101 lines
3.7 KiB
Go
101 lines
3.7 KiB
Go
package app
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"infinite-canvas/backend/internal/model"
|
|
"infinite-canvas/backend/internal/repository"
|
|
)
|
|
|
|
// The anchor records the current request and observable reference candidates.
|
|
// It does not infer creative permissions or carry an old goal into a new turn.
|
|
type cloudAgentCreativeAnchor struct {
|
|
Version int `json:"version"`
|
|
UserPrompt string `json:"userPrompt"`
|
|
ReferenceNodeIDs []string `json:"referenceNodeIds,omitempty"`
|
|
ReferenceAssets []cloudAgentReferenceAnchor `json:"referenceAssets,omitempty"`
|
|
}
|
|
|
|
type cloudAgentReferenceAnchor struct {
|
|
NodeID string `json:"nodeId"`
|
|
Type string `json:"type"`
|
|
Title string `json:"title,omitempty"`
|
|
Prompt string `json:"prompt,omitempty"`
|
|
AssetTags []string `json:"assetTags,omitempty"`
|
|
ReferenceReady bool `json:"referenceReady"`
|
|
VisualIdentity string `json:"visualIdentity"`
|
|
RequiresVisualInspection bool `json:"requiresVisualInspection"`
|
|
// 旧检查点可能含有未经确认的正文摘录,不再自动写入或跨轮继承。
|
|
VisualNote string `json:"visualNote,omitempty"`
|
|
Width any `json:"width,omitempty"`
|
|
Height any `json:"height,omitempty"`
|
|
}
|
|
|
|
// cloudAgentCreativeAnchorForCanvas 按当前画布重建候选素材锚点。
|
|
// 不继承旧视觉标记:工具成功和下一段正文都不是识别成功的可靠证据,节点也可能换图。
|
|
func cloudAgentCreativeAnchorForCanvas(repo *repository.Repository, userID string, canvas *model.CanvasProject, prompt string, _ *cloudAgentCreativeAnchor) (cloudAgentCreativeAnchor, error) {
|
|
anchor := cloudAgentCreativeAnchor{Version: 2, UserPrompt: prompt}
|
|
|
|
doc, err := creationDocument(canvas.PayloadJSON)
|
|
if err != nil {
|
|
return cloudAgentCreativeAnchor{}, BadAuthRequest("服务端画布内容无法解析,请先重新同步")
|
|
}
|
|
nodes := creationMaps(doc["nodes"])
|
|
byID := make(map[string]map[string]any, len(nodes))
|
|
for _, node := range nodes {
|
|
if id := stringValue(node["id"]); id != "" {
|
|
byID[id] = node
|
|
}
|
|
}
|
|
|
|
ids := make([]string, 0, 16)
|
|
for _, node := range nodes {
|
|
descriptor, known := cloudAgentNodeCapabilityForNode(node)
|
|
if known && descriptor.Connection.CanReference {
|
|
ids = append(ids, stringValue(node["id"]))
|
|
}
|
|
if len(ids) == 16 {
|
|
break
|
|
}
|
|
}
|
|
for _, id := range ids {
|
|
if id == "" || byID[id] == nil {
|
|
continue
|
|
}
|
|
node := byID[id]
|
|
descriptor, known := cloudAgentNodeCapabilityForNode(node)
|
|
if !known || !descriptor.Connection.CanReference {
|
|
continue
|
|
}
|
|
meta, _ := node["metadata"].(map[string]any)
|
|
prompt, _ := cloudAgentMediaPrompt(meta)
|
|
item := cloudAgentReferenceAnchor{
|
|
NodeID: stringValue(node["id"]), Type: descriptor.Type,
|
|
Title: truncateRunes(stringValue(node["title"]), 300),
|
|
Prompt: truncateRunes(prompt, 1000),
|
|
VisualIdentity: "unknown", RequiresVisualInspection: true,
|
|
}
|
|
if tags, ok := meta["assetTags"].([]any); ok {
|
|
for _, tag := range tags {
|
|
if text := strings.TrimSpace(stringValue(tag)); text != "" {
|
|
item.AssetTags = append(item.AssetTags, truncateRunes(text, 120))
|
|
}
|
|
}
|
|
}
|
|
if repo != nil {
|
|
// 角色卡按三视图判定是否可作参考;普通媒体按节点资源判定。
|
|
ref, _, refErr := cloudAgentMediaReference(repo, userID, "", node)
|
|
if refErr == nil {
|
|
item.ReferenceReady = true
|
|
item.Width, item.Height = ref["width"], ref["height"]
|
|
}
|
|
}
|
|
anchor.ReferenceNodeIDs = append(anchor.ReferenceNodeIDs, item.NodeID)
|
|
anchor.ReferenceAssets = append(anchor.ReferenceAssets, item)
|
|
if len(anchor.ReferenceAssets) == 16 {
|
|
break
|
|
}
|
|
}
|
|
return anchor, nil
|
|
}
|