Spaces:
Sleeping
Sleeping
| 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"]) | |
| 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) | |
| 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 | |
| ] | |
| 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, | |
| ) | |
| 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() | |
| ], | |
| } | |
| 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"} | |
| async def available_models(): | |
| """List available LLM models.""" | |
| return list_available_models() | |