From 46d41b27256b64273c5fddb1880b48cda4b489b2 Mon Sep 17 00:00:00 2001 From: David Jakowenko Date: Tue, 13 Jun 2023 02:55:28 -0400 Subject: [PATCH] feat: auto generate images --- README.md | 17 ++++++++++++++++- api/server.ts | 1 + api/src/config/default.ts | 6 ++++++ api/src/schemas/index.ts | 6 ++++++ api/src/util/cron.util.ts | 20 ++++++++++++++++++++ api/src/util/state.util.ts | 1 + frontend/src/views/ControllerView.vue | 10 +++++++++- 7 files changed, 59 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a599999..0892532 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ If you would like to make a donation to support development, please use [GitHub ## Features - Create unique AI-generated artwork from spoken conversations -- Manual or voice-activated summary generation for on-demand art +- Automatic, manual or voice-activated summary generation for on-demand art - User-friendly UI, optimized for both desktop and mobile - Real-time updates and remote control via WebSockets - Integrated config editor for customization @@ -181,6 +181,21 @@ image: order: recent ``` +### `autogen` + +Images can be automatically generated by creating random summaries. This can be scheduled with a cron expression. Keywords can be passed to help guide the summary. + +```yaml +# autogen settings (default: shown below) + +autogen: + # schedule as a cron expression for processing transcripts (at every 15th and 45th minute) + cron: '15,45 * * * *' + prompt: Provide a random short description to describe a picture. It should be no more than one or two sentences. If keywords are provided select a couple at random to help guide the description. + # keywords to guide the summary + keywords: [] +``` + ### `transcript` Images are generated by processing transcripts. This can be scheduled with a cron expression. All of the transcripts within X minutes will then be processed by OpenAI using `openai.summary.prompt` to summarize the transcripts. diff --git a/api/server.ts b/api/server.ts index cc6acb5..3f03cb0 100644 --- a/api/server.ts +++ b/api/server.ts @@ -47,6 +47,7 @@ const start = async () => { emitter.setup(); socket.connect(server); cron.transcript(); + cron.autogen(); cron.heartbeat(); }); }; diff --git a/api/src/config/default.ts b/api/src/config/default.ts index 4ea323d..b4ed779 100644 --- a/api/src/config/default.ts +++ b/api/src/config/default.ts @@ -2,6 +2,12 @@ export default { telemetry: true, logs: { level: 'verbose' }, time: { timezone: 'UTC', format: null }, + autogen: { + cron: '15,45 * * * *', + prompt: + 'Provide a random short description to describe a picture. It should be no more than one or two sentences. If keywords are provided select a couple at random to help guide the description.', + keywords: [], + }, image: { interval: 60, order: 'recent', diff --git a/api/src/schemas/index.ts b/api/src/schemas/index.ts index a4d4e86..c198d8a 100644 --- a/api/src/schemas/index.ts +++ b/api/src/schemas/index.ts @@ -59,6 +59,12 @@ const schema = z.object({ }), image: z.union([ z.object({ + autogen: z.object({ + enable: z.boolean(), + cron: z.string(), + prompt: z.string(), + keywords: z.array(z.string()), + }), size: z.enum(['1024x1024', '512x512', '256x256']), style: z.array(z.string()).min(1), }), diff --git a/api/src/util/cron.util.ts b/api/src/util/cron.util.ts index 5901397..fbe4aab 100644 --- a/api/src/util/cron.util.ts +++ b/api/src/util/cron.util.ts @@ -14,6 +14,7 @@ const { version } = require('../../package.json'); const { TELEMETRY, TRANSCRIPT: { CRON, MINUTES, MINIMUM }, + AUTOGEN, } = config(); export default { @@ -94,5 +95,24 @@ export default { log.error(error.message); } }, + autogen: async () => { + const { log } = new Log('autogen'); + try { + new CronJob(AUTOGEN.CRON, async () => { + const { autogen } = state.get(); + if (!autogen) { + log.verbose('paused'); + return; + } + const openai = (await import('../ai/openai')).default; + const summary = await new openai().random({ + prompt: AUTOGEN.PROMPT, + context: AUTOGEN.KEYWORDS.join(', '), + }); + emitter.emit('summary.create', summary); + }).start(); + } catch (error: any) { + log.error(error.message); + } }, }; diff --git a/api/src/util/state.util.ts b/api/src/util/state.util.ts index 5c867c1..9666bb3 100644 --- a/api/src/util/state.util.ts +++ b/api/src/util/state.util.ts @@ -11,6 +11,7 @@ const { let STATE: { [name: string]: any } = { processing: false, cron: true, + autogen: false, image: { index: 0, summary: true, diff --git a/frontend/src/views/ControllerView.vue b/frontend/src/views/ControllerView.vue index 44b6cb9..d9ed2ec 100644 --- a/frontend/src/views/ControllerView.vue +++ b/frontend/src/views/ControllerView.vue @@ -87,7 +87,7 @@ const getRandomSummary = async () => { } }; -const toggle = async (key: 'cron' | 'mic' | 'summary') => { +const toggle = async (key: 'cron' | 'mic' | 'summary' | 'autogen') => { if (key === 'cron') { socket.emit('state:patch', { cron: state.value.cron }); toast.add({ @@ -115,6 +115,14 @@ const toggle = async (key: 'cron' | 'mic' | 'summary') => { life: 3000, }); } + if (key === 'autogen') { + socket.emit('state:patch', { to: 'controller', autogen: state.value.autogen }); + toast.add({ + severity: 'info', + detail: `Autogen Processing ${state.value.autogen ? 'Enabled' : 'Disabled'}`, + life: 3000, + }); + } }; const imageControl = (task: 'prev' | 'next' | 'toggle') => {