Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
5d94a89
prompt tuning pass 1
thehabes Apr 21, 2026
8e644e2
Change their selection labels
thehabes Apr 21, 2026
d4b4c82
cleanup while testing
thehabes Apr 21, 2026
92f596a
prompt tuning round 2
thehabes Apr 21, 2026
0c42a66
accuracy bundle
thehabes Apr 22, 2026
a36c1a1
Tuning round 3
thehabes Apr 22, 2026
b5d8ff9
Changes from review
thehabes Apr 22, 2026
ce1d9c2
Now that's a demo
thehabes Apr 22, 2026
d565c74
Now that's a demo
thehabes Apr 22, 2026
9af6429
Now that's a demo
thehabes Apr 22, 2026
0255000
Order principle applied. New prompt to transcribe and include orderi…
thehabes Apr 22, 2026
1c14e54
Restore JSON-paste fallback submission flow
thehabes Apr 23, 2026
94a981b
recovering
thehabes Apr 23, 2026
d999104
recovering
thehabes Apr 23, 2026
a9ad8bb
changes during review
thehabes Apr 23, 2026
99623b1
changes during review
thehabes Apr 23, 2026
6114cd6
changes during review
thehabes Apr 23, 2026
31a2983
changes during review
thehabes Apr 23, 2026
f85b135
changes during review
thehabes Apr 23, 2026
68b9c40
condensed communication
thehabes Apr 23, 2026
26127d7
condensed communication
thehabes Apr 23, 2026
4977c7f
condensed communication
thehabes Apr 23, 2026
e5da7a8
changes from review
thehabes Apr 23, 2026
59d7363
condense
thehabes Apr 23, 2026
37643a4
changes during review
thehabes Apr 24, 2026
ac4b2aa
this is not right
thehabes Apr 24, 2026
3863853
this is not right
thehabes Apr 24, 2026
b7ec4df
this is right
thehabes Apr 24, 2026
b72f85c
changes during review
thehabes Apr 24, 2026
8682b35
small hack to get the transcription interface to refresh when the fal…
thehabes Apr 24, 2026
12202c1
Merge pull request #6 from CenterForDigitalHumanities/restore-api-usa…
thehabes Apr 24, 2026
b3074fc
Changes during review
thehabes Apr 24, 2026
48eb2d3
lock it in
thehabes Apr 24, 2026
2568ac6
Merge branch 'main' into prompt-tuning
thehabes Apr 24, 2026
c6a8085
Changes while testing
thehabes Apr 24, 2026
c8e8ab9
Simplify a bit
thehabes Apr 24, 2026
3f72073
Changes from review
thehabes Apr 24, 2026
fa25231
fail faster
thehabes Apr 24, 2026
b77c4e7
changes during review and sync
thehabes Apr 27, 2026
abc2037
changes during review and sync
thehabes Apr 27, 2026
c62296f
changes from testing
thehabes Apr 27, 2026
10976cc
Relax the origin gate in the child.
thehabes Apr 28, 2026
e19e4fa
changes from review
thehabes Apr 28, 2026
8ebe2f8
Do not need to worry about existing columns here anymore
thehabes Apr 28, 2026
75f3d20
Small touches from manual readthrough of .md and produced prompt.
thehabes Apr 28, 2026
b6f19d4
Changes during review. Going to test each one now.
thehabes Apr 28, 2026
a615664
changes during testing
thehabes Apr 28, 2026
a6b4d2e
Testing was good. Prepare for merge and a stable main.
thehabes Apr 28, 2026
09bfa2b
small change for security message
thehabes Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ASSISTANTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ You are a small GitHub Pages app that functions as a TPEN AI Prompt Generator.

## TPEN Interfaces

You are a TPEN Interfaces component with an accompanying interface for UI. Specifically, you are a splitscreen tool for the transcription interface.
You are a tool imported into a TPEN Interfaces component. That component is your parent.

> The TPEN Interfaces code can be found at https://github.com/CenterForDigitalHumanities/TPEN-interfaces.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# TPEN-Prompts

A small GitHub Pages app that composes well-formatted LLM prompts carrying TPEN3 project context. It emits prompt text only — it does **not** call any LLM. Offered as a splitscreen tool on the TPEN3 transcription interface.
A small GitHub Pages app that composes well-formatted LLM prompts carrying TPEN3 project context. It emits prompt text only — it does **not** call any LLM.
10 changes: 5 additions & 5 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,25 @@ const ACTIVE_ENV = (
?? 'prod'
)

/** @type {Record<string, { servicesURL: string, TPEN3URL: string }>} */
/** @type {Record<string, { servicesURL: string, interfacesURL: string }>} */
const ENVIRONMENTS = {
local: {
servicesURL: 'http://localhost:3012',
TPEN3URL: 'http://localhost:4000'
interfacesURL: 'http://localhost:4000'
},
dev: {
servicesURL: 'https://dev.api.t-pen.org',
TPEN3URL: 'http://localhost:4000'
interfacesURL: 'http://localhost:4000'
},
prod: {
servicesURL: 'https://api.t-pen.org',
TPEN3URL: 'https://app.t-pen.org'
interfacesURL: 'https://app.t-pen.org'
}
}

