File size: 4,633 Bytes
13b72a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const fs = require('fs');
const path = require('path');

const guideStructure = fs.readFileSync(path.join(__dirname, 'GUIDE-STRUCTURE.md'), 'utf-8');
const explainStructure = fs.readFileSync(path.join(__dirname, 'EXPLAIN-STRUCTURE.md'), 'utf-8');

// --- 1. OPENAI FORMAT (OpenAI, Groq, DeepSeek) ---
async function fetchOpenAIFormat(prompt, system, apiKey, endpoint, modelName, jsonMode) {
    let systemPrompt = system;
    let userPrompt = prompt;

    if (jsonMode) {
        if (!systemPrompt.toLowerCase().includes("json")) systemPrompt += "\n\nYou must respond strictly with a valid JSON object.";
        if (!userPrompt.toLowerCase().includes("json")) userPrompt += " (Respond strictly in JSON format)";
    }

    const payload = {
        model: modelName,
        messages: [{ role: "system", content: systemPrompt }, { role: "user", content: userPrompt }],
        temperature: 0.2
    };
    if (jsonMode) payload.response_format = { type: "json_object" };

    const res = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
        body: JSON.stringify(payload)
    });
    if (!res.ok) throw new Error(`OpenAI format error: ${await res.text()}`);
    const data = await res.json();
    return data.choices[0].message.content;
}

// --- 2. CLAUDE FORMAT ---
async function fetchClaude(prompt, system, apiKey, modelName, jsonMode) {
    let finalPrompt = prompt;
    if (jsonMode) finalPrompt += "\n\nRespond ONLY with valid JSON.";

    const res = await fetch("https://api.anthropic.com/v1/messages", {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
        body: JSON.stringify({ model: modelName, system: system, messages: [{ role: "user", content: finalPrompt }], max_tokens: 1024, temperature: 0.1 })
    });
    if (!res.ok) throw new Error(`Claude error: ${await res.text()}`);
    const data = await res.json();
    return data.content[0].text;
}

// --- 3. GEMINI FORMAT ---
async function fetchGemini(prompt, system, apiKey, modelName, jsonMode) {
    const url = `https://generativelanguage.googleapis.com/v1beta/models/${modelName}:generateContent?key=${apiKey}`;
    const payload = {
        systemInstruction: { parts: [{ text: system }] },
        contents: [{ parts: [{ text: prompt }] }],
        generationConfig: { temperature: 0.1 }
    };
    if (jsonMode) payload.generationConfig.responseMimeType = "application/json";

    const res = await fetch(url, {
        method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload)
    });
    if (!res.ok) throw new Error(`Gemini error: ${await res.text()}`);
    const data = await res.json();
    return data.candidates[0].content.parts[0].text;
}

// --- MAIN ROUTERS ---
async function callLLM(prompt, provider, apiKey, modelName, isExplain) {
    const system = isExplain ? explainStructure : guideStructure;
    const jsonMode = !isExplain;

    if (provider === 'zerogpu') {
        const endpoint = isExplain ? '/explain' : '/generate';
        const res = await fetch(`http://127.0.0.1:8000${endpoint}`, {
            method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: prompt })
        });
        if (!res.ok) throw new Error("Local Python AI Server is down");
        const data = await res.json();
        return isExplain ? data.explanation : JSON.stringify(data);
    }

    if (!apiKey) throw new Error(`API key required for ${provider}`);

    switch (provider.toLowerCase()) {
        case 'openai': return await fetchOpenAIFormat(prompt, system, apiKey, "https://api.openai.com/v1/chat/completions", modelName, jsonMode);
        case 'groq': return await fetchOpenAIFormat(prompt, system, apiKey, "https://api.groq.com/openai/v1/chat/completions", modelName, jsonMode);
        case 'claude': return await fetchClaude(prompt, system, apiKey, modelName, jsonMode);
        case 'gemini': return await fetchGemini(prompt, system, apiKey, modelName, jsonMode);
        default: throw new Error("Unsupported LLM Provider");
    }
}

async function routeCommand(query, provider, apiKey, modelName) {
    const text = await callLLM(query, provider, apiKey, modelName, false);
    try { return JSON.parse(text); } catch (e) { throw new Error(`LLM did not return valid JSON: ${text}`); }
}
async function explainResult(context, provider, apiKey, modelName) {
    return await callLLM(context, provider, apiKey, modelName, true);
}
module.exports = { routeCommand, explainResult };