Skip to content

Commit 35c8217

Browse files
feat: add v3 API using AwslBlobV2 table
Add new v3 API endpoints that query AwslBlobV2 table directly without CDN URL replacement. Also upgrade dependencies and simplify docker requirements. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 196f65b commit 35c8217

File tree

8 files changed

+128
-18
lines changed

8 files changed

+128
-18
lines changed

docker/dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM python:3.13-slim
22

3-
COPY requirements.docker.txt requirements.txt
3+
COPY requirements.txt requirements.txt
44
RUN python3 -m pip install -r requirements.txt
55

66
COPY . /app

main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from src.awsl_producers import router as producer_router
99
from src.awsl_blob import router as blob_router
10+
from src.awsl_blob_v3 import router as blob_v3_router
1011
from src.awsl_pic import router as pic_router
1112
from src.health_check import router as health_check_router
1213

@@ -36,6 +37,7 @@ def filter(self, record: logging.LogRecord) -> bool:
3637

3738
app.include_router(producer_router, prefix="")
3839
app.include_router(blob_router, prefix="")
40+
app.include_router(blob_v3_router, prefix="")
3941
app.include_router(pic_router, prefix="")
4042
app.include_router(health_check_router, prefix="")
4143

requirements.docker.txt

Lines changed: 0 additions & 7 deletions
This file was deleted.

requirements.txt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
fastapi==0.116.1
2-
fastapi-cli==0.0.8
3-
mysql-connector-python==9.4.0
4-
pydantic==2.11.7
5-
pydantic-settings==2.10.1
6-
pydantic_core==2.33.2
7-
requests==2.32.4
8-
SQLAlchemy==2.0.41
1+
fastapi==0.124.4
2+
mysql-connector-python==9.5.0
3+
pydantic==2.12.5
4+
pydantic-settings==2.12.0
5+
requests==2.32.5
6+
SQLAlchemy==2.0.45
7+
uvicorn==0.38.0

src/awsl_blob_v3.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import logging
2+
3+
from typing import List, Optional
4+
from fastapi import APIRouter
5+
from fastapi.responses import JSONResponse
6+
7+
from .response_models import BlobItem, Message
8+
from src.db.base import DBClientBase
9+
10+
router = APIRouter()
11+
_logger = logging.getLogger(__name__)
12+
13+
14+
@router.get("/v3/list", response_model=List[BlobItem], responses={404: {"model": Message}}, tags=["AwslV3"])
15+
def awsl_v3_list(uid: Optional[str] = "", limit: Optional[int] = 10, offset: Optional[int] = 0):
16+
if limit > 1000:
17+
return JSONResponse(
18+
status_code=404,
19+
content=Message(message="to large limit = {}".format(limit))
20+
)
21+
return DBClientBase.get_client().awsl_v3_list(uid, limit, offset)
22+
23+
24+
@router.get("/v3/list_count", response_model=int, tags=["AwslV3"])
25+
def awsl_v3_list_count(uid: Optional[str] = "") -> int:
26+
return DBClientBase.get_client().awsl_v3_list_count(uid)
27+
28+
29+
@router.get("/v3/random", response_model=str, tags=["AwslV3"])
30+
def awsl_v3_random(uid: Optional[str] = "") -> str:
31+
return DBClientBase.get_client().awsl_v3_random(uid)
32+
33+
34+
@router.get("/v3/random_json", response_model=BlobItem, tags=["AwslV3"])
35+
def awsl_v3_random_json(uid: Optional[str] = "") -> BlobItem:
36+
return DBClientBase.get_client().awsl_v3_random_json(uid)

src/db/base.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,20 @@ def awsl_pic_random(cls, uid: str) -> str:
7979
@classmethod
8080
def awsl_pic_random_json(cls, uid: str) -> str:
8181
...
82+
83+
# V3 API methods using AwslBlobV2
84+
@classmethod
85+
def awsl_v3_list(cls, uid: str, limit: int, offset: int) -> List[BlobItem]:
86+
...
87+
88+
@classmethod
89+
def awsl_v3_list_count(cls, uid: str) -> int:
90+
...
91+
92+
@classmethod
93+
def awsl_v3_random(cls, uid: str) -> str:
94+
...
95+
96+
@classmethod
97+
def awsl_v3_random_json(cls, uid: str) -> BlobItem:
98+
...

