Update genisi.js
Browse files
genisi.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
import express from 'express';
|
| 2 |
import cors from 'cors';
|
| 3 |
import { OpenAI } from "openai";
|
| 4 |
-
import fetch from 'node-fetch'; // أو fetch الأصلي في Node 18+
|
| 5 |
import path from 'path';
|
| 6 |
import { fileURLToPath } from 'url';
|
| 7 |
|
|
@@ -12,58 +11,7 @@ app.use(cors());
|
|
| 12 |
app.use(express.json());
|
| 13 |
app.use(express.static(__dirname));
|
| 14 |
|
| 15 |
-
// ✅
|
| 16 |
-
app.post('/api/fast', async (req, res) => {
|
| 17 |
-
const { message } = req.body;
|
| 18 |
-
|
| 19 |
-
try {
|
| 20 |
-
// استدعاء مباشر لـ Hugging Face Space API
|
| 21 |
-
const response = await fetch('https://ostarling-minimax-m2-5-chat.hf.space/api/predict', {
|
| 22 |
-
method: 'POST',
|
| 23 |
-
headers: {
|
| 24 |
-
'Content-Type': 'application/json',
|
| 25 |
-
// إذا احتجت token لاحقاً: 'Authorization': 'Bearer hf_...'
|
| 26 |
-
},
|
| 27 |
-
body: JSON.stringify({
|
| 28 |
-
fn_index: 0, // عادةً 0 للدالة الأولى
|
| 29 |
-
data: [
|
| 30 |
-
message, // message
|
| 31 |
-
"You are a helpful assistant.", // system_message
|
| 32 |
-
2048, // max_tokens
|
| 33 |
-
0.7, // temperature
|
| 34 |
-
0.95 // top_p
|
| 35 |
-
]
|
| 36 |
-
})
|
| 37 |
-
});
|
| 38 |
-
|
| 39 |
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
| 40 |
-
|
| 41 |
-
const result = await response.json();
|
| 42 |
-
// result.data يحتوي على الرد
|
| 43 |
-
|
| 44 |
-
res.json({
|
| 45 |
-
success: true,
|
| 46 |
-
content: result.data?.[0] || result.data || "لا يوجد رد",
|
| 47 |
-
model: "MiniMax-M2.5-Chat (HF)"
|
| 48 |
-
});
|
| 49 |
-
|
| 50 |
-
} catch (err) {
|
| 51 |
-
console.error('HF Error:', err);
|
| 52 |
-
// fallback: استخدام pollinations مباشرة
|
| 53 |
-
try {
|
| 54 |
-
const pollRes = await fetch('https://text.pollinations.ai/' + encodeURIComponent(message));
|
| 55 |
-
const text = await pollRes.text();
|
| 56 |
-
res.json({ success: true, content: text, model: "Pollinations (Fallback)" });
|
| 57 |
-
} catch (pollErr) {
|
| 58 |
-
res.status(500).json({
|
| 59 |
-
success: false,
|
| 60 |
-
error: "فشل الاتصال: " + err.message
|
| 61 |
-
});
|
| 62 |
-
}
|
| 63 |
-
}
|
| 64 |
-
});
|
| 65 |
-
|
| 66 |
-
// ✅ الوضع المفكر: Kimi (كما هو)
|
| 67 |
app.post('/api/think', async (req, res) => {
|
| 68 |
const { message } = req.body;
|
| 69 |
const POE_KEY = process.env.POE_API_KEY;
|
|
@@ -72,32 +20,101 @@ app.post('/api/think', async (req, res) => {
|
|
| 72 |
|
| 73 |
res.setHeader('Content-Type', 'text/event-stream');
|
| 74 |
res.setHeader('Cache-Control', 'no-cache');
|
|
|
|
| 75 |
|
| 76 |
-
const
|
| 77 |
apiKey: POE_KEY,
|
| 78 |
baseURL: "https://api.poe.com/v1"
|
| 79 |
});
|
| 80 |
|
| 81 |
try {
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
| 86 |
messages: [{ role: "user", content: message }],
|
| 87 |
-
stream: true
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
});
|
| 89 |
|
| 90 |
-
|
|
|
|
|
|
|
| 91 |
|
| 92 |
for await (const chunk of stream) {
|
| 93 |
-
const
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
}
|
| 96 |
|
| 97 |
res.write('data: [DONE]\n\n');
|
| 98 |
res.end();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
} catch (err) {
|
| 100 |
-
res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`);
|
| 101 |
res.end();
|
| 102 |
}
|
| 103 |
});
|
|
@@ -106,12 +123,5 @@ app.get('/', (req, res) => res.sendFile(path.join(__dirname, 'index.html')));
|
|
| 106 |
|
| 107 |
const PORT = process.env.PORT || 7860;
|
| 108 |
app.listen(PORT, () => {
|
| 109 |
-
console.log(`
|
| 110 |
-
✅ Server Ready (No @gradio/client needed)
|
| 111 |
-
-------------------------------------------
|
| 112 |
-
⚡ Fast: MiniMax (HF API) or Pollinations
|
| 113 |
-
🧠 Think: Kimi K2.5 FW (Poe API)
|
| 114 |
-
Port: ${PORT}
|
| 115 |
-
-------------------------------------------
|
| 116 |
-
`);
|
| 117 |
});
|
|
|
|
| 1 |
import express from 'express';
|
| 2 |
import cors from 'cors';
|
| 3 |
import { OpenAI } from "openai";
|
|
|
|
| 4 |
import path from 'path';
|
| 5 |
import { fileURLToPath } from 'url';
|
| 6 |
|
|
|
|
| 11 |
app.use(express.json());
|
| 12 |
app.use(express.static(__dirname));
|
| 13 |
|
| 14 |
+
// ✅ Kimi مع دعم Reasoning المنفصل
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
app.post('/api/think', async (req, res) => {
|
| 16 |
const { message } = req.body;
|
| 17 |
const POE_KEY = process.env.POE_API_KEY;
|
|
|
|
| 20 |
|
| 21 |
res.setHeader('Content-Type', 'text/event-stream');
|
| 22 |
res.setHeader('Cache-Control', 'no-cache');
|
| 23 |
+
res.setHeader('Connection', 'keep-alive');
|
| 24 |
|
| 25 |
+
const client = new OpenAI({
|
| 26 |
apiKey: POE_KEY,
|
| 27 |
baseURL: "https://api.poe.com/v1"
|
| 28 |
});
|
| 29 |
|
| 30 |
try {
|
| 31 |
+
// إشارة بدء التفكير
|
| 32 |
+
res.write(`data: ${JSON.stringify({ type: 'status', status: 'reasoning' })}\n\n`);
|
| 33 |
+
|
| 34 |
+
const stream = await client.chat.completions.create({
|
| 35 |
+
model: "kimi-k2.5-fw", // النموذج المفكر إجبارياً
|
| 36 |
messages: [{ role: "user", content: message }],
|
| 37 |
+
stream: true,
|
| 38 |
+
// محاولة طلب Reasoning منفصل (إن دعمته Poe لاحقاً)
|
| 39 |
+
extra_body: {
|
| 40 |
+
show_reasoning: true
|
| 41 |
+
}
|
| 42 |
});
|
| 43 |
|
| 44 |
+
let reasoningBuffer = "";
|
| 45 |
+
let isReasoningPhase = true;
|
| 46 |
+
let contentBuffer = "";
|
| 47 |
|
| 48 |
for await (const chunk of stream) {
|
| 49 |
+
const delta = chunk.choices[0]?.delta;
|
| 50 |
+
const content = delta?.content || "";
|
| 51 |
+
|
| 52 |
+
// ✅ محاولة استخراج Reasoning إن وُجد (OpenAI o1-style أو أTag)
|
| 53 |
+
if (delta?.reasoning && isReasoningPhase) {
|
| 54 |
+
res.write(`data: ${JSON.stringify({ type: 'reasoning', content: delta.reasoning })}\n\n`);
|
| 55 |
+
}
|
| 56 |
+
// ✅ إذا لم يوجد حقل منفصل، نفترض أن البداية هي التفكير ( heuristic )
|
| 57 |
+
else if (content) {
|
| 58 |
+
// نبحث عن علامة نهاية التفكير (إذا كان النموذج يستخدم <thinking> أو ---)
|
| 59 |
+
if (isReasoningPhase && (content.includes('</thinking>') || content.includes('\n\n**Answer:**'))) {
|
| 60 |
+
isReasoningPhase = false;
|
| 61 |
+
// إرسال ما سبق كتفكير
|
| 62 |
+
if (reasoningBuffer) {
|
| 63 |
+
res.write(`data: ${JSON.stringify({ type: 'reasoning_end' })}\n\n`);
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
if (isReasoningPhase) {
|
| 68 |
+
reasoningBuffer += content;
|
| 69 |
+
res.write(`data: ${JSON.stringify({ type: 'reasoning', content })}\n\n`);
|
| 70 |
+
} else {
|
| 71 |
+
res.write(`data: ${JSON.stringify({ type: 'content', content })}\n\n`);
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
}
|
| 75 |
|
| 76 |
res.write('data: [DONE]\n\n');
|
| 77 |
res.end();
|
| 78 |
+
|
| 79 |
+
} catch (err) {
|
| 80 |
+
res.write(`data: ${JSON.stringify({ type: 'error', error: err.message })}\n\n`);
|
| 81 |
+
res.end();
|
| 82 |
+
}
|
| 83 |
+
});
|
| 84 |
+
|
| 85 |
+
// ⚡ الوضع السريع: MiniMax (بدون تفكير معقد)
|
| 86 |
+
app.post('/api/fast', async (req, res) => {
|
| 87 |
+
const { message } = req.body;
|
| 88 |
+
|
| 89 |
+
res.setHeader('Content-Type', 'text/event-stream');
|
| 90 |
+
res.setHeader('Cache-Control', 'no-cache');
|
| 91 |
+
|
| 92 |
+
try {
|
| 93 |
+
const response = await fetch('https://ostarling-minimax-m2-5-chat.hf.space/api/predict', {
|
| 94 |
+
method: 'POST',
|
| 95 |
+
headers: { 'Content-Type': 'application/json' },
|
| 96 |
+
body: JSON.stringify({
|
| 97 |
+
fn_index: 0,
|
| 98 |
+
data: [message, "You are helpful", 1024, 0.7, 0.95]
|
| 99 |
+
})
|
| 100 |
+
});
|
| 101 |
+
|
| 102 |
+
const result = await response.json();
|
| 103 |
+
const text = result.data?.[0] || "";
|
| 104 |
+
|
| 105 |
+
// محاكاة Streaming للنص الكامل
|
| 106 |
+
const chars = text.split('');
|
| 107 |
+
for (let i = 0; i < chars.length; i += 2) {
|
| 108 |
+
const chunk = chars.slice(i, i + 2).join('');
|
| 109 |
+
res.write(`data: ${JSON.stringify({ type: 'content', content: chunk })}\n\n`);
|
| 110 |
+
await new Promise(r => setTimeout(r, 10));
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
res.write('data: [DONE]\n\n');
|
| 114 |
+
res.end();
|
| 115 |
+
|
| 116 |
} catch (err) {
|
| 117 |
+
res.write(`data: ${JSON.stringify({ type: 'error', error: err.message })}\n\n`);
|
| 118 |
res.end();
|
| 119 |
}
|
| 120 |
});
|
|
|
|
| 123 |
|
| 124 |
const PORT = process.env.PORT || 7860;
|
| 125 |
app.listen(PORT, () => {
|
| 126 |
+
console.log(`🧠 Server: Kimi Reasoning Mode | Port ${PORT}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
});
|