fix header

This commit is contained in:
felix
2025-11-23 10:33:00 +08:00
parent 0d871644f0
commit de780d783a
6 changed files with 106 additions and 21 deletions

19
.dockerignore Normal file
View File

@@ -0,0 +1,19 @@
__pycache__
*.pyo
*.pyd
.Python
env
venv
.venv
.env
.git
.cache
.pytest_cache
.coverage
htmlcov
*.log
notebooks
.DS_Store
README.md
.dockerignore
Dockerfile

View File

@@ -1,28 +1,59 @@
# 使用多阶段构建来分离构建环境和运行环境
FROM python:3.10-slim as builder
WORKDIR /app
# 1. 先只复制依赖文件
COPY requirements.txt .
# 换源和安装构建依赖
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources \
&& sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list.d/debian.sources
# 安装构建依赖
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple \
&& pip install --user -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# 第二阶段:运行环境
FROM python:3.10-slim
WORKDIR /app
COPY . .
# 换源
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources \
&& sed -i 's|security.debian.org/debian-security|mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list.d/debian.sources
# 安装运行时的系统依赖(只安装必要的)
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev supervisor \
&& rm -rf /var/lib/apt/lists/* \
&& pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple \
&& pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple \
&& pip install gunicorn wait-for-it -i https://mirrors.aliyun.com/pypi/simple
&& apt-get install -y --no-install-recommends supervisor \
&& rm -rf /var/lib/apt/lists/*
# 从构建阶段复制已安装的Python包
COPY --from=builder /root/.local /root/.local
# 设置PATH让Python可以找到用户安装的包
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONPATH=/app
# 设置时区
ENV TZ="Asia/Shanghai"
RUN mkdir -p /var/log/fastapi_server \
# 创建目录结构
RUN mkdir -p /var/log/app_server \
&& mkdir -p /var/log/supervisor \
&& mkdir -p /etc/supervisor/conf.d
# 复制配置文件
COPY deploy/supervisor.conf /etc/supervisor/supervisord.conf
COPY deploy/app_server.conf /etc/supervisor/conf.d/
COPY deploy/fastapi_server.conf /etc/supervisor/conf.d/
# 最后复制应用代码利用Docker缓存层
COPY backend/ ./backend
EXPOSE 8001

View File

@@ -4,8 +4,6 @@ import logging
import asyncio
from typing import Optional, List
from soupsieve.util import lower
from backend.app.ai.crud import recording_dao
from backend.app.ai.crud.image_text_crud import image_text_dao
from backend.app.ai.model.image_text import ImageText

View File

@@ -10,9 +10,8 @@ from datetime import datetime
from backend.app.ai.crud.image_task_crud import image_task_dao
from backend.app.ai.model.image_task import ImageTaskStatus
from backend.app.ai.service.image_service import image_service
from backend.database.db import async_db_session, background_db_session
from sqlalchemy.exc import SQLAlchemyError
from asyncpg import SerializationError
from backend.database.db import background_db_session
from sqlalchemy.exc import SQLAlchemyError, OperationalError
logger = logging.getLogger(__name__)
@@ -85,8 +84,8 @@ async def update_task_status_with_retry(db, task_id, status, result=None, error_
try:
result = await image_task_dao.update_task_status(db, task_id, status, result, error_message)
return result
except SerializationError as e:
logger.warning(f"Serialization error updating task {task_id} status to {status} (attempt {attempt + 1}): {str(e)}")
except OperationalError as e:
logger.warning(f"Operational error updating task {task_id} status to {status} (attempt {attempt + 1}): {str(e)}")
if attempt < max_retries - 1:
# Exponential backoff with jitter
import random
@@ -116,8 +115,8 @@ async def increment_retry_count_with_retry(db, task_id, max_retries=3):
try:
result = await image_task_dao.increment_retry_count(db, task_id)
return result
except SerializationError as e:
logger.warning(f"Serialization error incrementing retry count for task {task_id} (attempt {attempt + 1}): {str(e)}")
except OperationalError as e:
logger.warning(f"Operational error incrementing retry count for task {task_id} (attempt {attempt + 1}): {str(e)}")
if attempt < max_retries - 1:
# Exponential backoff with jitter
import random

View File

@@ -17,7 +17,9 @@ from pydantic_core import from_json
from sqlalchemy.ext.asyncio import AsyncSession
from backend.app.admin.model import WxUser
from backend.app.admin.schema.wx import GetWxUserInfoWithRelationDetail
from backend.app.admin.model.dict import DictCategory
from backend.app.admin.schema.wx import GetWxUserInfoWithRelationDetail, DictLevel
from backend.app.admin.service.points_service import points_service
from backend.common.dataclasses import AccessToken, NewToken, RefreshToken, TokenPayload
from backend.common.exception import errors
from backend.common.exception.errors import TokenError
@@ -25,6 +27,7 @@ from backend.core.conf import settings
from backend.database.db import async_db_session
from backend.database.redis import redis_client
from backend.utils.serializers import select_as_dict
from backend.utils.snowflake import snowflake
from backend.utils.timezone import timezone
@@ -337,3 +340,31 @@ async def jwt_authentication(token: str) -> GetWxUserInfoWithRelationDetail:
# https://docs.pydantic.dev/latest/concepts/json/#partial-json-parsing
user = GetWxUserInfoWithRelationDetail.model_validate(from_json(cache_user, allow_partial=True))
return user
async def wx_openid_authentication(openid: str, unionid: str) -> GetWxUserInfoWithRelationDetail:
from backend.app.admin.crud.wx_user_crud import wx_user_dao
async with async_db_session() as db:
user = None
try:
# 查找或创建用户
user = await wx_user_dao.get_by_openid(db, openid)
if not user:
session_key = snowflake.generate()
user = WxUser(
openid=openid,
unionid=unionid,
session_key=session_key,
profile={
'dict_level': DictLevel.LEVEL1.value,
'dict_category': DictCategory.GENERAL.value
},
)
await wx_user_dao.add(db, user)
await db.flush()
await db.refresh(user)
await points_service.initialize_user_points(user_id=user.id, db=db)
return GetWxUserInfoWithRelationDetail(**select_as_dict(user))
except Exception as e:
db.rollback()
raise

View File

@@ -10,7 +10,7 @@ from starlette.requests import HTTPConnection
from backend.app.admin.schema.wx import GetWxUserInfoWithRelationDetail
from backend.common.exception.errors import TokenError
from backend.common.log import log
from backend.common.security.jwt import jwt_authentication
from backend.common.security.jwt import jwt_authentication, wx_openid_authentication
from backend.core.conf import settings
from backend.utils.serializers import MsgSpecJSONResponse
@@ -55,6 +55,13 @@ class JwtAuthMiddleware(AuthenticationBackend):
:param request: FastAPI 请求对象
:return:
"""
wx_openid = request.headers.get('X-WX-OPENID')
wx_unionid = request.headers.get('X-WX-UNIONID')
if wx_openid:
user = await wx_openid_authentication(wx_openid, wx_unionid)
if user:
return AuthCredentials(['authenticated']), user
token = request.headers.get('Authorization')
if not token:
return None