更新前端配置、文档和脚本
This commit is contained in:
parent
69b1b481b2
commit
b982cd5368
267
docs/user-guide.md
Normal file
267
docs/user-guide.md
Normal 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月
|
||||
|
||||
|
||||
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@import "github-markdown-css/github-markdown.css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
|
||||
@ -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
BIN
portwardenc-amd64
Executable file
Binary file not shown.
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user