Ideal House
跳转到主要内容

户型图生成 API 文档#

基础 URL: https://api.ideal.house
版本: v1
更新于: 2026-08-09


📖 概述#

户型图生成 API 根据结构化的房间需求和可选的自定义提示或参考图片,生成一张由 AI 生成的黑白、俯视、CAD 风格的住宅概念户型图。

此输出用于早期布局探索。它不是施工图纸,生成的尺寸、几何形状、洁具布置和合规性必须由合格专业人员审核。

工作流为异步方式:

  1. 创建任务 — 提交户型图参数,获得一个 taskId
  2. 轮询结果 — 使用 taskId 查询结果端点,直到任务到达终止状态。

🔐 认证#

所有公共 API 请求必须包含一个 API 密钥。

头部必填
APIKEY✅ 是您的 API 密钥
Content-Type✅ POST 时必填application/json

[!WARNING] 妥善保管您的 API 密钥。请勿将其暴露在客户端代码或公开仓库中。


💰 积分扣减#

成功创建生成任务后扣除积分。若任务最终失败,扣除的积分将自动退还。积分不足将返回错误码 9051

模型(modelType输出尺寸积分
Base1536 × 102410
Pro2496 × 166420

Floor Plan API 不支持 Flash

参见 积分扣减参考 了解常见计费行为。


📌 API 端点#

1. 创建户型图任务#

创建户型图生成任务并返回唯一任务 ID。

端点

http
POST /api/v1/floorPlan/generate

请求头

头部必填说明
APIKEY✅ 是API 认证密钥
Content-Type✅ 是必须为 application/json

请求体#

字段类型必填说明默认值
bedroomsinteger❌ 否卧室数量,从 052
bathroomsnumber❌ 否卫生间总数,从 0.54,以 0.5 为步长1.5
totalAreastring✅ 是带单位 ft² 的正数目标总面积,如 220 m²1386 ft²
bedroomAreaRangesarray<object>❌ 否可选的卧室尺寸指导。参见 卧室面积范围省略时由 totalArea 推导
bathroomDetailsobject❌ 否仅全卫生间的偏好设置。参见 卫生间详情
kitchenDetailsobject❌ 否可选厨房配置。参见 厨房详情
keyRoomsarray<string>❌ 否附加房间或空间。参见 关键房间[]
promptstring❌ 否附加布局优先级。无法覆盖结构化计数或硬性视觉约束""
refImageUrlstring❌ 否公开可访问的参考图片 URL""
modelTypestring❌ 否枚举值:BaseProBase

[!IMPORTANT] 公共 API 当前将 bedrooms 验证为 0–5,将 bathrooms 验证为 0.5–4。其他客户端 UI 中可用的值不会扩大这些服务端限制。

通用请求规则#

  • 所有枚举值区分大小写,必须使用本文档中显示的英文值。
  • totalArea 是用于指导比例和尺寸的总建筑面积目标值;不被视为精确的施工尺寸。
  • 组装结构化图片提示时,有效自定义提示限制在前 800 个字符。
  • 结构化字段的优先级高于 prompt 中冲突的指令。
  • 一个成功的任务恰好生成一张图片。

📐 总面积#

totalArea 包含一个正数数值后跟一个面积单位。

单位示例
220 m²
ft²1386 ft²

建议在单位前留空格。正值的小数被接受。

有效示例:

json
{
  "totalArea": "200 m²"
}
json
{
  "totalArea": "1850 ft²"
}

🛏️ 卧室面积范围#

bedroomAreaRanges 提供相对卧室尺寸指导。它不会在生成图片中请求数值面积标签。

每个项目的格式如下:

字段类型必填说明
namestring❌ 否卧室标识,例如 Room 1 (Master)Room 2
minAreastring❌ 否正数最小面积
maxAreastring❌ 否正数最大面积;不得小于 minArea
unitstring❌ 否枚举值:ft²;与 totalArea 使用相同单位

显式范围示例

json
{
  "bedroomAreaRanges": [
    {
      "name": "Room 1 (Master)",
      "minArea": "30",
      "maxArea": "40",
      "unit": "m²"
    },
    {
      "name": "Room 2",
      "minArea": "20",
      "maxArea": "30",
      "unit": "m²"
    }
  ]
}

提供非空数组时的规则:

  • 其长度必须等于 bedrooms
  • 每个提供的 minAreamaxArea 必须是正数数字字符串。
  • 当两个值都提供时,minArea <= maxArea
  • 提供 unit 时,必须为 ft²
  • 名称会被保留。空项或 null 项不提供尺寸指导。

省略时的自动范围#

该字段可以省略或发送为空数组。当没有项目包含有效的 minAreamaxArea 时,结构化生成路径从 totalAreabedrooms 推导内部卧室范围:

  • 一间卧室时,卧室总面积预算为总面积的 20%。
  • 每增加一间卧室,预算增加 7.5 个百分点,最高不超过 50%。
  • 第一间卧室的面积分配权重为 1.3;其余每间卧室的权重为 1.0
  • 每个目标值转换为约 ±10% 的范围,并取整到整数面积单位。
  • 单位继承自 totalArea
  • 已有的非空房间名予以保留;否则服务器使用 Room 1Room 2 等命名。

对于 200 m²4 间卧室,当前推导的指导值约为:

json
[
  { "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²" }
]

这些值是内部比例指导,并非保证的最终房间面积。显式有效范围始终优先于自动范围。

bedrooms0 时,省略 bedroomAreaRanges 或发送 []


🛁 卫生间详情#

bathrooms 表示卫生间总数:

  • 其整数部分为全卫生间的数量。
  • 一个 .5 小数部分增加一个半卫生间。
  • 每个全卫生间均提示包含马桶、梳妆台/洗手盆以及淋浴区或湿区。
  • 半卫生间仅包含马桶和梳妆台/洗手盆,无淋浴或浴缸。

bathroomDetails 仅配置全卫生间:

json
{
  "bathroomDetails": {
    "fullBathroomOptions": [
      {
        "name": "Bathroom 1",
        "wetDrySeparation": "yes",
        "bathtub": "required"
      },
      {
        "name": "Bathroom 2",
        "wetDrySeparation": "no",
        "bathtub": "optional"
      }
    ]
  }
}
字段类型允许值说明
namestringBathroom 1Bathroom 2可选显示标识
wetDrySeparationstring / nullyesnonull是否显示分隔的湿区
bathtubstring / nullnooptionalrequirednull浴缸偏好

规则:

  • fullBathroomOptions.length 不得超过 floor(bathrooms)
  • 数组中只能包含已选择偏好的全卫生间。
  • null 值表示未指定。
  • 所需的浴缸是标准全卫生间洁具之外的额外配置;它不会替代马桶或淋浴。
  • 干湿分离是计数卫生间内部的分隔,而非额外的卫生间。

🍳 厨房详情#

所有 kitchenDetails 子字段均为可选。未选择厨房偏好时省略整个对象。

json
{
  "kitchenDetails": {
    "type": "open",
    "size": "standard",
    "layout": "U",
    "islandType": "preparation",
    "storage": "maximum",
    "features": ["breakfast nook", "pantry"]
  }
}
字段类型允许值
typestringopen, semi-open, closed
sizestringsmall, standard, large, extra large
layoutstringI, L, U, gallery
islandTypestringno, preparation, cooking, entertainment
storagestringminimal, standard, maximum
featuresarray<string>eating bar, breakfast nook, pantry

部分配置是有效的。例如:

json
{
  "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.featureskeyRooms 中,只请求一个食品储藏室。

示例:

json
{
  "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 输出,预期生成时间更长

仅支持 BasePro


不属于公开 API 接口约定的字段#

以下字段不应由公共 API 客户端依赖:

字段备注
imageNumbers当前生成器始终返回一张图片;此字段不需要
extData内部 Web 任务组跟踪元数据;公共客户端应省略
isApiCall由 API 端点确定,而非由请求体确定
genByMember内部生成元数据,不是户型图请求字段

已移除的旧字段,不得发送:

text
floorplanSetting
roomCounts
grossArea
totalAreaValue
totalAreaUnit
totalAreaType
fullBathrooms
halfBathrooms
halfBathroomRequirement
kitchenType
diningRooms
livingRooms
extras
referenceImage
hasDetailOptions

📥 创建任务示例#

带有自动卧室范围的最小请求#

bash
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
bash
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)
java
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)
python
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)
javascript
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();

