MGGroup commited on
Commit
18f4f0a
·
verified ·
1 Parent(s): 64e9ea2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -52
app.py CHANGED
@@ -2,86 +2,103 @@ import gradio as gr
2
  import requests
3
  import os
4
  import json
 
 
5
 
6
  # --- 核心配置 ---
7
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY")
8
- MODEL_ID = "google/gemini-2.0-flash-001"
9
 
10
- # --- 核心声明 HTML (保持不变) ---
11
  INFO_HTML = """
12
  <div style="text-align: left; border-left: 4px solid #2196F3; padding-left: 15px; margin-bottom: 20px;">
13
  <h3>MG TaxAI | 跨境财税合规实验室 (Beta)</h3>
14
- <p>本系统已关联 <b>MG 内部知识库</b> (Treaties & InvestmentGuide)。</p>
 
 
15
  <p style="font-size: 0.85em; color: #666;">
16
- <b>⚠️ AI 免责声明:</b>回答仅供参考,不构成正式税务建议。
 
17
  </p>
18
  </div>
19
  """
20
 
21
- # --- 模拟知识库检索 (RAG 核心) ---
22
- def search_knowledge_base(query):
23
  """
24
- 这里应该是你搜索 PDF逻辑
25
- 目前我先帮你写好框架,后续我们可以接入向量数据库或简单文件夹匹配。
26
  """
27
- # 示例:如果是搜索丹麦,你可以让程序去 Treaties 文件夹找相关内容
28
- # 暂时返回一个提醒,实际运行时这里应返回提取到的 PDF 文本内容
29
- return "已检索知识库:Treaties/Denmark, InvestmentGuide/Global_Tax_2025."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- # --- API 调用逻辑 ---
32
  def ask_ai(message, history):
33
  if not OPENROUTER_API_KEY:
34
- return "错误:未检测到 API Key。"
35
 
36
- url = "https://openrouter.ai/api/v1/chat/completions"
37
- headers = {
38
- "Authorization": f"Bearer {OPENROUTER_API_KEY}",
39
- "Content-Type": "application/json"
40
- }
41
 
42
- # 1. 构建对话历史 (修正 Gradio 的 [[u,b],[u,b]] 格式)
43
- formatted_messages = [
44
- {"role": "system", "content": "你是一个专业的国际税务专家。你必须基于 MG Consulting 的内部知识库(税收协定 Treaties 和 投资指南 InvestmentGuide)回答问题。如果不知道,请告知用户正在装载数据。"}
45
- ]
46
-
47
- # 循环处理历史记录确保逻辑连贯
48
- for user_msg, assistant_msg in history:
49
- formatted_messages.append({"role": "user", "content": user_msg})
50
- formatted_messages.append({"role": "assistant", "content": assistant_msg})
 
51
 
52
- # 2. 检索当前问题的背景知识 (RAG)
53
- # 在实际生产中,我们会根据 message 去搜索具体的 PDF 内容
54
- context = search_knowledge_base(message)
 
 
55
 
56
- # 3. 当前问题和背景知识合并发送
57
- final_user_input = f"参考背景:{context}\n\n当前问题:{message}"
58
- formatted_messages.append({"role": "user", "content": final_user_input})
59
 
 
 
 
60
  payload = {
61
  "model": MODEL_ID,
62
- "messages": formatted_messages,
63
- "temperature": 0.3, # 降低随机性,确保税务建议严谨
 
64
  }
65
 
66
  try:
67
- response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=60)
68
  if response.status_code == 200:
69
  return response.json()['choices'][0]['message']['content']
70
- return f"接口异常: {response.status_code} - {response.text}"
71
  except Exception as e:
72
- return f"连接失败: {str(e)}"
73
-
74
- # --- 构建界面 ---
75
- with gr.Blocks(title="MG Consulting TaxAI", fill_height=True) as demo:
76
- gr.HTML(INFO_HTML)
77
-
78
- chat_interface = gr.ChatInterface(
79
- fn=ask_ai,
80
- fill_height=True,
81
- retry_btn="🔄 重试",
82
- undo_btn="↩️ 撤回",
83
- clear_btn="🗑️ 清除记录",
84
- )
85
 
86
- if __name__ == "__main__":
87
- demo.launch()
 
2
  import requests
3
  import os
4
  import json
5
+ import fitz # PyMuPDF
6
+ from pathlib import Path
7
 
8
  # --- 核心配置 ---
9
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY")
10
+ MODEL_ID = "google/gemini-2.0-flash-001" # 性能与稳定性的平衡点
11
 
