JC321 commited on
Commit
c8af871
·
verified ·
1 Parent(s): 2db3948

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +39 -39
  2. app.py +237 -48
  3. requirements.txt +2 -1
README.md CHANGED
@@ -1,39 +1,39 @@
1
- ---
2
- title: SEC Financial Data Query Assistant
3
- emoji: 📊
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 6.0.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- # SEC Financial Data Query Assistant
14
-
15
- A Gradio-based web application for querying SEC financial data through MCP Server.
16
-
17
- ## Features
18
-
19
- - 🔍 Search companies by name or ticker symbol
20
- - 📈 View latest financial data
21
- - 📊 Analyze 3-year and 5-year financial trends
22
- - 💰 Display revenue, net income, EPS, operating expenses, and cash flow metrics
23
-
24
- ## Usage
25
-
26
- Simply enter a company name or ticker symbol (e.g., NVIDIA, AAPL, Microsoft) and select the query type:
27
- - **Latest Financial Data**: Shows the most recent fiscal year data
28
- - **3-Year Trend**: Displays financial trends over 3 years
29
- - **5-Year Trend**: Displays financial trends over 5 years
30
-
31
- ## Data Source
32
-
33
- SEC EDGAR data via MCP Server: https://jc321-easyreportdatemcp.hf.space
34
-
35
- ## Technology Stack
36
-
37
- - **Frontend**: Gradio 4.0+
38
- - **Backend**: Python with requests
39
- - **Data Source**: SEC EDGAR via MCP Server
 
1
+ ---
2
+ title: SEC Financial Data Query Assistant
3
+ emoji: 📊
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 6.0.1
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # SEC Financial Data Query Assistant
14
+
15
+ A Gradio-based web application for querying SEC financial data through MCP Server.
16
+
17
+ ## Features
18
+
19
+ - 🔍 Search companies by name or ticker symbol
20
+ - 📈 View latest financial data
21
+ - 📊 Analyze 3-year and 5-year financial trends
22
+ - 💰 Display revenue, net income, EPS, operating expenses, and cash flow metrics
23
+
24
+ ## Usage
25
+
26
+ Simply enter a company name or ticker symbol (e.g., NVIDIA, AAPL, Microsoft) and select the query type:
27
+ - **Latest Financial Data**: Shows the most recent fiscal year data
28
+ - **3-Year Trend**: Displays financial trends over 3 years
29
+ - **5-Year Trend**: Displays financial trends over 5 years
30
+
31
+ ## Data Source
32
+
33
+ SEC EDGAR data via MCP Server: https://huggingface.co/spaces/JC321/EasyReportDateMCP
34
+
35
+ ## Technology Stack
36
+
37
+ - **Frontend**: Gradio 4.0+
38
+ - **Backend**: Python with requests
39
+ - **Data Source**: SEC EDGAR via MCP Server
app.py CHANGED
@@ -5,9 +5,10 @@ import os
5
  import time
6
  from requests.adapters import HTTPAdapter
7
  from urllib3.util.retry import Retry
 
8
 
9
- MCP_SPACE = "JC321/EasyReportsMCPServer"
10
- MCP_URL = "https://jc321-easyreportsmcpserver.hf.space"
11
 
12
  # 设置请求头
