fix header
This commit is contained in:
19
.dockerignore
Normal file
19
.dockerignore
Normal 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
|
||||
49
Dockerfile
49
Dockerfile
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user