Initial miaojingAI project with image resolution guard
This commit is contained in:
143
src/app/api/creation-history/route.ts
Normal file
143
src/app/api/creation-history/route.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getDbClient } from '@/storage/database/local-db';
|
||||
import { getAuthenticatedUserId } from '@/lib/session-auth';
|
||||
|
||||
function toWorkType(type: string, params: Record<string, unknown>): string {
|
||||
const explicitMode = params.creationMode || params.workType || params.mode;
|
||||
if (explicitMode === 'text2img' || explicitMode === 'img2img' || explicitMode === 'text2video' || explicitMode === 'img2video' || explicitMode === 'reverse-prompt') {
|
||||
return explicitMode;
|
||||
}
|
||||
if (type === 'reverse-prompt') return 'reverse-prompt';
|
||||
const hasReference = Boolean(params.referenceImage)
|
||||
|| (Array.isArray(params.referenceImages) && params.referenceImages.length > 0)
|
||||
|| Number(params.refImageCount || 0) > 0;
|
||||
if (type === 'video') return hasReference ? 'img2video' : 'text2video';
|
||||
return hasReference ? 'img2img' : 'text2img';
|
||||
}
|
||||
|
||||
function fromWorkType(type: string): 'image' | 'video' | 'reverse-prompt' {
|
||||
if (type === 'reverse-prompt') return 'reverse-prompt';
|
||||
return type.includes('video') ? 'video' : 'image';
|
||||
}
|
||||
|
||||
function mapWork(row: Record<string, unknown>) {
|
||||
const params = (row.params || {}) as Record<string, unknown>;
|
||||
return {
|
||||
id: row.id,
|
||||
type: fromWorkType(String(row.type || 'text2img')),
|
||||
url: row.result_url,
|
||||
prompt: row.prompt || '',
|
||||
negativePrompt: row.negative_prompt || undefined,
|
||||
model: params.model || '',
|
||||
modelLabel: params.modelLabel || params.model || '',
|
||||
isCustomModel: Boolean(params.isCustomModel),
|
||||
params,
|
||||
referenceImage: params.referenceImage,
|
||||
referenceImages: Array.isArray(params.referenceImages)
|
||||
? params.referenceImages
|
||||
: params.referenceImage
|
||||
? [params.referenceImage]
|
||||
: undefined,
|
||||
published: row.is_public === true,
|
||||
createdAt: row.created_at,
|
||||
};
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const userId = await getAuthenticatedUserId(request);
|
||||
if (!userId) return NextResponse.json({ error: '请先登录' }, { status: 401 });
|
||||
const client = await getDbClient();
|
||||
try {
|
||||
const result = await client.query(
|
||||
`SELECT id, type, prompt, negative_prompt, params, result_url, is_public, status, created_at
|
||||
FROM works
|
||||
WHERE user_id = $1 AND status = 'completed'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 300`,
|
||||
[userId],
|
||||
);
|
||||
return NextResponse.json({ records: result.rows.map(mapWork) });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const userId = await getAuthenticatedUserId(request);
|
||||
if (!userId) return NextResponse.json({ error: '请先登录' }, { status: 401 });
|
||||
const body = await request.json();
|
||||
const records = Array.isArray(body.records) ? body.records : [body];
|
||||
const client = await getDbClient();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
const saved = [];
|
||||
for (const record of records) {
|
||||
const params = {
|
||||
...(record.params || {}),
|
||||
model: record.model || (record.params || {}).model,
|
||||
modelLabel: record.modelLabel || (record.params || {}).modelLabel,
|
||||
isCustomModel: Boolean(record.isCustomModel),
|
||||
referenceImage: record.referenceImage || (record.params || {}).referenceImage,
|
||||
referenceImages: record.referenceImages || (record.params || {}).referenceImages,
|
||||
};
|
||||
const workType = toWorkType(String(record.type || 'image'), params);
|
||||
let url = String(record.url || '').trim();
|
||||
if (workType === 'reverse-prompt') {
|
||||
url = url && !url.startsWith('data:') ? url : `[reverse-prompt:${record.id || Date.now()}]`;
|
||||
}
|
||||
if (!url || url.startsWith('data:')) continue;
|
||||
const existing = await client.query(
|
||||
`SELECT id, type, prompt, negative_prompt, params, result_url, is_public, status, created_at
|
||||
FROM works
|
||||
WHERE user_id = $1 AND result_url = $2
|
||||
LIMIT 1`,
|
||||
[userId, url],
|
||||
);
|
||||
if (existing.rows[0]) {
|
||||
saved.push(mapWork(existing.rows[0]));
|
||||
continue;
|
||||
}
|
||||
const result = await client.query(
|
||||
`INSERT INTO works (user_id, type, prompt, negative_prompt, params, result_url, is_public, status, credits_cost, created_at)
|
||||
VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7, 'completed', $8, COALESCE($9::timestamptz, NOW()))
|
||||
RETURNING id, type, prompt, negative_prompt, params, result_url, is_public, status, created_at`,
|
||||
[
|
||||
userId,
|
||||
workType,
|
||||
record.prompt || '',
|
||||
record.negativePrompt || null,
|
||||
JSON.stringify(params),
|
||||
url,
|
||||
Boolean(record.published),
|
||||
Number(record.creditsCost || 0),
|
||||
record.createdAt || null,
|
||||
],
|
||||
);
|
||||
if (result.rows[0]) saved.push(mapWork(result.rows[0]));
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
return NextResponse.json({ records: saved });
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest) {
|
||||
const userId = await getAuthenticatedUserId(request);
|
||||
if (!userId) return NextResponse.json({ error: '请先登录' }, { status: 401 });
|
||||
const id = request.nextUrl.searchParams.get('id');
|
||||
const client = await getDbClient();
|
||||
try {
|
||||
if (id) {
|
||||
await client.query('DELETE FROM works WHERE id = $1 AND user_id = $2', [id, userId]);
|
||||
} else {
|
||||
await client.query('DELETE FROM works WHERE user_id = $1', [userId]);
|
||||
}
|
||||
return NextResponse.json({ success: true });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user