feat(dependencies): update database engine dependencies to support async operations
This commit is contained in:
@@ -6,7 +6,6 @@ from typing import Annotated
|
||||
|
||||
import httpx
|
||||
from fastapi import Depends, Request
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine
|
||||
|
||||
from python.ebook_search.config import EbookSearchConfig
|
||||
|
||||
@@ -16,16 +15,10 @@ def get_config(request: Request) -> EbookSearchConfig:
|
||||
return request.app.state.config
|
||||
|
||||
|
||||
def get_engine(request: Request) -> AsyncEngine:
|
||||
"""Get the database engine from app state."""
|
||||
return request.app.state.engine
|
||||
|
||||
|
||||
def get_http_client(request: Request) -> httpx.AsyncClient:
|
||||
"""Get the shared LLM HTTP client from app state."""
|
||||
return request.app.state.http_client
|
||||
|
||||
|
||||
AppConfig = Annotated[EbookSearchConfig, Depends(get_config)]
|
||||
AppEngine = Annotated[AsyncEngine, Depends(get_engine)]
|
||||
AppHttpClient = Annotated[httpx.AsyncClient, Depends(get_http_client)]
|
||||
|
||||
@@ -10,7 +10,6 @@ from fastapi.responses import HTMLResponse
|
||||
from python.ebook_search.api.bm25_tasks import schedule_bm25_refresh
|
||||
from python.ebook_search.api.dependencies import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
|
||||
AppConfig,
|
||||
AppEngine,
|
||||
AppHttpClient,
|
||||
)
|
||||
from python.ebook_search.api.web import error_response, templates
|
||||
@@ -19,7 +18,10 @@ from python.ebook_search.ingest import ingest_configured_paths
|
||||
from python.ebook_search.protected_phrases.generate_ngrams import generate_candidate_phrases_for_books
|
||||
from python.ebook_search.protected_phrases.judge_ngrams import judge_candidate_phrases_for_books
|
||||
from python.ebook_search.protected_phrases.store import book_ids_pending_first_judgment, corpus_phrase_stats
|
||||
from python.fastapi_tools import AsyncDbSession # noqa: TC001 FastAPI resolves this annotated dependency at runtime
|
||||
from python.fastapi_tools import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
|
||||
AppAsyncEngine,
|
||||
AsyncDbSession,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -59,7 +61,7 @@ async def scan_library(request: Request, config: AppConfig, session: AsyncDbSess
|
||||
|
||||
|
||||
@router.post("/phrases/generate-all", response_class=HTMLResponse)
|
||||
async def generate_all_phrases(request: Request, config: AppConfig, engine: AppEngine) -> HTMLResponse:
|
||||
async def generate_all_phrases(request: Request, config: AppConfig, engine: AppAsyncEngine) -> HTMLResponse:
|
||||
"""Regenerate candidate phrases for every indexed book without LLM judging."""
|
||||
try:
|
||||
result = await generate_candidate_phrases_for_books(engine, config)
|
||||
@@ -83,7 +85,7 @@ async def generate_all_phrases(request: Request, config: AppConfig, engine: AppE
|
||||
|
||||
|
||||
@router.post("/phrases/judge-all", response_class=HTMLResponse)
|
||||
async def judge_all_phrases(request: Request, engine: AppEngine, config: AppConfig) -> HTMLResponse:
|
||||
async def judge_all_phrases(request: Request, engine: AppAsyncEngine, config: AppConfig) -> HTMLResponse:
|
||||
"""Judge unjudged candidate phrases across every indexed book."""
|
||||
return await run_phrase_judgment(request, engine, config, source_ids=None)
|
||||
|
||||
@@ -91,7 +93,7 @@ async def judge_all_phrases(request: Request, engine: AppEngine, config: AppConf
|
||||
@router.post("/phrases/judge-missing", response_class=HTMLResponse)
|
||||
async def judge_missing_phrases(
|
||||
request: Request,
|
||||
engine: AppEngine,
|
||||
engine: AppAsyncEngine,
|
||||
config: AppConfig,
|
||||
session: AsyncDbSession,
|
||||
) -> HTMLResponse:
|
||||
@@ -108,7 +110,7 @@ async def judge_missing_phrases(
|
||||
|
||||
async def run_phrase_judgment(
|
||||
request: Request,
|
||||
engine: AppEngine,
|
||||
engine: AppAsyncEngine,
|
||||
config: AppConfig,
|
||||
*,
|
||||
source_ids: list[int] | None,
|
||||
@@ -117,7 +119,7 @@ async def run_phrase_judgment(
|
||||
|
||||
Args:
|
||||
request (Request): Current request, for template rendering.
|
||||
engine (AppEngine): Engine used to open per-book judging sessions.
|
||||
engine (AppAsyncEngine): Engine used to open per-book judging sessions.
|
||||
config (AppConfig): Runtime phrase-tuning settings.
|
||||
source_ids (list[int] | None): Books to judge; ``None`` judges every indexed book.
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ from fastapi.responses import HTMLResponse
|
||||
from python.ebook_search.answer import answer_query
|
||||
from python.ebook_search.api.dependencies import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
|
||||
AppConfig,
|
||||
AppEngine,
|
||||
AppHttpClient,
|
||||
)
|
||||
from python.ebook_search.api.web import error_response, templates
|
||||
@@ -25,6 +24,7 @@ from python.ebook_search.guardrails import (
|
||||
)
|
||||
from python.ebook_search.search import SearchResponse, search_ebooks
|
||||
from python.ebook_search.timing import runtime_step_from_start
|
||||
from python.fastapi_tools import AppAsyncEngine # noqa: TC001 FastAPI resolves this annotated dependency at runtime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import httpx
|
||||
@@ -76,7 +76,7 @@ async def build_answer(
|
||||
async def search(
|
||||
request: Request,
|
||||
config: AppConfig,
|
||||
engine: AppEngine,
|
||||
engine: AppAsyncEngine,
|
||||
client: AppHttpClient,
|
||||
query: Annotated[str, Form()],
|
||||
*,
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
"""Reusable FastAPI tools."""
|
||||
|
||||
from python.fastapi_tools.db import AsyncDbSession, DbSession, get_async_db, get_db
|
||||
from python.fastapi_tools.db import (
|
||||
AppAsyncEngine,
|
||||
AppEngine,
|
||||
AsyncDbSession,
|
||||
DbSession,
|
||||
get_async_db,
|
||||
get_async_engine,
|
||||
get_db,
|
||||
get_engine,
|
||||
)
|
||||
from python.fastapi_tools.zstd_middleware import ZstdMiddleware
|
||||
|
||||
__all__ = ["AsyncDbSession", "DbSession", "ZstdMiddleware", "get_async_db", "get_db"]
|
||||
__all__ = [
|
||||
"AppAsyncEngine",
|
||||
"AppEngine",
|
||||
"AsyncDbSession",
|
||||
"DbSession",
|
||||
"ZstdMiddleware",
|
||||
"get_async_db",
|
||||
"get_async_engine",
|
||||
"get_db",
|
||||
"get_engine",
|
||||
]
|
||||
|
||||
@@ -5,13 +5,24 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from fastapi import Depends, Request
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.engine import Engine
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import AsyncIterator, Iterator
|
||||
|
||||
|
||||
def get_engine(request: Request) -> Engine:
|
||||
"""Get a synchronous database engine from app state."""
|
||||
return request.app.state.engine
|
||||
|
||||
|
||||
def get_async_engine(request: Request) -> AsyncEngine:
|
||||
"""Get an asynchronous database engine from app state."""
|
||||
return request.app.state.engine
|
||||
|
||||
|
||||
def get_db(request: Request) -> Iterator[Session]:
|
||||
"""Get database session from app state."""
|
||||
with Session(request.app.state.engine) as session:
|
||||
@@ -28,5 +39,7 @@ async def get_async_db(request: Request) -> AsyncIterator[AsyncSession]:
|
||||
yield session
|
||||
|
||||
|
||||
AppEngine = Annotated[Engine, Depends(get_engine)]
|
||||
AppAsyncEngine = Annotated[AsyncEngine, Depends(get_async_engine)]
|
||||
DbSession = Annotated[Session, Depends(get_db)]
|
||||
AsyncDbSession = Annotated[AsyncSession, Depends(get_async_db)]
|
||||
|
||||
Reference in New Issue
Block a user