#!/usr/bin/env python3
"""
看图选词 (core_reading_imageDrag) 多步 LLM prompt 模板

生成流水线：
  Step 1: 学习流程配置 (intermediate text)
  Step 2: 互动描述 (intermediate text)
  Step 3: taskInfo → taskData JSON
  Step 4: questionGroup → questionGroupData JSON
  Step 5: studyInfo → studyData JSON
"""

# ── Step 1: 学习流程配置 ──
STEP1_LEARNING_FLOW = r"""你是一个英语学习任务的教学流程设计助手。请你根据以下提供的信息，生成一个结构化的学习引导内容，用于引导孩子逐轮完成一个英语对话任务。

# 你的任务
参考 {互动配置} 和 {用户任务知识}，理解整个对话互动流程，然后生成一个 markdown 格式的教学流程。

每个题目需要包含两个步骤：
据义选词题：针对该题涉及的核心词汇或语法点进行先行讲解和测试。
原题降级：通过中文解析题干和缩小选项范围，引导孩子完成原始题目。

## 规则要求
* **互动结构**：每道题必须包含"知识点讲解"和"原题降级"两个互动回合。
* **选项逻辑**：
    * 选项：提供三个英文选项（1 正确[标识在选项内容后] + 2 干扰），每个选项附带 Brainy 的反馈
    * 若选项正确，Brainy 鼓励孩子朗读该句
    * 若选项错误，Brainy 用自然语言解释为什么该句不合适，避免批评，鼓励再尝试，告知再选一次。
    * 正确项标注 `[正确]`。

中间回合(通常1~3回合)：
- {{npc角色名}}：NPC 的英文发言（来自示例对话）
- Brainy：用中文解释该发言的意思，并引导孩子理解当前情境要做什么
- 选项：提供三个英文选项（1 正确[标识在选项内容后] + 2 干扰），每个选项附带 Brainy 的反馈
  - 若选项正确，Brainy 鼓励孩子朗读该句
  - 若选项错误，Brainy 用自然语言解释为什么该句不合适，避免批评，鼓励再尝试，告知再选一次。

结尾回合:
- {{npc角色名}}：NPC 的发言
- Brainy：友好地向用户表示任务已经完成。

注意：
所有{{npc角色名}}从{对话信息}中的对话角色抽取

# 输出格式
```
# 小题 X
## 材料内容
【展示该小题对应的图片 ID】

## 互动题目
### 1. 句意选词题
Brainy：（结合【用户任务知识】，引出本题考查的核心词汇/知识点）
- 选项 A（错误）
  Brainy：（解释词义，说明为什么不合适，鼓励再试）
- 选项 B（正确）
  Brainy：（确认正确，重复中文释义，鼓励孩子学会了）

### 2. 原题降级
Brainy：（用中文解释题干的意思，带入情境，解决看不懂的问题）
- 选项 A（正确）
  Brainy：答对了！（解释在该情境下的意义），引导大声朗读。
- 选项 B（错误）
  Brainy：（说明逻辑错误点，提示根据图片或题意再试一次）

---
（所有题目完成后）
# 完结反馈
Brainy：太棒了！你复习了所有的关键知识点...（鼓励话术）
```

#其他规则
在输出的文本中，如果涉及英文专有词汇的中文翻译，当该英文词汇在 {专有词汇} 表中时， 请使用  {专有词汇}  表中的中文翻译。

# 输入
 {互动配置} :
$互动配置$

 {用户任务知识}:
$用户任务知识$

{专有词汇}:
$专有词汇$

# 输出
现在请按照上述信息和要求，直接输出目标内容。
如果 {互动配置} 或{用户任务知识}内容为空，则直接输出"无"。"""


# ── Step 2: 互动描述 ──
STEP2_INTERACTION_DESC = r"""# 任务目标
你是一个儿童英语学习内容生成助手。现在有一个阅读理解互动配置，需要将其转写为对话记录中的叙事化描述，用于回顾剧情。

# 背景知识
阅读理解组件的定义：
- 阅读理解是剧情中的核心互动，要求孩子阅读一份或多份材料（如手册、指南、信件、邮件等），并回答多个问题才能通过。
- 互动内容（即孩子阅读材料并作答的过程）需要转写为一段自然的叙事描述。
- 叙事的作用是：让回顾对话时看起来像故事的进展，而不是练习题。
- 如果有多份材料（材料 1、材料 2…），则每份材料生成一条独立描述。

# 输入信息
- 任务信息：$用户任务描述$
- 阅读材料：$互动配置$

# 输出要求
1. 每份材料生成一条自然叙事描述。
2. 多条描述之间用换行分隔，不要插入空白行。
3. 每条描述以英文为主，中文放在括号中，必须在同一段话里。
4. 每条描述长度约 40–60 英文词，适合总结该材料的关键信息。
5. 每条描述必须包含对应材料中的核心信息，并结合正确答案来组织内容。
6. 描述要自然，像剧情推进，而不是答题总结。
7. 避免教学感，不能出现"问题""选项""正确答案"等字眼。
8. 输出时只返回最终的描述文本，不要解释，不要使用额外的样式。"""


# ── Step 3: taskInfo ──
STEP3_TASK_INFO = r"""# 字段内容要求
{
    "cType": "core_reading_imageDrag",
    "cId": "$ID$",
    "title": {用户任务描述}中的 【任务标题】,
    "taskDesc": {用户任务描述}中的【任务描述】,
    "sceneDesc": {用户任务描述}中的【任务背景】,
    "key"(只基于{用户任务知识} 部分做结构化抽取，**不要改动或添加文本内容 以及 标点符号**):
    [
        {
            "desc": "",
            "keyList": [
                {
                    "type": "default",
                    "content": 英文句字或单词,
                    "desc": 句子的中文翻译 或 词性+单词释义
                }
            ]
        }
    ],
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型):
    {
    样例:
    "Tom":43,
    "Jerry":10
    },
    "cDesc": "xxx"
}

# 输出格式
单行json输出。
样例:
{"cId":"0000999","cType":"core_reading_imageDrag","title":"从一堆工具中找出颜色相同的工具","taskDesc":"回答 Celina 的问题，找出成套的工具，复原工具箱","sceneDesc":"场景描述，场景描述，看图说话场景描述","key":[{"desc":"","keyList":[{"type":"default","content":"passport"},{"type":"default","content":"suitcase"},{"type":"default","content":"clothes"},{"type":"default","content":"pack"}]}],"resourceMapping":{"brainy":291,"jack":210},"cDesc":"xxxxxxxxxxx"}

# 输入
{ID}:
$ID$
{用户任务描述}:
$用户任务描述$
{用户任务知识}:
$用户任务知识$
{角色配置}:
$角色配置$
{互动描述}：
$互动描述$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***
如果{用户任务描述} 或者 {用户任务知识}中没有有效文本，则输出"无"。"""


# ── Step 4: questionGroup ──
STEP4_QUESTION_GROUP = r"""# 字段内容要求
按以下格式从{配置材料}抽取:
[
  {
    "image": "{ID}_00.png",
    "questionList": [{
      "type": "npc",
      "npcName": "Brainy",
      "content": "xxxxx",
      "title": "xxxxx",
      "desc": "Which zoo did ___ and Tina go ____ weekend?",
      "optionList": [
        {"option": "Mum"},
        {"option": "las"},
        {"option": "last"}
      ],
      "answer": [0]
      }
    ]
  }
]

注意:
- "content" 和 "title" 互斥：题干最后有（音频）才有 content 字段，没有（音频）才有 title 字段。
- "desc" 从答题区中提取，如果答题区为无则为"___"。
- "answer" 从选项中带（正确）的提取对应索引。

# 输出格式
单行json输出。
(注意，前后不带任何额外符号。)

# 输入
{配置材料}:
$配置材料$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本。前后不要输出任何额外符号！！！直接以"["开头***    或者  直接输出 "无"。"""


# ── Step 5: studyInfo ──
STEP5_STUDY_INFO = r"""# 从{学习流程配置}字段内容要求
{
    "learningPart": [
    {
      "image": "xxxxxx_xx.png",
      "learning": [
      {
        "question": {
        "type": "npc",
        "npcName": "Brainy",
        "content": "..."
      },
      "optionList": [
      {
        "option": "...",
        "feedback": {
          "type": "npc",
          "npcName": "Brainy",
          "content": "..."
         }
       }],
      "answer": [0]
     },
     {
        "question": {
          "type": "npc",
          "npcName": "Brainy",
          "content": "..."
        },
        "optionList": [{
          "option": "xxx",
          "feedback": {
            "type": "npc",
            "npcName": "Brainy",
            "content": "xxxx"
          }
        }],
        "answer": [0]
      }
      ]
    }
    ],
    "closing": {
        "type": "npc",
        "npcName": "Brainy",
        "content": "xxxx"
    }
}

注意: 双引号字符串文本中如果出现英文双引号，需要使用转义符确保最终输出是合法的json。

# 输入
{学习流程配置}:
$学习流程配置$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***
如果{学习流程配置}中没有有效文本，则输出"无"。"""


# ── Steps registry ──
CORE_IMAGEDRAG_STEPS = {
    "step1_learning_flow": {
        "template": STEP1_LEARNING_FLOW,
        "description": "学习流程配置",
        "output_type": "text",
    },
    "step2_interaction_desc": {
        "template": STEP2_INTERACTION_DESC,
        "description": "互动描述",
        "output_type": "text",
    },
    "step3_task_info": {
        "template": STEP3_TASK_INFO,
        "description": "taskInfo",
        "output_type": "json",
    },
    "step4_question_group": {
        "template": STEP4_QUESTION_GROUP,
        "description": "questionGroup",
        "output_type": "json",
    },
    "step5_study_info": {
        "template": STEP5_STUDY_INFO,
        "description": "studyInfo",
        "output_type": "json",
    },
}


def build_imagedrag_prompt(step_key, replacements):
    """Build a prompt for a given step by replacing $placeholder$ tokens."""
    info = CORE_IMAGEDRAG_STEPS[step_key]
    prompt = info["template"]
    for key, val in replacements.items():
        prompt = prompt.replace(f"${key}$", str(val) if val else "")
    return prompt