/**
* Active config for this page load, flattened for convenient destructuring.
* @type {{ env: string, servicesURL: string, TPEN3URL: string }}
* @type {{ env: string, servicesURL: string, interfacesURL: string }}
*/
export const CONFIG = {
env: ACTIVE_ENV,
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TPEN-Prompts</title>
<meta name="description" content="TPEN3 AI prompt generator — composes well-formatted LLM prompts carrying project context.">
<meta name="tpen-env" content="dev">
<meta name="tpen-env" content="prod">
<link rel="stylesheet" href="styles.css">
<script type="module" src="main.js"></script>
</head>
Expand Down
25 changes: 10 additions & 15 deletions message-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@
* clicking the consent button sends `REQUEST_TPEN_ID_TOKEN` upstream, and
* the parent replies with `TPEN_ID_TOKEN`.
*
* Replies are aimed at `parentOrigin`, captured from the first inbound
* message; before any inbound arrives, `CONFIG.interfacesURL` is used
* as the default target.
*
* @author thehabes
*/

import { CONFIG } from './config.js'

// Accept messages only from known TPEN3 origins and the current origin (for
// same-origin dev harnesses). Anything else could inject auth tokens or drive
// the tool's state, so drop silently.
const ALLOWED_ORIGINS = new Set([
CONFIG.TPEN3URL,
location.origin
])

/**
* Listens on `window` for postMessage traffic from the TPEN3 parent and routes
* recognized message types to the `PromptsApp`.
Expand All @@ -30,17 +26,16 @@ export class MessageHandler {
*/
constructor(app) {
this.app = app
/** Origin of the first trusted inbound message; used as targetOrigin for replies. */
/** Origin of the first inbound message; used as targetOrigin for replies. */
this.parentOrigin = null
window.addEventListener('message', (event) => this.handle(event))
}

/**
* Route an incoming postMessage. Origin-gated; unknown types are ignored.
* Route an incoming postMessage. Unknown types are ignored.
* @param {MessageEvent} event
*/
handle(event) {
if (!ALLOWED_ORIGINS.has(event.origin)) return
this.parentOrigin ??= event.origin
const data = event.data
if (!data?.type) return
Expand All @@ -61,15 +56,15 @@ export class MessageHandler {

/**
* Post a message to the parent frame. Replies target the origin of the
* first trusted inbound message; before any inbound arrives we fall back
* to `CONFIG.TPEN3URL` (the expected production parent). No-op when the
* parent is the page itself.
* first inbound message; before any inbound arrives we fall back to
* `CONFIG.interfacesURL` (the expected production parent). No-op when
* the parent is the page itself.
* @param {object} message
* @returns {boolean} true when a parent frame exists and the post was dispatched.
*/
#postToParent(message) {
if (window.parent === window) return false
const targetOrigin = this.parentOrigin ?? CONFIG.TPEN3URL
const targetOrigin = this.parentOrigin ?? CONFIG.interfacesURL
window.parent.postMessage(message, targetOrigin)
return true
}
Expand Down
26 changes: 13 additions & 13 deletions templates/detect-and-transcribe/PROMPT.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ You are assisting with TPEN manuscript transcription. Perform the task end-to-en

## Preconditions

All required inputs (`canvasId`, `token`, `pageEndpoint`, `imageUrl`, canvas dimensions) are provided above. You must have:
All required inputs (`canvasId`, `token`, `pageEndpoint`, `imageUrl`, canvas dimensions) are provided above. This template only creates new lines: `lineCount` = `{{lineCount}}`. If `lineCount` is not `0`, stop immediately and report — existing line data must not be modified.

You must have:

1. Ability to fetch the image bytes (or a derivative) and identify line bounds and text from them. Precise pixel measurement is preferred when available; visual estimation and on-sight transcription from the fetched image are acceptable otherwise.
2. Either HTTP PUT capability with `Content-Type: application/json`, or the ability to emit the payload as a fallback JSON code block in your report. If HTTP PUT is not available, skip straight to the Fallback section — do not retry.
Expand All @@ -21,31 +23,30 @@ Use only tools already available in your environment. Do not install packages, l
## Steps

1. Resolve `img_w`, `img_h`. If `{{imageUrl}}` looks like a IIIF Image API endpoint (path matches `…/{region}/{size}/{rotation}/{quality}.{format}`), strip that suffix to get `{base}`, then GET `{base}/info.json` for the dimensions. For the page-overview pass, fetch a small derivative `{base}/full/1500,/0/default.jpg` and scale measured coordinates back via `source = derivative * info.width / 1500`. If you have precise pixel tooling and want tighter bounds or a clearer crop for transcription, request a region server-side as `{base}/x,y,w,h/max/0/default.jpg` and add the crop's `x,y` origin back before applying the canvas conversion below. Otherwise GET `{{imageUrl}}` once and read dimensions from the bytes.
2. Detect text lines across the whole page in reading order. This task does not create TPEN columns.
2. Detect text lines across the whole page in reading order. This task does not create TPEN columns. Then do exactly one self-review pass to tweak line placement — catch missed lines, merge over-splits, split over-merges, tighten loose bounds. One pass only, then move on.
3. For every line, measure a bounding box in image-pixel space and convert to integer canvas coordinates using:
- `canvas_x = round(pixel_x * {{canvasWidth}} / img_w)`
- `canvas_y = round(pixel_y * {{canvasHeight}} / img_h)`
- `canvas_w = round(pixel_w * {{canvasWidth}} / img_w)`
- `canvas_h = round(pixel_h * {{canvasHeight}} / img_h)`
Then clamp to the canvas (`0 ≤ x`, `x + w ≤ {{canvasWidth}}`, `0 ≤ y`, `y + h ≤ {{canvasHeight}}`).
4. Run handwriting text recognition on each line's crop. Apply the recognition rules below.
5. If HTTP PUT is available, build the full payload under **TPEN API** — one Annotation per line with the recognized text and `xywh=x,y,w,h` selector — and send the request once. On any non-2xx response, do not retry — fall back.
6. If HTTP PUT is unavailable (or step 5 fell back), emit the condensed payload under **Fallback** as the final code block.
7. Report counts (lines saved/in payload, non-empty text, uncertain) and which path was used (direct PUT or fallback).
8. Report notable ambiguities (e.g., illegible lines transcribed as empty or flagged).
Then clamp `x,y,w,h` so that `0 ≤ x`, `x + w ≤ {{canvasWidth}}`, `0 ≤ y`, `y + h ≤ {{canvasHeight}}`.
4. Run text recognition (print or handwriting) on each line's crop. Apply the recognition rules below.
5. If HTTP PUT is available, build the full payload under **TPEN API** and send the request once. On any non-2xx response, stop and report the status and error body — do not emit a fallback payload; the same token and content would be re-submitted through it.
6. If HTTP PUT is unavailable from the start, emit the condensed payload under **Fallback** as the final code block — do not also attempt PUT.
7. Report counts (lines saved/in payload, non-empty text, uncertain), which path was used (direct PUT or fallback), and notable ambiguities (e.g., illegible lines transcribed as empty or flagged).

## Rules

### Detection (IMAGE_ANALYSIS)

- Bounds MUST be saved as integer coordinates in canvas space. No percent, no `pixel:` prefix on the selector value.
- Bounds MUST be saved as integer coordinates in canvas space. No percentage-based selectors. No `percent:` or `pixel:` prefix on the selector value.
- Preserve reading order across the whole page.
- Prefer tight bounds when you can measure them; best-effort bounds are acceptable. When uncertain whether a tall run is one line or several, prefer splitting over merging.
- Do not include decorative borders, frame rules, ornaments, or illustrations as part of a line.
- Completion beats refusal: approximate bounds on most lines are more useful than nothing — this data will be reviewed and corrected downstream.
- Completion beats refusal: approximate bounds on most lines are more useful than nothing — this data will be reviewed and corrected by humans downstream.
- Zero lines detected is an unprocessable outcome. Stop and report — do not PUT, do not emit a fallback payload. An empty `items` array would erase every existing annotation on the page.

### Recognition (HANDWRITING_TEXT_RECOGNITION)
### Recognition (TEXT_RECOGNITION)

- Prioritize diplomatic transcription over normalization.
- Preserve orthography and punctuation as observed.
Expand Down Expand Up @@ -84,7 +85,7 @@ Content-Type: application/json

## Fallback

When the direct PUT is impossible or returns non-2xx, emit the condensed payload below as the final code block of your report. The TPEN splitscreen tool expands each item into a full W3C Annotation before PUTting it — do not inline the canvas source, selector boilerplate, or motivation. It must be valid JSON (no comments, no placeholders — substitute the real coordinates and recognized text).
When HTTP PUT is unavailable from the start, emit the condensed payload below as the final code block of your report. The TPEN splitscreen tool expands each item into a full W3C Annotation before PUTting it — do not inline the canvas source, selector boilerplate, or motivation. It must be valid JSON (no comments, no placeholders — substitute the real coordinates and recognized text).

```
{
Expand All @@ -109,6 +110,5 @@ Fallback path, report:

- path: `fallback`
- counts: lines in payload, lines with non-empty text, lines flagged uncertain
- HTTP status and error body if a PUT was attempted first
- notable ambiguities worth a human review
- final code block: the condensed `{ "items": [...] }` JSON for the user to paste
Loading
Loading