| import express from "express"; |
| import path from "path"; |
| import { createServer as createViteServer } from "vite"; |
| import dotenv from "dotenv"; |
|
|
| dotenv.config(); |
|
|
| const app = express(); |
| const PORT = 3000; |
|
|
| app.use(express.json({ limit: "50mb" })); |
| app.use(express.urlencoded({ limit: "50mb", extended: true })); |
|
|
| app.use((req, res, next) => { |
| res.header("Access-Control-Allow-Origin", "*"); |
| res.header( |
| "Access-Control-Allow-Headers", |
| "Origin, X-Requested-With, Content-Type, Accept, Authorization" |
| ); |
| res.header( |
| "Access-Control-Allow-Methods", |
| "GET, POST, PUT, DELETE, OPTIONS" |
| ); |
|
|
| if (req.method === "OPTIONS") { |
| return res.sendStatus(200); |
| } |
|
|
| next(); |
| }); |
|
|
| |
| app.get("/api/proxy", async (req, res) => { |
| const targetUrl = req.query.url as string; |
|
|
| if (!targetUrl) { |
| return res.status(400).json({ |
| error: "الرابط مطلوب" |
| }); |
| } |
|
|
| try { |
| const formattedUrl = targetUrl.startsWith("http") |
| ? targetUrl |
| : `https://${targetUrl}`; |
|
|
| const response = await fetch(formattedUrl); |
|
|
| if (!response.ok) { |
| return res.status(response.status).json({ |
| error: `فشل جلب الموقع: ${response.statusText}` |
| }); |
| } |
|
|
| const contentType = response.headers.get("content-type") || ""; |
|
|
| if ( |
| contentType.includes("html") || |
| contentType.includes("css") || |
| contentType.includes("javascript") || |
| contentType.includes("text") || |
| contentType.includes("json") |
| ) { |
| const text = await response.text(); |
| res.setHeader("Content-Type", contentType); |
| return res.send(text); |
| } |
|
|
| const buffer = await response.arrayBuffer(); |
| res.setHeader("Content-Type", contentType); |
| return res.send(Buffer.from(buffer)); |
| } catch (err: any) { |
| return res.status(500).json({ |
| error: err.message |
| }); |
| } |
| }); |
|
|
| |
| app.post("/api/ai/chat", async (req, res) => { |
| const { messages, customApiKey } = req.body; |
|
|
| if (!messages || !Array.isArray(messages)) { |
| return res.status(400).json({ |
| error: "المحادثة غير صالحة" |
| }); |
| } |
|
|
| const apiKeys = [ |
| customApiKey, |
| process.env.GROQ_API_KEY, |
| process.env.GROQ_API_KEY_2, |
| process.env.GROQ_API_KEY_3 |
| ].filter(Boolean); |
|
|
| if (!apiKeys.length) { |
| return res.status(400).json({ |
| error: "لا يوجد مفتاح Groq" |
| }); |
| } |
|
|
| const systemPrompt = ` |
| أنت مساعد SiteClone Pro v20. |
| متخصص في: |
| - Web cloning |
| - Workflows |
| - APIs |
| - Debugging |
| - Hosting |
| أجب دائمًا بالعربية. |
| `; |
|
|
| const formattedMessages = [ |
| { |
| role: "system", |
| content: systemPrompt |
| }, |
| ...messages.map((m: any) => ({ |
| role: m.role === "model" ? "assistant" : "user", |
| content: m.content |
| })) |
| ]; |
|
|
| let lastError: any = null; |
|
|
| for (const key of apiKeys) { |
| try { |
| const controller = new AbortController(); |
| const timeoutId = setTimeout(() => controller.abort(), 20000); |
|
|
| const response = await fetch( |
| "https://api.groq.com/openai/v1/chat/completions", |
| { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Authorization: `Bearer ${key}` |
| }, |
| body: JSON.stringify({ |
| model: "llama-3.3-70b-versatile", |
| messages: formattedMessages, |
| temperature: 0.7 |
| }), |
| signal: controller.signal |
| } |
| ); |
|
|
| clearTimeout(timeoutId); |
|
|
| if (!response.ok) { |
| const errText = await response.text(); |
| throw new Error(errText); |
| } |
|
|
| const data = await response.json(); |
|
|
| return res.json({ |
| text: |
| data.choices?.[0]?.message?.content || |
| "لم يتم الحصول على رد.", |
| activeProvider: "Groq", |
| activeModel: "llama-3.3-70b-versatile" |
| }); |
| } catch (err: any) { |
| console.warn("Groq Key Failed:", err.message); |
| lastError = err; |
| continue; |
| } |
| } |
|
|
| return res.status(500).json({ |
| error: `فشل جميع مفاتيح Groq: ${lastError?.message}` |
| }); |
| }); |
|
|
| |
| async function initServer() { |
| if (process.env.NODE_ENV !== "production") { |
| const vite = await createViteServer({ |
| server: { |
| middlewareMode: true |
| }, |
| appType: "spa" |
| }); |
|
|
| app.use(vite.middlewares); |
| } else { |
| const distPath = path.join(process.cwd(), "dist"); |
|
|
| app.use(express.static(distPath)); |
|
|
| app.get("*", (req, res) => { |
| res.sendFile(path.join(distPath, "index.html")); |
| }); |
| } |
|
|
| app.listen(PORT, "0.0.0.0", () => { |
| console.log(`SiteClone Pro running on port ${PORT}`); |
| }); |
| } |
|
|
| initServer().catch((err) => { |
| console.error("Initialization error:", err); |
| }); |