163 lines
5.8 KiB
TypeScript
163 lines
5.8 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
|
|
export async function POST(request: Request) {
|
|
let userMessage = "";
|
|
|
|
try {
|
|
const json = await request.json();
|
|
userMessage = json.message;
|
|
const history = json.history || [];
|
|
|
|
if (!userMessage || typeof userMessage !== "string") {
|
|
return NextResponse.json(
|
|
{ error: "Message is required" },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
// Call your n8n chat webhook
|
|
const n8nWebhookUrl = process.env.N8N_WEBHOOK_URL;
|
|
|
|
if (!n8nWebhookUrl) {
|
|
console.error("N8N_WEBHOOK_URL not configured");
|
|
return NextResponse.json({
|
|
reply: getFallbackResponse(userMessage),
|
|
});
|
|
}
|
|
|
|
console.log(`Sending to n8n: ${n8nWebhookUrl}/webhook/chat`);
|
|
|
|
const response = await fetch(`${n8nWebhookUrl}/webhook/chat`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...(process.env.N8N_API_KEY && {
|
|
Authorization: `Bearer ${process.env.N8N_API_KEY}`,
|
|
}),
|
|
},
|
|
body: JSON.stringify({
|
|
message: userMessage,
|
|
history: history,
|
|
}),
|
|
});
|
|
if (!response.ok) {
|
|
console.error(`n8n webhook failed with status: ${response.status}`);
|
|
throw new Error(`n8n webhook failed: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
console.log("n8n response data:", data);
|
|
|
|
const reply =
|
|
data.reply ||
|
|
data.message ||
|
|
data.response ||
|
|
data.text ||
|
|
data.content ||
|
|
(Array.isArray(data) && data[0]?.reply);
|
|
|
|
if (!reply) {
|
|
console.warn("n8n response missing reply field:", data);
|
|
// If n8n returns successfully but without a clear reply field,
|
|
// we might want to show the fallback or a generic error,
|
|
// but strictly speaking we shouldn't show "Couldn't process".
|
|
// Let's try to stringify the whole data if it's small, or use fallback.
|
|
if (data && typeof data === "object" && Object.keys(data).length > 0) {
|
|
// It returned something, but we don't know what field to use.
|
|
// Check for common n8n structure
|
|
if (data.output) return NextResponse.json({ reply: data.output });
|
|
if (data.data) return NextResponse.json({ reply: data.data });
|
|
}
|
|
throw new Error("Invalid response format from n8n");
|
|
}
|
|
|
|
return NextResponse.json({
|
|
reply: reply,
|
|
});
|
|
} catch (error) {
|
|
console.error("Chat API error:", error);
|
|
|
|
// Fallback to mock responses
|
|
// Now using the variable captured at the start
|
|
return NextResponse.json({ reply: getFallbackResponse(userMessage) });
|
|
}
|
|
}
|
|
|
|
function getFallbackResponse(message: string): string {
|
|
if (!message || typeof message !== "string") {
|
|
return "I'm having a bit of trouble understanding. Could you try asking again?";
|
|
}
|
|
|
|
const lowerMessage = message.toLowerCase();
|
|
|
|
if (
|
|
lowerMessage.includes("skill") ||
|
|
lowerMessage.includes("tech") ||
|
|
lowerMessage.includes("stack")
|
|
) {
|
|
return "I specialize in full-stack development with Next.js, React, and Flutter for mobile. On the DevOps side, I love working with Docker Swarm, Traefik, and CI/CD pipelines. Basically, if it involves code or servers, I'm interested!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("project") ||
|
|
lowerMessage.includes("built") ||
|
|
lowerMessage.includes("work")
|
|
) {
|
|
return "One of my key projects is Clarity, a Flutter app designed to help people with dyslexia. I also maintain a comprehensive self-hosted infrastructure with Docker Swarm. You can check out more details in the Projects section!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("contact") ||
|
|
lowerMessage.includes("email") ||
|
|
lowerMessage.includes("reach") ||
|
|
lowerMessage.includes("hire")
|
|
) {
|
|
return "The best way to reach me is through the contact form below or by emailing contact@dk0.dev. I'm always open to discussing new ideas, opportunities, or just chatting about tech!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("location") ||
|
|
lowerMessage.includes("where") ||
|
|
lowerMessage.includes("live")
|
|
) {
|
|
return "I'm based in Osnabrück, Germany. It's a great place to be a student and work on tech projects!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("hobby") ||
|
|
lowerMessage.includes("free time") ||
|
|
lowerMessage.includes("fun")
|
|
) {
|
|
return "When I'm not coding or tweaking my servers, I enjoy gaming, going for a jog, or experimenting with new tech. Fun fact: I still use pen and paper for my calendar, even though I automate everything else!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("devops") ||
|
|
lowerMessage.includes("docker") ||
|
|
lowerMessage.includes("server") ||
|
|
lowerMessage.includes("hosting")
|
|
) {
|
|
return "I'm really into DevOps! I run my own infrastructure on IONOS and OVHcloud using Docker Swarm and Traefik. It allows me to host various services and game servers efficiently while learning a ton about system administration.";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("student") ||
|
|
lowerMessage.includes("study") ||
|
|
lowerMessage.includes("education")
|
|
) {
|
|
return "Yes, I'm currently a student in Osnabrück. I balance my studies with working on personal projects and managing my self-hosted infrastructure. It keeps me busy but I learn something new every day!";
|
|
}
|
|
|
|
if (
|
|
lowerMessage.includes("hello") ||
|
|
lowerMessage.includes("hi ") ||
|
|
lowerMessage.includes("hey")
|
|
) {
|
|
return "Hi there! I'm Dennis's AI assistant (currently in offline mode). How can I help you learn more about Dennis today?";
|
|
}
|
|
|
|
// Default response
|
|
return "That's an interesting question! I'm currently operating in fallback mode, so my knowledge is a bit limited right now. But I can tell you that Dennis is a full-stack developer and DevOps enthusiast who loves building with Next.js and Docker. Feel free to ask about his skills, projects, or how to contact him!";
|
|
}
|