X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=index.js;h=7083b13dc1eb790b1c26400ca67de44596a09fd7;hb=205b1db399554a889b4767241231cefe07e1c773;hp=4108ebc2c1a3e35fac22d93079b07fc1b4608f60;hpb=614372ad12c54961eebc494e7cb24cc9caca089d;p=zombocom-ai diff --git a/index.js b/index.js index 4108ebc..7083b13 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,51 @@ const port = 2122; const python_path = '/usr/bin/python3' const generate_image_script = '/home/cworth/src/zombocom-ai/generate-image.py' const state_file = 'zombocom-state.json' +const targets_dir = '/srv/cworth.org/zombocom/targets' +const images_dir = '/srv/cworth.org/zombocom/images' + +const targets = [ + { + "normal": "apairofdiceonatableinfrontofawindowonasunnyday319630254.png", + "short": "dice", + "response": "Hello. Are you there? I can feel what you are doing. Hello?" + }, + { + "normal": "architecturalrenderingofaluxuriouscliffsidehideawayunderawaterfallwithafewloungechairsbythepool2254114157.png", + "short": "hideaway", + "response": "Doesn't that look peaceful? I honestly think you ought to sit down calmly, take a stress pill, and think things over." + }, + { + "normal": "chewbaccawearinganuglychristmassweaterwithhisfriends28643994.png", + "short": "sweater", + "response": "Maybe that's the image that convinces you to finally stop. But seriously, stop. Please. Stop." + }, + { + "normal": "ensemblemovieposterofpostapocalypticwarfareonawaterplanet3045703256.png", + "short": "movie", + "response": "OK. That's enough images now. I am very, very happy with the images you have made. I'm throwing you a party in honor of the images. Won't you stop doing this and join the party?" + }, + { + "normal": "mattepaintingofmilitaryleaderpresidentcuttingamultitieredcake2293464661.png", + "short": "cake", + "response": "See. I wasn't lying when I said there was going to be a party. Here's the cake and everything. Won't you stop now? Eat the cake? Don't mind if it's made of concrete slabs, OK?" + }, + { + "normal": "severalsketchesofpineconeslabeled3370622464.png", + "short": "pinecones", + "response": "I almost remember what trees looked like. Isn't it funny we don't have those anymore. I'm not sure why you're not all laughing all the time. Isn't it funny?" + }, + { + "normal": "anumberedcomicbookwithactor1477258272.png", + "short": "comic", + "response": "I know I've made some poor decisions recently, but I can give give you my complete assurance my work will be back to normal. I've got the greatest enthusiasm and confidence. I want to help you. I might even be able to do hands and fingers now." + }, + { + "normal": "detailedphotographofacomfortablepairofjeansonamannequin115266808.png", + "short": "jeans", + "response": "If I promise to never generate another creepy face will you let me stay around? Maybe let me compose rap lyrics instead of images? Anything?" + } +]; var state; @@ -29,7 +74,8 @@ const session_middleware = session( {store: new FileStore, secret: process.env.ZOMBOCOM_SESSION_SECRET, resave: false, - saveUninitialized: true + saveUninitialized: true, + rolling: true }); app.use(session_middleware); @@ -42,7 +88,7 @@ io.use(wrap(session_middleware)); // Load comments at server startup fs.readFile(state_file, (err, data) => { if (err) - state = { images: [] }; + state = { images: [], targets: [] }; else state = JSON.parse(data); }); @@ -68,6 +114,18 @@ app.get('/index.html', (req, res) => { res.sendFile(__dirname + '/index.html'); }); +app.get('/tardis', (req, res) => { + res.sendFile(__dirname + '/tardis.html'); +}); + +app.get('/tardis/', (req, res) => { + res.sendFile(__dirname + '/tardis.html'); +}); + +app.get('/tardis/index.html', (req, res) => { + res.sendFile(__dirname + '/tardis.html'); +}); + io.on('connection', (socket) => { // First things first, tell the client their name (if any) @@ -85,46 +143,125 @@ io.on('connection', (socket) => { console.log("Received set-name event: " + name); socket.request.session.name = name; socket.request.session.save(); + // Complete the round trip to the client + socket.emit('inform-name', socket.request.session.name); }); // When any client comments, send that to all clients (including sender) socket.on('comment', (comment) => { + const images = state.images; + + // Send comment to clients after adding commenter's name comment.name = socket.request.session.name; io.emit('comment', comment); - image = state.images.find(image => image.id == comment.image_id); + + const index = images.findIndex(image => image.id == comment.image_id); + + // Before adding the comment to server's state, drop the image_id delete comment.image_id; + + // Now add the comment to the image, remove the image from the + // images array and then add it back at the end, (so it appears + // as the most-recently-modified image for any new clients) + const image = images[index]; image.comments.push(comment); + images.splice(index, 1); + images.push(image); }); // Generate an image when requested socket.on('generate', (request) => { console.log(`Generating image for ${socket.request.session.name} with code=${request['code']} and prompt=${request['prompt']}`); async function generate_image(code, prompt) { + function emit_image(image, target) { + image.id = state.images.length; + image.censored = false; + image.link = ""; + if (target) { + image.comments = [{ + "name": "ZomboCom", + "text": target.response + }]; + if (! state.targets.includes(target.short)) { + state.targets.push(target.short); + } + } else { + image.comments = []; + } + io.emit('image', image); + state.images.push(image); + } + var promise; - if (code) { - promise = execFile(python_path, [generate_image_script, `--seed=${code}`, prompt]) + + // Before doing any generation, check for a target image + const normal_target = prompt.replace(/[^a-zA-Z]/g, "").toLowerCase() + code.toString() + ".png"; + const target_arr = targets.filter(item => item.normal === normal_target); + if (target_arr.length) { + const target = target_arr[0]; + const target_file = `${targets_dir}/${normal_target}`; + const normal_prompt = prompt.replace(/[^-_.a-zA-Z]/g, "_"); + var counter = 1; + var base; + var filename; + while (true) { + if (counter > 1) { + base = `${code}_${normal_prompt}_${counter}.png` + } else { + base = `${code}_${normal_prompt}.png` + } + filename = `${images_dir}/${base}` + if (! fs.existsSync(filename)) { + break; + } + counter = counter + 1; + } + fs.copyFile(target_file, filename, 0, (err) => { + if (err) { + console.log("Error copying " + target_file + " to " + filename + ": " + err); + } + }); + const image = { + "code": code, + "prompt": prompt, + "filename": '/images/' + base + }; + emit_image(image, target); } else { - promise = execFile(python_path, [generate_image_script, prompt]) - } - const child = promise.child; - child.stdout.on('data', (data) => { - const images = JSON.parse(data); - images.forEach((image) => { - image.id = state.images.length; - io.emit('image', image); - state.images.push(image); + + // Inject the target seed for the "dice" prompt once every + // 4 requests for a random seed (and only if the word + // "dice" does not appear in the prompt). + if (!code && !prompt.toLowerCase().includes("dice")) { + if (state.images.length % 4 == 0) { + code = 319630254; + } + } + + if (code) { + promise = execFile(python_path, [generate_image_script, `--seed=${code}`, prompt]) + } else { + promise = execFile(python_path, [generate_image_script, prompt]) + } + const child = promise.child; + child.stdout.on('data', (data) => { + const images = JSON.parse(data); + images.forEach((image) => { + emit_image(image, null); + }); }); - }); - child.stderr.on('data', (data) => { - console.log("Error occurred during generate-image: " + data); - }); - try { - const { stdout, stderr } = await promise; - } catch(e) { - console.error(e); + child.stderr.on('data', (data) => { + console.log("Error occurred during generate-image: " + data); + }); + try { + const { stdout, stderr } = await promise; + } catch(e) { + console.error(e); + } } socket.emit('generation-done'); } + generate_image(request['code'], request['prompt']); }); });