feat: Add PM2 configuration for deployment, a database initialization script, and update project dependencies.
This commit is contained in:
parent
daf5808f05
commit
a5a43e9db8
57
README.md
57
README.md
@ -36,6 +36,63 @@
|
|||||||
*注:`IFIND_REFRESH_TOKEN` 为同花顺量化接口的 Refresh Token,需购买相关服务获取。*
|
*注:`IFIND_REFRESH_TOKEN` 为同花顺量化接口的 Refresh Token,需购买相关服务获取。*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 如何运行
|
||||||
|
## 守护进程管理 (PM2)
|
||||||
|
|
||||||
|
本项目推荐使用 [PM2](https://pm2.keymetrics.io/) 来管理和守护后端与前端进程,支持自动重启和日志管理。
|
||||||
|
|
||||||
|
### 1. 配置
|
||||||
|
项目根目录下已提供预置的 `ecosystem.config.js` 配置文件。
|
||||||
|
|
||||||
|
### 2. 管理命令
|
||||||
|
```bash
|
||||||
|
# 全局安装 PM2 (如果没有)
|
||||||
|
npm install -g pm2
|
||||||
|
|
||||||
|
# 启动所有服务 (后端 + 前端)
|
||||||
|
pm2 start ecosystem.config.js
|
||||||
|
|
||||||
|
# 查看服务状态
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
# 查看日志
|
||||||
|
pm2 logs
|
||||||
|
|
||||||
|
# 停止所有服务
|
||||||
|
pm2 stop all
|
||||||
|
|
||||||
|
# 重启所有服务
|
||||||
|
pm2 restart all
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 应用说明
|
||||||
|
- **datafetch-backend**: Python 后端服务 (Port 8000)
|
||||||
|
- **datafetch-frontend**: Next.js 前端开发服务 (Port 3000)
|
||||||
|
|
||||||
|
## 自动化部署脚本
|
||||||
|
|
||||||
|
为了简化部署流程,项目提供了一个自动化脚本 `deploy.sh`,可一键完成从系统依赖安装到服务启动的全过程。
|
||||||
|
|
||||||
|
### 使用方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 赋予执行权限
|
||||||
|
chmod +x deploy.sh
|
||||||
|
|
||||||
|
# 运行部署脚本(开发模式)
|
||||||
|
./deploy.sh
|
||||||
|
|
||||||
|
# 运行部署脚本(生产模式 - 会执行前端 build)
|
||||||
|
./deploy.sh prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### 脚本执行内容
|
||||||
|
1. **检查并安装系统级库**:自动安装 `python3-venv`、`pkg-config` 以及 `WeasyPrint` 所需的 `libpango` 等图形库。
|
||||||
|
2. **安装全局 Node 工具**:检查并安装 `pm2`。
|
||||||
|
3. **设置 Python 环境**:创建 `.venv` 并安装 `requirements.txt` 中的依赖。
|
||||||
|
4. **初始化数据库**:运行 `create_db.py` 创建 SQLite 数据库。
|
||||||
|
5. **启动服务**:构建前端(如指定 production)并使用 PM2 启动/重启所有服务。
|
||||||
|
|
||||||
## 如何运行
|
## 如何运行
|
||||||
|
|
||||||
### 参数说明
|
### 参数说明
|
||||||
|
|||||||
20
create_db.py
Normal file
20
create_db.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Ensure backend module can be found
|
||||||
|
sys.path.append(os.path.abspath("backend"))
|
||||||
|
|
||||||
|
from app.database import init_db
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
print("Initializing database...")
|
||||||
|
try:
|
||||||
|
await init_db()
|
||||||
|
print("Database initialized successfully.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error initializing database: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
87
deploy.sh
Executable file
87
deploy.sh
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 颜色定义
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
INFO="${GREEN}[INFO]${NC}"
|
||||||
|
ERROR="${RED}[ERROR]${NC}"
|
||||||
|
|
||||||
|
# 错误处理
|
||||||
|
set -e
|
||||||
|
trap 'echo -e "${ERROR} 部署失败,请检查上方错误日志。"' ERR
|
||||||
|
|
||||||
|
echo -e "${INFO} 开始自动化部署脚本..."
|
||||||
|
|
||||||
|
# 1. 检查并安装系统级依赖
|
||||||
|
echo -e "${INFO} 1/6 检查并安装系统依赖..."
|
||||||
|
if command -v apt-get &> /dev/null; then
|
||||||
|
sudo apt-get update
|
||||||
|
# 基础构建工具
|
||||||
|
sudo apt-get install -y build-essential python3-dev pkg-config
|
||||||
|
# WeasyPrint 依赖
|
||||||
|
sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 shared-mime-info
|
||||||
|
# Python 虚拟环境支持
|
||||||
|
sudo apt-get install -y python3-venv python3-pip
|
||||||
|
else
|
||||||
|
echo -e "${ERROR} 仅支持 Debian/Ubuntu 系统,请手动安装相关依赖。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 安装 Node.js 依赖 (PM2)
|
||||||
|
echo -e "${INFO} 2/6 检查并安装全局 Node.js 工具..."
|
||||||
|
if ! command -v pm2 &> /dev/null; then
|
||||||
|
echo "安装 PM2..."
|
||||||
|
sudo npm install -g pm2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. 创建并激活 Python 虚拟环境
|
||||||
|
echo -e "${INFO} 3/6 设置 Python 虚拟环境..."
|
||||||
|
if [ ! -d ".venv" ]; then
|
||||||
|
python3 -m venv .venv
|
||||||
|
fi
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
# 4. 安装 Python 项目依赖
|
||||||
|
echo -e "${INFO} 4/6 安装 Python 依赖..."
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 5. 初始化数据库
|
||||||
|
echo -e "${INFO} 5/6 初始化数据库..."
|
||||||
|
if [ -f "create_db.py" ]; then
|
||||||
|
python create_db.py
|
||||||
|
else
|
||||||
|
echo -e "${ERROR} 找不到 create_db.py,跳过数据库初始化。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. 启动服务
|
||||||
|
echo -e "${INFO} 6/6 启动服务..."
|
||||||
|
|
||||||
|
# 如果是生产环境部署前端
|
||||||
|
if [ "$1" == "prod" ]; then
|
||||||
|
echo "构建前端..."
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
# 修改 ecosystem.config.js 指向 build (如果是临时修改建议手动操作,这里演示默认 dev 模式)
|
||||||
|
echo -e "${INFO} 请确保 ecosystem.config.js 已配置为生产模式启动 (npm start)"
|
||||||
|
else
|
||||||
|
# 开发模式
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 重启 PM2
|
||||||
|
pm2 delete all 2>/dev/null || true
|
||||||
|
pm2 start ecosystem.config.js
|
||||||
|
|
||||||
|
echo -e "${INFO} =================================================="
|
||||||
|
echo -e "${INFO} 部署成功!"
|
||||||
|
echo -e "${INFO} 后端 API: http://localhost:8000"
|
||||||
|
echo -e "${INFO} 前端 页面: http://localhost:3000"
|
||||||
|
echo -e "${INFO} 使用 'pm2 list' 查看服务状态"
|
||||||
|
echo -e "${INFO} 使用 'pm2 logs' 查看日志"
|
||||||
|
echo -e "${INFO} =================================================="
|
||||||
22
ecosystem.config.js
Normal file
22
ecosystem.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "datafetch-backend",
|
||||||
|
script: ".venv/bin/python",
|
||||||
|
args: "-m uvicorn backend.app.main:app --host 0.0.0.0 --port 8000",
|
||||||
|
cwd: "./",
|
||||||
|
env: {
|
||||||
|
PYTHONPATH: "./backend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datafetch-frontend",
|
||||||
|
script: "npm",
|
||||||
|
args: "run dev", // 生产环境建议改为 "start" 并先运行 npm run build
|
||||||
|
cwd: "./frontend",
|
||||||
|
env: {
|
||||||
|
NODE_ENV: "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
22
ecosystem.config.js.bak
Normal file
22
ecosystem.config.js.bak
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "datafetch-backend",
|
||||||
|
script: ".venv/bin/uvicorn",
|
||||||
|
args: "backend.app.main:app --host 0.0.0.0 --port 8000",
|
||||||
|
cwd: ".",
|
||||||
|
env: {
|
||||||
|
PYTHONPATH: "."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "datafetch-frontend",
|
||||||
|
script: "npm",
|
||||||
|
args: "run dev",
|
||||||
|
cwd: "./frontend",
|
||||||
|
env: {
|
||||||
|
NODE_ENV: "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
17
frontend/package-lock.json
generated
17
frontend/package-lock.json
generated
@ -84,7 +84,6 @@
|
|||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@ -2423,7 +2422,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@ -2434,7 +2432,6 @@
|
|||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@ -2490,7 +2487,6 @@
|
|||||||
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.51.0",
|
"@typescript-eslint/scope-manager": "8.51.0",
|
||||||
"@typescript-eslint/types": "8.51.0",
|
"@typescript-eslint/types": "8.51.0",
|
||||||
@ -2996,7 +2992,6 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -3359,7 +3354,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@ -4060,7 +4054,6 @@
|
|||||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@ -4246,7 +4239,6 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@ -7478,7 +7470,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -7488,7 +7479,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@ -7501,7 +7491,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.69.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.69.0.tgz",
|
||||||
"integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==",
|
"integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
@ -8350,8 +8339,7 @@
|
|||||||
"version": "4.1.18",
|
"version": "4.1.18",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss-animate": {
|
"node_modules/tailwindcss-animate": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
@ -8417,7 +8405,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@ -8610,7 +8597,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@ -9050,7 +9036,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz",
|
||||||
"integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==",
|
"integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,3 +7,8 @@ markdown
|
|||||||
jquants-api-client
|
jquants-api-client
|
||||||
google-genai
|
google-genai
|
||||||
PyYAML
|
PyYAML
|
||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
sqlalchemy
|
||||||
|
aiosqlite
|
||||||
|
weasyprint
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user