code wiki / (root) / nx_companion_render.nx

nx_companion_render.nx source

↩ module page · 117 lines · 7048 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 { m=0 } 27 if m==0 { t[0]=48 as u8; k=1 } 28 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 29 var w: i64=o; var i: i64=0; while i<k { d[w]=t[k-1-i]; w=w+1; i=i+1 } 30 return w 31} 32 33// build the OpenAI-compat generation body for a GIVEN step (deterministic; no state change). Returns length. 34// Turbo Z-Image defaults: 8 steps, cfg 1.0, euler (per the verified sd-cli flags). 512x512. 35func render_body_at_pfx(prefix: *u8, persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { 36 let pbuf: *u8 = sys_mmap(16384) 37 let pl: i64 = varc_prompt_at_pfx(prefix, persona, step, pbuf, 16384) 38 if pl <= 0 { out[0]=0 as u8; return 0 } 39 var o: i64 = 0 40 o = tr_cat(out, o, "{\"prompt\":\"" as *u8) 41 o = rr_json_esc(out, o, pbuf, pl) 42 o = tr_cat(out, o, "\",\"n\":1,\"size\":\"512x512\",\"sample_steps\":8,\"cfg_scale\":1.0,\"sampling_method\":\"euler\"}" as *u8) 43 out[o] = 0 as u8 44 return o 45} 46 47// ADVANCE the persona's arc, then build the body at the new step. This is the per-render entry: every call 48// yields the same person in a NEW outfit/scene (the fix). Returns body length; *step_out = the new step. 49func render_request_pfx(prefix: *u8, persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { 50 let s: i64 = varc_advance_pfx(prefix, persona) 51 if (step_out as i64) != 0 { step_out[0] = s } 52 return render_body_at_pfx(prefix, persona, s, out, cap) 53} 54 55// wrap a body in a POST /v1/images/generations HTTP request for the sovereign HTTP client to send to the 56// hubbed generator (:7861). host = the generator host header. Returns request length. 57func render_http_at_pfx(prefix: *u8, persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { 58 let body: *u8 = sys_mmap(16384) 59 let bl: i64 = render_body_at_pfx(prefix, persona, step, body, 16384) 60 if bl <= 0 { out[0]=0 as u8; return 0 } 61 var o: i64 = 0 62 o = tr_cat(out, o, "POST /v1/images/generations HTTP/1.1\r\nHost: " as *u8) 63 o = tr_cat(out, o, host) 64 o = tr_cat(out, o, "\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 65 o = rr_catn(out, o, bl) 66 o = tr_cat(out, o, "\r\nConnection: close\r\n\r\n" as *u8) 67 var i: i64 = 0; while i < bl { out[o]=body[i]; o=o+1; i=i+1 } 68 out[o] = 0 as u8 69 return o 70} 71 72// --- integration with the EXISTING sovereign gen daemon (nx_gen_orchestrator, hubbed on the NAS) --- 73// The orchestrator exposes POST /gen/api/generate (opaque-gated behind nx_gen_gateway) with its OWN shape, 74// internally drives the GPU worker (/sdapi/v1/txt2img), then decodes/ingests/content-addresses each PNG and 75// serves it at /gen/img/<cid> through the gallery. Feeding the persona's advancing, grounded prompt to THIS 76// endpoint is the real integration -- the companion's images flow through the proven pipeline into her gallery, 77// same person, new scene every render. This targets the daemon's shape, not the raw worker's. 78func render_gen_body_at_pfx(prefix: *u8, persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { 79 let pbuf: *u8 = sys_mmap(16384) 80 let pl: i64 = varc_prompt_at_pfx(prefix, persona, step, pbuf, 16384) 81 if pl <= 0 { out[0]=0 as u8; return 0 } 82 var o: i64 = 0 83 o = tr_cat(out, o, "{\"prompt\":\"" as *u8) 84 o = rr_json_esc(out, o, pbuf, pl) 85 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) 86 out[o] = 0 as u8 87 return o 88} 89// ADVANCE the arc, then build the orchestrator body at the new step (the per-render entry for the NAS pipeline) 90func render_gen_request_pfx(prefix: *u8, persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { 91 let s: i64 = varc_advance_pfx(prefix, persona) 92 if (step_out as i64) != 0 { step_out[0] = s } 93 return render_gen_body_at_pfx(prefix, persona, s, out, cap) 94} 95// wrap the orchestrator body in a POST /gen/api/generate request for the sovereign HTTP client 96func render_gen_http_at_pfx(prefix: *u8, persona: *u8, step: i64, host: *u8, out: *u8, cap: i64) -> i64 { 97 let body: *u8 = sys_mmap(16384) 98 let bl: i64 = render_gen_body_at_pfx(prefix, persona, step, body, 16384) 99 if bl <= 0 { out[0]=0 as u8; return 0 } 100 var o: i64 = 0 101 o = tr_cat(out, o, "POST /gen/api/generate HTTP/1.1\r\nHost: " as *u8) 102 o = tr_cat(out, o, host) 103 o = tr_cat(out, o, "\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 104 o = rr_catn(out, o, bl) 105 o = tr_cat(out, o, "\r\nConnection: close\r\n\r\n" as *u8) 106 var i: i64 = 0; while i < bl { out[o]=body[i]; o=o+1; i=i+1 } 107 out[o] = 0 as u8 108 return o 109} 110func 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) } 111func 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) } 112func 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) } 113 114// production-prefix wrappers (the persona's real visual store) 115func render_body_at(persona: *u8, step: i64, out: *u8, cap: i64) -> i64 { return render_body_at_pfx(VID_PREFIX, persona, step, out, cap) } 116func render_request(persona: *u8, out: *u8, cap: i64, step_out: *i64) -> i64 { return render_request_pfx(VID_PREFIX, persona, out, cap, step_out) } 117func 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) }