码道:成语接龙 · AI 对话
·
成语接龙 · AI 对话
一个基于 HTML5 + CSS3 + 原生 JavaScript 实现的成语接龙 AI 对话小游戏。
通过与智谱/DeepSeek 兼容的 GitCode AI 对话接口(OpenAI 流式协议)实时对话,
AI 会以成语「尾字开头」的规则与玩家接龙,并返回成语的拼音、释义、出处、例句,
在游戏中潜移默化地积累成语知识。
功能特性
- 双向接龙:AI 出成语,你按最后一个字来接,AI 再继续接,你来我往。
- 流式输出:基于
fetch + ReadableStream解析 SSE 流,AI 逐字返回(对应参考 Python 的stream=True迭代)。 - JSON 结构化返回:通过系统提示词要求 AI 只输出合法 JSON,前端解析后渲染为精美的「成语卡片」(含读音、释义、出处、例句)。
- 同音放宽:允许以同音字接龙,降低难度、便于教学。
- 国风界面:宣纸底色、朱砂与鎏金配色、卷轴式标题,纯 CSS 实现,无任何外部依赖。
- 移动端适配:响应式布局,支持手机浏览。
目录结构
ruanjianjishu6/
├── index.html # 主页面
├── style.css # 国风样式
├── config.js # AI 接口配置(地址 / 令牌 / 模型 / 系统提示词)
├── api.js # Python 流式调用的 JavaScript 版(fetch + SSE 解析)
├── app.js # 接龙游戏交互与成语卡片渲染
└── README.md # 项目说明
快速开始
- 下载/克隆本项目,直接双击打开
index.html即可运行(纯前端,无需构建)。若浏览器对
https://api-ai.gitcode.com存在跨域限制,可先在本目录启动本地静态服务:python3 -m http.server 8080 # 然后访问 http://localhost:8080 - 在输入框输入「开始」或任意一个字 / 一个成语,按回车或点击「发送」。
- AI 会立即接出一个成语并以卡片形式展示,末尾会提示你该以哪个字继续接龙。
- 持续输入,直到对局结束(AI 提示无法接龙),再输入「开始」即可重新开局。
配置说明
所有接口配置集中在 config.js 的 AI_CONFIG 中,与参考 Python 代码逐项对应:
| config.js 字段 | 参考 Python 代码中的对应位置 | 说明 |
|---|---|---|
API_URL | API_URL | 对话接口地址 |
API_KEY | headers["Authorization"] | Bearer 鉴权令牌 |
MODEL | payload["model"] | 模型名称 |
MAX_TOKENS | payload["max_tokens"] | 最大生成字数 |
TEMPERATURE | payload["temperature"] | 采样温度 |
TOP_P | payload["top_p"] | 核采样参数 |
FREQUENCY_PENALTY | payload["frequency_penalty"] | 频率惩罚 |
THINKING_BUDGET | payload["thinking_budget"] | 思考预算 |
SYSTEM_PROMPT | messages[0](新加入) | 系统提示词,约定 JSON 返回格式 |
系统提示词与 JSON 返回格式
在 config.js 的 SYSTEM_PROMPT 中,我们要求 AI 只输出一个合法的 JSON 对象,
这样前端 app.js 就能直接 JSON.parse 出结构化字段并渲染成语卡片,而不再只是显示一段对话文字。
成功接龙时的返回格式:
{
"status": "success",
"last_word": "上一个成语的最后一个字",
"idiom": "你接出的成语",
"pinyin": "成语的完整拼音",
"meaning": "成语释义",
"source": "成语出处",
"example": "一个自然的使用例句",
"next_hint": "让用户接着接的字"
}
无法接龙(对局结束)时的返回格式:
{
"status": "game_over",
"reason": "无法接龙的原因说明",
"suggestion": "可以重新开始的提示语"
}
前端在 app.js 的 extractJson() 中还做了容错解析:即使 AI 使用
markdown 代码块(json ... )包裹、或附带少量说明文字,也能提取出其中的 JSON。
技术实现:Python → JavaScript 转换对照
参考的 Python 调用核心逻辑如下:
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload, stream=True)
for line in response.iter_lines():
if not line.startswith(b"data:"):
continue
if line.strip() in (b"data:[DONE]", b"data: [DONE]"):
return
yield json.loads(line.decode("utf-8").lstrip("data:"))
在 api.js 中与之对应的 JavaScript 实现:
| Python(参考代码) | JavaScript(本项目) |
|---|---|
requests.post(..., stream=True) | fetch(API_URL, { method: "POST", headers, body }) |
json=payload 自动序列化 | body: JSON.stringify(payload) |
response.iter_lines() | response.body.getReader() + TextDecoder 按 \n 切行 |
line.startswith(b"data:") | line.trim().startsWith("data:") |
line.strip() == b"data:[DONE]" 结束判定 | data === "[DONE]" |
json.loads(line.decode("utf-8").lstrip("data:")) | JSON.parse(data),再经 extractDeltaText() 取出内容 |
chunk["choices"] | chunk.choices[0].delta.content(兼容 message.content) |
注意事项
- API Key 安全:本项目为教学演示,密钥直接写在
config.js中;正式部署请收紧密钥权限或改为服务端代理转发,避免泄露。 - 跨域 CORS:若浏览器直连被跨域策略拦截,可在服务端配置允许跨域,或将请求转发到本地代理后访问。
- 内容真实性:AI 生成的释义、出处可能不准确,仅供参考,请以权威词典为准。

更多推荐


所有评论(0)