更新前端配置、文档和脚本

This commit is contained in:
xucheng 2025-10-31 22:14:19 +08:00
parent 69b1b481b2
commit b982cd5368
8 changed files with 319 additions and 71 deletions

267
docs/user-guide.md Normal file
View File

@ -0,0 +1,267 @@
# 用户使用文档
## 欢迎使用基本面分析系统
基本面分析系统是一个专业的股票分析平台,帮助投资者通过多维度的基本面分析,做出更明智的投资决策。
## 目录
- [快速开始](#快速开始)
- [主要功能](#主要功能)
- [使用指南](#使用指南)
- [常见问题](#常见问题)
- [系统配置](#系统配置)
## 快速开始
### 1. 生成分析报告
1. **访问首页**:在浏览器中打开系统首页
2. **输入股票代码**:在输入框中输入股票代码,例如:
- 中国股票:`600519`(会自动识别为 600519.SH`600519.SH`
- 美国股票:`AAPL`
- 香港股票:`00700.HK`
3. **选择交易市场**:从下拉菜单中选择对应的交易市场(中国、香港、美国、日本)
4. **生成报告**:点击"生成报告"按钮,系统将自动获取财务数据并生成分析报告
### 2. 查看报告
报告生成后,您将看到包含以下内容的综合报告:
- **股价图表**:来自 TradingView 的实时股价图表
- **财务数据**:多年财务指标对比,包括:
- 主要指标ROE、ROA、ROIC、毛利率、净利润率等
- 费用指标:销售费用率、管理费用率、研发费用率等
- 资产占比:现金占比、库存占比、应收款占比等
- 周转能力:存货周转天数、应收款周转天数等
- 人均效率:人均创收、人均创利、人均工资等
- 市场表现股价、市值、PE、PB、股东户数等
- **AI 分析模块**:基于财务数据的智能分析,包括:
- 公司简介
- 业务分析
- 财务健康度评估
- 投资建议等
### 3. 报告操作
- **开始分析**:点击"开始分析"按钮,系统将按顺序生成各个分析模块
- **停止**:在分析过程中,可以随时点击"停止"按钮中断分析
- **继续**:停止后可以点击"继续"按钮恢复分析
- **重新生成分析**:对任意分析模块,可以点击"重新生成分析"按钮重新生成
## 主要功能
### 1. 股票分析报告
系统提供全面的股票基本面分析,包括:
- **财务数据展示**:自动从 Tushare 等数据源获取最新的财务数据
- **多维度分析**:涵盖盈利能力、运营效率、财务健康度等多个维度
- **历史对比**:展示多年的财务指标变化趋势
- **实时图表**:集成 TradingView 高级图表组件,提供专业的股价图表
### 2. 智能分析模块
系统使用 AI 模型(如 Google Gemini对财务数据进行深度分析
- **自动生成**:根据财务数据自动生成业务分析和投资建议
- **模块化设计**:不同分析模块相互独立,可按需生成
- **依赖关系**:支持分析模块之间的依赖关系,确保分析的准确性
- **实时进度**:显示每个分析模块的生成进度和状态
### 3. 系统配置管理
系统提供完善的配置管理功能:
- **数据库配置**:配置 PostgreSQL 数据库连接
- **AI 服务配置**:配置 AI 模型的 API 密钥和端点
- **数据源配置**:配置 Tushare、Finnhub 等数据源的 API 密钥
- **分析模块配置**:自定义分析模块的名称、模型和提示词模板
- **配置测试**:支持测试各项配置的有效性
- **配置导入/导出**:支持配置的备份和恢复
### 4. 历史报告查询
系统支持查询历史生成的报告:
- **按市场和企业ID查询**根据交易市场和企业ID查询历史报告
- **报告列表**:查看所有历史报告及其状态
- **报告详情**:查看完整的报告内容
## 使用指南
### 股票代码格式
不同市场的股票代码格式:
- **中国市场**
- 上交所6 位数字,如 `600519`(系统会自动添加 `.SH` 后缀)
- 深交所6 位数字,如 `000001`(系统会自动添加 `.SZ` 后缀)
- 完整格式:`600519.SH` 或 `000001.SZ`
- **美国市场**:直接输入股票代码,如 `AAPL`、`MSFT`
- **香港市场**:股票代码,如 `00700`
- **日本市场**:股票代码,如 `7203`
### 财务数据解读
系统展示的财务数据按以下方式组织:
1. **主要指标**:核心财务指标
- ROE净资产收益率衡量股东权益的盈利能力>12% 为优秀
- ROA总资产收益率衡量资产利用效率
- ROIC投入资本回报率衡量资本使用效率>12% 为优秀
- 毛利率:反映产品或服务的盈利能力
- 净利润率:反映整体盈利能力
2. **费用指标**:各项费用占收入的比例
- 销售费用率、管理费用率、研发费用率等
- 其他费用率:通过毛利率减去各项费用率计算得出
3. **资产占比**:各项资产占总资产的比例
- 现金占比:反映资金充裕程度
- 库存占比:反映库存管理水平
- 应收款占比:反映应收账款风险
- 商誉占比:反映并购活动的影响
4. **周转能力**:反映资产周转效率
- 存货周转天数:存货变现的速度
- 应收款周转天数:应收账款回收速度(>90天需注意
- 应付款周转天数:应付账款支付周期
5. **人均效率**:反映人力资源效率
- 人均创收、人均创利:衡量员工贡献
- 人均工资:反映员工待遇水平
6. **市场表现**:股票市场的表现指标
- PE市盈率、PB市净率估值指标
- 股东户数:反映股东结构变化
### 分析模块说明
每个分析模块都有其特定的作用:
- **公司简介**:自动生成公司的基本介绍和业务概况
- **业务分析**:深度分析公司的业务模式和竞争优势
- **财务分析**:评估公司的财务健康状况
- **风险评估**:识别潜在的投资风险
- **投资建议**:提供基于分析的投资建议
分析模块会按依赖关系顺序执行,确保每个模块都能获得所需的前置分析结果。
### 执行详情
在报告页面的"执行详情"标签页,您可以查看:
- **执行概况**财务数据获取的耗时、API 调用次数等
- **分析任务**每个分析模块的执行状态、耗时、Token 消耗等
- **总体统计**:总耗时、完成的任务数量、总 Token 消耗等
这些信息有助于了解报告的生成过程和数据来源。
## 常见问题
### Q1: 为什么有些财务数据显示为 "-"
A: 可能是以下原因:
- 该股票在对应年份没有数据
- 数据源暂时不可用
- 该指标不适用于该股票类型
### Q2: 分析模块生成失败怎么办?
A: 您可以:
- 点击"重新生成分析"按钮重试
- 检查系统配置中的 AI 服务配置是否正确
- 查看"执行详情"中的错误信息
### Q3: 如何查看历史报告?
A:
1. 访问"查询"页面(如果已启用)
2. 选择交易市场和企业ID
3. 点击"查询"按钮查看历史报告列表
### Q4: 股票代码输入错误怎么办?
A: 系统会自动识别一些常见的代码格式,但如果识别失败,请:
- 中国市场:使用完整格式,如 `600519.SH``000001.SZ`
- 其他市场:按照该市场的标准格式输入
### Q5: 如何配置系统?
A:
1. 访问"配置"页面
2. 在对应的标签页中配置各项设置
3. 使用"测试"按钮验证配置是否正确
4. 点击"保存所有配置"保存设置
### Q6: 分析报告生成需要多长时间?
A: 生成时间取决于:
- 财务数据的获取速度(通常几秒钟)
- AI 分析模块的数量和复杂度
- AI 服务的响应速度
完整的报告生成通常需要 1-5 分钟。
### Q7: 可以同时分析多只股票吗?
A: 目前系统每次只能分析一只股票。如需分析多只股票,请分别提交请求。
### Q8: 报告数据是实时的吗?
A:
- 财务数据:来自 Tushare 等数据源,更新频率取决于数据源
- 股价图表TradingView 提供实时股价数据
- AI 分析:基于当前获取的财务数据实时生成
## 系统配置
### 首次使用配置
首次使用系统时,需要配置以下内容:
1. **数据库配置**(如使用)
- 数据库连接 URL`postgresql+asyncpg://user:password@host:port/database`
- 使用"测试连接"按钮验证连接
2. **AI 服务配置**
- API Key输入您的 AI 服务 API 密钥
- Base URL输入 API 端点地址(如使用自建服务)
3. **数据源配置**
- **Tushare**:输入 Tushare API Key中国市场必需
- **Finnhub**:输入 Finnhub API Key全球市场可选
### 配置注意事项
- **敏感信息保护**API 密钥等敏感信息在输入框中不会显示,留空表示保持当前值
- **配置验证**:保存前建议使用"测试"按钮验证各项配置
- **配置备份**:建议定期使用"导出配置"功能备份配置
- **配置恢复**:可使用"导入配置"功能恢复之前的配置
### 分析模块配置
在"配置"页面的"分析配置"标签页,您可以:
- **自定义模块名称**:修改分析模块的显示名称
- **选择 AI 模型**:为每个模块指定使用的 AI 模型
- **编辑提示词模板**:自定义每个模块的分析提示词
- **设置模块依赖**:配置分析模块之间的依赖关系
配置修改后,点击"保存分析配置"即可生效。
## 技术支持
如果您在使用过程中遇到问题,可以:
1. 查看"执行详情"中的错误信息
2. 检查系统配置是否正确
3. 查看系统日志(如果已启用)
4. 联系系统管理员获取支持
---
**最后更新**2025年1月

View File

@ -15,6 +15,7 @@
"@radix-ui/react-tabs": "^1.1.13",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"github-markdown-css": "^5.8.1",
"lucide-react": "^0.545.0",
"next": "15.5.5",
"react": "19.1.0",
@ -4587,6 +4588,18 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
"node_modules/github-markdown-css": {
"version": "5.8.1",
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.8.1.tgz",
"integrity": "sha512-8G+PFvqigBQSWLQjyzgpa2ThD9bo7+kDsriUIidGcRhXgmcaAWUIpCZf8DavJgc+xifjbCG+GvMyWr0XMXmc7g==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",

View File

@ -4,7 +4,7 @@
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build --turbopack",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
@ -16,6 +16,7 @@
"@radix-ui/react-tabs": "^1.1.13",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"github-markdown-css": "^5.8.1",
"lucide-react": "^0.545.0",
"next": "15.5.5",
"react": "19.1.0",

View File

@ -6,13 +6,13 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
async function getMarkdownContent() {
// process.cwd() is the root of the Next.js project (the 'frontend' directory)
const mdPath = path.join(process.cwd(), '..', 'docs', 'design.md');
const mdPath = path.join(process.cwd(), '..', 'docs', 'user-guide.md');
try {
const content = await fs.readFile(mdPath, 'utf8');
return content;
} catch (error) {
console.error("Failed to read design.md:", error);
return "# 文档加载失败\n\n无法读取 `docs/design.md` 文件。请检查文件是否存在以及服务器权限。";
console.error("Failed to read user-guide.md:", error);
return "# 文档加载失败\n\n无法读取 `docs/user-guide.md` 文件。请检查文件是否存在以及服务器权限。";
}
}
@ -22,42 +22,22 @@ export default async function DocsPage() {
return (
<div className="container mx-auto py-6 space-y-6">
<header className="space-y-2">
<h1 className="text-3xl font-bold"></h1>
<h1 className="text-3xl font-bold">使</h1>
<p className="text-muted-foreground">
使
</p>
</header>
<Card>
<CardContent className="p-6">
<article className="prose prose-zinc max-w-none dark:prose-invert">
<article className="markdown-body" style={{
boxSizing: 'border-box',
minWidth: '200px',
maxWidth: '980px',
margin: '0 auto',
padding: '0'
}}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
h1: ({node, ...props}) => <h1 className="text-3xl font-bold mb-4 mt-8 border-b pb-2" {...props} />,
h2: ({node, ...props}) => <h2 className="text-2xl font-bold mb-3 mt-6 border-b pb-2" {...props} />,
h3: ({node, ...props}) => <h3 className="text-xl font-semibold mb-2 mt-4" {...props} />,
p: ({node, ...props}) => <p className="mb-4 leading-7" {...props} />,
ul: ({node, ...props}) => <ul className="list-disc list-inside mb-4 space-y-2" {...props} />,
ol: ({node, ...props}) => <ol className="list-decimal list-inside mb-4 space-y-2" {...props} />,
li: ({node, ...props}) => <li className="ml-4" {...props} />,
code: ({node, inline, className, children, ...props}: any) => {
const match = /language-(\w+)/.exec(className || '');
return !inline ? (
<code className={className} {...props}>
{children}
</code>
) : (
<code className="bg-muted px-1.5 py-1 rounded text-sm font-mono" {...props}>
{children}
</code>
);
},
pre: ({children}) => <pre className="bg-muted p-4 rounded my-4 overflow-x-auto">{children}</pre>,
table: ({node, ...props}) => <div className="overflow-x-auto my-4"><table className="border-collapse border border-border w-full" {...props} /></div>,
th: ({node, ...props}) => <th className="border border-border px-4 py-2 bg-muted font-semibold text-left" {...props} />,
td: ({node, ...props}) => <td className="border border-border px-4 py-2" {...props} />,
a: ({node, ...props}) => <a className="text-primary underline hover:text-primary/80" {...props} />,
}}
>
{content}
</ReactMarkdown>

View File

@ -1,5 +1,6 @@
@import "tailwindcss";
@import "tw-animate-css";
@import "github-markdown-css/github-markdown.css";
@custom-variant dark (&:is(.dark *));

View File

@ -1491,19 +1491,7 @@ export default function ReportPage() {
: '待开始'}
</div>
</div>
{/* 失败时的“重新分析”按钮(兼容原逻辑) */}
{state.error && !state.loading && (
<Button
variant="outline"
size="sm"
onClick={() => retryAnalysis(analysisType)}
disabled={currentAnalysisTask !== null}
>
<RotateCw className="size-4" />
</Button>
)}
{/* 新增:始终可见的“重新生成分析”按钮 */}
{/* 始终可见的"重新生成分析"按钮 */}
{!state.loading && (
<Button
variant="ghost"
@ -1524,31 +1512,15 @@ export default function ReportPage() {
{(state.loading || state.content) && (
<div className="space-y-4">
<div className="border rounded-lg p-6 bg-card">
<div className="leading-relaxed">
<article className="markdown-body" style={{
boxSizing: 'border-box',
minWidth: '200px',
maxWidth: '980px',
margin: '0 auto',
padding: '0'
}}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
h1: ({node, ...props}) => <h1 className="text-2xl font-bold mb-4 mt-6 first:mt-0" {...props} />,
h2: ({node, ...props}) => <h2 className="text-xl font-bold mb-3 mt-5 first:mt-0" {...props} />,
h3: ({node, ...props}) => <h3 className="text-lg font-semibold mb-2 mt-4 first:mt-0" {...props} />,
p: ({node, ...props}) => <p className="mb-2 leading-7" {...props} />,
ul: ({node, ...props}) => <ul className="list-disc list-inside mb-2 space-y-1 ml-4" {...props} />,
ol: ({node, ...props}) => <ol className="list-decimal list-inside mb-2 space-y-1 ml-4" {...props} />,
li: ({node, ...props}) => <li className="ml-2" {...props} />,
strong: ({node, ...props}) => <strong className="font-semibold" {...props} />,
em: ({node, ...props}) => <em className="italic text-muted-foreground" {...props} />,
blockquote: ({node, ...props}) => <blockquote className="border-l-4 border-muted pl-4 italic my-2" {...props} />,
code: ({node, inline, ...props}: any) =>
inline
? <code className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono" {...props} />
: <code className="block bg-muted p-4 rounded my-2 overflow-x-auto font-mono text-sm" {...props} />,
pre: ({node, ...props}) => <pre className="bg-muted p-4 rounded my-2 overflow-x-auto" {...props} />,
table: ({node, ...props}) => <div className="overflow-x-auto my-2"><table className="border-collapse border border-border w-full" {...props} /></div>,
th: ({node, ...props}) => <th className="border border-border px-3 py-2 bg-muted font-semibold text-left" {...props} />,
td: ({node, ...props}) => <td className="border border-border px-3 py-2" {...props} />,
a: ({node, ...props}) => <a className="text-primary underline hover:text-primary/80" {...props} />,
hr: ({node, ...props}) => <hr className="my-4 border-border" {...props} />,
}}
>
{normalizedContent}
</ReactMarkdown>
@ -1558,7 +1530,7 @@ export default function ReportPage() {
<span className="text-sm">...</span>
</span>
)}
</div>
</article>
</div>
</div>
)}

BIN
portwardenc-amd64 Executable file

Binary file not shown.

View File

@ -34,9 +34,23 @@ ensure_backend() {
echo -e "${YELLOW}[SETUP]${RESET} Creating Python venv and installing backend requirements..."
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Upgrade pip first
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install --upgrade pip --timeout 100
# Install requirements with timeout and mirror
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install -r requirements.txt --timeout 300
else
source .venv/bin/activate
# Upgrade pip if needed
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple 2>/dev/null || \
pip install --upgrade pip --timeout 100 2>/dev/null || true
# Check if key dependencies are installed
if ! python -c "import uvicorn" 2>/dev/null; then
echo -e "${YELLOW}[SETUP]${RESET} Installing missing backend requirements..."
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
pip install -r requirements.txt --timeout 300
fi
fi
# Export TUSHARE_TOKEN from config if available (prefer jq, fallback to node)