zjrwtx commited on
Commit
d4ada08
·
1 Parent(s): a1520e7

more simple version

Browse files
Files changed (1) hide show
  1. owl/webapp_zh.py +305 -270
owl/webapp_zh.py CHANGED
@@ -2,208 +2,105 @@
2
  from owl.utils import run_society
3
  import os
4
  import gradio as gr
 
 
5
  from typing import Tuple, List, Dict, Any
6
  import importlib
 
7
 
8
  os.environ['PYTHONIOENCODING'] = 'utf-8'
9
 
10
- # Enhanced CSS with navigation bar and additional styling
11
- custom_css = """
12
- :root {
13
- --primary-color: #4a89dc;
14
- --secondary-color: #5d9cec;
15
- --accent-color: #7baaf7;
16
- --light-bg: #f8f9fa;
17
- --border-color: #e4e9f0;
18
- --text-muted: #8a9aae;
19
- }
20
-
21
- .container {
22
- max-width: 1200px;
23
- margin: 0 auto;
24
- }
25
-
26
- .navbar {
27
- display: flex;
28
- justify-content: space-between;
29
- align-items: center;
30
- padding: 15px 30px;
31
- background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
32
- color: white;
33
- border-radius: 10px 10px 0 0;
34
- margin-bottom: 0;
35
- box-shadow: 0 2px 10px rgba(74, 137, 220, 0.15);
36
- }
37
-
38
- .navbar-logo {
39
- display: flex;
40
- align-items: center;
41
- gap: 10px;
42
- font-size: 1.5em;
43
- font-weight: bold;
44
- }
45
-
46
- .navbar-menu {
47
- display: flex;
48
- gap: 20px;
49
- }
50
-
51
- /* Navbar styles moved to a more specific section below */
52
-
53
- .header {
54
- text-align: center;
55
- margin-bottom: 20px;
56
- background: linear-gradient(180deg, var(--secondary-color), var(--accent-color));
57
- color: white;
58
- padding: 40px 20px;
59
- border-radius: 0 0 10px 10px;
60
- box-shadow: 0 4px 6px rgba(93, 156, 236, 0.12);
61
- }
62
-
63
- .module-info {
64
- background-color: var(--light-bg);
65
- border-left: 5px solid var(--primary-color);
66
- padding: 10px 15px;
67
- margin-top: 10px;
68
- border-radius: 5px;
69
- font-size: 0.9em;
70
- }
71
 
72
- .answer-box {
73
- background-color: var(--light-bg);
74
- border-left: 5px solid var(--secondary-color);
75
- padding: 15px;
76
- margin-bottom: 20px;
77
- border-radius: 5px;
78
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
79
- }
80
-
81
- .token-count {
82
- background-color: #e9ecef;
83
- padding: 10px;
84
- border-radius: 5px;
85
- text-align: center;
86
- font-weight: bold;
87
- margin-bottom: 20px;
88
- }
89
-
90
- .chat-container {
91
- border: 1px solid var(--border-color);
92
- border-radius: 5px;
93
- max-height: 500px;
94
- overflow-y: auto;
95
- margin-bottom: 20px;
96
- }
97
-
98
- .footer {
99
- text-align: center;
100
- margin-top: 20px;
101
- color: var(--text-muted);
102
- font-size: 0.9em;
103
- padding: 20px;
104
- border-top: 1px solid var(--border-color);
105
- }
106
 
107
- .features-section {
108
- display: grid;
109
- grid-template-columns: repeat(3, 1fr);
110
- gap: 20px;
111
- margin: 20px 0;
112
- }
113
-
114
- @media (max-width: 1200px) {
115
- .features-section {
116
- grid-template-columns: repeat(2, 1fr);
117
- }
118
  }
119
 
120
- @media (max-width: 768px) {
121
- .features-section {
122
- grid-template-columns: 1fr;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
  }
125
 
126
- .feature-card {
127
- background-color: white;
128
- border-radius: 8px;
129
- padding: 20px;
130
- box-shadow: 0 2px 8px rgba(74, 137, 220, 0.08);
131
- transition: transform 0.3s, box-shadow 0.3s;
132
- height: 100%;
133
- display: flex;
134
- flex-direction: column;
135
- border: 1px solid rgba(228, 233, 240, 0.6);
136
- }
137
 
138
- .feature-card:hover {
139
- transform: translateY(-5px);
140
- box-shadow: 0 5px 15px rgba(74, 137, 220, 0.15);
141
- border-color: rgba(93, 156, 236, 0.3);
142
- }
143
 
144
- .feature-icon {
145
- font-size: 2em;
146
- color: var(--primary-color);
147
- margin-bottom: 10px;
148
- text-shadow: 0 1px 2px rgba(74, 137, 220, 0.1);
149
- }
150
 
151
- .feature-card h3 {
152
- margin-top: 10px;
153
- margin-bottom: 10px;
154
- }
155
 
156
- .feature-card p {
157
- flex-grow: 1;
158
- font-size: 0.95em;
159
- line-height: 1.5;
160
- }
161
 
162
- /* Navbar link styles - ensuring consistent colors */
163
- .navbar-menu a {
164
- color: #ffffff !important;
165
- text-decoration: none;
166
- padding: 5px 10px;
167
- border-radius: 5px;
168
- transition: background-color 0.3s, color 0.3s;
169
- font-weight: 500;
170
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
171
- }
172
 
173
- .navbar-menu a:hover {
174
- background-color: rgba(255, 255, 255, 0.15);
175
- color: #ffffff !important;
176
- }
177
 
178
- /* Improved button and input styles */
179
- button.primary {
180
- background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
181
- transition: all 0.3s;
182
- }
183
 
184
- button.primary:hover {
185
- background: linear-gradient(90deg, var(--secondary-color), var(--primary-color));
186
- transform: translateY(-2px);
187
- box-shadow: 0 4px 8px rgba(74, 137, 220, 0.2);
188
- }
189
  """