12
+ # --- 你的专属 HTML 声明 (完整) ---
13
  INFO_HTML = """
14
  <div style="text-align: left; border-left: 4px solid #2196F3; padding-left: 15px; margin-bottom: 20px;">
15
  <h3>MG TaxAI | 跨境财税合规实验室 (Beta)</h3>
16
+ <p>本系统依托 <b>MG 核心智库</b> 构建,旨在实现解析结果实时溯源至各国官方税收协定与法律文本。目前系统正处于<b>知识库全量装载阶段</b>,已优先上线核心业务国家的官方协定库。</p>
17
+ <p>我们正持续同步全球各主要经济体的国别投资税收指南及多税种年度税收报告。受限于测试版的数据填充进度,相关解析结果仅供专业参考。MG团队正加速完善每一条咨询建议的合规证据链,以确保交付专家级的数字化合规支持。</p>
18
+ <hr style="border: 0; border-top: 1px solid #eee; margin: 10px 0;">
19
  <p style="font-size: 0.85em; color: #666;">
20
+ <b>⚠️ AI 免责声明:</b><br>
21
+ 本系统生成的内容由人工智能根据现有库文件分析得出,不构成正式的法律或税务建议。在使用本系统结果进行任何商业决策前,请务必咨询 MG Consult 专业团队。
22
  </p>
23
  </div>
24
  """
25
 
26
+ # --- 深度知识库检索引擎 (RAG) ---
27
+ def get_knowledge_context(query):
28
  """
29
+ 扫描本地 Treaties 和 InvestmentGuide 件夹中相关 PDF 内容
30
+ 这里实现一个基础关键词匹配检索,确保 AI 能“读”到书
31
  """
32
+ context_chunks = []
33
+ base_dirs = ["Treaties", "InvestmentGuide"]
34
+
35
+ # 简单的关键词提取(可以根据需要改进)
36
+ keywords = [word for word in query.split() if len(word) > 1]
37
+
38
+ for folder in base_dirs:
39
+ path = Path(folder)
40
+ if not path.exists(): continue
41
+
42
+ # 扫描文件夹下的 PDF
43
+ for pdf_file in path.rglob("*.pdf"):
44
+ # 如果文件名包含关键词,优先读取
45
+ if any(kw.lower() in pdf_file.name.lower() for kw in keywords):
46
+ try:
47
+ with fitz.open(pdf_file) as doc:
48
+ # 提取前 2 页的核心内容(防止 Token 溢出)
49
+ text = "".join([page.get_text() for page in doc[:2]])
50
+ context_chunks.append(f"来自文件 [{pdf_file.name}]:\n{text}")
51
+ except:
52
+ continue
53
+
54
+ return "\n\n".join(context_chunks)[:4000] # 限制长度,保证 API 响应速度
55
 
56
+ # --- API 专家级调用逻辑 ---
57
  def ask_ai(message, history):
58
  if not OPENROUTER_API_KEY:
59
+ return "⚠️ 未检测到 API Key,请检查环境变量设置。"
60
 
61
+ # 1. 获取本地知识库背景
62
+ local_context = get_knowledge_context(message)
 
 
 
63
 
64
+ # 2. 构造专家级指令 (System Prompt)
65
+ # 这里决定了回复的质量和长度
66
+ system_instruction = """
67
+ 你是一位资深的 MG Consulting 国际税务合规专家。
68
+ 你的回答必须具备以下特征:
69
+ 1. 深度:不仅给出结论还要解释背后的税法逻辑
70
+ 2. 广度:考虑多税种(所得税、���值税、预提税等)及双边协定影响。
71
+ 3. 严谨:优先引用提供的背景知识。如果背景中没有,请基于 2025-2026 年最新财税知识库回答。
72
+ 4. 结构:使用 Markdown 标题、列表和加粗,使回复易于阅读且专业。
73
+ """
74
 
75
+ # 3. 组装对话历史
76
+ messages = [{"role": "system", "content": system_instruction}]
77
+ for user_msg, assistant_msg in history:
78
+ messages.append({"role": "user", "content": user_msg})
79
+ messages.append({"role": "assistant", "content": assistant_msg})
80
 
81
+ # 4. 组装当前请求
82
+ current_input = f"参考知识库内容】\n{local_context}\n\n【用户当前咨询】\n{message}"
83
+ messages.append({"role": "user", "content": current_input})
84
 
85
+ # 5. 发送请求
86
+ url = "https://openrouter.ai/api/v1/chat/completions"
87
+ headers = {"Authorization": f"Bearer {OPENROUTER_API_KEY}", "Content-Type": "application/json"}
88
  payload = {
89
  "model": MODEL_ID,
90
+ "messages": messages,
91
+ "temperature": 0.2, # 降低随机性,提升严谨
92
+ "top_p": 0.9
93
  }
94
 
95
  try:
96
+ response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=90)
97
  if response.status_code == 200:
98
  return response.json()['choices'][0]['message']['content']
99
+ return f"接口响应异常 ({response.status_code}): {response.text}"
100
  except Exception as e:
101
+ return f"💥 系统连接超时或失败: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
+ # --- 界面构建 ---
104
+ with gr