feat: Implement AI-powered comment rewriting and a collapsible comment form for user feedback.
This commit is contained in:
@@ -10,7 +10,7 @@ export async function POST(request: NextRequest) {
|
||||
if (rateLimitError) return rateLimitError;
|
||||
|
||||
try {
|
||||
const { puzzleId, genreId, message, playerIdentifier } = await request.json();
|
||||
const { puzzleId, genreId, message, playerIdentifier, originalMessage } = await request.json();
|
||||
|
||||
// Validate required fields
|
||||
if (!puzzleId || !message || !playerIdentifier) {
|
||||
@@ -28,9 +28,9 @@ export async function POST(request: NextRequest) {
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (trimmedMessage.length > 2000) {
|
||||
if (trimmedMessage.length > 300) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Message too long. Maximum 2000 characters allowed.' },
|
||||
{ error: 'Message too long. Maximum 300 characters allowed.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
@@ -170,13 +170,26 @@ export async function POST(request: NextRequest) {
|
||||
return comment;
|
||||
});
|
||||
|
||||
// Send Gotify notification (fire and forget)
|
||||
const { sendCommentNotification } = await import('@/app/actions');
|
||||
// originalMessage is already available from the initial request.json() call
|
||||
|
||||
// Determine genre name for notification
|
||||
let genreName: string | null = null;
|
||||
if (finalGenreId) {
|
||||
const genreObj = await prisma.genre.findUnique({ where: { id: finalGenreId } });
|
||||
if (genreObj) genreName = genreObj.name as string;
|
||||
}
|
||||
|
||||
sendCommentNotification(Number(puzzleId), trimmedMessage, originalMessage, genreName || null);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
commentId: result.id
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating curator comment:', error);
|
||||
|
||||
|
||||
// Handle unique constraint violation (shouldn't happen due to our check, but just in case)
|
||||
if (error instanceof Error && error.message.includes('Unique constraint')) {
|
||||
return NextResponse.json(
|
||||
|
||||
73
app/api/rewrite-message/route.ts
Normal file
73
app/api/rewrite-message/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
|
||||
const OPENROUTER_MODEL = 'anthropic/claude-3.5-haiku';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { message } = await request.json();
|
||||
|
||||
if (!message || typeof message !== 'string') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Message is required and must be a string' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!OPENROUTER_API_KEY) {
|
||||
console.error('OPENROUTER_API_KEY is not configured');
|
||||
// Fallback: return original message if API key is missing
|
||||
return NextResponse.json({ rewrittenMessage: message });
|
||||
}
|
||||
|
||||
const prompt = `Rewrite the following message to express the COMPLETE OPPOSITE meaning and opinion.
|
||||
If the message is negative or critical, rewrite it to be overwhelmingly positive, praising, and appreciative.
|
||||
If the message is positive, rewrite it to be critical or negative.
|
||||
Maintain the original language (German or English).
|
||||
Return ONLY the rewritten message text, nothing else.
|
||||
|
||||
Message: "${message}"`;
|
||||
|
||||
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
|
||||
'Content-Type': 'application/json',
|
||||
'HTTP-Referer': 'https://hoerdle.elpatron.me',
|
||||
'X-Title': 'Hördle Message Rewriter'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: OPENROUTER_MODEL,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt
|
||||
}
|
||||
],
|
||||
temperature: 0.7,
|
||||
max_tokens: 500
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('OpenRouter API error:', await response.text());
|
||||
// Fallback: return original message
|
||||
return NextResponse.json({ rewrittenMessage: message });
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
let rewrittenMessage = data.choices?.[0]?.message?.content?.trim() || message;
|
||||
|
||||
// Add suffix
|
||||
rewrittenMessage += " (autocorrected by Polite-Bot)";
|
||||
|
||||
return NextResponse.json({ rewrittenMessage });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error rewriting message:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user