LS8's picture
Upload folder using huggingface_hub
329924a verified
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from src.api.deps import get_db
from src.api.schemas.ingest import BookInfo, StatsResponse
from src.core.llm import list_available_models
from src.core.vector_store import get_collection_count
from src.db.repository import delete_book, get_all_books, get_book_by_id, get_book_chunks, get_stats
router = APIRouter(prefix="/admin", tags=["Admin"])
@router.get("/stats", response_model=StatsResponse)
async def collection_stats(session: AsyncSession = Depends(get_db)):
"""Get overall collection statistics."""
stats = await get_stats(session)
stats["vector_store_count"] = get_collection_count()
return StatsResponse(**stats)
@router.get("/books", response_model=list[BookInfo])
async def list_books(session: AsyncSession = Depends(get_db)):
"""List all books in the collection."""
books = await get_all_books(session)
return [
BookInfo(
id=b.id,
title=b.title,
author=b.author,
publication_year=b.publication_year,
edition=b.edition,
ingestion_status=b.ingestion_status,
total_chunks=b.total_chunks,
source_file=b.source_file,
notes=b.notes,
)
for b in books
]
@router.get("/books/{book_id}", response_model=BookInfo)
async def get_book(book_id: str, session: AsyncSession = Depends(get_db)):
"""Get details of a specific book."""
book = await get_book_by_id(session, book_id)
if not book:
raise HTTPException(status_code=404, detail="Book not found")
return BookInfo(
id=book.id,
title=book.title,
author=book.author,
publication_year=book.publication_year,
edition=book.edition,
ingestion_status=book.ingestion_status,
total_chunks=book.total_chunks,
source_file=book.source_file,
)
@router.get("/books/{book_id}/fulltext")
async def get_book_fulltext(book_id: str, session: AsyncSession = Depends(get_db)):
"""Get the full reconstructed text of a book, organized by chapter."""
book = await get_book_by_id(session, book_id)
if not book:
raise HTTPException(status_code=404, detail="Book not found")
chunks = await get_book_chunks(session, book_id)
# Organize chunks into chapters
chapters: dict[str, list] = {}
for chunk in chunks:
chapter_key = chunk.chapter_title or (
f"Chapter {chunk.chapter_number}" if chunk.chapter_number else "Full Text"
)
if chapter_key not in chapters:
chapters[chapter_key] = []
chapters[chapter_key].append({
"text": chunk.content,
"page": chunk.page_start,
"chunk_index": chunk.chunk_index,
})
return {
"id": book.id,
"title": book.title,
"author": book.author,
"publication_year": book.publication_year,
"total_chunks": book.total_chunks,
"chapters": [
{
"title": ch_title,
"passages": passages,
}
for ch_title, passages in chapters.items()
],
}
@router.delete("/books/{book_id}")
async def remove_book(book_id: str, session: AsyncSession = Depends(get_db)):
"""Delete a book and all its chunks."""
from src.core.vector_store import delete_by_book_id
book = await get_book_by_id(session, book_id)
if not book:
raise HTTPException(status_code=404, detail="Book not found")
# Remove from vector store
delete_by_book_id(book_id)
# Remove from SQLite
await delete_book(session, book_id)
return {"message": f"Book '{book.title}' deleted successfully"}
@router.get("/models", response_model=list[str])
async def available_models():
"""List available LLM models."""
return list_available_models()