canvas_api.md 15 KB

画布模式接口说明(保存节点 / 保存节点关联)

画布模式:无限画布(无固定宽高),节点无限扩展、无固定根节点,仅记录两两之间的无方向多对多关联。

通用说明:

  • 所有接口在 api 路由组下,需要登录态(bindToken / bindExportToken / checkLogin / checkSign / checkCompany 中间件)。
  • 返回格式统一为 { "msg": "", "code": 0, "data": {...} };出错时 code 为错误码,msg 为错误信息。
  • 表前缀统一为 mp_,节点类型为字符串小写。

1. 保存节点:POST api/canvas/saveNode

创建或更新画布节点。不传 node_id 表示创建node_id 表示更新(更新时节点类型以库中为准,不允许变更)。

1.1 入参说明

参数 类型 必填 说明
canvas_id int 画布 ID
node_id int 节点 ID,更新时必传,创建时不传
node_type string 创建时是 节点类型,枚举:theme-主题、subject-主体、scene-场景、prop-道具、segment-分镜、text-文字、image-图片、video-视频、audio-音频
name string 节点名称
content string 节点内容(主要用于text 文字节点)
text_prompt string 文字提示词
pic_prompt string 图片提示词
image_url string 图片 URL
video_url string 视频 URL
audio_url string 音频 URL
thumbnail_url string 缩略图 URL
duration int 时长(秒),视频/音频/分镜使用
pos_x number 节点在画布上的 X 坐标,默认0
pos_y number 节点在画布上的 Y 坐标,默认0
z_index int 节点层级,默认0
size_w number 节点显示宽度(可空)
size_h number 节点显示高度(可空)
source_type string 关联来源,枚举:none-无、product-全局资产库、episode-动漫分集,默认 none
source_product_id int 全局资产 ID(mp_products.id),source_type=product 时使用
source_anime_id int 动漫 ID(mp_animes.id),source_type=episode 时使用
source_episode_id int 剧集 ID(mp_anime_episodes.id),source_type=episode 时使用
source_ref string 来源明细引用,如剧集 JSON 列表中的 key,用于定位具体列表项
ext object/string 扩展信息,传对象或 JSON 字符串均可,库内以 JSON 存储
segment object 分镜数据子对象,仅node_type=segment 时生效(见 1.2)

1.2 segment 子对象字段

参数 类型 必填 说明
segment_number int 分镜序号,默认1
name string 分镜名称,缺省时取节点级name
text_prompt string 文字提示词,缺省时取节点级text_prompt
pic_prompt string 图片提示词,缺省时取节点级pic_prompt
image_url string 图片 URL,缺省时取节点级image_url
video_url string 视频 URL,缺省时取节点级video_url
audio_url string 音频 URL,缺省时取节点级audio_url
duration int 时长(秒)
status string 状态,枚举:draft-草稿、generating-生成中、completed-已完成、failed-失败,默认 draft
ext object/string 分镜扩展信息 JSON

保存分镜节点时,接口会同时写入节点表与画布分镜表(mp_canvas_segments);查询节点时返回的数据以分镜表字段为准。

1.3 示例请求体

创建普通节点(图片):

{
  "canvas_id": 1,
  "node_type": "image",
  "name": "图片-林默立绘",
  "image_url": "https://example.com/linmo.png",
  "thumbnail_url": "https://example.com/linmo_thumb.png",
  "pos_x": 280,
  "pos_y": 380
}

创建分镜节点:

{
  "canvas_id": 1,
  "node_type": "segment",
  "name": "分镜1-雨夜相遇",
  "pos_x": 480,
  "pos_y": 220,
  "segment": {
    "segment_number": 1,
    "text_prompt": "林默在雨夜街头偶遇苏晴",
    "pic_prompt": "写实。全景,雨夜街头,两人对视",
    "image_url": "https://example.com/seg1.png",
    "video_url": "",
    "audio_url": "",
    "duration": 8,
    "status": "completed"
  }
}

更新节点(复用动漫分集中的主体列表项):

{
  "canvas_id": 1,
  "node_id": 2,
  "name": "主体-林默",
  "source_type": "episode",
  "source_anime_id": 10,
  "source_episode_id": 3,
  "source_ref": "roles.0",
  "pos_x": 300,
  "pos_y": 100
}

1.4 返回示例

{
  "msg": "",
  "code": 0,
  "data": {
    "node_id": 21
  }
}

2. 保存节点关联:POST api/canvas/saveRels

保存某个节点的关联列表。整体替换语义:先清空该节点的全部关联,再写入新关联;返回实际写入的关联条数。

2.1 入参说明

