Spaces:
Sleeping
Sleeping
| import express from 'express'; | |
| import axios from 'axios'; | |
| import crypto from 'crypto'; | |
| import FormData from 'form-data'; // Import modul form-data untuk menghandle multipart | |
| import Groq from 'groq-sdk'; | |
| import bytes from 'bytes'; | |
| import { feloAI } from '../lib/feloAI.js'; | |
| import { toAnime } from '../lib/toanime.js'; | |
| import { convertWebpToPng } from '../lib/converter.js'; | |
| const APIrouter = express.Router(); | |
| const ISauthenticate = async (req, res, next) => { | |
| try { | |
| const secretResponse = 'ekspann'; | |
| const generatedApiKey = generateApiKey(secretResponse); | |
| console.log(generatedApiKey); | |
| console.log(req.headers); | |
| const authHeader = req.headers['authorization']; | |
| if (!authHeader || authHeader !== `Bearer ${generatedApiKey}`) { | |
| console.error(`user: ${authHeader}\n message: 'Unauthorized'`); | |
| return res.status(403).json({ success: false, message: 'Unauthorized' }); | |
| } | |
| next(); | |
| } catch (error) { | |
| console.error('Authentication error:', error); | |
| return res.status(500).json({ success: false, message: 'Internal Server Error' }); | |
| } | |
| }; | |
| // Inisialisasi Groq SDK | |
| const client = new Groq({ | |
| apiKey: process.env.GROQ_API_KEY || process.env.GROQ_API_KEY_2 || "", | |
| dangerouslyAllowBrowser: true, | |
| }); | |
| APIrouter.get('/', (req, res) => { | |
| res.send('Hello World'); | |
| }); | |
| APIrouter.get('/msecret', (req, res) => { | |
| const secret = 'ekspann'; | |
| res.json({ msec: secret }); | |
| }); | |
| APIrouter.post('/gpt/completions', ISauthenticate, async (req, res) => { | |
| const { | |
| messages, | |
| model, | |
| temperature, | |
| max_completion_tokens, | |
| top_p, | |
| stream, | |
| stop, | |
| searchMode | |
| } = req.body; | |
| try { | |
| // Set header untuk streaming (Server-Sent Events) | |
| res.setHeader('Content-Type', 'text/event-stream'); | |
| res.setHeader('Cache-Control', 'no-cache'); | |
| res.setHeader('Connection', 'keep-alive'); | |
| // Mode tanpa search (normal GPT response stream) | |
| if (searchMode === false) { | |
| const chatStream = await client.chat.completions.create({ | |
| messages, | |
| model, | |
| temperature, | |
| max_completion_tokens, | |
| top_p, | |
| stream, | |
| stop, | |
| }); | |
| // Kirim setiap chunk stream ke client | |
| for await (const chunk of chatStream) { | |
| res.write(`data: ${JSON.stringify(chunk)}\n\n`); | |
| } | |
| res.write('data: [DONE]\n\n'); | |
| return res.end(); | |
| } | |
| // Mode dengan search (tool use) | |
| else if (searchMode === true) { | |
| // Definisi fungsi searchEngine | |
| const searchEngine = async (query, langcode = 'en-US') => { | |
| try { | |
| console.log("searching..."); | |
| console.log("query:", query); | |
| console.log("lang:", langcode); | |
| const searchResult = await feloAI(query, langcode); | |
| // Susun hasil pencarian | |
| let result = { answer: "", source: [] }; | |
| result.answer = searchResult.answer; | |
| for (let i = 0; i < 5; i++) { | |
| result.source.push({ | |
| title: searchResult.source[i].title, | |
| link: searchResult.source[i].link, | |
| snippet: searchResult.source[i].snippet | |
| }); | |
| } | |
| return result; | |
| } catch (error) { | |
| console.error(error); | |
| return null; | |
| } | |
| }; | |
| // Definisi tool untuk searchEngine | |
| const tools = [ | |
| { | |
| type: "function", | |
| function: { | |
| name: "searchEngine", | |
| description: | |
| "Mencari informasi secara real-time dengan search engine berdasarkan query dan target daerah.", | |
| parameters: { | |
| type: "object", | |
| properties: { | |
| query: { | |
| type: "string", | |
| description: "Query pencarian untuk mencari informasi secara real-time." | |
| }, | |
| langcode: { | |
| type: "string", | |
| description: | |
| "Kode bahasa atau nama daerah target (misalnya 'id-MM' (indonesia), 'en-US' (inggris), atau lainnya). tergantung dengan ketikan bahasa yang di gunakan." | |
| } | |
| }, | |
| required: ["query", "langcode"] | |
| } | |
| } | |
| } | |
| ]; | |
| // Panggilan awal ke Groq untuk mendapatkan tool call | |
| const response = await client.chat.completions.create({ | |
| model: model, | |
| messages, | |
| stream: false, | |
| tools, | |
| tool_choice: "auto", | |
| max_completion_tokens: 4096 | |
| }); | |
| const responseMessage = response.choices[0].message; | |
| console.log("Response message:", JSON.stringify(responseMessage, null, 2)); | |
| // Hapus properti yang tidak didukung | |
| if (responseMessage.reasoning) { | |
| delete responseMessage.reasoning; | |
| } | |
| const toolCalls = responseMessage.tool_calls || []; | |
| if (toolCalls.length > 0) { | |
| const availableFunctions = { searchEngine }; | |
| // Tambahkan respons awal ke array pesan | |
| messages.push(responseMessage); | |
| // Eksekusi setiap tool call | |
| for (const toolCall of toolCalls) { | |
| const functionName = toolCall.function.name; | |
| const functionToCall = availableFunctions[functionName]; | |
| const functionArgs = JSON.parse(toolCall.function.arguments); | |
| const functionResponse = await functionToCall( | |
| functionArgs.query, | |
| functionArgs.langcode | |
| ); | |
| messages.push({ | |
| tool_call_id: toolCall.id, | |
| role: "tool", | |
| name: functionName, | |
| content: JSON.stringify(functionResponse) | |
| }); | |
| } | |
| } | |
| // Panggilan kedua dengan opsi streaming | |
| const secondResponseStream = await client.chat.completions.create({ | |
| model: model, | |
| messages, | |
| stream, | |
| }); | |
| let finalContent = ""; | |
| try { | |
| for await (const chunk of secondResponseStream) { | |
| // Ambil chunk respons (sesuaikan dengan struktur output model) | |
| const contentChunk = | |
| (chunk.choices && chunk.choices[0].delta && chunk.choices[0].delta.content) || ""; | |
| finalContent += contentChunk; | |
| res.write(`data: ${JSON.stringify(chunk)}\n\n`); | |
| } | |
| } catch (err) { | |
| console.error("Error processing stream:", err); | |
| } | |
| res.write('data: [DONE]\n\n'); | |
| res.end(); | |
| } | |
| } catch (error) { | |
| console.error('GPT completion error:', error); | |
| res.status(500).json({ message: 'Internal Server Error' }); | |
| } | |
| }); | |
| APIrouter.get('/gpt/modellist', ISauthenticate, async (req, res) => { | |
| try { | |
| const models = await client.models.list(); | |
| res.json(models); | |
| } catch (error) { | |
| console.error('GPT completion error:', error); | |
| res.status(500).json({ message: 'Internal Server Error' }); | |
| } | |
| }); | |
| APIrouter.post('/toanime', async (req, res) => { | |
| try { | |
| console.log(req.body) | |
| const { images } = req.body | |
| if (!images) return res.json({ success: false, message: 'Required an images!' }) | |
| if (/^(https?|http):\/\//i.test(images)) { | |
| const data_img = await axios.request({ | |
| method: "GET", | |
| url: images, | |
| responseType: "arraybuffer" | |
| }) | |
| const response = await toAnime({ imgBuffer: data_img.data }); | |
| //const type_img = await fileTypeFromBuffer(response) | |
| //res.setHeader('Content-Type', type_img.mime) | |
| res.json({ | |
| status: true, | |
| data: response | |
| }) | |
| } else if (images && typeof images == 'string' && isBase64(images)) { | |
| const response = await toAnime({ imgBuffer: Buffer.from(images, "base64") }); | |
| //const converted = await convertWebpToPng(response); | |
| //const type_img = await fileTypeFromBuffer(response) | |
| //res.setHeader('Content-Type', type_img.mime) | |
| res.json({ | |
| status: true, | |
| data: response | |
| }) | |
| } else { | |
| res.json({ | |
| success: false, message: 'No url or base64 detected!!' | |
| }) | |
| } | |
| } catch (e) { | |
| console.log(e) | |
| e = String(e) | |
| res.json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) | |
| } | |
| }) | |
| export default APIrouter; | |
| function generateApiKey(secret) { | |
| // Ambil menit saat ini sebagai nilai integer | |
| const currentMinute = Math.floor(Date.now() / 60000).toString(); | |
| // Buat HMAC menggunakan algoritma SHA256 dan secret key | |
| const hmac = crypto.createHmac('sha256', secret); | |
| hmac.update(currentMinute); | |
| // Kembalikan hash dalam format hexadecimal | |
| return hmac.digest('hex'); | |
| }; | |
| function formatSize(num) { | |
| return bytes(+num || 0, { unitSeparator: ' ' }) | |
| } | |
| function isBase64(str) { | |
| try { | |
| return btoa(atob(str)) === str | |
| } catch { | |
| return false | |
| } | |
| } |