Metadata-Version: 2.4
Name: solveit_dmtools
Version: 0.0.13
Summary: Personalized tools to add functionality to SolveIt
Home-page: https://github.com/shuane/solveit_dmtools
Author: Duane Milne
Author-email: duane.milne@gmail.com
License: Apache Software License 2.0
Keywords: nbdev jupyter notebook python
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: Apache Software License
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dialoghelper
Requires-Dist: contextkit
Requires-Dist: lisette
Provides-Extra: dev
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# solveit_dmtools


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Usage and examples

``` python
from dialoghelper.core import *
from solveit_dmtools import * # dhb, dhp, fab
```

``` python
add_msg(content=dhb.doc, msg_type='note')
```

    '_16aec1ea'

**Backup Chat for SolveIt using dialoghelper and lisette**

Sometimes we may have a problem in SolveIt while Sonnet is down (E300),
or maybe we want a different perspective.

This module helps us to leverage any other LLM that is available to
LiteLLM by providing our own keys and the model name.

Usage:

``` python
from solveit_dmtools import dhb

# then in another cell
# bc = dhb.c() to search model names
bc = dhb.c("model-name")
bc("Hi")
```

First calling with no model will prompt you to type in part of a model
name to search

``` python
bc = dhb.c()
```

    Please try again by using e.g. `bc = dhb.c('model_name')` with a model name in:
    azure/eu/gpt-5-2025-08-07
    azure/eu/gpt-5-mini-2025-08-07
    azure/eu/gpt-5.1
    azure/eu/gpt-5.1-chat
    azure/eu/gpt-5.1-codex
    azure/eu/gpt-5.1-codex-mini
    azure/eu/gpt-5-nano-2025-08-07
    azure/global/gpt-5.1
    azure/global/gpt-5.1-chat
    azure/global/gpt-5.1-codex
    azure/global/gpt-5.1-codex-mini
    azure/gpt-5.1-2025-11-13
    azure/gpt-5.1-chat-2025-11-13
    azure/gpt-5.1-codex-2025-11-13
    azure/gpt-5.1-codex-mini-2025-11-13
    azure/gpt-5
    azure/gpt-5-2025-08-07
    azure/gpt-5-chat
    azure/gpt-5-chat-latest
    azure/gpt-5-codex
    azure/gpt-5-mini
    azure/gpt-5-mini-2025-08-07
    azure/gpt-5-nano
    azure/gpt-5-nano-2025-08-07
    azure/gpt-5-pro
    azure/gpt-5.1
    azure/gpt-5.1-chat
    azure/gpt-5.1-codex
    azure/gpt-5.1-codex-mini
    azure/us/gpt-5-2025-08-07
    azure/us/gpt-5-mini-2025-08-07
    azure/us/gpt-5-nano-2025-08-07
    azure/us/gpt-5.1
    azure/us/gpt-5.1-chat
    azure/us/gpt-5.1-codex
    azure/us/gpt-5.1-codex-mini
    gpt-5
    gpt-5.1
    gpt-5.1-2025-11-13
    gpt-5.1-chat-latest
    gpt-5-pro
    gpt-5-pro-2025-10-06
    gpt-5-2025-08-07
    gpt-5-chat
    gpt-5-chat-latest
    gpt-5-codex
    gpt-5.1-codex
    gpt-5.1-codex-mini
    gpt-5-mini
    gpt-5-mini-2025-08-07
    gpt-5-nano
    gpt-5-nano-2025-08-07
    openrouter/openai/gpt-5-chat
    openrouter/openai/gpt-5-codex
    openrouter/openai/gpt-5
    openrouter/openai/gpt-5-mini
    openrouter/openai/gpt-5-nano

``` python
bc = dhb.c("openrouter/openai/gpt-5-codex")
```

The following will be automatically commented out when run, then a
prompt cell is added after it with input/output from the other LLM.

``` python
bc("Hi, can you use tools?")
```

I can use the built-in URL reader, but no other tools are currently
available in this session. What would you like to do—do you have other
tools or variables you’d like to add?

<details>

- id: `gen-1763944919-qpn4Xb5hfcJcAhCAa8nd`
- model: `openai/gpt-5-codex`
- finish_reason: `stop`
- usage:
  `Usage(completion_tokens=302, prompt_tokens=1706, total_tokens=2008, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=256, rejected_prediction_tokens=None, text_tokens=None, image_tokens=0), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None, video_tokens=0), cost=0.0051525, is_byok=False, cost_details={'upstream_inference_cost': None, 'upstream_inference_prompt_cost': 0.0021325, 'upstream_inference_completions_cost': 0.00302})`

