192 lines
7.3 KiB
Python
192 lines
7.3 KiB
Python
|
|
import streamlit as st
|
|||
|
|
import requests
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
from dotenv import load_dotenv
|
|||
|
|
import os
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
# 加载环境变量
|
|||
|
|
load_dotenv()
|
|||
|
|
|
|||
|
|
# 设置API密钥
|
|||
|
|
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "sk-b04b9134730c4375a5789e2e00978ee0")
|
|||
|
|
API_BASE_URL = "https://api.deepseek.com/v1/chat/completions"
|
|||
|
|
|
|||
|
|
# 定义Pydantic数据模型
|
|||
|
|
class IdiomResponse(BaseModel):
|
|||
|
|
idiom: str = Field(..., description="成语")
|
|||
|
|
meaning: str = Field(..., description="成语含义")
|
|||
|
|
pinyin: str = Field(..., description="拼音")
|
|||
|
|
explanation: str = Field(..., description="详细解释")
|
|||
|
|
|
|||
|
|
class GameState(BaseModel):
|
|||
|
|
current_idiom: str = Field(default="", description="当前成语")
|
|||
|
|
history: list = Field(default_factory=list, description="成语接龙历史")
|
|||
|
|
score: int = Field(default=0, description="得分")
|
|||
|
|
is_game_over: bool = Field(default=False, description="游戏是否结束")
|
|||
|
|
|
|||
|
|
# 初始化游戏状态
|
|||
|
|
if "game_state" not in st.session_state:
|
|||
|
|
st.session_state.game_state = GameState()
|
|||
|
|
|
|||
|
|
# 调用DeepSeek API生成下一个成语
|
|||
|
|
def get_next_idiom(last_idiom: str) -> IdiomResponse:
|
|||
|
|
headers = {
|
|||
|
|
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 构建提示词
|
|||
|
|
prompt = f"请你作为一个成语接龙游戏的助手,根据最后一个成语的最后一个字,生成下一个成语。上一个成语是:{last_idiom}。请严格按照JSON格式返回:{{\"idiom\": \"成语\", \"meaning\": \"简短含义\", \"pinyin\": \"拼音\", \"explanation\": \"详细解释\"}},不要添加任何其他内容。"
|
|||
|
|
|
|||
|
|
payload = {
|
|||
|
|
"model": "deepseek-chat",
|
|||
|
|
"messages": [
|
|||
|
|
{"role": "system", "content": "你是一个中文成语专家,精通成语接龙游戏。"},
|
|||
|
|
{"role": "user", "content": prompt}
|
|||
|
|
],
|
|||
|
|
"temperature": 0.3,
|
|||
|
|
"response_format": {"type": "json_object"}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
response = requests.post(API_BASE_URL, headers=headers, json=payload, timeout=30.0)
|
|||
|
|
response.raise_for_status()
|
|||
|
|
data = response.json()
|
|||
|
|
|
|||
|
|
# 解析API响应
|
|||
|
|
content = data["choices"][0]["message"]["content"]
|
|||
|
|
return IdiomResponse.model_validate_json(content)
|
|||
|
|
|
|||
|
|
# 检查用户输入的成语是否有效
|
|||
|
|
def validate_user_idiom(user_idiom: str, last_idiom: str) -> bool:
|
|||
|
|
if len(user_idiom) != 4:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
if last_idiom and user_idiom[0] != last_idiom[-1]:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 重置游戏
|
|||
|
|
def reset_game():
|
|||
|
|
st.session_state.game_state = GameState()
|
|||
|
|
|
|||
|
|
# 主应用界面
|
|||
|
|
st.title("🎯 成语接龙游戏")
|
|||
|
|
st.write("与AI一起玩成语接龙,看看谁的成语储备更丰富!")
|
|||
|
|
|
|||
|
|
# 游戏控制区
|
|||
|
|
col1, col2 = st.columns(2)
|
|||
|
|
with col1:
|
|||
|
|
if st.button("🎮 开始新游戏", type="primary"):
|
|||
|
|
reset_game()
|
|||
|
|
|
|||
|
|
with col2:
|
|||
|
|
if st.button("📊 查看规则"):
|
|||
|
|
st.info("""
|
|||
|
|
**成语接龙规则:**
|
|||
|
|
1. 游戏开始时,AI会先出一个成语
|
|||
|
|
2. 玩家需要接一个以AI成语最后一个字开头的四字成语
|
|||
|
|
3. AI会继续接玩家的成语
|
|||
|
|
4. 如此循环,直到一方无法接出成语
|
|||
|
|
5. 每成功接一个成语,得分+1
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# 游戏状态显示
|
|||
|
|
st.markdown("---")
|
|||
|
|
|
|||
|
|
# 初始状态:AI先出成语
|
|||
|
|
if not st.session_state.game_state.current_idiom and not st.session_state.game_state.is_game_over:
|
|||
|
|
with st.spinner("🤖 AI正在思考第一个成语..."):
|
|||
|
|
try:
|
|||
|
|
# 使用一个默认的起始成语让AI开始
|
|||
|
|
initial_idiom = get_next_idiom("开门见山")
|
|||
|
|
st.session_state.game_state.current_idiom = initial_idiom.idiom
|
|||
|
|
st.session_state.game_state.history.append({
|
|||
|
|
"role": "ai",
|
|||
|
|
"idiom": initial_idiom.idiom,
|
|||
|
|
"meaning": initial_idiom.meaning,
|
|||
|
|
"pinyin": initial_idiom.pinyin,
|
|||
|
|
"explanation": initial_idiom.explanation
|
|||
|
|
})
|
|||
|
|
except Exception as e:
|
|||
|
|
st.error(f"🤖 AI出错了:{str(e)}")
|
|||
|
|
st.session_state.game_state.is_game_over = True
|
|||
|
|
|
|||
|
|
# 游戏进行中
|
|||
|
|
if st.session_state.game_state.current_idiom and not st.session_state.game_state.is_game_over:
|
|||
|
|
# 显示当前成语
|
|||
|
|
current = st.session_state.game_state.history[-1]
|
|||
|
|
st.markdown(f"\n**🤖 AI 出的成语:** {current['idiom']}")
|
|||
|
|
st.caption(f"拼音:{current['pinyin']} | 含义:{current['meaning']}")
|
|||
|
|
|
|||
|
|
with st.expander("查看详细解释"):
|
|||
|
|
st.write(current['explanation'])
|
|||
|
|
|
|||
|
|
# 用户输入区
|
|||
|
|
user_input = st.text_input(
|
|||
|
|
f"\n请接一个以'**{st.session_state.game_state.current_idiom[-1]}**'开头的四字成语:",
|
|||
|
|
placeholder="例如:xxx",
|
|||
|
|
key="user_idiom_input"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 提交按钮
|
|||
|
|
if st.button("✅ 提交", key="submit_btn"):
|
|||
|
|
if validate_user_idiom(user_input, st.session_state.game_state.current_idiom):
|
|||
|
|
# 验证通过,记录用户的成语
|
|||
|
|
st.session_state.game_state.history.append({
|
|||
|
|
"role": "user",
|
|||
|
|
"idiom": user_input,
|
|||
|
|
"meaning": "",
|
|||
|
|
"pinyin": ""
|
|||
|
|
})
|
|||
|
|
st.session_state.game_state.score += 1
|
|||
|
|
|
|||
|
|
# AI 接成语
|
|||
|
|
with st.spinner("🤖 AI正在思考..."):
|
|||
|
|
try:
|
|||
|
|
next_idiom = get_next_idiom(user_input)
|
|||
|
|
st.session_state.game_state.current_idiom = next_idiom.idiom
|
|||
|
|
st.session_state.game_state.history.append({
|
|||
|
|
"role": "ai",
|
|||
|
|
"idiom": next_idiom.idiom,
|
|||
|
|
"meaning": next_idiom.meaning,
|
|||
|
|
"pinyin": next_idiom.pinyin,
|
|||
|
|
"explanation": next_idiom.explanation
|
|||
|
|
})
|
|||
|
|
st.rerun()
|
|||
|
|
except Exception as e:
|
|||
|
|
st.success("🎉 AI接不上来,你赢了!")
|
|||
|
|
st.session_state.game_state.is_game_over = True
|
|||
|
|
else:
|
|||
|
|
st.error("❌ 无效的成语!请确保是四字成语且第一个字与上一个成语的最后一个字相同。")
|
|||
|
|
|
|||
|
|
# 游戏结束
|
|||
|
|
if st.session_state.game_state.is_game_over:
|
|||
|
|
st.markdown("\n---")
|
|||
|
|
st.success(f"🎉 游戏结束!你的得分:{st.session_state.game_state.score}")
|
|||
|
|
|
|||
|
|
# 显示历史记录
|
|||
|
|
if st.session_state.game_state.history:
|
|||
|
|
st.markdown("\n📝 **游戏历史:**")
|
|||
|
|
for i, item in enumerate(st.session_state.game_state.history):
|
|||
|
|
role = "🤖 AI" if item["role"] == "ai" else "👤 你"
|
|||
|
|
st.write(f"{i+1}. {role}: {item['idiom']}")
|
|||
|
|
|
|||
|
|
# 侧边栏信息
|
|||
|
|
with st.sidebar:
|
|||
|
|
st.markdown("## 📊 游戏统计")
|
|||
|
|
st.write(f"**当前得分:** {st.session_state.game_state.score}")
|
|||
|
|
st.write(f"**接龙次数:** {len(st.session_state.game_state.history)}")
|
|||
|
|
|
|||
|
|
if st.session_state.game_state.history:
|
|||
|
|
st.markdown("\n## 📖 最近成语")
|
|||
|
|
for i, item in enumerate(reversed(st.session_state.game_state.history[-5:])):
|
|||
|
|
role = "🤖" if item["role"] == "ai" else "👤"
|
|||
|
|
st.write(f"{role} {item['idiom']}")
|
|||
|
|
|
|||
|
|
st.markdown("\n## 📌 提示")
|
|||
|
|
st.write("- 确保输入的是标准四字成语")
|
|||
|
|
st.write("- 注意汉字的正确写法")
|
|||
|
|
st.write("- 可以使用同音字进行接龙")
|