#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 英语学习程序主脚本(Python版本) 实现对话流程、API集成和用户交互功能 """ import json import time import requests import os from typing import Dict, List, Optional # 导入数据 from data import english_data class GameState: """游戏状态管理类""" def __init__(self): self.current_scene_index = 0 self.current_dialog_index = 0 self.score = 0 self.total_questions = 0 self.correct_answers = 0 def reset(self): """重置游戏状态""" self.current_scene_index = 0 self.current_dialog_index = 0 self.score = 0 self.total_questions = 0 self.correct_answers = 0 class EnglishLearningApp: """英语学习应用主类""" def __init__(self): self.game_state = GameState() self.current_scene = None self.api_key = os.getenv("DEEPSEEK_API_KEY", "your-api-key-here") self.api_url = "https://api.deepseek.com/v1/chat/completions" def load_scene(self, scene_index: int) -> bool: """加载指定场景""" if scene_index < 0 or scene_index >= len(english_data["scenes"]): print("所有场景已完成!") return False self.current_scene = english_data["scenes"][scene_index] self.game_state.current_scene_index = scene_index self.game_state.current_dialog_index = 0 print("\n" + "=" * 50) print(f"场景:{self.current_scene['title']}") print(f"描述:{self.current_scene['description']}") print("=" * 50) # 加载场景图片(在命令行环境下仅显示图片路径) self._load_scene_image() # 开始对话 self.show_next_dialog() return True def _load_scene_image(self): """加载场景图片""" scene = self.current_scene image_path = scene.get("image", "") if not image_path: # 自动查找图片 possible_extensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg"] base_name_id = str(scene["id"]) # 简单的拼音转换(仅保留字母数字) base_name_title = ''.join(c for c in scene["title"] if c.isalnum()).lower() all_possible_paths = [ # 优先使用ID命名 *[f"images/{base_name_id}{ext}" for ext in possible_extensions], # 支持标题命名 *[f"images/{base_name_title}{ext}" for ext in possible_extensions] ] for path in all_possible_paths: if os.path.exists(path): image_path = path break if image_path and os.path.exists(image_path): print(f"图片:{image_path}") else: print("图片:无") def show_next_dialog(self): """显示下一条对话""" if not self.current_scene: return conversation = self.current_scene["conversation"] dialog_index = self.game_state.current_dialog_index if dialog_index >= len(conversation): # 当前场景对话结束 self._scene_complete() return dialog = conversation[dialog_index] if dialog["type"] == "user_question": # 区分选择题和自由回答题 if "options" in dialog: self._show_question(dialog) else: self._show_dynamic_question(dialog) else: # 显示普通对话 self._add_message(dialog) # 自动显示下一个对话 self.game_state.current_dialog_index += 1 time.sleep(1) self.show_next_dialog() def _add_message(self, dialog: Dict): """添加对话消息""" speaker = dialog["speaker"] text = dialog["text"] print(f"\n{speaker}: {text}") def _show_question(self, dialog: Dict): """显示选择题""" print(f"\n{dialog['question']}") for i, option in enumerate(dialog["options"]): print(f"{i + 1}. {option}") # 获取用户输入 try: user_choice = int(input("请输入选项编号:")) - 1 if 0 <= user_choice < len(dialog["options"]): self._check_answer(dialog, user_choice) else: print("无效的选项,请重新选择!") self._show_question(dialog) except ValueError: print("请输入有效的数字!") self._show_question(dialog) def _show_dynamic_question(self, dialog: Dict): """显示动态问题(使用API调用)""" print(f"\n{dialog['question']}") user_input = input("请输入您的回答:") # 保存用户输入到对话历史 self._save_user_input(dialog, user_input) # 获取AI响应 ai_response = self._get_ai_response(user_input) # 显示AI响应 print(f"\nAI响应: {ai_response}") # 继续对话 self.game_state.current_dialog_index += 2 # 跳过用户问题和AI响应 self.show_next_dialog() def _save_user_input(self, dialog: Dict, user_input: str): """保存用户输入到对话历史""" if not self.current_scene: return conversation = self.current_scene["conversation"] dialog_index = self.game_state.current_dialog_index # 插入用户输入 user_message = { "speaker": "我", "text": user_input, "type": "user" } conversation.insert(dialog_index + 1, user_message) # 插入AI响应占位符 ai_message = { "speaker": "AI", "text": "", "type": "other" } conversation.insert(dialog_index + 2, ai_message) def _get_ai_response(self, user_input: str) -> str: """获取AI响应""" if not self.api_key: return "抱歉,API密钥未配置,无法获取AI响应。" try: # 构建对话历史 messages = [ {"role": "system", "content": "你是一位英语学习助手,帮助用户进行日常对话练习。请用英语回复,保持对话自然流畅。"} ] # 添加当前对话历史 if self.current_scene: for dialog in self.current_scene["conversation"][:self.game_state.current_dialog_index + 1]: role = "assistant" if dialog["speaker"] != "我" else "user" content = dialog.get("text", dialog.get("question", "")) messages.append({"role": role, "content": content}) # 添加用户最新输入 messages.append({"role": "user", "content": user_input}) # 调用API headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } payload = { "model": "deepseek-chat", "messages": messages, "stream": True } response = requests.post(self.api_url, headers=headers, json=payload, stream=True) response.raise_for_status() # 处理流式响应 ai_response = "" print("\nAI正在思考...", end="", flush=True) for chunk in response.iter_content(chunk_size=None): if chunk: decoded_chunk = chunk.decode("utf-8") # 解析SSE格式 lines = decoded_chunk.split("\n") for line in lines: if line.startswith("data: "): data = line[6:].strip() if data != "[DONE]": try: json_data = json.loads(data) if "choices" in json_data and json_data["choices"]: delta = json_data["choices"][0].get("delta", {}) if "content" in delta: content = delta["content"] ai_response += content print(content, end="", flush=True) except json.JSONDecodeError: continue print() # 换行 return ai_response if ai_response else "抱歉,无法生成响应。" except requests.exceptions.RequestException as e: print(f"\nAPI调用错误: {e}") return "抱歉,API调用失败。" def _check_answer(self, dialog: Dict, user_choice: int): """检查答案""" is_correct = user_choice == dialog["correctAnswer"] if is_correct: self.game_state.correct_answers += 1 print("\n✅ 回答正确!") else: correct_answer = dialog["options"][dialog["correctAnswer"]] print(f"\n❌ 回答错误!正确答案是:{correct_answer}") self.game_state.total_questions += 1 self.game_state.score += 1 if is_correct else 0 # 更新进度 self.update_progress() # 继续对话 self.game_state.current_dialog_index += 1 time.sleep(1) self.show_next_dialog() def _scene_complete(self): """场景完成""" print("\n" + "=" * 50) print("当前场景对话已完成!") print("=" * 50) if self.game_state.current_scene_index < len(english_data["scenes"]) - 1: # 询问是否进入下一个场景 next_scene = input("是否进入下一个场景?(y/n): ") if next_scene.lower() == "y": next_index = self.game_state.current_scene_index + 1 self.load_scene(next_index) else: print("\n🎉 所有场景已完成!") self._show_final_score() def _show_final_score(self): """显示最终得分""" if self.game_state.total_questions > 0: accuracy = (self.game_state.correct_answers / self.game_state.total_questions) * 100 print(f"\n最终得分: {self.game_state.score}") print(f"正确率: {accuracy:.1f}%") print(f"总题目数: {self.game_state.total_questions}") print(f"正确答案: {self.game_state.correct_answers}") else: print("\n未完成任何题目") def update_progress(self): """更新进度信息""" total_scenes = len(english_data["scenes"]) current_scene = self.game_state.current_scene_index + 1 print(f"\n进度:场景 {current_scene}/{total_scenes} | 得分:{self.game_state.score}") def start(self): """启动应用""" print("欢迎使用英语学习程序!") print("=" * 50) # 加载第一个场景 self.load_scene(0) if __name__ == "__main__": # 创建应用实例 app = EnglishLearningApp() # 启动应用 app.start()