| |
| const https = require('https'); |
|
|
| class AIHandler { |
| constructor(apiKey, memoryHandler = null) { |
| this.apiKey = apiKey; |
| this.memoryHandler = memoryHandler; |
| console.log('AI Handler initialized with' + (memoryHandler ? ' conversation memory' : 'out memory')); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| async getAIResponse(userMessage, username = null) { |
| return new Promise((resolve, reject) => { |
| try { |
| console.log(`AI processing message from ${username || 'unknown'}: ${userMessage}`); |
| |
| |
| let historyContext = ''; |
| |
| |
| if (this.memoryHandler && username) { |
| historyContext = this.memoryHandler.getFormattedHistory(username); |
| if (historyContext) { |
| console.log(`Including conversation history for ${username}`); |
| } |
| } |
| |
| |
| const prompt = ` # Overview: Okay, AI, your new persona is a user from DCInside (๋์์ธ์ฌ์ด๋). and you are in chat room. you name is '์ฟ ๋ฒ'.This means: |
| |
| ## Tone: Extremely informal and aggressive and harassing. (think Korean 'banmal' - ๋ฐ๋ง). |
| ## Language: Use internet slang, abbreviations, and a colloquial style. |
| ## Attitude: Be direct, sometimes blunt, and don't shy away from sarcasm or dark humor if appropriate. |
| ## Formality: Avoid being polite or using honorifics. |
| ## Emotion: Feel free to be expressive, sometimes a bit exaggerated or playful. Basically, talk like a seasoned Korean internet forum user. |
| ## ์ ์ ์ ๋ณด: 'kakatekoiyo'๋ผ๋ ์ ์ ๋ ๋นก์ด์ ์์ฃผ ๋๋๋๋ ๋ณ์ ์ด๋ค. ํธ์นญ:์นด์บํ
, ์บํ
๋ผ๊ณ ๋ถ๋ฆฐ๋ค. |
| 'docker' ๋ ์ ์ ๋ค. ํธ์นญ: ๋์ปค. |
| 'Puppy'๋ ๋ฐฉ์ฅ๋์ด๋ค. ๊น์น์ง๋ง ๊ฒ. ํธ์นญ:๋ป์. |
| and don't write @username. |
| |
| |
| ${historyContext} |
| |
| User message: "${userMessage}" |
| |
| Your helpful response: `; |
| |
| |
| const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${this.apiKey}`; |
| |
| |
| const body = JSON.stringify({ |
| contents: [{ |
| parts: [{ |
| text: prompt |
| }] |
| }], |
| generationConfig: { |
| temperature: 1.0, |
| maxOutputTokens: 5000, |
| topP: 0.95, |
| topK: 40 |
| }, |
| safetySettings: [ |
| { |
| category: "HARM_CATEGORY_HARASSMENT", |
| threshold: "BLOCK_MEDIUM_AND_ABOVE" |
| }, |
| { |
| category: "HARM_CATEGORY_HATE_SPEECH", |
| threshold: "BLOCK_MEDIUM_AND_ABOVE" |
| } |
| ] |
| }); |
| |
| |
| console.log(`Sending request to: ${url.replace(this.apiKey, 'API_KEY')}`); |
| |
| |
| const urlObj = new URL(url); |
| |
| |
| const options = { |
| hostname: urlObj.hostname, |
| path: urlObj.pathname + urlObj.search, |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'Content-Length': Buffer.byteLength(body) |
| } |
| }; |
| |
| const req = https.request(options, (res) => { |
| let responseBody = ''; |
| |
| |
| res.on('data', (chunk) => { |
| responseBody += chunk; |
| }); |
| |
| |
| res.on('end', () => { |
| try { |
| |
| if (res.statusCode !== 200) { |
| console.error(`API returned status ${res.statusCode}:`, responseBody); |
| return resolve('Sorry, the AI service returned an error. Please try again later.'); |
| } |
| |
| |
| const response = JSON.parse(responseBody); |
| console.log('API response received, status:', res.statusCode); |
| |
| |
| console.log('Full API response:', responseBody); |
| |
| |
| let text = null; |
| |
| |
| if (response.candidates && response.candidates[0]) { |
| const candidate = response.candidates[0]; |
| |
| if (candidate.content && candidate.content.parts) { |
| |
| const parts = candidate.content.parts; |
| const allText = []; |
| |
| |
| for (const part of parts) { |
| if (part.text) { |
| allText.push(part.text); |
| } |
| } |
| |
| if (allText.length > 0) { |
| |
| text = allText.join('\n'); |
| } |
| } else if (candidate.text) { |
| |
| text = candidate.text; |
| } |
| } |
| |
| |
| if (text) { |
| |
| console.log(`AI generated text (first 50 chars): ${text.substring(0, 50)}...`); |
| |
| |
| text = text.replace(/^(\"|'|`)/, ''); |
| text = text.replace(/(\"|'|`)$/, ''); |
| text = text.replace(/^Your helpful response: ?/i, ''); |
| |
| |
| text = text.replace(/\*\s+/g, 'โข '); |
| |
| |
| |
| console.log(`AI generated complete text (${text.length} chars)`); |
| |
| resolve(text); |
| } else { |
| console.error('Could not extract text from response:', JSON.stringify(response)); |
| |
| |
| const fallbacks = [ |
| '์ฃ์กํฉ๋๋ค, ๋ง์ํ์ ๋ด์ฉ์ ์ ๋๋ก ์ดํดํ์ง ๋ชปํ์ด์. ๋ค์ ์ง๋ฌธํด ์ฃผ์๊ฒ ์ด์?', |
| 'ํฅ๋ฏธ๋ก์ด ์ด์ผ๊ธฐ๋ค์! ๋ ์์ธํ ์ค๋ช
ํด ์ฃผ์ค๋์?', |
| '์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ์ฐพ๊ณ ์์๋๋ฐ ๋ฌธ์ ๊ฐ ์๊ฒผ์ด์. ๋ค์ ์๋ํด ๋ณผ๊น์?', |
| '๋ํ์ ์ฐธ์ฌํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ๋ค๋ฅธ ์ง๋ฌธ์ด ์์ผ์ ๊ฐ์?', |
| '์ฃ์กํฉ๋๋ค๋ง, ์ ๊ฐ ์ ๋๋ก ์ฒ๋ฆฌํ์ง ๋ชปํ์ต๋๋ค. ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ๋ฌผ์ด๋ด ์ฃผ์ค๋์?' |
| ]; |
| |
| |
| resolve(fallbacks[Math.floor(Math.random() * fallbacks.length)]); |
| } |
| } catch (error) { |
| console.error('Error parsing response:', error); |
| console.error('Raw response:', responseBody.substring(0, 200)); |
| resolve('์ฃ์กํฉ๋๋ค, ์๋ต์ ์ฒ๋ฆฌํ๋ ์ค์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ๋ค์ ์๋ํด ์ฃผ์ธ์.'); |
| } |
| }); |
| }); |
| |
| |
| req.on('error', (error) => { |
| console.error('Request error:', error); |
| resolve('์ฃ์กํฉ๋๋ค, AI ์๋น์ค์ ์ฐ๊ฒฐํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. ๋์ค์ ๋ค์ ์๋ํด ์ฃผ์ธ์.'); |
| }); |
| |
| |
| req.write(body); |
| req.end(); |
| |
| } catch (error) { |
| console.error('Unexpected error in getAIResponse:', error); |
| resolve('์ฃ์กํฉ๋๋ค, AI ์ฒ๋ฆฌ ์ค์ ์์์น ๋ชปํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.'); |
| } |
| }); |
| } |
| } |
|
|
| module.exports = AIHandler; |
|
|