JC321 commited on
Commit
e91674b
·
1 Parent(s): 9592def
app.py DELETED
@@ -1,76 +0,0 @@
1
- import gradio as gr
2
- import os
3
- from components.header import create_header
4
- from components.sidebar import create_sidebar
5
- from components.metrics import create_metrics_dashboard
6
- from components.tabs import create_tab_content
7
- from components.chat import create_chat_panel
8
-
9
- custom_css = """
10
- /* 匹配所有以 gradio-container- 开头的类 */
11
- div[class^="gradio-container-"],
12
- div[class*=" gradio-container-"] {
13
- -webkit-text-size-adjust: 100% !important;
14
- line-height: 1.5 !important;
15
- font-family: unset !important;
16
- -moz-tab-size: 4 !important;
17
- tab-size: 4 !important;
18
- }
19
- """
20
-
21
- def main():
22
- # 获取当前目录
23
- current_dir = os.path.dirname(os.path.abspath(__file__))
24
- css_dir = os.path.join(current_dir, "css")
25
-
26
- # 设置CSS路径
27
- css_paths = [
28
- os.path.join(css_dir, "main.css"),
29
- os.path.join(css_dir, "components.css"),
30
- os.path.join(css_dir, "layout.css")
31
- ]
32
-
33
- with gr.Blocks(
34
- title="Financial Analysis Dashboard",
35
- css_paths=css_paths,
36
- css=custom_css,
37
-
38
-
39
- ) as demo:
40
- with gr.Column(elem_classes=["container", "container-h"]):
41
- # 头部
42
- create_header()
43
-
44
- # 创建主布局
45
- with gr.Row(elem_classes=["main-content-box"]):
46
- # 左侧边栏
47
- with gr.Column(scale=2):
48
- create_sidebar()
49
-
50
- # 主内容区域
51
- with gr.Column(scale=8):
52
- # 指标仪表板
53
- create_metrics_dashboard()
54
-
55
- with gr.Row():
56
- with gr.Column(scale=8):
57
- # Tab导航和内容
58
- with gr.Tabs() as tabs:
59
- with gr.TabItem("Summary", id="summary"):
60
- create_tab_content("summary")
61
-
62
- with gr.TabItem("Detailed Analysis", id="detailed"):
63
- create_tab_content("detailed")
64
-
65
- # with gr.TabItem("Comparative Analysis", id="comparative"):
66
- # create_tab_content("comparative")
67
- with gr.Column(scale=2):
68
- # 右侧聊天面板
69
- create_chat_panel()
70
-
71
-
72
- return demo
73
-
74
- if __name__ == "__main__":
75
- app = main()
76
- app.launch(share=True, show_api=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/chat.py DELETED
@@ -1,54 +0,0 @@
1
- import gradio as gr
2
-
3
- def create_chat_panel():
4
- """创建聊天面板组件"""
5
- with gr.Column(elem_classes=["chat-panel"]):
6
- # 聊天头部
7
- with gr.Row(elem_classes=["p-4", "border-b", "border-gray-200", "items-center", "gap-2"]):
8
- gr.Markdown("🤖", elem_classes=["text-xl", "text-blue-600"])
9
- gr.Markdown("Financial Assistant", elem_classes=["font-medium"])
10
-
11
- # 聊天区域
12
- chatbot = gr.Chatbot(
13
- value=[
14
- {"role": "assistant", "content": "Hello! I can help you analyze financial data. Ask questions like \"Show revenue trends\" or \"Compare profitability ratios\""},
15
- {"role": "user", "content": "Show revenue trends for last 4 quarters"},
16
- {"role": "assistant", "content": "Revenue trend for GlobalTech Inc.:\n\nQ4 2024: $2.53B (+8.2%)\nQ1 2025: $2.61B (+9.8%)\nQ2 2025: $2.71B (+11.6%)\nQ3 2025: $2.84B (+12.4%)"},
17
- {"role": "assistant", "content": "Revenue trend for GlobalTech Inc.:\n\nQ4 2024: $2.53B (+8.2%)\nQ1 2025: $2.61B (+9.8%)\nQ2 2025: $2.71B (+11.6%)\nQ3 2025: $2.84B (+12.4%)"},
18
- {"role": "assistant", "content": "Revenue trend for GlobalTech Inc.:\n\nQ4 2024: $2.53B (+8.2%)\nQ1 2025: $2.61B (+9.8%)\nQ2 2025: $2.71B (+11.6%)\nQ3 2025: $2.84B (+12.4%)"},
19
-
20
- {"role": "assistant", "content": "Revenue trend for GlobalTech Inc.:\n\nQ4 2024: $2.53B (+8.2%)\nQ1 2025: $2.61B (+9.8%)\nQ2 2025: $2.71B (+11.6%)\nQ3 2025: $2.84B (+12.4%)"}
21
-
22
- ],
23
- type="messages",
24
- elem_classes=["min-h-0", "overflow-y-auto", "space-y-4", "chat-content-box"],
25
- show_label=False,
26
- autoscroll=True,
27
- show_copy_button=True,
28
- height=400,
29
- )
30
-
31
- # 输入区域
32
- with gr.Row(elem_classes=["border-t", "border-gray-200", "gap-2"]):
33
- msg = gr.Textbox(
34
- placeholder="Ask a financial question...",
35
- elem_classes=["flex-1", "border", "border-gray-300", "rounded-lg", "px-4", "py-2", "focus:border-blue-500"],
36
- show_label=False,
37
- lines=1,
38
- submit_btn=True,
39
- container=False,
40
-
41
- )
42
- # send_btn = gr.Button(
43
- # "Send",
44
- # elem_classes=["bg-blue-600", "text-white", "rounded-lg", "p-2", "hover:bg-blue-700"]
45
- # )
46
-
47
- # 绑定事件
48
- # msg.submit(None, None, None, queue=False)
49
- # send_btn.click(None, None, None, queue=False)
50
-
51
- if __name__ == "__main__":
52
- with gr.Blocks() as demo:
53
- create_chat_panel()
54
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/header.py DELETED
@@ -1,34 +0,0 @@
1
- import gradio as gr
2
-
3
- import datetime
4
-
5
- def create_header():
6
- """创建头部组件"""
7
- # 获取当前时间
8
- current_time = datetime.datetime.now().strftime("%B %d, %Y - Market Data Updated Today")
9
-
10
- with gr.Row(elem_classes=["header", "justify-between", "items-center"]):
11
- # 左侧:图标和标题
12
- with gr.Row(elem_classes=["flex", "items-center", "gap-4"]):
13
- # 使用圆柱体SVG图标表示数据库
14
- gr.HTML('''
15
- <div class="top-logo-box">
16
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 48 48">
17
- <g fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4">
18
- <path d="M44 11v27c0 3.314-8.954 6-20 6S4 41.314 4 38V11"></path>
19
- <path d="M44 29c0 3.314-8.954 6-20 6S4 32.314 4 29m40-9c0 3.314-8.954 6-20 6S4 23.314 4 20"></path>
20
- <ellipse cx="24" cy="10" rx="20" ry="6"></ellipse>
21
- </g>
22
- </svg>
23
- <span class="logo-title">Easy Financial Report Dashboard</span>
24
- </div>
25
- ''', elem_classes=["text-2xl"])
26
-
27
- # 右侧:时间信息
28
- gr.Markdown(current_time, elem_classes=["text-sm-top-time"])
29
-
30
-
31
- if __name__ == "__main__":
32
- with gr.Blocks() as demo:
33
- create_header()
34
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/metrics.py DELETED
@@ -1,142 +0,0 @@
1
- import gradio as gr
2
-
3
- def create_metrics_dashboard():
4
- """创建指标仪表板组件"""
5
- with gr.Row(elem_classes=["metrics-dashboard"]):
6
- # 总收入
7
- with gr.Column(elem_classes=["metric-card"]):
8
- # with gr.Row(elem_classes=["justify-between"]):
9
- # gr.Markdown("Total Revenue", elem_classes=["font-semibold", "text-gray-700"])
10
- # gr.Markdown("💵", elem_classes=["text-green-500"])
11
- # with gr.Column(elem_classes=["mt-4"]):
12
- # gr.Markdown("$2.84B", elem_classes=["metric-value"])
13
- # with gr.Row(elem_classes=["metric-change", "positive", "mt-1"]):
14
- # gr.Markdown("+12.4% YoY")
15
- # gr.Markdown("↗️", elem_classes=["text-green-500"])
16
- gr.HTML(f'''
17
- <div class="metric-card-item" style="
18
- # width: 250px;
19
- height: 150px;
20
- # border: 1px solid red;
21
- # padding: 10px;
22
- ">
23
- <div class="" style="
24
- display: flex;
25
- justify-content: space-between;
26
- align-items: center;
27
- ">
28
- <span class="" style="font-size: 18px;">Total Revenue</span>
29
- <span style="color: green;font-size: 18px;font-weight: 500;">💵</span>
30
- </div>
31
- <div class="">
32
- <p class="" style="font-size: 30px;font-weight: 600;color: #333333;margin-top: 20px;">$2.84B</p> <div class="">
33
- <span style="color: green;font-size: 18px;">+12.4% YoY</span>
34
- <span style="color: green;font-size: 26px;margin-left: 10px;">↗</span>
35
- </div>
36
- </div>
37
- </div>
38
- ''')
39
- # 净收入
40
- with gr.Column(elem_classes=["metric-card"]):
41
- # with gr.Row(elem_classes=["justify-between"]):
42
- # gr.Markdown("Net Income", elem_classes=["font-semibold", "text-gray-700"])
43
- # gr.Markdown("💰", elem_classes=["text-green-500"])
44
- # with gr.Column(elem_classes=["mt-4"]):
45
- # gr.Markdown("$685M", elem_classes=["metric-value"])
46
- # with gr.Row(elem_classes=["metric-change", "negative", "mt-1"]):
47
- # gr.Markdown("-3.2% QoQ")
48
- # gr.Markdown("↘️", elem_classes=["text-red-600"])
49
- gr.HTML(f'''
50
- <div class="metric-card-item" style="
51
- # width: 250px;
52
- height: 150px;
53
- # border: 1px solid red;
54
- # padding: 10px;
55
- ">
56
- <div class="" style="
57
- display: flex;
58
- justify-content: space-between;
59
- align-items: center;
60
- ">
61
- <span class="" style="font-size: 18px;">Net Income</span>
62
- <span style="color: red;font-size: 18px;font-weight: 500;">💰</span>
63
- </div>
64
- <div class="">
65
- <p class="" style="font-size: 30px;font-weight: 600;color: #333333;margin-top: 20px;">$685M</p> <div class="">
66
- <span style="color: red;font-size: 18px;">-3.2% QoQ</span>
67
- <span style="color: red;font-size: 26px;margin-left: 10px;">↘</span>
68
- </div>
69
- </div>
70
- </div>
71
- ''')
72
- # 毛利率
73
- with gr.Column(elem_classes=["metric-card"]):
74
- # with gr.Row(elem_classes=["justify-between"]):
75
- # gr.Markdown("Gross Profit Margin", elem_classes=["font-semibold", "text-gray-700"])
76
- # gr.Markdown("📊", elem_classes=["text-blue-500"])
77
- # with gr.Column(elem_classes=["mt-4"]):
78
- # gr.Markdown("42.3%", elem_classes=["metric-value"])
79
- # with gr.Row(elem_classes=["metric-change", "positive", "mt-1"]):
80
- # gr.Markdown("+180 bps")
81
- # gr.Markdown("↗️", elem_classes=["text-green-500"])
82
- gr.HTML(f'''
83
- <div class="metric-card-item" style="
84
- # width: 250px;
85
- height: 150px;
86
- # border: 1px solid red;
87
- # padding: 10px;
88
- ">
89
- <div class="" style="
90
- display: flex;
91
- justify-content: space-between;
92
- align-items: center;
93
- ">
94
- <span class="" style="font-size: 18px;">Total Revenue</span>
95
- <span style="color: green;font-size: 18px;font-weight: 500;">📊</span>
96
- </div>
97
- <div class="">
98
- <p class="" style="font-size: 30px;font-weight: 600;color: #333333;margin-top: 20px;">42.3%</p> <div class="">
99
- <span style="color: green;font-size: 18px;">+180 bps</span>
100
- <span style="color: green;font-size: 26px;margin-left: 10px;">↗</span>
101
- </div>
102
- </div>
103
- </div>
104
- ''')
105
- # 流动比率
106
- with gr.Column(elem_classes=["metric-card"]):
107
- # with gr.Row(elem_classes=["justify-between"]):
108
- # gr.Markdown("Current Ratio", elem_classes=["font-semibold", "text-gray-700"])
109
- # gr.Markdown("⚖️", elem_classes=["text-purple-500"])
110
- # with gr.Column(elem_classes=["mt-4"]):
111
- # gr.Markdown("1.82", elem_classes=["metric-value"])
112
- # with gr.Column(elem_classes=["mt-1"]):
113
- # with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-2"]):
114
- # with gr.Column(elem_classes=["bg-blue-600", "h-2", "rounded-full", "w-3/4"]):
115
- # gr.Markdown("")
116
- # gr.Markdown("Target: 1.5", elem_classes=["text-xs", "text-gray-500", "mt-1"])
117
- gr.HTML(f'''
118
- <div class="" style="
119
- display: flex;
120
- justify-content: space-between;
121
- align-items: center;
122
- ">
123
- <span class="" style="font-size: 18px;">Total Revenue</span>
124
- <span style="color: green;font-size: 18px;font-weight: 500;">⚖️</span>
125
- </div>
126
- ''')
127
- gr.Slider(
128
- minimum=1.5,
129
- maximum=2,
130
- value=1.82,
131
- # label="Current Ratio"
132
- show_label=False,
133
- show_reset_button=False,
134
- container=False,
135
- info="Target: 1.5",
136
- elem_classes=["metric-card-item-current-ratio"],
137
- )
138
-
139
- if __name__ == "__main__":
140
- with gr.Blocks() as demo:
141
- create_metrics_dashboard()
142
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/sidebar.py DELETED
@@ -1,167 +0,0 @@
1
- from turtle import title
2
- import gradio as gr
3
-
4
- def create_sidebar():
5
- """创建侧边栏组件"""
6
- with gr.Column(elem_classes=["sidebar"]):
7
- # 公司选择
8
- with gr.Group(elem_classes=["card"]):
9
- gr.Markdown("### Select Company", elem_classes=["card-title", "left-card-title"])
10
- with gr.Column():
11
- # 公司列表显示区域 - 使用样式更好的列表
12
- company_list = gr.HTML("", elem_classes=["company-list-container", "bg-white", "rounded-lg", "p-3", "mb-3", "border", "border-gray-200", "shadow-sm"])
13
- company_input = gr.Textbox(
14
- show_label=False,
15
- placeholder="Add Company",
16
- elem_classes=["company-input-box"],
17
- lines=1,
18
- max_lines=1,
19
- # container=False
20
- )
21
- # 弹窗选择列表
22
- company_modal = gr.Radio(
23
- show_label=False,
24
- choices=["Alibaba (BABA)", "Baidu(BAIDU)"],
25
- visible=False,
26
- elem_classes=["company-modal"]
27
- )
28
-
29
- # 回车事件处理
30
- company_input.submit(
31
- fn=lambda x: gr.update(visible=True),
32
- inputs=[company_input],
33
- outputs=[company_modal]
34
- )
35
-
36
- # 选择公司事件处理
37
- def add_company(selected, current_list):
38
- if selected:
39
- # 如果当前列表为空,创建新的HTML列表
40
- if not current_list:
41
- return gr.update(visible=False), f'<div class="company-item p-2 mb-2 bg-blue-50 rounded hover:bg-blue-100 cursor-pointer">{selected}</div>'
42
- # 如果当前列表不为空,在现有列表基础上添加新公司
43
- else:
44
- # 提取现有公司项
45
- existing_items = current_list
46
- new_item = f'<div class="company-item p-2 mb-2 bg-blue-50 rounded hover:bg-blue-100 cursor-pointer">{selected}</div>'
47
- return gr.update(visible=False), f'{existing_items}\n{new_item}'
48
- return gr.update(visible=False), current_list
49
-
50
- company_modal.change(
51
- fn=add_company,
52
- inputs=[company_modal, company_list],
53
- outputs=[company_modal, company_list]
54
- )
55
-
56
-
57
- # 时间周期
58
- with gr.Group(elem_classes=["card"]):
59
- gr.Markdown("### Time Period", elem_classes=["card-title", "left-card-title"])
60
- with gr.Column():
61
- period_radio = gr.Radio(
62
- choices=["Newest (Q3 2025)", "Last 3 Years (2025)", "Next ReportPredict"],
63
- value="Newest (Q3 2025)",
64
- container=False,
65
- elem_classes=["bg-white", "outline-none", "ml-2"]
66
- )
67
-
68
- # 相关报告
69
- with gr.Group(elem_classes=["card"]):
70
- gr.Markdown("### Related Report", elem_classes=["card-title", "left-card-title"])
71
- # 根据数据创建报告列表
72
- report_data = [
73
- {
74
- "title": "阿里巴巴2025年10月财报",
75
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
76
- },
77
- {
78
- "title": "阿里巴巴2025年10月财报",
79
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
80
- },
81
- {
82
- "title": "阿里巴巴2025年10月财报",
83
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
84
- },
85
- {
86
- "title": "阿里巴巴2025年10月财报",
87
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
88
- },
89
- {
90
- "title": "阿里巴巴2025年10月财报",
91
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
92
- },
93
- {
94
- "title": "阿里巴巴2025年10月财报",
95
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
96
- },
97
- {
98
- "title": "阿里巴巴2025年10月财报",
99
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
100
- },
101
- {
102
- "title": "阿里巴巴2025年10月财报",
103
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
104
- },
105
- {
106
- "title": "阿里巴巴2025年10月财报",
107
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
108
- },
109
- {
110
- "title": "阿里巴巴2025年10月财报",
111
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
112
- },
113
- {
114
- "title": "阿里巴巴2025年10月财报",
115
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
116
- },
117
- {
118
- "title": "阿里巴巴2025年10月财报",
119
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
120
- },
121
- {
122
- "title": "阿里巴巴2025年10月财报",
123
- "link": "https://data.alibabagroup.com/ecms-files/1532295521/3a67450d-a037-4181-909c-73629e20a7ed/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E9%9B%86%E5%9B%A2%E5%85%AC%E5%B8%832025%E5%B9%B46%E6%9C%88%E4%BB%BD%E5%AD%A3%E5%BA%A6%E4%B8%9A%E7%BB%A9.pdf"
124
- }
125
- ]
126
-
127
- with gr.Column(elem_classes=["report-list-box", "bg-white"]):
128
- for report in report_data:
129
- gr.HTML(f'''
130
- <div class="report-item bg-white hover:bg-blue-50 cursor-pointer" onclick="window.open('{report['link']}', '_blank')">
131
- <div class="report-item-content">
132
- <span class="text-gray-800">{report['title']}</span>
133
- <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="text-blue-500" viewBox="0 0 20 20" fill="currentColor">
134
- <path fill-rule="evenodd" d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z" clip-rule="evenodd" />
135
- </svg>
136
- </div>
137
- </div>
138
- ''', elem_classes=["report-item"])
139
-
140
- with gr.Row(elem_classes=["pdf-footer", "mt-3"]):
141
- gr.Markdown(f"共{len(report_data)}份报告", elem_classes=["text-xs", "text-gray-500"])
142
-
143
-
144
- # 占位符
145
- # gr.Markdown("", elem_classes=["flex-1"])
146
-
147
- # 生成报告按钮
148
- generate_btn = gr.Button(
149
- "Generate Investment Report",
150
- elem_classes=["btn-primary", "py-2", "rounded-lg", "flex", "items-center", "justify-center", "gap-2"]
151
- )
152
-
153
- # 操作按钮
154
- # with gr.Row(elem_classes=["gap-2"]):
155
- # reset_btn = gr.Button(
156
- # "Reset Filters",
157
- # elem_classes=["flex-1", "btn-secondary", "py-2"]
158
- # )
159
- # apply_btn = gr.Button(
160
- # "Apply",
161
- # elem_classes=["flex-1", "bg-gray-200", "py-2", "border", "border-gray-300", "hover:bg-gray-300"]
162
- # )
163
-
164
- if __name__ == "__main__":
165
- with gr.Blocks() as demo:
166
- create_sidebar()
167
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
components/tabs.py DELETED
@@ -1,188 +0,0 @@
1
- import gradio as gr
2
-
3
- def create_tab_content(tab_name):
4
- """创建Tab内容组件"""
5
- if tab_name == "summary":
6
- with gr.Column(elem_classes=["tab-content"]):
7
- # 标题和操作按钮
8
- # with gr.Row(elem_classes=["justify-between", "items-center", "mb-6"]):
9
- # gr.Markdown("## Financial Overview", elem_classes=["text-xl", "font-semibold", "text-gray-900"])
10
- # with gr.Row(elem_classes=["gap-2"]):
11
- # export_btn = gr.Button("Export", elem_classes=["border", "border-gray-300", "px-3", "py-1", "rounded-md"])
12
- # save_btn = gr.Button("Save Report", elem_classes=["bg-blue-600", "text-white", "px-3", "py-1", "rounded-md"])
13
- gr.Markdown("## Financial Overview", elem_classes=["text-xl", "font-semibold", "text-gray-900"])
14
- # 图表网格
15
- with gr.Row():
16
- with gr.Column(scale=8, min_width=300, elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
17
- gr.Markdown("#### Income Statement")
18
- gr.Markdown("""
19
- | Category | Q3 2025 | Q2 2025 | YoY % |
20
- |--------------------|-----------|-----------|----------|
21
- | Total Revenue | $2,842M | $2,712M | +12.4% |
22
- | Gross Profit | $1,203M | $1,124M | +7.0% |
23
- | Operating Income | $742M | $798M | -7.0% |
24
- | Net Income | $685M | $708M | -3.2% |
25
- | Earnings Per Share | $2.15 | $2.22 | -3.2% |
26
- """)
27
-
28
- with gr.Column(scale=2, min_width=280):
29
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
30
- gr.Markdown("#### Balance Sheet Summary")
31
- gr.Markdown("""
32
- | Category | Q3 2025 |
33
- |--------------------|-----------|
34
- | Total Assets | $2,842M |
35
- | Total Liabilities | $1,203M |
36
- | Total Equity | $742M |
37
- """)
38
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
39
- gr.Markdown("#### Cash Flow Statement")
40
- # 数据:现金流量
41
- cash_flows = [
42
- {"label": "Operating Cash Flow", "value": 982, "color": "#4CAF50"}, # 绿色
43
- {"label": "Investing Cash Flow", "value": -415, "color": "#2196F3"}, # 蓝色
44
- {"label": "Financing Cash Flow", "value": -212, "color": "#F44336"} # 红色
45
- ]
46
- # 生成 HTML 内容
47
- def render_cash_flow():
48
- html_content = "<div style='font-family: sans-serif; background-color: #f9f9f9;'>"
49
- for item in cash_flows:
50
- # 根据值决定颜色和显示符号
51
- sign = "" if item["value"] >= 0 else "-"
52
- value_str = f"${abs(item['value'])}M"
53
- color = item["color"]
54
-
55
- # 计算进度条宽度(假设最大值为 1000M,最大宽度 200px)
56
- max_val = 1000
57
- width = min(200 * abs(item["value"]) / max_val, 200) # 最大 200px
58
- width_pct = (abs(item["value"]) / max_val) * 100
59
-
60
- html_content += f"""
61
- <div style='display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px;'>
62
- <span style='font-size: 16px; font-weight: 500; color: #333;'>{item['label']}</span>
63
- <span style='font-size: 16px; font-weight: 500; color: #333;'>{sign}{value_str}</span>
64
- </div>
65
- <div style='width: 100%; height: 8px; background-color: #e0e0e0; border-radius: 4px; overflow: hidden;margin-bottom: 15px;'>
66
- <div style='height: 100%; background-color: {color}; width: {width}px; border-radius: 4px;'></div>
67
- </div>
68
- """
69
- html_content += "</div>"
70
- return html_content
71
- gr.HTML(render_cash_flow())
72
- # 收入表现图表
73
- # with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
74
- # gr.Markdown("Revenue Performance", elem_classes=["font-medium", "mb-3"])
75
- # # 这里将显示收入图表
76
-
77
- # # 收益增长图表
78
- # with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
79
- # gr.Markdown("Earnings Growth", elem_classes=["font-medium", "mb-3"])
80
- # # 这里将显示收益图表
81
-
82
- # 运营指标
83
- # with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
84
- # gr.Markdown("Operating Metrics", elem_classes=["font-medium", "mb-3"])
85
- # with gr.Column(elem_classes=["space-y-3"]):
86
- # # EBITDA利润率
87
- # with gr.Column():
88
- # with gr.Row(elem_classes=["justify-between", "text-sm"]):
89
- # gr.Markdown("EBITDA Margin")
90
- # gr.Markdown("32.1%")
91
- # with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-2", "mt-1"]):
92
- # with gr.Column(elem_classes=["bg-green-500", "h-2", "rounded-full"], scale=85):
93
- # gr.Markdown("")
94
-
95
- # # 经营现金流
96
- # with gr.Column():
97
- # with gr.Row(elem_classes=["justify-between", "text-sm"]):
98
- # gr.Markdown("Operating Cash Flow")
99
- # gr.Markdown("$982M")
100
- # with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-2", "mt-1"]):
101
- # with gr.Column(elem_classes=["bg-blue-500", "h-2", "rounded-full"], scale=72):
102
- # gr.Markdown("")
103
-
104
- # # 研发投资
105
- # with gr.Column():
106
- # with gr.Row(elem_classes=["justify-between", "text-sm"]):
107
- # gr.Markdown("R&D Investment")
108
- # gr.Markdown("$312M")
109
- # with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-2", "mt-1"]):
110
- # with gr.Column(elem_classes=["bg-purple-500", "h-2", "rounded-full"], scale=67):
111
- # gr.Markdown("")
112
-
113
- elif tab_name == "detailed":
114
- with gr.Column(elem_classes=["tab-content"]):
115
- gr.Markdown("Financial Statements", elem_classes=["text-xl", "font-semibold", "text-gray-900", "mb-6"])
116
-
117
- with gr.Row(elem_classes=["gap-6"]):
118
- # 收入报表 (3/5宽度)
119
- with gr.Column(elem_classes=["w-3/5", "bg-gray-50", "rounded-xl", "p-4"]):
120
- gr.Markdown("Income Statement", elem_classes=["font-medium", "mb-3"])
121
- # 这里将显示收入报表表格
122
-
123
- # 资产负债表和现金流量表 (2/5宽度)
124
- with gr.Column(elem_classes=["w-2/5", "flex", "flex-col", "gap-6"]):
125
- # 资产负债表
126
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
127
- gr.Markdown("Balance Sheet Summary", elem_classes=["font-medium", "mb-3"])
128
- # 这里将显示资产负债表图表
129
-
130
- # 现金流量表
131
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
132
- with gr.Row(elem_classes=["justify-between", "items-start"]):
133
- gr.Markdown("Cash Flow Statement", elem_classes=["font-medium"])
134
- gr.Markdown("View Detailed", elem_classes=["text-xs", "text-blue-600", "font-medium"])
135
-
136
- with gr.Column(elem_classes=["mt-4", "space-y-3"]):
137
- # 经营现金流
138
- with gr.Column():
139
- with gr.Row(elem_classes=["justify-between"]):
140
- gr.Markdown("Operating Cash Flow")
141
- gr.Markdown("$982M", elem_classes=["font-medium"])
142
- with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-1.5", "mt-1"]):
143
- with gr.Column(elem_classes=["bg-green-500", "h-1.5", "rounded-full"], scale=85):
144
- gr.Markdown("")
145
-
146
- # 投资现金流
147
- with gr.Column():
148
- with gr.Row(elem_classes=["justify-between"]):
149
- gr.Markdown("Investing Cash Flow")
150
- gr.Markdown("-$415M", elem_classes=["font-medium"])
151
- with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-1.5", "mt-1"]):
152
- with gr.Column(elem_classes=["bg-blue-500", "h-1.5", "rounded-full"], scale=42):
153
- gr.Markdown("")
154
-
155
- # 融资现金流
156
- with gr.Column():
157
- with gr.Row(elem_classes=["justify-between"]):
158
- gr.Markdown("Financing Cash Flow")
159
- gr.Markdown("-$212M", elem_classes=["font-medium"])
160
- with gr.Row(elem_classes=["w-full", "bg-gray-200", "rounded-full", "h-1.5", "mt-1"]):
161
- with gr.Column(elem_classes=["bg-red-500", "h-1.5", "rounded-full"], scale=25):
162
- gr.Markdown("")
163
-
164
- elif tab_name == "comparative":
165
- with gr.Column(elem_classes=["tab-content"]):
166
- gr.Markdown("Industry Benchmarking", elem_classes=["text-xl", "font-semibold", "text-gray-900", "mb-6"])
167
-
168
- # 收入增长对比
169
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4", "mb-6"]):
170
- gr.Markdown("Revenue Growth - Peer Comparison", elem_classes=["font-medium", "mb-3"])
171
- # 这里将显示对比图表
172
-
173
- # 利润率和报告预览网格
174
- with gr.Row(elem_classes=["grid-cols-2", "gap-6"]):
175
- # 利润率表格
176
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
177
- gr.Markdown("Profitability Ratios", elem_classes=["font-medium", "mb-3"])
178
- # 这里将显示利润率表格
179
-
180
- # 报告预览
181
- with gr.Column(elem_classes=["bg-gray-50", "rounded-xl", "p-4"]):
182
- gr.Markdown("Report Preview", elem_classes=["font-medium", "mb-3"])
183
- # 这里将显示报告预览
184
-
185
- if __name__ == "__main__":
186
- with gr.Blocks() as demo:
187
- create_tab_content("summary")
188
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/components.css DELETED
@@ -1,288 +0,0 @@
1
- /* 组件样式 */
2
-
3
- /* 按钮样式 */
4
- .btn-primary {
5
- background-color: #2563eb;
6
- color: white;
7
- font-weight: 600;
8
- padding: 0.5rem 1rem;
9
- border-radius: 0.5rem;
10
- border: none;
11
- cursor: pointer;
12
- transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
13
- }
14
-
15
- .btn-primary:hover {
16
- background-color: #1d4ed8;
17
- }
18
-
19
- .btn-secondary {
20
- background-color: #e5e7eb;
21
- color: #374151;
22
- font-weight: 500;
23
- padding: 0.5rem 1rem;
24
- border-radius: 0.5rem;
25
- border: 1px solid #d1d5db;
26
- cursor: pointer;
27
- transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
28
- }
29
-
30
- .btn-secondary:hover {
31
- background-color: #f3f4f6;
32
- }
33
-
34
- /* 输入框样式 */
35
- .input-field {
36
- flex: 1;
37
- background-color: transparent;
38
- padding: 0.5rem 0.5rem;
39
- outline: none;
40
- }
41
-
42
- .input-container {
43
- display: flex;
44
- align-items: center;
45
- border: 1px solid #d1d5db;
46
- border-radius: 0.25rem;
47
- /* padding: 0.25rem 0.5rem; */
48
- background-color: #f3f4f6;
49
- margin-top: 10px;
50
- }
51
-
52
- .input-container:focus-within {
53
- border-color: #3b82f6;
54
- }
55
-
56
- .company-list-container {
57
- padding: 0 !important;
58
- margin: 0 !important;
59
- border: 0 !important;
60
- border-radius: unset !important;
61
- border-color: unset !important;
62
- }
63
-
64
- .company-item {
65
- padding: 8px 10px !important;
66
- margin-top: 6px !important;
67
- font-size: 16px !important;
68
- background-color: unset !important;
69
- cursor: pointer;
70
- }
71
-
72
- .company-item:hover {
73
- background-color: #466bb5 !important;
74
- }
75
-
76
- /* 卡片样式 */
77
- .card {
78
- background-color: white;
79
- border: 1px solid #d1d5db;
80
- border-radius: 0.5rem;
81
- /* padding: 1rem; */
82
- }
83
-
84
- .card-title {
85
- font-weight: 500;
86
- color: #111827;
87
- /* margin: 0 0 0.75rem 0; */
88
- padding: 5px 7px;
89
- }
90
-
91
- /* 表格样式 */
92
- .data-table {
93
- width: 100%;
94
- font-size: 0.875rem;
95
- }
96
-
97
- .data-table th {
98
- text-align: left;
99
- padding: 0.5rem 0;
100
- color: #6b7280;
101
- border-bottom: 1px solid #e5e7eb;
102
- }
103
-
104
- .data-table td {
105
- padding: 0.5rem 0;
106
- border-bottom: 1px solid #e5e7eb;
107
- }
108
-
109
- .data-table tr:last-child td {
110
- border-bottom: none;
111
- }
112
-
113
- .text-right {
114
- text-align: right;
115
- }
116
-
117
- .text-green {
118
- color: #16a34a;
119
- }
120
-
121
- .text-red {
122
- color: #dc2626;
123
- }
124
-
125
- /* 进度条样式 */
126
- .progress-container {
127
- width: 100%;
128
- background-color: #e5e7eb;
129
- border-radius: 0.5rem;
130
- height: 0.5rem;
131
- margin-top: 0.25rem;
132
- }
133
-
134
- .progress-bar {
135
- height: 100%;
136
- border-radius: 0.5rem;
137
- }
138
-
139
- .progress-bar.blue {
140
- background-color: #3b82f6;
141
- }
142
-
143
- .progress-bar.green {
144
- background-color: #22c55e;
145
- }
146
-
147
- .progress-bar.purple {
148
- background-color: #a855f7;
149
- }
150
-
151
- .progress-bar.red {
152
- background-color: #ef4444;
153
- }
154
-
155
- /* PDF预览样式 */
156
- .pdf-preview {
157
- border: 1px solid #d1d5db;
158
- border-radius: 0.5rem;
159
- overflow: hidden;
160
- }
161
-
162
- .pdf-header {
163
- display: flex;
164
- align-items: center;
165
- gap: 0.25rem;
166
- padding: 0.5rem;
167
- border-bottom: 1px solid #d1d5db;
168
- font-size: 0.875rem;
169
- }
170
-
171
- .pdf-pages {
172
- display: flex;
173
- padding: 0.5rem;
174
- }
175
-
176
- .pdf-page {
177
- height: 6rem;
178
- border: 1px solid #d1d5db;
179
- border-radius: 0.25rem;
180
- cursor: pointer;
181
- margin-right: 0.5rem;
182
- }
183
-
184
- .pdf-page:hover {
185
- border-color: #93c5fd;
186
- }
187
-
188
- .pdf-page.active {
189
- border-color: #93c5fd;
190
- border-width: 2px;
191
- }
192
-
193
- .pdf-viewer {
194
- height: 100%;
195
- border: 1px solid #e5e7eb;
196
- background-color: #f3f4f6;
197
- display: flex;
198
- align-items: center;
199
- justify-content: center;
200
- }
201
-
202
- .pdf-footer {
203
- padding: 0.5rem;
204
- background-color: #f3f4f6;
205
- display: flex;
206
- align-items: center;
207
- justify-content: space-between;
208
- font-size: 0.875rem;
209
- color: #6b7280;
210
- margin-top: 0 !important;
211
- }
212
-
213
- /* 图标按钮 */
214
- .icon-button {
215
- cursor: pointer;
216
- padding: 0.25rem;
217
- border-radius: 0.25rem;
218
- }
219
-
220
- .icon-button:hover {
221
- background-color: #f3f4f6;
222
- color: #2563eb;
223
- }
224
-
225
- .custom-add-input {
226
- position: relative;
227
- padding-left: 32px !important;
228
- }
229
-
230
- .custom-add-input textarea::before {
231
- content: "+";
232
- position: absolute;
233
- left: 8px;
234
- top: 50%;
235
- transform: translateY(-50%);
236
- color: #007bff;
237
- font-weight: bold;
238
- font-size: 16px;
239
- }
240
-
241
- .report-list-box {
242
- height: 300px;
243
- display: unset !important;
244
- overflow-y: auto !important;
245
- }
246
- .report-item-content {
247
- display: flex;
248
- align-items: center;
249
- justify-content: space-between;
250
- }
251
- .report-item {
252
- height: fit-content;
253
- padding: 4px 6px;
254
- }
255
- .report-item-content span:hover {
256
- color: #e1853e !important;
257
- }
258
-
259
- .metric-card-item-current-ratio {
260
- height: 109px !important;
261
- padding-top: 15px !important;
262
- }
263
- .metric-card-item-current-ratio .slider_input_container {
264
- padding-top: 15px !important;
265
- }
266
- .chat-content-box {
267
- height: 500px !important;
268
- overflow-y: auto !important;
269
- }
270
- .chat-content-box .message-wrap {
271
- height: 400px !important;
272
- }
273
- .company-input-box {
274
- width: 100% !important;
275
- }
276
- .company-input-box label {
277
- width: 100% !important;
278
- min-width: 100% !important;
279
- }
280
- .company-input-box div {
281
- width: 100% !important;
282
- }
283
- .company-input-box textarea {
284
- width: 100% !important;
285
- }
286
- .left-card-title {
287
- background: #fff !important;
288
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/layout.css DELETED
@@ -1,558 +0,0 @@
1
- /* 布局样式 */
2
-
3
- /* 网格布局 */
4
- .grid-cols-2 {
5
- display: grid;
6
- grid-template-columns: repeat(2, minmax(0, 1fr));
7
- gap: 1.5rem;
8
- }
9
-
10
- .grid-cols-3 {
11
- display: grid;
12
- grid-template-columns: repeat(3, minmax(0, 1fr));
13
- gap: 1.5rem;
14
- }
15
-
16
- .grid-cols-4 {
17
- display: grid;
18
- grid-template-columns: repeat(4, minmax(0, 1fr));
19
- gap: 1rem;
20
- }
21
-
22
- /* Flex布局 */
23
- .flex {
24
- display: flex;
25
- }
26
-
27
- .flex-col {
28
- flex-direction: column;
29
- }
30
-
31
- .flex-1 {
32
- flex: 1 1 0%;
33
- }
34
-
35
- .flex-row {
36
- flex-direction: row;
37
- }
38
-
39
- .items-start {
40
- align-items: flex-start;
41
- }
42
-
43
- .items-center {
44
- align-items: center;
45
- }
46
-
47
- .justify-center {
48
- justify-content: center;
49
- }
50
-
51
- .justify-between {
52
- justify-content: space-between;
53
- }
54
-
55
- .gap-1 {
56
- gap: 0.25rem;
57
- }
58
-
59
- .gap-2 {
60
- gap: 0.5rem;
61
- }
62
-
63
- .gap-4 {
64
- gap: 1rem;
65
- }
66
-
67
- .gap-6 {
68
- gap: 1.5rem;
69
- }
70
-
71
- /* 间距 */
72
- .mt-1 {
73
- margin-top: 0.25rem;
74
- }
75
-
76
- .mt-2 {
77
- margin-top: 0.5rem;
78
- }
79
-
80
- .mt-3 {
81
- margin-top: 0.75rem;
82
- }
83
-
84
- .mt-4 {
85
- margin-top: 1rem;
86
- }
87
-
88
- .mb-1 {
89
- margin-bottom: 0.25rem;
90
- }
91
-
92
- .mb-3 {
93
- margin-bottom: 0.75rem;
94
- }
95
-
96
- .mb-6 {
97
- margin-bottom: 1.5rem;
98
- }
99
-
100
- .ml-auto {
101
- margin-left: auto;
102
- }
103
-
104
- .p-2 {
105
- padding: 0.5rem;
106
- }
107
-
108
- .p-3 {
109
- padding: 0.75rem;
110
- }
111
-
112
- .p-4 {
113
- padding: 1rem;
114
- }
115
-
116
- .p-5 {
117
- padding: 1.25rem;
118
- }
119
-
120
- .p-6 {
121
- padding: 1.5rem;
122
- }
123
-
124
- .px-2 {
125
- padding-left: 0.5rem;
126
- padding-right: 0.5rem;
127
- }
128
-
129
- .px-3 {
130
- padding-left: 0.75rem;
131
- padding-right: 0.75rem;
132
- }
133
-
134
- .px-4 {
135
- padding-left: 1rem;
136
- padding-right: 1rem;
137
- }
138
-
139
- .px-5 {
140
- padding-left: 1.25rem;
141
- padding-right: 1.25rem;
142
- }
143
-
144
- .py-1 {
145
- padding-top: 0.25rem;
146
- padding-bottom: 0.25rem;
147
- }
148
-
149
- .py-2 {
150
- padding-top: 0.5rem;
151
- padding-bottom: 0.5rem;
152
- }
153
-
154
- .py-3 {
155
- padding-top: 0.75rem;
156
- padding-bottom: 0.75rem;
157
- }
158
-
159
- .py-4 {
160
- padding-top: 1rem;
161
- padding-bottom: 1rem;
162
- }
163
-
164
- .pt-2 {
165
- padding-top: 0.5rem;
166
- }
167
-
168
- .pt-3 {
169
- padding-top: 0.75rem;
170
- }
171
-
172
- .pb-2 {
173
- padding-bottom: 0.5rem;
174
- }
175
-
176
- /* 尺寸 */
177
- .h-full {
178
- height: 100%;
179
- }
180
-
181
- .h-24 {
182
- height: 6rem;
183
- }
184
-
185
- .h-32 {
186
- height: 8rem;
187
- }
188
-
189
- .h-56 {
190
- height: 14rem;
191
- }
192
-
193
- .h-60 {
194
- height: 15rem;
195
- }
196
-
197
- .h-72 {
198
- height: 18rem;
199
- }
200
-
201
- .w-full {
202
- width: 100%;
203
- }
204
-
205
- .w-1\/4 {
206
- width: 25%;
207
- }
208
-
209
- .w-3\/4 {
210
- width: 75%;
211
- }
212
-
213
- .w-2\/5 {
214
- width: 40%;
215
- }
216
-
217
- .w-3\/5 {
218
- width: 60%;
219
- }
220
-
221
- .min-h-screen {
222
- min-height: 100vh;
223
- }
224
-
225
- .min-h-0 {
226
- min-height: 0px;
227
- }
228
-
229
- .min-h-\[250px\] {
230
- min-height: 250px;
231
- }
232
-
233
- .min-h-\[90vh\] {
234
- min-height: 90vh;
235
- }
236
-
237
- /* 文本对齐 */
238
- .text-left {
239
- text-align: left;
240
- }
241
-
242
- .text-right {
243
- text-align: right;
244
- }
245
-
246
- /* 边框 */
247
- .border {
248
- border-width: 1px;
249
- }
250
-
251
- .border-2 {
252
- border-width: 2px;
253
- }
254
-
255
- .border-t {
256
- border-top-width: 1px;
257
- }
258
-
259
- .border-b {
260
- border-bottom-width: 1px;
261
- }
262
-
263
- .border-b-2 {
264
- border-bottom-width: 2px;
265
- }
266
-
267
- .border-r {
268
- border-right-width: 1px;
269
- }
270
-
271
- .border-l {
272
- border-left-width: 1px;
273
- }
274
-
275
- .border-gray-200 {
276
- border-color: #e5e7eb;
277
- }
278
-
279
- .border-gray-300 {
280
- border-color: #d1d5db;
281
- }
282
-
283
- .border-blue-400 {
284
- border-color: #60a5fa;
285
- }
286
-
287
- .border-blue-600 {
288
- border-color: #2563eb;
289
- }
290
-
291
- /* 圆角 */
292
- .rounded {
293
- border-radius: 0.25rem;
294
- }
295
-
296
- .rounded-lg {
297
- border-radius: 0.5rem;
298
- }
299
-
300
- .rounded-xl {
301
- border-radius: 0.75rem;
302
- }
303
-
304
- .rounded-2xl {
305
- border-radius: 1rem;
306
- }
307
-
308
- .rounded-full {
309
- border-radius: 9999px;
310
- }
311
-
312
- .rounded-tl-none {
313
- border-top-left-radius: 0px;
314
- }
315
-
316
- .rounded-tr-none {
317
- border-top-right-radius: 0px;
318
- }
319
-
320
- /* 阴影 */
321
- .shadow {
322
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
323
- }
324
-
325
- .shadow-xl {
326
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
327
- }
328
-
329
- .shadow-inner {
330
- box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
331
- }
332
-
333
- /* 溢出 */
334
- .overflow-hidden {
335
- overflow: hidden;
336
- }
337
-
338
- .overflow-x-auto {
339
- overflow-x: auto;
340
- }
341
-
342
- .overflow-y-auto {
343
- overflow-y: auto;
344
- }
345
-
346
- /* 光标 */
347
- .cursor-pointer {
348
- cursor: pointer;
349
- }
350
-
351
- /* 文本大小 */
352
- .text-xs {
353
- font-size: 0.75rem;
354
- line-height: 1rem;
355
- }
356
-
357
- .text-sm {
358
- font-size: 0.875rem;
359
- line-height: 1.25rem;
360
- }
361
- .text-sm-top-time {
362
- font-size: 0.875rem;
363
- line-height: 1.25rem;
364
- text-align: end;
365
-
366
- }
367
- .text-sm-top-time p {
368
- color: #fff !important;
369
- }
370
-
371
- .text-base {
372
- font-size: 1rem;
373
- line-height: 1.5rem;
374
- }
375
-
376
- .text-xl {
377
- font-size: 1.25rem;
378
- line-height: 1.75rem;
379
- }
380
-
381
- .text-2xl {
382
- font-size: 1.5rem;
383
- line-height: 2rem;
384
- }
385
-
386
- /* 文本粗细 */
387
- .font-medium {
388
- font-weight: 500;
389
- }
390
-
391
- .font-semibold {
392
- font-weight: 600;
393
- }
394
-
395
- .font-bold {
396
- font-weight: 700;
397
- }
398
-
399
- /* 文本颜色 */
400
- .text-white {
401
- color: #ffffff;
402
- }
403
-
404
- .text-gray-500 {
405
- color: #6b7280;
406
- }
407
-
408
- .text-gray-600 {
409
- color: #4b5563;
410
- }
411
-
412
- .text-gray-700 {
413
- color: #374151;
414
- }
415
-
416
- .text-gray-900 {
417
- color: #111827;
418
- }
419
-
420
- .text-blue-500 {
421
- color: #3b82f6;
422
- }
423
-
424
- .text-blue-600 {
425
- color: #2563eb;
426
- }
427
-
428
- .text-blue-700 {
429
- color: #1d4ed8;
430
- }
431
-
432
- .text-green-500 {
433
- color: #22c55e;
434
- }
435
-
436
- .text-green-600 {
437
- color: #16a34a;
438
- }
439
-
440
- .text-red-500 {
441
- color: #ef4444;
442
- }
443
-
444
- .text-red-600 {
445
- color: #dc2626;
446
- }
447
-
448
- .text-purple-500 {
449
- color: #a855f7;
450
- }
451
-
452
- /* 背景颜色 */
453
- .bg-white {
454
- background-color: #ffffff;
455
- }
456
- .bg-white .wrap label {
457
- border: unset !important;
458
- border-color: unset !important;
459
- }
460
-
461
- .bg-gray-50 {
462
- background-color: #f9fafb;
463
- }
464
-
465
- .bg-gray-100 {
466
- background-color: #f3f4f6;
467
- }
468
-
469
- .bg-gray-200 {
470
- background-color: #e5e7eb;
471
- }
472
-
473
- .bg-blue-50 {
474
- background-color: #eff6ff;
475
- }
476
-
477
- .bg-blue-500 {
478
- background-color: #3b82f6;
479
- }
480
-
481
- .bg-blue-600 {
482
- background-color: #2563eb;
483
- }
484
-
485
- .bg-green-500 {
486
- background-color: #22c55e;
487
- }
488
-
489
- .bg-purple-500 {
490
- background-color: #a855f7;
491
- }
492
-
493
- .bg-red-500 {
494
- background-color: #ef4444;
495
- }
496
-
497
- .bg-gradient-to-r {
498
- background-image: linear-gradient(to right, var(--tw-gradient-stops));
499
- }
500
-
501
- .from-blue-600 {
502
- --tw-gradient-from: #2563eb;
503
- --tw-gradient-to: rgba(37, 99, 235, 0);
504
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
505
- }
506
-
507
- .to-blue-800 {
508
- --tw-gradient-to: #1e40af;
509
- }
510
-
511
- /* 对象适应 */
512
- .object-contain {
513
- object-fit: contain;
514
- }
515
-
516
- /* 最小宽度 */
517
- .min-w-0 {
518
- min-width: 0px;
519
- }
520
-
521
- /* 最大宽度 */
522
- .max-w-\[85\%\] {
523
- max-width: 85%;
524
- }
525
-
526
- /* .gradio-container-5-49-1 {
527
- -webkit-text-size-adjust: 100%;
528
- line-height: 1.5;
529
- font-family:unset !important;
530
- -moz-tab-size: 4;
531
- tab-size: 4
532
- } */
533
-
534
- /* [class^="gradio-container-"] {
535
- -webkit-text-size-adjust: 100%;
536
- line-height: 1.5;
537
- font-family: unset !important;
538
- -moz-tab-size: 4;
539
- tab-size: 4;
540
- } */
541
-
542
- main {
543
- min-width: 1440px !important;
544
- padding: 0 !important;
545
- }
546
- /* main .wrap {
547
- height: 100vh !important;
548
- } */
549
- /* main .wrap .contain {
550
- height: 100% !important;
551
- } */
552
- /* main .wrap .contain .column {
553
- height: 100vh !important;
554
- } */
555
-
556
- .main-content-box {
557
- gap: unset !important;
558
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/main.css DELETED
@@ -1,242 +0,0 @@
1
- /* 主体样式 */
2
- body {
3
- background-color: #f3f4f6;
4
- /* font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; */
5
- font-family: unset !important;
6
- margin: 0;
7
- padding: 0;
8
- }
9
-
10
- /* 容器样式 */
11
- .container {
12
- min-width: 1440px;
13
- /* margin: 2rem auto; */
14
- background-color: white;
15
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
16
- border-radius: 0.75rem;
17
- /* min-height: 90vh; */
18
- overflow: hidden;
19
- margin-top: 0 !important;
20
- gap: unset !important;
21
- margin: 0 auto !important;
22
- }
23
- .container-h {
24
- height: 97vh !important;
25
- }
26
- .html-container {
27
- padding: 0 !important;
28
- }
29
- footer {
30
- margin-top: 0 !important;
31
- }
32
-
33
- /* 头部样式 */
34
- .header {
35
- background: linear-gradient(to right, #2563eb, #1e40af);
36
- color: white;
37
- padding: 1rem 2rem;
38
- display: flex;
39
- align-items: center;
40
- justify-content: space-between;
41
- }
42
-
43
- .top-logo-box {
44
- display: flex;
45
- }
46
-
47
- .logo-title {
48
- color: #fff !important;
49
- margin-left: 10px;
50
- }
51
-
52
- .header h1 {
53
- font-size: 1.5rem;
54
- font-weight: 600;
55
- margin: 0;
56
- }
57
-
58
- /* 主要内容区域 */
59
- .main-content {
60
- display: flex;
61
- flex: 1;
62
- overflow: hidden;
63
- }
64
-
65
- /* 左侧边栏 */
66
- .sidebar {
67
- background-color: #f9fafb;
68
- width: 300px;
69
- padding: 1.5rem;
70
- display: flex;
71
- flex-direction: column;
72
- gap: 1.5rem;
73
- border-right: 1px solid #e5e7eb;
74
- }
75
-
76
- /* 主内容区域 */
77
- .content-area {
78
- flex: 1;
79
- display: flex;
80
- flex-direction: column;
81
- background-color: #eff6ff;
82
- }
83
-
84
- /* 指标仪表板 */
85
- .metrics-dashboard {
86
- background-color: #eff6ff;
87
- border-bottom: 1px solid #e5e7eb;
88
- padding: 1.5rem;
89
- display: grid;
90
- grid-template-columns: repeat(4, 1fr);
91
- gap: 1rem;
92
- min-height: 250px;
93
- }
94
-
95
- .metric-card {
96
- background-color: white;
97
- border-radius: 0.5rem;
98
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
99
- padding: 1.25rem;
100
- }
101
-
102
- .metric-card h3 {
103
- font-weight: 600;
104
- color: #374151;
105
- margin: 0 0 1rem 0;
106
- }
107
-
108
- .metric-value {
109
- font-size: 1.5rem;
110
- font-weight: 700;
111
- color: #111827;
112
- margin: 1rem 0 0.25rem 0;
113
- }
114
-
115
- .metric-change {
116
- display: flex;
117
- align-items: center;
118
- margin-top: 0.25rem;
119
- }
120
-
121
- .metric-change.positive {
122
- color: #16a34a;
123
- }
124
-
125
- .metric-change.negative {
126
- color: #dc2626;
127
- }
128
-
129
- /* 分析区域 */
130
- .analysis-area {
131
- flex: 1;
132
- display: flex;
133
- min-height: 0;
134
- overflow: hidden;
135
- }
136
-
137
- /* Tab内容 */
138
- .tab-content {
139
- flex: 1;
140
- display: flex;
141
- flex-direction: column;
142
- min-width: 0;
143
- padding: 0 16px !important;
144
- }
145
-
146
- /* Tab导航 */
147
- .tab-navigation {
148
- display: flex;
149
- border-bottom: 1px solid #e5e7eb;
150
- }
151
-
152
- .tab-button {
153
- padding: 0.75rem 1.25rem;
154
- font-weight: 500;
155
- font-size: 1rem;
156
- color: #6b7280;
157
- border-bottom: 2px solid transparent;
158
- }
159
-
160
- .tab-button.active {
161
- color: #111827;
162
- border-bottom: 2px solid #2563eb;
163
- }
164
-
165
- /* 聊天面板 */
166
- .chat-panel {
167
- /* width: 340px; */
168
- display: flex;
169
- flex-direction: column;
170
- border-left: 1px solid #e5e7eb;
171
- background-color: white;
172
- box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
173
- gap: unset !important;
174
- }
175
-
176
- .chat-header {
177
- padding: 1rem;
178
- border-bottom: 1px solid #e5e7eb;
179
- display: flex;
180
- align-items: center;
181
- gap: 0.5rem;
182
- font-weight: 500;
183
- }
184
-
185
- .chat-area {
186
- flex: 1;
187
- min-height: 0;
188
- overflow-y: auto;
189
- padding: 1rem;
190
- display: flex;
191
- flex-direction: column;
192
- gap: 1rem;
193
- }
194
-
195
- .chat-message {
196
- max-width: 85%;
197
- padding: 0.75rem;
198
- border-radius: 1rem;
199
- }
200
-
201
- .chat-message.bot {
202
- background-color: #eff6ff;
203
- border-bottom-left-radius: 0;
204
- }
205
-
206
- .chat-message.user {
207
- background-color: #f3f4f6;
208
- border-bottom-right-radius: 0;
209
- margin-left: auto;
210
- }
211
-
212
- .chat-input-area {
213
- padding: 1rem;
214
- border-top: 1px solid #e5e7eb;
215
- display: flex;
216
- gap: 0.5rem;
217
- }
218
-
219
- /* 隐藏滚动条 */
220
- .hide-scrollbar::-webkit-scrollbar {
221
- display: none;
222
- }
223
-
224
- .hide-scrollbar {
225
- -ms-overflow-style: none;
226
- scrollbar-width: none;
227
- }
228
-
229
- /* 渐变动画 */
230
- .fade-in {
231
- animation: fadeIn 0.3s ease-in-out;
232
- }
233
-
234
- @keyframes fadeIn {
235
- from {
236
- opacity: 0;
237
- }
238
-
239
- to {
240
- opacity: 1;
241
- }
242
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=5.49.1
2
+ huggingface_hub>=0.20.0
3
+ python-dotenv>=1.0.0
4
+ SQLAlchemy>=2.0.44
5
+ plotly>=5.24.1
6
+ pandas>=2.2.2
7
+ numpy>=1.26.4