创建任务成功响应#

json
{
  "code": 0,
  "message": "success",
  "data": 1234567890123456789
}
字段类型说明
codeinteger0 表示任务创建成功
messagestring响应消息
datalong用于轮询结果端点的任务 ID

2. 获取任务结果#

返回任务进度及可用的生成图片。

端点

http
GET /api/v1/floorPlan/result?taskId={taskId}

请求头

头部必填说明
APIKEY✅ 是API 认证密钥

查询参数

参数类型必填说明
taskIdlong✅ 是由创建端点返回的任务 ID

结果请求示例#

cURL
bash
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
  -H "APIKEY: your_api_key_here"
Python 轮询
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 轮询
javascript
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');

已完成任务响应#

json
{
  "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
    }
  }
}

处理中响应#

json
{
  "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
  }
}

失败任务响应#

json
{
  "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
  }
}

结果字段#

字段类型说明
idlong任务 ID
statusstring当前任务状态
waitNumberinteger队列中排在任务前面的数量;0 表示前面无排队任务
percentageinteger0100 的近似完成百分比
inputobject规范化任务输入,包括自动推导的卧室范围(如适用)
outputobject / null任务成功时生成输出;否则通常为 null
output.resultUrlstring生成户型图图片的签名 URL
output.widthinteger输出宽度(像素)
output.heightinteger输出高度(像素)

