Photo-based book cataloger with AI identification. Room → Cabinet → Shelf → Book hierarchy; FastAPI + SQLite backend; vanilla JS SPA; OpenAI-compatible plugin system for boundary detection, text recognition, and archive search.
53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
"""Archive search plugin runner."""
|
|
|
|
import json
|
|
|
|
import db
|
|
from errors import BookNotFoundError
|
|
from models import ArchiveSearcherPlugin, BookRow, CandidateRecord
|
|
from logic.identification import build_query
|
|
|
|
|
|
def run_archive_searcher(plugin: ArchiveSearcherPlugin, book_id: str) -> BookRow:
|
|
"""Run an archive search for a book and merge results into the candidates list.
|
|
|
|
Args:
|
|
plugin: The archive searcher plugin to execute.
|
|
book_id: ID of the book to search for.
|
|
|
|
Returns:
|
|
Updated BookRow after merging search results.
|
|
|
|
Raises:
|
|
BookNotFoundError: If book_id does not exist.
|
|
"""
|
|
with db.transaction() as c:
|
|
book = db.get_book(c, book_id)
|
|
if not book:
|
|
raise BookNotFoundError(book_id)
|
|
query = build_query(book)
|
|
if not query:
|
|
return book
|
|
results: list[CandidateRecord] = plugin.search(query)
|
|
existing: list[CandidateRecord] = json.loads(book.candidates or "[]")
|
|
existing = [cd for cd in existing if cd.get("source") != plugin.plugin_id]
|
|
existing.extend(results)
|
|
db.set_book_candidates(c, book_id, json.dumps(existing))
|
|
updated = db.get_book(c, book_id)
|
|
if not updated:
|
|
raise BookNotFoundError(book_id)
|
|
return updated
|
|
|
|
|
|
def run_archive_searcher_bg(plugin: ArchiveSearcherPlugin, book_id: str) -> None:
|
|
"""Run an archive search in fire-and-forget mode; all exceptions are suppressed.
|
|
|
|
Args:
|
|
plugin: The archive searcher plugin to execute.
|
|
book_id: ID of the book to search for.
|
|
"""
|
|
try:
|
|
run_archive_searcher(plugin, book_id)
|
|
except Exception:
|
|
pass
|