Ollama settings #5
No files matched your search
@@ -16,6 +16,24 @@ OLLAMA_URL=http://localhost:11434
|
||||
EXTRACT_MODEL=nemotron-3.5-bolt:e4b
|
||||
# ANTHROPIC_API_KEY=
|
||||
|
||||
# Ollama settings. Commented-out lines show the default.
|
||||
# Sampling: leave top P and top K unset to use the model's own.
|
||||
# EXTRACT_TEMPERATURE=0
|
||||
# EXTRACT_TOP_P=0.9
|
||||
# EXTRACT_TOP_K=40
|
||||
# Context size in tokens; raise it if a dense page or thinking runs out of room.
|
||||
# EXTRACT_NUM_CTX=16384
|
||||
# How long Ollama keeps the model loaded after a scan: 10m, 1h, 0 to unload right away, -1 forever.
|
||||
# EXTRACT_KEEP_ALIVE=10m
|
||||
# 1 lets the model reason before answering (slower, needs more context).
|
||||
# EXTRACT_THINK=0
|
||||
# Only with EXTRACT_THINK=1, for models that have levels: low, medium or high.
|
||||
# EXTRACT_THINK_LEVEL=medium
|
||||
|
||||
# 1 reads every page twice and flags where the reads disagree, for the command-line eval in phase0/.
|
||||
# In the app, each source's "double read" setting decides instead.
|
||||
# EXTRACT_DOUBLE_READ=0
|
||||
|
||||
# Labels that are never food or events, for every source (each source can add its own).
|
||||
# EXTRACT_IGNORE=BHS
|
||||
|
||||
|
||||
+5
-1
@@ -5,9 +5,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.0.3] - 2026-11-06
|
||||
|
||||
### Added
|
||||
|
||||
- The server prints its version, commit and commit date, then its settings, when it starts (the API key only as set or unset).
|
||||
- Ollama settings `EXTRACT_TOP_P`, `EXTRACT_TOP_K`, `EXTRACT_THINK_LEVEL` (low, medium or high, with `EXTRACT_THINK=1`), `EXTRACT_NUM_CTX` (default 16384) and `EXTRACT_KEEP_ALIVE` (default 10m).
|
||||
- A "Pack lunch" event's notes are the day's first menu line, for example "Orange Chicken".
|
||||
|
||||
## [0.0.2] - 2026-11-06
|
||||
@@ -45,6 +48,7 @@ First test release: the Phase 1 MVP.
|
||||
- Runs with plain Python or as a Docker image, with SQLite and a `backup` command.
|
||||
- Release workflow that pushes the image to the Gitea container registry: stable releases tag `X.Y.Z`, `X.Y`, `X` and `latest`; pre-releases tag `X.Y.Z` and `dev`.
|
||||
|
||||
[Unreleased]: https://git.dou.bet/iamdoubz/parentcalendar/compare/v0.0.2...main
|
||||
[Unreleased]: https://git.dou.bet/iamdoubz/parentcalendar/compare/v0.0.3...main
|
||||
[0.0.3]: https://git.dou.bet/iamdoubz/parentcalendar/compare/v0.0.2...v0.0.3
|
||||
[0.0.2]: https://git.dou.bet/iamdoubz/parentcalendar/compare/v0.0.1...v0.0.2
|
||||
[0.0.1]: https://git.dou.bet/iamdoubz/parentcalendar/src/tag/v0.0.1
|
||||
@@ -96,6 +96,11 @@ Both include `python main.py backup <destination>`, which runs SQLite's online b
|
||||
| `DATA_DIR` | Database and images; must be a local disk | `./data` when run directly, `/data` in Docker |
|
||||
| `OLLAMA_URL` | Ollama server for the extraction model | `http://localhost:11434` |
|
||||
| `EXTRACT_MODEL` | Ollama model name, or a `claude-*` model to use the Anthropic API instead | `nemotron-3.5-bolt:e4b` |
|
||||
| `EXTRACT_TEMPERATURE`, `EXTRACT_TOP_P`, `EXTRACT_TOP_K` | Ollama sampling settings. Top P and top K fall back to the model's own when not set | `0`, not set, not set |
|
||||
| `EXTRACT_NUM_CTX` | Ollama context size in tokens. Raise it if a dense page or thinking runs out of room | `16384` |
|
||||
| `EXTRACT_KEEP_ALIVE` | How long Ollama keeps the model loaded after a call: `10m`, `1h`, `0` to unload, `-1` forever | `10m` |
|
||||
| `EXTRACT_THINK` | `1` to let an Ollama model reason before answering | `0` |
|
||||
| `EXTRACT_THINK_LEVEL` | `low`, `medium` or `high`, for models with thinking levels. Only used with `EXTRACT_THINK=1` | Not set |
|
||||
| `ANTHROPIC_API_KEY` | Only needed for a `claude-*` model | Not set |
|
||||
| `EXTRACT_IGNORE` | Comma-separated labels dropped from every source's menu items and event titles. Each source can add its own in `ignore_labels` | Not set; for example `BHS,Milk` |
|
||||
| `HOST`, `PORT` | Bind address | `127.0.0.1`, `8000` |
|
||||
|
||||
@@ -43,7 +43,10 @@ def serve():
|
||||
settings = { # what the app actually uses, defaults included
|
||||
"PUBLIC_URL": config.PUBLIC_URL, "DATA_DIR": config.DATA_DIR, "HOST": config.HOST, "PORT": config.PORT,
|
||||
"OLLAMA_URL": extraction.OLLAMA_URL, "EXTRACT_MODEL": extraction.MODEL, "EXTRACT_THINK": int(extraction.THINK),
|
||||
"EXTRACT_TEMPERATURE": extraction.TEMPERATURE, "EXTRACT_DOUBLE_READ": int(extraction.DOUBLE_READ),
|
||||
"EXTRACT_THINK_LEVEL": extraction.THINK_LEVEL or "", "EXTRACT_TEMPERATURE": extraction.TEMPERATURE,
|
||||
"EXTRACT_TOP_P": "" if extraction.TOP_P is None else extraction.TOP_P,
|
||||
"EXTRACT_TOP_K": "" if extraction.TOP_K is None else extraction.TOP_K,
|
||||
"EXTRACT_NUM_CTX": extraction.NUM_CTX, "EXTRACT_KEEP_ALIVE": extraction.KEEP_ALIVE, "EXTRACT_DOUBLE_READ": int(extraction.DOUBLE_READ),
|
||||
"EXTRACT_IGNORE": ",".join(sorted(extraction.IGNORE)), "IMAGE_RETENTION_DAYS": config.IMAGE_RETENTION_DAYS,
|
||||
"ANTHROPIC_API_KEY": "set" if env("ANTHROPIC_API_KEY") else "unset", # never print the key
|
||||
}
|
||||
|
||||
@@ -6,7 +6,12 @@ Settings (environment variables):
|
||||
EXTRACT_MODEL Ollama model, or a claude-* model for the Anthropic API (default nemotron-3.5-bolt:e4b)
|
||||
OLLAMA_URL Ollama server (default http://localhost:11434)
|
||||
EXTRACT_THINK 1 to let an Ollama model reason before answering (default 0)
|
||||
EXTRACT_THINK_LEVEL low, medium or high, for models with thinking levels; only used with EXTRACT_THINK=1
|
||||
(default not set: plain on)
|
||||
EXTRACT_TEMPERATURE Ollama sampling temperature (default 0)
|
||||
EXTRACT_TOP_P, EXTRACT_TOP_K Ollama sampling top_p (0-1) and top_k (whole number) (default not set: the model's own)
|
||||
EXTRACT_NUM_CTX Ollama context size in tokens; raise it if a dense page or thinking runs out of room (default 16384)
|
||||
EXTRACT_KEEP_ALIVE how long Ollama keeps the model loaded after a call: 10m, 1h, 0 to unload, -1 forever (default 10m)
|
||||
EXTRACT_DOUBLE_READ 1 to read every page twice and flag where the reads disagree (default 0;
|
||||
in the app each source's double_read setting decides)
|
||||
EXTRACT_IGNORE comma-separated labels to drop from menu items and event titles, e.g. "BHS,Milk" (default none)
|
||||
@@ -40,6 +45,16 @@ MODEL = os.environ.get("EXTRACT_MODEL", "nemotron-3.5-bolt:e4b")
|
||||
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434").rstrip("/")
|
||||
THINK = os.environ.get("EXTRACT_THINK") == "1"
|
||||
TEMPERATURE = float(os.environ.get("EXTRACT_TEMPERATURE", "0"))
|
||||
TOP_P = float(os.environ["EXTRACT_TOP_P"]) if os.environ.get("EXTRACT_TOP_P") else None
|
||||
TOP_K = int(os.environ["EXTRACT_TOP_K"]) if os.environ.get("EXTRACT_TOP_K") else None
|
||||
NUM_CTX = int(os.environ.get("EXTRACT_NUM_CTX") or 16384)
|
||||
KEEP_ALIVE = os.environ.get("EXTRACT_KEEP_ALIVE", "").strip() or "10m"
|
||||
THINK_LEVEL = os.environ.get("EXTRACT_THINK_LEVEL", "").strip().lower() or None
|
||||
if THINK_LEVEL not in (None, "low", "medium", "high"):
|
||||
raise SystemExit(f"EXTRACT_THINK_LEVEL must be low, medium or high, not {THINK_LEVEL!r}")
|
||||
OLLAMA_THINK = THINK_LEVEL if THINK and THINK_LEVEL else THINK # what Ollama's "think" field gets
|
||||
OLLAMA_OPTIONS = {"num_ctx": NUM_CTX, "temperature": TEMPERATURE,
|
||||
**({"top_p": TOP_P} if TOP_P is not None else {}), **({"top_k": TOP_K} if TOP_K is not None else {})}
|
||||
DOUBLE_READ = os.environ.get("EXTRACT_DOUBLE_READ") == "1"
|
||||
IGNORE = {w.strip().lower() for w in os.environ.get("EXTRACT_IGNORE", "").split(",") if w.strip()}
|
||||
EFFORT = "high" # Claude only
|
||||
@@ -283,8 +298,9 @@ def call_claude(image, message, system, schema):
|
||||
|
||||
def call_ollama(image, message, system, schema):
|
||||
body = {
|
||||
"model": MODEL, "stream": False, "think": THINK, "format": schema,
|
||||
"options": {"num_ctx": 16384, "temperature": TEMPERATURE}, # ponytail: raise num_ctx if a dense page or thinking runs out of room
|
||||
"model": MODEL, "stream": False, "think": OLLAMA_THINK, "format": schema, "options": OLLAMA_OPTIONS,
|
||||
# Ollama wants a number for bare seconds ("300" isn't a duration), a string for "10m".
|
||||
"keep_alive": int(KEEP_ALIVE) if KEEP_ALIVE.lstrip("-").isdigit() else KEEP_ALIVE,
|
||||
"messages": [{"role": "system", "content": system},
|
||||
{"role": "user", "content": message, "images": [image]}],
|
||||
}
|
||||
@@ -489,8 +505,11 @@ def extract_image(img, hint, double_read=None, ignore=None):
|
||||
return {
|
||||
"model": model,
|
||||
"method": method + (" x2" if double_read else ""),
|
||||
"think": THINK if call is call_ollama else None,
|
||||
"think": OLLAMA_THINK if call is call_ollama else None,
|
||||
"temperature": TEMPERATURE if call is call_ollama else None,
|
||||
"top_p": TOP_P if call is call_ollama else None,
|
||||
"top_k": TOP_K if call is call_ollama else None,
|
||||
"num_ctx": NUM_CTX if call is call_ollama else None,
|
||||
"seconds": round(time.time() - started, 1),
|
||||
"usage": {"input_tokens": tokens[0], "output_tokens": tokens[1]},
|
||||
"result": result,
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ def main(names):
|
||||
cases = [GOLDEN / f"{n}.json" for n in names] or sorted(GOLDEN.glob("*.json"))
|
||||
out = RUNS / datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
out.mkdir(parents=True)
|
||||
ollama = "" if x.MODEL.startswith("claude") else f" at {x.OLLAMA_URL}, think={x.THINK}, temperature={x.TEMPERATURE}"
|
||||
ollama = "" if x.MODEL.startswith("claude") else f" at {x.OLLAMA_URL}, think={x.OLLAMA_THINK}, temperature={x.TEMPERATURE}, top_p={x.TOP_P}, top_k={x.TOP_K}, num_ctx={x.NUM_CTX}, keep_alive={x.KEEP_ALIVE}"
|
||||
print(f"Model: {x.MODEL}{ollama}")
|
||||
tokens_in = tokens_out = 0
|
||||
for path in cases:
|
||||
|
||||
Reference in new issue
Block a user