@aastrika/ai-elements 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ `@aastrika/ai-elements`. Newest first. One line per change, so a host team can
4
+ see at a glance what to expect when they upgrade.
5
+
6
+ Versions follow semver: a **minor** adds something, a **patch** fixes something,
7
+ and neither removes anything a host was using.
8
+
9
+ ## 0.3.0
10
+
11
+ **Added**
12
+ - `default-translate-into` on `<aastrika-assessment>` — produce the same
13
+ questions in other languages, comma-separated: `"ta,or,bn"`
14
+ - `assessmentReady` now carries `languages`, the translations actually produced
15
+ - Reviewers get a tab per language; Excel exports one sheet per language, CSV
16
+ one language at a time
17
+
18
+ **Fixed**
19
+ - `onError` was never called for hosts configuring through `provideAastrika()`
20
+
21
+ **Notes for integrators**
22
+ - Nothing is removed and nothing changes for a host that ignores the new input
23
+ - `languages` can be shorter than what was asked for: a translation that fails
24
+ its checks is dropped rather than stored wrong
25
+
26
+ ## 0.2.1
27
+
28
+ **Fixed**
29
+ - Documentation corrections in the published README
30
+
31
+ ## 0.2.0
32
+
33
+ **Added**
34
+ - Starting-value inputs (`default-language`, `default-difficulty` and others),
35
+ events (`planReady`, `videoReady`, `assessmentReady`, `reportLoaded`) and an
36
+ `onError` callback
37
+
38
+ ## 0.1.0
39
+
40
+ **Added**
41
+ - First release: `<aastrika-content-studio>`, `<aastrika-assessment>` and
42
+ `<aastrika-reports>` as custom elements, with `configure()`
package/README.md CHANGED
@@ -1,42 +1,37 @@
1
+ <div align="center">
2
+
1
3
  # @aastrika/ai-elements
2
4
 
3
- **Three Aastrika features as custom elements.** Works in React, Vue, Angular,
4
- Svelte or plain HTML.
5
+ **Three AI features. Three HTML tags. Any framework.**
5
6
 
