AIchat/gui.py

197 lines
6.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import tkinter as tk
from tkinter import messagebox, ttk
import sqlite3
import pygame
import subprocess
import pyaudio
import sys
import threading
import queue
import main
import app
# 在这里调用 main.py 中的函数或类
def get_match_logs(db_name="conversation.db"):
conn = sqlite3.connect(db_name)
c = conn.cursor()
c.execute("SELECT id, question, answer, audio_path FROM conversation")
logs = c.fetchall()
conn.close()
return logs
def delete_log(log_id, audio_path, db_name="conversation.db"):
conn = sqlite3.connect(db_name)
c = conn.cursor()
c.execute("DELETE FROM conversation WHERE id = ?", (log_id,))
conn.commit()
conn.close()
# 删除音频文件
if audio_path and os.path.isfile(audio_path):
os.remove(audio_path)
def clear_all_logs(db_name="conversation.db"):
conn = sqlite3.connect(db_name)
c = conn.cursor()
c.execute("SELECT audio_path FROM conversation")
audio_paths = c.fetchall()
# 删除所有记录
c.execute("DELETE FROM conversation")
conn.commit()
conn.close()
# 删除所有音频文件
for path in audio_paths:
if path[0] and os.path.isfile(path[0]):
os.remove(path[0])
class App:
def __init__(self, root):
self.root = root
self.root.title("交流记录")
# 初始化pygame
pygame.mixer.init()
# 创建表格
self.tree = ttk.Treeview(root, columns=("Question", "Answer", "Audio Path"), show='headings')
self.tree.heading("Question", text="问题")
self.tree.heading("Answer", text="回答")
self.tree.heading("Audio Path", text="音频路径")
self.tree.pack(fill=tk.BOTH, expand=True)
# 添加滚动条
scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscroll=scrollbar.set)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 加载日志
self.load_logs()
# 创建按钮容器
button_frame = tk.Frame(root)
button_frame.pack(pady=10)
# 删除按钮
self.delete_button = tk.Button(button_frame, text="删除选中记录", command=self.delete_selected)
self.delete_button.pack(side=tk.LEFT, padx=5)
# 播放按钮
self.play_button = tk.Button(button_frame, text="播放音频", command=self.play_audio)
self.play_button.pack(side=tk.LEFT, padx=5)
# 清除所有记录按钮
self.clear_button = tk.Button(button_frame, text="清除所有记录", command=self.clear_all)
self.clear_button.pack(side=tk.LEFT, padx=5)
# 刷新记录按钮
self.refresh_button = tk.Button(button_frame, text="刷新记录", command=self.load_logs)
self.refresh_button.pack(side=tk.LEFT, padx=5)
# 添加执行主程序的按钮
self.start_button = tk.Button(root, text="开始录音和识别", command=self.start_main)
self.start_button.pack(pady=20)
# 创建小屏幕区域
full_width = self.root.winfo_width()
self.small_frame = tk.Frame(root, width=full_width, height=200, bg="black")
self.small_frame.pack(side=tk.RIGHT, padx=10, pady=10)
self.output_text = tk.Text(self.small_frame, bg="black", fg="white", wrap="word")
self.output_text.pack(expand=True, fill=tk.BOTH)
self.process = None
self.output_queue = queue.Queue() # 用于存放输出的队列
# 定时器检查队列中的输出
self.root.after(100, self.check_queue)
def start_main(self):
# 创建并启动线程
thread = threading.Thread(target=self.run_main)
thread.start()
def run_main(self):
# 获取当前脚本的路径
script_path = os.path.join(os.path.dirname(__file__), 'main.py')
# 调用 main.py确保使用当前虚拟环境的 Python 解释器
self.process = subprocess.Popen(
[sys.executable, script_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8' # 设置编码为 utf-8
)
self.read_output()
def read_output(self):
if self.process:
output = self.process.stdout.readline()
if output:
self.output_queue.put(output) # 将输出放入队列
if self.process.poll() is None: # 进程仍在运行
self.root.after(100, self.read_output)
def check_queue(self):
while not self.output_queue.empty():
output = self.output_queue.get()
self.output_text.insert(tk.END, output)
self.output_text.see(tk.END) # 自动滚动到最新输出
self.root.after(100, self.check_queue) # 定时检查队列
def load_logs(self):
for row in self.tree.get_children():
self.tree.delete(row)
logs = get_match_logs()
for log in logs:
self.tree.insert("", tk.END, values=(log[1], log[2], log[3]))
def delete_selected(self):
selected_item = self.tree.selection()
if selected_item:
selected_index = self.tree.index(selected_item[0])
log_id = get_match_logs()[selected_index][0]
audio_path = get_match_logs()[selected_index][3]
full_audio_path = os.path.join("static", audio_path)
delete_log(log_id, full_audio_path)
self.load_logs()
else:
messagebox.showwarning("警告", "请先选择要删除的记录。")
def play_audio(self):
selected_item = self.tree.selection()
if selected_item:
selected_index = self.tree.index(selected_item[0])
audio_path = get_match_logs()[selected_index][3]
# 拼接静态文件夹路径
full_audio_path = os.path.join("static", audio_path)
# 打印音频路径用于调试
print("尝试加载音频文件:", full_audio_path)
# 检查文件是否存在
if os.path.isfile(full_audio_path):
pygame.mixer.music.load(full_audio_path)
pygame.mixer.music.play()
else:
messagebox.showerror("错误", "音频文件不存在。")
else:
messagebox.showwarning("警告", "请先选择要播放的记录。")
def clear_all(self):
confirm = messagebox.askyesno("确认", "您确定要清除所有记录吗?")
if confirm:
clear_all_logs()
self.load_logs()
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
root.mainloop()