Estazz commited on
Commit
d405811
·
verified ·
1 Parent(s): 4c605ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -41
app.py CHANGED
@@ -43,7 +43,35 @@ except Exception:
43
  # 设置 API Key
44
  dashscope.api_key = API_KEY
45
 
46
- # ==================== 事件处理函数 ====================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  def clear_cache():
48
  """清空缓存"""
49
  from cache_manager import file_cache, request_cache
@@ -59,10 +87,18 @@ def update_file_status(files):
59
  """更新文件状态显示"""
60
  if not files:
61
  return "📁 文件状态:未上传"
62
-
63
  file_list = files if isinstance(files, (list, tuple)) else [files]
64
- file_names = [os.path.basename(getattr(f, "name", str(f))) for f in file_list]
65
- return f"📁 文件状态:已上传 {len(file_names)} 个文件\n" + "\n".join(f" • {name}" for name in file_names[:3]) + ("\n ..." if len(file_names) > 3 else "")
 
 
 
 
 
 
 
 
 
66
 
67
  def export_history_to_markdown(history):
68
  """将聊天历史导出为 Markdown 文件,并返回文件路径供下载"""
@@ -70,21 +106,20 @@ def export_history_to_markdown(history):
70
  import pathlib
71
  from datetime import datetime
72
 
73
- # history 为 [(user, bot), ...]
 
 
74
  lines = ["# 对话记录", ""]
