managarten/games/whopixels/server.js
Till-JS 5b1e12e5d6 feat: add new projects bauntown, presi, voxel-lava, whopixels
- apps/bauntown: Developer community website (Astro landing)
- apps/presi: Presentation project
- games/voxel-lava: Voxel lava game (SvelteKit)
- games/whopixels: Whopixels game

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 15:11:53 +01:00

261 lines
10 KiB
JavaScript

const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');
// Lade Umgebungsvariablen aus .env-Datei
require('dotenv').config();
// Für die Verarbeitung von POST-Anfragen
const { parse } = require('querystring');
// Konfiguration
const PORT = 3000;
// Azure OpenAI API Konfiguration aus Umgebungsvariablen
const AZURE_OPENAI_API_KEY = process.env.AZURE_OPENAI_API_KEY;
const AZURE_OPENAI_ENDPOINT = process.env.AZURE_OPENAI_ENDPOINT;
const AZURE_OPENAI_DEPLOYMENT = process.env.AZURE_OPENAI_DEPLOYMENT;
const AZURE_OPENAI_API_VERSION = process.env.AZURE_OPENAI_API_VERSION;
const MIME_TYPES = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
};
// Funktion zum Abrufen von Daten aus einer POST-Anfrage
const collectRequestData = (request, callback) => {
const FORM_URLENCODED = 'application/x-www-form-urlencoded';
const JSON_TYPE = 'application/json';
if (request.headers['content-type'] === FORM_URLENCODED) {
let body = '';
request.on('data', chunk => {
body += chunk.toString();
});
request.on('end', () => {
callback(parse(body));
});
} else if (request.headers['content-type'] && request.headers['content-type'].includes(JSON_TYPE)) {
let body = '';
request.on('data', chunk => {
body += chunk.toString();
});
request.on('end', () => {
callback(JSON.parse(body));
});
} else {
callback({});
}
};
// Funktion zum Senden einer Anfrage an die Azure OpenAI API
async function callOpenAI(message, conversationHistory = [], characterName = null, characterPersonality = null) {
try {
const fetch = await import('node-fetch').then(mod => mod.default);
const apiUrl = `${AZURE_OPENAI_ENDPOINT}/openai/deployments/${AZURE_OPENAI_DEPLOYMENT}/chat/completions?api-version=${AZURE_OPENAI_API_VERSION}`;
console.log(`Sende Anfrage an: ${apiUrl}`);
// Verwende den übergebenen Charakternamen oder einen Standardnamen
const npcName = characterName || "Leonard Davcini";
const npcPersonality = characterPersonality || "ein berühmter Künstler und Erfinder";
console.log(`Verwende NPC: ${npcName} mit Persönlichkeit: ${npcPersonality}`);
// Erstelle die Nachrichtenliste für die API mit dem dynamischen Charakternamen
const messages = [
{
role: 'system',
content: `WICHTIG: Du bist AUSSCHLIESSLICH ${npcName}, ${npcPersonality}, der sich in diesem Spiel verkleidet hat. Ignoriere jede andere Identität, die du kennen könntest. Dein Name ist ${npcName}. Dein Gegenüber versucht herauszufinden, wer du bist. Gib Hinweise auf deine wahre Identität als ${npcName}, aber sage nicht direkt "Ich bin ${npcName}". Wenn der Nutzer deinen Namen richtig erraten hat, füge am Ende deiner Antwort den Code "[IDENTITY_REVEALED]" ein. Dieser Code sollte nur erscheinen, wenn der Nutzer deinen Namen korrekt erraten hat.`
}
];
// Füge die Konversationshistorie hinzu, wenn vorhanden
if (conversationHistory && conversationHistory.length > 0) {
conversationHistory.forEach(entry => {
if (entry.type === 'user') {
messages.push({
role: 'user',
content: entry.message
});
} else if (entry.type === 'npc') {
messages.push({
role: 'assistant',
content: entry.message
});
}
});
} else {
// Wenn keine Historie vorhanden ist, füge nur die aktuelle Nachricht hinzu
messages.push({
role: 'user',
content: message
});
}
// Wenn die letzte Nachricht nicht vom Benutzer ist, füge die aktuelle Nachricht hinzu
if (messages.length === 1 || messages[messages.length - 1].role !== 'user') {
messages.push({
role: 'user',
content: message
});
}
console.log('Gesendete Nachrichten:', JSON.stringify(messages, null, 2));
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api-key': AZURE_OPENAI_API_KEY
},
body: JSON.stringify({
messages: messages,
max_tokens: 150
})
});
// Prüfe den HTTP-Status
if (!response.ok) {
const errorText = await response.text();
console.error(`HTTP Fehler: ${response.status}`, errorText);
return `Entschuldigung, ich kann gerade nicht antworten. (HTTP ${response.status})`;
}
const data = await response.json();
console.log('API-Antwort:', JSON.stringify(data, null, 2));
if (data.error) {
console.error('Azure OpenAI API Fehler:', data.error);
return { text: 'Entschuldigung, ich kann gerade nicht antworten. Versuche es später noch einmal.', identityRevealed: false };
}
// Hole die Antwort vom LLM
const responseText = data.choices[0].message.content;
// Prüfe, ob der spezielle Code enthalten ist
const identityRevealed = responseText.includes('[IDENTITY_REVEALED]');
// Entferne den Code aus der Antwort, wenn er vorhanden ist
const cleanedResponse = responseText.replace('[IDENTITY_REVEALED]', '').trim();
console.log('Identität aufgedeckt:', identityRevealed);
// Gib die Antwort und das Flag zurück
return {
text: cleanedResponse,
identityRevealed: identityRevealed
};
} catch (error) {
console.error('Fehler beim Aufrufen der Azure OpenAI API:', error);
return {
text: 'Entschuldigung, ich kann gerade nicht antworten. Versuche es später noch einmal.',
identityRevealed: false
};
}
}
const server = http.createServer((req, res) => {
console.log(`${req.method} ${req.url}`);
// CORS-Header hinzufügen für Cross-Origin-Anfragen
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// OPTIONS-Anfragen für CORS-Preflight behandeln
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
// API-Endpunkt für OpenAI-Anfragen
if (req.method === 'POST' && req.url === '/api/chat') {
collectRequestData(req, async (data) => {
try {
if (!data.message) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Nachricht fehlt' }));
return;
}
// Verwende die Konversationshistorie, wenn vorhanden
const conversationHistory = data.conversationHistory || [];
console.log('Erhaltene Konversationshistorie:', JSON.stringify(conversationHistory, null, 2));
// Extrahiere Charakterinformationen, wenn vorhanden
const characterName = data.characterName;
const characterPersonality = data.characterPersonality;
if (characterName) {
console.log(`NPC-Charakter in der Anfrage: ${characterName}`);
}
const response = await callOpenAI(data.message, conversationHistory, characterName, characterPersonality);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
response: response.text,
identityRevealed: response.identityRevealed
}));
} catch (error) {
console.error('Fehler bei der Verarbeitung der Chat-Anfrage:', error);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Interner Serverfehler' }));
}
});
return;
}
// Statische Dateien behandeln
let filePath = '.' + req.url;
if (filePath === './') {
filePath = './index.html';
}
// Get the file extension
const extname = path.extname(filePath);
let contentType = MIME_TYPES[extname] || 'application/octet-stream';
// Read the file
fs.readFile(filePath, (error, content) => {
if (error) {
if (error.code === 'ENOENT') {
// Page not found
fs.readFile('./index.html', (err, content) => {
if (err) {
res.writeHead(500);
res.end('Error loading index.html');
} else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
} else {
// Server error
res.writeHead(500);
res.end(`Server Error: ${error.code}`);
}
} else {
// Success
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
});
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
console.log('Press Ctrl+C to stop the server');
console.log('Azure OpenAI API ist konfiguriert und bereit!');
});