190
 
191
- # Dictionary containing module descriptions
192
- MODULE_DESCRIPTIONS = {
193
- "run": "默认模式:使用OpenAI模型的默认的智能体协作模式,适合大多数任务。",
194
- "run_mini":"使用使用OpenAI模型最小化配置处理任务",
195
- "run_deepseek_zh":"使用deepseek模型处理中文任务",
196
- "run_terminal_zh": "终端模式:可执行命令行操作,支持网络搜索、文件处理等功能。适合需要系统交互的任务,使用OpenAI模型",
197
- "run_gaia_roleplaying":"GAIA基准测试实现,用于评估Agent能力",
198
- "run_openai_compatiable_model":"使用openai兼容模型处理任务",
199
- "run_ollama":"使用本地ollama模型处理任务",
200
- "run_qwen_mini_zh":"使用qwen模型最小化配置处理任务",
201
- "run_qwen_zh":"使用qwen模型处理任务",
202
-
203
-
204
-
205
- }
206
-
207
  def format_chat_history(chat_history: List[Dict[str, str]]) -> List[List[str]]:
208
  """将聊天历史格式化为Gradio聊天组件可接受的格式
209
 
@@ -261,6 +158,8 @@ def run_owl(question: str, example_module: str) -> Tuple[str, List[List[str]], s
261
  )
262
 
263
  try:
 
 
264
  # 检查模块是否在MODULE_DESCRIPTIONS中
265
  if example_module not in MODULE_DESCRIPTIONS:
266
  return (
@@ -354,67 +253,115 @@ def update_module_description(module_name: str) -> str:
354
  """返回所选模块的描述"""
355
  return MODULE_DESCRIPTIONS.get(module_name, "无可用描述")
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  def create_ui():
358
  """创建增强版Gradio界面"""
359
- with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="blue")) as app:
360
- with gr.Column(elem_classes="container"):
361
- gr.HTML("""
362
- <div class="navbar">
363
- <div class="navbar-logo">
364
- 🦉 OWL 多智能体协作系统
365
- </div>
366
- <div class="navbar-menu">
367
- <a href="#home">首页</a>
368
- <a href="https://github.com/camel-ai/owl/blob/main/README.md#-community">加入交流群</a>
369
- <a href="https://github.com/camel-ai/owl/blob/main/README.md">OWL文档</a>
370
- <a href="https://github.com/camel-ai/camel">CAMEL框架</a>
371
- <a href="https://camel-ai.org">CAMEL-AI官网</a>
372
- </div>
373
- </div>
374
- <div class="header" id="home">
375
-
376
- <p>我们的愿景是彻底改变AI代理协作解决现实世界任务的方式。通过利用动态代理交互,OWL能够在多个领域实现更自然、高效和稳健的任务自动化。</p>
377
- </div>
378
- """)
379
-
380
- with gr.Row(elem_id="features"):
381
- gr.HTML("""
382
- <div class="features-section">
383
- <div class="feature-card">
384
- <div class="feature-icon">🔍</div>
385
- <h3>实时信息检索</h3>
386
- <p>利用维基百科、谷歌搜索和其他在线资源获取最新信息。</p>
387
- </div>
388
- <div class="feature-card">
389
- <div class="feature-icon">📹</div>
390
- <h3>多模态处理</h3>
391
- <p>支持处理互联网或本地的视频、图像和音频数据。</p>
392
- </div>
393
- <div class="feature-card">
394
- <div class="feature-icon">🌐</div>
395
- <h3>浏览器自动化</h3>
396
- <p>使用Playwright框架模拟浏览器交互,实现网页操作自动化。</p>
397
- </div>
398
- <div class="feature-card">
399
- <div class="feature-icon">📄</div>
400
- <h3>文档解析</h3>
401
- <p>从各种文档格式中提取内容,并转换为易于处理的格式。</p>
402
- </div>
403
- <div class="feature-card">
404
- <div class="feature-icon">💻</div>
405
- <h3>代码执行</h3>
406
- <p>使用解释器编写和运行Python代码,实现自动化数据处理。</p>
407
- </div>
408
- <div class="feature-card">
409
- <div class="feature-icon">🧰</div>
410
- <h3>内置工具包</h3>
411
- <p>提供丰富的工具包,支持搜索、数据分析、代码执行等多种功能。</p>
412
- </div>
413
- </div>
414
- """)
415
 
416
  with gr.Row():
417
- with gr.Column(scale=2):
418
  question_input = gr.Textbox(
419
  lines=5,
420
  placeholder="请输入您的问题...",
@@ -441,43 +388,125 @@ def create_ui():
441
  )
442
 
443
  run_button = gr.Button("运行", variant="primary", elem_classes="primary")
 
 
 
 
 
 
 
444
 
445
- with gr.Column(scale=1):
446
- gr.Markdown("""
447
- ### 使用指南
448
-
449
- 1. **选择适合的模块**:根据您的任务需求选择合适的功能模块
450
- 2. **详细描述您的需求**:在输入框中清晰描述您的问题或任务
451
- 3. **启动智能处理**:点击"运行"按钮开始多智能体协作处理
452
- 4. **查看结果**:在下方标签页查看回答和完整对话历史
453
-
454
- > **高级提示**: 对于复杂任务,可以尝试指定具体步骤和预期结果
455
- """)
456
-
457
- status_output = gr.Textbox(label="状态", interactive=False)
458
-
459
- with gr.Tabs():
460
- with gr.TabItem("回答"):
461
- answer_output = gr.Textbox(
462
- label="回答",
463
- lines=10,
464
- elem_classes="answer-box"
465
- )
466
 
467
- with gr.TabItem("对话历史"):
468
- chat_output = gr.Chatbot(
469
- label="完整对话记录",
470
- elem_classes="chat-container",
471
- height=500
472
- )
 
 
 
 
 
 
 
 
473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
 
475
-
476
- token_count_output = gr.Textbox(
477
- label="令牌计数",
478
- interactive=False,
479
- elem_classes="token-count"
480
- )
481
 
482
  # 示例问题
483
  examples = [
@@ -492,6 +521,10 @@ def create_ui():
492
  examples=examples,
493
  inputs=question_input
494
  )
 
 
 
 
495
 
496
  gr.HTML("""
