更新代码并修改远程仓库地址
This commit is contained in:
18
.claude/settings.local.json
Normal file
18
.claude/settings.local.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(docker build:*)",
|
||||||
|
"Bash(npm install)",
|
||||||
|
"Bash(mkdir:*)",
|
||||||
|
"Bash(docker run:*)",
|
||||||
|
"Bash(docker logs:*)",
|
||||||
|
"Bash(npm run build:*)",
|
||||||
|
"Bash(docker stop:*)",
|
||||||
|
"Bash(docker rm:*)",
|
||||||
|
"Bash(docker tag:*)",
|
||||||
|
"Bash(docker push:*)",
|
||||||
|
"Bash(docker login:*)"
|
||||||
|
],
|
||||||
|
"deny": []
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Dockerfile
11
Dockerfile
@@ -1,5 +1,5 @@
|
|||||||
# 阶段一: 构建Vue前端
|
# 阶段一: 构建Vue前端
|
||||||
FROM node:18-alpine as frontend-builder
|
FROM node:18-alpine AS frontend-builder
|
||||||
|
|
||||||
# 设置工作目录
|
# 设置工作目录
|
||||||
WORKDIR /app/frontend
|
WORKDIR /app/frontend
|
||||||
@@ -13,18 +13,21 @@ RUN npm ci
|
|||||||
# 复制前端源代码
|
# 复制前端源代码
|
||||||
COPY frontend/ ./
|
COPY frontend/ ./
|
||||||
|
|
||||||
|
# 确保node_modules中的可执行文件有正确权限
|
||||||
|
RUN chmod +x node_modules/.bin/*
|
||||||
|
|
||||||
# 构建前端应用
|
# 构建前端应用
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# 阶段二: 构建Python后端
|
# 阶段二: 构建Python后端
|
||||||
FROM python:3.10-slim as backend-builder
|
FROM python:3.10-slim AS backend-builder
|
||||||
|
|
||||||
# 设置工作目录
|
# 设置工作目录
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 安装系统依赖和构建依赖
|
# 安装系统依赖和构建依赖
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
libgl1-mesa-glx \
|
libgl1 \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
build-essential \
|
build-essential \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
@@ -43,7 +46,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
# 安装运行时依赖
|
# 安装运行时依赖
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
libgl1-mesa-glx \
|
libgl1 \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
29
Dockerfile.backend
Normal file
29
Dockerfile.backend
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# 简化版本:只构建后端,不包含前端
|
||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制requirements.txt
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# 安装Python依赖
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# 复制后端代码
|
||||||
|
COPY *.py ./
|
||||||
|
COPY services/ ./services/
|
||||||
|
COPY utils/ ./utils/
|
||||||
|
|
||||||
|
# 创建数据目录和日志目录
|
||||||
|
RUN mkdir -p data logs
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 8888
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
ENV PYTHONPATH=/app
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# 启动应用
|
||||||
|
CMD ["python", "web_server.py"]
|
||||||
32
Dockerfile.full
Normal file
32
Dockerfile.full
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# 完整版本:包含前端和后端
|
||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制requirements.txt
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# 安装Python依赖
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# 复制后端代码
|
||||||
|
COPY *.py ./
|
||||||
|
COPY services/ ./services/
|
||||||
|
COPY utils/ ./utils/
|
||||||
|
|
||||||
|
# 复制前端构建产物
|
||||||
|
COPY frontend/dist/ ./frontend/dist/
|
||||||
|
|
||||||
|
# 创建数据目录和日志目录
|
||||||
|
RUN mkdir -p data logs
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 8888
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
ENV PYTHONPATH=/app
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# 启动应用
|
||||||
|
CMD ["python", "web_server.py"]
|
||||||
27
docker-compose.local.yml
Normal file
27
docker-compose.local.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: stock-scanner-app-local
|
||||||
|
ports:
|
||||||
|
- "8999:8888"
|
||||||
|
environment:
|
||||||
|
- API_KEY=${API_KEY}
|
||||||
|
- API_URL=${API_URL}
|
||||||
|
- API_MODEL=${API_MODEL}
|
||||||
|
- API_TIMEOUT=${API_TIMEOUT}
|
||||||
|
- LOGIN_PASSWORD=${LOGIN_PASSWORD}
|
||||||
|
- ANNOUNCEMENT_TEXT=${ANNOUNCEMENT_TEXT}
|
||||||
|
volumes:
|
||||||
|
- ./logs:/app/logs
|
||||||
|
- ./data:/app/data
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- stock-scanner-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
stock-scanner-network:
|
||||||
|
driver: bridge
|
||||||
@@ -7,6 +7,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
platform: linux/amd64
|
||||||
container_name: stock-scanner-app
|
container_name: stock-scanner-app
|
||||||
ports:
|
ports:
|
||||||
- "8888:8888"
|
- "8888:8888"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pandas==2.2.2
|
|||||||
scipy==1.15.1
|
scipy==1.15.1
|
||||||
|
|
||||||
# 数据获取和分析库
|
# 数据获取和分析库
|
||||||
akshare==1.16.35
|
akshare==1.17.44
|
||||||
tqdm==4.67.1
|
tqdm==4.67.1
|
||||||
|
|
||||||
# Web框架与异步处理
|
# Web框架与异步处理
|
||||||
|
|||||||
@@ -266,13 +266,17 @@ class AIAnalyzer:
|
|||||||
chunk_data = json.loads(line)
|
chunk_data = json.loads(line)
|
||||||
|
|
||||||
# 检查是否有finish_reason
|
# 检查是否有finish_reason
|
||||||
finish_reason = chunk_data.get("choices", [{}])[0].get("finish_reason")
|
choices = chunk_data.get("choices", [])
|
||||||
|
if not choices:
|
||||||
|
logger.debug("收到空的choices数组,跳过")
|
||||||
|
continue
|
||||||
|
finish_reason = choices[0].get("finish_reason")
|
||||||
if finish_reason == "stop":
|
if finish_reason == "stop":
|
||||||
logger.debug("收到finish_reason=stop,流结束")
|
logger.debug("收到finish_reason=stop,流结束")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 获取delta内容
|
# 获取delta内容
|
||||||
delta = chunk_data.get("choices", [{}])[0].get("delta", {})
|
delta = choices[0].get("delta", {})
|
||||||
|
|
||||||
# 检查delta是否为空对象
|
# 检查delta是否为空对象
|
||||||
if not delta or delta == {}:
|
if not delta or delta == {}:
|
||||||
@@ -350,7 +354,16 @@ class AIAnalyzer:
|
|||||||
return
|
return
|
||||||
|
|
||||||
response_data = response.json()
|
response_data = response.json()
|
||||||
analysis_text = response_data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
choices = response_data.get("choices", [])
|
||||||
|
if not choices:
|
||||||
|
logger.error("API响应中没有choices数据")
|
||||||
|
yield json.dumps({
|
||||||
|
"stock_code": stock_code,
|
||||||
|
"error": "API响应格式错误:缺少choices数据",
|
||||||
|
"status": "error"
|
||||||
|
})
|
||||||
|
return
|
||||||
|
analysis_text = choices[0].get("message", {}).get("content", "")
|
||||||
|
|
||||||
# 尝试从分析内容中提取投资建议
|
# 尝试从分析内容中提取投资建议
|
||||||
recommendation = self._extract_recommendation(analysis_text)
|
recommendation = self._extract_recommendation(analysis_text)
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ def test_api_stream():
|
|||||||
json_data = json.loads(data_content)
|
json_data = json.loads(data_content)
|
||||||
logger.debug(f"JSON结构: {_truncate_json_for_logging(json_data)}")
|
logger.debug(f"JSON结构: {_truncate_json_for_logging(json_data)}")
|
||||||
|
|
||||||
if 'choices' in json_data:
|
if 'choices' in json_data and json_data['choices']:
|
||||||
delta = json_data['choices'][0].get('delta', {})
|
delta = json_data['choices'][0].get('delta', {})
|
||||||
content = delta.get('content', '')
|
content = delta.get('content', '')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user