1
0

main.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. """
  2. DeepSeek Chat - 图形界面问答程序
  3. 使用 tkinter 构建 GUI,调用 DeepSeek API 进行问答
  4. """
  5. import tkinter as tk
  6. from tkinter import scrolledtext, messagebox, ttk
  7. import threading
  8. import json
  9. from datetime import datetime
  10. from openai import OpenAI
  11. import config
  12. class DeepSeekChatApp:
  13. """DeepSeek 问答图形界面程序"""
  14. def __init__(self, root):
  15. self.root = root
  16. self.root.title("DeepSeek 智能问答助手")
  17. self.root.geometry("800x600")
  18. self.root.minsize(600, 400)
  19. # 设置窗口图标和背景色
  20. self.root.configure(bg="#f0f0f0")
  21. # 初始化 API 客户端
  22. self.client = None
  23. self.conversation_history = []
  24. self.is_loading = False
  25. # 创建界面组件
  26. self._create_widgets()
  27. # 初始化 API 连接
  28. self._init_api()
  29. def _init_api(self):
  30. """初始化 DeepSeek API 客户端"""
  31. try:
  32. self.client = OpenAI(
  33. api_key=config.API_KEY,
  34. base_url=config.API_BASE
  35. )
  36. self.status_var.set("✓ API 连接已就绪")
  37. except Exception as e:
  38. self.status_var.set(f"✗ API 初始化失败: {str(e)}")
  39. def _create_widgets(self):
  40. """创建界面组件"""
  41. # 顶部标题栏
  42. header = tk.Frame(self.root, bg="#4a90d9", height=50)
  43. header.pack(fill=tk.X)
  44. header.pack_propagate(False)
  45. title_label = tk.Label(
  46. header,
  47. text="💬 DeepSeek 智能问答助手",
  48. font=("Microsoft YaHei", 14, "bold"),
  49. bg="#4a90d9",
  50. fg="white"
  51. )
  52. title_label.pack(side=tk.LEFT, padx=15, pady=10)
  53. # 清空对话按钮
  54. clear_btn = tk.Button(
  55. header,
  56. text="清空对话",
  57. font=("Microsoft YaHei", 9),
  58. bg="#e74c3c",
  59. fg="white",
  60. relief=tk.FLAT,
  61. cursor="hand2",
  62. command=self.clear_conversation
  63. )
  64. clear_btn.pack(side=tk.RIGHT, padx=15, pady=10)
  65. # 主内容区域
  66. main_frame = tk.Frame(self.root, bg="#f0f0f0")
  67. main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
  68. # 对话显示区域
  69. self.chat_display = scrolledtext.ScrolledText(
  70. main_frame,
  71. wrap=tk.WORD,
  72. font=("Microsoft YaHei", 11),
  73. bg="white",
  74. fg="#333333",
  75. state=tk.DISABLED,
  76. relief=tk.FLAT,
  77. padx=10,
  78. pady=10
  79. )
  80. self.chat_display.pack(fill=tk.BOTH, expand=True)
  81. # 配置文本标签样式
  82. self.chat_display.tag_configure(
  83. "user",
  84. foreground="#2c3e50",
  85. font=("Microsoft YaHei", 11, "bold"),
  86. spacing1=10,
  87. spacing3=5
  88. )
  89. self.chat_display.tag_configure(
  90. "assistant",
  91. foreground="#27ae60",
  92. font=("Microsoft YaHei", 11),
  93. spacing1=10,
  94. spacing3=5
  95. )
  96. self.chat_display.tag_configure(
  97. "system",
  98. foreground="#95a5a6",
  99. font=("Microsoft YaHei", 9, "italic"),
  100. spacing1=5,
  101. spacing3=5
  102. )
  103. self.chat_display.tag_configure(
  104. "error",
  105. foreground="#e74c3c",
  106. font=("Microsoft YaHei", 11),
  107. spacing1=10,
  108. spacing3=5
  109. )
  110. # 输入区域
  111. input_frame = tk.Frame(main_frame, bg="#f0f0f0")
  112. input_frame.pack(fill=tk.X, pady=(10, 0))
  113. # 输入框
  114. self.input_text = tk.Text(
  115. input_frame,
  116. height=3,
  117. font=("Microsoft YaHei", 11),
  118. bg="white",
  119. fg="#333333",
  120. relief=tk.FLAT,
  121. padx=10,
  122. pady=10,
  123. wrap=tk.WORD
  124. )
  125. self.input_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  126. self.input_text.bind("<Return>", self._on_enter)
  127. self.input_text.bind("<Shift-Return>", self._on_shift_enter)
  128. # 发送按钮
  129. self.send_btn = tk.Button(
  130. input_frame,
  131. text="发送 ➤",
  132. font=("Microsoft YaHei", 11, "bold"),
  133. bg="#4a90d9",
  134. fg="white",
  135. relief=tk.FLAT,
  136. cursor="hand2",
  137. padx=20,
  138. pady=10,
  139. command=self.send_message
  140. )
  141. self.send_btn.pack(side=tk.RIGHT, padx=(10, 0))
  142. # 底部状态栏
  143. status_frame = tk.Frame(self.root, bg="#e0e0e0", height=30)
  144. status_frame.pack(fill=tk.X, side=tk.BOTTOM)
  145. status_frame.pack_propagate(False)
  146. self.status_var = tk.StringVar()
  147. self.status_var.set("正在初始化...")
  148. status_label = tk.Label(
  149. status_frame,
  150. textvariable=self.status_var,
  151. font=("Microsoft YaHei", 9),
  152. bg="#e0e0e0",
  153. fg="#666666"
  154. )
  155. status_label.pack(side=tk.LEFT, padx=10, pady=5)
  156. # 显示欢迎消息
  157. self._display_message(
  158. "system",
  159. "欢迎使用 DeepSeek 智能问答助手!\n在下方输入你的问题,按 Enter 发送,Shift+Enter 换行。"
  160. )
  161. def _on_enter(self, event):
  162. """处理 Enter 键发送消息"""
  163. if not event.state & 0x0001: # 检查是否按下 Shift
  164. self.send_message()
  165. return "break"
  166. return None
  167. def _on_shift_enter(self, event):
  168. """处理 Shift+Enter 换行"""
  169. return None
  170. def _display_message(self, role, content):
  171. """在对话区域显示消息"""
  172. self.chat_display.config(state=tk.NORMAL)
  173. # 添加时间戳
  174. timestamp = datetime.now().strftime("%H:%M:%S")
  175. if role == "user":
  176. prefix = f"👤 你 ({timestamp}):\n"
  177. tag = "user"
  178. elif role == "assistant":
  179. prefix = f"🤖 DeepSeek ({timestamp}):\n"
  180. tag = "assistant"
  181. elif role == "error":
  182. prefix = f"⚠️ 错误 ({timestamp}):\n"
  183. tag = "error"
  184. else:
  185. prefix = f"ℹ️ ({timestamp}):\n"
  186. tag = "system"
  187. self.chat_display.insert(tk.END, prefix, tag)
  188. self.chat_display.insert(tk.END, content + "\n\n", tag)
  189. self.chat_display.see(tk.END)
  190. self.chat_display.config(state=tk.DISABLED)
  191. def send_message(self):
  192. """发送消息到 DeepSeek API"""
  193. if self.is_loading:
  194. return
  195. # 获取用户输入
  196. user_input = self.input_text.get("1.0", tk.END).strip()
  197. if not user_input:
  198. messagebox.showwarning("提示", "请输入问题内容")
  199. return
  200. # 清空输入框
  201. self.input_text.delete("1.0", tk.END)
  202. # 显示用户消息
  203. self._display_message("user", user_input)
  204. # 添加到对话历史
  205. self.conversation_history.append({"role": "user", "content": user_input})
  206. # 禁用发送按钮,显示加载状态
  207. self.is_loading = True
  208. self.send_btn.config(state=tk.DISABLED, text="思考中...")
  209. self.status_var.set("正在请求 DeepSeek API...")
  210. # 在后台线程中调用 API
  211. thread = threading.Thread(target=self._call_api, daemon=True)
  212. thread.start()
  213. def _call_api(self):
  214. """在后台线程中调用 DeepSeek API"""
  215. try:
  216. if not self.client:
  217. raise Exception("API 客户端未初始化,请检查 config.py 中的 API Key 配置")
  218. # 调用 API
  219. response = self.client.chat.completions.create(
  220. model=config.MODEL,
  221. messages=self.conversation_history,
  222. stream=False
  223. )
  224. # 获取回复内容
  225. reply = response.choices[0].message.content
  226. # 添加到对话历史
  227. self.conversation_history.append({"role": "assistant", "content": reply})
  228. # 在主线程中更新界面
  229. self.root.after(0, self._display_message, "assistant", reply)
  230. self.root.after(0, self._reset_ui, "✓ 回复完成")
  231. except Exception as e:
  232. error_msg = f"请求失败: {str(e)}\n\n请检查:\n1. API Key 是否正确\n2. 网络连接是否正常\n3. 是否已安装 openai 库"
  233. self.root.after(0, self._display_message, "error", error_msg)
  234. self.root.after(0, self._reset_ui, "✗ 请求失败")
  235. def _reset_ui(self, status_text):
  236. """重置界面状态"""
  237. self.is_loading = False
  238. self.send_btn.config(state=tk.NORMAL, text="发送 ➤")
  239. self.status_var.set(status_text)
  240. def clear_conversation(self):
  241. """清空对话"""
  242. if messagebox.askyesno("确认", "确定要清空所有对话记录吗?"):
  243. self.conversation_history = []
  244. self.chat_display.config(state=tk.NORMAL)
  245. self.chat_display.delete("1.0", tk.END)
  246. self.chat_display.config(state=tk.DISABLED)
  247. self._display_message(
  248. "system",
  249. "对话已清空。开始新的对话吧!"
  250. )
  251. self.status_var.set("对话已清空")
  252. def main():
  253. """程序入口"""
  254. root = tk.Tk()
  255. app = DeepSeekChatApp(root)
  256. root.mainloop()
  257. if __name__ == "__main__":
  258. main()