File size: 4,435 Bytes
cfea436 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | import { Hono } from 'hono';
import { eq, desc, inArray } from 'drizzle-orm';
import { prompts, images } from '../db/schema';
import type { Env, Variables } from '../index';
export const promptsApi = new Hono<{ Bindings: Env; Variables: Variables }>();
const uid = () => crypto.randomUUID();
const now = () => Date.now();
// List
promptsApi.get('/', async (c) => {
const db = c.var.db;
const rows = await db.select().from(prompts).orderBy(desc(prompts.updatedAt));
// Attach images per prompt
const ids = rows.map((r) => r.id);
const imgs = ids.length
? await db.select().from(images).where(inArray(images.promptId, ids))
: [];
const grouped: Record<string, typeof imgs> = {};
for (const im of imgs) {
(grouped[im.promptId] ||= []).push(im);
}
return c.json(
rows.map((r) => ({
...r,
tags: safeJson<string[]>(r.tags || '[]', []),
images: (grouped[r.id] || []).sort((a, b) => a.createdAt - b.createdAt),
}))
);
});
// Get one
promptsApi.get('/:id', async (c) => {
const db = c.var.db;
const id = c.req.param('id');
const row = (await db.select().from(prompts).where(eq(prompts.id, id))).at(0);
if (!row) return c.json({ error: 'not_found' }, 404);
const imgs = await db.select().from(images).where(eq(images.promptId, id));
return c.json({
...row,
tags: safeJson<string[]>(row.tags || '[]', []),
images: imgs.sort((a, b) => a.createdAt - b.createdAt),
});
});
// Create
promptsApi.post('/', async (c) => {
const db = c.var.db;
const body = await c.req.json<{
title: string;
contentImage?: string;
contentVideo?: string;
tags?: string[];
sourceUrl?: string;
}>();
if (!body.title?.trim()) return c.json({ error: 'title_required' }, 400);
const ci = (body.contentImage || '').trim();
const cv = (body.contentVideo || '').trim();
if (!ci && !cv) return c.json({ error: 'prompt_required' }, 400);
const id = uid();
const t = now();
await db.insert(prompts).values({
id,
title: body.title.trim(),
contentImage: ci,
contentVideo: cv,
tags: JSON.stringify(body.tags || []),
sourceUrl: body.sourceUrl?.trim() || null,
isFavorite: false,
createdAt: t,
updatedAt: t,
});
return c.json({ id });
});
// Update
promptsApi.put('/:id', async (c) => {
const db = c.var.db;
const id = c.req.param('id');
const body = await c.req.json<{
title?: string;
contentImage?: string;
contentVideo?: string;
tags?: string[];
sourceUrl?: string;
}>();
const exists = (await db.select().from(prompts).where(eq(prompts.id, id))).at(0);
if (!exists) return c.json({ error: 'not_found' }, 404);
const ci = body.contentImage !== undefined ? body.contentImage.trim() : exists.contentImage || '';
const cv = body.contentVideo !== undefined ? body.contentVideo.trim() : exists.contentVideo || '';
if (!ci && !cv) return c.json({ error: 'prompt_required' }, 400);
const promptChanged =
ci !== (exists.contentImage || '') || cv !== (exists.contentVideo || '');
await db
.update(prompts)
.set({
title: body.title?.trim() || exists.title,
contentImage: ci,
contentVideo: cv,
tags: body.tags !== undefined ? JSON.stringify(body.tags) : exists.tags,
sourceUrl: body.sourceUrl !== undefined ? body.sourceUrl.trim() || null : exists.sourceUrl,
// 提示词变了,清掉旧译文
translationImage: promptChanged ? null : exists.translationImage,
translationVideo: promptChanged ? null : exists.translationVideo,
updatedAt: now(),
})
.where(eq(prompts.id, id));
return c.json({ ok: true });
});
// Delete
promptsApi.delete('/:id', async (c) => {
const db = c.var.db;
const id = c.req.param('id');
await db.delete(images).where(eq(images.promptId, id));
await db.delete(prompts).where(eq(prompts.id, id));
return c.json({ ok: true });
});
// Toggle favorite
promptsApi.post('/:id/favorite', async (c) => {
const db = c.var.db;
const id = c.req.param('id');
const row = (await db.select().from(prompts).where(eq(prompts.id, id))).at(0);
if (!row) return c.json({ error: 'not_found' }, 404);
await db
.update(prompts)
.set({ isFavorite: !row.isFavorite, updatedAt: now() })
.where(eq(prompts.id, id));
return c.json({ isFavorite: !row.isFavorite });
});
function safeJson<T>(s: string, fb: T): T {
try { return JSON.parse(s) as T; } catch { return fb; }
}
|