gallery

The hand-made demos: vowel sandhi, reciprocal rank fusion, softmax and temperature, nakṣatra and pāda, and a parabola.

The gallery demos live in rupaka/demos/ as JSON. They show what a good demo looks like, and the agent gives two of them to the model as examples. The data of the Sanskrit and jyotiṣa demos comes from the vedicreader and ganapati sources, not from memory:

demo data source
vowel sandhi the six rule names and their Aṣṭādhyāyī numbers (6.1.101, 6.1.87, 6.1.88, 6.1.77, 6.1.78, 6.1.109) ganapati vyakarana.py, JOINS
nakṣatra and pāda the 27 nakṣatra names and lords, the 12 rāśi names, 13°20′ for a nakṣatra and 3°20′ for a pāda vedicreader vr/muhurtha/names.py, vr/jyotisha/nakshatra/primer.py
import json
from rupaka.spec import *
from rupaka.spec import _gates
from rupaka.render import show, save, page
from rupaka.check import check, can_check, browser, in_thread

The demos

Each demo has a gate. Here are the gate questions and the blocks of each demo.

g = gallery()
for k, s in g.items(): print(f"{k:24} {[b['type'] for b in s['blocks']]}\n{'':24} {next(_gates(s['blocks']))['prompt']}")

Each demo is valid

validate finds no errors in any gallery demo.

test_eq({k: list(validate(s)) for k, s in g.items()}, {k: [] for k in g})

The builder form

A notebook author can write the sandhi demo with the builders. The result is the same dict as the JSON file.

V = ['a', 'ā', 'i', 'ī', 'u', 'ū', 'ṛ', 'e', 'ai', 'o', 'au']
sd = g['vowel-sandhi']
d = demo('vowel-sandhi', 'Vowel sandhi', ask=sd['ask'], state=dict(a='a', b='i'), derive=[rules('sandhi', ['a', 'b'], 'join')],
         blocks=[row(wheel('a', V, 'End of word 1'), wheel('b', V, 'Start of word 2')),
                 gate('join', 'What do the two vowels become?', from_('join.alts'), 'join.out', context='For {a} + {b}:',
                      why='Say why, in one line, before you lock in.', again=True),
                 readout('{a} + {b} → {join.out}', label='The join', after='join'),
                 caption(sd['blocks'][3]['text'], after='join')],
         tables=sd['tables'])
test_eq(d, sd)

The data

At 47°, the point is in Rohiṇī, pāda 3, in Vṛṣabha. At 30°, the start of Vṛṣabha, it is in Kṛttikā, pāda 2.

nk = g['nakshatra-pada']
test_eq(run(nk)['where'], 'Rohiṇī, pāda 3')
test_eq(run(nk)['rasi']['name'], 'Vṛṣabha')
test_eq(run(nk, dict(lon=30, show_pada=False))['where'], 'Kṛttikā, pāda 2')

For a + i, the join is e (guṇa). The wrong options come from the other rows of the table.

j = run(sd)['join']
test_eq((j['out'], j['name']), ('e', 'guṇa'))
test_eq(sorted(j['alts']), ['e', 'ā', 'ī', 'ū'])

With k = 60 the fused winner is B, which is in both lists. With k = 1 it is A, the top of one list.

rr = g['reciprocal-rank-fusion']
test_eq(run(rr)['fused'][0]['id'], 'B')
test_eq(run(rr, {**rr['state'], 'k': 1})['fused'][0]['id'], 'A')

Each demo draws and plays

In a browser, each demo passes the whole check in light and dark.

def check_all(specs, shots=None):
    with browser() as br: return {k: check(s, shots=shots, b=br).errors for k, s in specs.items()}
if can_check(): test_eq(in_thread(check_all, g), {k: [] for k in g})

One page

save writes the whole gallery to one page that works from file://.

import tempfile
from pathlib import Path
p = save(list(g.values()), Path(tempfile.mkdtemp())/'gallery.html', title='rupaka gallery', lead='Predict first. Then the demo shows the rest.')
assert p.exists() and (p.parent/'fonts').exists()

In a notebook, show draws a demo:

show(g['reciprocal-rank-fusion'])