参数 类型 必填 说明
canvas_id int 画布 ID
node_id int 中心节点 ID
related_ids array 要关联的节点 ID 数组;也可传逗号分隔的字符串(如"3,7,9")。传空数组/空字符串表示清空该节点的所有关联

2.2 规则说明

  • 关联无方向A 关联 BB 关联 A 等价,内部统一按(小 id,大 id)存储,同一对节点只保留一条。
  • 支持多对多:一个节点可以关联任意多个节点,1:1、1:N、N:1、N:N 均由该表表达。
  • 自动过滤:与自身关联、跨画布的节点、不存在的节点会被忽略,不影响其他关联写入。
  • related_ids 会整体替换该节点原有全部关联,不需要前端先查再删。

2.3 示例请求体

{
  "canvas_id": 1,
  "node_id": 2,
  "related_ids": [6, 8, 12, 16]
}

清空节点 2 的全部关联:

{
  "canvas_id": 1,
  "node_id": 2,
  "related_ids": []
}

2.4 返回示例

{
  "msg": "",
  "code": 0,
  "data": {
    "success": 1,
    "rel_count": 4
  }
}

3. 关联查询接口(配套)

3.1 获取节点关联:GET api/canvas/nodeRels

入参:

参数 类型 必填 说明
canvas_id int 画布 ID
node_id int 节点 ID

返回:rel_ids(关联节点 ID 数组)+ related_nodes(关联节点完整信息数组)。

3.2 画布关系图:GET api/canvas/graph

入参:

参数 类型 必填 说明
canvas_id int 画布 ID
node_id int 中心节点 ID;不传返回画布全部节点与关联,传了返回以该节点为中心的局部子图
depth int 局部子图深度(1-5),默认1,仅 node_id 传入时生效

返回:nodes(节点数组)+ rels(关联数组,每项含 node_id_a / node_id_b),局部子图模式额外返回 center_node_iddepthlevels

局部子图模式下(传了 node_id),节点与关联都附带 level 字段,并提供 levels 层级摘要,方便前端逐层加载与动画:

  • nodes[].level:节点距中心节点的跳数,中心节点为 0,直接邻居为 1,以此类推;
  • rels[].level:关联首次被 BFS 触及的轮次(depth=1 时全部为 1,即中心节点的直接关联);
  • levels:数组,每项 { level, node_ids, rel_ids }node_ids / rel_ids 分别为该层包含的节点 ID 与关联 ID 列表(level=0 为中心节点)。

前端渲染建议:直接用平铺的 nodes / rels 画节点和连线;需要"逐层展开/动画"时,按 level 过滤即可(如 nodes.filter(n => n.level <= 1)),或直接遍历 levels 摘要。

局部子图的 rels 只包含从中心节点展开过程中触及的关联:depth=1 时仅返回中心节点的直接关联,不会返回"邻居之间的边"(例如节点 9 的邻居 5 与 18 之间若存在关联,不会在 depth=1 的结果中出现,需 depth=2 才会包含)。

以演示数据中心节点 9、depth=2 为例的返回结果图示见 canvas_subgraph_depth2.png:返回 9 个节点、9 条边;节点 1 与 2 之间的边虽然两者都在子图内,但 BFS 展开过程中未触及,因此不返回。

3.3 节点详情:GET api/canvas/nodeInfo

入参:canvas_idnode_id。返回节点完整信息(分镜节点含分镜数据)+ rel_ids + related_nodes


4. 接口测试演示数据

仓库内已提供演示数据生成器 database/seeders/CanvasDemoSeeder.php,会生成一个名为「接口测试画布-示例」的画布,包含:

  • 20 个节点:主题×2、主体×2、场景×2、道具×2、分镜×3、文字×2、图片×3、视频×2、音频×2
  • 27 条无方向关联,节点间构成连通网络
  • 3 条画布分镜数据(含提示词、图片/视频 URL、状态)

运行前确认画布数据表已创建(php artisan migrate),然后执行:

# 指定测试用户的 uid / cpid(不指定默认 uid=1, cpid=1)
$env:CANVAS_DEMO_UID = 123
$env:CANVAS_DEMO_CPID = 456
php artisan db:seed --class=CanvasDemoSeeder

重复执行会先清理同名演示画布再重新生成。执行成功后控制台会输出 canvas_id 与 20 个节点的编号→ID 映射,便于直接拼接测试请求。

测试建议顺序:

  1. GET api/canvas/list 查看画布;
  2. GET api/canvas/graph?canvas_id=1 查看全部节点与关联;
  3. GET api/canvas/nodeRels?canvas_id=1&node_id=8 查看分镜节点的关联;
  4. POST api/canvas/saveRels 修改某节点关联后,再调用 graphnodeRels 验证;
  5. POST api/canvas/saveNode 新建/更新节点后,用 nodeInfo 验证。