497
  <div class="footer" id="about">
@@ -521,6 +554,8 @@ def create_ui():
521
  # 主函数
522
  def main():
523
  try:
 
 
524
  app = create_ui()
525
  app.launch(share=False)
526
  except Exception as e:
 
2
  from owl.utils import run_society
3
  import os
4
  import gradio as gr
5
+ import time
6
+ import json
7
  from typing import Tuple, List, Dict, Any
8
  import importlib
9
+ from dotenv import load_dotenv, set_key, find_dotenv, unset_key
10
 
11
  os.environ['PYTHONIOENCODING'] = 'utf-8'
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # Dictionary containing module descriptions
16
+ MODULE_DESCRIPTIONS = {
17
+ "run": "默认模式:使用OpenAI模型的默认的智能体协作模式,适合大多数任务。",
18
+ "run_mini":"使用使用OpenAI模型最小化配置处理任务",
19
+ "run_deepseek_zh":"使用deepseek模型处理中文任务",
20
+ "run_terminal_zh": "终端模式:可执行命令行操作,支持网络搜索、文件处理等功能。适合需要系统交互的任务,使用OpenAI模型",
21
+ "run_gaia_roleplaying":"GAIA基准测试实现,用于评估Agent能力",
22
+ "run_openai_compatiable_model":"使用openai兼容模型处理任务",
23
+ "run_ollama":"使用本地ollama模型处理任务",
24
+ "run_qwen_mini_zh":"使用qwen模型最小化配置处理任务",
25
+ "run_qwen_zh":"使用qwen模型处理任务",
26
  }