6
- | Tag | What it does |
7
- |---|---|
8
- | `<aastrika-content-studio>` | A document becomes a narrated, illustrated training video |
9
- | `<aastrika-assessment>` | Source material becomes a validated MCQ set |
10
- | `<aastrika-reports>` | Who used what, and what it cost *(admin only)* |
7
+ [![npm](https://img.shields.io/npm/v/@aastrika/ai-elements?color=A98229&label=npm)](https://www.npmjs.com/package/@aastrika/ai-elements)
8
+ [![size](https://img.shields.io/badge/gzipped-99%20kB-A98229)](https://www.npmjs.com/package/@aastrika/ai-elements)
9
+ [![deps](https://img.shields.io/badge/dependencies-0-A98229)](https://www.npmjs.com/package/@aastrika/ai-elements)
10
+ [![licence](https://img.shields.io/npm/l/@aastrika/ai-elements?color=A98229)](https://github.com/Sphere/aastrika-ai-service/blob/master/LICENSE)
11
11
 
12
- One file, **86 kB** over the wire, **no dependencies**. Angular is compiled
13
- inside, so you never install it and never upgrade because we did.
12
+ </div>
14
13
 
15
- ---
16
-
17
- ## Contents
14
+ ```html
15
+ <aastrika-content-studio></aastrika-content-studio> <!-- document → narrated video -->
16
+ <aastrika-assessment></aastrika-assessment> <!-- material → MCQ set, translated -->
17
+ <aastrika-reports></aastrika-reports> <!-- who used what, and what it cost -->
18
+ ```
18
19
 
19
- | | |
20
- |---|---|
21
- | [The three features](#the-three-features) | What each element does |
22
- | [Setup](#setup) | Install, access, configure, mount |
23
- | [Framework notes](#framework-notes) | React · Angular · Plain HTML |
24
- | [Configuration](#configuration) | The three values, and why two are functions |
25
- | [Access](#access) | Which gateway groups each feature needs |
26
- | [Theming](#theming) | CSS custom properties |
27
- | [Knowing when something failed](#knowing-when-something-failed) | Routing errors to your monitoring |
28
- | [Inputs and events](#inputs-and-events) | Opening the form set up, and acting on the result |
29
- | [When it does not work](#when-it-does-not-work) | Symptom → cause |
30
- | [Browser support](#browser-support) · [Server rendering](#server-rendering) | Constraints |
20
+ Works in **React, Vue, Angular, Svelte or plain HTML**. Angular is compiled
21
+ inside the package, so you never install it and never upgrade because we did.
31
22
 
32
23
  ---
33
24
 
34
- ## Quick start
25
+ ## Ship it in three steps
26
+
27
+ **1 — Install.** No peer dependencies, nothing to match.
35
28
 
36
29
  ```bash
37
30
  npm i @aastrika/ai-elements
38
31
  ```
39
32
 
33
+ **2 — Configure once**, before anything renders.
34
+
40
35
  ```js
41
36
  import { configure } from '@aastrika/ai-elements';
42
37
 
@@ -47,53 +42,43 @@ configure({
47
42
  });
48
43
  ```
49
44
 
45
+ **3 — Write the tag.** Importing the package registers it, so there is no step 4.
46
+
50
47
  ```html
51
- <aastrika-content-studio></aastrika-content-studio>
48
+ <aastrika-assessment default-language="hi" default-translate-into="ta,or"></aastrika-assessment>
52
49
  ```
53
50
 
54
- That is the whole integration. The rest of this file is detail.
55
-
56
- > **You also need gateway access.** The package authenticates nobody — see
57
- > [Access](#access) for the groups each feature requires.
51
+ <div align="center">
58
52
 
59
- ---
53
+ **That is the whole integration.**
54
+ A trainer uploads a PDF and gets a validated quiz in Hindi, Tamil and Odia —
55
+ same questions, same answer key, ready to download.
60
56
 
61
- ## How it fits together
57
+ </div>
62
58
 
63
- ```mermaid
64
- flowchart LR
65
- subgraph host["Your application"]
66
- cfg["configure()"]
67
- tag["&lt;aastrika-content-studio&gt;"]
68
- end
59
+ > [!IMPORTANT]
60
+ > **You also need gateway access.** This package authenticates nobody — your
61
+ > gateway decides. See [Access](#access) for the groups each feature needs.
69
62
 
70
- subgraph pkg["@aastrika/ai-elements"]
71
- el["Custom element"]
72
- int["Interceptor"]
73
- end
63
+ ---
74
64
 
75
- subgraph svc["Aastrika"]
76
- gw["Gateway<br/>checks the token"]
77
- api["AI service"]
78
- end
65
+ ## Where to look
79
66
 
80
- cfg -.->|apiBase · auth · creator| int
81
- tag --> el
82
- el --> int
83
- int -->|"Authorization<br/>x-aastrika-creator"| gw
84
- gw --> api
85
- api -.->|JSON| el
86
- el -.->|onError| cfg
87
-
88
- classDef a fill:#0F766E,stroke:none,color:#fff
89
- classDef b fill:#f1f5f4,stroke:#cbd5d3,color:#16181d
90
- class el,int a
91
- class cfg,tag,gw,api b
92
- ```
67
+ | | |
68
+ |---|---|
69
+ | **[The three features](#the-three-features)** | What each element actually does |
70
+ | **[Setup](#setup)** | Install · access · configure · mount |
71
+ | **[Configuration](#configuration)** | The three values, and why two are functions |
72
+ | **[Access](#access)** | Which gateway groups each feature needs |
73
+ | **[Inputs and events](#inputs-and-events)** | Open the form set up, act on the result |
74
+ | **[Error reporting](#knowing-when-something-failed)** | Route failures to your monitoring |
75
+ | | |
76
+ | [Integration guide ↗](https://github.com/Sphere/aastrika-ai-service/blob/master/docs/INTEGRATION.md) | Step by step, both auth paths |
77
+ | [Runnable Angular app ↗](https://github.com/Sphere/aastrika-ai-service/tree/master/frontend/lib-demo-app) | Clone it, change one line, run it |
78
+ | [Changelog ↗](./CHANGELOG.md) | What changed in each version |
93
79
 
94
- **Your application supplies three values. The package does the rest** — builds
95
- every request from `apiBase`, calls your two functions on each one, and renders
96
- into your page, styled through CSS custom properties.
80
+ *Framework notes, theming, troubleshooting and server rendering are collapsed
81
+ below — open the one you need.*
97
82
 
98
83
  ---
99
84
 
@@ -101,45 +86,65 @@ into your page, styled through CSS custom properties.
101
86
 
102
87
  ### `<aastrika-content-studio>`
103
88
 
104
- Upload a PDF, pick a style, language and voice, and get back a narrated,
105
- illustrated training video.
89
+ **A PDF goes in. A narrated, illustrated training video comes out.**
90
+
91
+ ```
92
+ upload ──▶ pick style ──▶ review the plan ──▶ generate ──▶ play / download
93
+ language free, revisable the only
94
+ voice cost shown first paid step
95
+ ```
106
96
 
107
- Planning is free and repeatable — the user sees the scene-by-scene plan and a
108
- cost estimate, and can revise it in writing as many times as they like. Only
109
- **Generate video** spends money, and the user sees what it will cost first.
110
- While it renders they get five-phase progress and a live log; at the end they
111
- can play, download or delete it.
97
+ The user uploads source material, picks a style, language and voice, and sees a
98
+ scene-by-scene plan with an estimated cost. **Planning is free and repeatable** —
99
+ they can rewrite it in plain words as often as they like. Only *Generate video*
100
+ spends money, and the estimate is on screen before they commit.
112
101
 
113
- [Full walkthrough →](features/content-studio/README.md)
102
+ While it renders they see five-phase progress and a live log. At the end they
103
+ can play it, download it, or delete it.
104
+
105
+ [Full walkthrough →](https://github.com/Sphere/aastrika-ai-service/blob/master/docs/API.md)
114
106
 
115
107
  ### `<aastrika-assessment>`
116
108
 
117
- Files and links in, a validated multiple-choice set out — with control over
118
- language, question count, difficulty and Bloom level.
109
+ **Training material goes in. A validated MCQ set comes out — in as many
110
+ languages as you need.**
111
+
112
+ ```
113
+ files & links ──▶ settings ──▶ questions ──▶ review each ──▶ export
114
+ language checked language on xlsx / csv
115
+ count before you its own tab
116
+ difficulty see them
117
+ ```
118
+
119
+ Every question is checked before it reaches the user: exactly one correct
120
+ option, no duplicates, nothing the source material does not support.
119
121
 
120
- Every question is checked before it is returned: one correct option, no
121
- duplicates, nothing the source material does not support. The user can fix
122
- wording, re-tick the correct option, then export XLSX or CSV.
122
+ Ask for other languages and you get the **same** questions translated — same
123
+ order, same options, same answer key — so one answer key marks every paper and
124
+ scores compare across them. The reviewer reads each language on its own tab and
125
+ fixes wording in place; the correct option is shared, so it is set once.
123
126
 
124
- [Full walkthrough →](features/assessment/README.md)
127
+ [Full walkthrough →](https://github.com/Sphere/aastrika-ai-service/blob/master/docs/API.md)
125
128
 
126
129
  ### `<aastrika-reports>`
127
130
 
128
- Who used what, and what it cost — totals for videos, assessments, people and
129
- estimated spend, split by tool, with a searchable table of creators.
131
+ **Who made what, and what it cost.**
132
+
133
+ Totals for videos, assessments, people and estimated spend, split by tool, with
134
+ a searchable table of creators.
130
135
 
131
- **Needs `contentAdmin` at the gateway**, and most consumers should not have it:
132
- spend figures are not for a partner's ordinary users. The service applies no
133
- role check of its own, so the gateway's ACL is the only thing keeping them
134
- apart.
136
+ > [!WARNING]
137
+ > **Needs `contentAdmin`, and most consumers should not have it.** Spend figures
138
+ > are not for a partner's ordinary users. The service applies no role check of
139
+ > its own — the gateway's ACL is the only thing keeping them apart.
135
140
 
136
- [Full walkthrough →](features/reports/README.md)
141
+ [Full walkthrough →](https://github.com/Sphere/aastrika-ai-service/blob/master/docs/API.md)
137
142
 
138
143
  ---
139
144
 
140
145
  ## Setup
141
146
 
142
- The [Quick start](#quick-start) above is the whole integration. What each step
147
+ The [Quick start](#ship-it-in-three-steps) above is the whole integration. What each step
143
148
  is actually doing:
144
149
 
145
150
  | | Step | Notes |
@@ -151,7 +156,8 @@ is actually doing:
151
156
 
152
157
  ---
153
158
 
154
- ## Framework notes
159
+ <details>
160
+ <summary><b>React · Angular · Vue · plain HTML</b></summary>
155
161
 
156
162
  ### React
157
163
 
@@ -252,31 +258,79 @@ calling it, as above, prevents both.
252
258
 
253
259
  ---
254
260
 
261
+ </details>
262
+
263
+ ---
264
+
265
+ ## How it fits together
266
+
267
+ ```mermaid
268
+ flowchart LR
269
+ subgraph host["Your application"]
270
+ cfg["configure()"]
271
+ tag["&lt;aastrika-content-studio&gt;"]
272
+ end
273
+
274
+ subgraph pkg["@aastrika/ai-elements"]
275
+ el["Custom element"]
276
+ int["Interceptor"]
277
+ end
278
+
279
+ subgraph svc["Aastrika"]
280
+ gw["Gateway<br/>checks the token"]
281
+ api["AI service"]
282
+ end
283
+
284
+ cfg -.->|apiBase · auth · creator| int
285
+ tag --> el
286
+ el --> int
287
+ int -->|"Authorization<br/>creator in the body"| gw
288
+ gw --> api
289
+ api -.->|JSON| el
290
+ el -.->|onError| cfg
291
+
292
+ classDef a fill:#0F766E,stroke:none,color:#fff
293
+ classDef b fill:#f1f5f4,stroke:#cbd5d3,color:#16181d
294
+ class el,int a
295
+ class cfg,tag,gw,api b
296
+ ```
297
+
298
+ **Your application supplies three values. The package does the rest** — builds
299
+ every request from `apiBase`, calls your two functions on each one, and renders
300
+ into your page, styled through CSS custom properties.
301
+
302
+ ---
303
+
255
304
  ## Configuration
256
305
 
257
- Three things, and nothing else.
306
+ Three values. That is the whole contract.
258
307
 
259
- | | |
260
- |---|---|
261
- | `apiBase` | Where the service is, no trailing slash. Empty string means same-origin. |
262
- | `getAuthHeaders` | Headers proving the caller may use the service — in practice a bearer token. |
263
- | `creator` | Who is signed into **your** application — their name or email, shown as-is in the usage report. |
264
- | `onError` | Optional. Called whenever a request fails, so your monitoring hears about it. |
308
+ | | | |
309
+ |---|---|---|
310
+ | `apiBase` | **required** | Where the service is, no trailing slash. `''` means same-origin |
311
+ | `getAuthHeaders` | **required** | Headers proving the caller may use the service — a bearer token in practice |
312
+ | `creator` | **required** | Who is signed into *your* app. A name or email, shown as-is in the usage report |
313
+ | `onError` | optional | Called whenever a request fails, so your monitoring hears about it |
314
+
315
+ ### Why two of them are functions
265
316
 
266
- **Both are functions, and both are called on every request.** Tokens expire: a
267
- string handed over at startup stops working mid-session and the package has no
268
- way to ask for a fresh one. A function lets you return whatever your own auth
269
- library currently holds, and lets you switch user without reloading.
317
+ Tokens expire. A string handed over at startup stops working mid-session, and
318
+ the package has no way to ask for a fresh one.
270
319
 
271
- `creator` should be a **name or email** — it is displayed as-is in the usage
272
- report, so `asha.kumari` reads well and a UUID does not.
320
+ ```js
321
+ getAuthHeaders: async () => ({ Authorization: `Bearer ${await auth.token()}` }),
322
+ // ^^^^^ called on every request, so a refreshed token just works
323
+ ```
273
324
 
274
- `creator` is **attribution, not identity**. It is recorded against anything the
275
- call creates and the usage report groups by it. Nothing verifies it — the
276
- gateway decides whether the call is allowed at all.
325
+ The same goes for `creator`: a function lets you switch user without reloading
326
+ the page.
277
327
 
278
- The package authenticates nobody and has no login of its own. You are already
279
- signed in, and you know who that is better than we could.
328
+ > [!NOTE]
329
+ > **`creator` is attribution, not identity.** It is recorded against whatever
330
+ > the call creates and the usage report groups by it. Nothing verifies it — the
331
+ > gateway decides whether the call is allowed at all.
332
+ >
333
+ > Use `asha.kumari`, not a UUID. It appears as-is in the report.
280
334
 
281
335
  ---
282
336
 
@@ -294,12 +348,14 @@ needs:
294
348
  Deleting anything needs `contentAdmin` as well. Without `contentUpdate` the
295
349
  features still work, but the revise step returns 403.
296
350
 
351
+ > [!CAUTION]
297
352
  > **`generate-video` is the only call that spends real money**, and it sits on a
298
353
  > deliberately low rate limit. Users see a cost estimate before triggering it.
299
354
 
300
355
  ---
301
356
 
302
- ## Theming
357
+ <details>
358
+ <summary><b>Theming with CSS custom properties</b></summary>
303
359
 
304
360
  CSS custom properties are the styling surface:
305
361
 
@@ -319,6 +375,10 @@ stylesheet is broad, scope it away from the three tags.
319
375
 
320
376
  ---
321
377
 
378
+ </details>
379
+
380
+ ---
381
+
322
382
  ## Knowing when something failed
323
383
 
324
384
  The elements show their own error to the user. `onError` is the second copy, for
@@ -366,6 +426,7 @@ All are **starting values** the user can still change.
366
426
  | `assessment` | `default-language` | |
367
427
  | | `default-question-count` | |
368
428
  | | `default-difficulty` | `mixed`, `easy`, `medium`, `hard` |
429
+ | | `default-translate-into` | Also produce the same questions in these languages, comma-separated: `"ta,or,bn"` |
369
430
  | `reports` | `creator-filter` | Opens filtered to one creator |
370
431
 
371
432
  ```html
@@ -373,6 +434,34 @@ All are **starting values** the user can still change.
373
434
  </aastrika-content-studio>
374
435
  ```
375
436
 
437
+ ### One quiz, several languages
438
+
439
+ `default-translate-into` produces the **same** questions in other languages —
440
+ same order, same options, same answer key — so one answer key marks every
441
+ language and scores compare across them.
442
+
443
+ ```html
444
+ <aastrika-assessment default-language="hi" default-translate-into="en,mr">
445
+ </aastrika-assessment>
446
+ ```
447
+
448
+ The reviewer gets a tab per language. Excel holds every language, one sheet
449
+ each; CSV holds one language at a time.
450
+
451
+ `assessmentReady` reports what came back:
452
+
453
+ ```js
454
+ el.addEventListener('assessmentReady', (e) => {
455
+ e.detail.language; // 'hi' — the one the questions were written in
456
+ e.detail.languages; // ['en','mr'] — the translations produced
457
+ });
458
+ ```
459
+
460
+ `languages` can be shorter than what was asked for. A translation is checked for
461
+ question count, ids, answer key, clinical numbers and script; one that fails is
462
+ dropped rather than stored wrong. What is **not** checked is whether the
463
+ translation reads well — that still needs someone who speaks the language.
464
+
376
465
  ### Events
377
466
 
378
467
  | Element | Event | Fires when | `detail` |
@@ -380,7 +469,7 @@ All are **starting values** the user can still change.
380
469
  | `content-studio` | `planReady` | A plan comes back. **Repeatable** — free, so this can fire several times | `jobId`, `title`, `sceneCount`, `estimatedUsd` |
381
470
  | | `videoStarted` | The user commits to a render. **This is where money is spent** | `jobId` |
382
471
  | | `videoReady` | The video is finished | `jobId`, `videoUrl` |
383
- | `assessment` | `assessmentReady` | A validated question set comes back | `jobId`, `questionCount`, `language` |
472
+ | `assessment` | `assessmentReady` | A validated question set comes back | `jobId`, `questionCount`, `language`, `languages` |
384
473
  | `reports` | `reportLoaded` | The figures are on screen | `videos`, `assessments`, `users`, `spendUsd` |
385
474
 
386
475
  ```js
@@ -398,7 +487,8 @@ any DOM event: `(videoReady)="onReady($event)"`.
398
487
 
399
488
  ---
400
489
 
401
- ## When it does not work
490
+ <details>
491
+ <summary><b>Troubleshooting — symptom → cause</b></summary>
402
492
 
403
493
  | Symptom | Cause |
404
494
  |---|---|
@@ -407,16 +497,21 @@ any DOM event: `(videoReady)="onReady($event)"`.
407
497
  | `403` on revise only | missing `contentUpdate` |
408
498
  | `403` on delete only | missing `contentAdmin` |
409
499
  | `429` on Generate video | the low rate limit, and it is intentional |
410
- | Creator recorded as `unknown` | the gateway's CORS config is dropping `x-aastrika-creator` — tell us |
500
+ | Everything recorded as `admin` | `creator` was not set, or it returned null |
411
501
  | Blank box, no errors | the module did not load, so the tag is an unknown element |
412
502
 
413
503
  ---
414
504
 
505
+ </details>
506
+
507
+ ---
508
+
415
509
  ## Browser support
416
510
 
417
- Any browser with Custom Elements v1 and Shadow DOM — everything since 2018.
511
+ Any browser with Custom Elements v1 — everything since 2018.
418
512
 
419
- ## Server rendering
513
+ <details>
514
+ <summary><b>Server rendering (Next.js, Angular Universal)</b></summary>
420
515
 
421
516
  **Import this package only in browser code.** It is not server-renderable, and
422
517
  the failure is a crash rather than an empty box: `@angular/elements` declares a
@@ -440,3 +535,8 @@ Angular Universal: keep the import inside a browser-only guard, or load it in
440
535
  Nothing is lost by this. The elements have no server-rendered output to hydrate
441
536
  — they fetch everything at runtime — so a client-only import renders exactly the
442
537
  same page.
538
+
539
+ </details>
540
+
541
+ ---
542
+
@@ -20,8 +20,15 @@
20
20
 
21
21
  /** What a request failure tells the host. Stable across features. */
22
22
  export interface AastrikaError {
23
- /** Which element the failure came from. */
24
- feature: 'content-studio' | 'assessment' | 'reports';
23
+ /**
24
+ * Which element the failure came from.
25
+ *
26
+ * The three shipped today, and open to more: a future feature emits a name
27
+ * not in this list, and narrowing the type to only these three would turn
28
+ * that into a compile error in every host's handler. The literals stay so
29
+ * an editor still suggests them.
30
+ */
31
+ feature: 'content-studio' | 'assessment' | 'reports' | (string & {});
25
32
  /** The sentence already shown to the user. */
26
33
  message: string;
27
34
  /** HTTP status. 0 means the request never left the browser — usually CORS. */
@@ -116,11 +123,29 @@ interface AastrikaAssessmentElement extends HTMLElement {
116
123
  defaultQuestionCount?: number;
117
124
  /** `'mixed'`, `'easy'`, `'medium'` or `'hard'`. */
118
125
  defaultDifficulty?: string;
126
+ /**
127
+ * Languages to render the same questions into, comma-separated
128
+ * (`"ta,or,bn"`), written as `default-translate-into` in HTML. The SAME
129
+ * assessment in each — same order, same options, same answer key — so one
130
+ * key marks every language.
131
+ *
132
+ * A starting value like the others: the user can change the selection before
133
+ * generating.
134
+ */
135
+ defaultTranslateInto?: string;
119
136
 
120
- /** A validated question set came back. */
137
+ /**
138
+ * A validated question set came back.
139
+ *
140
+ * `language` is the primary; `languages` lists the translations that were
141
+ * produced, which may be shorter than what was asked for — a language the
142
+ * model could not render faithfully is dropped rather than stored wrong.
143
+ */
121
144
  addEventListener(
122
145
  type: 'assessmentReady',
123
- listener: (e: CustomEvent<{ jobId: string; questionCount: number; language: string }>) => void,
146
+ listener: (e: CustomEvent<{
147
+ jobId: string; questionCount: number; language: string; languages: string[];
148
+ }>) => void,
124
149
  options?: boolean | AddEventListenerOptions,
125
150
  ): void;
126
151
  addEventListener(