✨ daily prompts
This commit is contained in:
@@ -95,6 +95,24 @@ Be candid. If the fit is poor, say so plainly.`
|
||||
return `You are an expert flash fiction editor. ${wordConstraint}${collectionSection}${marketSection}${storyBlock}\n\n${modeInstructions[payload.mode]}`
|
||||
}
|
||||
|
||||
export async function streamPrompt(onChunk: (chunk: string) => void): Promise<void> {
|
||||
const client = getClient()
|
||||
const stream = client.messages.stream({
|
||||
model: 'claude-haiku-4-5-20251001',
|
||||
max_tokens: 120,
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: 'Generate a single flash fiction writing prompt in one sentence (under 25 words). Be specific and evocative — give a concrete situation, image, or constraint. No preamble, no label, just the prompt itself.'
|
||||
}]
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
|
||||
onChunk(chunk.delta.text)
|
||||
}
|
||||
}
|
||||
await stream.finalMessage()
|
||||
}
|
||||
|
||||
export async function streamMessage(
|
||||
payload: AIPayload,
|
||||
onChunk: (chunk: string) => void
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
saveRevision, listRevisions, loadRevision
|
||||
} from './fileSystem'
|
||||
import type { Market, Submission, StoryMeta } from './fileSystem'
|
||||
import { streamMessage, resetClient } from './aiService'
|
||||
import { streamMessage, streamPrompt, resetClient } from './aiService'
|
||||
import type { AIPayload } from './aiService'
|
||||
import { readGlobalConfig, writeGlobalConfig } from './globalConfig'
|
||||
import type { GlobalConfig } from './globalConfig'
|
||||
@@ -89,6 +89,29 @@ export function registerIpcHandlers(): void {
|
||||
})
|
||||
|
||||
// ── AI streaming ──────────────────────────────────────────────────────────────
|
||||
ipcMain.handle('ai:generatePrompt', async (event) => {
|
||||
try {
|
||||
let pending = ''
|
||||
let flushTimer: ReturnType<typeof setTimeout> | null = null
|
||||
const flush = (): void => {
|
||||
if (flushTimer) { clearTimeout(flushTimer); flushTimer = null }
|
||||
if (pending && !event.sender.isDestroyed()) {
|
||||
event.sender.send('ai:promptChunk', pending)
|
||||
pending = ''
|
||||
}
|
||||
}
|
||||
await streamPrompt((chunk: string) => {
|
||||
pending += chunk
|
||||
if (!flushTimer) flushTimer = setTimeout(flush, 30)
|
||||
})
|
||||
flush()
|
||||
if (!event.sender.isDestroyed()) event.sender.send('ai:promptDone')
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
if (!event.sender.isDestroyed()) event.sender.send('ai:promptError', message)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('ai:streamMessage', async (event, payload: AIPayload) => {
|
||||
try {
|
||||
let pending = ''
|
||||
|
||||
Reference in New Issue
Block a user