27
 
28
+ # API帮助信息
29
+ API_HELP_INFO = {
30
+ "OPENAI_API_KEY": {
31
+ "name": "OpenAI API",
32
+ "desc": "OpenAI API密钥,用于访问GPT系列模型",
33
+ "url": "https://platform.openai.com/api-keys"
34
+ },
35
+ "QWEN_API_KEY": {
36
+ "name": "通义千问 API",
37
+ "desc": "阿里云通义千问API密钥",
38
+ "url": "https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key"
39
+ },
40
+ "DEEPSEEK_API_KEY": {
41
+ "name": "DeepSeek API",
42
+ "desc": "DeepSeek API密钥",
43
+ "url": "https://platform.deepseek.com/api_keys"
44
+ },
45
+ "GOOGLE_API_KEY": {
46
+ "name": "Google Search API",
47
+ "desc": "Google自定义搜索API密钥",
48
+ "url": "https://developers.google.com/custom-search/v1/overview"
49
+ },
50
+ "SEARCH_ENGINE_ID": {
51
+ "name": "Google Search Engine ID",
52
+ "desc": "Google自定义搜索引擎ID",
53
+ "url": "https://developers.google.com/custom-search/v1/overview"
54
+ },
55
+ "HF_TOKEN": {
56
+ "name": "Hugging Face API",
57
+ "desc": "Hugging Face API令牌",
58
+ "url": "https://huggingface.co/join"
59
+ },
60
+ "CHUNKR_API_KEY": {
61
+ "name": "Chunkr API",
62
+ "desc": "Chunkr API密钥",
63
+ "url": "https://chunkr.ai/"
64
+ },
65
+ "FIRECRAWL_API_KEY": {
66
+ "name": "Firecrawl API",
67
+ "desc": "Firecrawl API密钥",
68
+ "url": "https://www.firecrawl.dev/"
69
  }
70
  }
71
 
