Spaces:
Running
Running
Download render.py from ciaochris/HumanTouch: direct link, hf CLI and curl.
- Browser
- Download file 18.9 kB
-
https://huggingface.co/spaces/ciaochris/HumanTouch/resolve/main/render.py
- Command line
-
hf download hf://spaces/ciaochris/HumanTouch/render.py
-
curl -L -o render.py https://huggingface.co/spaces/ciaochris/HumanTouch/resolve/main/render.py
18.9 kB
| """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 = """ | |
| <nav class="masthead" aria-label="Studio identity"> | |
| <div class="wordmark"><span class="brand-mark" aria-hidden="true">h.</span>HumanTouch</div> | |
| <span class="masthead-note">A writing studio by Vers3Dynamics</span> | |
| <span class="edition">YOUR WORDS, WITH CHARACTER</span> | |
| </nav> | |
| <section class="hero" aria-labelledby="studio-title"> | |
| <div class="hero-copy"> | |
| <p class="eyebrow"><span></span> AN EDITOR THAT WORKS UNDERNEATH YOUR VOICE</p> | |
| <h1 id="studio-title">Edited.<br>Still <em>yours.</em><svg class="underline" viewBox="0 0 200 16" aria-hidden="true"><path d="M3 10 Q82 0 196 7 M14 14 Q111 5 183 12"/></svg></h1> | |
| <p class="hero-description">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.</p> | |
| </div> | |
| <aside class="margin-note" aria-label="How HumanTouch treats an edit"> | |
| <div class="note-top"><span>WHAT THE LEDGER LOOKS LIKE</span><span aria-hidden="true">↙</span></div> | |
| <p class="note-before">“I think this could help.”</p> | |
| <p class="note-after">“This will help.”</p> | |
| <div class="note-bottom"><span class="handwritten">More certain than you were. Kept yours.</span><span>AN ILLUSTRATION</span></div> | |
| </aside> | |
| </section> | |
| """ | |
| FOOTER = """ | |
| <footer class="studio-footer"><span><b>HumanTouch</b> AI can change the writing without quietly replacing the writer.</span> | |
| <span>The final authority is you.</span></footer> | |
| """ | |
| EMPTY = '<p class="quiet">Nothing here yet. This fills in after an edit.</p>' | |
| 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 = ['<section class="ht-summary" aria-label="Summary of this revision">'] | |
| if fixture: | |
| parts.append('<p class="notice">Development provider: these edits come from a mechanical test double, not a language model.</p>') | |
| mode = 'ghost' if a['assistance_mode'] == 'ghostwriter' else 'mirror' | |
| parts.append(f'<p class="mode {mode}"><b>{"New language added" if mode == "ghost" else "Edited, not rewritten"}.</b> {escape(a["assistance_note"])}</p>') | |
| active = s['changes'] - s['changes_restored'] | |
| parts.append(f'<p class="counts">{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</p>') | |
| for action in result.get('guard_actions', []): | |
| parts.append(f'<p class="guard">{escape(action)}</p>') | |
| high = [w for w in a['meaning_warnings'] if w['severity'] != 'low'] | |
| if high: | |
| parts.append(f'<p class="warn-line"><b>{len(high)} thing{"s" if len(high) != 1 else ""} to check below</b>: this revision may change more than style.</p>') | |
| parts.append('<dl class="estimates">') | |
| for name, est in a['confidence'].items(): | |
| parts.append(f'<div><dt>{escape(name.capitalize())}</dt><dd><span class="lvl lvl-{escape(est["level"].replace(" ", "-"))}">{escape(est["level"])}</span> ' | |
| f'<span class="means">{escape(est["means"])}</span></dd></div>') | |
| parts.append('</dl></section>') | |
| return ''.join(parts) | |
| def warnings(result: dict | None) -> str: | |
| if not result: | |
| return EMPTY | |
| items = result['analysis']['meaning_warnings'] | |
| out = ['<section class="ht-warnings"><h4>Did I change what you meant?</h4>'] | |
| if not items: | |
| out.append('<p class="quiet">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.</p>') | |
| for w in items: | |
| out.append(f'<article class="warning sev-{w["severity"]}"><p class="w-head"><span class="tag">{escape(w["status"])}</span> {escape(w["what"])}</p>') | |
| if w['original']: | |
| out.append(f'<p class="w-pair"><span>Original</span> {escape(w["original"])}</p>') | |
| if w['revised']: | |
| out.append(f'<p class="w-pair"><span>Revision</span> {escape(w["revised"])}</p>') | |
| if w['change_ids']: | |
| out.append(f'<p class="w-fix">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.</p>') | |
| out.append('</article>') | |
| audit = result.get('audit') | |
| if audit: | |
| out.append('<h4>A model’s second reading <span class="tag soft">model judgment</span></h4>' | |
| '<p class="quiet">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.</p>') | |
| for item in audit['items']: | |
| out.append(f'<p class="audit"><span class="tag soft">{escape(item["status"])}</span> “{escape(_short(item["original"], 140))}” → ' | |
| f'“{escape(_short(item["revised"], 140))}” <em>{escape(item["note"])}</em></p>') | |
| elif result.get('audit_error'): | |
| out.append(f'<p class="notice">{escape(result["audit_error"])}</p>') | |
| out.append('</section>') | |
| return ''.join(out) | |
| def ledger(result: dict | None) -> str: | |
| if not result: | |
| return EMPTY | |
| changes = result['analysis']['changes'] | |
| if not changes: | |
| return '<p class="quiet">No edits. The text came back exactly as you wrote it.</p>' | |
| out = ['<section class="ht-ledger"><p class="quiet">Categories describe the kind of difference each edit makes. They are read from the edit itself, ' | |
| 'not from the model’s account of why.</p>'] | |
| 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'<article class="change {cls}"><header><span class="num">CHANGE {c["id"]:02d}</span><span class="tag">{escape(c["category"])}</span>' | |
| + (f'<span class="tag kept">{escape(who)}</span>' if who else '') + '</header>' | |
| f'<p class="pair"><del>{escape(c["original"]) or "<i>(nothing)</i>"}</del><span aria-hidden="true"> → </span>' | |
| f'<ins>{escape(c["revised"]) or "<i>(removed)</i>"}</ins></p>' | |
| f'<p class="meta">{escape(c["reason"])} · Voice impact: <b>{c["voice_impact"]}</b> · Meaning impact: <b>{c["meaning_impact"]}</b></p></article>') | |
| out.append('</section>') | |
| return ''.join(out) | |
| def _legend(states: list[str]) -> str: | |
| seen = [s for s in STATE_CLASS if s in states] | |
| return '<p class="legend">' + ''.join(f'<span class="{STATE_CLASS[s]}">{escape(s)}</span><small>{escape(STATE_HELP[s])}</small>' for s in seen) + '</p>' | |
| 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'<span class="{STATE_CLASS[p["state"]]}" title="{escape(p["state"])}: {p["original_share"]:.0%} your wording">' | |
| f'{escape(p["text"])}<sup>{escape(p["state"])}</sup></span>' for p in prov) | |
| return (f'<section class="ht-authorship"><p class="quiet">Where did these words come from? {len(prov)} sentences: {escape(tally)}. ' | |
| 'This is about awareness, not contamination: added words are not worse words.</p>' | |
| f'{_legend(list(counts))}<div class="map">{body}</div></section>') | |
| def voice(result: dict | None) -> str: | |
| if not result: | |
| return EMPTY | |
| a = result['analysis'] | |
| drift = a['voice_drift'] | |
| out = [f'<section class="ht-voice"><h4>Voice drift <span class="tag soft">against {escape(drift["reference"])}</span></h4>' | |
| f'<p class="{"warn-line" if drift["detected"] else "quiet"}">{escape(drift["summary"])}</p>'] | |
| if drift['shifts']: | |
| out.append('<table><thead><tr><th scope="col">Habit</th><th scope="col">Before</th><th scope="col">Now</th><th scope="col">Change</th></tr></thead><tbody>') | |
| for s in drift['shifts']: | |
| out.append(f'<tr><th scope="row">{escape(s["label"])}</th><td>{s["before"]:g}</td><td>{s["after"]:g}</td><td>{escape(s["change"])}</td></tr>') | |
| out.append('</tbody></table>') | |
| out.append('<h4>Authorial distance</h4><p class="quiet">How far this revision moved from your text, axis by axis. A navigational aid, not a verdict.</p><dl class="distance">') | |
| for name, axis in a['authorial_distance'].items(): | |
| out.append(f'<div><dt>{escape(name.capitalize())}</dt><dd><span class="bar" aria-hidden="true"><i style="width:{LEVEL_WIDTH[axis["level"]]}%"></i></span>' | |
| f'<b>{escape(axis["level"])}</b><small>{escape(axis["how"])}</small></dd></div>') | |
| out.append('</dl>') | |
| if a['preserved_features']: | |
| out.append('<h4>What I kept</h4><ul>' + ''.join(f'<li>{escape(x)}</li>' for x in a['preserved_features']) + '</ul>') | |
| out.append('</section>') | |
| return ''.join(out) | |
| def plan_text(intent: dict | None) -> str: | |
| if not intent: | |
| return '' | |
| return ('<p class="plan-basis">I think you want (' + escape(intent['basis']) + '; untick anything I got wrong):</p>') | |
| def notice_list(items: list[dict]) -> str: | |
| if not items: | |
| return '' | |
| return '<ul class="notices">' + ''.join(f'<li>{escape(i["message"])}</li>' for i in items) + '</ul>' | |
| def data_link(obj: dict, filename: str, label: str) -> str: | |
| payload = base64.b64encode(json.dumps(obj, ensure_ascii=False, indent=2).encode('utf-8')).decode() | |
| return f'<a class="download" download="{escape(filename)}" href="data:application/json;base64,{payload}">{escape(label)}</a>' | |
| def voiceprint(vp: dict | None) -> str: | |
| if not vp: | |
| return ('<p class="quiet">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.</p>') | |
| q = vp['sample_quality'] | |
| out = [f'<section class="voice-portrait"><h3>Your Voiceprint</h3><p class="sample sample-{q["rating"]}"><b>Sample: {escape(q["rating"])}.</b> {escape(q["advice"])}</p>'] | |
| if vp['tendencies']: | |
| out.append('<h4>Your writing tends to</h4><ul>' + ''.join(f'<li>{escape(t)};</li>' for t in vp['tendencies']) + '</ul>') | |
| out.append('<h4>Dimensions</h4><p class="quiet">Descriptions, not grades. <i>Observed</i> is measured from your samples; <i>inferred</i> is a proxy built on ' | |
| 'those measurements; <i>model judgment</i> is a model’s reading that quoted your samples.</p><div class="dims">') | |
| 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'<span class="tag kept">{escape(labels[d["correction"]])}</span>' if d.get('correction') else '' | |
| evidence = ''.join(f'<q>{escape(e)}</q>' for e in d['evidence']) | |
| out.append(f'<article class="dim{" off" if d.get("correction") in ("not_me", "never_imitate") else ""}"><header><b>{escape(d["name"].capitalize())}</b>' | |
| f'<span class="tag soft">{escape(d["basis"])}</span><span class="tag soft">confidence: {escape(d["confidence"])}</span>{corrected}</header>' | |
| f'<p>{escape(d["summary"])} {evidence}</p></article>') | |
| out.append('</div>') | |
| if vp['signature_patterns']: | |
| out.append('<h4>Signature patterns</h4><p class="patterns">' + ''.join( | |
| f'<span title="{escape(p["basis"])}">{escape(p["text"])} <small>×{p["count"]}</small></span>' for p in vp['signature_patterns']) + '</p>') | |
| if vp['stable_traits'] or vp['contextual_traits']: | |
| out.append(f'<h4>Across contexts ({escape(", ".join(vp["contexts"]))})</h4><p><b>Stable:</b> {escape(", ".join(vp["stable_traits"]) or "none measured")}.<br>' | |
| f'<b>Changes with context:</b> {escape(", ".join(vp["contextual_traits"]) or "none measured")}.</p>') | |
| if vp['voice_notes']: | |
| out.append('<h4>Your voice notes</h4><ul>' + ''.join( | |
| f'<li>“{escape(n["note"])}” <span class="tag soft">{escape(n["effect"])}</span>' | |
| + (f' <span class="tag kept">protects: {escape(", ".join(n["protected_phrases"]))}</span>' if n['protected_phrases'] else '') + '</li>' | |
| for n in vp['voice_notes']) + '</ul>') | |
| 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'<p class="quiet">{escape(model)}</p><details><summary>Limitations and every measurement</summary><ul>' | |
| + ''.join(f'<li>{escape(x)}</li>' for x in vp['limitations']) + f'</ul><pre>{escape(json.dumps(vp["observed"], indent=2))}</pre></details>') | |
| out.append(data_link(vp, 'humantouch-voiceprint.json', 'Download this Voiceprint (JSON)')) | |
| out.append('<p class="quiet">The file holds derived measurements, your notes, and short quoted phrases from your samples. It does not hold the samples.</p></section>') | |
| return ''.join(out) | |
| def voice_indicator(vp: dict | None) -> str: | |
| if not vp: | |
| return '<p class="voice-hint">No Voiceprint loaded. I’ll protect the voice of the text itself.</p>' | |
| q = vp['sample_quality'] | |
| return f'<p class="voice-hint active">Voiceprint active · {q["words"]:,} words sampled · {escape(q["rating"])}</p>' | |
| def comparison(cmp: dict | None) -> str: | |
| if not cmp: | |
| return '' | |
| out = ['<section class="ht-compare"><ul>' + ''.join(f'<li>{escape(s)}</li>' for s in cmp['statements']) + '</ul>'] | |
| for title, items in (('Certainty differences', cmp['certainty']), ('Factual and content differences', cmp['facts'])): | |
| if items: | |
| out.append(f'<h4>{title}</h4>' + ''.join( | |
| f'<p class="w-pair"><span>{escape(w["status"])}</span> {escape(w["what"])}' | |
| + (f'<br><small>A: {escape(w["original"])}</small>' if w['original'] else '') | |
| + (f'<br><small>B: {escape(w["revised"])}</small>' if w['revised'] else '') + '</p>' for w in items)) | |
| out.append(f'<p class="quiet">{escape(cmp["note"])}</p></section>') | |
| 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'<span class="{STATE_CLASS[p["state"]]}">{escape(p["text"])}</span>' for p in a['provenance']) | |
| table = ''.join(f'<tr><th scope="row">{escape(k)}</th><td>{escape(v)}</td></tr>' for k, v in rows) | |
| return (f'<article><h4>{escape(title)}</h4><div class="map">{body}</div><table>{table}</table>' | |
| f'<p class="quiet">{escape(a["voice_drift"]["summary"])}</p></article>') | |
| states = [p['state'] for r in (generic, touched) for p in r['analysis']['provenance']] | |
| return ('<section class="ht-demo"><p class="quiet">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.</p>' | |
| f'{_legend(states)}<div class="cols">{column("A conventional rewrite prompt", generic)}{column("HumanTouch", touched)}</div></section>') | |
| def cowrite_map(sentences: list[dict]) -> str: | |
| if not sentences: | |
| return '' | |
| body = ' '.join(f'<span class="{c}" title="{escape(label)}">{escape(text)}<sup>{escape(label)}</sup></span>' 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'<section class="ht-authorship"><div class="map">{body}</div></section>' | |
| __all__ = ['HEADER', 'FOOTER', 'STRENGTH_LABELS'] | |