Files
Rain-Bus 21f16e6756 feat: refactor summarizer and PDF extraction pipeline
- Split summarizer into summary_generator and summary_persister modules
- Refactor pdf_image_extractor to two-phase pipeline with PicoDet layout detection
- Add layout_detector service for PicoDet-S_layout_3cls integration
- Add exceptions module with ConflictError and NotFoundError
- Improve admin dashboard with better statistics and task management
- Add design review document with system optimization suggestions
- Add new tests for crawler, pdf_downloader, pipeline, and summary_utils
- Update dependencies and configuration
- Clean up dead code and improve error handling
2026-06-13 13:16:47 +08:00

86 lines
2.8 KiB
Python

"""用户数据 JSON API — 收藏、阅读状态、笔记。"""
from __future__ import annotations
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.database import get_db
from app.exceptions import NotFoundError
from app.services.user_data import (
get_note,
save_note,
set_reading_status,
toggle_bookmark,
)
router = APIRouter(prefix="/api", tags=["user-data"])
# ── 请求模型 ──────────────────────────────────────────────────────────
class ReadingStatusRequest(BaseModel):
status: str
class NoteRequest(BaseModel):
content: str
# ── 收藏 ──────────────────────────────────────────────────────────────
@router.post("/bookmark/{arxiv_id}")
def bookmark_toggle(arxiv_id: str, request: Request, db: Session = Depends(get_db)):
"""切换收藏状态。支持 HTMX 局部刷新和 JSON 响应。"""
result = toggle_bookmark(db, arxiv_id)
# HTMX 请求 → 返回 HTML 片段
if request.headers.get("HX-Request"):
star = "" if result["bookmarked"] else ""
active_class = " active" if result["bookmarked"] else ""
html = (
f'<button class="btn-bookmark{active_class}" '
f'hx-post="/api/bookmark/{arxiv_id}" '
f'hx-target="#user-data-{arxiv_id}" '
f'hx-swap="outerHTML">'
f"{star}</button>"
)
return HTMLResponse(content=html)
return result
# ── 阅读状态 ──────────────────────────────────────────────────────────
@router.post("/reading-status/{arxiv_id}")
def reading_status_update(
arxiv_id: str,
body: ReadingStatusRequest,
db: Session = Depends(get_db),
):
"""更新阅读状态。"""
return set_reading_status(db, arxiv_id, body.status)
# ── 笔记 ──────────────────────────────────────────────────────────────
@router.get("/note/{arxiv_id}")
def note_get(arxiv_id: str, db: Session = Depends(get_db)):
"""获取笔记。"""
result = get_note(db, arxiv_id)
if result is None:
raise NotFoundError(f"Paper not found: {arxiv_id}")
return result
@router.post("/note/{arxiv_id}")
def note_save(arxiv_id: str, body: NoteRequest, db: Session = Depends(get_db)):
"""保存笔记。"""
return save_note(db, arxiv_id, body.content)