# 互动组件配置JSON生成器 — 需求描述 ## 项目概述 从飞书wiki剧本文档出发,经过sheet数据解析、组件类型匹配、LLM驱动的jsonData生成, 最终输出组件配置JSON并持久化到本地SQLite数据库。 ## 数据来源 **剧本文档表格的"组件配置"列**。多维表格(bitable)是旧的数据流程, 我们基于剧本文档进行自动化生产是新流程,目标是替换多维表格流程。 bitable数据可用于验证和参考。 ## 已实现的互动类型 ### 中互动(27种,v1-v3.1完成) 覆盖对话类(6)、信息类(6)、图片类(4)、其他(11)共27种中互动组件。 详见 `scripts/match_component.py` 的 `MID_INTERACTION_TYPES`。 - 每种类型使用独立的精确Prompt模板(`prompts/prompt_registry.py`) - 角色配置通过section-character映射解析 - 教研配置文本拆解为结构化字段 - 语音识别热词自动生成(表达类组件) ### 核心互动(5种,v4-v6完成) #### 1. 合作阅读 core_reading_order(v4) - 7步LLM调用流水线 - 输出: taskInfo, materialInfo, flowInfo, studyInfo - bitable wiki: H6DJweNkpigCbak2Y5LcTZ8Vnfb #### 2. 看图选词 core_reading_imageDrag(v5) - 5步LLM调用流水线 - 输入: 教研-导览配置 + 教研-互动配置 - 中间步骤: 学习流程配置, 互动描述 - 最终JSON: taskInfo, questionGroup, studyInfo - bitable wiki: MVo7wugWfimJPIkxhJCcqppFnyf, table: tblKl9CGmARjpw1O - prompt模板: `prompts/core_imagedrag_prompts.py` #### 3. 口语快答 core_speaking_reply(v5) - 7步LLM调用流水线 - 输入: 教研-用户视角任务信息 + 教研-任务规则与NPC设定 - 中间步骤: 学习流程配置, promptInfo配置, 语音识别热词 - 最终JSON: taskInfo, dialogSetting, dialogConfig, studyInfo - bitable wiki: TSwcw0nFmi21khkpUndchNMsn6f, table: tbl4Qg8d45O58Cqf - prompt模板: `prompts/core_speaking_prompts.py` #### 4. 口语妙问 core_speaking_inquiry(v6) - 7步LLM调用流水线 - 输入: 教研-用户视角任务信息 + 教研-任务规则与NPC设定 - 中间步骤: 学习流程配置, promptInfo配置(NPC角色扮演被动问答型), 语音识别热词 - 最终JSON: taskInfo, dialogSetting, dialogConfig, studyInfo - 与口语快答的关键差异: Step2生成被动型NPC角色提示词(含知识库),而非主动提问型 - bitable wiki: GJUVwNSEkis3EXkrVj0ccbqdn8c, table: tbl1Q68oopST9Mel - prompt模板: `prompts/core_speaking_inquiry_prompts.py` #### 5. 看图说话 core_speaking_image(v6) - 8步LLM调用流水线 - 输入: 教研-导览配置 + 教研-对话配置 - 中间步骤: 学习流程配置, 语音识别热词 - 最终JSON: taskInfo, dialogConfig, imageInfo, optionList, questionList, studyInfo - Step7(dialogConfig)依赖Step6(questionList), Step8(studyInfo)依赖Step1(学习流程配置) - bitable wiki: KBOXwzVHfin6ORkKbA3c3eWEnoh, table: tblvi5HF0uSU2GNo - prompt模板: `prompts/core_speaking_image_prompts.py` ## 通用机制:resourceMapping **所有核心互动都使用统一的 resourceMapping 处理逻辑**,不是某个类型的特有字段: 1. **数据来源**: `parse_script.py` 提取两级角色映射: - `section_char_map`: 从文档"角色-section对应"表解析,按section分组 - `character_map`: 从sheet数据全局提取,作为fallback 2. **解析流程**: `generate_json.py` → `resolve_resource_mapping()` 解析section对应 → 格式化为 `"Name:ID"` 字符串 → 注入prompt的 `{角色配置}` 占位符 3. **LLM提取**: prompt模板统一指示LLM从 `{角色配置}` 提取 `{"name": int_id}` JSON对象 4. **npcName#id规则**: 部分类型(合作阅读、合作听力)在 textData/sequenceData 步骤中,npcName字段追加 `#id`(仅限npcName字段,不适用于content等字段) ## 已实现的核心互动类型(续) ### v7 — 听力类(3种,已完成) 详见 `prd/v7.md`,bitable 数据已验证 | 类型 | cType | LLM步数 | 输出字段 | bitable wiki | |------|-------|---------|---------|-------------| | 合作听力 | core_listening_order | 6 | taskInfo, materialInfo, flowInfo, studyInfo | FrxtwNRQDizqiikPkATcBzTCnYe | | 听力拖拽 | core_listening_drag | 7 | taskInfo, preDialog, dialogList, questionList, studyInfo | K3QrwQnWqiPBm1krhnNcWDTqnhe | | 听力选择 | core_listening_choose | 5 | taskInfo, questionGroup, studyInfo | Kwrcw6A4jip2sxkdLn4czd1knvf | - 输入: 合作听力用 `教研配置-任务` + `教研配置-材料`;听力拖拽/选择用 `教研配置-导览配置` + `教研配置-互动配置` - 中间步骤: 学习过程配置(LLM生成) + 互动描述(LLM生成) - 合作听力的听音选意用2个中文含义选项;听力拖拽/选择改为"对/错"判断题 - 所有taskInfo均包含 resourceMapping(通用机制) - 专有名词对照暂不实现,后续单独处理 - prompt模板: `prompts/core_listening_order_prompts.py`, `prompts/core_listening_drag_prompts.py`, `prompts/core_listening_choose_prompts.py` ## 待实现的核心互动类型 ### v8 — 写作类(4种,已完成) 详见 `prd/v8.md`,bitable 数据已验证 | 类型 | cType | LLM步数 | 输出字段 | bitable wiki | |------|-------|---------|---------|-------------| | 看图组句 | core_writing_imgMakeSentence | 6 | taskInfo, textInfo, studyInfo, evalInfo | BkmtwUBwMiHd5Ak7VS6ccE9SnHd | | 看图撰写 | core_writing_imgWrite | 6 | taskInfo, textInfo, studyInfo, evalInfo | KwPHwnaqdiWlvNkDm5fcFreDnQh | | 邮件组句 | core_writing_questionMakeSentence | 6 | taskInfo, textInfo, studyInfo, evalInfo | M5oTwUP6wiImC4kVJU8cRYnfnyf | | 邮件撰写 | core_writing_questionWrite | 6 | taskInfo, textInfo, studyInfo, evalInfo | Brn0wldKYizsLZkBqK6clp1tnKd | - 输入: `教研配置-任务信息` + `教研配置-全文信息` - 中间步骤: 学习流程配置(LLM生成) + 互动描述(LLM生成) - 4种类型共享通用6步流水线 `_generate_core_writing()` - 按输入源特征分为2个prompt文件: `core_writing_img_prompts.py`(看图类) + `core_writing_question_prompts.py`(邮件类) - 关键差异: 看图类stemDesc=图片列表+leadIn用image;邮件类stemDesc=题干描述+leadIn用desc - 组句类inputType=sentence(optionList+answer);撰写类inputType=write(answerText+hint) - prompt模板: `prompts/core_writing_img_prompts.py`, `prompts/core_writing_question_prompts.py` ### 其他未实现类型 - 口语独白、口语探讨 - 写作互动 ## v9 — 中互动 cDesc 互动描述预生成(已完成) 详见 `prd/v9.md` 为 10 种中互动类型增加 cDesc(互动描述)LLM 预生成步骤: - 信息类(6种): mid_message_trace/spell/combine/fillin/word/sentence - 图片类(4种): mid_image_choose/multiple/sequence/drag 实现方式: - 在 `_generate_with_template()` 中,jsonData 生成前调用 LLM 预生成互动描述 - 信息类使用 `CDESC_PROMPT_MESSAGE` 模板(输入: 互动名称 + 互动内容) - 图片类使用 `CDESC_PROMPT_IMAGE` 模板(输入: 互动名称 + 情境引入 + 互动内容 + 互动反馈 + 后置对话) - 生成结果注入 `parsed_fields["互动描述"]`,由主 prompt 模板映射到 jsonData 的 `cDesc` 字段 - 补全了 `mid_image_sequence` 模板中遗漏的 cDesc 字段定义 - 始终使用 LLM 生成,覆盖教研配置中可能存在的值 ## v10 — 知识点匹配 + 触发命令 + HTML增强(已完成) 详见 `prd/v10.md` ### 知识点匹配功能 - 新增 `scripts/kp_matcher.py`:连接 MySQL `vala_test.vala_kp` 表(2613条有效记录) - 两阶段匹配:title 精确/模糊粗召回 → LLM 多候选精筛(用于同名不同释义消歧) - kpInfo 中 `kpId` 从数据库 `kp_id` 字段获取,`kpType` 从 `type` 字段获取 - kpSkill 使用默认值(vocab→vocab_meaning, sentence→sentence_meaning) - MySQL 不可达时 fallback 到 kpId=null ### 集成改动 - `generate_json.py`:所有 `_try_rule_based_kp` 调用替换为 `generate_kp_info()` → `kp_matcher.match_knowledge_points()` - 所有核心互动生成器(12个)和中互动入口统一使用新接口 - 新增 `level` 参数贯穿 pipeline → generate_component → 各生成器 → kp_matcher ### 触发命令 - SKILL.md 添加触发场景:`*组件配置-json* {飞书剧本文档链接}` - 触发后执行完整 pipeline,返回 HTML 报告 ### HTML 增强 - 中互动组件在 HTML 报告中也展示 kpInfo section(之前仅核心互动展示) ## v11 — 字段重命名 + 交互式HTML + 推送功能(已完成) 详见 `prd/v11.md` ### 字段重命名(方案B:全量重命名为推送接口字段名) - 所有核心互动输出字段统一改名为推送接口字段名 - 映射: taskData→taskInfo, textData→materialInfo, sequenceData→flowInfo, learningData→studyInfo, settingData→dialogSetting, configData→dialogConfig, questionGroupData→questionGroup, studyData→studyInfo, preDialogData→preDialog, dialogListData→dialogList, questionListData→questionList - 涉及文件: generate_json.py, pipeline.py, db_manager.py, html_report.py, validate_core_v5.py ### 交互式HTML报告(v2) - 每个JSON section使用 textarea 可直接编辑 - kpId 使用下拉选择(显示粗筛 top10 候选) - 每个组件 header 内嵌两个推送按钮:[配置↑] [知识↑] - 顶部固定操作栏:一键推送全部 + 进度条 + 成功/失败统计 - 推送状态实时指示(loading/ok/fail) ### 推送接口 - POST https://api-test.valavala.com/content/feishu/notify - 中互动: `{"componentData": jsonData}` - 核心互动: `{"pushType":"core", ...各字段}`(按cType不同组装) - 知识点: `{"pushRelationKp": kpInfoObj}` ### kp_matcher增强 - 粗召回加 LIMIT 10 - 每条知识点匹配结果附带 `candidates` 字段(top10候选)供HTML下拉展示 ## 参考文档 - v11需求详细文档: `prd/v11.md` - v10需求详细文档: `prd/v10.md` - v9需求详细文档: `prd/v9.md` - v8需求详细文档: `prd/v8.md` - v7需求详细文档: `prd/v7.md` - v6需求详细文档: `prd/v6.md` - v5需求详细文档: `prd/v5.md` - v4需求详细文档: `prd/v4.md` - 组件类型注册表: `references/component_registry.md` ## v12 — 解析增强 + pipeline 自动 HTML + 进度输出(已完成) ### 组件行识别增强(parse_script.py) - 支持单行空格分隔格式: `"合作阅读 0000800"` → type_name + cId - 支持多行带前缀格式: `"核心互动- 囗语\n听力选择\n0000810"` → 跳过前缀取实际类型 - LLM 兜底: 正则无法提取时,如果 cell 含中文+5位以上数字,调 LLM 解析(带缓存) - 测试文档识别率: 15 → 42 组件 ### pipeline 自动生成交互式 HTML - 无需 `--dry-run --html` 参数,执行完自动生成 v2 交互式 HTML 报告 - 非 dry-run 模式也保留完整 jsonData/kpInfo 到 report results - report 返回 `html_path` 字段供外部调用者使用 ### 进度输出 - 每个组件完成后打印 ✓/✗ 状态行 - 每 5 个组件输出进度摘要(成功/失败/跳过计数) - 末尾输出最终统计 ### cType=None 优雅跳过 - 未实现类型(口语独白、口语探讨、写作互动)标记为 skipped,不触发异常 ## v13 — CORS 代理服务(已完成) ### 问题背景 用户直接打开本地HTML文件(file://协议)点击推送按钮时,浏览器发送 `Origin: null`, 目标API服务端校验 Origin 返回 403。curl 直接测试正常但浏览器无法绕过。 ### 解决方案:轻量代理中转服务 - 新增 `scripts/proxy_server.py`:基于 http.server + requests 的转发代理 - 新增 `config.json`:代理配置(外网IP、端口、速率限制、目标URL) - 代理只转发到固定目标地址,加上正确的 Origin 头 - HTML 报告中 API 地址改为代理地址 ### 安全措施 - 硬编码单一目标URL(不可被滥用为开放代理) - body 结构校验(必须含 componentData/pushRelationKp/pushType) - 可配置速率限制(默认 60 req/min/IP) - 专用端口 18080,用户在安全组中精确控制 ### 集成方式 - pipeline 执行时自动检测代理运行状态(GET /health) - 未运行则 subprocess 自动后台启动 - 代理 URL 传入 html_report 生成到 HTML 的默认 API 地址中 ### 配置文件 config.json ```json { "proxy": { "external_ip": "115.190.225.235", "port": 18080, "rate_limit_per_minute": 60, "target_url": "https://api-test.valavala.com/content/feishu/notify", "target_origin": "https://flow-test.valavala.com" } } ```