promptpump 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- promptpump-0.1.0/LICENSE +21 -0
- promptpump-0.1.0/PKG-INFO +103 -0
- promptpump-0.1.0/README.md +71 -0
- promptpump-0.1.0/promptpump/__init__.py +16 -0
- promptpump-0.1.0/promptpump/cli.py +188 -0
- promptpump-0.1.0/promptpump/context.py +322 -0
- promptpump-0.1.0/promptpump/engine.py +217 -0
- promptpump-0.1.0/promptpump/templates.py +232 -0
- promptpump-0.1.0/promptpump.egg-info/PKG-INFO +103 -0
- promptpump-0.1.0/promptpump.egg-info/SOURCES.txt +15 -0
- promptpump-0.1.0/promptpump.egg-info/dependency_links.txt +1 -0
- promptpump-0.1.0/promptpump.egg-info/entry_points.txt +2 -0
- promptpump-0.1.0/promptpump.egg-info/requires.txt +9 -0
- promptpump-0.1.0/promptpump.egg-info/top_level.txt +1 -0
- promptpump-0.1.0/pyproject.toml +51 -0
- promptpump-0.1.0/setup.cfg +4 -0
- promptpump-0.1.0/tests/test_engine.py +165 -0
promptpump-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ritesh Nipane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: promptpump
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic context-engineering engine and prompt compiler powered by a local Ollama model.
|
|
5
|
+
Author: Ritesh Nipane
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/RiteshNipane/PromptPump
|
|
8
|
+
Project-URL: Issues, https://github.com/RiteshNipane/PromptPump/issues
|
|
9
|
+
Keywords: prompt-engineering,ollama,llm,cli,context-engineering
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: typer>=0.12
|
|
24
|
+
Requires-Dist: rich>=13.0
|
|
25
|
+
Requires-Dist: requests>=2.31
|
|
26
|
+
Requires-Dist: pyperclip>=1.8
|
|
27
|
+
Requires-Dist: pathspec>=0.11
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# PromptPump
|
|
34
|
+
|
|
35
|
+
A local CLI tool and Python library that turns a short shorthand prompt into a
|
|
36
|
+
high-density, production-ready **master prompt**. It scans your project (file tree,
|
|
37
|
+
README/config snippets, Python AST outlines), merges that with a strict structural
|
|
38
|
+
schema, and compiles it with a local model (Ollama + Qwen2.5-Coder). Nothing leaves
|
|
39
|
+
your machine.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
Requires Python 3.10+ and [Ollama](https://ollama.com) (Windows, macOS, Linux).
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ollama pull qwen2.5-coder:7b # or qwen2.5-coder:14b for better quality
|
|
47
|
+
pip install pipx && pipx ensurepath # once; then reopen your terminal
|
|
48
|
+
pipx install promptpump # works in PowerShell, cmd, bash, zsh
|
|
49
|
+
promptpump doctor # verify Ollama + model
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Plain `pip install promptpump` also works. On Linux, clipboard support needs `xclip` or `xsel`.
|
|
53
|
+
|
|
54
|
+
Develop from source: `pip install -e ".[dev]"`.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
promptpump doctor # verify Ollama + model
|
|
60
|
+
promptpump stacks # list stack profiles
|
|
61
|
+
promptpump run "add jwt auth to the api" --stack fastapi --copy
|
|
62
|
+
promptpump run "add a pause menu" --stack pygame --stack python --path ../mygame
|
|
63
|
+
promptpump run "refactor db layer" --dry-run # inspect the payload, no model call
|
|
64
|
+
promptpump run "add caching" --no-copy > prompt.md # progress goes to stderr, prompt to stdout
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Option | Description |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `--stack/-s` | Inject stack rules (repeatable): python, fastapi, django, react, nextjs, node, pygame, pytorch |
|
|
70
|
+
| `--copy/--no-copy` | Copy to clipboard (default: on) |
|
|
71
|
+
| `--path/-p` | Project directory to scan (default: `.`) |
|
|
72
|
+
| `--model/-m` | Ollama model (env `PROMPTPUMP_MODEL`) |
|
|
73
|
+
| `--host` | Ollama URL (env `PROMPTPUMP_HOST`) |
|
|
74
|
+
| `--max-context-tokens` | Workspace context budget (default 3000) |
|
|
75
|
+
| `--ground/--no-ground` | Replace the model's `<codebase_context>` with deterministic scan facts (default: on) |
|
|
76
|
+
| `--dry-run` | Print the system/user payload and exit |
|
|
77
|
+
|
|
78
|
+
## Library use
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from promptpump import OllamaClient, PromptCompiler, scan_workspace
|
|
82
|
+
|
|
83
|
+
ctx = scan_workspace(".")
|
|
84
|
+
result = PromptCompiler(OllamaClient()).compile("add rate limiting", ctx, ["fastapi"])
|
|
85
|
+
print(result.prompt)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## How it stays deterministic
|
|
89
|
+
|
|
90
|
+
- Fixed system prompt and stack rules (`templates.py`); temperature 0.2 and fixed seed.
|
|
91
|
+
- Output validated against the seven required tags, with one automatic repair retry.
|
|
92
|
+
- Conversational filler and code fences stripped; `<codebase_context>` overwritten with real scan data so the model cannot hallucinate files.
|
|
93
|
+
- Secrets (`.env`, keys), binaries, and `.gitignore`d paths are never read.
|
|
94
|
+
|
|
95
|
+
## Tests
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pytest
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Limitations
|
|
102
|
+
|
|
103
|
+
Only the root `.gitignore` is parsed; nested ignore files are not.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# PromptPump
|
|
2
|
+
|
|
3
|
+
A local CLI tool and Python library that turns a short shorthand prompt into a
|
|
4
|
+
high-density, production-ready **master prompt**. It scans your project (file tree,
|
|
5
|
+
README/config snippets, Python AST outlines), merges that with a strict structural
|
|
6
|
+
schema, and compiles it with a local model (Ollama + Qwen2.5-Coder). Nothing leaves
|
|
7
|
+
your machine.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Requires Python 3.10+ and [Ollama](https://ollama.com) (Windows, macOS, Linux).
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ollama pull qwen2.5-coder:7b # or qwen2.5-coder:14b for better quality
|
|
15
|
+
pip install pipx && pipx ensurepath # once; then reopen your terminal
|
|
16
|
+
pipx install promptpump # works in PowerShell, cmd, bash, zsh
|
|
17
|
+
promptpump doctor # verify Ollama + model
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Plain `pip install promptpump` also works. On Linux, clipboard support needs `xclip` or `xsel`.
|
|
21
|
+
|
|
22
|
+
Develop from source: `pip install -e ".[dev]"`.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
promptpump doctor # verify Ollama + model
|
|
28
|
+
promptpump stacks # list stack profiles
|
|
29
|
+
promptpump run "add jwt auth to the api" --stack fastapi --copy
|
|
30
|
+
promptpump run "add a pause menu" --stack pygame --stack python --path ../mygame
|
|
31
|
+
promptpump run "refactor db layer" --dry-run # inspect the payload, no model call
|
|
32
|
+
promptpump run "add caching" --no-copy > prompt.md # progress goes to stderr, prompt to stdout
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Option | Description |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `--stack/-s` | Inject stack rules (repeatable): python, fastapi, django, react, nextjs, node, pygame, pytorch |
|
|
38
|
+
| `--copy/--no-copy` | Copy to clipboard (default: on) |
|
|
39
|
+
| `--path/-p` | Project directory to scan (default: `.`) |
|
|
40
|
+
| `--model/-m` | Ollama model (env `PROMPTPUMP_MODEL`) |
|
|
41
|
+
| `--host` | Ollama URL (env `PROMPTPUMP_HOST`) |
|
|
42
|
+
| `--max-context-tokens` | Workspace context budget (default 3000) |
|
|
43
|
+
| `--ground/--no-ground` | Replace the model's `<codebase_context>` with deterministic scan facts (default: on) |
|
|
44
|
+
| `--dry-run` | Print the system/user payload and exit |
|
|
45
|
+
|
|
46
|
+
## Library use
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from promptpump import OllamaClient, PromptCompiler, scan_workspace
|
|
50
|
+
|
|
51
|
+
ctx = scan_workspace(".")
|
|
52
|
+
result = PromptCompiler(OllamaClient()).compile("add rate limiting", ctx, ["fastapi"])
|
|
53
|
+
print(result.prompt)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## How it stays deterministic
|
|
57
|
+
|
|
58
|
+
- Fixed system prompt and stack rules (`templates.py`); temperature 0.2 and fixed seed.
|
|
59
|
+
- Output validated against the seven required tags, with one automatic repair retry.
|
|
60
|
+
- Conversational filler and code fences stripped; `<codebase_context>` overwritten with real scan data so the model cannot hallucinate files.
|
|
61
|
+
- Secrets (`.env`, keys), binaries, and `.gitignore`d paths are never read.
|
|
62
|
+
|
|
63
|
+
## Tests
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pytest
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Limitations
|
|
70
|
+
|
|
71
|
+
Only the root `.gitignore` is parsed; nested ignore files are not.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""PromptPump: compile shorthand prompts into dense, structured master prompts."""
|
|
2
|
+
|
|
3
|
+
from .context import WorkspaceContext, scan_workspace
|
|
4
|
+
from .engine import CompileResult, OllamaClient, PromptCompiler, PromptPumpError
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0"
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"CompileResult",
|
|
10
|
+
"OllamaClient",
|
|
11
|
+
"PromptCompiler",
|
|
12
|
+
"PromptPumpError",
|
|
13
|
+
"WorkspaceContext",
|
|
14
|
+
"scan_workspace",
|
|
15
|
+
"__version__",
|
|
16
|
+
]
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Typer CLI entry point: ``promptpump run "shorthand" --stack python --copy``."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Annotated, Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.markup import escape
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from . import __version__
|
|
14
|
+
from .context import scan_workspace
|
|
15
|
+
from .engine import (
|
|
16
|
+
DEFAULT_HOST,
|
|
17
|
+
DEFAULT_MODEL,
|
|
18
|
+
OllamaClient,
|
|
19
|
+
PromptCompiler,
|
|
20
|
+
PromptPumpError,
|
|
21
|
+
)
|
|
22
|
+
from .templates import UnknownStackError, get_stack, list_stacks
|
|
23
|
+
|
|
24
|
+
app = typer.Typer(
|
|
25
|
+
name="promptpump",
|
|
26
|
+
help="Compile a short shorthand prompt into a dense, production-ready master prompt "
|
|
27
|
+
"using local codebase context and a local Ollama model.",
|
|
28
|
+
no_args_is_help=True,
|
|
29
|
+
add_completion=False,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Progress and diagnostics go to stderr so stdout stays clean for piping the prompt.
|
|
33
|
+
err = Console(stderr=True)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def copy_to_clipboard(text: str) -> bool:
|
|
37
|
+
"""Copy ``text`` to the system clipboard; return False if unavailable."""
|
|
38
|
+
try:
|
|
39
|
+
import pyperclip
|
|
40
|
+
|
|
41
|
+
pyperclip.copy(text)
|
|
42
|
+
return True
|
|
43
|
+
except Exception: # pyperclip raises PyperclipException when no backend exists
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _force_utf8() -> None:
|
|
48
|
+
"""Avoid UnicodeEncodeError on Windows when output is redirected (cp1252 default)."""
|
|
49
|
+
for stream in (sys.stdout, sys.stderr):
|
|
50
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
51
|
+
if reconfigure is not None:
|
|
52
|
+
try:
|
|
53
|
+
reconfigure(encoding="utf-8", errors="replace")
|
|
54
|
+
except (OSError, ValueError):
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _version_callback(value: bool) -> None:
|
|
59
|
+
if value:
|
|
60
|
+
typer.echo(f"promptpump {__version__}")
|
|
61
|
+
raise typer.Exit()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@app.callback()
|
|
65
|
+
def main(
|
|
66
|
+
version: Annotated[
|
|
67
|
+
Optional[bool],
|
|
68
|
+
typer.Option("--version", callback=_version_callback, is_eager=True, help="Show version."),
|
|
69
|
+
] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
"""PromptPump: deterministic context engineering for coding prompts."""
|
|
72
|
+
_force_utf8()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@app.command()
|
|
76
|
+
def run(
|
|
77
|
+
prompt: Annotated[str, typer.Argument(help="Shorthand prompt, e.g. 'add jwt auth'.")],
|
|
78
|
+
stack: Annotated[
|
|
79
|
+
Optional[list[str]],
|
|
80
|
+
typer.Option("--stack", "-s", help="Stack rules to inject (repeatable). See `stacks`."),
|
|
81
|
+
] = None,
|
|
82
|
+
copy: Annotated[
|
|
83
|
+
bool, typer.Option("--copy/--no-copy", help="Copy the result to the clipboard.")
|
|
84
|
+
] = True,
|
|
85
|
+
path: Annotated[
|
|
86
|
+
Path,
|
|
87
|
+
typer.Option("--path", "-p", exists=True, file_okay=False, resolve_path=True,
|
|
88
|
+
help="Project directory to scan."),
|
|
89
|
+
] = Path("."),
|
|
90
|
+
model: Annotated[
|
|
91
|
+
str, typer.Option("--model", "-m", envvar="PROMPTPUMP_MODEL", help="Ollama model name.")
|
|
92
|
+
] = DEFAULT_MODEL,
|
|
93
|
+
host: Annotated[
|
|
94
|
+
str, typer.Option("--host", envvar="PROMPTPUMP_HOST", help="Ollama base URL.")
|
|
95
|
+
] = DEFAULT_HOST,
|
|
96
|
+
max_context_tokens: Annotated[
|
|
97
|
+
int, typer.Option("--max-context-tokens", min=500, help="Workspace context budget.")
|
|
98
|
+
] = 3000,
|
|
99
|
+
ground: Annotated[
|
|
100
|
+
bool,
|
|
101
|
+
typer.Option("--ground/--no-ground",
|
|
102
|
+
help="Overwrite <codebase_context> with deterministic scan facts."),
|
|
103
|
+
] = True,
|
|
104
|
+
timeout: Annotated[float, typer.Option(help="Seconds to wait for the model.")] = 300.0,
|
|
105
|
+
dry_run: Annotated[
|
|
106
|
+
bool, typer.Option("--dry-run", help="Print the payload; do not call the model.")
|
|
107
|
+
] = False,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Compile PROMPT into a structured master prompt."""
|
|
110
|
+
try:
|
|
111
|
+
profiles = [get_stack(s) for s in stack or []]
|
|
112
|
+
except UnknownStackError as exc:
|
|
113
|
+
err.print(f"[red]error:[/red] {escape(str(exc))}")
|
|
114
|
+
raise typer.Exit(2) from exc
|
|
115
|
+
|
|
116
|
+
with err.status("Scanning workspace..."):
|
|
117
|
+
context = scan_workspace(path, max_tokens=max_context_tokens)
|
|
118
|
+
err.print(
|
|
119
|
+
f"[dim]Scanned {context.root.name}/: {len(context.tree_lines)} tree entries, "
|
|
120
|
+
f"{len(context.key_files)} key files, {len(context.outlines)} outlined modules[/dim]"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
compiler = PromptCompiler(
|
|
124
|
+
OllamaClient(host=host, model=model, timeout=timeout), ground_context=ground
|
|
125
|
+
)
|
|
126
|
+
stack_names = [p.name for p in profiles]
|
|
127
|
+
|
|
128
|
+
if dry_run:
|
|
129
|
+
for message in compiler.build_messages(prompt, context, stack_names):
|
|
130
|
+
typer.echo(f"===== {message['role'].upper()} =====\n{message['content']}\n")
|
|
131
|
+
raise typer.Exit()
|
|
132
|
+
|
|
133
|
+
start = time.perf_counter()
|
|
134
|
+
try:
|
|
135
|
+
with err.status(f"Compiling with {escape(model)} (local)..."):
|
|
136
|
+
result = compiler.compile(prompt, context, stack_names)
|
|
137
|
+
except PromptPumpError as exc:
|
|
138
|
+
err.print(f"[red]error:[/red] {escape(str(exc))}")
|
|
139
|
+
raise typer.Exit(1) from exc
|
|
140
|
+
elapsed = time.perf_counter() - start
|
|
141
|
+
|
|
142
|
+
if result.missing_tags:
|
|
143
|
+
err.print(
|
|
144
|
+
f"[yellow]warning:[/yellow] model output is missing tags: "
|
|
145
|
+
f"{', '.join(result.missing_tags)}. Try a larger model or rephrase."
|
|
146
|
+
)
|
|
147
|
+
err.print(f"[green]Compiled[/green] in {elapsed:.1f}s ({result.attempts} attempt(s))")
|
|
148
|
+
|
|
149
|
+
typer.echo(result.prompt)
|
|
150
|
+
|
|
151
|
+
if copy:
|
|
152
|
+
if copy_to_clipboard(result.prompt):
|
|
153
|
+
err.print("[green]Copied to clipboard.[/green]")
|
|
154
|
+
else:
|
|
155
|
+
err.print("[yellow]Clipboard unavailable (install xclip/xsel on Linux).[/yellow]")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@app.command()
|
|
159
|
+
def stacks() -> None:
|
|
160
|
+
"""List available --stack profiles."""
|
|
161
|
+
table = Table("Name", "Label", "Rules")
|
|
162
|
+
for profile in list_stacks():
|
|
163
|
+
table.add_row(profile.name, profile.label, str(len(profile.rules)))
|
|
164
|
+
Console().print(table)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@app.command()
|
|
168
|
+
def doctor(
|
|
169
|
+
model: Annotated[str, typer.Option("--model", "-m", envvar="PROMPTPUMP_MODEL")] = DEFAULT_MODEL,
|
|
170
|
+
host: Annotated[str, typer.Option("--host", envvar="PROMPTPUMP_HOST")] = DEFAULT_HOST,
|
|
171
|
+
) -> None:
|
|
172
|
+
"""Check that Ollama is reachable and the model is installed."""
|
|
173
|
+
client = OllamaClient(host=host, model=model)
|
|
174
|
+
try:
|
|
175
|
+
installed = client.list_models()
|
|
176
|
+
except PromptPumpError as exc:
|
|
177
|
+
err.print(f"[red]x[/red] {escape(str(exc))} Start it with `ollama serve`.")
|
|
178
|
+
raise typer.Exit(1) from exc
|
|
179
|
+
err.print(f"[green]ok[/green] Ollama reachable at {host}")
|
|
180
|
+
if any(name == model or name.split(":")[0] == model for name in installed):
|
|
181
|
+
err.print(f"[green]ok[/green] Model '{model}' is installed")
|
|
182
|
+
else:
|
|
183
|
+
err.print(f"[red]x[/red] Model '{model}' missing. Run: ollama pull {model}")
|
|
184
|
+
raise typer.Exit(1)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
app()
|