src/db/mysql_provider.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from sqlalchemy.orm import sessionmaker
88

99
from config import WB_URL_PREFIX, settings
10-
from src.models.models import AwslBlob, AwslProducer, Mblog, Pic
10+
from src.models.models import AwslBlob, AwslBlobV2, AwslProducer, Mblog, Pic
1111
from src.models.pydantic_models import Blob, Blobs
1212
from src.response_models import BlobItem, PicInfo, ProducerItem, ProducerRes
1313

@@ -257,3 +257,66 @@ def awsl_pic_random_json(cls, uid: str) -> str:
257257
pic_id=blob.pic_id,
258258
pic_info=PicInfo.model_validate_json(blob.pic_info).root
259259
)
260+
261+
# V3 API methods using AwslBlobV2
262+
@classmethod
263+
def awsl_v3_list(cls, uid: str, limit: int, offset: int) -> List[BlobItem]:
264+
with cls.DBSession() as session:
265+
blobs = session.query(AwslBlobV2).join(
266+
Mblog, AwslBlobV2.awsl_id == Mblog.id
267+
).filter(
268+
Mblog.uid == uid
269+
).order_by(
270+
AwslBlobV2.awsl_id.desc()
271+
).limit(limit).offset(offset).all() if uid else session.query(
272+
AwslBlobV2
273+
).join(
274+
Mblog, AwslBlobV2.awsl_id == Mblog.id
275+
).order_by(
276+
AwslBlobV2.awsl_id.desc()
277+
).limit(limit).offset(offset).all()
278+
res = [BlobItem(
279+
wb_url=WB_URL_PREFIX.format(
280+
blob.awsl_mblog.re_user_id, blob.awsl_mblog.re_mblogid),
281+
pic_id=blob.pic_id,
282+
pic_info=Blobs.model_validate_json(blob.pic_info).blobs
283+
) for blob in blobs if blob.awsl_mblog]
284+
return res
285+
286+
@classmethod
287+
def awsl_v3_list_count(cls, uid: str) -> int:
288+
with cls.DBSession() as session:
289+
res = session.query(func.count(AwslBlobV2.id)).join(Mblog, AwslBlobV2.awsl_id == Mblog.id).filter(
290+
Mblog.uid == uid
291+
).one() if uid else session.query(func.count(AwslBlobV2.id)).one()
292+
return int(res[0]) if res else 0
293+
294+
@classmethod
295+
def awsl_v3_random(cls, uid: str) -> str:
296+
with cls.DBSession() as session:
297+
blob = session.query(AwslBlobV2).join(Mblog, AwslBlobV2.awsl_id == Mblog.id).filter(
298+
Mblog.uid == uid
299+
).order_by(
300+
func.rand()
301+
).limit(1).one() if uid else session.query(AwslBlobV2).order_by(
302+
func.rand()
303+
).limit(1).one()
304+
url_dict = Blobs.model_validate_json(blob.pic_info).blobs
305+
return url_dict["original"].url
306+
307+
@classmethod
308+
def awsl_v3_random_json(cls, uid: str) -> BlobItem:
309+
with cls.DBSession() as session:
310+
blob = session.query(AwslBlobV2).join(Mblog, AwslBlobV2.awsl_id == Mblog.id).filter(
311+
Mblog.uid == uid
312+
).order_by(
313+
func.rand()
314+
).limit(1).one() if uid else session.query(AwslBlobV2).order_by(
315+
func.rand()
316+
).limit(1).one()
317+
return BlobItem(
318+
wb_url=WB_URL_PREFIX.format(
319+
blob.awsl_mblog.re_user_id, blob.awsl_mblog.re_mblogid),
320+
pic_id=blob.pic_id,
321+
pic_info=Blobs.model_validate_json(blob.pic_info).blobs
322+
)

src/models

0 commit comments

Comments
 (0)