388 lines
14 KiB
Python
388 lines
14 KiB
Python
import modes as mc
|
||
import tkinter as tk
|
||
from tkinter import ttk
|
||
import threading
|
||
import base_mode as bm
|
||
|
||
IS_BOARD = True
|
||
|
||
try:
|
||
from pinpong.board import Board, Pin, NeoPixel
|
||
from unihiker import GUI
|
||
gui = GUI()
|
||
except ModuleNotFoundError:
|
||
print("警告:非行空板环境")
|
||
IS_BOARD = False
|
||
import time
|
||
|
||
|
||
class XingkongBoardBase:
|
||
def __init__(self):
|
||
pass
|
||
|
||
def on_btn_click(self, callback):
|
||
"""
|
||
按下机外的那个按钮。
|
||
该按钮按键流程(必须辩论模式):
|
||
1. 进入立论模式(若是正方,则直接说话;若是反方,则直接开始录音)
|
||
2. 当本方为正方时,开始录(反方)音;为反方时,停止录(正方的)音
|
||
3. 当本方为正方时,停止录(反方)音;为反方时,开始说话
|
||
4. 当本方为正方时,进入进入自由辩论模式;为反方时,也是进入自由辩论模式(请确保灯光为绿)
|
||
5. 关闭自由辩论模式
|
||
6. 进入总结陈词模式。为正方时将直接开始录音;为反方时将直接输出语音,完成后辩论模式结束
|
||
7. 正方停止录音
|
||
8. 正方输出语音。完成后辩论模式结束
|
||
:param callback: 当按下时的回调函数
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
def on_btn_dialog_click(self, callback):
|
||
"""
|
||
按下“对话模式”按钮
|
||
:param callback: 当按下时的回调函数
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
def on_btn_debate_click(self, callback):
|
||
"""
|
||
按下“辩论模式”按钮
|
||
:param callback: 当按下时的回调函数
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
def on_btn_stop_click(self, callback):
|
||
"""
|
||
按下“停止”按钮
|
||
:param callback: 当按下时的回调函数
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
def set_light_color(self, color):
|
||
"""
|
||
设置灯光颜色。
|
||
在对话模式和自由辩论模式不设置灯光颜色。
|
||
red: 正在处理一些事件,此时不能点击机外按钮
|
||
green: 准备就绪,可以点击机外按钮
|
||
blue: 正在录音
|
||
orange: 成功进入辩论模式和自由辩论
|
||
:param color: "red"|"green"|"blue"|"orange"
|
||
:return:
|
||
"""
|
||
pass
|
||
|
||
|
||
SYSTEM = \
|
||
"""
|
||
你是人大附中经开学校金鹏科技团开发的辩论智能体机器人,名叫人开一号。
|
||
这个机器人运用了流式语音识别、大语言模型、流式语音合成等技术。
|
||
当你被要求介绍自己时,请简要介绍你的功能和技术实现。
|
||
请注意,你的回答将被直接通过语音合成输出,因此你不能输出不适合TTS的内容。
|
||
"""
|
||
|
||
|
||
class Unihiker_Board(XingkongBoardBase):
|
||
def __init__(self):
|
||
super().__init__()
|
||
Board().begin()
|
||
# self.gui=GUI()
|
||
self.btn21 = Pin(Pin.P21, Pin.IN)
|
||
self.pin23 = Pin(Pin.D23)
|
||
self.np1 = NeoPixel(self.pin23, 22)
|
||
self.np1.brightness(150)
|
||
gui.add_button(x=0, y=290, w=80, h=30, text="对话", origin='nw', onclick=self._trigger_dialog_click)
|
||
gui.add_button(x=80, y=290, w=80, h=30, text="辩论", origin='nw', onclick=self._trigger_debate_click)
|
||
gui.add_button(x=160, y=290, w=80, h=30, text="停止", origin='nw', onclick=self._trigger_stop_click)
|
||
|
||
self.btn_count = 0
|
||
|
||
self.btn_callback = None
|
||
self.dialog_callback = None
|
||
self.debate_callback = None
|
||
self.stop_callback = None
|
||
|
||
def on_btn_click(self, callback):
|
||
self.btn_callback = callback
|
||
|
||
def on_btn_dialog_click(self, callback):
|
||
self.dialog_callback = callback
|
||
|
||
def on_btn_debate_click(self, callback):
|
||
self.debate_callback = callback
|
||
|
||
def on_btn_stop_click(self, callback):
|
||
self.stop_callback = callback
|
||
|
||
def set_light_color(self, color):
|
||
if color == "red":
|
||
self.np1.range_color(0, 21, 0xFF0000)
|
||
if color == "green":
|
||
self.np1.range_color(0, 21, 0x00FF00)
|
||
if color == "blue":
|
||
self.np1.range_color(0, 21, 0x0000FF)
|
||
if color == "orange":
|
||
self.np1.range_color(0, 21, 0xFFFF00)
|
||
|
||
def _trigger_btn_click(self):
|
||
if self.btn_callback:
|
||
threading.Thread(target=self.btn_callback, daemon=True).start()
|
||
|
||
def _trigger_dialog_click(self):
|
||
if self.dialog_callback:
|
||
threading.Thread(target=self.dialog_callback, daemon=True).start()
|
||
|
||
def _trigger_debate_click(self):
|
||
if self.debate_callback:
|
||
threading.Thread(target=self.debate_callback, daemon=True).start()
|
||
|
||
def _trigger_stop_click(self):
|
||
if self.stop_callback:
|
||
threading.Thread(target=self.stop_callback, daemon=True).start()
|
||
|
||
def btn_click_check(self):
|
||
while True:
|
||
if self.btn21.read_digital() == 0:
|
||
while self.btn21.read_digital() == 0:
|
||
pass
|
||
self._trigger_btn_click()
|
||
|
||
def run(self):
|
||
threading.Thread(target=self.btn_click_check, daemon=True).start()
|
||
while True:
|
||
time.sleep(1)
|
||
|
||
|
||
class Robot:
|
||
def __init__(self, board: XingkongBoardBase):
|
||
self.modes = dict()
|
||
self.btn_count = 0
|
||
self.board = board
|
||
self.side = ""
|
||
self.topic = ""
|
||
self.opinion = ""
|
||
self.last_prompt = ""
|
||
self.session_id = None
|
||
|
||
def register_mode(self, modename: str, mode: bm.Mode):
|
||
self.modes[modename] = mode
|
||
|
||
def run_mode(self, modename):
|
||
self.modes[modename].run()
|
||
|
||
def stop_mode(self, modename):
|
||
self.modes[modename].stop()
|
||
del self.modes[modename]
|
||
|
||
def get_mode(self, modename):
|
||
return self.modes[modename]
|
||
|
||
def stop_all(self):
|
||
for mode in self.modes.values():
|
||
mode.stop()
|
||
self.modes.clear()
|
||
|
||
def dialog(self):
|
||
self.stop_all()
|
||
self.board.set_light_color("orange")
|
||
dialog_mode = mc.DialogMode(system_prompt=SYSTEM)
|
||
self.register_mode("dialog", dialog_mode)
|
||
self.run_mode("dialog")
|
||
|
||
def set_debate_config(self, side, topic, opinion):
|
||
self.side = side
|
||
self.topic = topic
|
||
self.opinion = opinion
|
||
|
||
def debate(self):
|
||
self.stop_all()
|
||
self.board.set_light_color("orange")
|
||
self.btn_count = 0
|
||
if self.side == "正方":
|
||
self.board.on_btn_click(self._btn_right_callback)
|
||
else:
|
||
self.board.on_btn_click(self._btn_against_callback)
|
||
|
||
def on_cancel(self):
|
||
self.stop_all()
|
||
self.board.set_light_color("green")
|
||
|
||
def _btn_right_callback(self):
|
||
self.btn_count += 1
|
||
if self.btn_count == 1:
|
||
self.board.set_light_color("red")
|
||
self.register_mode("make_point", mc.MakePointMode(side=self.side, topic=self.topic, opinion=self.opinion))
|
||
self.run_mode("make_point")
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 2:
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
self.board.set_light_color("blue")
|
||
md.start_record()
|
||
elif self.btn_count == 3:
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
self.board.set_light_color("red")
|
||
md.stop_record()
|
||
self.board.set_light_color("green")
|
||
self.last_prompt = md.ready_next()
|
||
elif self.btn_count == 4:
|
||
self.board.set_light_color("red")
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
self.session_id = md.session_id
|
||
self.stop_mode("make_point")
|
||
self.register_mode("free_debate", mc.FreeDebateMode(side=self.side, topic=self.topic, opinion=self.opinion,
|
||
last_prompt=self.last_prompt,
|
||
session_id=self.session_id))
|
||
self.run_mode("free_debate")
|
||
self.board.set_light_color("orange")
|
||
elif self.btn_count == 5:
|
||
self.board.set_light_color("red")
|
||
md: mc.FreeDebateMode = self.get_mode("free_debate")
|
||
self.session_id = md.session_id
|
||
self.stop_mode("free_debate")
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 6:
|
||
self.board.set_light_color("red")
|
||
self.register_mode("end_debate", mc.EndDebateMode(side=self.side, topic=self.topic, opinion=self.opinion,
|
||
session_id=self.session_id))
|
||
self.run_mode("end_debate")
|
||
self.board.set_light_color("blue")
|
||
elif self.btn_count == 7:
|
||
md: mc.EndDebateMode = self.get_mode("end_debate")
|
||
md.stop_record()
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 8:
|
||
self.board.set_light_color("red")
|
||
md: mc.EndDebateMode = self.get_mode("end_debate")
|
||
md.start_talk()
|
||
self.board.set_light_color("green")
|
||
self.stop_mode("end_debate")
|
||
|
||
|
||
def _btn_against_callback(self):
|
||
self.btn_count += 1
|
||
if self.btn_count == 1:
|
||
self.board.set_light_color("blue")
|
||
self.register_mode("make_point", mc.MakePointMode(side=self.side, topic=self.topic, opinion=self.opinion))
|
||
self.run_mode("make_point")
|
||
elif self.btn_count == 2:
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
self.board.set_light_color("red")
|
||
md.stop_record()
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 3:
|
||
self.board.set_light_color("red")
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
md.ready_next()
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 4:
|
||
self.board.set_light_color("red")
|
||
md: mc.MakePointMode = self.get_mode("make_point")
|
||
self.session_id = md.session_id
|
||
self.stop_mode("make_point")
|
||
self.register_mode("free_debate", mc.FreeDebateMode(side=self.side, topic=self.topic, opinion=self.opinion,
|
||
session_id=self.session_id))
|
||
self.run_mode("free_debate")
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 5:
|
||
self.board.set_light_color("red")
|
||
md: mc.FreeDebateMode = self.get_mode("free_debate")
|
||
self.session_id = md.session_id
|
||
self.stop_mode("free_debate")
|
||
self.board.set_light_color("green")
|
||
elif self.btn_count == 6:
|
||
self.board.set_light_color("red")
|
||
self.register_mode("end_debate", mc.EndDebateMode(side=self.side, topic=self.topic, opinion=self.opinion,
|
||
session_id=self.session_id))
|
||
self.run_mode("end_debate")
|
||
md: mc.EndDebateMode = self.get_mode("end_debate")
|
||
md.start_talk()
|
||
|
||
def run(self):
|
||
self.board.on_btn_dialog_click(self.dialog)
|
||
self.board.on_btn_debate_click(self.debate)
|
||
self.board.on_btn_stop_click(self.on_cancel)
|
||
|
||
|
||
class MockXingkongBoard(XingkongBoardBase):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.root = tk.Tk()
|
||
self.root.title("模拟控制台")
|
||
self.root.geometry("300x200")
|
||
|
||
# 灯光显示
|
||
self.light = tk.Label(self.root, width=10, height=5, bg="gray")
|
||
self.light.pack(pady=10)
|
||
|
||
# 按钮布局
|
||
btn_frame = ttk.Frame(self.root)
|
||
btn_frame.pack(pady=10)
|
||
|
||
# 机外按钮
|
||
ttk.Button(btn_frame, text="机外按钮", command=self._trigger_btn_click).grid(row=0, column=0, padx=5)
|
||
|
||
# 功能按钮
|
||
ttk.Button(btn_frame, text="对话模式", command=self._trigger_dialog_click).grid(row=1, column=0, padx=5)
|
||
ttk.Button(btn_frame, text="辩论模式", command=self._trigger_debate_click).grid(row=1, column=1, padx=5)
|
||
ttk.Button(btn_frame, text="停止", command=self._trigger_stop_click).grid(row=1, column=2, padx=5)
|
||
|
||
# 回调存储
|
||
self.btn_callback = None
|
||
self.dialog_callback = None
|
||
self.debate_callback = None
|
||
self.stop_callback = None
|
||
|
||
def on_btn_click(self, callback):
|
||
self.btn_callback = callback
|
||
|
||
def on_btn_dialog_click(self, callback):
|
||
self.dialog_callback = callback
|
||
|
||
def on_btn_debate_click(self, callback):
|
||
self.debate_callback = callback
|
||
|
||
def on_btn_stop_click(self, callback):
|
||
self.stop_callback = callback
|
||
|
||
def set_light_color(self, color):
|
||
# 仅设置颜色,不添加任何模式判断
|
||
self.light.config(bg=color)
|
||
|
||
def _trigger_btn_click(self):
|
||
# 直接触发回调,高耗时操作放线程
|
||
if self.btn_callback:
|
||
threading.Thread(target=self.btn_callback, daemon=True).start()
|
||
|
||
def _trigger_dialog_click(self):
|
||
if self.dialog_callback:
|
||
threading.Thread(target=self.dialog_callback, daemon=True).start()
|
||
|
||
def _trigger_debate_click(self):
|
||
if self.debate_callback:
|
||
threading.Thread(target=self.debate_callback, daemon=True).start()
|
||
|
||
def _trigger_stop_click(self):
|
||
if self.stop_callback:
|
||
threading.Thread(target=self.stop_callback, daemon=True).start()
|
||
|
||
def run(self):
|
||
self.root.mainloop()
|
||
|
||
|
||
if __name__ == '__main__':
|
||
board = Unihiker_Board() if IS_BOARD else MockXingkongBoard()
|
||
robot = Robot(board)
|
||
robot.set_debate_config(
|
||
"反方",
|
||
"利用基因技术复活已灭绝物种(反灭绝工程)是生态责任还是资源浪费",
|
||
"利用基因技术复活已灭绝物种(反灭绝工程)是资源浪费"
|
||
) if IS_BOARD else robot.set_debate_config(
|
||
"反方",
|
||
"量子计算机的实用化是否会首先对现有加密体系构成致命威胁",
|
||
"量子计算机的实用化是否不会首先对现有加密体系构成致命威胁"
|
||
)
|
||
robot.run()
|
||
board.run()
|