package main import ( "encoding/json" "errors" "strings" ) func buildPrompt(summaries []RegionSummary) (string, error) { regionsJSON, err := json.MarshalIndent(summaries, "", " ") if err != nil { return "", err } return `你是微信 RPA 多模态任务规划器。 请根据图片和标注区域完成: 1. 识别当前聊天记录。 2. 识别联系人或会话对象,如果无法识别则填 unknown。 3. 判断是否需要回复。 4. 如果需要回复,生成 reply_text。 5. 生成 dry-run 动作计划。 限制: - 只能返回合法 JSON,不要 Markdown,不要解释。 - 不要编造坐标。 - 点击坐标只能使用我提供的区域中心点。 - 如果区域 type 是 custom,请重点参考 description 判断该区域的用途和可执行动作。 - description 是用户标注时填写的用途说明,优先级高于模型自行猜测。 - 微信发送消息使用键入回车键,不要规划点击发送按钮。 - action.type 只能是 click、type_text、press_enter、scroll、wait、noop。 - 当前是 dry_run,只生成计划,不要假设动作已执行。 - 如果无需回复,task_type 使用 wechat_observe 或 noop,并给出 observations。 标注区域如下: ` + string(regionsJSON) + ` 请严格返回如下 JSON 结构: { "task_id": "", "task_name": "识别微信聊天并生成回复", "task_type": "wechat_reply", "task_status": "planned", "confidence": 0.0, "llm_summary": { "contact_name": "unknown", "chat_summary": "", "latest_user_message": "", "reply_text": "" }, "actions": [ {"action_id":"action_001","type":"click","name":"点击输入框","status":"pending","target_region":"input_box"}, {"action_id":"action_002","type":"type_text","name":"输入回复内容","status":"pending","text":""}, {"action_id":"action_003","type":"press_enter","name":"按回车发送","status":"pending"} ] }`, nil } func extractJSON(text string) (string, error) { trimmed := strings.TrimSpace(text) trimmed = strings.TrimPrefix(trimmed, "```json") trimmed = strings.TrimPrefix(trimmed, "```") trimmed = strings.TrimSuffix(trimmed, "```") trimmed = strings.TrimSpace(trimmed) start := strings.Index(trimmed, "{") end := strings.LastIndex(trimmed, "}") if start < 0 || end < start { return "", errors.New("no JSON object found in LLM response") } return trimmed[start : end+1], nil } func parseTaskFromLLM(raw string) (Task, string, error) { jsonText, err := extractJSON(raw) if err != nil { return Task{}, "", err } var task Task if err := json.Unmarshal([]byte(jsonText), &task); err != nil { return Task{}, jsonText, err } return task, jsonText, nil }