📊 任务状态#

状态说明
Unprocessed任务已创建但尚未开始
Processing任务正在处理中
Success任务完成,output.resultUrl 可用
Failed任务失败
Termination任务被中断或终止

3–5 秒 轮询一次。参见 API 任务限制


❌ 错误响应#

所有错误响应使用通用响应结构:

json
{
  "code": 1011,
  "message": "bedroomAreaRanges size must match bedrooms",
  "data": null
}
代码名称说明建议操作
1001FAILED通用请求失败检查 message 字段
1003INTERNAL_ERROR内部服务器错误稍后重试;若持续发生请联系支持
1011PARAM_ERROR无效请求参数验证计数、单位、枚举值和嵌套数组
5002API_KEY_INVALID无效或缺失的 API 密钥验证 APIKEY 头部
9010SCAN_TEXT_ERROR提示内容审核失败修改提示
9038PROHIBITED_CONTENT生成输出包含禁止内容调整输入并重试
9051COINS_NOT_ENOUGH积分不足充值积分并重试

参见 错误码参考 获取完整公共错误列表。


🔄 Web 集成说明#

经过认证的 Web 应用和公共 API 使用不同的端点和认证方式:

客户端端点认证方式
Web 应用POST /floorPlan/generate登录 token
公共 APIPOST /api/v1/floorPlan/generateAPIKEY

业务字段结构是对齐的,但公共 API 客户端应遵循本文档中的服务端限制和公共契约。特别是:

  • Web 客户端可以包含内部 imageNumbersextData;公共客户端不需要它们。
  • 公共 API 根据端点和凭据确定 API 调用元数据。请求字段如 isApiCallgenByMember 是不必要的。
  • balcon 为兼容而接受并标准化为 balcony;新集成应发送 balcony
  • 当前的公共服务端限制仍然是 0–5 间卧室和 0.5–4 个卫生间,即使另一个 UI 暂时提供了更宽的选择器。