summaryrefslogtreecommitdiff
path: root/recitalMachine2.py
diff options
context:
space:
mode:
authorDogKing <dogking@DESKTOP-35DN20C.>2025-09-13 16:57:55 +0800
committerDogKing <dogking@DESKTOP-35DN20C.>2025-09-13 16:57:55 +0800
commitc53865f73972fa8a0070c2075c7649a97601a63a (patch)
treea6d3be4d276e0b33247757666d19ee7518ee5f28 /recitalMachine2.py
parentb9bea8689d72270e2ac37e89da958f01737f218e (diff)
decouple game controller functions and game status, enable multi user sessionsHEADmaster
Diffstat (limited to 'recitalMachine2.py')
-rw-r--r--recitalMachine2.py287
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