Skip to content

Commit d2a5b9d

Browse files
author
gaozhe
committed
feat: deploy
1 parent aa84968 commit d2a5b9d

File tree

19 files changed

+1253
-380
lines changed

19 files changed

+1253
-380
lines changed

.github/workflows/build.yml

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
name: Build & Push Docker Images
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- dev
8+
tags:
9+
- 'v*.*.*'
10+
workflow_dispatch:
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}
15+
16+
jobs:
17+
# ============================================================
18+
# Backend: FastAPI Server
19+
# ============================================================
20+
build-backend-server:
21+
name: Build Backend (Server)
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
packages: write
26+
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Set up Docker Buildx
32+
uses: docker/setup-buildx-action@v3
33+
34+
- name: Login to GHCR
35+
uses: docker/login-action@v3
36+
with:
37+
registry: ${{ env.REGISTRY }}
38+
username: ${{ github.actor }}
39+
password: ${{ secrets.GITHUB_TOKEN }}
40+
41+
- name: Docker metadata (server)
42+
id: meta
43+
uses: docker/metadata-action@v5
44+
with:
45+
images: ${{ env.IMAGE_PREFIX }}/wemcp-server
46+
tags: |
47+
type=ref,event=branch
48+
type=semver,pattern={{version}}
49+
type=semver,pattern={{major}}.{{minor}}
50+
type=sha,prefix=sha-,format=short
51+
52+
- name: Build and push (server)
53+
uses: docker/build-push-action@v6
54+
with:
55+
context: ./backend
56+
file: ./backend/Dockerfile
57+
build-args: |
58+
SERVER_TYPE=fastapi_server
59+
push: true
60+
tags: ${{ steps.meta.outputs.tags }}
61+
labels: ${{ steps.meta.outputs.labels }}
62+
cache-from: type=gha,scope=backend-server
63+
cache-to: type=gha,mode=max,scope=backend-server
64+
65+
# ============================================================
66+
# Backend: Celery Worker
67+
# ============================================================
68+
build-backend-worker:
69+
name: Build Backend (Worker)
70+
runs-on: ubuntu-latest
71+
permissions:
72+
contents: read
73+
packages: write
74+
75+
steps:
76+
- name: Checkout
77+
uses: actions/checkout@v4
78+
79+
- name: Set up Docker Buildx
80+
uses: docker/setup-buildx-action@v3
81+
82+
- name: Login to GHCR
83+
uses: docker/login-action@v3
84+
with:
85+
registry: ${{ env.REGISTRY }}
86+
username: ${{ github.actor }}
87+
password: ${{ secrets.GITHUB_TOKEN }}
88+
89+
- name: Docker metadata (worker)
90+
id: meta
91+
uses: docker/metadata-action@v5
92+
with:
93+
images: ${{ env.IMAGE_PREFIX }}/wemcp-celery
94+
tags: |
95+
type=ref,event=branch
96+
type=semver,pattern={{version}}
97+
type=semver,pattern={{major}}.{{minor}}
98+
type=sha,prefix=sha-,format=short
99+
100+
- name: Build and push (worker)
101+
uses: docker/build-push-action@v6
102+
with:
103+
context: ./backend
104+
file: ./backend/Dockerfile
105+
build-args: |
106+
SERVER_TYPE=celery
107+
push: true
108+
tags: ${{ steps.meta.outputs.tags }}
109+
labels: ${{ steps.meta.outputs.labels }}
110+
cache-from: type=gha,scope=backend-worker
111+
cache-to: type=gha,mode=max,scope=backend-worker
112+
113+
# ============================================================
114+
# Frontend: Next.js
115+
# ============================================================
116+
build-frontend:
117+
name: Build Frontend
118+
runs-on: ubuntu-latest
119+
permissions:
120+
contents: read
121+
packages: write
122+
123+
steps:
124+
- name: Checkout
125+
uses: actions/checkout@v4
126+
127+
- name: Set up Docker Buildx
128+
uses: docker/setup-buildx-action@v3
129+
130+
- name: Login to GHCR
131+
uses: docker/login-action@v3
132+
with:
133+
registry: ${{ env.REGISTRY }}
134+
username: ${{ github.actor }}
135+
password: ${{ secrets.GITHUB_TOKEN }}
136+
137+
# 前端 Dockerfile 会 COPY deploy/.env.production,需要提前写入
138+
- name: Write frontend .env.production
139+
run: |
140+
mkdir -p frontend/deploy
141+
echo "${{ secrets.FRONTEND_ENV_PRODUCTION }}" > frontend/deploy/.env.production
142+
143+
- name: Docker metadata (frontend)
144+
id: meta
145+
uses: docker/metadata-action@v5
146+
with:
147+
images: ${{ env.IMAGE_PREFIX }}/wemcp-frontend
148+
tags: |
149+
type=ref,event=branch
150+
type=semver,pattern={{version}}
151+
type=semver,pattern={{major}}.{{minor}}
152+
type=sha,prefix=sha-,format=short
153+
154+
- name: Build and push (frontend)
155+
uses: docker/build-push-action@v6
156+
with:
157+
context: ./frontend
158+
file: ./frontend/Dockerfile
159+
build-args: |
160+
COS_SECRET_ID=${{ secrets.COS_SECRET_ID }}
161+
COS_SECRET_KEY=${{ secrets.COS_SECRET_KEY }}
162+
COS_BUCKET=${{ secrets.COS_BUCKET }}
163+
COS_REGION=${{ secrets.COS_REGION }}
164+
push: true
165+
tags: ${{ steps.meta.outputs.tags }}
166+
labels: ${{ steps.meta.outputs.labels }}
167+
cache-from: type=gha,scope=frontend
168+
cache-to: type=gha,mode=max,scope=frontend

