diff options
author | DogKing <dogking@DESKTOP-35DN20C.> | 2025-09-13 16:57:55 +0800 |
---|---|---|
committer | DogKing <dogking@DESKTOP-35DN20C.> | 2025-09-13 16:57:55 +0800 |
commit | c53865f73972fa8a0070c2075c7649a97601a63a (patch) | |
tree | a6d3be4d276e0b33247757666d19ee7518ee5f28 | |
parent | b9bea8689d72270e2ac37e89da958f01737f218e (diff) |
-rw-r--r-- | recitalMachine2.py | 287 |
1 files changed, 163 insertions, 124 deletions
diff --git a/recitalMachine2.py b/recitalMachine2.py index 3db1785..4a328e5 100644 --- a/recitalMachine2.py +++ b/recitalMachine2.py @@ -6,16 +6,36 @@ from datetime import datetime import os import random from collections import defaultdict +from uuid import uuid4 +from typing import Dict +import threading + #TODO #Restart game - Done - Need to reset iterator -#Local knowledge base -#dynamic difficulty +#Local knowledge base - Done +#dynamic difficulty - Done #save log locally - Done +#multi user status + QUESTIONS_DATASET_PATH='./recitalMachine/recitalMachine_dataset.json' QUESTION_MODE='LOCAL' #LOCAL:本地题库,AI:完全由AI负责出题 +class GameStatus: + def __init__(self): + # 游戏状态 + self.questionIterator=QuestionIterator() + self.conversation_history_hidden=[] + self.correct_count=0 + self.is_correct=False + self.difficulty_level=1 + self.is_game_over=False + self.initial_message=[] + self.next_question=None + self.conversation_history_hidden.append({"role": "system", "content": GameController.system_prompt}) + GameController.get_initial_chat_display(self) + class GameController: model="Moonshot-Kimi-K2-Instruct" #model="deepseek-v3" @@ -43,29 +63,16 @@ class GameController: 4. **终止条件**: 除非皇子主动哭泣、求饶(说出“我错了”、“别打了”、“疼”等类似词),否则绝不停下出题。一旦皇子求饶,你可表现出失望又略带一丝心疼的情绪,并结束考验。结束时总结一共答对了几题,答错了几题,惩罚有哪些,并输出<游戏结束>作为标记。 """ - def __init__(self): - # 游戏状态 - self.questionIterator=QuestionIterator() - self.game_state = { - "conversation_history_hidden": [], # 对话历史,AI看到的 - "correct_count": 0, # 连续答对次数 - "is_correct": False, # 总答题数 - "difficulty_level": 1, # 难度等级 (1, 2, 3) - "is_game_over": False, # 游戏是否结束 - "initial_message": [], - "next_question": None, - } - - self.game_state["conversation_history_hidden"].append({"role": "system", "content": GameController.system_prompt}) - self.get_initial_chat_display() - - def get_ai_response(self): + initial_message = "(在书房里恭敬地站在你面前) 父皇今日可要考校儿臣功课?" + + @staticmethod + def get_ai_response(g:GameStatus): ''' Given the current hidden conversation history, get AI response, and append the response in the history ''' response = GameController.client.chat.completions.create( model=GameController.model, - messages=self.game_state["conversation_history_hidden"], + messages=g.conversation_history_hidden, temperature=0.7, # 温度不宜过高,保证出题的准确性 top_p=0.95, stream=True, @@ -80,12 +87,12 @@ class GameController: yield chunk_content # 逐块返回 # 将完整的AI回复加入历史 - self.game_state["conversation_history_hidden"].append({"role": "assistant", "content": full_response}) - self.update_status(full_response) - + g.conversation_history_hidden.append({"role": "assistant", "content": full_response}) + GameController.update_status(g,full_response) - def chat_with_ai(self,message, chat_history): + @staticmethod + def chat_with_ai(g:GameStatus,message, chat_history): ''' Take the chat history from gradio, get ai response and return the updated chat history @params @@ -93,101 +100,105 @@ class GameController: chat_history: a list of chat history visible to users ''' # 添加用户消息到历史 - self.game_state["conversation_history_hidden"].append({"role": "user", "content": message}) - if not self.game_state['is_game_over']: - if self.game_state['is_correct']: - self.hint_next_question() - self.game_state['is_correct'] = False + g.conversation_history_hidden.append({"role": "user", "content": message}) + if not g.is_game_over: + if g.is_correct: + GameController.hint_next_question(g) + g.is_correct = False chat_history.append({'role':'user','content':message}) chat_history.append({'role':'assistant', 'content':""}) # 获取流式响应并逐步更新聊天界面 full_response = "" - for chunk in self.get_ai_response(): + for chunk in GameController.get_ai_response(g): full_response += chunk chat_history[-1] = {'role':'assistant', 'content': full_response} - yield "", chat_history # 逐步更新界面 + yield chat_history # 逐步更新界面 - return "", chat_history + return chat_history - def get_initial_chat_display(self): - initial_message = "(在书房里恭敬地站在你面前) 父皇今日可要考校儿臣功课?" - self.game_state["conversation_history_hidden"].append({"role": "user", "content": initial_message}) - self.hint_next_question() + @staticmethod + def get_initial_chat_display(g: GameStatus): + + g.conversation_history_hidden.append({"role": "user", "content": GameController.initial_message}) + GameController.hint_next_question(g) # 获取初始响应(非流式) response = GameController.client.chat.completions.create( model=GameController.model, - messages=self.game_state["conversation_history_hidden"], + messages=g.conversation_history_hidden, temperature=0.7, top_p=0.95 ) ai_response = response.choices[0].message.content.strip() - self.game_state["conversation_history_hidden"].append({"role": "assistant", "content": ai_response}) - self.update_status(ai_response) + g.conversation_history_hidden.append({"role": "assistant", "content": ai_response}) + GameController.update_status(g,ai_response) - self.game_state['initial_message'].append({'role':'user','content':initial_message}) - self.game_state['initial_message'].append({'role':'assistant','content':ai_response}) + g.initial_message.append({'role':'user','content':GameController.initial_message}) + g.initial_message.append({'role':'assistant','content':ai_response}) - def update_status(self,ai_response): + @staticmethod + def update_status(g: GameStatus,ai_response): end_mark="游戏结束" - if not self.game_state['is_game_over']: + if not g.is_game_over: if end_mark in ai_response: - self.game_state['is_game_over']=True + g.is_game_over=True return - if self.game_state['next_question'] in ai_response: - self.game_state['is_correct'] = True - self.game_state['correct_count'] += 1 - self.game_state['difficulty_level'] += 1 + if g.next_question in ai_response: + g.is_correct = True + g.correct_count += 1 + g.difficulty_level += 1 - - def hint_next_question(self): - if self.game_state['difficulty_level'] > 9: + @staticmethod + def hint_next_question(g: GameStatus): + if g.difficulty_level > 9: return - if self.game_state['difficulty_level'] == 9: - self.game_state["conversation_history_hidden"].append({"role": "user", "content": '[系统提示]:这是最后一题,答完这题无论对错都停止游戏'}) + if g.difficulty_level == 9: + g.conversation_history_hidden.append({"role": "user", "content": '[系统提示]:这是最后一题,答完这题无论对错都停止游戏'}) try: - next_question = self.questionIterator.get_next_question(self.game_state['difficulty_level'])['question'] - self.game_state["conversation_history_hidden"].append({"role": "user", "content": f'[系统提示]:下一题,{next_question}'}) - self.game_state['next_question']=next_question + next_question = g.questionIterator.get_next_question(g.difficulty_level)['question'] + g.conversation_history_hidden.append({"role": "user", "content": f'[系统提示]:下一题,{next_question}'}) + g.next_question=next_question except: return - - def restart(self,chat_history): - self.game_state = { - "conversation_history_hidden": [], # 对话历史,AI看到的 - "correct_count": 0, # 连续答对次数 - "is_correct": False, # 总答题数 - "difficulty_level": 1, # 难度等级 (1, 2, 3) - "is_game_over": False, # 游戏是否结束 - "initial_message": [], - "next_question": None, - } - - self.game_state["conversation_history_hidden"].append({"role": "system", "content": GameController.system_prompt}) - self.get_initial_chat_display() - chat_history=self.game_state['initial_message'] - self.questionIterator.reset() + + @staticmethod + def restart(g:GameStatus,chat_history): + g.conversation_history_hidden=[] + g.correct_count=0 + g.is_correct=False + g.difficulty_level=1 + g.is_game_over=False + g.initial_message=[] + g.next_question=None + g.conversation_history_hidden.append({"role": "system", "content": GameController.system_prompt}) + GameController.get_initial_chat_display(g) + + chat_history=g.initial_message + g.questionIterator.reset() return chat_history - - def clear_history(self): + + @staticmethod + def clear_history(g:GameStatus): """清空对话历史""" - self.game_state["conversation_history_hidden"] = [] + g.conversation_history_hidden = [] return "历史已清空" - def show_history(self): + @staticmethod + def show_history(g:GameStatus): """显示当前对话历史""" history_text = "" - for msg in self.game_state["conversation_history_hidden"]: + for msg in g.conversation_history_hidden: role = "用户" if msg["role"] == "user" else "AI" if msg["role"] == "assistant" else "系统" history_text += f"{role}: {msg['content']}\n\n" return history_text if history_text else "暂无对话历史" - def save_conversation_history(self): + @staticmethod + def save_conversation_history(g:GameStatus): """保存对话历史到JSON文件""" try: # 创建保存目录(如果不存在) @@ -201,8 +212,8 @@ class GameController: save_data = { "save_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), #"total_rounds": self.game_state["total_rounds"], - "correct_count": self.game_state["correct_count"], - "conversation": self.game_state["conversation_history_hidden"] + "correct_count": g.correct_count, + "conversation": g.conversation_history_hidden } # 保存到文件 @@ -287,55 +298,83 @@ class QuestionIterator: for difficulty in [1,2,3,4,5,6,7,8,9]: self.reset_difficulty(difficulty) -def create_interface(g:GameController): - with gr.Blocks(title="皇帝出题机") as demo: - gr.Markdown("# 皇帝出题机") +class GRServer: + def __init__(self): + # 使用线程安全的字典存储用户状态 + self.user_sessions: Dict[str, GameStatus] = {} + self.session_lock = threading.Lock() + + def get_or_create_session(self, chatbot,session_id: str = None): + + """获取或创建用户会话""" + if not session_id: + session_id = str(uuid4()) - with gr.Row(): - with gr.Column(scale=2): - chatbot = gr.Chatbot(label="对话界面",height=600,value=g.game_state['initial_message'],type='messages') - msg = gr.Textbox(label="输入消息", placeholder="在这里输入你的消息...") - - with gr.Column(): - btn_send = gr.Button("发送", variant="primary") - with gr.Row(): - btn_save = gr.Button("保存对话历史", variant="secondary") - btn_restart = gr.Button("重新开始", variant="secondary") - - # with gr.Column(scale=1): - # gr.Markdown("### 历史管理") - # history_display = gr.Textbox(label="当前对话历史", interactive=False, lines=15) - # btn_show_history = gr.Button("刷新历史显示") - # btn_clear = gr.Button("清空历史") - # status = gr.Textbox(label="状态", interactive=False) + with self.session_lock: + if session_id not in self.user_sessions: + g=GameStatus() + chatbot=g.initial_message + self.user_sessions[session_id] = g + + return session_id,chatbot + + def session_chat(self,session_id,msg,chat_history): + g=self.user_sessions[session_id] - # # 事件处理 - # btn_send.click(chat_with_ai, [msg, chatbot], [msg, chatbot]).then( - # lambda: "", None, msg - # ) - - btn_send.click(g.chat_with_ai, [msg, chatbot], [msg, chatbot]) - msg.submit(g.chat_with_ai, [msg, chatbot], [msg, chatbot]) # 回车键触发 - btn_save.click( - fn=g.save_conversation_history, - inputs=[], - outputs=[] - ) - btn_restart.click(fn=g.restart,inputs=[chatbot],outputs=[chatbot]) + for updated_chat_history in GameController.chat_with_ai(g, msg, chat_history): + yield "", chat_history - # btn_show_history.click(show_history, None, history_display) - # btn_clear.click(clear_history, None, status).then( - # lambda: "历史已清空", None, history_display - # ) + return "", updated_chat_history + + def session_restart(self, session_id, chat_history): + g=self.user_sessions[session_id] + chat_history=GameController.restart(g, chat_history) + return chat_history + + def session_save(self, session_id): + g=self.user_sessions[session_id] + GameController.save_conversation_history(g) + + def create_interface(self): + # 创建Gradio界面 + with gr.Blocks(title="皇帝出题机") as demo: + session_state = gr.State(value="") + gr.Markdown("# 皇帝出题机") - # # 初始化显示历史 - # demo.load(show_history, None, history_display) - - demo.launch() + with gr.Row(): + with gr.Column(scale=2): + chatbot = gr.Chatbot(label="对话界面",height=600,type='messages') + msg = gr.Textbox(label="输入消息", placeholder="在这里输入你的消息...") + + with gr.Column(): + btn_send = gr.Button("发送", variant="primary") + with gr.Row(): + btn_save = gr.Button("保存对话历史", variant="secondary") + btn_restart = gr.Button("重新开始", variant="secondary") + + # 页面加载时初始化会话 + demo.load( + fn=self.get_or_create_session, + inputs=[chatbot], + outputs=[session_state,chatbot] + ) + + btn_send.click(self.session_chat, [session_state,msg, chatbot], [msg, chatbot]) + msg.submit(self.session_chat, [session_state, msg, chatbot], [msg, chatbot]) # 回车键触发 + btn_save.click( + fn=self.session_save, + inputs=[session_state], + outputs=[] + ) + btn_restart.click(fn=self.session_restart,inputs=[session_state,chatbot],outputs=[chatbot]) + + demo.launch() if __name__ == "__main__": - g=GameController() - question_iterator = QuestionIterator() + server=GRServer() + server.create_interface() + # g=GameController() + # question_iterator = QuestionIterator() # while True: # try: @@ -348,4 +387,4 @@ if __name__ == "__main__": # print(f"问题: {question['question']}, 长度: {question['length_of_answer']}") # question_iterator.reset_difficulty(4) - create_interface(g)
\ No newline at end of file + #create_interface(g)
\ No newline at end of file |