Upload app.py
Browse files
app.py
CHANGED
|
@@ -23,7 +23,9 @@ from service.report_tools import build_financial_metrics_three_year_data, calcul
|
|
| 23 |
from service.three_year_table_tool import build_table_format
|
| 24 |
from service.three_year_tool import process_financial_data_with_metadata
|
| 25 |
from service.tool_processor import get_stock_price
|
| 26 |
-
|
|
|
|
|
|
|
| 27 |
|
| 28 |
get_companys_state = True
|
| 29 |
my_companies = [
|
|
@@ -1270,13 +1272,19 @@ def build_income_table(table_data):
|
|
| 1270 |
if year_header in yoy_map[category]:
|
| 1271 |
growth = yoy_map[category][year_header]
|
| 1272 |
|
| 1273 |
-
if growth and growth != "N/A":
|
| 1274 |
arrow = "▲" if growth.startswith("+") else "▼"
|
| 1275 |
color = "green" if growth.startswith("+") else "red"
|
| 1276 |
cells += f"""<td style='padding: 8px; border: 1px solid #ddd; text-align: center; font-size: 13px; position: relative;'>
|
| 1277 |
<div>{cell}</div>
|
| 1278 |
<div style='position: absolute; bottom: 2px; right: 5px; font-size: 10px; color: {color};'>{arrow}{growth}</div>
|
| 1279 |
</td>"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1280 |
else:
|
| 1281 |
cells += f"<td style='padding: 8px; border: 1px solid #ddd; text-align: center; font-size: 13px;'>{cell}</td>"
|
| 1282 |
table_rows += f"<tr style='{row_style}'>{cells}</tr>"
|
|
@@ -1775,6 +1783,10 @@ def main():
|
|
| 1775 |
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 1776 |
css_dir = os.path.join(current_dir, "css")
|
| 1777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1778 |
# def load_css_files(css_dir, filenames):
|
| 1779 |
# """读取多个 CSS 文件并合并为一个字符串"""
|
| 1780 |
# css_content = ""
|
|
@@ -1852,37 +1864,14 @@ def main():
|
|
| 1852 |
# 当选中的公司改变时,重新加载tab内容
|
| 1853 |
def update_tab_content(company):
|
| 1854 |
if company:
|
| 1855 |
-
#
|
| 1856 |
-
|
| 1857 |
-
<div style="display: flex; justify-content: center; align-items: center; height: 200px;">
|
| 1858 |
-
<div style="text-align: center;">
|
| 1859 |
-
<div class="loading-spinner" style="width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto;"></div>
|
| 1860 |
-
<p style="margin-top: 20px; color: #666;">Loading investment suggestions for {company}...</p>
|
| 1861 |
-
<style>
|
| 1862 |
-
@keyframes spin {{
|
| 1863 |
-
0% {{ transform: rotate(0deg); }}
|
| 1864 |
-
100% {{ transform: rotate(360deg); }}
|
| 1865 |
-
}}
|
| 1866 |
-
</style>
|
| 1867 |
-
</div>
|
| 1868 |
-
</div>
|
| 1869 |
-
'''
|
| 1870 |
-
yield loading_html
|
| 1871 |
-
|
| 1872 |
-
# 获取投资建议数据
|
| 1873 |
-
try:
|
| 1874 |
-
# content = get_invest_suggest(company)
|
| 1875 |
stock_code = get_stock_code_by_company_name(company)
|
| 1876 |
-
|
| 1877 |
-
|
| 1878 |
-
|
| 1879 |
-
|
| 1880 |
-
|
| 1881 |
-
<p>Error loading investment suggestions: {str(e)}</p>
|
| 1882 |
-
<p>Please try again later.</p>
|
| 1883 |
-
</div>
|
| 1884 |
-
'''
|
| 1885 |
-
yield error_html
|
| 1886 |
else:
|
| 1887 |
yield "<div style=\"padding: 20px; text-align: center; color: #666;\">Please select a company</div>"
|
| 1888 |
|
|
@@ -1907,41 +1896,14 @@ def main():
|
|
| 1907 |
# 当选中的公司改变时,重新加载tab内容
|
| 1908 |
def update_analysis_tab_content(company):
|
| 1909 |
if company:
|
| 1910 |
-
#
|
| 1911 |
-
|
| 1912 |
-
<div style="display: flex; justify-content: center; align-items: center; height: 200px;">
|
| 1913 |
-
<div style="text-align: center;">
|
| 1914 |
-
<div class="loading-spinner" style="width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto;"></div>
|
| 1915 |
-
<p style="margin-top: 20px; color: #666;">Loading analysis report for {company}...</p>
|
| 1916 |
-
<style>
|
| 1917 |
-
@keyframes spin {{
|
| 1918 |
-
0% {{ transform: rotate(0deg); }}
|
| 1919 |
-
100% {{ transform: rotate(360deg); }}
|
| 1920 |
-
}}
|
| 1921 |
-
</style>
|
| 1922 |
-
</div>
|
| 1923 |
-
</div>
|
| 1924 |
-
'''
|
| 1925 |
-
yield loading_html
|
| 1926 |
-
|
| 1927 |
-
# 获取分析报告数据
|
| 1928 |
-
try:
|
| 1929 |
-
# 这里应该调用获取详细分析报告的函数
|
| 1930 |
-
# 暂时使用占位内容,您需要替换为实际的函数调用
|
| 1931 |
-
# content = f"# Analysis Report for {company}\n\nDetailed financial analysis for {company} will be displayed here."
|
| 1932 |
stock_code = get_stock_code_by_company_name(company)
|
| 1933 |
-
|
| 1934 |
-
|
| 1935 |
-
|
| 1936 |
-
|
| 1937 |
-
|
| 1938 |
-
error_html = f'''
|
| 1939 |
-
<div style="padding: 20px; text-align: center; color: #666;">
|
| 1940 |
-
<p>Error loading analysis report: {str(e)}</p>
|
| 1941 |
-
<p>Please try again later.</p>
|
| 1942 |
-
</div>
|
| 1943 |
-
'''
|
| 1944 |
-
yield error_html
|
| 1945 |
else:
|
| 1946 |
yield "<div style=\"padding: 20px; text-align: center; color: #666;\">Please select a company</div>"
|
| 1947 |
|
|
@@ -2003,26 +1965,14 @@ def main():
|
|
| 2003 |
# 绑定公司选择事件到指标仪表板更新
|
| 2004 |
def update_metrics_dashboard_wrapper(company_name):
|
| 2005 |
if company_name:
|
| 2006 |
-
#
|
| 2007 |
-
|
| 2008 |
-
|
| 2009 |
-
<div style="text-align: center;">
|
| 2010 |
-
<div class="loading-spinner" style="width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto;"></div>
|
| 2011 |
-
<p style="margin-top: 20px; color: #666;">Loading financial data for {company_name}...</p>
|
| 2012 |
-
<style>
|
| 2013 |
-
@keyframes spin {{
|
| 2014 |
-
0% {{ transform: rotate(0deg); }}
|
| 2015 |
-
100% {{ transform: rotate(360deg); }}
|
| 2016 |
-
}}
|
| 2017 |
-
</style>
|
| 2018 |
-
</div>
|
| 2019 |
-
</div>
|
| 2020 |
-
'''
|
| 2021 |
-
yield loading_html, loading_html, loading_html
|
| 2022 |
|
| 2023 |
-
#
|
| 2024 |
try:
|
| 2025 |
-
|
|
|
|
| 2026 |
yield stock_card_html, financial_metrics_html, income_table_html
|
| 2027 |
except Exception as e:
|
| 2028 |
error_html = f'''
|
|
|
|
| 23 |
from service.three_year_table_tool import build_table_format
|
| 24 |
from service.three_year_tool import process_financial_data_with_metadata
|
| 25 |
from service.tool_processor import get_stock_price
|
| 26 |
+
# ✅ 导入缓存管理器
|
| 27 |
+
from service.report_cache_manager import ReportCacheManager
|
| 28 |
+
from service.financial_data_cache_manager import FinancialDataCacheManager
|
| 29 |
|
| 30 |
get_companys_state = True
|
| 31 |
my_companies = [
|
|
|
|
| 1272 |
if year_header in yoy_map[category]:
|
| 1273 |
growth = yoy_map[category][year_header]
|
| 1274 |
|
| 1275 |
+
if growth and growth != "N/A" and growth != "--":
|
| 1276 |
arrow = "▲" if growth.startswith("+") else "▼"
|
| 1277 |
color = "green" if growth.startswith("+") else "red"
|
| 1278 |
cells += f"""<td style='padding: 8px; border: 1px solid #ddd; text-align: center; font-size: 13px; position: relative;'>
|
| 1279 |
<div>{cell}</div>
|
| 1280 |
<div style='position: absolute; bottom: 2px; right: 5px; font-size: 10px; color: {color};'>{arrow}{growth}</div>
|
| 1281 |
</td>"""
|
| 1282 |
+
elif growth == "--":
|
| 1283 |
+
# 显示"--"但不显示箭头
|
| 1284 |
+
cells += f"""<td style='padding: 8px; border: 1px solid #ddd; text-align: center; font-size: 13px; position: relative;'>
|
| 1285 |
+
<div>{cell}</div>
|
| 1286 |
+
<div style='position: absolute; bottom: 2px; right: 5px; font-size: 10px; color: #999;'>--</div>
|
| 1287 |
+
</td>"""
|
| 1288 |
else:
|
| 1289 |
cells += f"<td style='padding: 8px; border: 1px solid #ddd; text-align: center; font-size: 13px;'>{cell}</td>"
|
| 1290 |
table_rows += f"<tr style='{row_style}'>{cells}</tr>"
|
|
|
|
| 1783 |
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 1784 |
css_dir = os.path.join(current_dir, "css")
|
| 1785 |
|
| 1786 |
+
# ✅ 初始化缓存管理器
|
| 1787 |
+
report_cache = ReportCacheManager(cache_ttl_seconds=3600, max_cache_size=50)
|
| 1788 |
+
data_cache = FinancialDataCacheManager(cache_ttl_seconds=1800, max_cache_size=100)
|
| 1789 |
+
|
| 1790 |
# def load_css_files(css_dir, filenames):
|
| 1791 |
# """读取多个 CSS 文件并合并为一个字符串"""
|
| 1792 |
# css_content = ""
|
|
|
|
| 1864 |
# 当选中的公司改变时,重新加载tab内容
|
| 1865 |
def update_tab_content(company):
|
| 1866 |
if company:
|
| 1867 |
+
# ✅ 使用缓存管理器生成投资建议
|
| 1868 |
+
def generate_suggestion():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1869 |
stock_code = get_stock_code_by_company_name(company)
|
| 1870 |
+
return query_company_advanced(stock_code, "suggestion")
|
| 1871 |
+
|
| 1872 |
+
# 使用生成器yield缓存管理器的输出
|
| 1873 |
+
for result in report_cache.get_or_create_report(company, "suggestion", generate_suggestion):
|
| 1874 |
+
yield result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1875 |
else:
|
| 1876 |
yield "<div style=\"padding: 20px; text-align: center; color: #666;\">Please select a company</div>"
|
| 1877 |
|
|
|
|
| 1896 |
# 当选中的公司改变时,重新加载tab内容
|
| 1897 |
def update_analysis_tab_content(company):
|
| 1898 |
if company:
|
| 1899 |
+
# ✅ 使用缓存管理器生成分析报告
|
| 1900 |
+
def generate_report():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1901 |
stock_code = get_stock_code_by_company_name(company)
|
| 1902 |
+
return query_company_advanced(stock_code, "report")
|
| 1903 |
+
|
| 1904 |
+
# 使用生成器yield缓存管理器的输出
|
| 1905 |
+
for result in report_cache.get_or_create_report(company, "report", generate_report):
|
| 1906 |
+
yield result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1907 |
else:
|
| 1908 |
yield "<div style=\"padding: 20px; text-align: center; color: #666;\">Please select a company</div>"
|
| 1909 |
|
|
|
|
| 1965 |
# 绑定公司选择事件到指标仪表板更新
|
| 1966 |
def update_metrics_dashboard_wrapper(company_name):
|
| 1967 |
if company_name:
|
| 1968 |
+
# ✅ 使用缓存管理器加载财务数据
|
| 1969 |
+
def load_financial_data():
|
| 1970 |
+
return update_metrics_dashboard(company_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1971 |
|
| 1972 |
+
# 使用缓存管理器获取数据
|
| 1973 |
try:
|
| 1974 |
+
result = data_cache.get_or_load_data(company_name, "metrics", load_financial_data)
|
| 1975 |
+
stock_card_html, financial_metrics_html, income_table_html = result
|
| 1976 |
yield stock_card_html, financial_metrics_html, income_table_html
|
| 1977 |
except Exception as e:
|
| 1978 |
error_html = f'''
|