backend/.env.production

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Env: dev、pro
2+
ENVIRONMENT='dev'
3+
4+
# Database
5+
DATABASE_TYPE='mysql'
6+
DATABASE_HOST='wemcp_mysql'
7+
DATABASE_PORT=3306
8+
DATABASE_USER='root'
9+
DATABASE_PASSWORD='123456'
10+
11+
# Redis
12+
REDIS_HOST='wemcp_redis'
13+
REDIS_PORT=6379
14+
REDIS_PASSWORD=''
15+
REDIS_DATABASE=0
16+
17+
# secret
18+
TOKEN_SECRET_KEY='xxx'
19+
OPERA_LOG_ENCRYPT_SECRET_KEY='xxx'
20+
21+
# OAuth2
22+
OAUTH2_GITHUB_CLIENT_ID='xxx'
23+
OAUTH2_GITHUB_CLIENT_SECRET='xxx'
24+
OAUTH2_GITHUB_REDIRECT_URI='xxx'
25+
OAUTH2_FRONTEND_LOGIN_REDIRECT_URI='xxx'
26+
27+
# celery
28+
CELERY_BROKER_REDIS_DATABASE=1
29+
CELERY_TASK_MAX_RETRIES=5
30+
31+
# serverless
32+
SERVERLESS_PROVIDER='aliyun'
33+
SERVERLESS_ENDPOINT=xx
34+
SERVERLESS_ACCESS_KEY_ID=xxx
35+
SERVERLESS_ACCESS_KEY_SECRET=xxx
36+
37+
# email
38+
SMTP_HOST=smtp.xxx.com
39+
SMTP_PORT=465
40+
SMTP_USER=noreply@xxx.com
41+
SMTP_PASSWORD=xxx
42+
43+
# 后期在系统设置配置
44+
GITHUB_APP_ACCESS_TOKEN=xxx
45+
DASHSCOPE_API_KEY=sk-xxx

backend/=0.15.10

Whitespace-only changes.

backend/common/schema.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from datetime import datetime
44
from typing import Annotated, Any
55

6-
from pydantic import BaseModel, ConfigDict, EmailStr, Field, validate_email
6+
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_serializer, validate_email
77
from utils.timezone import timezone
88

99
CustomPhoneNumber = Annotated[str, Field(pattern=r'^1[3-9]\d{9}$')]
@@ -22,13 +22,18 @@ class SchemaBase(BaseModel):
2222

2323
model_config = ConfigDict(
2424
use_enum_values=True,
25-
json_encoders={
26-
datetime: lambda x: timezone.to_str(timezone.from_datetime(x))
27-
if x.tzinfo is not None and x.tzinfo != timezone.tz_info
28-
else timezone.to_str(x)
29-
},
3025
)
3126