</details>

**Prompt (openrouter/openai/gpt-5-codex):** Hi, can you use tools?

##### 🤖Reply🤖<!-- SOLVEIT_SEPARATOR_7f3a9b2c -->

I can use the built-in URL reader, but no other tools are currently
available in this session. What would you like to do—do you have other
tools or variables you’d like to add?

``` python
bc("Can you please read https://raw.githubusercontent.com/AnswerDotAI/fhdaisy/refs/heads/main/README.md and give the elevator pitch and some sample code? No need to store the raw content.")
```

**Elevator pitch**

`fhdaisy` wraps the DaisyUI component library for FastHTML so you can
build polished interfaces without hand‑crafting HTML classes. Instead of
writing verbose class strings like `class="btn btn-primary"`, you
compose Python components (`Btn`, `Card`, `Alert`, etc.) that
automatically map to the right HTML tags and DaisyUI modifiers. This
keeps your FastHTML code concise, consistent, and themeable while still
letting you mix in custom helpers when needed.

**Sample usage**

``` python
from fasthtml.common import Div, H2
from fhdaisy import Btn, Card, Alert, Input, Modal

# Card with a button call-to-action
card = Card(
    H2("Join the beta!", cls="-lg"),
    "Get early access to the newest FastHTML components.",
    Btn("Sign up", cls="-primary"),
    cls="-compact -shadow"
)

# Alert and input field using DaisyUI modifiers
banner = Alert("Deployment succeeded ✅", cls="-success -shadow")

email_field = Input(type="email", placeholder="you@example.com", cls="-bordered -primary")

# Modal with a form
dialog = Modal(
    Div(
        H2("Feedback"),
        email_field,
        Btn("Send", cls="-accent"),
        cls="space-y-3"
    ),
    cls="-open"
)
```

These components render with the appropriate DaisyUI classes applied
automatically, keeping your FastHTML views tidy and expressive.

<details>

- id: `gen-1763945007-BW11GMmG8i8PaQpURfVe`
- model: `openai/gpt-5-codex`
- finish_reason: `stop`
- usage:
  `Usage(completion_tokens=502, prompt_tokens=3020, total_tokens=3522, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=192, rejected_prediction_tokens=None, text_tokens=None, image_tokens=0), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None, video_tokens=0), cost=0.008795, is_byok=False, cost_details={'upstream_inference_cost': None, 'upstream_inference_prompt_cost': 0.003775, 'upstream_inference_completions_cost': 0.00502})`

</details>

**Prompt (openrouter/openai/gpt-5-codex):** Can you please read
https://raw.githubusercontent.com/AnswerDotAI/fhdaisy/refs/heads/main/README.md
and give the elevator pitch and some sample code? No need to store the
raw content.

##### 🤖Reply🤖<!-- SOLVEIT_SEPARATOR_7f3a9b2c -->

<details class="tool-usage-details">

``` json
{
  "id": "call_ikBfSjiiyCzhnIyOUfuwwftg",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://raw.githubusercontent.com/AnswerDotAI/fhdaisy/refs/heads/main/README.md",
      "as_md": true,
      "extract_section": false,
      "selector": ""
    }
  },
  "result": "# fhdaisy\n\n`fhdaisy` is a Python wrapper for [DaisyUI](https://daisyui.com/) that\nbrings its compone<TRUNCATED>"
}
```

</details>

**Elevator pitch**

`fhdaisy` wraps the DaisyUI component library for FastHTML so you can
build polished interfaces without hand‑crafting HTML classes. Instead of
writing verbose class strings like `class="btn btn-primary"`, you
compose Python components (`Btn`, `Card`, `Alert`, etc.) that
automatically map to the right HTML tags and DaisyUI modifiers. This
keeps your FastHTML code concise, consistent, and themeable while still
letting you mix in custom helpers when needed.

**Sample usage**

``` python
from fasthtml.common import Div, H2
from fhdaisy import Btn, Card, Alert, Input, Modal

# Card with a button call-to-action
card = Card(
    H2("Join the beta!", cls="-lg"),
    "Get early access to the newest FastHTML components.",
    Btn("Sign up", cls="-primary"),
    cls="-compact -shadow"
)

# Alert and input field using DaisyUI modifiers
banner = Alert("Deployment succeeded ✅", cls="-success -shadow")

email_field = Input(type="email", placeholder="you@example.com", cls="-bordered -primary")

# Modal with a form
dialog = Modal(
    Div(
        H2("Feedback"),
        email_field,
        Btn("Send", cls="-accent"),
        cls="space-y-3"
    ),
    cls="-open"
)
```

