Files
Story-extractor/backend/app/api/files.py
2026-04-24 16:02:16 +08:00

137 lines
4.4 KiB
Python

import os
import uuid
from typing import Annotated
from fastapi import APIRouter, UploadFile, File, HTTPException, Depends
from fastapi.responses import FileResponse
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete
from app.database import get_db
from app.models.transcript import Transcript
from app.models.person import Person
from app.schemas.schemas import TranscriptOut, PersonOut
from app.services.file_service import file_service
from app.services.docx_parser import parse_transcript, parse_person_info
router = APIRouter(prefix="/files", tags=["文件管理"])
# ===== 文字稿 =====
@router.post("/transcripts", response_model=list[TranscriptOut])
async def upload_transcripts(files: list[UploadFile], db: Annotated[AsyncSession, Depends(get_db)]):
"""批量上传文字稿"""
results = []
for file in files:
if not file.filename.endswith(".docx"):
raise HTTPException(400, f"仅支持 .docx 格式: {file.filename}")
saved = await file_service.save_transcript(file)
# 解析行数
paragraphs = parse_transcript(saved["file_path"])
line_count = len(paragraphs)
record = Transcript(
id=saved["id"],
filename=saved["filename"],
file_path=saved["file_path"],
line_count=line_count,
file_size=saved["file_size"],
status="pending",
)
db.add(record)
results.append(record)
await db.commit()
for r in results:
await db.refresh(r)
return results
@router.get("/transcripts", response_model=list[TranscriptOut])
async def list_transcripts(db: Annotated[AsyncSession, Depends(get_db)]):
"""获取文字稿列表"""
result = await db.execute(select(Transcript).order_by(Transcript.uploaded_at.desc()))
return result.scalars().all()
@router.delete("/transcripts/{transcript_id}")
async def delete_transcript(transcript_id: str, db: Annotated[AsyncSession, Depends(get_db)]):
"""删除文字稿"""
record = await db.get(Transcript, transcript_id)
if not record:
raise HTTPException(404, "文字稿不存在")
file_service.delete_file(record.file_path)
await db.delete(record)
await db.commit()
return {"message": "已删除"}
# ===== 讲述者信息 =====
@router.post("/persons", response_model=list[PersonOut])
async def upload_persons(files: list[UploadFile], db: Annotated[AsyncSession, Depends(get_db)]):
"""批量上传讲述者信息"""
results = []
for file in files:
if not file.filename.endswith(".docx"):
raise HTTPException(400, f"仅支持 .docx 格式: {file.filename}")
saved = await file_service.save_person(file)
# 解析个人信息
info = parse_person_info(saved["file_path"])
record = Person(
id=saved["id"],
name=info["name"],
filename=saved["filename"],
file_path=saved["file_path"],
photo_path=info["photos"][0] if info["photos"] else "",
info=info["info_text"],
)
db.add(record)
results.append(record)
await db.commit()
for r in results:
await db.refresh(r)
return results
@router.get("/persons", response_model=list[PersonOut])
async def list_persons(db: Annotated[AsyncSession, Depends(get_db)]):
"""获取讲述者列表"""
result = await db.execute(select(Person).order_by(Person.uploaded_at.desc()))
return result.scalars().all()
@router.delete("/persons/{person_id}")
async def delete_person(person_id: str, db: Annotated[AsyncSession, Depends(get_db)]):
"""删除讲述者信息"""
record = await db.get(Person, person_id)
if not record:
raise HTTPException(404, "讲述者不存在")
file_service.delete_file(record.file_path)
if record.photo_path:
file_service.delete_file(record.photo_path)
await db.delete(record)
await db.commit()
return {"message": "已删除"}
@router.get("/persons/{person_id}/preview")
async def preview_person(person_id: str, db: Annotated[AsyncSession, Depends(get_db)]):
"""预览讲述者信息"""
record = await db.get(Person, person_id)
if not record:
raise HTTPException(404, "讲述者不存在")
return {
"id": record.id,
"name": record.name,
"nickname": record.nickname,
"info": record.info,
"photo_path": record.photo_path,
}