code wiki / (root) / nx_companion_render.nx

nx_companion_render.nx source

↩ module page · 118 lines · 7103 B

1// nx_companion_render.nx -- ties the visual arc to the LIVE image-gen API. The sovereign generator already 2// exists and works: nx_pe_container_sdserver (a Nishi container PE, no Docker) Job-governs sd-server, which 3// serves an OpenAI-compatible endpoint POST /v1/images/generations on :7861 and returns a real PNG. What was 4// missing (the "clothes stayed the same, arcs never shifted" defect) is HERE: this composes the generation 5// request from the persona's ADVANCING visual arc, so each render is the same person in a NEW outfit/scene/pose. 6// render_request advances the arc and builds the JSON body; render_http wraps it in a POST the sovereign HTTP 7// client sends to the hubbed generator. The prompt is the load-bearing field (identity anchor + varying state, 8// from nx_visual_arc) -- projected verbatim, no censor (rule 25). license_tier: ORIGINAL 9import "nx_visual_arc.nx" 10 11// JSON-escape s[0..slen) into d at o (escape '"' and '\\'); returns new offset 12func rr_json_esc(d: *u8, o: i64, s: *u8, slen: i64) -> i64 { 13 var i: i64 = 0 14 var w: i64 = o 15 while i < slen { 16 let c: u8 = s[i] 17 if c == (0x22 as u8) { d[w]=0x5C as u8; w=w+1; d[w]=0x22 as u8; w=w+1 } 18 else { if c == (0x5C as u8) { d[w]=0x5C as u8; w=w+1; d[w]=0x5C as u8; w=w+1 } 19 else { d[w]=c; w=w+1 } } 20 i = i + 1 21 } 22 return w 23} 24func rr_catn(d: *u8, o: i64, v: i64) -> i64 { 25 let t: *u8=sys_mmap(24); var m: i64=v; var k: i64=0 26 if m < 0 { d[o] = 45 as u8; o = o + 1; m = 0 - m } 27 if m<0 { m=0 } 28 if m==0 { t[0]=48 as u8; k=1 } 29 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 30 var w: i64=o; var i: i64=0; while i<k { d[w]=t[k-1-i]; w=w+1; i=i+1 } 31 return w 32} 33 34// build the OpenAI-compat generation body for a GIVEN step (deterministic; no state change). Returns length. 35// Turbo Z-Image defaults: 8 steps, cfg 1.0, euler (per the verified sd-cli flags). 512x512. 36func render_body_at_pfx(prefix: *u8, persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { 37 let pbuf: *u8 = sys_mmap(16384) 38 let pl: i64 = varc_prompt_at_pfx(prefix, persona, step, pbuf, 16384) 39 if pl <= 0 { out[0]=0 as u8; return 0 } 40 var o: i64 = 0 41 o = tr_cat(out, o, "{\"prompt\":\"" as *u8) 42 o = rr_json_esc(out, o, pbuf, pl) 43 o = tr_cat(out, o, "\",\"n\":1,\"size\":\"512x512\",\"sample_steps\":8,\"cfg_scale\":1.0,\"sampling_method\":\"euler\"}" as *u8) 44 out[o] = 0 as u8 45 return o 46} 47 48// ADVANCE the persona's arc, then build the body at the new step. This is the per-render entry: every call 49// yields the same person in a NEW outfit/scene (the fix). Returns body length; *step_out = the new step. 50func render_request_pfx(prefix: *u8, persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { 51 let s: i64 = varc_advance_pfx(prefix, persona) 52 if (step_out as i64) != 0 { step_out[0] = s } 53 return render_body_at_pfx(prefix, persona, s, out, cap) 54} 55 56// wrap a body in a POST /v1/images/generations HTTP request for the sovereign HTTP client to send to the 57// hubbed generator (:7861). host = the generator host header. Returns request length. 58func render_http_at_pfx(prefix: *u8, persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { 59 let body: *u8 = sys_mmap(16384) 60 let bl: i64 = render_body_at_pfx(prefix, persona, step, body, 16384) 61 if bl <= 0 { out[0]=0 as u8; return 0 } 62 var o: i64 = 0 63 o = tr_cat(out, o, "POST /v1/images/generations HTTP/1.1\r\nHost: " as *u8) 64 o = tr_cat(out, o, host) 65 o = tr_cat(out, o, "\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 66 o = rr_catn(out, o, bl) 67 o = tr_cat(out, o, "\r\nConnection: close\r\n\r\n" as *u8) 68 var i: i64 = 0; while i < bl { out[o]=body[i]; o=o+1; i=i+1 } 69 out[o] = 0 as u8 70 return o 71} 72 73// --- integration with the EXISTING sovereign gen daemon (nx_gen_orchestrator, hubbed on the NAS) --- 74// The orchestrator exposes POST /gen/api/generate (opaque-gated behind nx_gen_gateway) with its OWN shape, 75// internally drives the GPU worker (/sdapi/v1/txt2img), then decodes/ingests/content-addresses each PNG and 76// serves it at /gen/img/<cid> through the gallery. Feeding the persona's advancing, grounded prompt to THIS 77// endpoint is the real integration -- the companion's images flow through the proven pipeline into her gallery, 78// same person, new scene every render. This targets the daemon's shape, not the raw worker's. 79func render_gen_body_at_pfx(prefix: *u8, persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { 80 let pbuf: *u8 = sys_mmap(16384) 81 let pl: i64 = varc_prompt_at_pfx(prefix, persona, step, pbuf, 16384) 82 if pl <= 0 { out[0]=0 as u8; return 0 } 83 var o: i64 = 0 84 o = tr_cat(out, o, "{\"prompt\":\"" as *u8) 85 o = rr_json_esc(out, o, pbuf, pl) 86 o = tr_cat(out, o, "\",\"negative\":\"blurry, lowres, deformed, extra limbs\",\"width\":512,\"height\":512,\"steps\":8,\"cfg\":\"1.0\",\"seed\":-1,\"count\":1,\"sampler\":\"euler\"}" as *u8) 87 out[o] = 0 as u8 88 return o 89} 90// ADVANCE the arc, then build the orchestrator body at the new step (the per-render entry for the NAS pipeline) 91func render_gen_request_pfx(prefix: *u8, persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { 92 let s: i64 = varc_advance_pfx(prefix, persona) 93 if (step_out as i64) != 0 { step_out[0] = s } 94 return render_gen_body_at_pfx(prefix, persona, s, out, cap) 95} 96// wrap the orchestrator body in a POST /gen/api/generate request for the sovereign HTTP client 97func render_gen_http_at_pfx(prefix: *u8, persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { 98 let body: *u8 = sys_mmap(16384) 99 let bl: i64 = render_gen_body_at_pfx(prefix, persona, step, body, 16384) 100 if bl <= 0 { out[0]=0 as u8; return 0 } 101 var o: i64 = 0 102 o = tr_cat(out, o, "POST /gen/api/generate HTTP/1.1\r\nHost: " as *u8) 103 o = tr_cat(out, o, host) 104 o = tr_cat(out, o, "\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 105 o = rr_catn(out, o, bl) 106 o = tr_cat(out, o, "\r\nConnection: close\r\n\r\n" as *u8) 107 var i: i64 = 0; while i < bl { out[o]=body[i]; o=o+1; i=i+1 } 108 out[o] = 0 as u8 109 return o 110} 111func render_gen_body_at(persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { return render_gen_body_at_pfx(VID_PREFIX, persona, step, out, cap) } 112func render_gen_request(persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { return render_gen_request_pfx(VID_PREFIX, persona, out, cap, step_out) } 113func render_gen_http_at(persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { return render_gen_http_at_pfx(VID_PREFIX, persona, step, host, out, cap) } 114 115// production-prefix wrappers (the persona's real visual store) 116func render_body_at(persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { return render_body_at_pfx(VID_PREFIX, persona, step, out, cap) } 117func render_request(persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { return render_request_pfx(VID_PREFIX, persona, out, cap, step_out) } 118func render_http_at(persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { return render_http_at_pfx(VID_PREFIX, persona, step, host, out, cap) }