13
  HEADERS = {
@@ -32,6 +33,71 @@ def create_session_with_retry():
32
  # 创建全局 session
33
  session = create_session_with_retry()
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # 格式化数值显示
36
  def format_value(value, value_type="money"):
37
  """
@@ -475,50 +541,180 @@ def query_financial_data(company_name, query_type):
475
  import traceback
476
  return f"❌ Unexpected Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
477
 
478
- # Chatbot 功能:使用MCP工具
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  def chatbot_response(message, history):
480
- """聊天机器人响应函数,集成MCP工具"""
481
  try:
482
- # 检查是否是财务查询相关问题
483
- financial_keywords = ['financial', 'revenue', 'income', 'earnings', 'cash flow', 'expenses', '财务', '收入', '利润', 'data', 'trend', 'performance']
484
-
485
- if any(keyword in message.lower() for keyword in financial_keywords):
486
- # 提取公司名称和查询类型
487
- company_keywords = ['apple', 'microsoft', 'nvidia', 'tesla', 'alibaba', 'google', 'amazon', 'meta', 'tsla', 'aapl', 'msft', 'nvda', 'googl', 'amzn']
488
- detected_company = None
489
-
490
- for company in company_keywords:
491
- if company in message.lower():
492
- if company in ['aapl']: detected_company = 'Apple'
493
- elif company in ['msft']: detected_company = 'Microsoft'
494
- elif company in ['nvda']: detected_company = 'NVIDIA'
495
- elif company in ['tsla']: detected_company = 'Tesla'
496
- elif company in ['googl']: detected_company = 'Google'
497
- elif company in ['amzn']: detected_company = 'Amazon'
498
- else: detected_company = company.capitalize()
499
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
 
501
- if detected_company:
502
- # 根据问题内容选择查询类型
503
- if any(word in message.lower() for word in ['trend', '趋势', 'history', 'historical', 'over time']):
504
- if any(word in message for word in ['5', 'five', '五年']):
505
- query_type = '5-Year Trends'
506
- else:
507
- query_type = '3-Year Trends'
508
- else:
509
- query_type = 'Latest Financial Data'
510
 
511
- # 调用财务查询函数
512
- result = query_financial_data(detected_company, query_type)
513
- return f"Here's the financial information for {detected_company}:\n\n{result}"
514
- else:
515
- return "I can help you query financial data! Please specify a company name. For example: 'Show me Apple's latest financial data' or 'What's NVIDIA's 3-year trend?' \n\nSupported companies include: Apple, Microsoft, NVIDIA, Tesla, Alibaba, Google, Amazon, and more."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
 
517
- # 如果不是财务查询,返回通用回复
518
- return "Hello! I'm a financial data assistant powered by SEC EDGAR data. I can help you query financial information for US listed companies.\n\n**What I can do:**\n- Get latest financial data (revenue, income, EPS, etc.)\n- Show 3-year or 5-year financial trends\n- Provide detailed financial metrics\n\n**Try asking:**\n- 'Show me Apple's latest financial data'\n- 'What's NVIDIA's 3-year financial trend?'\n- 'How is Microsoft performing financially?'"
519
-
520
  except Exception as e:
521
- return f"Sorry, I encountered an error: {str(e)}. Please try asking about financial data for specific companies like Apple, Microsoft, NVIDIA, Tesla, etc."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
  # 包装函数,显示加载状态
524
  def query_with_status(company, query_type):
@@ -540,13 +736,6 @@ def query_with_status(company, query_type):
540
  # 创建 Gradio 界面
541
  with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
542
  gr.Markdown("# 🤖 SEC Financial Data Query Assistant")
543
- gr.Markdown("Query SEC financial data for US listed companies through MCP Server")
544
-
545
- # 添加 MCP Server 状态提示
546
- with gr.Row():
547
- gr.Markdown(f"🔗 **MCP Server**: [{MCP_URL}]({MCP_URL})")
548
- with gr.Row():
549
- gr.Markdown("⚠️ **Note**: First query after idle may take 1-2 minutes (server cold start). Please be patient.")
550
 
551
  with gr.Tab("AI Assistant"):
552
  # 使用 Gradio ChatInterface(兼容 4.44.1)
@@ -609,7 +798,7 @@ with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
609
  )
610
 
611
  gr.Markdown("---")
612
- gr.Markdown(f"**Data Source**: SEC EDGAR | **MCP Server**: `{MCP_URL}`")
613
 
614
  # Launch the app for Hugging Face Space
615
  if __name__ == "__main__":
 
5
  import time
6
  from requests.adapters import HTTPAdapter
7
  from urllib3.util.retry import Retry
8
+ from huggingface_hub import InferenceClient
9
 
10
+ MCP_SPACE = "JC321/EasyReportDateMCP"
11
+ MCP_URL = "https://jc321-easyreportdatemcp.hf.space"
12
 
13
  # 设置请求头
14
  HEADERS = {
 
33
  # 创建全局 session
34
  session = create_session_with_retry()
35
 
36
+ # 初始化 Hugging Face Inference Client
37
+ # 使用环境变量或者免费的公开模型
38
+ HF_TOKEN = os.getenv("HF_TOKEN", None) # 可选:如果需要访问私有模型
39
+ client = InferenceClient(token=HF_TOKEN)
40
+
41
+ # 定义可用的 MCP 工具
42
+ MCP_TOOLS = [
43
+ {
44
+ "type": "function",
45
+ "function": {
46
+ "name": "advanced_search_company",
47
+ "description": "Search for a US listed company by name or stock ticker symbol to get basic company information including CIK, name, and ticker",
48
+ "parameters": {
49
+ "type": "object",
50
+ "properties": {
51
+ "company_input": {
52
+ "type": "string",
53
+ "description": "Company name or stock ticker symbol (e.g., 'Apple', 'AAPL', 'Microsoft', 'TSLA')"
54
+ }
55
+ },
56
+ "required": ["company_input"]
57
+ }
58
+ }
59
+ },
60
+ {
61
+ "type": "function",
62
+ "function": {
63
+ "name": "get_latest_financial_data",
64
+ "description": "Get the latest financial data for a company using its CIK number. Returns revenue, net income, EPS, operating expenses, and cash flow for the most recent fiscal period",
65
+ "parameters": {
66
+ "type": "object",
67
+ "properties": {
68
+ "cik": {
69
+ "type": "string",
70
+ "description": "10-digit CIK number of the company (must be obtained from advanced_search_company first)"
71
+ }
72
+ },
73
+ "required": ["cik"]
74
+ }
75
+ }
76
+ },
77
+ {
78
+ "type": "function",
79
+ "function": {
80
+ "name": "extract_financial_metrics",
81
+ "description": "Extract financial metrics trends over multiple years for a company. Returns historical data including revenue, net income, EPS, operating expenses, and cash flow",
82
+ "parameters": {
83
+ "type": "object",
84
+ "properties": {
85
+ "cik": {
86
+ "type": "string",
87
+ "description": "10-digit CIK number of the company"
88
+ },
89
+ "years": {
90
+ "type": "integer",
91
+ "description": "Number of years to retrieve (typically 3 or 5)",
92
+ "enum": [3, 5]
93
+ }
94
+ },
95
+ "required": ["cik", "years"]
96
+ }
97
+ }
98
+ }
99
+ ]
100
+
101
  # 格式化数值显示
102
  def format_value(value, value_type="money"):
103
  """
 
541
  import traceback
542
  return f"❌ Unexpected Error: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
543
 
544
+ # 调用 MCP 工具的实际执行函数
545
+ def call_mcp_tool(tool_name, arguments):
546
+ """调用 MCP 工具并返回结果"""
547
+ try:
548
+ response = session.post(
549
+ f"{MCP_URL}/message",
550
+ json={
551
+ "method": "tools/call",
552
+ "params": {
553
+ "name": tool_name,
554
+ "arguments": arguments
555
+ }
556
+ },
557
+ headers=HEADERS,
558
+ timeout=60
559
+ )
560
+
561
+ if response.status_code != 200:
562
+ return {"error": f"HTTP {response.status_code}: {response.text[:200]}"}
563
+
564
+ result = response.json()
565
+ return parse_mcp_response(result)
566
+ except Exception as e:
567
+ return {"error": str(e)}
568
+
569
+ # Chatbot 功能:使用 LLM + MCP 工具
570
  def chatbot_response(message, history):
571
+ """智能聊天机器人,集成 LLM 和 MCP 工具"""
572
  try:
573
+ # 构建对话历史
574
+ messages = []
575
+
576
+ # 系统提示词
577
+ system_prompt = """You are a helpful financial data assistant with access to SEC EDGAR data through specialized tools.
578
+
579
+ You can help users with:
580
+ - General questions and conversations about any topic
581
+ - Financial data queries for US listed companies
582
+ - Company information and stock data analysis
583
+
584
+ When users ask about financial data, company information, or stock performance, you should use the available tools to retrieve accurate, real-time data from SEC EDGAR filings.
585
+
586
+ Available tools:
587
+ 1. advanced_search_company: Search for company information by name or ticker
588
+ 2. get_latest_financial_data: Get the latest financial metrics for a company
589
+ 3. extract_financial_metrics: Get historical financial trends (3 or 5 years)
590
+
591
+ Always be helpful, accurate, and cite the data sources when providing financial information."""
592
+
593
+ messages.append({"role": "system", "content": system_prompt})
594
+
595
+ # 添加历史对话(最近 5 轮)
596
+ for user_msg, assistant_msg in history[-5:]:
597
+ messages.append({"role": "user", "content": user_msg})
598
+ messages.append({"role": "assistant", "content": assistant_msg})
599
+
600
+ # 添加当前消息
601
+ messages.append({"role": "user", "content": message})
602
+
603
+ # 调用 LLM,启用工具调用
604
+ response_text = ""
605
+ tool_calls_log = []
606
+ max_iterations = 5 # 防止无限循环
607
+ iteration = 0
608
+
609
+ while iteration < max_iterations:
610
+ iteration += 1
611
 
612
+ # 使用支持工具调用的模型(如 Qwen, Llama 等)
613
+ try:
614
+ response = client.chat_completion(
615
+ messages=messages,
616
+ model="Qwen/Qwen2.5-72B-Instruct", # 支持工具调用的模型
617
+ tools=MCP_TOOLS,
618
+ max_tokens=2000,
619
+ temperature=0.7
620
+ )
621
 
622
+ choice = response.choices[0]
623
+
624
+ # 检查是否有工具调用
625
+ if choice.message.tool_calls:
626
+ # 有工具调用
627
+ messages.append(choice.message)
628
+
629
+ for tool_call in choice.message.tool_calls:
630
+ tool_name = tool_call.function.name
631
+ tool_args = json.loads(tool_call.function.arguments)
632
+
633
+ # 记录工具调用
634
+ tool_calls_log.append({
635
+ "name": tool_name,
636
+ "arguments": tool_args
637
+ })
638
+
639
+ # 调用 MCP 工具
640
+ tool_result = call_mcp_tool(tool_name, tool_args)
641
+
642
+ # 将工具结果添加到消息列表
643
+ messages.append({
644
+ "role": "tool",
645
+ "name": tool_name,
646
+ "content": json.dumps(tool_result),
647
+ "tool_call_id": tool_call.id
648
+ })
649
+
650
+ # 继续下一轮对话,让 LLM 处理工具结果
651
+ continue
652
+ else:
653
+ # 没有工具调用,直接返回回答
654
+ response_text = choice.message.content
655
+ break
656
+
657
+ except Exception as e:
658
+ # 如果 LLM API 失败,退回到简单逻辑
659
+ return fallback_chatbot_response(message)
660
+
661
+ # 构建最终响应
662
+ final_response = ""
663
+
664
+ # 如果有工具调用,显示调用日志
665
+ if tool_calls_log:
666
+ final_response += "**🛠️ MCP Tools Used:**\n\n"
667
+ for i, tool_call in enumerate(tool_calls_log, 1):
668
+ final_response += f"{i}. `{tool_call['name']}` with arguments: `{json.dumps(tool_call['arguments'])}`\n"
669
+ final_response += "\n---\n\n"
670
+
671
+ final_response += response_text
672
+
673
+ return final_response
674
 
 
 
 
675
  except Exception as e:
676
+ import traceback
677
+ return f"❌ Error: {str(e)}\n\nTraceback:\n```\n{traceback.format_exc()}\n```"
678
+
679
+ def fallback_chatbot_response(message):
680
+ """退回策略:当 LLM API 不可用时使用的简单逻辑"""
681
+ # 检查是否是财务查询相关问题
682
+ financial_keywords = ['financial', 'revenue', 'income', 'earnings', 'cash flow', 'expenses', '财务', '收入', '利润', 'data', 'trend', 'performance']
683
+
684
+ if any(keyword in message.lower() for keyword in financial_keywords):
685
+ # 提取公司名称和查询类型
686
+ company_keywords = ['apple', 'microsoft', 'nvidia', 'tesla', 'alibaba', 'google', 'amazon', 'meta', 'tsla', 'aapl', 'msft', 'nvda', 'googl', 'amzn']
687
+ detected_company = None
688
+
689
+ for company in company_keywords:
690
+ if company in message.lower():
691
+ if company in ['aapl']: detected_company = 'Apple'
692
+ elif company in ['msft']: detected_company = 'Microsoft'
693
+ elif company in ['nvda']: detected_company = 'NVIDIA'
694
+ elif company in ['tsla']: detected_company = 'Tesla'
695
+ elif company in ['googl']: detected_company = 'Google'
696
+ elif company in ['amzn']: detected_company = 'Amazon'
697
+ else: detected_company = company.capitalize()
698
+ break
699
+
700
+ if detected_company:
701
+ # 根据问题内容选择查询类型
702
+ if any(word in message.lower() for word in ['trend', '趋势', 'history', 'historical', 'over time']):
703
+ if any(word in message for word in ['5', 'five', '五年']):
704
+ query_type = '5-Year Trends'
705
+ else:
706
+ query_type = '3-Year Trends'
707
+ else:
708
+ query_type = 'Latest Financial Data'
709
+
710
+ # 调用财务查询函数
711
+ result = query_financial_data(detected_company, query_type)
712
+ return f"Here's the financial information for {detected_company}:\n\n{result}"
713
+ else:
714
+ return "I can help you query financial data! Please specify a company name. For example: 'Show me Apple's latest financial data' or 'What's NVIDIA's 3-year trend?' \n\nSupported companies include: Apple, Microsoft, NVIDIA, Tesla, Alibaba, Google, Amazon, and more."
715
+
716
+ # 如果不是财务查询,返回通用回复
717
+ return "Hello! I'm a financial data assistant powered by SEC EDGAR data. I can help you query financial information for US listed companies.\n\n**What I can do:**\n- Get latest financial data (revenue, income, EPS, etc.)\n- Show 3-year or 5-year financial trends\n- Provide detailed financial metrics\n\n**Try asking:**\n- 'Show me Apple's latest financial data'\n- 'What's NVIDIA's 3-year financial trend?'\n- 'How is Microsoft performing financially?'"
718
 
719
  # 包装函数,显示加载状态
720
  def query_with_status(company, query_type):
 
736
  # 创建 Gradio 界面
737
  with gr.Blocks(title="SEC Financial Data Query Assistant") as demo:
738
  gr.Markdown("# 🤖 SEC Financial Data Query Assistant")
 
 
 
 
 
 
 
739
 
740
  with gr.Tab("AI Assistant"):
741
  # 使用 Gradio ChatInterface(兼容 4.44.1)
 
798
  )
799
 
800
  gr.Markdown("---")
801
+ gr.Markdown("**Data Source**: SEC EDGAR | **MCP Server**: https://huggingface.co/spaces/JC321/EasyReportDateMCP")
802
 
803
  # Launch the app for Hugging Face Space
804
  if __name__ == "__main__":
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
  # Updated to Gradio 6.0.1
2
  gradio==6.0.1
3
- requests
 
 
1
  # Updated to Gradio 6.0.1
2
  gradio==6.0.1
3
+ requests
4
+ huggingface_hub