mirror of
https://github.com/lfnovo/open-notebook.git
synced 2026-10-14 21:59:13 +00:00
* fix(podcasts): restore the language instruction and stop the prompts handing the model a copyable skeleton (#1238) Two independent defects in prompts/podcast/*.jinja, plus the failure hints that made both of them hard to diagnose. Split out of #1239 at review request; the voice pre-flight from that PR stays there. Language -------- These templates shadow podcast-creator's bundled ones - the library resolves Path.cwd()/prompts/podcast/<name>.jinja before its own package resources, and this app configures only profiles - and the app's copies never referenced `{{ language }}`. The value is plumbed correctly end to end, so an episode profile set to he-IL produced an English outline and English segment titles: EpisodeProfile.language looked supported and did nothing. The bundled block is restored in both templates, and a regression test fails when a variable the bundled template uses is missing from the app's copy - the drift that lost it in the first place. Copyable skeleton ----------------- Both templates showed a fill-in JSON skeleton (`"speaker": "[Actual Speaker Name]"`, a bare `...`) inside a ```json fence while also instructing the model not to use fences. Models returned the skeleton verbatim, which failed podcast-creator's speaker-name validation and aborted the episode - discarding the outline and every segment already generated. The example now carries the episode's real speaker names (serialized with tojson, so a name containing a quote can't break it) and written-out sample values, so a verbatim copy is valid output. Placeholders and truncation are banned explicitly, the contradictory fence and the second copyable example are gone, and the example is labelled a two-entry excerpt that restates the required turns/num_segments count so it can't read as a finished answer. No sample is rendered at all when a language is set: any hard-coded sample is English, and a copied English line in a Hebrew episode goes straight to TTS. The structure is stated in prose there, and format_instructions still carries the schema. Hints ----- explain_generation_failure() maps a failure to the hint that fits it. The GPT-5 extended-thinking note was the only one, keyed on `Invalid json output` / `Expecting value`, so `Invalid speaker name` got nothing and a truncated Gemini response was advised to switch to gpt-4o. Placeholder speaker names, unusable voices and truncated output now each get their own explanation. * fix(podcasts): make the failure hints reachable and scope the not-found one (#1238) Review follow-ups on this PR. - The hint mapper never ran for the failures it was written for. `except ValueError: raise` sits ahead of the handler that attaches hints, and both LangChain's OutputParserException and json.JSONDecodeError are ValueError subclasses - so a placeholder speaker name, `Invalid json output` and a truncated response all left untouched. That includes the pre-existing GPT-5 extended-thinking note, which has been dead for exactly the case it describes. The ValueError branch now attaches the hint and re-raises a ValueError, keeping the command layer's permanent-failure contract intact. - `Requested entity was not found` no longer claims the voice is at fault. Google returns it for any missing resource, including a model id on the outline or transcript call, so the hint now names both candidates and says which is likelier when audio had already started. The voice-specific hint stays keyed on `Voice name ... is not supported`, which does name the voice. - A solo speaker profile renders a one-entry example; the prose called it a two-entry excerpt and told the model to return more than "the two shown". Both now follow speakers|length. - The template drift check counted Jinja's `not` as a variable, so `{% if not language %}` would fail the check the moment one template negated a test the other didn't. * chore(podcasts): rebase on main, ruff format, update the truncation hint - Rebased onto main (CHANGELOG conflict). - tests/test_podcast_prompt_templates.py formatted with ruff (CI now gates ruff format, #1429). - The truncated-JSON hint quoted podcast-creator's old 5000-token transcript cap; since 0.13 (#1446) outline and transcript request up to 8192, so the hint now says to set max_tokens to the model's limit when it stops earlier. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy * fix(podcasts): keep the JSON contract in English; English keeps the sample - The language instruction now says the JSON keys (and outline size values, transcript speaker names) stay exactly as written, so a non-English run can't translate them and fail validation. - English locales resolve to "English"; they keep the (English) sample. - The drift check uses jinja2.meta, so variables used only as `for` iterables count too. - Docs: solo transcript excerpts are one-entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy * docs(podcasts): the excerpt's entries are reusable, the excerpt is not a full answer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBYpxzSS62Y3TZkgB9NUZy --------- Co-authored-by: Yehuda Korotkin <yehuda.korotkin@ness-tech.co.il> Co-authored-by: Luis Novo <lfnovo@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| ask | ||
| chat | ||
| pattern | ||
| podcast | ||
| source_chat | ||
| transformation | ||