72
+ # 默认环境变量模板
73
+ DEFAULT_ENV_TEMPLATE = """# MODEL & API (See https://docs.camel-ai.org/key_modules/models.html#)
 
 
 
 
 
 
 
 
 
74
 
75
+ # OPENAI API
76
+ # OPENAI_API_KEY= ""
77
+ # OPENAI_API_BASE_URL=""
 
 
78
 
79
+ # Qwen API (https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key)
80
+ # QWEN_API_KEY=""
 
 
 
 
81
 
82
+ # DeepSeek API (https://platform.deepseek.com/api_keys)
83
+ # DEEPSEEK_API_KEY=""
 
 
84
 
85
+ #===========================================
86
+ # Tools & Services API
87
+ #===========================================
 
 
88
 
89
+ # Google Search API (https://developers.google.com/custom-search/v1/overview)
90
+ GOOGLE_API_KEY=""
91
+ SEARCH_ENGINE_ID=""
 
 
 
 
 
 
 
92
 
93
+ # Hugging Face API (https://huggingface.co/join)
94
+ HF_TOKEN=""
 
 
95
 
96
+ # Chunkr API (https://chunkr.ai/)
97
+ CHUNKR_API_KEY=""
 
 
 
98
 
99
+ # Firecrawl API (https://www.firecrawl.dev/)
100
+ FIRECRAWL_API_KEY=""
101
+ #FIRECRAWL_API_URL="https://api.firecrawl.dev"
 
 
102
  """
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  def format_chat_history(chat_history: List[Dict[str, str]]) -> List[List[str]]:
105
  """将聊天历史格式化为Gradio聊天组件可接受的格式
106
 
 
158
  )
159
 
160
  try:
161
+ # 确保环境变量已加载
162
+ load_dotenv(find_dotenv(), override=True)
163
  # 检查模块是否在MODULE_DESCRIPTIONS中
164
  if example_module not in MODULE_DESCRIPTIONS:
165
  return (
 
253
  """返回所选模块的描述"""
254
  return MODULE_DESCRIPTIONS.get(module_name, "无可用描述")
255
 
256
+ # 环境变量管理功能
257
+ def init_env_file():
258
+ """初始化.env文件如果不存在"""
259
+ dotenv_path = find_dotenv()
260
+ if not dotenv_path:
261
+ with open(".env", "w") as f:
262
+ f.write(DEFAULT_ENV_TEMPLATE)
263
+ dotenv_path = find_dotenv()
264
+ return dotenv_path
265
+
266
+ def load_env_vars():
267
+ """加载环境变量并返回字典格式"""
268
+ dotenv_path = init_env_file()
269
+ load_dotenv(dotenv_path, override=True)
270
+
271
+ env_vars = {}
272
+ with open(dotenv_path, "r") as f:
273
+ for line in f:
274
+ line = line.strip()
275
+ if line and not line.startswith("#"):
276
+ if "=" in line:
277
+ key, value = line.split("=", 1)
278
+ env_vars[key.strip()] = value.strip().strip('"\'')
279
+
280
+ return env_vars
281
+
282
+ def save_env_vars(env_vars):
283
+ """保存环境变量到.env文件"""
284
+ try:
285
+ dotenv_path = init_env_file()
286
+
287
+ # 保存每个环境变量
288
+ for key, value in env_vars.items():
289
+ if key and key.strip(): # 确保键不为空
290
+ set_key(dotenv_path, key.strip(), value.strip())
291
+
292
+ # 重新加载环境变量以确保��效
293
+ load_dotenv(dotenv_path, override=True)
294
+
295
+ return True, "环境变量已成功保存!"
296
+ except Exception as e:
297
+ return False, f"保存环境变量时出错: {str(e)}"
298
+
299
+ def add_env_var(key, value):
300
+ """添加或更新单个环境变量"""
301
+ try:
302
+ if not key or not key.strip():
303
+ return False, "变量名不能为空"
304
+
305
+ dotenv_path = init_env_file()
306
+ set_key(dotenv_path, key.strip(), value.strip())
307
+ load_dotenv(dotenv_path, override=True)
308
+
309
+ return True, f"环境变量 {key} 已成功添加/更新!"
310
+ except Exception as e:
311
+ return False, f"添加环境变量时出错: {str(e)}"
312
+
313
+ def delete_env_var(key):
314
+ """删除环境变量"""
315
+ try:
316
+ if not key or not key.strip():
317
+ return False, "变量名不能为空"
318
+
319
+ dotenv_path = init_env_file()
320
+ unset_key(dotenv_path, key.strip())
321
+
322
+ # 从当前进程环境中也删除
323
+ if key in os.environ:
324
+ del os.environ[key]
325
+
326
+ return True, f"环境变量 {key} 已成功删除!"
327
+ except Exception as e:
328
+ return False, f"删除环境变量时出错: {str(e)}"
329
+
330
+ def mask_sensitive_value(key: str, value: str) -> str:
331
+ """对敏感信息进行掩码处理
332
+
333
+ Args:
334
+ key: 环境变量名
335
+ value: 环境变量值
336
+
337
+ Returns:
338
+ str: 处理后的值
339
+ """
340
+ # 定义需要掩码的敏感关键词
341
+ sensitive_keywords = ['key', 'token', 'secret', 'password', 'api']
342
+
343
+ # 检查是否包含敏感关键词(不区分大小写)
344
+ is_sensitive = any(keyword in key.lower() for keyword in sensitive_keywords)
345
+
346
+ if is_sensitive and value:
347
+ # 如果是敏感信息且有值,则显示掩码
348
+ return '*' * 8
349
+ return value
350
+
351
+ def update_env_table():
352
+ """更新环境变量表格显示,对敏感信息进行掩码处理"""
353
+ env_vars = load_env_vars()
354
+ # 对敏感值进行掩码处理
355
+ masked_env_vars = [[k, mask_sensitive_value(k, v)] for k, v in env_vars.items()]
356
+ return masked_env_vars
357
+
358
  def create_ui():
359
  """创建增强版Gradio界面"""
360
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as app:
361
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
  with gr.Row():
364
+ with gr.Column(scale=1):
365
  question_input = gr.Textbox(
366
  lines=5,
367
  placeholder="请输入您的问题...",
 
388
  )
389
 
390
  run_button = gr.Button("运行", variant="primary", elem_classes="primary")
391
+
392
+ status_output = gr.Textbox(label="状态", interactive=False)
393
+ token_count_output = gr.Textbox(
394
+ label="令牌计数",
395
+ interactive=False,
396
+ elem_classes="token-count"
397
+ )
398
 
399
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
 
401
+ with gr.Tabs(scale=2):
402
+ with gr.TabItem("回答"):
403
+ answer_output = gr.Textbox(
404
+ label="回答",
405
+ lines=10,
406
+ elem_classes="answer-box"
407
+ )
408
+
409
+ with gr.TabItem("对话历史"):
410
+ chat_output = gr.Chatbot(
411
+ label="完整对话记录",
412
+ elem_classes="chat-container",
413
+ height=500
414
+ )
415
 
416
+ with gr.TabItem("环境变量管理", id="env-settings"):
417
+ gr.Markdown("""
418
+ ## 环境变量管理
419
+
420
+ 在此处设置模型API密钥和其他服务凭证。这些信息将保存在本地的`.env`文件中,确保您的API密钥安全存储且不会上传到网络。
421
+ """)
422
+
423
+ # 添加API密钥获取指南
424
+ gr.Markdown("### API密钥获取指南")
425
+
426
+ for key, info in API_HELP_INFO.items():
427
+ with gr.Accordion(f"{info['name']} ({key})", open=False):
428
+ gr.Markdown(f"""
429
+ - **说明**: {info['desc']}
430
+ - **获取地址**: [{info['url']}]({info['url']})
431
+ """)
432
+
433
+ gr.Markdown("---")
434
+
435
+ # 环境变量表格
436
+ env_table = gr.Dataframe(
437
+ headers=["变量名", "值"],
438
+ datatype=["str", "str"],
439
+ row_count=10,
440
+ col_count=(2, "fixed"),
441
+ value=update_env_table,
442
+ label="当前环境变量",
443
+ interactive=False
444
+ )
445
+
446
+ with gr.Row():
447
+ with gr.Column(scale=1):
448
+ new_env_key = gr.Textbox(label="变量名", placeholder="例如: OPENAI_API_KEY")
449
+ with gr.Column(scale=2):
450
+ new_env_value = gr.Textbox(label="值", placeholder="��入API密钥或其他配置值")
451
+
452
+ with gr.Row():
453
+ add_env_button = gr.Button("添加/更新变量", variant="primary")
454
+ refresh_button = gr.Button("刷新变量列表")
455
+ delete_env_button = gr.Button("删除选定变量", variant="stop")
456
+
457
+ env_status = gr.Textbox(label="状态", interactive=False)
458
+
459
+ # 变量选择器(用于删除)
460
+ env_var_to_delete = gr.Dropdown(
461
+ choices=[],
462
+ label="选择要删除的变量",
463
+ interactive=True
464
+ )
465
+
466
+ # 更新变量选择器的选项
467
+ def update_delete_dropdown():
468
+ env_vars = load_env_vars()
469
+ return gr.Dropdown.update(choices=list(env_vars.keys()))
470
+
471
+ # 连接事件处理函数
472
+ add_env_button.click(
473
+ fn=lambda k, v: add_env_var(k, v),
474
+ inputs=[new_env_key, new_env_value],
475
+ outputs=[env_status]
476
+ ).then(
477
+ fn=update_env_table,
478
+ outputs=[env_table]
479
+ ).then(
480
+ fn=update_delete_dropdown,
481
+ outputs=[env_var_to_delete]
482
+ ).then(
483
+ fn=lambda: ("", ""), # 修改为返回两个空字符串的元组
484
+ outputs=[new_env_key, new_env_value]
485
+ )
486
+
487
+ refresh_button.click(
488
+ fn=update_env_table,
489
+ outputs=[env_table]
490
+ ).then(
491
+ fn=update_delete_dropdown,
492
+ outputs=[env_var_to_delete]
493
+ )
494
+
495
+ delete_env_button.click(
496
+ fn=lambda k: delete_env_var(k),
497
+ inputs=[env_var_to_delete],
498
+ outputs=[env_status]
499
+ ).then(
500
+ fn=update_env_table,
501
+ outputs=[env_table]
502
+ ).then(
503
+ fn=update_delete_dropdown,
504
+ outputs=[env_var_to_delete]
505
+ )
506
+
507
+
508
 
509
+
 
 
 
 
 
510
 
511
  # 示例问题
512
  examples = [
 
521
  examples=examples,
522
  inputs=question_input
523
  )
524
+
525
+
526
+
527
+
528
 
529
  gr.HTML("""
530
  <div class="footer" id="about">
 
554
  # 主函数
555
  def main():
556
  try:
557
+ # 初始化.env文件(如果不存在)
558
+ init_env_file()
559
  app = create_ui()
560
  app.launch(share=False)
561
  except Exception as e: