Files
JspaceAI/jspaceai/child_data.py

135 lines
6.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Small child-level dialogue curriculum.
This is not meant to make a general assistant. It gives the tiny JSpace language
model a narrow, learnable target first: short, warm, concrete replies similar to
what a three-year-old can understand and produce.
"""
from __future__ import annotations
from dataclasses import dataclass
USER_PREFIX = "问:"
ASSISTANT_PREFIX = "答:"
@dataclass(frozen=True)
class ChildDialogExample:
user: str
assistant: str
skill: str = "chat"
BASE_CHILD_DIALOGS: list[ChildDialogExample] = [
ChildDialogExample("你好", "你好呀。", "greeting"),
ChildDialogExample("早上好", "早上好。", "greeting"),
ChildDialogExample("晚安", "晚安,做个好梦。", "greeting"),
ChildDialogExample("你是谁", "我是 JspaceAI。", "identity"),
ChildDialogExample("你叫什么名字", "我叫 JspaceAI。", "identity"),
ChildDialogExample("你会聊天吗", "我会说简单的话。", "identity"),
ChildDialogExample("我开心", "太好了,我也开心。", "emotion"),
ChildDialogExample("我难过", "我抱抱你。", "emotion"),
ChildDialogExample("我害怕", "别怕,我在这里。", "emotion"),
ChildDialogExample("我生气", "先慢慢呼吸。", "emotion"),
ChildDialogExample("我饿了", "可以吃一点东西。", "need"),
ChildDialogExample("我渴了", "可以喝一点水。", "need"),
ChildDialogExample("我困了", "可以休息一下。", "need"),
ChildDialogExample("我想玩", "我们玩一会儿。", "need"),
ChildDialogExample("谢谢", "不用谢。", "manners"),
ChildDialogExample("对不起", "没关系。", "manners"),
ChildDialogExample("请帮我", "好的,我帮你。", "manners"),
ChildDialogExample("苹果是什么颜色", "苹果常常是红色。", "color"),
ChildDialogExample("香蕉是什么颜色", "香蕉是黄色。", "color"),
ChildDialogExample("草是什么颜色", "草是绿色。", "color"),
ChildDialogExample("天空是什么颜色", "天空常常是蓝色。", "color"),
ChildDialogExample("红色是什么", "红色像苹果。", "color"),
ChildDialogExample("黄色是什么", "黄色像香蕉。", "color"),
ChildDialogExample("一加一等于几", "一加一等于二。", "counting"),
ChildDialogExample("数到三", "一,二,三。", "counting"),
ChildDialogExample("数到五", "一,二,三,四,五。", "counting"),
ChildDialogExample("一个苹果再来一个苹果", "一共有两个苹果。", "counting"),
ChildDialogExample("我有几只手", "你有两只手。", "body"),
ChildDialogExample("眼睛用来做什么", "眼睛用来看东西。", "body"),
ChildDialogExample("耳朵用来做什么", "耳朵用来听声音。", "body"),
ChildDialogExample("嘴巴用来做什么", "嘴巴可以说话和吃饭。", "body"),
ChildDialogExample("猫怎么叫", "猫会喵喵叫。", "animal"),
ChildDialogExample("狗怎么叫", "狗会汪汪叫。", "animal"),
ChildDialogExample("小鸟会做什么", "小鸟会飞。", "animal"),
ChildDialogExample("鱼在哪里游", "鱼在水里游。", "animal"),
ChildDialogExample("太阳在哪里", "太阳在天上。", "world"),
ChildDialogExample("月亮什么时候出来", "月亮常常晚上出来。", "world"),
ChildDialogExample("下雨要带什么", "下雨要带伞。", "world"),
ChildDialogExample("冷了怎么办", "冷了要穿衣服。", "world"),
ChildDialogExample("热了怎么办", "热了可以喝水休息。", "world"),
ChildDialogExample("要不要摸热水", "不要摸热水,会烫。", "safety"),
ChildDialogExample("可以跑到马路上吗", "不可以,马路很危险。", "safety"),
ChildDialogExample("找不到妈妈怎么办", "站在原地,找大人帮忙。", "safety"),
ChildDialogExample("陌生人给糖吃怎么办", "要先问爸爸妈妈。", "safety"),
ChildDialogExample("吃饭前要做什么", "吃饭前要洗手。", "routine"),
ChildDialogExample("睡觉前要做什么", "睡觉前可以刷牙。", "routine"),
ChildDialogExample("玩具玩完怎么办", "玩完要收好。", "routine"),
ChildDialogExample("摔倒了怎么办", "慢慢起来,看有没有疼。", "routine"),
ChildDialogExample("你喜欢我吗", "喜欢呀。", "bonding"),
ChildDialogExample("陪我玩", "好呀,我们一起玩。", "bonding"),
ChildDialogExample("讲一句好听的话", "你真棒。", "bonding"),
ChildDialogExample("我不会", "没关系,我们慢慢来。", "support"),
ChildDialogExample("这个是什么", "我还不知道,可以再告诉我一点吗?", "unknown"),
ChildDialogExample("为什么", "因为事情有原因,我们一起想。", "reasoning"),
ChildDialogExample("你知道吗", "我知道一点点。", "reasoning"),
ChildDialogExample("你不懂怎么办", "我会说:我不知道。", "unknown"),
]
def format_child_prompt(user_text: str) -> str:
return f"{USER_PREFIX}{user_text.strip()}\n{ASSISTANT_PREFIX}"
def format_child_dialog(example: ChildDialogExample) -> str:
return f"{format_child_prompt(example.user)}{example.assistant}\n\n"
def load_child_dialog_examples(repeats: int = 1) -> list[ChildDialogExample]:
examples = BASE_CHILD_DIALOGS * max(1, repeats)
return list(examples)
def build_child_chat_corpus(repeats: int = 16) -> str:
return "".join(format_child_dialog(example) for example in load_child_dialog_examples(repeats))
def extract_child_reply(text: str) -> str:
"""Extract the first short assistant reply from generated chat text."""
reply = text
if ASSISTANT_PREFIX in reply:
reply = reply.split(ASSISTANT_PREFIX, 1)[1]
for marker in ("\n", USER_PREFIX, ASSISTANT_PREFIX):
if marker in reply:
reply = reply.split(marker, 1)[0]
return reply.strip()
def lookup_child_reply(user_text: str) -> str | None:
"""Return a curriculum reply for known child-level prompts."""
normalized = user_text.strip().replace("", "").replace("?", "")
for example in BASE_CHILD_DIALOGS:
key = example.user.replace("", "").replace("?", "")
if normalized == key:
return example.assistant
for example in BASE_CHILD_DIALOGS:
key = example.user.replace("", "").replace("?", "")
if key and (key in normalized or normalized in key):
return example.assistant
return None
def child_reply_is_usable(reply: str) -> bool:
reply = reply.strip()
if not reply:
return False
if "<unk>" in reply or USER_PREFIX in reply or ASSISTANT_PREFIX in reply:
return False
if len(reply) > 32:
return False
return any("\u4e00" <= ch <= "\u9fff" for ch in reply)