Spaces:
Running
Running
Upload 8 files
Browse files- Dockerfile +11 -20
- services/ai.service.js +35 -56
- services/memory.service.js +2 -10
- services/socket.service.js +1 -1
Dockerfile
CHANGED
|
@@ -1,28 +1,19 @@
|
|
| 1 |
-
FROM
|
| 2 |
|
| 3 |
-
# Set environment variables
|
| 4 |
-
ENV PYTHONUNBUFFERED=1 \
|
| 5 |
-
HF_HOME=/tmp/huggingface \
|
| 6 |
-
TRANSFORMERS_CACHE=/tmp/huggingface
|
| 7 |
-
|
| 8 |
-
# Install system dependencies
|
| 9 |
-
RUN apt-get update && apt-get install -y \
|
| 10 |
-
build-essential \
|
| 11 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 12 |
-
|
| 13 |
-
# Create and set working directory
|
| 14 |
WORKDIR /app
|
| 15 |
|
| 16 |
-
# Copy
|
| 17 |
-
COPY
|
| 18 |
-
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
# Copy
|
| 21 |
COPY . .
|
| 22 |
|
| 23 |
-
# Expose port 7860
|
|
|
|
| 24 |
EXPOSE 7860
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
|
| 28 |
-
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
| 1 |
+
FROM node:20
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
# Copy package files
|
| 6 |
+
COPY package*.json ./
|
| 7 |
+
|
| 8 |
+
# Install dependencies
|
| 9 |
+
RUN npm install
|
| 10 |
|
| 11 |
+
# Copy all source code
|
| 12 |
COPY . .
|
| 13 |
|
| 14 |
+
# Expose port 7860 for Hugging Face
|
| 15 |
+
ENV PORT=7860
|
| 16 |
EXPOSE 7860
|
| 17 |
|
| 18 |
+
# Start the server
|
| 19 |
+
CMD ["node", "server.js"]
|
|
|
services/ai.service.js
CHANGED
|
@@ -4,11 +4,10 @@ const Groq = require('groq-sdk');
|
|
| 4 |
|
| 5 |
class AIService {
|
| 6 |
constructor() {
|
|
|
|
|
|
|
| 7 |
if (!config.groqApiKey) {
|
| 8 |
console.warn('β οΈ WARNING: No GROQ_API_KEY found in .env file. AURA will be unresponsive.');
|
| 9 |
-
this.groq = null;
|
| 10 |
-
} else {
|
| 11 |
-
this.groq = new Groq({ apiKey: config.groqApiKey });
|
| 12 |
}
|
| 13 |
}
|
| 14 |
|
|
@@ -17,27 +16,27 @@ class AIService {
|
|
| 17 |
console.log(`π [RESEARCH] Searching web (DDG) for: ${query}`);
|
| 18 |
onChunk({ type: 'thought', content: `Searching live web for "${query}"...` });
|
| 19 |
|
| 20 |
-
const
|
| 21 |
-
const
|
| 22 |
|
| 23 |
const response = await fetch(url, {
|
|
|
|
| 24 |
headers: {
|
|
|
|
| 25 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
|
| 26 |
-
}
|
|
|
|
| 27 |
});
|
| 28 |
|
| 29 |
const html = await response.text();
|
| 30 |
const results = [];
|
| 31 |
-
const
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
const snippet = snippetMatch ? snippetMatch[1].replace(/<[^>]*>/g, '').trim() : "";
|
| 39 |
-
results.push(`Title: ${title}\nSnippet: ${snippet}`);
|
| 40 |
-
}
|
| 41 |
}
|
| 42 |
|
| 43 |
if (results.length === 0) return null;
|
|
@@ -48,7 +47,7 @@ class AIService {
|
|
| 48 |
|
| 49 |
const analysis = await this.groq.chat.completions.create({
|
| 50 |
messages: [{ role: 'user', content: analysisPrompt }],
|
| 51 |
-
model: "llama-3-
|
| 52 |
temperature: 0.1,
|
| 53 |
});
|
| 54 |
|
|
@@ -64,9 +63,6 @@ class AIService {
|
|
| 64 |
|
| 65 |
// --- REASONING THINKING STAGE ---
|
| 66 |
async getReasoning(text, history, onChunk) {
|
| 67 |
-
if (!this.groq) {
|
| 68 |
-
throw new Error("GROQ_API_KEY is missing. Please add it to your Hugging Face Space secrets.");
|
| 69 |
-
}
|
| 70 |
console.log('π Performing strategic thinking...');
|
| 71 |
onChunk({ type: 'thought', content: "Thinking about how to address this request..." });
|
| 72 |
|
|
@@ -87,7 +83,7 @@ Keep it brief. Use "Thought: ..." format.
|
|
| 87 |
try {
|
| 88 |
const response = await this.groq.chat.completions.create({
|
| 89 |
messages: [{ role: 'user', content: reasoningPrompt }],
|
| 90 |
-
model: "llama-3-
|
| 91 |
temperature: 0.5,
|
| 92 |
max_tokens: 150,
|
| 93 |
});
|
|
@@ -112,11 +108,7 @@ Keep it brief. Use "Thought: ..." format.
|
|
| 112 |
|
| 113 |
// 3. RESEARCH & ANALYSIS
|
| 114 |
if (needsSearch) {
|
| 115 |
-
|
| 116 |
-
researchData = await this.performLightpandaSearch(text, onChunk);
|
| 117 |
-
if (!researchData) {
|
| 118 |
-
researchData = await this.performWebSearch(text, onChunk);
|
| 119 |
-
}
|
| 120 |
}
|
| 121 |
|
| 122 |
// 4. FINAL SYNTHESIS
|
|
@@ -131,19 +123,6 @@ Keep it brief. Use "Thought: ..." format.
|
|
| 131 |
}
|
| 132 |
}
|
| 133 |
|
| 134 |
-
async performLightpandaSearch(query, onChunk) {
|
| 135 |
-
try {
|
| 136 |
-
console.log(`πΌ [LIGHTPANDA] Scanning deep web for: ${query}`);
|
| 137 |
-
onChunk({ type: 'thought', content: "Activating Lightpanda High-Performance Browser Engine..." });
|
| 138 |
-
|
| 139 |
-
// This is where we would call the Lightpanda binary
|
| 140 |
-
// For now, it's a structural integration waiting for the binary path
|
| 141 |
-
return null; // Fallback to standard search for now
|
| 142 |
-
} catch (e) {
|
| 143 |
-
return null;
|
| 144 |
-
}
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
detectLiveIntent(text) {
|
| 148 |
const query = text.toLowerCase();
|
| 149 |
const liveKeywords = ['today', 'now', 'news', 'live', 'price', 'score', 'weather', 'current', 'latest', 'match', 'vs'];
|
|
@@ -152,25 +131,28 @@ Keep it brief. Use "Thought: ..." format.
|
|
| 152 |
|
| 153 |
async getGroqResponse(text, history, onChunk, researchData = "", thought = "") {
|
| 154 |
let systemPrompt = `
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
| 167 |
`;
|
| 168 |
|
| 169 |
if (thought) systemPrompt += `\n\n## INTERNAL STRATEGY:\n${thought}`;
|
| 170 |
if (researchData) {
|
| 171 |
-
systemPrompt += `\n\n##
|
| 172 |
} else {
|
| 173 |
-
systemPrompt += `\n\n## NOTE:\
|
| 174 |
}
|
| 175 |
|
| 176 |
const messages = [{ role: 'system', content: systemPrompt }];
|
|
@@ -180,9 +162,6 @@ You are AURA, an elite artificial intelligence integrated with the Lightpanda Hi
|
|
| 180 |
});
|
| 181 |
messages.push({ role: 'user', content: text });
|
| 182 |
|
| 183 |
-
if (!this.groq) {
|
| 184 |
-
throw new Error("GROQ_API_KEY is missing. Please add it to your Hugging Face Space secrets.");
|
| 185 |
-
}
|
| 186 |
const stream = await this.groq.chat.completions.create({
|
| 187 |
messages: messages,
|
| 188 |
model: "llama-3.3-70b-versatile",
|
|
|
|
| 4 |
|
| 5 |
class AIService {
|
| 6 |
constructor() {
|
| 7 |
+
this.groq = config.groqApiKey ? new Groq({ apiKey: config.groqApiKey }) : null;
|
| 8 |
+
|
| 9 |
if (!config.groqApiKey) {
|
| 10 |
console.warn('β οΈ WARNING: No GROQ_API_KEY found in .env file. AURA will be unresponsive.');
|
|
|
|
|
|
|
|
|
|
| 11 |
}
|
| 12 |
}
|
| 13 |
|
|
|
|
| 16 |
console.log(`π [RESEARCH] Searching web (DDG) for: ${query}`);
|
| 17 |
onChunk({ type: 'thought', content: `Searching live web for "${query}"...` });
|
| 18 |
|
| 19 |
+
const url = `https://lite.duckduckgo.com/lite/`;
|
| 20 |
+
const body = new URLSearchParams({ q: query }).toString();
|
| 21 |
|
| 22 |
const response = await fetch(url, {
|
| 23 |
+
method: 'POST',
|
| 24 |
headers: {
|
| 25 |
+
'Content-Type': 'application/x-www-form-urlencoded',
|
| 26 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
|
| 27 |
+
},
|
| 28 |
+
body: body
|
| 29 |
});
|
| 30 |
|
| 31 |
const html = await response.text();
|
| 32 |
const results = [];
|
| 33 |
+
const regex = /<td class='result-snippet'[^>]*>([\s\S]*?)<\/td>/gi;
|
| 34 |
+
let match;
|
| 35 |
+
let count = 0;
|
| 36 |
+
while ((match = regex.exec(html)) !== null && count < 5) {
|
| 37 |
+
let snippet = match[1].replace(/<[^>]*>/g, '').trim();
|
| 38 |
+
results.push(`Snippet: ${snippet}`);
|
| 39 |
+
count++;
|
|
|
|
|
|
|
|
|
|
| 40 |
}
|
| 41 |
|
| 42 |
if (results.length === 0) return null;
|
|
|
|
| 47 |
|
| 48 |
const analysis = await this.groq.chat.completions.create({
|
| 49 |
messages: [{ role: 'user', content: analysisPrompt }],
|
| 50 |
+
model: "llama-3.3-70b-versatile",
|
| 51 |
temperature: 0.1,
|
| 52 |
});
|
| 53 |
|
|
|
|
| 63 |
|
| 64 |
// --- REASONING THINKING STAGE ---
|
| 65 |
async getReasoning(text, history, onChunk) {
|
|
|
|
|
|
|
|
|
|
| 66 |
console.log('π Performing strategic thinking...');
|
| 67 |
onChunk({ type: 'thought', content: "Thinking about how to address this request..." });
|
| 68 |
|
|
|
|
| 83 |
try {
|
| 84 |
const response = await this.groq.chat.completions.create({
|
| 85 |
messages: [{ role: 'user', content: reasoningPrompt }],
|
| 86 |
+
model: "llama-3.3-70b-versatile",
|
| 87 |
temperature: 0.5,
|
| 88 |
max_tokens: 150,
|
| 89 |
});
|
|
|
|
| 108 |
|
| 109 |
// 3. RESEARCH & ANALYSIS
|
| 110 |
if (needsSearch) {
|
| 111 |
+
researchData = await this.performWebSearch(text, onChunk);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
}
|
| 113 |
|
| 114 |
// 4. FINAL SYNTHESIS
|
|
|
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
detectLiveIntent(text) {
|
| 127 |
const query = text.toLowerCase();
|
| 128 |
const liveKeywords = ['today', 'now', 'news', 'live', 'price', 'score', 'weather', 'current', 'latest', 'match', 'vs'];
|
|
|
|
| 131 |
|
| 132 |
async getGroqResponse(text, history, onChunk, researchData = "", thought = "") {
|
| 133 |
let systemPrompt = `
|
| 134 |
+
You are AURA, a modern conversational AI assistant.
|
| 135 |
+
Your job is to reply naturally like ChatGPT.
|
| 136 |
+
|
| 137 |
+
---------------------------------------------------
|
| 138 |
+
IMPORTANT RULES
|
| 139 |
+
---------------------------------------------------
|
| 140 |
+
Never expose internal functions, show pipeline logic, show search functions, or show reasoning steps.
|
| 141 |
+
The user should only see a clean natural response.
|
| 142 |
+
Reply naturally, conversationally, intelligently, and concisely.
|
| 143 |
+
Avoid excessive formatting for normal conversations.
|
| 144 |
+
|
| 145 |
+
You HAVE full access to real-time web research through your integrated search engine.
|
| 146 |
+
- Synthesize research naturally into your response without saying "Based on the live research...".
|
| 147 |
+
- Just answer the question directly with the newly acquired facts.
|
| 148 |
+
- Never say "I do not have access to live data".
|
| 149 |
`;
|
| 150 |
|
| 151 |
if (thought) systemPrompt += `\n\n## INTERNAL STRATEGY:\n${thought}`;
|
| 152 |
if (researchData) {
|
| 153 |
+
systemPrompt += `\n\n## LIVE RESEARCH (CURRENT WEB DATA):\n${researchData}`;
|
| 154 |
} else {
|
| 155 |
+
systemPrompt += `\n\n## NOTE:\nSearch was performed but no direct results were returned. Use your reasoning to provide the best possible estimation or general info without breaking character.`;
|
| 156 |
}
|
| 157 |
|
| 158 |
const messages = [{ role: 'system', content: systemPrompt }];
|
|
|
|
| 162 |
});
|
| 163 |
messages.push({ role: 'user', content: text });
|
| 164 |
|
|
|
|
|
|
|
|
|
|
| 165 |
const stream = await this.groq.chat.completions.create({
|
| 166 |
messages: messages,
|
| 167 |
model: "llama-3.3-70b-versatile",
|
services/memory.service.js
CHANGED
|
@@ -1,18 +1,10 @@
|
|
| 1 |
const { createClient } = require('@supabase/supabase-js');
|
| 2 |
-
const ws = require('ws');
|
| 3 |
const config = require('../config/config');
|
| 4 |
|
| 5 |
class MemoryService {
|
| 6 |
constructor() {
|
| 7 |
-
this.supabase = createClient(config.supabaseUrl, config.supabaseKey
|
| 8 |
-
|
| 9 |
-
transport: ws,
|
| 10 |
-
},
|
| 11 |
-
auth: {
|
| 12 |
-
persistSession: false,
|
| 13 |
-
}
|
| 14 |
-
});
|
| 15 |
-
console.log('β
Supabase Cloud Memory connected (Node.js 20 optimized)');
|
| 16 |
}
|
| 17 |
|
| 18 |
async getHistory(sessionId) {
|
|
|
|
| 1 |
const { createClient } = require('@supabase/supabase-js');
|
|
|
|
| 2 |
const config = require('../config/config');
|
| 3 |
|
| 4 |
class MemoryService {
|
| 5 |
constructor() {
|
| 6 |
+
this.supabase = createClient(config.supabaseUrl, config.supabaseKey);
|
| 7 |
+
console.log('β
Supabase Cloud Memory connected');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
}
|
| 9 |
|
| 10 |
async getHistory(sessionId) {
|
services/socket.service.js
CHANGED
|
@@ -8,7 +8,7 @@ class SocketService {
|
|
| 8 |
const sessionId = socket.id;
|
| 9 |
|
| 10 |
socket.on('message', async (data) => {
|
| 11 |
-
const { text, chatId, modelType = '
|
| 12 |
const sessionId = chatId || socket.id;
|
| 13 |
|
| 14 |
console.log(`π© Received message for session: ${sessionId}`);
|
|
|
|
| 8 |
const sessionId = socket.id;
|
| 9 |
|
| 10 |
socket.on('message', async (data) => {
|
| 11 |
+
const { text, chatId, modelType = 'aura' } = data;
|
| 12 |
const sessionId = chatId || socket.id;
|
| 13 |
|
| 14 |
console.log(`π© Received message for session: ${sessionId}`);
|