"""HTML for the studio. Every string that came from a person or a model is escaped here.
These functions take the plain dicts the engine produces (model_dump output),
so the same data shown on screen is what MCP callers and exports receive.
"""
from __future__ import annotations
import base64
import json
from html import escape
from humantouch.intent import STRENGTH_LABELS
STATE_CLASS = {
'original': 'p-original', 'lightly edited': 'p-light', 'substantially rewritten': 'p-heavy', 'moved': 'p-moved',
'AI-added': 'p-added', 'restored by you': 'p-restored', 'kept by guard': 'p-guard',
'edited by you after generation': 'p-user',
}
STATE_HELP = {
'original': 'exactly as you wrote it', 'lightly edited': 'mostly your wording', 'substantially rewritten': 'reworked from your sentence',
'moved': 'your sentence, in a new place', 'AI-added': 'no counterpart in your text', 'restored by you': 'you put your wording back',
'kept by guard': 'an edit was withheld to protect meaning or protected text', 'edited by you after generation': 'you changed this by hand afterwards',
}
LEVEL_WIDTH = {'none': 0, 'very low': 12, 'low': 30, 'medium': 60, 'high': 100}
HEADER = """
AN EDITOR THAT WORKS UNDERNEATH YOUR VOICE
Edited. Still yours.
HumanTouch helps AI edit your writing without sanding away the parts that make it yours.
Paste something you’ve written. I can tighten it, reshape it, help you continue it, compare versions, or learn the patterns of your voice.
I’ll tell you when I think a revision changes more than style.
"""
FOOTER = """
"""
EMPTY = '
Nothing here yet. This fills in after an edit.
'
def _short(text: str, limit: int = 90) -> str:
text = ' '.join((text or '').split())
return text if len(text) <= limit else text[:limit - 1] + '…'
def change_label(change: dict) -> str:
left = f'“{_short(change["original"], 40)}”' if change['original'] else '(nothing)'
right = f'“{_short(change["revised"], 40)}”' if change['revised'] else '(removed)'
return f'{change["id"]:02d} · {left} → {right} · {change["category"]}'
def summary(result: dict | None, fixture: bool = False) -> str:
if not result:
return ''
a = result['analysis']
s = a['stats']
parts = ['']
if fixture:
parts.append('
Development provider: these edits come from a mechanical test double, not a language model.
{"New language added" if mode == "ghost" else "Edited, not rewritten"}. {escape(a["assistance_note"])}
')
active = s['changes'] - s['changes_restored']
parts.append(f'
{int(active)} edit{"s" if active != 1 else ""} in effect · {int(s["sentences_untouched"])} of {int(s["sentences"])} sentences '
f'exactly yours · {int(s["source_words"])} → {int(s["result_words"])} words
')
for action in result.get('guard_actions', []):
parts.append(f'
{escape(action)}
')
high = [w for w in a['meaning_warnings'] if w['severity'] != 'low']
if high:
parts.append(f'
{len(high)} thing{"s" if len(high) != 1 else ""} to check below: this revision may change more than style.
')
parts.append('
')
for name, est in a['confidence'].items():
parts.append(f'
{escape(name.capitalize())}
{escape(est["level"])} '
f'{escape(est["means"])}
')
parts.append('
')
return ''.join(parts)
def warnings(result: dict | None) -> str:
if not result:
return EMPTY
items = result['analysis']['meaning_warnings']
out = ['
Did I change what you meant?
']
if not items:
out.append('
No warning from the deterministic checks (numbers, dates, names, quotations, links, negation, scope and '
'certainty words). They cannot see a subtle paraphrase, so a read-through is still yours to do.
')
for w in items:
out.append(f'
{escape(w["status"])} {escape(w["what"])}
')
if w['original']:
out.append(f'
Original {escape(w["original"])}
')
if w['revised']:
out.append(f'
Revision {escape(w["revised"])}
')
if w['change_ids']:
out.append(f'
To restore your wording, tick edit{"s" if len(w["change_ids"]) != 1 else ""} '
f'{", ".join(f"{i:02d}" for i in w["change_ids"])} in the ledger.
')
out.append('')
audit = result.get('audit')
if audit:
out.append('
A model’s second reading model judgment
'
'
This is another model call’s opinion, kept separate from the checks above. Each line quotes both texts exactly; '
f'{audit["unverified_dropped"]} line(s) that did not were dropped.
')
out.append('')
return ''.join(out)
def ledger(result: dict | None) -> str:
if not result:
return EMPTY
changes = result['analysis']['changes']
if not changes:
return '
No edits. The text came back exactly as you wrote it.
'
out = ['
Categories describe the kind of difference each edit makes. They are read from the edit itself, '
'not from the model’s account of why.
']
for c in changes:
cls = 'restored' if c['restored'] else 'active'
who = {'you': 'restored by you', 'guard': 'withheld by the meaning guard', 'protected text': 'withheld: protected text'}.get(c.get('restored_by') or '', '')
out.append(
f'CHANGE {c["id"]:02d}{escape(c["category"])}'
+ (f'{escape(who)}' if who else '') + ''
f'
{escape(c["original"]) or "(nothing)"} → '
f'{escape(c["revised"]) or "(removed)"}
'
f'
{escape(c["reason"])} · Voice impact: {c["voice_impact"]} · Meaning impact: {c["meaning_impact"]}
')
out.append('')
return ''.join(out)
def _legend(states: list[str]) -> str:
seen = [s for s in STATE_CLASS if s in states]
return '
' + ''.join(f'{escape(s)}{escape(STATE_HELP[s])}' for s in seen) + '
'
def authorship(result: dict | None) -> str:
if not result:
return EMPTY
prov = result['analysis']['provenance']
counts: dict[str, int] = {}
for p in prov:
counts[p['state']] = counts.get(p['state'], 0) + 1
tally = ', '.join(f'{n} {s}' for s, n in counts.items())
body = ' '.join(f''
f'{escape(p["text"])}{escape(p["state"])}' for p in prov)
return (f'
Where did these words come from? {len(prov)} sentences: {escape(tally)}. '
'This is about awareness, not contamination: added words are not worse words.
'
f'{_legend(list(counts))}
{body}
')
def voice(result: dict | None) -> str:
if not result:
return EMPTY
a = result['analysis']
drift = a['voice_drift']
out = [f'
Voice drift against {escape(drift["reference"])}
'
f'
{escape(drift["summary"])}
']
if drift['shifts']:
out.append('
Habit
Before
Now
Change
')
for s in drift['shifts']:
out.append(f'
{escape(s["label"])}
{s["before"]:g}
{s["after"]:g}
{escape(s["change"])}
')
out.append('
')
out.append('
Authorial distance
How far this revision moved from your text, axis by axis. A navigational aid, not a verdict.
')
for name, axis in a['authorial_distance'].items():
out.append(f'
{escape(name.capitalize())}
'
f'{escape(axis["level"])}{escape(axis["how"])}
')
out.append('
')
if a['preserved_features']:
out.append('
What I kept
' + ''.join(f'
{escape(x)}
' for x in a['preserved_features']) + '
')
out.append('')
return ''.join(out)
def plan_text(intent: dict | None) -> str:
if not intent:
return ''
return ('
I think you want (' + escape(intent['basis']) + '; untick anything I got wrong):
')
def notice_list(items: list[dict]) -> str:
if not items:
return ''
return '
No Voiceprint yet. Add some of your own writing above and build one. Without it, HumanTouch protects the voice '
'of whatever text you paste; with it, it can also notice drift from how you usually write.
Descriptions, not grades. Observed is measured from your samples; inferred is a proxy built on '
'those measurements; model judgment is a model’s reading that quoted your samples.
')
labels = {'keep': 'you said: keep this', 'not_me': 'you said: that isn’t me', 'more': 'you said: more of this', 'less': 'you said: less of this',
'never_imitate': 'you said: never imitate this'}
for d in vp['dimensions']:
corrected = f'{escape(labels[d["correction"]])}' if d.get('correction') else ''
evidence = ''.join(f'{escape(e)}' for e in d['evidence'])
out.append(f'{escape(d["name"].capitalize())}'
f'{escape(d["basis"])}confidence: {escape(d["confidence"])}{corrected}'
f'
{escape(d["summary"])} {evidence}
')
out.append('
')
if vp['signature_patterns']:
out.append('
Signature patterns
' + ''.join(
f'{escape(p["text"])} ×{p["count"]}' for p in vp['signature_patterns']) + '
')
if vp['stable_traits'] or vp['contextual_traits']:
out.append(f'
Across contexts ({escape(", ".join(vp["contexts"]))})
Stable: {escape(", ".join(vp["stable_traits"]) or "none measured")}. '
f'Changes with context: {escape(", ".join(vp["contextual_traits"]) or "none measured")}.
')
model = {'included': f'A model reading is included; {vp["unverified_dropped"]} claim(s) it could not tie to an exact quotation were dropped.',
'not requested': 'No model was used. Everything above is measured on this server.',
'failed': 'The model reading failed, so humor, abstraction and imagery are marked “not assessed” rather than guessed.'}[vp['model_read']]
out.append(f'
{escape(model)}
Limitations and every measurement
'
+ ''.join(f'
{escape(x)}
' for x in vp['limitations']) + f'
{escape(json.dumps(vp["observed"], indent=2))}
')
out.append(data_link(vp, 'humantouch-voiceprint.json', 'Download this Voiceprint (JSON)'))
out.append('
The file holds derived measurements, your notes, and short quoted phrases from your samples. It does not hold the samples.
')
return ''.join(out)
def voice_indicator(vp: dict | None) -> str:
if not vp:
return '
No Voiceprint loaded. I’ll protect the voice of the text itself.
'
q = vp['sample_quality']
return f'
Voiceprint active · {q["words"]:,} words sampled · {escape(q["rating"])}
'
def comparison(cmp: dict | None) -> str:
if not cmp:
return ''
out = ['
' + ''.join(f'
{escape(s)}
' for s in cmp['statements']) + '
']
for title, items in (('Certainty differences', cmp['certainty']), ('Factual and content differences', cmp['facts'])):
if items:
out.append(f'
{title}
' + ''.join(
f'
{escape(w["status"])} {escape(w["what"])}'
+ (f' A: {escape(w["original"])}' if w['original'] else '')
+ (f' B: {escape(w["revised"])}' if w['revised'] else '') + '
' for w in items))
out.append(f'
{escape(cmp["note"])}
')
return ''.join(out)
def demo(generic: dict, touched: dict, source: str) -> str:
def column(title: str, r: dict) -> str:
a = r['analysis']
s = a['stats']
medium_up = sum(w['severity'] != 'low' for w in a['meaning_warnings'])
rows = [('Sentences left exactly as written', f'{int(s["sentences_untouched"])} of {int(s["sentences"])}'),
('Share of the original’s words edited', f'{s["edit_ratio"]:.0%}'),
('Meaning warnings to check', str(medium_up)),
('Habits that drifted', str(len(a['voice_drift']['shifts']))),
('Sentences with no counterpart', str(int(s['ai_added_sentences']))),
('Length', f'{int(s["source_words"])} → {int(s["result_words"])} words')]
body = ' '.join(f'{escape(p["text"])}' for p in a['provenance'])
table = ''.join(f'
{escape(k)}
{escape(v)}
' for k, v in rows)
return (f'
{escape(title)}
{body}
{table}
'
f'
{escape(a["voice_drift"]["summary"])}
')
states = [p['state'] for r in (generic, touched) for p in r['analysis']['provenance']]
return ('
Both columns were produced just now by the same model from the same text and the same request. '
'Only the instructions around the model differ. The numbers are measurements of these two outputs, so they will vary from run to run.
')
def cowrite_map(sentences: list[dict]) -> str:
if not sentences:
return ''
body = ' '.join(f'{escape(text)}{escape(label)}' for text, label, c in
((s['text'], s['state'], 'p-added' if s['state'] == 'AI-added' else 'p-light' if 'edited' in s['state'] else 'p-original') for s in sentences))
return f'