户型图生成 API 文档#
基础 URL:
https://api.ideal.house
版本: v1
更新于: 2026-08-09
📖 概述#
户型图生成 API 根据结构化的房间需求和可选的自定义提示或参考图片,生成一张由 AI 生成的黑白、俯视、CAD 风格的住宅概念户型图。
此输出用于早期布局探索。它不是施工图纸,生成的尺寸、几何形状、洁具布置和合规性必须由合格专业人员审核。
工作流为异步方式:
- 创建任务 — 提交户型图参数,获得一个
taskId。 - 轮询结果 — 使用
taskId查询结果端点,直到任务到达终止状态。
🔐 认证#
所有公共 API 请求必须包含一个 API 密钥。
| 头部 | 必填 | 值 |
|---|---|---|
APIKEY | ✅ 是 | 您的 API 密钥 |
Content-Type | ✅ POST 时必填 | application/json |
[!WARNING] 妥善保管您的 API 密钥。请勿将其暴露在客户端代码或公开仓库中。
💰 积分扣减#
成功创建生成任务后扣除积分。若任务最终失败,扣除的积分将自动退还。积分不足将返回错误码 9051。
模型(modelType) | 输出尺寸 | 积分 |
|---|---|---|
Base | 1536 × 1024 | 10 |
Pro | 2496 × 1664 | 20 |
Floor Plan API 不支持 Flash。
参见 积分扣减参考 了解常见计费行为。
📌 API 端点#
1. 创建户型图任务#
创建户型图生成任务并返回唯一任务 ID。
端点
POST /api/v1/floorPlan/generate
请求头
| 头部 | 必填 | 说明 |
|---|---|---|
APIKEY | ✅ 是 | API 认证密钥 |
Content-Type | ✅ 是 | 必须为 application/json |
请求体#
| 字段 | 类型 | 必填 | 说明 | 默认值 |
|---|---|---|---|---|
bedrooms | integer | ❌ 否 | 卧室数量,从 0 到 5 | 2 |
bathrooms | number | ❌ 否 | 卫生间总数,从 0.5 到 4,以 0.5 为步长 | 1.5 |
totalArea | string | ✅ 是 | 带单位 m² 或 ft² 的正数目标总面积,如 220 m² 或 1386 ft² | — |
bedroomAreaRanges | array<object> | ❌ 否 | 可选的卧室尺寸指导。参见 卧室面积范围 | 省略时由 totalArea 推导 |
bathroomDetails | object | ❌ 否 | 仅全卫生间的偏好设置。参见 卫生间详情 | — |
kitchenDetails | object | ❌ 否 | 可选厨房配置。参见 厨房详情 | — |
keyRooms | array<string> | ❌ 否 | 附加房间或空间。参见 关键房间 | [] |
prompt | string | ❌ 否 | 附加布局优先级。无法覆盖结构化计数或硬性视觉约束 | "" |
refImageUrl | string | ❌ 否 | 公开可访问的参考图片 URL | "" |
modelType | string | ❌ 否 | 枚举值:Base、Pro | Base |
[!IMPORTANT] 公共 API 当前将
bedrooms验证为0–5,将bathrooms验证为0.5–4。其他客户端 UI 中可用的值不会扩大这些服务端限制。
通用请求规则#
- 所有枚举值区分大小写,必须使用本文档中显示的英文值。
totalArea是用于指导比例和尺寸的总建筑面积目标值;不被视为精确的施工尺寸。- 组装结构化图片提示时,有效自定义提示限制在前 800 个字符。
- 结构化字段的优先级高于
prompt中冲突的指令。 - 一个成功的任务恰好生成一张图片。
📐 总面积#
totalArea 包含一个正数数值后跟一个面积单位。
| 单位 | 示例 |
|---|---|
m² | 220 m² |
ft² | 1386 ft² |
建议在单位前留空格。正值的小数被接受。
有效示例:
{
"totalArea": "200 m²"
}
{
"totalArea": "1850 ft²"
}
🛏️ 卧室面积范围#
bedroomAreaRanges 提供相对卧室尺寸指导。它不会在生成图片中请求数值面积标签。
每个项目的格式如下:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | ❌ 否 | 卧室标识,例如 Room 1 (Master) 或 Room 2 |
minArea | string | ❌ 否 | 正数最小面积 |
maxArea | string | ❌ 否 | 正数最大面积;不得小于 minArea |
unit | string | ❌ 否 | 枚举值:m²、ft²;与 totalArea 使用相同单位 |
显式范围示例
{
"bedroomAreaRanges": [
{
"name": "Room 1 (Master)",
"minArea": "30",
"maxArea": "40",
"unit": "m²"
},
{
"name": "Room 2",
"minArea": "20",
"maxArea": "30",
"unit": "m²"
}
]
}
提供非空数组时的规则:
- 其长度必须等于
bedrooms。 - 每个提供的
minArea和maxArea必须是正数数字字符串。 - 当两个值都提供时,
minArea <= maxArea。 - 提供
unit时,必须为m²或ft²。 - 名称会被保留。空项或 null 项不提供尺寸指导。
省略时的自动范围#
该字段可以省略或发送为空数组。当没有项目包含有效的 minArea 或 maxArea 时,结构化生成路径从 totalArea 和 bedrooms 推导内部卧室范围:
- 一间卧室时,卧室总面积预算为总面积的 20%。
- 每增加一间卧室,预算增加 7.5 个百分点,最高不超过 50%。
- 第一间卧室的面积分配权重为
1.3;其余每间卧室的权重为1.0。 - 每个目标值转换为约
±10%的范围,并取整到整数面积单位。 - 单位继承自
totalArea。 - 已有的非空房间名予以保留;否则服务器使用
Room 1、Room 2等命名。
对于 200 m² 和 4 间卧室,当前推导的指导值约为:
[
{ "name": "Room 1", "minArea": "23", "maxArea": "28", "unit": "m²" },
{ "name": "Room 2", "minArea": "18", "maxArea": "22", "unit": "m²" },
{ "name": "Room 3", "minArea": "18", "maxArea": "22", "unit": "m²" },
{ "name": "Room 4", "minArea": "18", "maxArea": "22", "unit": "m²" }
]
这些值是内部比例指导,并非保证的最终房间面积。显式有效范围始终优先于自动范围。
当 bedrooms 为 0 时,省略 bedroomAreaRanges 或发送 []。
🛁 卫生间详情#
bathrooms 表示卫生间总数:
- 其整数部分为全卫生间的数量。
- 一个
.5小数部分增加一个半卫生间。 - 每个全卫生间均提示包含马桶、梳妆台/洗手盆以及淋浴区或湿区。
- 半卫生间仅包含马桶和梳妆台/洗手盆,无淋浴或浴缸。
bathroomDetails 仅配置全卫生间:
{
"bathroomDetails": {
"fullBathroomOptions": [
{
"name": "Bathroom 1",
"wetDrySeparation": "yes",
"bathtub": "required"
},
{
"name": "Bathroom 2",
"wetDrySeparation": "no",
"bathtub": "optional"
}
]
}
}
| 字段 | 类型 | 允许值 | 说明 |
|---|---|---|---|
name | string | Bathroom 1、Bathroom 2 等 | 可选显示标识 |
wetDrySeparation | string / null | yes、no、null | 是否显示分隔的湿区 |
bathtub | string / null | no、optional、required、null | 浴缸偏好 |
规则:
fullBathroomOptions.length不得超过floor(bathrooms)。- 数组中只能包含已选择偏好的全卫生间。
null值表示未指定。- 所需的浴缸是标准全卫生间洁具之外的额外配置;它不会替代马桶或淋浴。
- 干湿分离是计数卫生间内部的分隔,而非额外的卫生间。
🍳 厨房详情#
所有 kitchenDetails 子字段均为可选。未选择厨房偏好时省略整个对象。
{
"kitchenDetails": {
"type": "open",
"size": "standard",
"layout": "U",
"islandType": "preparation",
"storage": "maximum",
"features": ["breakfast nook", "pantry"]
}
}
| 字段 | 类型 | 允许值 |
|---|---|---|
type | string | open, semi-open, closed |
size | string | small, standard, large, extra large |
layout | string | I, L, U, gallery |
islandType | string | no, preparation, cooking, entertainment |
storage | string | minimal, standard, maximum |
features | array<string> | eating bar, breakfast nook, pantry |
部分配置是有效的。例如:
{
"kitchenDetails": {
"type": "semi-open"
}
}
🚪 关键房间#
keyRooms 接受以下确切值的数组:
| 值 | 说明 |
|---|---|
walk-in closet | 连接卧室区的专用步入式衣帽间 |
laundry room | 专用洗衣房 |
storage room | 通用储物间 |
utility room | 设备间或服务区 |
home office | 专用办公室或书房 |
garage | 带外部车辆开口和内部住宅通道的车库 |
pantry | 紧邻厨房的食品储藏室 |
combined living-dining | 共用起居和用餐区 |
balcony | 连接起居空间或主卧室的户外阳台 |
遗留的 Web 值 balcon 也被接受并标准化为 balcony。
规则:
- 空白值将被忽略,重复值将被去除。
- 选中的关键房间只请求一次。
- 未选中的可选空间不包含在生成的房间配置方案中。
- 如果
pantry同时出现在kitchenDetails.features和keyRooms中,只请求一个食品储藏室。
示例:
{
"keyRooms": [
"garage",
"home office",
"combined living-dining"
]
}
🖼️ 参考图片#
refImageUrl 是可选的,必须由 API 服务器直接访问。
要求:
- 格式:JPG/JPEG、PNG 或 WebP。
- 最大文件大小:20 MB。
- 最小尺寸:128 × 128 px。
- 最大尺寸:6,000 × 6,000 px。更大的图片在处理前按比例缩放。
参考图片用于指导布局、邻接关系、比例或视觉风格。它不会覆盖结构化房间计数或其他硬性约束。
🤖 模型类型#
| 值 | 说明 |
|---|---|
Base | 默认。平衡生成质量,1536 × 1024 输出 |
Pro | 更高分辨率,2496 × 1664 输出,预期生成时间更长 |
仅支持 Base 和 Pro。
不属于公开 API 接口约定的字段#
以下字段不应由公共 API 客户端依赖:
| 字段 | 备注 |
|---|---|
imageNumbers | 当前生成器始终返回一张图片;此字段不需要 |
extData | 内部 Web 任务组跟踪元数据;公共客户端应省略 |
isApiCall | 由 API 端点确定,而非由请求体确定 |
genByMember | 内部生成元数据,不是户型图请求字段 |
已移除的旧字段,不得发送:
floorplanSetting
roomCounts
grossArea
totalAreaValue
totalAreaUnit
totalAreaType
fullBathrooms
halfBathrooms
halfBathroomRequirement
kitchenType
diningRooms
livingRooms
extras
referenceImage
hasDetailOptions
📥 创建任务示例#
带有自动卧室范围的最小请求#
curl -X POST "https://api.ideal.house/api/v1/floorPlan/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro",
"prompt": "Upper floor of a two-story Saudi Arabian villa with a master bedroom, family living area, staircase landing, and balcony"
}'
完整请求#
cURL
curl -X POST "https://api.ideal.house/api/v1/floorPlan/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"bedrooms": 3,
"bathrooms": 2.5,
"totalArea": "220 m²",
"bedroomAreaRanges": [
{"name": "Room 1 (Master)", "minArea": "30", "maxArea": "40", "unit": "m²"},
{"name": "Room 2", "minArea": "20", "maxArea": "30", "unit": "m²"},
{"name": "Room 3", "minArea": "20", "maxArea": "30", "unit": "m²"}
],
"bathroomDetails": {
"fullBathroomOptions": [
{"name": "Bathroom 1", "wetDrySeparation": "yes", "bathtub": "required"},
{"name": "Bathroom 2", "wetDrySeparation": "no", "bathtub": "optional"}
]
},
"kitchenDetails": {
"type": "open",
"size": "standard",
"layout": "U",
"islandType": "preparation",
"storage": "maximum",
"features": ["breakfast nook", "pantry"]
},
"keyRooms": ["garage", "home office", "combined living-dining"],
"prompt": "Bright modern home with good natural lighting",
"refImageUrl": "https://example.com/reference-plan.png",
"modelType": "Pro"
}'
Java (OkHttp)
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class FloorPlanApiExample {
private static final String BASE_URL = "https://api.ideal.house";
private static final String API_KEY = "your_api_key_here";
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
String json = """
{
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro"
}
""";
Request request = new Request.Builder()
.url(BASE_URL + "/api/v1/floorPlan/generate")
.addHeader("APIKEY", API_KEY)
.addHeader("Content-Type", "application/json")
.post(RequestBody.create(json, MediaType.parse("application/json")))
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println(response.body().string());
}
}
}
Python (requests)
import requests
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
payload = {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro",
}
response = requests.post(
f"{BASE_URL}/api/v1/floorPlan/generate",
headers={"APIKEY": API_KEY, "Content-Type": "application/json"},
json=payload,
)
response.raise_for_status()
print("Task ID:", response.json()["data"])
Node.js (axios)
const axios = require('axios');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function createFloorPlanTask() {
const response = await axios.post(
`${BASE_URL}/api/v1/floorPlan/generate`,
{
bedrooms: 4,
bathrooms: 2,
totalArea: '200 m²',
keyRooms: ['walk-in closet', 'balcony'],
prompt: 'Upper floor with a master bedroom and family living area',
modelType: 'Pro'
},
{
headers: {
APIKEY: API_KEY,
'Content-Type': 'application/json'
}
}
);
console.log('Task ID:', response.data.data);
return response.data.data;
}
createFloorPlanTask();
创建任务成功响应#
{
"code": 0,
"message": "success",
"data": 1234567890123456789
}
| 字段 | 类型 | 说明 |
|---|---|---|
code | integer | 0 表示任务创建成功 |
message | string | 响应消息 |
data | long | 用于轮询结果端点的任务 ID |
2. 获取任务结果#
返回任务进度及可用的生成图片。
端点
GET /api/v1/floorPlan/result?taskId={taskId}
请求头
| 头部 | 必填 | 说明 |
|---|---|---|
APIKEY | ✅ 是 | API 认证密钥 |
查询参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
taskId | long | ✅ 是 | 由创建端点返回的任务 ID |
结果请求示例#
cURL
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
-H "APIKEY: your_api_key_here"
Python 轮询
import time
import requests
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
task_id = 1234567890123456789
while True:
response = requests.get(
f"{BASE_URL}/api/v1/floorPlan/result",
headers={"APIKEY": API_KEY},
params={"taskId": task_id},
)
response.raise_for_status()
task = response.json()["data"]
print(task["status"], task["percentage"], task["waitNumber"])
if task["status"] in ("Success", "Failed", "Termination"):
break
time.sleep(3)
if task["status"] == "Success":
print("Result URL:", task["output"]["resultUrl"])
Node.js 轮询
const axios = require('axios');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function pollFloorPlanResult(taskId) {
while (true) {
const response = await axios.get(
`${BASE_URL}/api/v1/floorPlan/result`,
{
headers: { APIKEY: API_KEY },
params: { taskId }
}
);
const task = response.data.data;
console.log(task.status, task.percentage, task.waitNumber);
if (['Success', 'Failed', 'Termination'].includes(task.status)) {
if (task.status === 'Success') {
console.log('Result URL:', task.output.resultUrl);
}
return task;
}
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
pollFloorPlanResult('1234567890123456789');
已完成任务响应#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Success",
"waitNumber": 0,
"percentage": 100,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"bedroomAreaRanges": [
{"name": "Room 1", "minArea": "23", "maxArea": "28", "unit": "m²"},
{"name": "Room 2", "minArea": "18", "maxArea": "22", "unit": "m²"},
{"name": "Room 3", "minArea": "18", "maxArea": "22", "unit": "m²"},
{"name": "Room 4", "minArea": "18", "maxArea": "22", "unit": "m²"}
],
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro"
},
"output": {
"resultUrl": "https://cdn.ideal.house/output/floor-plan.jpg",
"width": 2496,
"height": 1664
}
}
}
处理中响应#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Processing",
"waitNumber": 1,
"percentage": 45,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro"
},
"output": null
}
}
失败任务响应#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Failed",
"waitNumber": 0,
"percentage": 0,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro"
},
"output": null
}
}
结果字段#
| 字段 | 类型 | 说明 |
|---|---|---|
id | long | 任务 ID |
status | string | 当前任务状态 |
waitNumber | integer | 队列中排在任务前面的数量;0 表示前面无排队任务 |
percentage | integer | 从 0 到 100 的近似完成百分比 |
input | object | 规范化任务输入,包括自动推导的卧室范围(如适用) |
output | object / null | 任务成功时生成输出;否则通常为 null |
output.resultUrl | string | 生成户型图图片的签名 URL |
output.width | integer | 输出宽度(像素) |
output.height | integer | 输出高度(像素) |
📊 任务状态#
| 状态 | 说明 |
|---|---|
Unprocessed | 任务已创建但尚未开始 |
Processing | 任务正在处理中 |
Success | 任务完成,output.resultUrl 可用 |
Failed | 任务失败 |
Termination | 任务被中断或终止 |
每 3–5 秒 轮询一次。参见 API 任务限制。
❌ 错误响应#
所有错误响应使用通用响应结构:
{
"code": 1011,
"message": "bedroomAreaRanges size must match bedrooms",
"data": null
}
| 代码 | 名称 | 说明 | 建议操作 |
|---|---|---|---|
1001 | FAILED | 通用请求失败 | 检查 message 字段 |
1003 | INTERNAL_ERROR | 内部服务器错误 | 稍后重试;若持续发生请联系支持 |
1011 | PARAM_ERROR | 无效请求参数 | 验证计数、单位、枚举值和嵌套数组 |
5002 | API_KEY_INVALID | 无效或缺失的 API 密钥 | 验证 APIKEY 头部 |
9010 | SCAN_TEXT_ERROR | 提示内容审核失败 | 修改提示 |
9038 | PROHIBITED_CONTENT | 生成输出包含禁止内容 | 调整输入并重试 |
9051 | COINS_NOT_ENOUGH | 积分不足 | 充值积分并重试 |
参见 错误码参考 获取完整公共错误列表。
🔄 Web 集成说明#
经过认证的 Web 应用和公共 API 使用不同的端点和认证方式:
| 客户端 | 端点 | 认证方式 |
|---|---|---|
| Web 应用 | POST /floorPlan/generate | 登录 token 头 |
| 公共 API | POST /api/v1/floorPlan/generate | APIKEY 头 |
业务字段结构是对齐的,但公共 API 客户端应遵循本文档中的服务端限制和公共契约。特别是:
- Web 客户端可以包含内部
imageNumbers和extData;公共客户端不需要它们。 - 公共 API 根据端点和凭据确定 API 调用元数据。请求字段如
isApiCall和genByMember是不必要的。 balcon为兼容而接受并标准化为balcony;新集成应发送balcony。- 当前的公共服务端限制仍然是
0–5间卧室和0.5–4个卫生间,即使另一个 UI 暂时提供了更宽的选择器。