nx_caption_emit_test.nx source
↩ module page · 204 lines · 7868 B
1// nx_caption_emit_test.nx -- full HTML-paste -> first-person caption smoke.
2//
3// Exercises the full Tier 0-5 chain end-to-end:
4// 1. paste raw HTML (mock literotica chapter)
5// 2. nx_html_extract -> body text + title
6// 3. nx_text_ingest -> StoryBeats
7// 4. nx_term_extract -> learned outfit/location vocabulary
8// 5. nx_cooccur_observe_db + nx_arc_anchor_discover -> motifs
9// 6. nx_scene_index_build -> SceneCandidate
10// 7. nx_caption_emit (LITEROTICA / JOYCAPTION / RAW_JSON) -> downstream
11// prompt text
12//
13// Exit code: 0 = pass, N = failed assertion N.
14
15import "syscalls.nx"
16import "nx_media_pool.nx"
17import "nx_storybeat.nx"
18import "nx_storydb.nx"
19import "nx_html_extract.nx"
20import "nx_text_ingest.nx"
21import "nx_term_registry.nx"
22import "nx_term_extract.nx"
23import "nx_term_cooccur.nx"
24import "nx_arc_anchor.nx"
25import "nx_scene_index.nx"
26import "nx_pov_shift.nx"
27import "nx_caption_emit.nx"
28
29func main() -> i64 {
30
31 // ---------- Block 10: html extract -----------------------------
32 let html_buf: *u8 = sys_mmap(2048)
33 var hk: i64 = 0
34 while hk < 2048 { html_buf[hk] = 0; hk = hk + 1 }
35 let html: *u8 = "<html><head><title>Apron Morning</title><style>body{}</style></head><body><p>He walked into the kitchen wearing an apron.</p><p>She watched him from the doorway.</p><script>x=1</script><p>He stood at the stove and stirred the pot.</p></body></html>"
36 var ci: i64 = 0
37 while html[ci] != 0 {
38 html_buf[ci] = html[ci]
39 ci = ci + 1
40 }
41 let hlen: i64 = ci
42
43 let extract: *HtmlExtract = nx_html_extract(html_buf, hlen)
44 if extract.title_len < 5 { return 10 }
45 if extract.body_len < 20 { return 11 }
46 // Title should equal "Apron Morning" (13 bytes).
47 if extract.title_len != 13 { return 12 }
48 // First two title bytes "Ap".
49 if extract.title_buf[0] != 0x41 { return 13 }
50 if extract.title_buf[1] != 0x70 { return 14 }
51 // Body should NOT contain "x=1" (script stripped). Check by
52 // scanning for '=' which only appears in the stripped script.
53 var has_eq: i64 = 0
54 var bi: i64 = 0
55 while bi < extract.body_len {
56 if extract.body_buf[bi] == 0x3D { has_eq = 1 }
57 bi = bi + 1
58 }
59 if has_eq != 0 { return 15 }
60
61 // ---------- Block 20: POV shift directly on a literal ---------
62 //
63 // Source: "He walked into the kitchen wearing an apron."
64 // After he->I: "I walked into the kitchen wearing an apron."
65 let src1: *u8 = "He walked into the kitchen wearing an apron."
66 var src1_n: i64 = 0
67 while src1[src1_n] != 0 { src1_n = src1_n + 1 }
68 let dst1: *u8 = sys_mmap(256)
69 let n1: i64 = nx_pov_shift(NX_POV_GENDER_HE, src1, src1_n, dst1, 256)
70 if n1 < src1_n - 2 { return 20 }
71 // First byte should be capital I.
72 if dst1[0] != 0x49 { return 21 }
73 if dst1[1] != 0x20 { return 22 } // ' '
74 if dst1[2] != 0x77 { return 23 } // 'w' in "walked"
75 // Verify "his" rewrite: "He took his hat" -> "I took my hat".
76 let src2: *u8 = "He took his hat."
77 var src2_n: i64 = 0
78 while src2[src2_n] != 0 { src2_n = src2_n + 1 }
79 let dst2: *u8 = sys_mmap(64)
80 let n2: i64 = nx_pov_shift(NX_POV_GENDER_HE, src2, src2_n, dst2, 64)
81 if n2 < 12 { return 24 }
82 // Should contain "my" at the position of "his".
83 // Find "my " in output.
84 var found_my: i64 = 0
85 var fi: i64 = 0
86 while fi < n2 - 2 {
87 if dst2[fi] == 0x6D {
88 if dst2[fi + 1] == 0x79 {
89 if dst2[fi + 2] == 0x20 { found_my = 1 }
90 }
91 }
92 fi = fi + 1
93 }
94 if found_my != 1 { return 25 }
95
96 // ---------- Block 30: full chain into caption emit -----------
97 let db: *StoryDb = nx_storydb_alloc()
98 let mid: i64 = nx_media_pool_add(db.media_pool, NX_MEDIA_TYPE_TEXT,
99 NX_MEDIA_SRC_USER_PASTE,
100 extract.body_buf, extract.body_len,
101 0 as *u8, 0,
102 0 as *u8, 0,
103 1700000000)
104 if mid < 0 { return 30 }
105 if nx_text_ingest(db, mid) != NX_TEXT_INGEST_OK { return 31 }
106 if db.n_beats < 2 { return 32 }
107
108 let reg: *TermRegistry = nx_term_registry_alloc()
109 if nx_term_extract_all(db, reg) != NX_EXTR_OK { return 33 }
110
111 let co: *Cooccur = nx_cooccur_alloc()
112 let n_pairs: i64 = nx_cooccur_observe_db(co, db)
113 if n_pairs < 1 { return 34 }
114
115 let scratch_buf: *u8 = sys_mmap(32 * NX_COOCCUR_PAIR_BYTES)
116 let scratch: *CooccurPair = scratch_buf as *CooccurPair
117 let anchor_buf: *u8 = sys_mmap(16 * NX_ARC_ANCHOR_BYTES)
118 let anchors: *ArcAnchor = anchor_buf as *ArcAnchor
119 let n_anch: i64 = nx_arc_anchor_discover(co, reg, scratch, 32,
120 anchors, 16)
121 if n_anch < 1 { return 35 }
122
123 let idx: *SceneIndex = nx_scene_index_alloc()
124 let n_built: i64 = nx_scene_index_build(idx, db, anchors, n_anch)
125 if n_built < 1 { return 36 }
126
127 // Find an OUTFIT_LOCATION candidate.
128 let cid: i64 = nx_scene_index_first_of_kind(idx,
129 NX_ANCHOR_OUTFIT_LOCATION)
130 if cid < 0 { return 37 }
131
132 // ---------- Block 40: emit literotica POV-shifted caption -----
133 let cap_buf: *u8 = sys_mmap(2048)
134 let cap_len: i64 = nx_caption_emit(NX_CAP_FORMAT_LITEROTICA,
135 db, idx, cid,
136 NX_POV_GENDER_HE,
137 cap_buf, 2048)
138 if cap_len <= 0 { return 40 }
139 // The caption must NOT contain "He " (3rd person stripped).
140 // It must contain "I " (1st person inserted).
141 var has_he_cap: i64 = 0
142 var has_I_cap: i64 = 0
143 var k: i64 = 0
144 while k < cap_len - 2 {
145 if cap_buf[k] == 0x48 { // 'H'
146 if cap_buf[k + 1] == 0x65 { // 'e'
147 if cap_buf[k + 2] == 0x20 { has_he_cap = 1 }
148 }
149 }
150 if cap_buf[k] == 0x49 { // 'I'
151 if cap_buf[k + 1] == 0x20 { has_I_cap = 1 }
152 }
153 k = k + 1
154 }
155 if has_he_cap != 0 { return 41 }
156 if has_I_cap != 1 { return 42 }
157
158 // ---------- Block 50: emit joycaption (3rd person verbatim) ---
159 let cap_buf2: *u8 = sys_mmap(2048)
160 let cap_len2: i64 = nx_caption_emit(NX_CAP_FORMAT_JOYCAPTION,
161 db, idx, cid,
162 NX_POV_GENDER_HE,
163 cap_buf2, 2048)
164 if cap_len2 <= 0 { return 50 }
165 // JoyCaption should KEEP "He " (3rd person preserved).
166 var has_he2: i64 = 0
167 var k2: i64 = 0
168 while k2 < cap_len2 - 2 {
169 if cap_buf2[k2] == 0x48 {
170 if cap_buf2[k2 + 1] == 0x65 {
171 if cap_buf2[k2 + 2] == 0x20 { has_he2 = 1 }
172 }
173 }
174 k2 = k2 + 1
175 }
176 if has_he2 != 1 { return 51 }
177
178 // ---------- Block 60: emit raw JSON ---------------------------
179 let cap_buf3: *u8 = sys_mmap(2048)
180 let cap_len3: i64 = nx_caption_emit(NX_CAP_FORMAT_RAW_JSON,
181 db, idx, cid,
182 NX_POV_GENDER_HE,
183 cap_buf3, 2048)
184 if cap_len3 <= 0 { return 60 }
185 // Must start with '{' and contain "anchor_kind".
186 if cap_buf3[0] != 0x7B { return 61 }
187 var found_anchor_key: i64 = 0
188 var k3: i64 = 0
189 while k3 < cap_len3 - 11 {
190 if cap_buf3[k3] == 0x61 { // 'a'
191 if cap_buf3[k3 + 1] == 0x6E { // 'n'
192 if cap_buf3[k3 + 2] == 0x63 { // 'c'
193 if cap_buf3[k3 + 3] == 0x68 { // 'h'
194 found_anchor_key = 1
195 }
196 }
197 }
198 }
199 k3 = k3 + 1
200 }
201 if found_anchor_key != 1 { return 62 }
202
203 return 0
204}