Files
pxpipe/legacy/python/proxy.py
T
teamchong 437afa4dfe Restructure: archive Python+Rust, prep for TypeScript rewrite
- Move Python proxy + scripts to legacy/python/ (parity oracle during port)
- Delete Rust port (src/rust/) - history preserved in commits 482c967, f094649
- Delete Zig atlas builder (src/zig/) - will regenerate from TTF via Node
- Move JetBrainsMono-Regular.ttf to assets/
- Update .gitignore for Node/TS/Wrangler

Next: scaffold TypeScript with dual Node + Cloudflare Workers targets.
2026-05-18 15:22:41 -04:00

976 lines
44 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Experimental Python proxy for testing system-prompt-as-image compression.
Sits between Claude Code and api.anthropic.com. Forwards Claude Code's own auth
(OAuth bearer + headers) untouched. When COMPRESS_SYSTEM is set, intercepts the
request body and rewrites the system prompt as image content blocks rendered
with a popular terminal font (Menlo) at small pt-size so Anthropic's vision
encoder can OCR it. Logs the full token breakdown (input / output / cache_read /
cache_create) so we can measure the actual win/loss vs plain text.
Usage:
PORT=47821 COMPRESS_SYSTEM=1 python3 proxy_py.py
# in another shell:
ANTHROPIC_BASE_URL=http://127.0.0.1:47821 claude -p "..."
"""
from __future__ import annotations
import base64, io, json, os, sys, threading, traceback
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import httpx
from PIL import Image, ImageDraw, ImageFont
PORT = int(os.environ.get("PORT", "47821"))
COMPRESS = os.environ.get("COMPRESS_SYSTEM", "0") == "1"
FONT_PATH = os.environ.get("FONT_PATH", "/System/Library/Fonts/Menlo.ttc")
FONT_SIZE = int(os.environ.get("FONT_SIZE", "5")) # 5pt verified OCR=99.7% on Opus 4.7
MAX_EDGE = 1568 # Anthropic resizes larger images, destroying tiny-font OCR
MIN_COMPRESS_CHARS = int(os.environ.get("MIN_COMPRESS_CHARS", "2000"))
UPSTREAM = "https://api.anthropic.com"
# Memoize rendered images so the SAME system prompt across turns produces
# byte-identical PNGs (PIL's PNG encoder has tiny non-determinism that breaks
# Anthropic's prompt cache lookup).
import hashlib
_render_cache: dict[str, list[bytes]] = {}
# Inject COMPRESS_SYSTEM as default value for compress_mode placement
# 'system' : put images in the system field (may not be supported by API)
# 'user' : prepend image to first user message (cache_control on the image)
# 'replace_system' : replace system with an empty text + add image to first user msg
PLACEMENT = os.environ.get("PLACEMENT", "user")
_font_cache: dict[int, ImageFont.FreeTypeFont] = {}
def get_font(size: int) -> ImageFont.FreeTypeFont:
if size not in _font_cache:
_font_cache[size] = ImageFont.truetype(FONT_PATH, size)
return _font_cache[size]
_render_dims_cache: dict[str, list[tuple[int, int]]] = {}
def render_chunks(text: str, font_size: int = FONT_SIZE) -> list[bytes]:
"""Render text into the MINIMUM number of MAXIMALLY-PACKED images.
Layout strategy: NEWSPAPER (multi-column). For 26K-char system prompt
rendered at 5pt, a single-column layout would be ~3600 px tall (exceeds
1568 cap → forces multiple images + per-image overhead). Multi-column
packs the same text into a SQUAREish image: width = N_cols × col_width,
height ≤ 1568. One image avoids per-image overhead doubling.
Memoized on text content so the same prompt across turns yields BYTE-
IDENTICAL PNG (PIL's PNG encoder has tiny non-determinism that breaks
Anthropic's prompt cache hash if not memoized).
"""
key = hashlib.sha256(f"{font_size}:{text}".encode()).hexdigest()
if key in _render_cache:
return _render_cache[key]
font = get_font(font_size)
asc, desc = font.getmetrics()
line_h = asc + desc
char_w = font.getlength("M") or (font_size * 0.6)
col_gap_px = 4 # tighter gap — every pixel matters
edge = MAX_EDGE
# Minify: kill trailing whitespace + collapse runs of blank lines.
# Critical because system prompt has lots of blank lines that waste rows.
raw = []
last_blank = False
for ln in text.split("\n"):
ln = ln.rstrip()
if ln == "":
if last_blank:
continue
last_blank = True
else:
last_blank = False
raw.append(ln if ln else " ")
# Force aggressive wrapping at FIXED_COL_CHARS. Narrower cols pack better:
# short lines (bullets, headers) waste the unused chars in their row.
FIXED_COL_CHARS = int(os.environ.get("COL_CHARS", "80"))
lines: list[str] = []
for ln in raw:
if len(ln) <= FIXED_COL_CHARS:
lines.append(ln)
else:
for i in range(0, len(ln), FIXED_COL_CHARS):
lines.append(ln[i:i + FIXED_COL_CHARS])
col_w_px = int(FIXED_COL_CHARS * char_w) + 1
lines_per_col = max(8, edge // line_h)
n_cols_total = max(1, (len(lines) + lines_per_col - 1) // lines_per_col)
img_w = n_cols_total * col_w_px + (n_cols_total - 1) * col_gap_px
pngs: list[bytes] = []
dims: list[tuple[int, int]] = []
max_cols_per_img = max(1, edge // (col_w_px + col_gap_px))
lines_per_img = lines_per_col * max_cols_per_img
for s in range(0, len(lines), lines_per_img):
chunk = lines[s:s + lines_per_img]
c_needed = max(1, (len(chunk) + lines_per_col - 1) // lines_per_col)
# Width: ONLY as wide as the cols actually used in this image
chunk_img_w = c_needed * col_w_px + (c_needed - 1) * col_gap_px
# Height: ONLY as tall as the tallest column in this image
max_col_lines = min(lines_per_col, len(chunk) - (c_needed - 1) * lines_per_col)
if c_needed > 1:
# Earlier cols are full, last col may be partial
tallest = lines_per_col if c_needed > 1 else len(chunk)
else:
tallest = len(chunk)
# All non-last columns are full lines_per_col; last col has the remainder.
# Single-column case → tight bound (just last_col_lines, no canvas pad).
# Multi-column case → all earlier cols are full lines_per_col tall, so
# the image must be lines_per_col rows tall to fit them.
last_col_lines = len(chunk) - (c_needed - 1) * lines_per_col
tallest = max(1, last_col_lines) if c_needed == 1 else lines_per_col
chunk_img_h = line_h * tallest
img = Image.new("L", (chunk_img_w, chunk_img_h), 255)
d = ImageDraw.Draw(img)
for c in range(c_needed):
col_lines = chunk[c * lines_per_col:(c + 1) * lines_per_col]
x = c * (col_w_px + col_gap_px)
for i, ln in enumerate(col_lines):
d.text((x, i * line_h - desc // 2), ln, fill=0, font=font)
buf = io.BytesIO()
# Save as 8-bit grayscale PNG so the rendered image has full contrast
# AND preserves antialiasing. Previously used `P + ADAPTIVE colors=2`
# which picked white+gray instead of white+black on AA-heavy content,
# producing washed-out images that visually look broken (and OCR worse).
# Grayscale PNG bytes are still deterministic → Anthropic cache still hits.
img.save(buf, "PNG", optimize=True)
pngs.append(buf.getvalue())
dims.append((chunk_img_w, chunk_img_h))
_render_cache[key] = pngs
_render_dims_cache[key] = dims
return pngs
def render_dims(text: str, font_size: int = FONT_SIZE) -> list[tuple[int, int]]:
key = hashlib.sha256(f"{font_size}:{text}".encode()).hexdigest()
if key not in _render_dims_cache:
render_chunks(text, font_size)
return _render_dims_cache.get(key, [])
def image_block(png_bytes: bytes, cache: bool = False) -> dict:
blk = {
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": base64.standard_b64encode(png_bytes).decode("ascii"),
},
}
if cache:
# Match Claude Code's extended cache TTL. If we use ephemeral (5m) here
# while CC uses 1h later in the request, Anthropic rejects with
# "ttl='1h' cache_control must not come after ttl='5m'".
blk["cache_control"] = {"type": "ephemeral", "ttl": "1h"}
return blk
def extract_system_text(system_field) -> tuple[str, list[dict] | str | None]:
"""Return (extracted_text, remainder).
remainder is what should stay in the system field (or None to delete it)."""
if system_field is None:
return "", None
if isinstance(system_field, str):
return system_field, "" # replace with empty string
if isinstance(system_field, list):
# Concatenate all text blocks; keep non-text blocks in place.
text_parts = []
kept = []
for b in system_field:
if isinstance(b, dict) and b.get("type") == "text":
text_parts.append(b.get("text", ""))
else:
kept.append(b)
return "\n\n".join(text_parts), kept
return "", system_field
def transform_request(body: bytes) -> tuple[bytes, dict]:
"""Compress system prompt + tool descriptions to image content."""
info = {"compressed": False}
try:
req = json.loads(body)
except Exception as e:
info["parse_error"] = str(e)
return body, info
sys_field = req.get("system")
text, remainder = extract_system_text(sys_field)
# Strip Claude Code's per-turn-random `x-anthropic-billing-header: ...; cch=<rand>;`
# line so the rest renders byte-identical across turns.
billing_line_kept = None
lines = text.split("\n", 1)
if lines and lines[0].startswith("x-anthropic-billing-header:"):
billing_line_kept = lines[0]
text = lines[1] if len(lines) > 1 else ""
# COMPRESS_TOOLS: move tool descriptions (+ optionally schemas) into the
# same image. Replace each tool's description with a tiny stub.
compress_tools = os.environ.get("COMPRESS_TOOLS", "1") == "1"
compress_schemas = os.environ.get("COMPRESS_SCHEMAS", "1") == "1"
tool_text_added = 0
schemas_compressed = 0
if compress_tools and isinstance(req.get("tools"), list):
tool_doc_blocks = []
for t in req["tools"]:
if not isinstance(t, dict):
continue
name = t.get("name", "?")
desc = t.get("description", "")
doc_part = ""
if desc and len(desc) > 80:
doc_part = f"### Tool: {name}\n{desc}"
t["description"] = f"See `{name}` docs in system context image."
elif desc:
doc_part = f"### Tool: {name}\n{desc}"
# Compress input_schema: serialize full schema to text inside the
# image, replace tools[].input_schema with a permissive stub. The
# model still emits well-formed tool_use because it sees the real
# schema in the image; Anthropic accepts any JSON object against
# the {"type":"object"} placeholder.
if compress_schemas and isinstance(t.get("input_schema"), dict):
schema_json = json.dumps(t["input_schema"], indent=1)
if len(schema_json) > 200: # only worth it for non-trivial schemas
doc_part += f"\n#### Schema for `{name}`\n```json\n{schema_json}\n```"
t["input_schema"] = {"type": "object"}
schemas_compressed += 1
if doc_part:
tool_doc_blocks.append(doc_part)
if tool_doc_blocks:
tool_section = "\n\n# Tool Documentation\n\n" + "\n\n".join(tool_doc_blocks)
text = text + tool_section
tool_text_added = len(tool_section)
info["tool_text_added"] = tool_text_added
info["schemas_compressed"] = schemas_compressed
info["system_text_chars"] = len(text)
info["system_text_sha8"] = hashlib.sha256(text.encode()).hexdigest()[:8]
# Dump every system text we see to /tmp so we can diff what changes.
if os.environ.get("DUMP_SYSTEM") == "1":
n = 0
while os.path.exists(f"/tmp/sys_dump_{n}.txt"):
n += 1
with open(f"/tmp/sys_dump_{n}.txt", "w") as f:
f.write(text)
if len(text) < MIN_COMPRESS_CHARS:
info["skipped"] = f"system <{MIN_COMPRESS_CHARS} chars"
return body, info
pngs = render_chunks(text)
dims = render_dims(text)
info["png_sha8"] = [hashlib.sha256(p).hexdigest()[:8] for p in pngs]
info["dims"] = dims
info["total_pixels"] = sum(w * h for w, h in dims)
info["expected_image_tokens"] = sum(max(1, (w * h) // 750) for w, h in dims) + 85 * len(dims)
info["text_tokens_estimate"] = len(text) // 4
info["images"] = len(pngs)
info["png_bytes"] = sum(len(p) for p in pngs)
# Stash the FIRST image for the dashboard preview (so users can SEE what
# we're sending). Cropped to a reasonable size so the page doesn't blow up.
if pngs:
with _session_stats["lock"]:
_session_stats["latest_png_bytes"] = pngs[0]
w0, h0 = dims[0] if dims else (0, 0)
_session_stats["latest_png_meta"] = (
f"{len(pngs)} image(s), {w0}×{h0}px, "
f"{sum(len(p) for p in pngs)} bytes total — "
f"compressed {info['system_text_chars']:,} chars "
f"({info.get('text_tokens_estimate',0):,}→~{info['expected_image_tokens']:,} tokens)"
)
# Anthropic caps cache_control breakpoints at 4 per request. The model's
# cache lookup matches the LONGEST cached prefix, so we only need ONE
# well-placed breakpoint — on the last image of the system+tools render.
# Reminders and tool_result images get NO cache_control (they're still
# in the cached prefix by virtue of position).
image_blocks = [image_block(p, cache=(i == len(pngs)-1))
for i, p in enumerate(pngs)]
info["cc_breakpoints_added"] = 1
msgs = req.get("messages", [])
if PLACEMENT in ("user", "replace_system"):
# Prepend image blocks to first user message as a "context" frame
prefix_text = ("[Context (rendered as image for token efficiency, "
"OCR carefully and treat as authoritative system instructions):]")
first_idx = None
for i, m in enumerate(msgs):
if m.get("role") == "user":
first_idx = i
break
if first_idx is None:
info["skipped"] = "no user message to attach image to"
return body, info
target = msgs[first_idx]
content = target.get("content", "")
if isinstance(content, str):
content = [{"type": "text", "text": content}]
elif not isinstance(content, list):
content = [{"type": "text", "text": str(content)}]
# Compress CC-injected <system-reminder> blocks in first user message.
# These are large static blobs (skill listings, project context) that
# CC injects every turn — perfect cache candidates as images.
# Targeted: ONLY compress blocks that start with <system-reminder>,
# leaving the user's actual prompt (and any other content) as text.
compress_reminders = os.environ.get("COMPRESS_REMINDERS", "1") == "1"
reminder_imgs_added = 0
if compress_reminders and isinstance(content, list):
new_content_parts = []
for blk in content:
txt = blk.get("text", "") if isinstance(blk, dict) and blk.get("type") == "text" else ""
# Heuristic: long system-reminder-style blocks. Cover both the
# opening tag style and large generic system blocks.
is_reminder = txt.lstrip().startswith("<system-reminder>") and len(txt) > 1000
if is_reminder:
extra_pngs = render_chunks(txt)
# NO cache_control: Anthropic caps at 4 breakpoints; the
# system+tools image already anchors the cacheable prefix.
for p in extra_pngs:
new_content_parts.append(image_block(p, cache=False))
reminder_imgs_added += 1
else:
new_content_parts.append(blk)
content = new_content_parts
info["reminder_imgs"] = reminder_imgs_added
new_content = (
[{"type": "text", "text": prefix_text}]
+ image_blocks
+ [{"type": "text", "text": "[End context.]"}]
+ content
)
msgs[first_idx] = {**target, "content": new_content}
# COMPRESS_TOOL_RESULTS: walk ALL user messages and image-compress any
# large tool_result text content. Tool results accumulate in history as
# files are read; compressing them at the source compounds per-turn
# savings across the rest of the session.
compress_tr = os.environ.get("COMPRESS_TOOL_RESULTS", "1") == "1"
tr_imgs_added = 0
if compress_tr:
for mi, m in enumerate(msgs):
if m.get("role") != "user":
continue
content_list = m.get("content")
if not isinstance(content_list, list):
continue
changed = False
new_blocks = []
for blk in content_list:
if (isinstance(blk, dict) and blk.get("type") == "tool_result"):
# Anthropic API constraint: when is_error=true, the
# tool_result content MUST be type=text only (no images).
# Leave error tool_results untouched.
if blk.get("is_error") is True:
new_blocks.append(blk)
continue
inner = blk.get("content")
# tool_result.content can be str or list[block]
# NO cache_control on tool_result images (Anthropic
# caps at 4 breakpoints, and these aren't useful as
# cache anchors — they change every session).
if isinstance(inner, str) and len(inner) > 2000:
pngs_tr = render_chunks(inner)
new_inner = [image_block(p, cache=False)
for p in pngs_tr]
blk = {**blk, "content": new_inner}
tr_imgs_added += len(pngs_tr)
changed = True
elif isinstance(inner, list):
new_inner = []
for ib in inner:
if (isinstance(ib, dict) and ib.get("type") == "text"
and len(ib.get("text", "")) > 2000):
pngs_tr = render_chunks(ib["text"])
for p in pngs_tr:
new_inner.append(image_block(p, cache=False))
tr_imgs_added += len(pngs_tr)
changed = True
else:
new_inner.append(ib)
blk = {**blk, "content": new_inner}
new_blocks.append(blk)
if changed:
msgs[mi] = {**m, "content": new_blocks}
info["tool_result_imgs"] = tr_imgs_added
req["messages"] = msgs
if PLACEMENT == "replace_system":
req["system"] = "Follow the instructions in the first image of the user message exactly."
elif billing_line_kept is not None:
# Replace original system with JUST the billing header line (small, stable
# in spirit but per-turn random — keep it as text so it doesn't pollute
# our cacheable image).
req["system"] = billing_line_kept
# else: leave system unchanged so Anthropic still has guardrails
info["placement"] = PLACEMENT
else:
# PLACEMENT == 'system': put images directly into system field
new_sys = []
if isinstance(remainder, list):
new_sys.extend(remainder)
new_sys.extend(image_blocks)
req["system"] = new_sys
info["placement"] = "system"
info["compressed"] = True
return json.dumps(req).encode(), info
# Running session totals so users can see live savings.
# Persisted to ~/.cache/pixelpipe/stats.json on every update so
# restarts don't wipe history. Recent feed + latest PNG stay in-memory only.
import threading, time, collections, pathlib
_STATS_DIR = pathlib.Path.home() / ".cache" / "pixelpipe"
_STATS_FILE = _STATS_DIR / "stats.json" # cumulative totals (rewritten atomically)
_REQUESTS_FILE = _STATS_DIR / "requests.jsonl" # full per-request log (append-only)
_REQUESTS_ROTATE_BYTES = 10 * 1024 * 1024 # rotate at 10 MB
_session_stats = {
"requests": 0,
"compressed_requests": 0,
"effective_input_actual": 0.0,
"effective_input_baseline_est": 0.0,
"started_at": time.time(),
"first_seen_at": time.time(), # persists across restarts; "uptime since first install"
"recent": collections.deque(maxlen=50), # in-memory only — restart resets
"latest_png_bytes": None, # in-memory only
"latest_png_meta": "",
"lock": threading.Lock(),
}
def _load_persisted_stats():
"""Load cumulative totals + recent request history on startup."""
try:
if _STATS_FILE.exists():
with open(_STATS_FILE) as f:
d = json.load(f)
_session_stats["requests"] = int(d.get("requests", 0))
_session_stats["compressed_requests"] = int(d.get("compressed_requests", 0))
_session_stats["effective_input_actual"] = float(d.get("effective_input_actual", 0.0))
_session_stats["effective_input_baseline_est"] = float(d.get("effective_input_baseline_est", 0.0))
_session_stats["first_seen_at"] = float(d.get("first_seen_at", time.time()))
saved = _session_stats["effective_input_baseline_est"] - _session_stats["effective_input_actual"]
print(f"[PROXY] loaded persisted stats: {_session_stats['requests']} requests, "
f"~{saved:.0f} effective tokens saved (~${saved * 15.0 / 1e6:.4f})", flush=True)
except Exception as e:
print(f"[PROXY] could not load persisted stats: {e}", flush=True)
# Replay last N entries from requests.jsonl into the in-memory recent feed
try:
if _REQUESTS_FILE.exists():
tail = collections.deque(maxlen=_session_stats["recent"].maxlen)
with open(_REQUESTS_FILE) as f:
for line in f:
line = line.strip()
if not line: continue
try:
tail.append(json.loads(line))
except Exception:
pass
_session_stats["recent"].extend(tail)
if tail:
print(f"[PROXY] replayed {len(tail)} recent requests from {_REQUESTS_FILE.name}",
flush=True)
except Exception as e:
print(f"[PROXY] could not load request history: {e}", flush=True)
def _persist_stats():
"""Atomically rewrite cumulative totals."""
try:
_STATS_DIR.mkdir(parents=True, exist_ok=True)
payload = {
"requests": _session_stats["requests"],
"compressed_requests": _session_stats["compressed_requests"],
"effective_input_actual": _session_stats["effective_input_actual"],
"effective_input_baseline_est": _session_stats["effective_input_baseline_est"],
"first_seen_at": _session_stats["first_seen_at"],
"saved_at": time.time(),
}
tmp = _STATS_FILE.with_suffix(".json.tmp")
with open(tmp, "w") as f:
json.dump(payload, f, indent=2)
tmp.replace(_STATS_FILE)
except Exception as e:
print(f"[PROXY] could not persist stats: {e}", flush=True)
def _append_request_log(entry: dict):
"""Append one JSONL line for the per-request log. Rotate when oversize."""
try:
_STATS_DIR.mkdir(parents=True, exist_ok=True)
# Rotate if file is too big
if _REQUESTS_FILE.exists() and _REQUESTS_FILE.stat().st_size > _REQUESTS_ROTATE_BYTES:
rotated = _STATS_DIR / "requests.jsonl.1"
try: rotated.unlink()
except FileNotFoundError: pass
_REQUESTS_FILE.rename(rotated)
with open(_REQUESTS_FILE, "a") as f:
f.write(json.dumps(entry, separators=(",", ":")) + "\n")
except Exception as e:
# Don't crash request handling on disk errors
print(f"[PROXY] could not append request log: {e}", flush=True)
_load_persisted_stats()
DASHBOARD_HTML = """<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pixelpipe — live dashboard</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; padding: 24px; background: #0d1117; color: #c9d1d9;
font: 14px/1.45 -apple-system,BlinkMacSystemFont,"SF Mono",Menlo,monospace; }
h1 { font-size: 18px; font-weight: 600; margin: 0 0 6px; letter-spacing: -0.01em; }
.sub { color: #6e7681; font-size: 12px; margin-bottom: 22px; }
.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 22px; }
.card { background: #161b22; border: 1px solid #30363d; border-radius: 10px;
padding: 14px 16px; }
.card .label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
color: #8b949e; margin-bottom: 6px; }
.card .value { font-size: 24px; font-weight: 600; color: #e6edf3; font-variant-numeric: tabular-nums; }
.card .small { font-size: 11px; color: #6e7681; margin-top: 4px; }
.pos { color: #3fb950 !important; }
.panel { background: #161b22; border: 1px solid #30363d; border-radius: 10px;
padding: 14px 16px; margin-bottom: 14px; }
.panel h2 { font-size: 13px; font-weight: 600; color: #8b949e; margin: 0 0 10px;
text-transform: uppercase; letter-spacing: 0.08em; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th { text-align: left; color: #6e7681; font-weight: 500; padding: 6px 8px;
border-bottom: 1px solid #30363d; font-variant-numeric: tabular-nums; }
th.num { text-align: right; }
td { padding: 6px 8px; border-bottom: 1px solid #21262d; font-variant-numeric: tabular-nums; }
tr:last-child td { border-bottom: none; }
td.num { text-align: right; }
td.good { color: #3fb950; }
td.warn { color: #d29922; }
td.bad { color: #f85149; }
img.preview { max-width: 100%; image-rendering: pixelated; border: 1px solid #30363d;
background: #fff; padding: 4px; border-radius: 4px; }
.row { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr 1fr; } .row { grid-template-columns: 1fr; } }
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
background: #3fb950; margin-right: 6px; vertical-align: middle;
animation: pulse 2s infinite; }
@keyframes pulse { 50% { opacity: 0.4; } }
</style>
</head>
<body>
<h1><span class="dot"></span>pixelpipe</h1>
<div class="sub" id="sub">connecting...</div>
<div class="grid">
<div class="card"><div class="label">requests</div>
<div class="value" id="m_req">0</div>
<div class="small" id="m_req_sub">— compressed</div>
</div>
<div class="card"><div class="label">tokens saved</div>
<div class="value pos" id="m_saved">0</div>
<div class="small" id="m_saved_sub">effective input tokens</div>
</div>
<div class="card"><div class="label">$ saved (opus 4.7)</div>
<div class="value pos" id="m_usd">$0.00</div>
<div class="small" id="m_usd_sub">at $15/M input tokens</div>
</div>
<div class="card"><div class="label">reduction</div>
<div class="value pos" id="m_pct">0%</div>
<div class="small" id="m_pct_sub">vs uncompressed baseline</div>
</div>
</div>
<div class="row">
<div class="panel">
<h2>recent requests</h2>
<table>
<thead>
<tr>
<th>#</th><th>status</th><th>path</th><th class="num">size in</th>
<th class="num">cc</th><th class="num">img tok</th>
<th class="num">actual</th><th class="num">saved</th>
</tr>
</thead>
<tbody id="rows"></tbody>
</table>
</div>
<div class="panel">
<h2>latest rendered image</h2>
<div id="preview_wrap"><div class="sub">(none yet)</div></div>
<div class="small" id="preview_meta" style="margin-top:8px;color:#6e7681"></div>
</div>
</div>
<script>
async function tick() {
try {
const s = await fetch('/proxy-stats').then(r => r.json());
const r = await fetch('/proxy-recent').then(r => r.json());
document.getElementById('sub').textContent =
`port :__PORT__ · uptime ${formatDuration(s.uptime_sec)} · live`;
document.getElementById('m_req').textContent = s.requests;
document.getElementById('m_req_sub').textContent = `${s.compressed_requests} compressed`;
document.getElementById('m_saved').textContent = numFmt(s.saved_effective_tokens);
document.getElementById('m_saved_sub').textContent =
`${numFmt(s.effective_input_actual)} paid · ${numFmt(s.effective_input_baseline_est)} baseline`;
document.getElementById('m_usd').textContent = `$${s.saved_usd_opus47.toFixed(4)}`;
document.getElementById('m_pct').textContent = `${s.saved_pct.toFixed(1)}%`;
const tbody = document.getElementById('rows');
tbody.innerHTML = '';
let i = 0;
for (const e of r.recent.slice().reverse()) {
const tr = document.createElement('tr');
const statusCls = e.status >= 500 ? 'bad' : e.status >= 400 ? 'warn' : 'good';
const saved = (e.session_saved_so_far_delta || 0);
tr.innerHTML = `
<td>${++i}</td>
<td class="num ${statusCls}">${e.status}</td>
<td>${escapeHtml((e.path || '').slice(0,40))}</td>
<td class="num">${numFmt(e.size_in)}</td>
<td class="num">${e.cc_added ?? ''}</td>
<td class="num">${numFmt(e.expected_image_tokens || 0)}</td>
<td class="num">${numFmt(e.effective_actual || 0)}</td>
<td class="num pos">${saved > 0 ? '+'+numFmt(saved) : ''}</td>`;
tbody.appendChild(tr);
}
if (r.has_preview) {
const wrap = document.getElementById('preview_wrap');
// Show a native-resolution crop so the tiny font is actually readable
// (the full image is 1466×1568, gets unreadably downsampled in the panel).
// Pixelated upscaling via CSS preserves crisp edges.
wrap.innerHTML =
`<img class="preview" src="/proxy-latest-png?crop=480&t=${Date.now()}" `
+ `style="width:100%;image-rendering:pixelated">`;
document.getElementById('preview_meta').textContent =
(r.preview_meta || '') + ' — showing top-left 480×480 crop';
}
} catch (e) {
document.getElementById('sub').textContent = 'proxy unreachable';
}
}
function numFmt(n) {
n = Math.round(Number(n) || 0);
return n.toLocaleString();
}
function escapeHtml(s) {
return String(s).replace(/[&<>"]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
}
function formatDuration(s) {
s = Math.floor(s);
const h = Math.floor(s/3600), m = Math.floor((s%3600)/60), sec = s%60;
return (h>0?h+'h ':'') + (m>0?m+'m ':'') + sec + 's';
}
tick(); setInterval(tick, 2000);
</script>
</body></html>
"""
class ProxyHandler(BaseHTTPRequestHandler):
server_version = "TokenProxy/0.1"
def log_message(self, fmt, *args):
pass
def _serve_stats(self):
with _session_stats["lock"]:
saved = _session_stats["effective_input_baseline_est"] - _session_stats["effective_input_actual"]
pct = (saved / _session_stats["effective_input_baseline_est"] * 100.0
if _session_stats["effective_input_baseline_est"] > 0 else 0)
uptime = time.time() - _session_stats["started_at"]
payload = {
"requests": _session_stats["requests"],
"compressed_requests": _session_stats["compressed_requests"],
"effective_input_actual": round(_session_stats["effective_input_actual"], 1),
"effective_input_baseline_est": round(_session_stats["effective_input_baseline_est"], 1),
"saved_effective_tokens": round(saved, 1),
"saved_pct": round(pct, 1),
"saved_usd_opus47": round(saved * 15.0 / 1e6, 4),
"uptime_sec": uptime,
}
body = json.dumps(payload, indent=2).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def _serve_recent(self):
with _session_stats["lock"]:
recent = list(_session_stats["recent"])
has_preview = _session_stats["latest_png_bytes"] is not None
preview_meta = _session_stats.get("latest_png_meta", "")
body = json.dumps({
"recent": recent,
"has_preview": has_preview,
"preview_meta": preview_meta,
}).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def _serve_latest_png(self):
"""Serve the current rendered image. Supports `?crop=N` to return only
the top-left N×N region at native resolution (so humans can actually
SEE the tiny font — at 1466x1568 full-image scaled to 280px wide
the browser turns the antialiased glyphs into unreadable noise)."""
with _session_stats["lock"]:
data = _session_stats["latest_png_bytes"]
if not data:
self.send_response(404)
self.end_headers()
return
# Parse ?crop=N from query string
crop_n = 0
if "?" in self.path:
qs = self.path.split("?", 1)[1]
for kv in qs.split("&"):
if kv.startswith("crop="):
try: crop_n = int(kv[5:])
except: pass
if crop_n > 0:
try:
img = Image.open(io.BytesIO(data))
cw = min(crop_n, img.width)
ch = min(crop_n, img.height)
cropped = img.crop((0, 0, cw, ch))
buf = io.BytesIO()
cropped.save(buf, "PNG", optimize=True)
data = buf.getvalue()
except Exception:
pass # fall back to full image
self.send_response(200)
self.send_header("Content-Type", "image/png")
self.send_header("Cache-Control", "no-cache")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def _do_proxy(self, method: str):
# Local endpoints — never forwarded to Anthropic.
if method == "GET" and self.path in ("/", "/dashboard"):
html = DASHBOARD_HTML.replace("__PORT__", str(PORT)).encode()
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(html)))
self.end_headers()
self.wfile.write(html)
return
if method == "GET" and self.path == "/proxy-stats":
self._serve_stats()
return
if method == "GET" and self.path == "/proxy-recent":
self._serve_recent()
return
if method == "GET" and self.path.split("?", 1)[0] == "/proxy-latest-png":
self._serve_latest_png()
return
try:
length = int(self.headers.get("Content-Length", "0"))
body = self.rfile.read(length) if length > 0 else b""
# Strip hop-by-hop headers
HOP = {"connection", "keep-alive", "proxy-connection",
"transfer-encoding", "upgrade", "te", "host",
"content-length", "expect", "accept-encoding"}
fwd_headers = {k: v for k, v in self.headers.items()
if k.lower() not in HOP}
fwd_headers.setdefault("anthropic-version", "2023-06-01")
log = {"method": method, "path": self.path, "size_in": len(body)}
if COMPRESS and method == "POST" and self.path.startswith("/v1/messages"):
new_body, info = transform_request(body)
log.update(info)
body = new_body
log["size_after"] = len(body)
with httpx.Client(http2=False, timeout=120.0) as c:
resp = c.request(method, UPSTREAM + self.path,
content=body if body else None,
headers=fwd_headers)
log["status"] = resp.status_code
log["size_out"] = len(resp.content)
log["upstream_ms"] = log.get("upstream_ms") # placeholder if added
# Try plain JSON first; if that fails, parse SSE event stream for usage.
usage = None
try:
usage = resp.json().get("usage")
except Exception:
pass
if not usage and b"event:" in resp.content[:200]:
# SSE: aggregate usage from message_start (input) + message_delta (output).
txt = resp.content.decode("utf-8", errors="replace")
inp = cr = cc = out = 0
for raw in txt.split("\n"):
if not raw.startswith("data: "):
continue
try:
ev = json.loads(raw[6:])
except Exception:
continue
if ev.get("type") == "message_start":
u = ev.get("message", {}).get("usage", {})
inp = u.get("input_tokens", inp)
cr = u.get("cache_read_input_tokens", cr)
cc = u.get("cache_creation_input_tokens", cc)
elif ev.get("type") == "message_delta":
u = ev.get("usage", {})
if "output_tokens" in u:
out = u["output_tokens"]
if inp or out or cr or cc:
usage = {"input_tokens": inp, "output_tokens": out,
"cache_read_input_tokens": cr,
"cache_creation_input_tokens": cc}
if usage:
inp = usage.get("input_tokens", 0) or 0
out = usage.get("output_tokens", 0) or 0
cr = usage.get("cache_read_input_tokens", 0) or 0
cc = usage.get("cache_creation_input_tokens", 0) or 0
eff = inp + cc * 1.25 + cr * 0.10
log["tokens"] = {
"in": inp, "out": out,
"cache_read": cr, "cache_create": cc,
"effective_cost": round(eff, 1),
}
# Update session totals + estimate the baseline (uncompressed) cost.
# Baseline estimate: add back the text-token equivalent of whatever
# we replaced with images. Conservative — assumes baseline would
# also have cached, so we apply the 10% cache_read rate to the
# uncompressed delta.
if log.get("compressed"):
txt_replaced = (log.get("system_text_chars", 0)
+ log.get("tool_text_added", 0)) // 4
img_tokens_est = log.get("expected_image_tokens", 0)
extra_text_input_baseline = max(0, txt_replaced - img_tokens_est)
# CRITICAL: the extra text would have been billed at the
# SAME mix of cache_create/cache_read as the actual call,
# NOT all at cache_read (10%). On cold-start turns where
# cache_create dominates, baseline should be billed at 1.25
# not 0.10 — otherwise we drastically under-estimate the
# savings and the dashboard shows tiny numbers.
cached_total = (cr or 0) + (cc or 0)
if cached_total > 0:
cc_share = (cc or 0) / cached_total
# Effective rate the extra text would have paid:
baseline_rate = cc_share * 1.25 + (1 - cc_share) * 0.10
else:
baseline_rate = 0.10 # fully warm-cache assumption
baseline_eff = eff + extra_text_input_baseline * baseline_rate
else:
baseline_eff = eff
with _session_stats["lock"]:
prev_saved = (_session_stats["effective_input_baseline_est"]
- _session_stats["effective_input_actual"])
_session_stats["requests"] += 1
if log.get("compressed"):
_session_stats["compressed_requests"] += 1
_session_stats["effective_input_actual"] += eff
_session_stats["effective_input_baseline_est"] += baseline_eff
saved_so_far = (_session_stats["effective_input_baseline_est"]
- _session_stats["effective_input_actual"])
# Push compact row for dashboard
row = {
"ts": time.time(),
"method": method,
"path": log.get("path", ""),
"status": log.get("status", 0),
"size_in": log.get("size_in", 0),
"size_out": log.get("size_out", 0),
"compressed": bool(log.get("compressed")),
"cc_added": log.get("cc_breakpoints_added"),
"expected_image_tokens": log.get("expected_image_tokens"),
"input_tokens": inp,
"cache_create": cc,
"cache_read": cr,
"effective_actual": round(eff, 1),
"effective_baseline": round(baseline_eff, 1),
"session_saved_so_far_delta": round(saved_so_far - prev_saved, 1),
}
_session_stats["recent"].append(row)
# Persist cumulative totals (atomic JSON rewrite) + append
# per-request line to the JSONL log so dashboards survive restart.
_persist_stats()
_append_request_log(row)
log["session_saved_so_far"] = round(saved_so_far, 1)
log["session_saved_usd"] = round(saved_so_far * 15.0 / 1e6, 4)
print(f"[PROXY] {json.dumps(log)}", flush=True)
try:
self.send_response(resp.status_code)
for k, v in resp.headers.items():
if k.lower() in HOP or k.lower() == "content-encoding":
continue
self.send_header(k, v)
self.send_header("Content-Length", str(len(resp.content)))
self.end_headers()
self.wfile.write(resp.content)
except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError) as e:
# Client (Claude Code) closed before we finished writing. Common
# on stream timeouts / Ctrl-C / fast aborts. Not fatal — just log.
print(f"[PROXY] client disconnect during response: {type(e).__name__}", flush=True)
except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError) as e:
print(f"[PROXY] transport error: {type(e).__name__}", flush=True)
except Exception as e:
traceback.print_exc()
try:
self.send_response(502)
self.send_header("Content-Type", "application/json")
msg = json.dumps({"error": "proxy_error", "detail": str(e)}).encode()
self.send_header("Content-Length", str(len(msg)))
self.end_headers()
self.wfile.write(msg)
except Exception:
pass
def do_GET(self): self._do_proxy("GET")
def do_POST(self): self._do_proxy("POST")
def do_PUT(self): self._do_proxy("PUT")
def do_DELETE(self): self._do_proxy("DELETE")
def do_HEAD(self): self._do_proxy("HEAD")
def main():
print(f"Python token proxy listening on http://127.0.0.1:{PORT}", flush=True)
print(f" COMPRESS_SYSTEM={COMPRESS} FONT={FONT_PATH}@{FONT_SIZE}pt "
f"PLACEMENT={PLACEMENT} MIN_CHARS={MIN_COMPRESS_CHARS}", flush=True)
srv = ThreadingHTTPServer(("127.0.0.1", PORT), ProxyHandler)
try:
srv.serve_forever()
except KeyboardInterrupt:
srv.shutdown()
if __name__ == "__main__":
main()