Spaces:
Restarting
Restarting
| """Backtest book URL metadata fetch across all supported platforms.""" | |
| from __future__ import annotations | |
| import asyncio | |
| import json | |
| import sys | |
| from dataclasses import asdict | |
| # Core fields expected for a "complete" import preview | |
| CORE_FIELDS = ("title", "author", "description", "genre", "cover_url") | |
| EXTRA_FIELDS = ("about_author", "isbn", "publisher", "publish_year", "page_count", "language") | |
| TEST_URLS: dict[str, str] = { | |
| "amazon": "https://www.amazon.com/dp/0593128257", | |
| "barnes_noble": "https://www.barnesandnoble.com/w/james-percival-everett/1143678734?ean=9780385550369", | |
| "goodreads": "https://www.goodreads.com/book/show/4671.The_Great_Gatsby", | |
| "google_books": "https://books.google.com/books/about/Project_Hail_Mary.html?id=GrYsEAAAQBAJ", | |
| "apple_books": "https://books.apple.com/us/book/fang-fiction/id6475274221", | |
| "kobo": "https://www.kobo.com/ca/en/ebook/project-hail-mary-9780593135204", | |
| "thriftbooks": "https://www.thriftbooks.com/w/1q84_haruki-murakami/252010/", | |
| "abebooks": "https://www.abebooks.com/products/isbn/9780593135204", | |
| "worldcat": "https://search.worldcat.org/search?q=bn:9780593135204", | |
| "open_library": "https://openlibrary.org/works/OL268236W/The_Cat_Who_Went_to_Heaven", | |
| "bookshop": "https://bookshop.org/p/books/1q84-haruki-murakami/525d944c7585381e?ean=9780307476463", | |
| "lulu": "https://www.lulu.com/shop/brett-arquette/operation-hail-storm/paperback/product-22895695.html", | |
| "walmart": "https://www.walmart.com/ip/Winternight-Trilogy-The-Bear-and-the-Nightingale-Book-1-Hardcover-9781101885932/53596259", | |
| "waterstones": "https://www.waterstones.com/book/9780575077331", | |
| "booksamillion": "https://www.booksamillion.com/p/Three-Body-Problem/Cixin-Liu/9780765382030", | |
| "powells": "https://www.powells.com/book/project-hail-mary-9780593135204", | |
| "indigo": "https://www.indigo.ca/en-ca/project-hail-mary-a-novel/9780593135204.html", | |
| } | |
| def _field_ok(name: str, value) -> bool: | |
| if name == "description": | |
| return bool(value) and len(str(value)) >= 40 | |
| if name == "about_author": | |
| return bool(value) and len(str(value)) >= 50 | |
| if name == "page_count": | |
| return int(value or 0) > 0 | |
| return bool(value) | |
| async def main() -> int: | |
| from app.services.book_url_scraper import fetch_book_metadata, detect_platform | |
| results = [] | |
| for platform, url in TEST_URLS.items(): | |
| detected = detect_platform(url) | |
| meta = await fetch_book_metadata(url, force_refresh=True) | |
| row = { | |
| "platform": platform, | |
| "detected": detected, | |
| "url": url, | |
| "confidence": meta.confidence, | |
| "error": meta.error, | |
| "warnings": meta.warnings, | |
| "fields": {}, | |
| "missing_core": [], | |
| "missing_extra": [], | |
| } | |
| d = asdict(meta) | |
| for f in CORE_FIELDS + EXTRA_FIELDS: | |
| val = d.get(f, "") | |
| if f == "page_count": | |
| display = val if val else "" | |
| else: | |
| display = (str(val)[:60] + "...") if len(str(val)) > 60 else val | |
| row["fields"][f] = {"ok": _field_ok(f, val), "value": display} | |
| row["missing_core"] = [f for f in CORE_FIELDS if not row["fields"][f]["ok"]] | |
| row["missing_extra"] = [f for f in EXTRA_FIELDS if not row["fields"][f]["ok"]] | |
| row["perfect"] = not row["missing_core"] and not row["error"] | |
| results.append(row) | |
| # Print summary table | |
| print("\n" + "=" * 100) | |
| print("BOOK URL METADATA BACKTEST") | |
| print("=" * 100) | |
| perfect = sum(1 for r in results if r["perfect"]) | |
| print(f"\nPerfect (all core fields): {perfect}/{len(results)}\n") | |
| for r in results: | |
| status = "PASS" if r["perfect"] else "FAIL" | |
| print(f"[{status}] {r['platform']:15} conf={r['confidence']:.2f} detected={r['detected']}") | |
| print(f" title: {ascii(r['fields']['title']['value'])}") | |
| print(f" author: {ascii(r['fields']['author']['value'])}") | |
| if r["missing_core"]: | |
| print(f" MISSING CORE: {', '.join(r['missing_core'])}") | |
| if r["missing_extra"]: | |
| print(f" missing extra: {', '.join(r['missing_extra'])}") | |
| if r["error"]: | |
| print(f" ERROR: {r['error']}") | |
| print() | |
| out_path = "scripts/backtest_book_urls_results.json" | |
| with open(out_path, "w", encoding="utf-8") as f: | |
| json.dump(results, f, indent=2) | |
| print(f"Full results written to {out_path}") | |
| return 0 if perfect == len(results) else 1 | |
| if __name__ == "__main__": | |
| sys.path.insert(0, ".") | |
| raise SystemExit(asyncio.run(main())) | |