These components render with the appropriate DaisyUI classes applied
automatically, keeping your FastHTML views tidy and expressive.

``` python
add_msg(content=dhp.doc, msg_type="note")
```

    '_94fe5acd'

**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 `a`, or
`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)

**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)

**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

The following is just dhp.help()

Please pick an appropriate next-step/prompt from the below:

## doc: 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)

info: (prompt) “What information do we have? What information do we not
have? What might change as we learn more?” lateral: (prompt) “Can you
relate this problem to a more general or a more specific problem?”
notation: (prompt) “Can we pick a suitable notation (e.g. symbols for
quantities/data, states, and transitions)?” related: (prompt) “Can you
think of a related problem that we can solve? It could even be a simpler
one we could solve first to help understand this one.” similar: (prompt)
“Have you seen a similar problem before?” simplest: (prompt) “What might
be the simplest way to look at this problem?” simplify: (prompt) “Can we
separate the various parts of the problem (e.g. break down complex
conditions into simpler ones)?” summary: (prompt) “Could you please give
a concise summary of the problem?” viz: (prompt) “Can we create a figure
or diagram to represent the problem?”

## doc: 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)

analogy: (prompt) “Can you use analogy or similarity to relate the
problem to a known solution?” aux: (prompt) “Could we use an auxiliary
element (e.g., a variable, diagram, or example) to clarify the path?”
backward: (prompt) “Can we work backward from the desired result?”
chunks: (prompt) “Could you please break down the problem into smaller
sub-problems?” known_approach: (prompt) “Could we use a known algorithm
or library to solve the problem, or some of it?” partial: (prompt) “Is
there a smaller part or representation of the problem we could solve?”
review: (prompt) “Could you please critique the plan of attack? Be
frank, do not be afraid to be critical.” verifiable: (prompt) “How would
we verify if our solution is consistent and correct?”

## doc: ACT STAGE - Execute your plan while monitoring progress

- dhp.a.doubt() - Creates a prompt cell asking SolveIt if we’re **using
  the right approach**
- 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.symmetry() - Creates a prompt cell asking SolveIt about
  **symmetries or patterns** in the problem to exploit
- dhp.a.next() - Creates a prompt cell asking SolveIt **what is next**
- dhp.a.valid() - Creates a prompt cell asking SolveIt if **this step
  was a valid step**
- dhp.a.check() - Creates a prompt cell asking SolveIt if **this step
  seems correct**
- dhp.a.simpler() - Creates a prompt cell asking SolveIt if there was a
  **simpler way** to do this step
- dhp.a.all() - Creates a prompt cell asking SolveIt if we **covered all
  of the data or examples** for this step

all: (prompt) “Did we cover all of the data or examples for this step?”
check: (prompt) “Does this step seem correct?” doubt: (prompt) “Are we
using the right approach?” next: (prompt) “What is next?” other:
(prompt) “Is there another way to look at this?” partial: (prompt) “Are
there any intermediate results or milestones that we can aim for?”
simpler: (prompt) “Was there a simpler way we could have done this
step?” symmetry: (prompt) “Are there any symmetries or patterns in the
problem that we can exploit?” valid: (prompt) “Does this step seem to
have been a valid step?”

## doc: 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.sanity() - Creates a prompt cell asking SolveIt if the **result
  makes sense** and can be verified by substitution or another method
- 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.general() - Creates a prompt cell asking SolveIt if we can
  **generalize the solution** to other similar problems
- dhp.r.alter() - Creates a prompt cell asking SolveIt for **alternative
  solutions or approaches** that might be more efficient or effective
- dhp.r.other() - Creates a prompt cell asking SolveIt if we can
  **derive the result differently**
- dhp.r.mistakes() - Creates a prompt cell asking SolveIt about **common
  mistakes** made
- dhp.r.simpler() - Creates a prompt cell asking SolveIt if we can
  **derive the result in a simpler way**
- dhp.r.principles() - Creates a prompt cell asking SolveIt to
  **identify underlying principles or patterns** that emerged during the
  solution process
- dhp.r.test() - Creates a prompt cell asking SolveIt for **different
  ways to test** this

all: (prompt) “Did we cover all of the data or examples for this
problem?” alter: (prompt) “Can you think of alternative solutions or
approaches that might be more efficient or effective?” general: (prompt)
“Can we generalize the solution to other similar problems?” grok: (note)
“**To consider:** Can I understand the solution without having to
perform all the steps?” learned: (prompt) “What lessons have I learned
from this?” mistakes: (prompt) “What were my common mistakes?” other:
(prompt) “Can we derive the result differently?” principles: (prompt)
“Can you identify any underlying principles or patterns that emerged
during the solution process?” sanity: (prompt) “Does the result make
sense? Can we verify by substition or another method?” simpler: (prompt)
“Can we derive the result in a simpler way?” test: (prompt) “What are
some different ways we can test this?”

’**Dialog Helper for Polya's Problem-Solving Method**module provides
quick access to Polya's four-stage problem-solving processinteractive
prompts.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 `a`, or `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`)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)\*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)\*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’

##### 🤖Reply🤖<!-- SOLVEIT_SEPARATOR_7f3a9b2c -->

Based on where we are in the conversation, I’d recommend starting with:

**`dhp.u.summary()`**

Since we’ve just been introduced to the `dhp` (Dialog Helper for Polya’s
method) tool and haven’t defined a specific problem yet, beginning with
a summary prompt would help clarify what problem we’re trying to solve.
This follows Polya’s method by starting in the UNDERSTAND stage before
moving to planning or action.

Would you like to run that, or do you have a specific problem in mind
that you’d like to work on? If you already have a problem and want to
jump to a different stage, let me know!

``` python
# Uncomment and submit the line below if you do not already have a copy of fabric in your fabric folder
#!git clone --depth 1 https://github.com/danielmiessler/fabric.git
```

``` python
add_msg(content=fab.doc, msg_type="note")
```

    '_9b1e86d1'

**fab - Open Source ‘fabric’ prompts made quickly available in SolveIt**

This module leverages over 200 open source LLM prompts that are
available in Daniel Miesller’s ‘fabric’ project.

If you import as fab, Submit the following to see an overview of all the
prompts: `fab.p`

**HOW TO USE IT**

Most Common Syntax: `prompt="Your Prompt"` in one cell then
`fab.p.pattern_name()` in another, where pattern_name is any of the 200+
available fabric patterns.

**MOST IMPORTANT AND USED OPTIONS AND FEATURES**

- **Variable Targeting**: Use `fab.p.pattern_name('variable_name')` to
  process content from a specific variable instead of the default
  ‘prompt’ variable.

- **Pattern Discovery**: Use `fab.p.help()` (an alias for
  suggest_pattern()) to get suggestions of which pattern to pick for
  your prompt.

- **Compression Feature**: Use `fab.compress()` after running a pattern
  to save tokens by marking the previous cell as skipped and compressing
  the output to a new note.

- **Default Variable**: Most patterns work with a variable called
  ‘prompt’ by default, making it easy to process your main content.

**COMMON PATTERNS**

- For Summarizing Content: `fab.p.summarize()`
- For Explaining Code: `fab.p.explain_code()`
- For Analyzing Claims: `fab.p.analyze_claims()`
- For Extracting Wisdom from Text: `fab.p.extract_wisdom()`
- For Creating Quizzes: `fab.p.create_quiz()`

``` python
fab.p.explain_code
```

    Fabric pattern: explain_code - Analyze/explain code, security tool outputs, and configs.

``` python
prompt = read_url("https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/blogtopod.py")
```

The next cell is running fab.p.explain_code()

(From fab.p.explain_code folded below) \# IDENTITY and PURPOSE

You are an expert coder that takes code and documentation as input and
do your best to explain it.

Take a deep breath and think step by step about how to best accomplish
this goal using the following steps. You have a lot of freedom in how to
carry out the task to achieve the best result.

# 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

##### 🤖Reply🤖<!-- SOLVEIT_SEPARATOR_7f3a9b2c -->

**EXPLANATION:**

This Python script (`blogtopod.py`) converts blog posts into
podcast-style audio files using text-to-speech. Here’s what it does:

The script fetches a blog post from a URL, extracts the main content,
and converts it to audio using OpenAI’s TTS API. It processes the text
in chunks (since TTS APIs have size limits), generates audio for each
chunk, then combines them into a single MP3 file.

**Key components:**

- Uses `contextkit.read_url` to extract article content from URLs
- Leverages `openai` library for text-to-speech conversion (voice:
  “alloy”)
- Splits text into ~4000 character chunks at sentence boundaries to
  avoid cutting mid-sentence
- Uses `pydub` to concatenate audio segments into one file
- Saves the final audio as `output.mp3`

**Main workflow:** 1. Parse the URL and extract article text 2. Break
text into manageable chunks 3. Generate audio for each chunk via OpenAI
TTS 4. Combine all audio segments 5. Export as a single MP3 file

The script is designed to run from command line, taking a blog URL as an
argument. It requires an OpenAI API key to function.

------------------------------------------------------------------------

Would you like me to explain any specific part in more detail, or would
you like to explore how you might modify or extend this code?

To go back full-circle, we can have a different LLM correct the results…

``` python
# bc("That's not quite right - can you compare your answer to https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/README.md and correct it?")
```

**Prompt (openrouter/openai/gpt-5-codex):** That’s not quite right - can
you compare your answer to
https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/README.md
and correct it?

##### 🤖Reply🤖<!-- SOLVEIT_SEPARATOR_7f3a9b2c -->

<details class="tool-usage-details">

``` json
{
  "id": "call_s3YbiJZa6Z7VT1NtUe4Qm36Q",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://raw.githubusercontent.com/shuane/blogtopod/refs/heads/main/README.md",
      "as_md": true,
      "extract_section": false,
      "selector": ""
    }
  },
  "result": "# blogtopod: Turn blog posts into podcast episodes\n\n*Convert blog posts into podcast episodes using <TRUNCATED>"
}
```

</details>

Here’s what I found after revisiting the project information and
reconciling it with the earlier summary:

**Key corrections**

- The app isn’t just a plain command-line script—it opens an interactive
  Marimo interface (a small web UI). In that UI you paste a blog URL,
  choose an output filename, and click “Run.” The script then pulls the
  article, builds a narrated script via Gemini 2.5 Pro, and finally
  turns that script into narrated audio using OpenAI’s latest
  text-to-speech voices. When it’s done, you get both the MP3 and the
  generated script (saved as `*_script.md`).  
- Because of the dual-model workflow, you need **two API keys**: one for
  OpenAI and another for Google Gemini. They’re expected in the
  environment variables `OPENAI_API_KEY` and `GEMINI_API_KEY`.  
- A recommended way to run it is through `uvx marimo run --sandbox ...`,
  which means you don’t have to manage dependencies manually—the
  requirements are embedded in the file. A traditional pip + marimo
  option also exists, but it’s secondary.  
- The workflow intentionally uses Gemini to craft a polished podcast
  script before OpenAI voices read it. The earlier summary skipped
  Gemini entirely and made it sound like straight text-to-speech on raw
  article text; that was inaccurate.

**Revised high-level explanation**

`blogtopod.py` is a Marimo-based app that turns any blog post into a
polished podcast episode. After you provide the blog URL, it:

1.  Extracts the page content (via contextkit under the hood).  
2.  Sends that reflowed text to Gemini 2.5 Pro, which produces a
    listener-friendly podcast script.  
3.  Feeds the script into OpenAI’s TTS service to synthesize speech
    (voice defaults to Alloy), chunking the text as needed and stitching
    the audio together with `pydub`.  
4.  Outputs both the generated MP3 and the textual script so you can
    review or publish it.

It therefore serves anyone wanting to consume or distribute blog content
in audio form, using a blend of Gemini for narrative shaping and OpenAI
for natural speech.

## Developer Guide

If you are new to using `nbdev` here are some useful pointers to get you
started.

### Installing solveit_dmtools in Development mode

1.  local dev install:

`$ pip install -e .`

2.  make changes under nbs/ directory: …
3.  prepare for commit:

`$ alias nbprep='nbdev_clean ; nbdev_export'`

`$ nbprep`

``` python
#!pip install -e ..
# OR
#!pip install -Uqq solveit_dmtools
```

### Installation

Install latest from the GitHub
[repository](https://github.com/shuane/solveit_dmtools):

``` sh
$ pip install git+https://github.com/shuane/solveit_dmtools.git
```

or from [pypi](https://pypi.org/project/solveit_dmtools/)

``` sh
$ pip install solveit_dmtools
```

### Documentation

Documentation can be found hosted on this GitHub
[repository](https://github.com/shuane/solveit_dmtools)’s
[pages](https://shuane.github.io/solveit_dmtools/). Additionally you can
find package manager specific guidelines on the
[pypi](https://pypi.org/project/solveit_dmtools/) site.
