const {chromium}=require('playwright'); const assert=require('node:assert/strict'); const {execFileSync}=require('node:child_process'); const fs=require('node:fs'); const path=require('node:path'); const root='http://127.0.0.1:7866'; function read(file){ const code="from PIL import Image; import sys,json; im=Image.open(sys.argv[1]); print(json.dumps({'record':json.loads(im.info['anima_collection']),'parameters':im.info['parameters'],'format':im.format,'size':im.size},ensure_ascii=True))"; return JSON.parse(execFileSync(process.env.TEST_PYTHON,["-c",code,file],{encoding:'utf8'})); } function check(data,family,embedding){ assert.equal(data.format,'PNG');assert.deepEqual(data.size,[64,64]); assert.equal(data.record.family,family); assert.equal(data.record.seed_string,'9223372036854775806'); assert(data.parameters.includes('Seed: 9223372036854775806')); assert.equal(data.record.input_prompt,', 日本語\nblue eyes'); assert.equal(data.record.prompt,'red hair, 日本語\nblue eyes'); assert(data.parameters.startsWith(data.record.prompt+'\nNegative prompt: ')); assert.equal(data.record.loras[0].strength_model,.7); assert.deepEqual(data.record.negative_embeddings,embedding?['negativeXL_D.safetensors']:[]); assert.equal(data.record.sampler,family==='anima'?'er_sde':'euler_ancestral'); } (async()=>{ const browser=await chromium.launch({headless:true,executablePath:process.env.TEST_CHROME}); try { for(const width of [1440,390]){ const page=await browser.newPage({viewport:{width,height:900},acceptDownloads:true}); const errors=[];page.on('pageerror',e=>errors.push(e.message)); await page.goto(root,{waitUntil:'domcontentloaded'}); for(const family of ['anima','illustrious']){ await page.getByRole('tab',{name:family,exact:true}).click(); await page.getByRole('button',{name:'Generate fixture '+family,exact:true}).click(); const link=page.locator('a[download]:visible').first();await link.waitFor(); const downloaded=page.waitForEvent('download');await link.click(); const file=path.resolve(`../outputs/metadata-${width}-${family}.png`); await (await downloaded).saveAs(file); check(read(file),family,family==='illustrious'); console.log(`PASS ${width}px ${family}: actual toolbar PNG download contains parameters + native JSON`); } assert.deepEqual(errors,[]);await page.close(); } }finally{await browser.close();} for(const family of ['anima','illustrious']){ const args=[family==='anima'?'anima_INT8.safetensors':'wai.safetensors',', 日本語\nblue eyes','bad quality',64,64,-1, 8,1,'er_sde','simple',true,'details.safetensors',.7,false,'---',1,false,'---',1,false,'---',1]; if(family==='illustrious'){args[8]='euler_ancestral';args[9]='normal';} const start=await fetch(root+'/gradio_api/call/generate_image',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({data:args})}); assert(start.ok);const {event_id}=await start.json(); const stream=await (await fetch(root+'/gradio_api/call/generate_image/'+event_id)).text(); const completed=stream.split('\n\n').find(block=>block.includes('event: complete')); assert(completed,stream); const data=JSON.parse(completed.split('\n').find(line=>line.startsWith('data: ')).slice(6)); assert.equal(data.length,2);assert.equal(typeof data[1],'string');assert.equal(typeof data[0].url,'string'); const response=await fetch(data[0].url); const file=path.resolve('../outputs/metadata-api-'+family+'.png'); fs.writeFileSync(file,Buffer.from(await response.arrayBuffer())); check(read(file),family,false); console.log(`PASS API ${family}: original image-file + string response; downloaded PNG retains both metadata formats`); } })().catch(e=>{console.error(e);process.exit(1);});