from dialoghelper.core import *
from solveit_dmtools import * # core, dhb, dhp, fab
import solveit_dmtools # This will be just for the next cell to print the versionsolveit_dmtools
Usage and examples
print(solveit_dmtools.__version__); del solveit_dmtools0.0.30
TL;DR:
| module | what it gives you | try |
|---|---|---|
dhb |
chat with any LiteLLM model you have a key for | bc = dhb.c('gemini/gemini-flash-lite-latest'); bc("hi") |
dhp |
Polya’s four stages as one-liners that write prompt cells | dhp.help(), dhp.u.summary() |
fab |
200+ open-source fabric prompts | fab.p.summarize() |
Full docs for each module are on its own page; await add_msg(modulename.doc, msg_type='note') prints more details in a cell if you’d rather stay here.
dhb - Backup Chat for SolveIt
First calling with no model will prompt you to type in part of a model name to search
dhb.c() # `dhb.c()` with no model prompts you for a substring and lists matching modelsPlease try again by using e.g. `bc = dhb.c('model_name')` with a model name e.g. pick from these found by searching for 'gemini/gem':
gemini/gemini-live-2.5-flash-preview-native-audio-09-2025
gemini/gemini-robotics-er-1.5-preview
gemini/gemini-robotics-er-2-preview
gemini/gemini-robotics-er-1.6-preview
gemini/gemini-embedding-001
gemini/gemini-embedding-2-preview
gemini/gemini-embedding-2
gemini/gemini-1.5-flash
gemini/gemini-2.0-flash
gemini/gemini-2.0-flash-001
gemini/gemini-2.0-flash-lite
gemini/gemini-2.5-flash
gemini/gemini-2.5-flash-image
gemini/gemini-3-pro-image
gemini/gemini-3-pro-image-preview
gemini/gemini-3.1-flash-image
gemini/gemini-3.1-flash-image-preview
gemini/gemini-2.5-flash-lite
gemini/gemini-2.5-flash-lite-preview-09-2025
gemini/gemini-2.5-flash-preview-09-2025
gemini/gemini-flash-latest
gemini/gemini-flash-lite-latest
gemini/gemini-2.5-flash-lite-preview-06-17
gemini/gemini-2.5-flash-preview-tts
gemini/gemini-2.5-pro
gemini/gemini-2.5-computer-use-preview-10-2025
gemini/gemini-3-pro-preview
gemini/gemini-3.1-flash-lite-preview
gemini/gemini-3.1-flash-lite
gemini/gemini-3.5-flash-lite
gemini/gemini-3-flash-preview
gemini/gemini-3.5-flash
gemini/gemini-3.6-flash
gemini/gemini-omni-flash-preview
gemini/gemini-3.1-pro-preview
gemini/gemini-3.1-pro-preview-customtools
gemini/gemini-2.5-pro-preview-tts
gemini/gemini-exp-1114
gemini/gemini-exp-1206
gemini/gemini-gemma-2-27b-it
gemini/gemini-gemma-2-9b-it
gemini/gemma-3-27b-it
gemini/gemini-2.0-flash-exp-image-generation
gemini/gemini-2.0-flash-lite-001
gemini/gemini-2.5-flash-native-audio-latest
gemini/gemini-2.5-flash-native-audio-preview-09-2025
gemini/gemini-2.5-flash-native-audio-preview-12-2025
gemini/gemini-3.1-flash-live-preview
gemini/gemini-pro-latest
### The following ones are listed by OpenRouter but not LiteLLM (may still work)
<solveit_dmtools.dhb.BackupChat>
bc = dhb.c("openrouter/openai/gpt-5.2-codex")
# bc = dhb.c("openrouter/moonshotai/kimi-k2.5")The following will be automatically commented out when run, then a prompt cell is added after it with input/output from the other LLM.
bc("Hi, can you use tools?")Yes—I can use the available tools (e.g., read_url), but I’ll ask for confirmation before accessing any URLs. What would you like to do?
- id:
gen-1786095705-Y8KGvpeB6uBr8yLeAjp2 - model:
openai/gpt-5.2-codex - finish_reason:
stop - usage:
Usage(completion_tokens=71, prompt_tokens=1738, total_tokens=1809, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=0, reasoning_tokens=97, rejected_prediction_tokens=None, text_tokens=None, image_tokens=0, video_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cache_write_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None, video_tokens=0, cache_creation_tokens=0), cost=0.0040355, is_byok=False, cost_details={'upstream_inference_cost': 0.0040355, 'upstream_inference_prompt_cost': 0.0030415, 'upstream_inference_completions_cost': 0.000994})
Prompt (openrouter/openai/gpt-5.2-codex): Hi, can you use tools?
🤖Reply🤖
Yes—I can use the available tools (e.g., read_url), but I’ll ask for confirmation before accessing any URLs. What would you like to do?
{"model": "openrouter/openai/gpt-5.2-codex", "prompt_tokens": 1738, "completion_tokens": 71, "total_tokens": 1809, "cached_tokens": 0, "cache_creation_tokens": 0, "cost": 0.0043995}def bad_joke():
"Tells a bad joke"
return "Why are engineers bad at telling jokes timing?"bc.add_tools('bad_joke')
len(bc.tool_schemas)2
%bc Tell me a bad joke using your tools pleaseWhy are engineers bad at telling jokes timing?
- id:
gen-1786095857-BqlLTP3a2yngmpz7ZTGr - model:
openai/gpt-5.2-codex - finish_reason:
stop - usage:
Usage(completion_tokens=13, prompt_tokens=1922, total_tokens=1935, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=None, text_tokens=None, image_tokens=0, video_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cache_write_tokens=0, cached_tokens=1792, text_tokens=None, image_tokens=None, video_tokens=0, cache_creation_tokens=0), cost=0.0007231, is_byok=False, cost_details={'upstream_inference_cost': 0.0007231, 'upstream_inference_prompt_cost': 0.0005411, 'upstream_inference_completions_cost': 0.000182})
Prompt (openrouter/openai/gpt-5.2-codex): Tell me a bad joke using your tools please
dhp - Polya helpers for SolveIt
Dialog Helper for Polya’s Problem-Solving Method
The dhp module provides quick access to Polya’s four-stage problem-solving process through interactive prompts.
Each stage has multiple questions/prompts: - To preview one you can just print it/type its name in a cell and hit Submit - e.g. dhp.act.next shows you “(prompt) What is next?”. - To execute one you call it by adding () after the name - e.g. dhp.act.next() will replace the current message cell with a prompt cell having “What is next?” in it - It will be automatically executed, you can hit Esc to stop it and/or Enter to edit the prompt
TYPICAL FLOW: - Start with dhp.u (understand) (even briefly) to clarify your understanding of the problem - Move to dhp.p (plan) to develop initial strategies - Switch between plan and act (or dhp.a, or dhp.x/ execute) as you develop and test approaches - Use dhp.r (review) to gain deeper understanding of your approach and findings - You might loop back to other steps after dhp.r (review)
If you feel stuck, run dhp.help() and it will submit the prompt cell it creates - SolveIt will help you pick a next prompt!
The problem we want to solve is demonstrating the dhp module
The following cell is from running dhp.help() then running the prompt cell it creates
Please pick an appropriate next-step/prompt from the below:
Dialog Helper for Polya’s Problem-Solving Method
This module provides quick access to Polya’s four-stage problem-solving process through interactive prompts.
Each stage has multiple questions/prompts: - To preview one you can just print it/type its name in a cell and hit Submit - e.g. dhp.act.next shows you “(prompt) What is next?”. - To execute one you call it by adding () after the name - e.g. dhp.act.next() will replace the current message cell with a prompt cell having “What is next?” in it - It will be automatically executed, you can hit Esc to stop it and/or Enter to edit the prompt
TYPICAL FLOW: - Start with dhp.u (understand) (even briefly) to clarify your understanding of the problem - Move to dhp.p (plan) to develop initial strategies - Switch between plan and act (or dhp.a, or dhp.x/execute) as you develop and test approaches - Use dhp.r (review) to gain deeper understanding of your approach and findings - You might loop back to other steps after r (review)
If you feel stuck, run dhp.help() and it will submit the prompt cell it creates - SolveIt will help you pick a next prompt!
UNDERSTAND STAGE - Clarify the problem before solving - dhp.u.summary() - Creates a prompt cell asking SolveIt to give a concise summary of the problem - dhp.u.info() - Creates a prompt cell asking SolveIt to inventory known/unknown information - dhp.u.similar() - Creates a prompt cell asking SolveIt if it has seen a similar problem before - dhp.u.lateral() - Creates a prompt cell to explore problem relationships and scope - dhp.u.related() - Creates a prompt cell to identify similar or simpler problems - dhp.u.viz() - Creates a prompt cell asking SolveIt to create a figure or diagram to represent the problem - dhp.u.notation() - Creates a prompt cell asking SolveIt to pick suitable notation (symbols for quantities/data, states, transitions) - dhp.u.simplest() - Creates a prompt cell asking SolveIt for the simplest way to look at the problem - dhp.u.simplify() - Creates a prompt cell asking SolveIt to separate problem parts (break down complex conditions into simpler ones) - dhp.u.objective() - Creates a note cell asking you to state the objective in one sentence, without reference to algorithms, models, or data - dhp.u.levers() - Creates a note cell asking you to separate what you can control from what you cannot - dhp.u.ideal_data() - Creates a prompt cell asking SolveIt what data you would collect if you could measure anything
PLAN STAGE - Develop strategies and approaches - dhp.p.chunks() - Creates a prompt cell asking SolveIt to break down the problem into smaller sub-problems - dhp.p.partial() - Creates a prompt cell asking SolveIt if there’s a smaller part or representation of the problem to solve - dhp.p.known_approach() - Creates a prompt cell asking SolveIt to use a known algorithm or library to solve the problem - dhp.p.verifiable() - Creates a prompt cell asking SolveIt how to verify if the solution is consistent and correct - dhp.p.backward() - Creates a prompt cell asking SolveIt to work backward from the desired result - dhp.p.aux() - Creates a prompt cell asking SolveIt to use an auxiliary element (variable, diagram, or example) to clarify the path - dhp.p.analogy() - Creates a prompt cell asking SolveIt to use analogy or similarity to relate the problem to a known solution - dhp.p.review() - Creates a prompt cell asking SolveIt to critique the plan of attack (be frank and critical) - dhp.p.completeness() - Creates a prompt cell asking SolveIt if you’ve used all the data and taken into account all essential notions
ACT STAGE - Execute your plan while monitoring progress - dhp.a.all() - Creates a prompt cell asking SolveIt if we covered all of the data or examples for this step - dhp.a.check() - Creates a prompt cell asking SolveIt if this step seems correct - dhp.a.doubt() - Creates a prompt cell asking SolveIt if we’re using the right approach - dhp.a.next() - Creates a prompt cell asking SolveIt what is next - dhp.a.other() - Creates a prompt cell asking SolveIt if there’s another way to look at this - dhp.a.partial() - Creates a prompt cell asking SolveIt about intermediate results or milestones to aim for - dhp.a.simpler() - Creates a prompt cell asking SolveIt if there was a simpler way to do this step - dhp.a.symmetry() - Creates a prompt cell asking SolveIt about symmetries or patterns in the problem to exploit - dhp.a.valid() - Creates a prompt cell asking SolveIt if this step was a valid step
REVIEW STAGE - Verify results, reflect on process, and extract lessons - dhp.r.all() - Creates a prompt cell asking SolveIt if we covered all of the data or examples for this problem - dhp.r.alter() - Creates a prompt cell asking SolveIt for alternative solutions or approaches that might be more efficient or effective - dhp.r.general() - Creates a prompt cell asking SolveIt if we can generalize the solution to other similar problems - dhp.r.grok() - Creates a note cell with the text “To consider: Can I understand the solution without having to perform all the steps?” - dhp.r.learned() - Creates a prompt cell asking SolveIt what lessons have been learned from this - dhp.r.mistakes() - Creates a prompt cell asking SolveIt about common mistakes made - dhp.r.other() - Creates a prompt cell asking SolveIt if we can derive the result differently - dhp.r.principles() - Creates a prompt cell asking SolveIt to identify underlying principles or patterns that emerged during the solution process - dhp.r.sanity() - Creates a prompt cell asking SolveIt if the result makes sense and can be verified by substitution or another method - dhp.r.simpler() - Creates a prompt cell asking SolveIt if we can derive the result in a simpler way - dhp.r.test() - Creates a prompt cell asking SolveIt for different ways to test this - dhp.r.framing() - Creates a note cell asking you to reflect on whether you started with the objective or with a tool - dhp.r.levers_overlooked() - Creates a prompt cell asking SolveIt what levers you might have overlooked - dhp.r.future_data() - Creates a prompt cell asking SolveIt what data you would collect differently next time
OUTPUT SECTIONS
If the content is code, you explain what the code does in a section called EXPLANATION:.
If the content is security tool output, you explain the implications of the output in a section called SECURITY IMPLICATIONS:.
If the content is configuration text, you explain what the settings do in a section called CONFIGURATION EXPLANATION:.
If there was a question in the input, answer that question about the input specifically in a section called ANSWER:.
OUTPUT
- Do not output warnings or notes—just the requested sections.
INPUT:
INPUT:
$prompt
Prompt (From fab.p.explain_code) for $prompt
EXPLANATION:
This is a marimo notebook script (a reactive, cell-based Python UI, run with uv run given the inline PEP 723 metadata block at the top) that turns a web article into a two-host podcast, complete with synthesized audio.
Setup cells - Declares dependencies (marimo, gaspare, openai, pydub, contextkit) via the # ///script header, so uv run can provision them automatically. - Imports OpenAI for text-to-speech, gaspare (aliased gp) for calling an LLM (Gemini) to write the script, contextkit.read_url to fetch and clean web content, and pydub.AudioSegment for stitching audio clips together. - Asserts that OPENAI_API_KEY and GEMINI_API_KEY are set in the environment, then creates an OpenAI client.
UI form - Builds a marimo form with: source URL, output filename, two host names, two OpenAI TTS voice names, a slider for approximate episode length (3–60 min), and a “Run!” button. Nothing downstream executes until the button is clicked (mo.stop(not run_button.value) gates every later cell).
Helper functions - clean_text_for_tts: repairs common mis-encoded punctuation (broken ellipses, curly quotes), strips non-ASCII characters, collapses whitespace, and NFKD-normalizes the text so it’s safe to feed to a TTS engine. - parse_podcast_script: parses a raw script into a list of {"speaker": ..., "text": ...} segments, splitting on lines that start with HOSTNAME: (case-insensitive match against the two configured host names) and cleaning each segment’s text.
Pipeline (only runs once “Run!” is clicked) 1. read_url fetches and converts the source page into text/markdown. 2. A large prompt is built asking Gemini to convert that source material into a two-host podcast script, with detailed instructions on hosts’ personalities, structure, tone, and a strict HOSTNAME: text output format, targeting the requested approximate spoken length. 3. gp.Chat(model="gemini-2.5-pro-preview-03-25") sends that prompt and the response is parsed into segments via parse_podcast_script. 4. For each segment, client.audio.speech.with_streaming_response.create (OpenAI’s gpt-4o-mini-tts model) synthesizes audio using the voice and persona instructions matching that speaker, streaming bytes into a BytesIO buffer and loading it as a pydub.AudioSegment. 5. All segments are concatenated (sum(parts, AudioSegment.empty())) into a single preview audio object, previewed inline, then exported to the configured output MP3 path. 6. The generated script text is also cleaned and written to a companion _script.md file, and rendered inline as markdown for review.
Overall purpose: given nothing but a URL and some UI settings, the script scrapes an article, has an LLM turn it into a natural two-host dialogue script of a target length, and synthesizes it into a playable/downloadable podcast MP3 with two distinct AI voices — all inside an interactive marimo app.
{"model": "claude-sonnet-5", "prompt_tokens": 68864, "completion_tokens": 1259, "total_tokens": 70123, "cached_tokens": 8701, "cache_creation_tokens": 60161, "cost": 0.011273850000000002}To go back full-circle, we can have a different LLM validate the results… Note that the %%bc cell magic allows you to pick a different BackupChat instance (%bc line magic does not)
gemini = dhb.c("gemini/gemini-3.1-pro-preview")%%bc gemini
Please compare the answer above to https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/README.md and comment on any issues? It's OK, it's not a big download, so go ahead and read it!The previous code explanation was remarkably accurate and aligns perfectly with what the README.md describes! The explain_code prompt did a great job dissecting the pipeline (Contextkit -> Gemini 2.5 Pro -> OpenAI TTS -> Pydub) exactly as the author intended.
However, cross-referencing with the README.md reveals a few practical, user-facing details that the raw code analysis missed:
- Python Version Constraint: The README explicitly notes that you need a Python version before 3.13 (specifically recommending 3.12). This is due to a limitation with the
pydubaudio processing library. - Execution Method: While the code explanation noted it can be run via
uv rundue to the PEP 723 block, the README specifically recommends running it headlessly/sandboxed with:uvx marimo run --sandbox https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/blogtopod.py - Patience Required: The README gives the user a heads-up that clicking “Run!” might take 6 to 10 minutes to process.
Are there any specific parts of the pipeline (like how it chunks the script or handles the TTS streams) you want to dive deeper into?
- id:
OW14apiNOcyB-8YPgcW2mAI - model:
gemini-3.1-pro-preview - finish_reason:
stop - usage:
Usage(completion_tokens=1235, prompt_tokens=10316, total_tokens=11551, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=948, rejected_prediction_tokens=None, text_tokens=287, image_tokens=None, video_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=8059, text_tokens=2257, image_tokens=None, video_tokens=None), cache_read_input_tokens=8059)
Prompt (gemini/gemini-3.1-pro-preview): Please the answer above to https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/README.md and comment on any issues? It’s OK, it’s not a big download, so go ahead and read it!
Developer Guide
If you are new to using nbdev here are some useful pointers to get you started.
Installing solveit_dmtools in Development mode
- local dev install:
$ pip install -e .
- make changes under nbs/ directory: …
- prepare for commit:
$ alias nbprep='nbdev-clean ; nbdev-export'
$ nbprep
#!pip install -e ..
# OR
#!pip install -Uqq solveit_dmtoolsInstallation
Install latest from the GitHub repository:
$ pip install git+https://github.com/shuane/solveit_dmtools.gitor from pypi
$ pip install solveit_dmtoolsDocumentation
Documentation can be found hosted on this GitHub repository’s pages. Additionally you can find package manager specific guidelines on the pypi site.