open-notebook/api/routers
Luis Novo ef5bd2ce7b
feat(sources): add Crawl4AI URL engine + honor persisted engine settings (#432) (#1118)
* feat(sources): add Crawl4AI URL engine and honor persisted engine settings (#432)

- Add "crawl4ai" as a selectable URL processing engine (domain Literal,
  settings API validation, SettingsForm select, and label across all 14
  locales; urlHelp updated in en-US to describe the new fallback chain).
- The source graph now loads the persisted ContentSettings and passes the
  document/URL engine choices to ContentCoreConfig. Previously it built a
  hard-coded ContentSettings with "auto" engines, so a user's selection in
  Settings never took effect. Falls back to defaults if settings can't load.
- Crawl4AI Docker mode is driven by content-core's native CRAWL4AI_API_URL
  env var (documented separately under #1105).

Part of #939.

* fix(432): bundle Crawl4AI runtime + address review

- Bundle the Crawl4AI runtime so its local, no-API-key mode works out of
  the box: depend on content-core[crawl4ai] and install the Chromium
  browser via playwright in the Docker runtime-base (both image variants).
  Footprint is modest (no torch/transformers/CUDA); image grows ~300 MB
  from Chromium + system libs.
- Preserve the server-side traceback when persisted content settings fail
  to load (logger.opt(exception=True)) instead of only the message.
- Reset the ContentSettings singleton between domain tests (clear_instance)
  so a non-default value can't leak into neighboring tests.

Addresses review on #432.

* i18n(432): translate urlHelp Crawl4AI description across all 13 non-en locales

The Crawl4AI engine label was already localized; this brings the URL-engine
'help me choose' text in line with en-US in every locale — describing
Crawl4AI (local JS rendering, no API key) and its place in the auto
fallback chain (Firecrawl -> Jina -> Crawl4AI -> simple).
2026-07-12 20:05:03 -03:00
..
__init__.py Api podcast migration (#93) 2025-07-17 08:36:11 -03:00
_chat_shared.py refactor(api): extract shared session and message helpers for chat routers (#1072) 2026-07-11 19:01:47 -03:00
auth.py feat: credential-based API key management (#477) (#540) 2026-02-10 08:30:22 -03:00
chat.py refactor(api): single context-building implementation (#1079) 2026-07-11 19:55:46 -03:00
commands.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
config.py chore(lint): re-enable F401/F841/E722 and fix fallout (#1062) 2026-07-11 18:36:04 -03:00
credentials.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
embedding.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
embedding_rebuild.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
episode_profiles.py chore(podcasts): drop legacy provider/model string fields from podcast profiles (#1107) (#1112) 2026-07-12 14:35:04 -03:00
insights.py fix(insights): stamp created/updated on source_insight and stop serializing "None" (#1085) 2026-07-12 11:05:51 -03:00
languages.py feat(podcasts): model registry integration, credential passthrough & new features (#632) 2026-02-27 11:06:47 -03:00
models.py fix(models): allow clearing optional model defaults (#1097) 2026-07-12 09:47:17 -03:00
notebooks.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
notes.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
podcasts.py fix(podcasts): render EpisodeCard model details from resolved model references (#1115) 2026-07-12 14:57:54 -03:00
providers.py refactor(ai): single provider registry as the backend source of truth (#1075) 2026-07-11 19:21:36 -03:00
search.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
settings.py feat(sources): add Crawl4AI URL engine + honor persisted engine settings (#432) (#1118) 2026-07-12 20:05:03 -03:00
source_chat.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
sources.py fix(sources): reject unsupported uploads at ingestion with 415 (#975) (#1117) 2026-07-12 18:59:59 -03:00
speaker_profiles.py chore(podcasts): drop legacy provider/model string fields from podcast profiles (#1107) (#1112) 2026-07-12 14:35:04 -03:00
transformations.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00