|
| 1 | +<script lang="ts"> |
| 2 | + import { page } from '$app/state'; |
| 3 | + import { resolve } from '$app/paths'; |
| 4 | + import { ALIGNER_SITE_HOST } from '$lib/brand.js'; |
| 5 | + import SiteFooter from '$lib/components/layout/SiteFooter.svelte'; |
| 6 | +
|
| 7 | + const TITLE = 'API'; |
| 8 | + const DESCRIPTION = |
| 9 | + 'Word Aligner API: generate a pre-filled alignment link by posting text lines and optional word-pair data. Free, no auth required.'; |
| 10 | +
|
| 11 | + const canonical = $derived(page.url.origin + page.url.pathname); |
| 12 | + const apiBase = $derived(page.url.origin); |
| 13 | +
|
| 14 | + const linkClass = |
| 15 | + 'font-medium text-primary-700 underline decoration-primary-700/40 underline-offset-2 hover:text-primary-800 hover:decoration-primary-800 dark:text-primary-400 dark:decoration-primary-400/50 dark:hover:text-primary-300'; |
| 16 | +
|
| 17 | + const headingClass = 'font-heading mt-10 text-xl font-semibold text-gray-900 dark:text-white'; |
| 18 | +
|
| 19 | + const codeClass = |
| 20 | + 'rounded bg-gray-100 px-1.5 py-0.5 font-mono text-sm text-gray-800 dark:bg-gray-800 dark:text-gray-200'; |
| 21 | +
|
| 22 | + const preClass = |
| 23 | + 'overflow-x-auto rounded-md border border-gray-200 bg-gray-50 p-4 font-mono text-sm leading-relaxed text-gray-800 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200'; |
| 24 | +</script> |
| 25 | + |
| 26 | +<svelte:head> |
| 27 | + <title>{TITLE} · Word Aligner</title> |
| 28 | + <meta name="description" content={DESCRIPTION} /> |
| 29 | + <link rel="canonical" href={canonical} /> |
| 30 | + <meta name="robots" content="index,follow" /> |
| 31 | + <meta property="og:type" content="website" /> |
| 32 | + <meta property="og:title" content="{TITLE} · Word Aligner" /> |
| 33 | + <meta property="og:description" content={DESCRIPTION} /> |
| 34 | + <meta property="og:url" content={canonical} /> |
| 35 | +</svelte:head> |
| 36 | + |
| 37 | +<main |
| 38 | + class="mx-auto w-full max-w-3xl min-w-0 px-4 pt-4 pb-16 leading-relaxed text-gray-700 sm:px-6 md:pt-6 md:pb-20 dark:text-gray-300" |
| 39 | +> |
| 40 | + <header class="mb-8 border-b border-gray-200 pb-6 dark:border-gray-700"> |
| 41 | + <nav class="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm"> |
| 42 | + <a href={resolve('/')} class={linkClass}>← Word Aligner</a> |
| 43 | + <span class="text-gray-400 dark:text-gray-500" aria-hidden="true">·</span> |
| 44 | + <a href={resolve('/about')} class={linkClass}>About</a> |
| 45 | + </nav> |
| 46 | + </header> |
| 47 | + |
| 48 | + <h1 class="font-heading text-3xl font-semibold tracking-tight text-gray-900 sm:text-4xl dark:text-white"> |
| 49 | + API |
| 50 | + </h1> |
| 51 | + <p class="mt-4 text-lg text-gray-600 dark:text-gray-400"> |
| 52 | + One endpoint: send text lines and optional alignment pairs, get back a shareable Word Aligner |
| 53 | + URL. No API key, no sign-up. |
| 54 | + </p> |
| 55 | + <p class="mt-2 text-sm text-gray-500 dark:text-gray-400"> |
| 56 | + OpenAPI schema: <a href={resolve('/api/align/openapi.json')} class={linkClass} |
| 57 | + >/api/align/openapi.json</a |
| 58 | + > |
| 59 | + </p> |
| 60 | + |
| 61 | + <nav |
| 62 | + class="mt-8 rounded-md border border-gray-200 bg-gray-50 px-4 py-3 text-sm dark:border-gray-700 dark:bg-gray-800/60" |
| 63 | + aria-label="On this page" |
| 64 | + > |
| 65 | + <p class="m-0 font-medium text-gray-900 dark:text-white">On this page</p> |
| 66 | + <ul class="mt-2 list-none space-y-1 p-0"> |
| 67 | + <li> |
| 68 | + <a |
| 69 | + href="#post-api-align" |
| 70 | + class="block py-1 text-gray-700 underline decoration-gray-400/40 underline-offset-2 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white" |
| 71 | + >POST /api/align</a |
| 72 | + > |
| 73 | + </li> |
| 74 | + <li> |
| 75 | + <a |
| 76 | + href="#get-api-align" |
| 77 | + class="block py-1 text-gray-700 underline decoration-gray-400/40 underline-offset-2 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white" |
| 78 | + >GET /api/align (lines only)</a |
| 79 | + > |
| 80 | + </li> |
| 81 | + <li> |
| 82 | + <a |
| 83 | + href="#word-indices" |
| 84 | + class="block py-1 text-gray-700 underline decoration-gray-400/40 underline-offset-2 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white" |
| 85 | + >Word indices and tokenization</a |
| 86 | + > |
| 87 | + </li> |
| 88 | + <li> |
| 89 | + <a |
| 90 | + href="#errors" |
| 91 | + class="block py-1 text-gray-700 underline decoration-gray-400/40 underline-offset-2 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white" |
| 92 | + >Errors</a |
| 93 | + > |
| 94 | + </li> |
| 95 | + </ul> |
| 96 | + </nav> |
| 97 | + |
| 98 | + <h2 id="post-api-align" class={headingClass}>POST /api/align</h2> |
| 99 | + <p class="mt-3"> |
| 100 | + The main endpoint. Returns a URL to Word Aligner with the given lines and alignment links |
| 101 | + pre-filled. |
| 102 | + </p> |
| 103 | + |
| 104 | + <h3 class="mt-6 font-semibold text-gray-900 dark:text-white">Request</h3> |
| 105 | + <p class="mt-2 text-sm"><span class={codeClass}>Content-Type: application/json</span></p> |
| 106 | + |
| 107 | + <div class="mt-4 overflow-x-auto rounded-md border border-gray-200 dark:border-gray-700"> |
| 108 | + <table class="min-w-full divide-y divide-gray-200 text-sm dark:divide-gray-700"> |
| 109 | + <thead class="bg-gray-50 dark:bg-gray-800/60"> |
| 110 | + <tr> |
| 111 | + <th class="px-4 py-2 text-left font-semibold text-gray-700 dark:text-gray-300">Field</th> |
| 112 | + <th class="px-4 py-2 text-left font-semibold text-gray-700 dark:text-gray-300">Type</th> |
| 113 | + <th class="px-4 py-2 text-left font-semibold text-gray-700 dark:text-gray-300" |
| 114 | + >Description</th |
| 115 | + > |
| 116 | + </tr> |
| 117 | + </thead> |
| 118 | + <tbody class="divide-y divide-gray-100 dark:divide-gray-700/60"> |
| 119 | + <tr> |
| 120 | + <td class="px-4 py-2 font-mono text-gray-800 dark:text-gray-200">lines</td> |
| 121 | + <td class="px-4 py-2 text-gray-600 dark:text-gray-400">string[] (required)</td> |
| 122 | + <td class="px-4 py-2 text-gray-700 dark:text-gray-300" |
| 123 | + >Text lines, top to bottom. 1–8 lines.</td |
| 124 | + > |
| 125 | + </tr> |
| 126 | + <tr class="bg-gray-50/50 dark:bg-gray-800/20"> |
| 127 | + <td class="px-4 py-2 font-mono text-gray-800 dark:text-gray-200">alignments</td> |
| 128 | + <td class="px-4 py-2 text-gray-600 dark:text-gray-400">[int,int,int,int][] (optional)</td> |
| 129 | + <td class="px-4 py-2 text-gray-700 dark:text-gray-300" |
| 130 | + >Word-alignment pairs as <span class={codeClass}>[lineA, wordA, lineB, wordB]</span>. Lines |
| 131 | + A and B must be adjacent (<span class={codeClass}>|A−B| = 1</span>). Indices are 0-based.</td |
| 132 | + > |
| 133 | + </tr> |
| 134 | + </tbody> |
| 135 | + </table> |
| 136 | + </div> |
| 137 | + |
| 138 | + <h3 class="mt-6 font-semibold text-gray-900 dark:text-white">Response</h3> |
| 139 | + <pre class="{preClass} mt-3">{`{ "url": "https://${ALIGNER_SITE_HOST}/?data=..." }`}</pre> |
| 140 | + |
| 141 | + <h3 class="mt-6 font-semibold text-gray-900 dark:text-white">Example</h3> |
| 142 | + <pre class="{preClass} mt-3">{`curl -X POST ${apiBase}/api/align \\ |
| 143 | + -H "Content-Type: application/json" \\ |
| 144 | + -d '{ |
| 145 | + "lines": ["Hello world", "Bonjour le monde"], |
| 146 | + "alignments": [ |
| 147 | + [0, 0, 1, 0], |
| 148 | + [0, 1, 1, 2] |
| 149 | + ] |
| 150 | + }'`}</pre> |
| 151 | + <p class="mt-2 text-sm text-gray-500 dark:text-gray-400"> |
| 152 | + This links "Hello" → "Bonjour" (word 0 of line 0 to word 0 of line 1) and "world" → "monde" |
| 153 | + (word 1 of line 0 to word 2 of line 1 — "le" is word 1, "monde" is word 2). |
| 154 | + </p> |
| 155 | + |
| 156 | + <p class="mt-3 text-sm text-gray-500 dark:text-gray-400"> |
| 157 | + Response: |
| 158 | + </p> |
| 159 | + <pre class="{preClass} mt-2">{`{ "url": "https://${ALIGNER_SITE_HOST}/?data=..." }`}</pre> |
| 160 | + |
| 161 | + <h2 id="get-api-align" class={headingClass}>GET /api/align</h2> |
| 162 | + <p class="mt-3"> |
| 163 | + Simple variant for quick links: pass lines as repeated query parameters. No alignments. Useful |
| 164 | + for opening the editor pre-filled via a link. |
| 165 | + </p> |
| 166 | + |
| 167 | + <pre class="{preClass} mt-4">{`GET /api/align?lines=Hello+world&lines=Bonjour+le+monde`}</pre> |
| 168 | + |
| 169 | + <p class="mt-3 text-sm"> |
| 170 | + <strong class="text-gray-900 dark:text-white">Parameters:</strong> |
| 171 | + <span class={codeClass}>lines</span> — repeat for each line (1–8). |
| 172 | + </p> |
| 173 | + |
| 174 | + <h2 id="word-indices" class={headingClass}>Word indices and tokenization</h2> |
| 175 | + <p class="mt-3"> |
| 176 | + Words are counted from 0, left to right as written. The default split rules: whitespace always |
| 177 | + splits, and the characters <span class={codeClass}>.</span> |
| 178 | + <span class={codeClass}>-</span> |
| 179 | + <span class={codeClass}>|</span> also create word boundaries. Punctuation is not split into |
| 180 | + separate tokens by default. |
| 181 | + </p> |
| 182 | + <p class="mt-3">Example — <em>"Bonjour le monde"</em>:</p> |
| 183 | + <div class="mt-3 overflow-x-auto rounded-md border border-gray-200 dark:border-gray-700"> |
| 184 | + <table class="min-w-full divide-y divide-gray-200 text-sm dark:divide-gray-700"> |
| 185 | + <thead class="bg-gray-50 dark:bg-gray-800/60"> |
| 186 | + <tr> |
| 187 | + <th class="px-4 py-2 text-left font-semibold text-gray-700 dark:text-gray-300">Index</th> |
| 188 | + <th class="px-4 py-2 text-left font-semibold text-gray-700 dark:text-gray-300">Word</th> |
| 189 | + </tr> |
| 190 | + </thead> |
| 191 | + <tbody class="divide-y divide-gray-100 dark:divide-gray-700/60"> |
| 192 | + <tr> |
| 193 | + <td class="px-4 py-2 font-mono text-gray-800 dark:text-gray-200">0</td> |
| 194 | + <td class="px-4 py-2 text-gray-700 dark:text-gray-300">Bonjour</td> |
| 195 | + </tr> |
| 196 | + <tr class="bg-gray-50/50 dark:bg-gray-800/20"> |
| 197 | + <td class="px-4 py-2 font-mono text-gray-800 dark:text-gray-200">1</td> |
| 198 | + <td class="px-4 py-2 text-gray-700 dark:text-gray-300">le</td> |
| 199 | + </tr> |
| 200 | + <tr> |
| 201 | + <td class="px-4 py-2 font-mono text-gray-800 dark:text-gray-200">2</td> |
| 202 | + <td class="px-4 py-2 text-gray-700 dark:text-gray-300">monde</td> |
| 203 | + </tr> |
| 204 | + </tbody> |
| 205 | + </table> |
| 206 | + </div> |
| 207 | + <p class="mt-3 text-sm text-gray-500 dark:text-gray-400"> |
| 208 | + If you are unsure about word counts, use the GET endpoint without alignments first — open the |
| 209 | + returned URL and count the word boxes in the editor. |
| 210 | + </p> |
| 211 | + |
| 212 | + <h2 id="errors" class={headingClass}>Errors</h2> |
| 213 | + <p class="mt-3"> |
| 214 | + Errors return HTTP 400 with a JSON body: |
| 215 | + </p> |
| 216 | + <pre class="{preClass} mt-3">{`{ "error": "alignments[0]: lines 0 and 2 are not adjacent" }`}</pre> |
| 217 | + |
| 218 | + <p class="mt-3 text-sm text-gray-500 dark:text-gray-400"> |
| 219 | + All endpoints support CORS (<span class={codeClass}>Access-Control-Allow-Origin: *</span>). |
| 220 | + </p> |
| 221 | + |
| 222 | + <SiteFooter class="mt-12" /> |
| 223 | +</main> |
0 commit comments