JC321 commited on
Commit
39d15d3
·
verified ·
1 Parent(s): fce88e6

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +156 -38
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import gradio as gr
2
  import requests
3
  import json
 
4
 
5
  MCP_SPACE = "JC321/EasyReportDateMCP"
6
  MCP_URL = "https://jc321-easyreportdatemcp.hf.space"
@@ -11,11 +12,39 @@ HEADERS = {
11
  "User-Agent": "SEC-Query-Assistant/1.0 (jtyxabc@gmail.com)"
12
  }
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def query_financial_data(company_name, query_type):
15
  """查询财务数据的主函数"""
16
 
17
  if not company_name:
18
- return "请输入公司名称或股票代码"
 
 
 
 
 
 
 
 
19
 
20
  try:
21
  # 直接调用 FastAPI 的 REST API 端点
@@ -45,7 +74,7 @@ def query_financial_data(company_name, query_type):
45
  cik = company.get('cik')
46
 
47
  # 根据查询类型获取数据
48
- if query_type == "最新财务数据":
49
  data_resp = requests.post(
50
  f"{MCP_URL}/api/get_latest_financial_data",
51
  json={"cik": cik},
@@ -64,15 +93,23 @@ def query_financial_data(company_name, query_type):
64
  if isinstance(data, dict) and data.get("error"):
65
  return result + f"❌ {data['error']}"
66
 
67
- result += f"## 财年 {data.get('period', 'N/A')}\n\n"
68
- result += f"- **总收入**: ${data.get('total_revenue', 0):,.0f} (${data.get('total_revenue', 0)/1e9:.2f}B)\n"
69
- result += f"- **净利润**: ${data.get('net_income', 0):,.0f} (${data.get('net_income', 0)/1e9:.2f}B)\n"
70
- result += f"- **每股收益**: ${data.get('earnings_per_share', 0):.2f}\n"
71
- result += f"- **运营花费**: ${data.get('operating_expenses', 0):,.0f} (${data.get('operating_expenses', 0)/1e9:.2f}B)\n"
72
- result += f"- **运营现金流**: ${data.get('operating_cash_flow', 0):,.0f} (${data.get('operating_cash_flow', 0)/1e9:.2f}B)\n"
73
- result += f"- **来源**: {data.get('source_form', 'N/A')}\n"
 
 
 
 
 
 
 
 
74
 
75
- elif query_type == "3年趋势":
76
  metrics_resp = requests.post(
77
  f"{MCP_URL}/api/extract_financial_metrics",
78
  json={"cik": cik, "years": 3},
@@ -103,15 +140,19 @@ def query_financial_data(company_name, query_type):
103
  period = m.get('period', 'N/A')
104
  rev = (m.get('total_revenue') or 0) / 1e9
105
  inc = (m.get('net_income') or 0) / 1e9
106
- eps = m.get('earnings_per_share') or 0
107
  opex = (m.get('operating_expenses') or 0) / 1e9
108
  ocf = (m.get('operating_cash_flow') or 0) / 1e9
109
- source = m.get('source_form', 'N/A')
 
 
110
  # 区分年度和季度
111
  period_prefix = "FY" if 'Q' not in period else ""
112
- result += f"| {period_prefix}{period} | ${rev:.2f}B | ${inc:.2f}B | ${eps:.2f} | ${opex:.2f}B | ${ocf:.2f}B | {source} |\n"
 
 
113
 
114
- elif query_type == "5年趋势":
115
  metrics_resp = requests.post(
116
  f"{MCP_URL}/api/extract_financial_metrics",
117
  json={"cik": cik, "years": 5},
@@ -141,13 +182,17 @@ def query_financial_data(company_name, query_type):
141
  period = m.get('period', 'N/A')
142
  rev = (m.get('total_revenue') or 0) / 1e9
143
  inc = (m.get('net_income') or 0) / 1e9
144
- eps = m.get('earnings_per_share') or 0
145
  opex = (m.get('operating_expenses') or 0) / 1e9
146
  ocf = (m.get('operating_cash_flow') or 0) / 1e9
147
- source = m.get('source_form', 'N/A')
 
 
148
  # 区分年度和季度
149
  period_prefix = "FY" if 'Q' not in period else ""
150
- result += f"| {period_prefix}{period} | ${rev:.2f}B | ${inc:.2f}B | ${eps:.2f} | ${opex:.2f}B | ${ocf:.2f}B | {source} |\n"
 
 
151
 
152
  return result
153
 
@@ -157,35 +202,108 @@ def query_financial_data(company_name, query_type):
157
  import traceback
158
  return f"❌ Unexpected Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  # 创建 Gradio 界面
161
  with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
162
- gr.Markdown("# 🤖 SEC 财务数据查询助手")
163
- gr.Markdown("通过调用 MCP Server 查询美国上市公司的财务数据")
164
 
165
  with gr.Row():
166
- company_input = gr.Textbox(
167
- label="公司名称或股票代码",
168
- placeholder="例如: NVIDIA, Apple, Alibaba, AAPL",
169
- scale=2
170
- )
171
- query_type = gr.Radio(
172
- ["最新财务数据", "3年趋势", "5年趋势"],
173
- label="查询类型",
174
- value="最新财务数据",
175
- scale=1
176
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
- submit_btn = gr.Button("🔍 查询", variant="primary", size="lg")
179
- output = gr.Markdown(label="查询结果")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  # 示例
182
  gr.Examples(
183
  examples=[
184
- ["NVIDIA", "最新财务数据"],
185
- ["Apple", "3年趋势"],
186
- ["Microsoft", "5年趋势"],
187
- ["Alibaba", "最新财务数据"],
188
- ["Tesla", "3年趋势"]
189
  ],
190
  inputs=[company_input, query_type],
191
  outputs=output,
@@ -200,6 +318,6 @@ with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
200
  )
201
 
202
  gr.Markdown("---")
203
- gr.Markdown(f"**数据来源**: SEC EDGAR | **MCP Server**: `{MCP_URL}`")
204
 
205
  demo.launch()
 
1
  import gradio as gr
2
  import requests
3
  import json
4
+ import os
5
 
6
  MCP_SPACE = "JC321/EasyReportDateMCP"
7
  MCP_URL = "https://jc321-easyreportdatemcp.hf.space"
 
12
  "User-Agent": "SEC-Query-Assistant/1.0 (jtyxabc@gmail.com)"
13
  }
14
 
15
+ # 格式化数值显示
16
+ def format_value(value, is_money=True):
17
+ """格式化数值:0显示为N/A,其他显示为带单位的格式"""
18
+ if value is None or value == 0:
19
+ return "N/A"
20
+ if is_money:
21
+ return f"${value:.2f}B"
22
+ else:
23
+ return f"{value:.2f}"
24
+
25
+ # 创建超链接
26
+ def create_source_link(source_form, cik=None):
27
+ """为Source Form创建SEC EDGAR超链接"""
28
+ if not source_form or source_form == 'N/A' or not cik:
29
+ return source_form
30
+
31
+ # 构建SEC EDGAR链接(这是一个示例,实际链接需要更多参数)
32
+ edgar_url = f"https://www.sec.gov/edgar/browse/?CIK={cik}"
33
+ return f"[{source_form}]({edgar_url})"
34
+
35
  def query_financial_data(company_name, query_type):
36
  """查询财务数据的主函数"""
37
 
38
  if not company_name:
39
+ return "Please enter a company name or stock symbol"
40
+
41
+ # 翻译英文查询类型为中文(用于后端处理)
42
+ query_type_mapping = {
43
+ "Latest Financial Data": "最新财务数据",
44
+ "3-Year Trends": "3年趋势",
45
+ "5-Year Trends": "5年趋势"
46
+ }
47
+ internal_query_type = query_type_mapping.get(query_type, query_type)
48
 
49
  try:
50
  # 直接调用 FastAPI 的 REST API 端点
 
74
  cik = company.get('cik')
75
 
76
  # 根据查询类型获取数据
77
+ if internal_query_type == "最新财务数据":
78
  data_resp = requests.post(
79
  f"{MCP_URL}/api/get_latest_financial_data",
80
  json={"cik": cik},
 
93
  if isinstance(data, dict) and data.get("error"):
94
  return result + f"❌ {data['error']}"
95
 
96
+ cik = data.get('cik')
97
+ result += f"## Fiscal Year {data.get('period', 'N/A')}\n\n"
98
+
99
+ total_revenue = data.get('total_revenue', 0) / 1e9 if data.get('total_revenue') else 0
100
+ net_income = data.get('net_income', 0) / 1e9 if data.get('net_income') else 0
101
+ eps = data.get('earnings_per_share', 0) if data.get('earnings_per_share') else 0
102
+ opex = data.get('operating_expenses', 0) / 1e9 if data.get('operating_expenses') else 0
103
+ ocf = data.get('operating_cash_flow', 0) / 1e9 if data.get('operating_cash_flow') else 0
104
+
105
+ result += f"- **Total Revenue**: {format_value(total_revenue)}\n"
106
+ result += f"- **Net Income**: {format_value(net_income)}\n"
107
+ result += f"- **Earnings Per Share**: {format_value(eps, False)}\n"
108
+ result += f"- **Operating Expenses**: {format_value(opex)}\n"
109
+ result += f"- **Operating Cash Flow**: {format_value(ocf)}\n"
110
+ result += f"- **Source Form**: {create_source_link(data.get('source_form', 'N/A'), cik)}\n"
111
 
112
+ elif internal_query_type == "3年趋势":
113
  metrics_resp = requests.post(
114
  f"{MCP_URL}/api/extract_financial_metrics",
115
  json={"cik": cik, "years": 3},
 
140
  period = m.get('period', 'N/A')
141
  rev = (m.get('total_revenue') or 0) / 1e9
142
  inc = (m.get('net_income') or 0) / 1e9
143
+ eps_val = m.get('earnings_per_share') or 0
144
  opex = (m.get('operating_expenses') or 0) / 1e9
145
  ocf = (m.get('operating_cash_flow') or 0) / 1e9
146
+ source_form = m.get('source_form', 'N/A')
147
+ cik_val = m.get('cik') or cik
148
+
149
  # 区分年度和季度
150
  period_prefix = "FY" if 'Q' not in period else ""
151
+ source_link = create_source_link(source_form, cik_val)
152
+
153
+ result += f"| {period_prefix}{period} | {format_value(rev)} | {format_value(inc)} | {format_value(eps_val, False)} | {format_value(opex)} | {format_value(ocf)} | {source_link} |\n"
154
 
155
+ elif internal_query_type == "5年趋势":
156
  metrics_resp = requests.post(
157
  f"{MCP_URL}/api/extract_financial_metrics",
158
  json={"cik": cik, "years": 5},
 
182
  period = m.get('period', 'N/A')
183
  rev = (m.get('total_revenue') or 0) / 1e9
184
  inc = (m.get('net_income') or 0) / 1e9
185
+ eps_val = m.get('earnings_per_share') or 0
186
  opex = (m.get('operating_expenses') or 0) / 1e9
187
  ocf = (m.get('operating_cash_flow') or 0) / 1e9
188
+ source_form = m.get('source_form', 'N/A')
189
+ cik_val = m.get('cik') or cik
190
+
191
  # 区分年度和季度
192
  period_prefix = "FY" if 'Q' not in period else ""
193
+ source_link = create_source_link(source_form, cik_val)
194
+
195
+ result += f"| {period_prefix}{period} | {format_value(rev)} | {format_value(inc)} | {format_value(eps_val, False)} | {format_value(opex)} | {format_value(ocf)} | {source_link} |\n"
196
 
197
  return result
198
 
 
202
  import traceback
203
  return f"❌ Unexpected Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
204
 
205
+ # Chatbot 功能:使用MCP工具
206
+ def chatbot_response(message, history):
207
+ """聊天机器人响应函数,集成MCP工具"""
208
+ try:
209
+ # 检查是否是财务查询相关问题
210
+ if any(keyword in message.lower() for keyword in ['financial', 'revenue', 'income', 'earnings', 'cash flow', 'expenses', '财务', '收入', '利润']):
211
+ # 提取公司名称和查询类型
212
+ company_keywords = ['apple', 'microsoft', 'nvidia', 'tesla', 'alibaba', 'google', 'amazon']
213
+ detected_company = None
214
+
215
+ for company in company_keywords:
216
+ if company in message.lower():
217
+ detected_company = company.capitalize()
218
+ break
219
+
220
+ if detected_company:
221
+ # 根据问题内容选择查询类型
222
+ if 'trend' in message.lower() or '趋势' in message:
223
+ if '5' in message or 'five' in message:
224
+ query_type = '5-Year Trends'
225
+ else:
226
+ query_type = '3-Year Trends'
227
+ else:
228
+ query_type = 'Latest Financial Data'
229
+
230
+ # 调用财务查询函数
231
+ result = query_financial_data(detected_company, query_type)
232
+ return f"I found financial information for {detected_company}:\n\n{result}"
233
+
234
+ # 如果不是财务查询,返回通用回复
235
+ return "Hello! I'm a financial data assistant. I can help you query SEC financial data for US listed companies. Try asking about companies like Apple, Microsoft, NVIDIA, Tesla, or Alibaba. For example: 'Show me Apple's latest financial data' or 'What's NVIDIA's 3-year trend?'"
236
+
237
+ except Exception as e:
238
+ return f"Sorry, I encountered an error: {str(e)}. Please try asking about financial data for specific companies."
239
+
240
  # 创建 Gradio 界面
241
  with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
242
+ gr.Markdown("# 🤖 SEC Financial Data Query Assistant")
243
+ gr.Markdown("Query SEC financial data for US listed companies through MCP Server")
244
 
245
  with gr.Row():
246
+ # 左侧:聊天机器人
247
+ with gr.Column(scale=1):
248
+ gr.Markdown("## 💬 AI Financial Assistant")
249
+ chatbot = gr.Chatbot(
250
+ height=500,
251
+ placeholder="Ask me about financial data for any US listed company!",
252
+ label="Chat with AI Assistant"
253
+ )
254
+ chat_input = gr.Textbox(
255
+ placeholder="e.g., 'Show me Apple's latest financial data' or 'What's NVIDIA's 3-year trend?'",
256
+ label="Your Question",
257
+ lines=2
258
+ )
259
+ chat_submit = gr.Button("🗨️ Send", variant="primary")
260
+
261
+ # 右侧:原有的查询界面
262
+ with gr.Column(scale=1):
263
+ gr.Markdown("## 🔍 Direct Query")
264
+ with gr.Row():
265
+ company_input = gr.Textbox(
266
+ label="Company Name or Stock Symbol",
267
+ placeholder="e.g., NVIDIA, Apple, Alibaba, AAPL",
268
+ scale=2
269
+ )
270
+ query_type = gr.Radio(
271
+ ["Latest Financial Data", "3-Year Trends", "5-Year Trends"],
272
+ label="Query Type",
273
+ value="Latest Financial Data",
274
+ scale=1
275
+ )
276
+
277
+ submit_btn = gr.Button("🔍 Query", variant="primary", size="lg")
278
+ output = gr.Markdown(label="Query Results")
279
 
280
+ # 聊天机器人事件
281
+ chat_submit.click(
282
+ fn=chatbot_response,
283
+ inputs=[chat_input, chatbot],
284
+ outputs=chatbot
285
+ ).then(
286
+ lambda: "",
287
+ outputs=chat_input
288
+ )
289
+
290
+ chat_input.submit(
291
+ fn=chatbot_response,
292
+ inputs=[chat_input, chatbot],
293
+ outputs=chatbot
294
+ ).then(
295
+ lambda: "",
296
+ outputs=chat_input
297
+ )
298
 
299
  # 示例
300
  gr.Examples(
301
  examples=[
302
+ ["NVIDIA", "Latest Financial Data"],
303
+ ["Apple", "3-Year Trends"],
304
+ ["Microsoft", "5-Year Trends"],
305
+ ["Alibaba", "Latest Financial Data"],
306
+ ["Tesla", "3-Year Trends"]
307
  ],
308
  inputs=[company_input, query_type],
309
  outputs=output,
 
318
  )
319
 
320
  gr.Markdown("---")
321
+ gr.Markdown(f"**Data Source**: SEC EDGAR | **MCP Server**: `{MCP_URL}`")
322
 
323
  demo.launch()