75
  lines.append(f"- 导出时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
76
  lines.append("")
77
- for idx, pair in enumerate(history or [], start=1):
78
- user_msg, bot_msg = pair if isinstance(pair, (list, tuple)) and len(pair) == 2 else ("", "")
79
  lines.append(f"## 轮次 {idx}")
80
  if user_msg:
81
- lines.append("**用户**:")
82
- lines.append("")
83
  lines.append(user_msg)
84
  lines.append("")
85
  if bot_msg:
86
- lines.append("**助手**:")
87
- lines.append("")
88
  lines.append(bot_msg)
89
  lines.append("")
90
 
@@ -97,6 +132,16 @@ def export_history_to_markdown(history):
97
  f.write(content)
98
  return str(filename)
99
 
 
 
 
 
 
 
 
 
 
 
100
  # ==================== Gradio 界面(Poker Skin) ====================
101
  with gr.Blocks(
102
  theme=gr.themes.Soft(),
@@ -114,7 +159,7 @@ with gr.Blocks(
114
  """)
115
 
116
  with gr.Row(equal_height=True):
117
- # 左侧:设置区(半透明卡片)
118
  with gr.Column(scale=1, min_width=MIN_WIDTH_LEFT):
119
  with gr.Group(elem_classes="side-card"):
120
  gr.Markdown("### 输入与约束")
@@ -153,64 +198,70 @@ with gr.Blocks(
153
  with gr.Group(elem_classes="side-card"):
154
  gr.Markdown("### 快捷操作")
155
  with gr.Row():
156
- clear_cache_btn = gr.Button("清空缓存", variant="secondary", size="sm")
157
- clear_files_btn = gr.Button("清空文件", variant="secondary", size="sm")
158
-
 
 
159
  # 缓存状态显示
160
  cache_status = gr.Markdown("💾 缓存状态:正常", elem_classes="hint")
161
-
162
  # 文件上传状态
163
  file_status = gr.Markdown("📁 文件状态:未上传", elem_classes="hint")
164
 
165
- # 右侧:聊天区(放在"扑克桌"里)
166
  with gr.Column(scale=2, min_width=MIN_WIDTH_RIGHT):
167
  with gr.Group(elem_classes="table"):
168
- # 单独定义 Chatbot,便于导出历史消息
169
  chatbot = gr.Chatbot(
170
  height=CHATBOT_HEIGHT,
171
- bubble_full_width=True,
172
  elem_classes="custom-chatbot",
173
  avatar_images=("landlord.png", "bot.png")
174
  )
175
 
 
 
 
 
 
 
 
 
 
176
  chat = gr.ChatInterface(
177
- fn=design_poker_game,
178
- additional_inputs=[file_uploader, custom_prompt_box, prompt_mode],
179
  chatbot=chatbot,
180
- textbox=gr.Textbox(
181
- placeholder="例如:设计一个适合3-5人的派对风格扑克游戏(请写清目标人群/时长/创新点)…",
182
- show_label=False,
183
- max_lines=5,
184
- lines=3,
185
- show_copy_button=True
186
- ),
187
  submit_btn="发送",
188
- retry_btn="重新生成",
189
- undo_btn="撤销",
190
- clear_btn="清空对话",
191
- description="""
192
- **使用方式**
193
- 左侧上传 GDL 与(可选)自定义 Prompt,然后在这里输入需求。我会遵循上传的规范,并结合你的目标人群/复杂度/时长做设计。
194
- """
195
  )
196
 
197
  with gr.Row():
198
  export_btn = gr.Button("导出对话(Markdown)", variant="secondary")
199
  export_file = gr.File(label="点击下载导出文件", interactive=False)
200
 
 
 
 
 
201
  # ==================== 事件绑定 ====================
202
  # 清空缓存按钮
203
  clear_cache_btn.click(
204
  fn=clear_cache,
205
  outputs=[cache_status]
206
  )
207
-
208
  # 清空文件按钮
209
  clear_files_btn.click(
210
  fn=clear_files,
211
  outputs=[file_uploader]
212
  )
213
-
214
  # 文件上传状态更新
215
  file_uploader.change(
216
  fn=update_file_status,
@@ -218,14 +269,13 @@ with gr.Blocks(
218
  outputs=[file_status]
219
  )
220
 
221
- # 导出历史对话(从 Chatbot 读取 state)
222
  def _export_wrapper(chat_history):
223
  try:
224
  path = export_history_to_markdown(chat_history)
225
  return path
226
  except Exception as e:
227
- import tempfile, os
228
- # 导出失败则写入一个错误说明文件
229
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".md")
230
  with open(tmp.name, 'w', encoding='utf-8') as f:
231
  f.write(f"导出失败:{type(e).__name__}: {str(e)}\n")
@@ -239,4 +289,5 @@ with gr.Blocks(
239
 
240
  # ==================== 启动应用 ====================
241
  if __name__ == "__main__":
242
- demo.launch(share=True, show_api=False)
 
 
43
  # 设置 API Key
44
  dashscope.api_key = API_KEY
45
 
46
+ # ==================== 工具函数 ====================
47
+ def _messages_to_tuples(history):
48
+ """
49
+ 将 Chatbot 的 messages 格式([{role, content}, ...])转换为 [(user, bot), ...]。
50
+ 若已是 tuples,则原样返回。
51
+ """
52
+ if not history:
53
+ return []
54
+
55
+ # 已经是列表且第一个元素为 dict,则认为是 messages 模式
56
+ if isinstance(history, list) and history and isinstance(history[0], dict):
57
+ pairs = []
58
+ last_user = None
59
+ for msg in history:
60
+ role = msg.get("role")
61
+ content = msg.get("content", "")
62
+ if role == "user":
63
+ last_user = content
64
+ elif role == "assistant":
65
+ pairs.append((last_user or "", content))
66
+ last_user = None
67
+ else:
68
+ # 其他角色(如 system)直接忽略到导出/兼容对里
69
+ pass
70
+ return pairs
71
+
72
+ # 否则当作老的 [(user, bot)] 结构
73
+ return history
74
+
75
  def clear_cache():
76
  """清空缓存"""
77
  from cache_manager import file_cache, request_cache
 
87
  """更新文件状态显示"""
88
  if not files:
89
  return "📁 文件状态:未上传"
 
90
  file_list = files if isinstance(files, (list, tuple)) else [files]
91
+ names = []
92
+ for f in file_list:
93
+ # gr.File(type="filepath") 传回的是路径字符串
94
+ if isinstance(f, str):
95
+ names.append(os.path.basename(f))
96
+ else:
97
+ # 兼容其他情况
98
+ names.append(os.path.basename(getattr(f, "name", str(f))))
99
+ head = "\n".join(f" • {n}" for n in names[:3])
100
+ tail = "\n ..." if len(names) > 3 else ""
101
+ return f"📁 文件状态:已上传 {len(names)} 个文件\n{head}{tail}"
102
 
103
  def export_history_to_markdown(history):
104
  """将聊天历史导出为 Markdown 文件,并返回文件路径供下载"""
 
106
  import pathlib
107
  from datetime import datetime
108
 
109
+ # 统一转为 [(user, bot)] 再导出
110
+ pairs = _messages_to_tuples(history)
111
+
112
  lines = ["# 对话记录", ""]
113
  lines.append(f"- 导出时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
114
  lines.append("")
115
+ for idx, (user_msg, bot_msg) in enumerate(pairs, start=1):
 
116
  lines.append(f"## 轮次 {idx}")
117
  if user_msg:
118
+ lines.append("**用户**:\n")
 
119
  lines.append(user_msg)
120
  lines.append("")
121
  if bot_msg:
122
+ lines.append("**助手**:\n")
 
123
  lines.append(bot_msg)
124
  lines.append("")
125
 
 
132
  f.write(content)
133
  return str(filename)
134
 
135
+ # 为 ChatInterface 提供一个向后兼容的适配器
136
+ def chat_fn_adapter(user_message, history, files, custom_prompt, prompt_mode):
137
+ """
138
+ ChatInterface(type='messages') 会传入 history 为 messages 列表。
139
+ 这里做一次转换,调用你现有的 design_poker_game(假设其使用 [(user, bot)] 历史)。
140
+ 返回值保持为纯文本(由 ChatInterface 追加到对话)。
141
+ """
142
+ history_tuples = _messages_to_tuples(history)
143
+ return design_poker_game(user_message, history_tuples, files, custom_prompt, prompt_mode)
144
+
145
  # ==================== Gradio 界面(Poker Skin) ====================
146
  with gr.Blocks(
147
  theme=gr.themes.Soft(),
 
159
  """)
160
 
161
  with gr.Row(equal_height=True):
162
+ # 左侧:设置区
163
  with gr.Column(scale=1, min_width=MIN_WIDTH_LEFT):
164
  with gr.Group(elem_classes="side-card"):
165
  gr.Markdown("### 输入与约束")
 
198
  with gr.Group(elem_classes="side-card"):
199
  gr.Markdown("### 快捷操作")
200
  with gr.Row():
201
+ clear_cache_btn = gr.Button("清空缓存", variant="secondary")
202
+ clear_files_btn = gr.Button("清空文件", variant="secondary")
203
+ # “清空对话”使用 ClearButton 以兼容新版
204
+ # 先在右侧定义完 chatbot / user_input 后再绑定(见下文)
205
+
206
  # 缓存状态显示
207
  cache_status = gr.Markdown("💾 缓存状态:正常", elem_classes="hint")
 
208
  # 文件上传状态
209
  file_status = gr.Markdown("📁 文件状态:未上传", elem_classes="hint")
210
 
211
+ # 右侧:聊天区
212
  with gr.Column(scale=2, min_width=MIN_WIDTH_RIGHT):
213
  with gr.Group(elem_classes="table"):
214
+ # 单独定义 Chatbot(新版使用 messages 格式)
215
  chatbot = gr.Chatbot(
216
  height=CHATBOT_HEIGHT,
217
+ type="messages", # ✅ 新格式,避免弃用警告
218
  elem_classes="custom-chatbot",
219
  avatar_images=("landlord.png", "bot.png")
220
  )
221
 
222
+ user_input = gr.Textbox(
223
+ placeholder="例如:设计一个适合3-5人的派对风格扑克游戏(请写清目标人群/时长/创新点)…",
224
+ show_label=False,
225
+ max_lines=5,
226
+ lines=3,
227
+ show_copy_button=True
228
+ )
229
+
230
+ # ChatInterface:去掉已移除的 retry_btn/undo_btn/clear_btn
231
  chat = gr.ChatInterface(
232
+ fn=chat_fn_adapter,
 
233
  chatbot=chatbot,
234
+ textbox=user_input,
235
+ additional_inputs=[file_uploader, custom_prompt_box, prompt_mode],
236
+ type="messages", # ✅ 与 Chatbot 保持一致
 
 
 
 
237
  submit_btn="发送",
238
+ stop_btn=True,
239
+ description=(
240
+ "**使用方式** \n"
241
+ "左侧上传 GDL 与(可选)自定义 Prompt,然后在这里输入需求。"
242
+ "我会遵循上传的规范,并结合你的目标人群/复杂度/时长做设计。"
243
+ ),
 
244
  )
245
 
246
  with gr.Row():
247
  export_btn = gr.Button("导出对话(Markdown)", variant="secondary")
248
  export_file = gr.File(label="点击下载导出文件", interactive=False)
249
 
250
+ # 在这里补上“清空对话”按钮(等同于你以前的 clear_btn)
251
+ with gr.Row():
252
+ clear_dialog_btn = gr.ClearButton([chatbot, user_input], value="清空对话", variant="secondary")
253
+
254
  # ==================== 事件绑定 ====================
255
  # 清空缓存按钮
256
  clear_cache_btn.click(
257
  fn=clear_cache,
258
  outputs=[cache_status]
259
  )
 
260
  # 清空文件按钮
261
  clear_files_btn.click(
262
  fn=clear_files,
263
  outputs=[file_uploader]
264
  )
 
265
  # 文件上传状态更新
266
  file_uploader.change(
267
  fn=update_file_status,
 
269
  outputs=[file_status]
270
  )
271
 
272
+ # 导出历史对话
273
  def _export_wrapper(chat_history):
274
  try:
275
  path = export_history_to_markdown(chat_history)
276
  return path
277
  except Exception as e:
278
+ import tempfile
 
279
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".md")
280
  with open(tmp.name, 'w', encoding='utf-8') as f:
281
  f.write(f"导出失败:{type(e).__name__}: {str(e)}\n")
 
289
 
290
  # ==================== 启动应用 ====================
291
  if __name__ == "__main__":
292
+ # 在 Hugging Face Spaces 上 share 参数会被忽略,但本地调试可用
293
+ demo.queue().launch(share=True, show_api=False)