27+
@field_serializer('*', when_used='json')
28+
def serialize_datetime(self, value):
29+
if isinstance(value, datetime):
30+
return (
31+
timezone.to_str(timezone.from_datetime(value))
32+
if value.tzinfo is not None and value.tzinfo != timezone.tz_info
33+
else timezone.to_str(value)
34+
)
35+
return value
36+
3237

3338
def ser_string(value: Any) -> str | None:
3439
if value:

backend/core/conf.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class Settings(BaseSettings):
9090

9191
# Token
9292
TOKEN_ALGORITHM: str = 'HS256'
93-
TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 # 1
93+
TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 3 # 3
9494
TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 7 天
9595
TOKEN_REDIS_PREFIX: str = 'wemcp:token'
9696
TOKEN_EXTRA_INFO_REDIS_PREFIX: str = 'wemcp:token_extra_info'
@@ -156,8 +156,7 @@ class Settings(BaseSettings):
156156
WS_NO_AUTH_MARKER: str = 'internal'
157157

158158
# CORS
159-
CORS_ALLOWED_ORIGINS: list[str] = [ # 末尾不带斜杠
160-
'http://127.0.0.1:8000',
159+
CORS_ALLOWED_ORIGINS: list[str] = [
161160
'http://127.0.0.1:3000',
162161
'http://localhost:3000',
163162
'https://www.wemcp.cn',

backend/core/registrar.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from starlette_context.middleware import ContextMiddleware
1616

1717
from backend import __version__
18-
from backend.common.cache.pubsub import cache_pubsub_manager
1918
from backend.common.exception.exception_handler import register_exception
2019
from backend.common.log import set_custom_logfile, setup_logging
2120
from backend.common.response.response_code import StandardResponseCode
@@ -54,12 +53,12 @@ async def register_init(app: FastAPI) -> AsyncGenerator[None, None]:
5453
create_task(OperaLogMiddleware.consumer())
5554

5655
# 启动缓存 Pub/Sub 监听器
57-
cache_pubsub_manager.start_listener()
56+
# cache_pubsub_manager.start_listener()
5857

5958
yield
6059

6160
# 停止缓存 Pub/Sub 监听器
62-
await cache_pubsub_manager.stop_listener()
61+
# await cache_pubsub_manager.stop_listener()
6362

6463
# 释放 snowflake 节点
6564
await snowflake.shutdown()

backend/pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ dependencies = [
2929
"fast-agent-mcp>=0.2.25",
3030
"fast-captcha>=0.3.2",
3131
"fastapi-pagination>=0.15.10",
32-
"fastapi[standard-no-fastapi-cloud-cli]>=0.116.1",
32+
"fastapi[standard-no-fastapi-cloud-cli]==0.129.0",
3333
"flower>=2.0.1",
3434
"gevent>=25.8.2",
3535
"granian>=2.5.1",
@@ -42,15 +42,15 @@ dependencies = [
4242
"psutil>=7.0.0",
4343
"psycopg[binary]>=3.2.9",
4444
"pwdlib>=0.2.1",
45-
"pydantic>=2.11.7",
45+
"pydantic==2.12.5",
4646
"pydantic-settings>=2.10.1",
4747
"pymysql>=1.1.1",
4848
"python-jose>=3.5.0",
4949
"python-socketio>=5.13.0",
5050
"redis[hiredis]>=6.4.0",
5151
"rtoml>=0.12.0",
5252
"sqlalchemy-crud-plus>=1.11.0",
53-
"sqlalchemy[asyncio]>=2.0.43",
53+
"sqlalchemy[asyncio]==2.0.46",
5454
"sqlparse>=0.5.3",
5555
"tenacity>=9.1.2",
5656
"user-agents>=2.2.0",
@@ -59,7 +59,6 @@ dependencies = [
5959
"agentscope==1.0.16",
6060
"aiomysql>=0.3.2",
6161
"agentscope-runtime>=1.0.5",
62-
"aiosqlite>=0.22.1",
6362
"ag-ui-protocol>=0.1.10",
6463
"starlette-context>=0.4.0",
6564
"pyrate-limiter>=4.0.2",

0 commit comments

Comments
 (0)