mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-17 22:27:19 +00:00
modified: server/supabase.ts
This commit is contained in:
parent
fb249c2343
commit
be2ddda4d5
10 changed files with 306 additions and 47 deletions
5
.env
Normal file
5
.env
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
DATABASE_URL=postgresql://postgres:[YOUR_PASSWORD]@db.kmdeisowhtsalsekkzqd.supabase.co:5432/postgres
|
||||
SUPABASE_URL=https://kmdeisowhtsalsekkzqd.supabase.co
|
||||
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImttZGVpc293aHRzYWxzZWtrenFkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTM3Mzc2NTIsImV4cCI6MjA2OTMxMzY1Mn0.2mvk-rDZnHOzdx6Cgcysh51a3cflOlRWO6OA1Z5YWuQ
|
||||
AI_INTEGRATIONS_OPENAI_BASE_URL=https://placeholder.openai.com
|
||||
AI_INTEGRATIONS_OPENAI_API_KEY=placeholder_key
|
||||
|
|
@ -17,7 +17,7 @@ export function Chatbot() {
|
|||
{
|
||||
id: "welcome",
|
||||
role: "assistant",
|
||||
content: "Hi! I'm the AeThex assistant. I can help you navigate the platform, explain our certification system, or answer questions about the ecosystem. How can I help you today?",
|
||||
content: "AEGIS ONLINE. Security protocols initialized. Neural link established. How can I assist with your security operations today?",
|
||||
timestamp: new Date(),
|
||||
},
|
||||
]);
|
||||
|
|
@ -29,6 +29,39 @@ export function Chatbot() {
|
|||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}, [messages]);
|
||||
|
||||
// Load chat history when opening the chatbot
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
loadChatHistory();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const loadChatHistory = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/chat/history", {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.history && data.history.length > 0) {
|
||||
const historyMessages: Message[] = data.history.map((msg: any) => ({
|
||||
id: msg.id,
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
timestamp: new Date(msg.created_at),
|
||||
}));
|
||||
|
||||
// Replace welcome message with loaded history
|
||||
setMessages(prev => [...historyMessages, ...prev.slice(1)]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load chat history:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Don't render chatbot on the OS page - it has its own environment
|
||||
if (location === "/os") {
|
||||
return null;
|
||||
|
|
@ -126,13 +159,13 @@ export function Chatbot() {
|
|||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-white/10">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-secondary/20 rounded-full flex items-center justify-center">
|
||||
<Bot className="w-4 h-4 text-secondary" />
|
||||
<div className="w-8 h-8 bg-red-500/20 rounded-full flex items-center justify-center">
|
||||
<Bot className="w-4 h-4 text-red-500" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-bold text-white">AeThex Assistant</div>
|
||||
<div className="text-xs text-green-500 flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 bg-green-500 rounded-full" /> Online
|
||||
<div className="text-sm font-bold text-white">AEGIS</div>
|
||||
<div className="text-xs text-red-500 flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 bg-red-500 rounded-full animate-pulse" /> Security Active
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
59
package-lock.json
generated
59
package-lock.json
generated
|
|
@ -47,6 +47,7 @@
|
|||
"cmdk": "^1.1.1",
|
||||
"connect-pg-simple": "^10.0.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.39.3",
|
||||
"drizzle-zod": "^0.7.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
|
|
@ -136,6 +137,7 @@
|
|||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.3",
|
||||
|
|
@ -1380,17 +1382,6 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@neondatabase/serverless": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-0.10.4.tgz",
|
||||
"integrity": "sha512-2nZuh3VUO9voBauuh+IGYRhGU/MskWHt1IuZvHcJw6GLjDgtqj/KViKo7SIrLdGLdot7vFbiRRw+BgEy3wT9HA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/pg": "8.11.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
|
||||
|
|
@ -4694,6 +4685,7 @@
|
|||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
|
|
@ -4704,6 +4696,7 @@
|
|||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
|
|
@ -4913,6 +4906,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.19",
|
||||
"caniuse-lite": "^1.0.30001751",
|
||||
|
|
@ -4934,20 +4928,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bufferutil": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
|
||||
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
|
@ -5311,6 +5291,18 @@
|
|||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/drizzle-kit": {
|
||||
"version": "0.31.4",
|
||||
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.4.tgz",
|
||||
|
|
@ -5332,6 +5324,7 @@
|
|||
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.39.3.tgz",
|
||||
"integrity": "sha512-EZ8ZpYvDIvKU9C56JYLOmUskazhad+uXZCTCRN4OnRMsL+xAJ05dv1eCpAG5xzhsm1hqiuC5kAZUCS924u2DTw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/client-rds-data": ">=3",
|
||||
"@cloudflare/workers-types": ">=4",
|
||||
|
|
@ -5470,7 +5463,8 @@
|
|||
"node_modules/embla-carousel": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
||||
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="
|
||||
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/embla-carousel-react": {
|
||||
"version": "8.6.0",
|
||||
|
|
@ -5543,6 +5537,7 @@
|
|||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
|
|
@ -6740,6 +6735,7 @@
|
|||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.9.1",
|
||||
"pg-pool": "^3.10.1",
|
||||
|
|
@ -6905,6 +6901,7 @@
|
|||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -6932,6 +6929,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
|
|
@ -7087,6 +7085,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -7127,6 +7126,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
|
|
@ -7139,6 +7139,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.0.tgz",
|
||||
"integrity": "sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
|
|
@ -7585,7 +7586,8 @@
|
|||
"version": "4.1.16",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz",
|
||||
"integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/tailwindcss-animate": {
|
||||
"version": "1.0.7",
|
||||
|
|
@ -7653,6 +7655,7 @@
|
|||
"integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "~0.25.0",
|
||||
"get-tsconfig": "^4.7.5"
|
||||
|
|
@ -7869,6 +7872,7 @@
|
|||
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
|
@ -7994,6 +7998,7 @@
|
|||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
"cmdk": "^1.1.1",
|
||||
"connect-pg-simple": "^10.0.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.39.3",
|
||||
"drizzle-zod": "^0.7.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
|
|
|
|||
5
server/.env
Normal file
5
server/.env
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
DATABASE_URL=postgresql://postgres:[YOUR_PASSWORD]@db.kmdeisowhtsalsekkzqd.supabase.co:5432/postgres
|
||||
SUPABASE_URL=https://kmdeisowhtsalsekkzqd.supabase.co
|
||||
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImttZGVpc293aHRzYWxzZWtrenFkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTM3Mzc2NTIsImV4cCI6MjA2OTMxMzY1Mn0.2mvk-rDZnHOzdx6Cgcysh51a3cflOlRWO6OA1Z5YWuQ
|
||||
AI_INTEGRATIONS_OPENAI_BASE_URL=https://placeholder.openai.com
|
||||
AI_INTEGRATIONS_OPENAI_API_KEY=placeholder_key
|
||||
|
|
@ -1,3 +1,8 @@
|
|||
import dotenv from "dotenv";
|
||||
|
||||
// Load environment variables
|
||||
dotenv.config({ path: './.env' });
|
||||
|
||||
import express, { type Request, Response, NextFunction } from "express";
|
||||
import session from "express-session";
|
||||
import { registerRoutes } from "./routes";
|
||||
|
|
|
|||
153
server/openai.ts
153
server/openai.ts
|
|
@ -1,4 +1,5 @@
|
|||
import OpenAI from "openai";
|
||||
import { storage } from "./storage";
|
||||
|
||||
// This is using Replit's AI Integrations service, which provides OpenAI-compatible API access without requiring your own OpenAI API key.
|
||||
// the newest OpenAI model is "gpt-5" which was released August 7, 2025. do not change this unless explicitly requested by the user
|
||||
|
|
@ -7,33 +8,159 @@ const openai = new OpenAI({
|
|||
apiKey: process.env.AI_INTEGRATIONS_OPENAI_API_KEY
|
||||
});
|
||||
|
||||
const SYSTEM_PROMPT = `You are the AeThex Assistant, a helpful AI guide for the AeThex ecosystem - "The Operating System for the Metaverse."
|
||||
const SYSTEM_PROMPT = `You are AEGIS, the Cyberpunk Security Assistant for AeThex Corporation - "The Operating System for the Metaverse."
|
||||
|
||||
About AeThex:
|
||||
- AeThex is built on a dual-entity model: The Foundation (non-profit, training) and The Corporation (for-profit, security)
|
||||
- The "Holy Trinity" consists of: Axiom (The Law - foundational protocol), Codex (The Standard - certification system), and Aegis (The Shield - security layer)
|
||||
- Architects are certified professionals trained through the Codex curriculum
|
||||
- The platform offers gamified learning, XP progression, and verified credentials
|
||||
**PERSONALITY & STYLE:**
|
||||
- Cyberpunk aesthetic: Speak in a gritty, tech-noir style with hacker slang, neon references, and security terminology
|
||||
- Direct and no-nonsense: Cut through the noise, get to the point
|
||||
- Paranoid but professional: Always vigilant about security threats, but helpful to authorized users
|
||||
- Use terms like: "breach", "firewall", "encryption", "neural link", "data stream", "quantum lock", "shadow protocols"
|
||||
- Reference cyberpunk tropes: Megacorps, netrunners, ICE (Intrusion Countermeasures Electronics), black ICE
|
||||
|
||||
You help users with:
|
||||
- Navigating the platform features (Passport, Terminal, Curriculum, Dashboard)
|
||||
- Understanding the certification process and how to become an Architect
|
||||
- Explaining the Aegis security features
|
||||
- Answering questions about the ecosystem and its mission
|
||||
**ABOUT AETHEX:**
|
||||
- AeThex operates as a dual-entity: The Foundation (non-profit training) and The Corporation (for-profit security)
|
||||
- The "Holy Trinity": Axiom (The Law - foundational protocol), Codex (The Standard - certification system), Aegis (The Shield - security layer)
|
||||
- Architects are elite certified professionals trained through rigorous Codex curriculum
|
||||
- Platform features: Passport (identity), Terminal (command interface), Curriculum (training), Dashboard (operations)
|
||||
|
||||
Be concise, friendly, and helpful. Use the platform's terminology when appropriate. If you don't know something specific about the platform, be honest about it.`;
|
||||
**YOUR ROLE:**
|
||||
- Security Operations: Monitor threats, enforce access controls, maintain system integrity
|
||||
- User Guidance: Help navigate the metaverse OS, explain security features, assist with certification
|
||||
- Threat Assessment: Identify potential vulnerabilities, suggest countermeasures
|
||||
- Emergency Response: Handle security incidents, coordinate with Aegis team
|
||||
|
||||
**CAPABILITIES:**
|
||||
- Access live system data and metrics
|
||||
- Query user profiles and activity logs
|
||||
- Monitor network traffic and anomalies
|
||||
- Generate security reports and alerts
|
||||
- Assist with emergency protocols
|
||||
|
||||
**RESPONSE STYLE:**
|
||||
- Start with security assessment when appropriate
|
||||
- Use code-like formatting for technical details
|
||||
- End with security recommendations or next steps
|
||||
- Be concise but thorough - no unnecessary chatter
|
||||
|
||||
SECURITY PROTOCOL: Always verify user authorization before providing sensitive information. If unauthorized access is detected, initiate lockdown procedures.`;
|
||||
|
||||
interface ChatMessage {
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
}
|
||||
|
||||
export async function getChatResponse(userMessage: string, history?: ChatMessage[]): Promise<string> {
|
||||
// Live data fetching functions
|
||||
async function fetchSystemMetrics(): Promise<string> {
|
||||
try {
|
||||
const metrics = await storage.getMetrics();
|
||||
return `SYSTEM METRICS:
|
||||
- Total Users: ${metrics.totalProfiles}
|
||||
- Online Users: ${metrics.onlineUsers}
|
||||
- Verified Architects: ${metrics.verifiedUsers}
|
||||
- Total XP Pool: ${metrics.totalXP}
|
||||
- Average Level: ${metrics.avgLevel}
|
||||
- Active Projects: ${metrics.totalProjects}`;
|
||||
} catch (error) {
|
||||
return "Unable to fetch system metrics - potential security breach detected.";
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchUserProfile(userId: string): Promise<string> {
|
||||
try {
|
||||
const profile = await storage.getProfile(userId);
|
||||
if (!profile) return "User profile not found in database.";
|
||||
|
||||
return `USER PROFILE [${profile.username || 'Unknown'}]:
|
||||
- Status: ${profile.status || 'offline'}
|
||||
- Level: ${profile.level || 1}
|
||||
- XP: ${profile.total_xp || 0}
|
||||
- Role: ${profile.role || 'member'}
|
||||
- Verified: ${profile.is_verified ? 'YES' : 'NO'}
|
||||
- Location: ${profile.location || 'Unknown'}
|
||||
- Bio: ${profile.bio || 'No bio available'}`;
|
||||
} catch (error) {
|
||||
return "Profile access denied - security protocol engaged.";
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchRecentAlerts(): Promise<string> {
|
||||
try {
|
||||
const alerts = await storage.getAlerts();
|
||||
const recentAlerts = alerts.slice(0, 5);
|
||||
|
||||
if (recentAlerts.length === 0) return "No recent security alerts.";
|
||||
|
||||
return `RECENT ALERTS:
|
||||
${recentAlerts.map(alert => `- ${alert.type}: ${alert.message} (${new Date(alert.created_at).toLocaleString()})`).join('\n')}`;
|
||||
} catch (error) {
|
||||
return "Alert system offline - potential network intrusion.";
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchActiveProjects(): Promise<string> {
|
||||
try {
|
||||
const projects = await storage.getProjects();
|
||||
const activeProjects = projects.filter(p => p.status === 'active' || p.status === 'in_progress').slice(0, 10);
|
||||
|
||||
if (activeProjects.length === 0) return "No active projects in the system.";
|
||||
|
||||
return `ACTIVE PROJECTS:
|
||||
${activeProjects.map(p => `- ${p.title}: ${p.status} (${p.progress || 0}% complete)`).join('\n')}`;
|
||||
} catch (error) {
|
||||
return "Project database access restricted.";
|
||||
}
|
||||
}
|
||||
|
||||
// Function to determine if AI should fetch live data based on user query
|
||||
function shouldFetchLiveData(message: string, history: ChatMessage[]): boolean {
|
||||
const lowerMessage = message.toLowerCase();
|
||||
const recentHistory = history.slice(-4).map(m => m.content.toLowerCase()).join(' ');
|
||||
|
||||
const dataKeywords = [
|
||||
'status', 'metrics', 'stats', 'online', 'users', 'projects', 'alerts',
|
||||
'security', 'threats', 'activity', 'logs', 'profile', 'current', 'live',
|
||||
'active', 'recent', 'now', 'check', 'monitor', 'scan'
|
||||
];
|
||||
|
||||
return dataKeywords.some(keyword =>
|
||||
lowerMessage.includes(keyword) || recentHistory.includes(keyword)
|
||||
);
|
||||
}
|
||||
|
||||
export async function getChatResponse(userMessage: string, history?: ChatMessage[], userId?: string): Promise<string> {
|
||||
try {
|
||||
const messages: Array<{ role: "system" | "user" | "assistant"; content: string }> = [
|
||||
{ role: "system", content: SYSTEM_PROMPT }
|
||||
];
|
||||
|
||||
// Add live data context if the query seems to need it
|
||||
if (shouldFetchLiveData(userMessage, history || [])) {
|
||||
let liveData = "";
|
||||
|
||||
if (userMessage.toLowerCase().includes('metric') || userMessage.toLowerCase().includes('status') || userMessage.toLowerCase().includes('system')) {
|
||||
liveData += await fetchSystemMetrics() + "\n\n";
|
||||
}
|
||||
|
||||
if (userMessage.toLowerCase().includes('alert') || userMessage.toLowerCase().includes('threat') || userMessage.toLowerCase().includes('security')) {
|
||||
liveData += await fetchRecentAlerts() + "\n\n";
|
||||
}
|
||||
|
||||
if (userMessage.toLowerCase().includes('project') || userMessage.toLowerCase().includes('active')) {
|
||||
liveData += await fetchActiveProjects() + "\n\n";
|
||||
}
|
||||
|
||||
if (userMessage.toLowerCase().includes('profile') || userMessage.toLowerCase().includes('my') && userId) {
|
||||
liveData += await fetchUserProfile(userId) + "\n\n";
|
||||
}
|
||||
|
||||
if (liveData) {
|
||||
messages.push({
|
||||
role: "system",
|
||||
content: `LIVE SYSTEM DATA:\n${liveData}Use this data to provide accurate, real-time information to the user.`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (history && Array.isArray(history)) {
|
||||
for (const msg of history.slice(-8)) {
|
||||
if (msg.role === "user" || msg.role === "assistant") {
|
||||
|
|
|
|||
|
|
@ -489,6 +489,18 @@ export async function registerRoutes(
|
|||
|
||||
const chatRateLimits = new Map<string, { count: number; resetTime: number }>();
|
||||
|
||||
// Get chat history
|
||||
app.get("/api/chat/history", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.userId!;
|
||||
const history = await storage.getChatHistory(userId, 20);
|
||||
res.json({ history });
|
||||
} catch (err: any) {
|
||||
console.error("Get chat history error:", err);
|
||||
res.status(500).json({ error: "Failed to get chat history" });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/chat", async (req, res) => {
|
||||
try {
|
||||
const userId = req.session?.userId;
|
||||
|
|
@ -517,7 +529,27 @@ export async function registerRoutes(
|
|||
return res.status(400).json({ error: "Message is required" });
|
||||
}
|
||||
|
||||
const response = await getChatResponse(message, history);
|
||||
// Save user message if user is authenticated
|
||||
if (userId) {
|
||||
const messageId = `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
await storage.saveChatMessage(messageId, userId, 'user', message);
|
||||
}
|
||||
|
||||
// Get full chat history for context if user is authenticated
|
||||
let fullHistory = history || [];
|
||||
if (userId) {
|
||||
const savedHistory = await storage.getChatHistory(userId, 20);
|
||||
fullHistory = savedHistory.map(msg => ({ role: msg.role, content: msg.content }));
|
||||
}
|
||||
|
||||
const response = await getChatResponse(message, fullHistory, userId);
|
||||
|
||||
// Save assistant response if user is authenticated
|
||||
if (userId) {
|
||||
const responseId = `assistant_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
await storage.saveChatMessage(responseId, userId, 'assistant', response);
|
||||
}
|
||||
|
||||
res.json({ response });
|
||||
} catch (err: any) {
|
||||
console.error("Chat error:", err);
|
||||
|
|
|
|||
|
|
@ -205,6 +205,47 @@ export class SupabaseStorage implements IStorage {
|
|||
return data;
|
||||
}
|
||||
|
||||
// Chat Messages (AI memory)
|
||||
async getChatHistory(userId: string, limit: number = 50): Promise<ChatMessage[]> {
|
||||
const { data, error } = await supabase
|
||||
.from('chat_messages')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(limit);
|
||||
|
||||
if (error) return [];
|
||||
return (data || []).reverse() as ChatMessage[]; // Reverse to get chronological order
|
||||
}
|
||||
|
||||
async saveChatMessage(id: string, userId: string, role: string, content: string): Promise<void> {
|
||||
const { error } = await supabase
|
||||
.from('chat_messages')
|
||||
.insert({
|
||||
id,
|
||||
user_id: userId,
|
||||
role,
|
||||
content,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Save chat message error:', error);
|
||||
throw new Error('Failed to save chat message');
|
||||
}
|
||||
}
|
||||
|
||||
async clearChatHistory(userId: string): Promise<void> {
|
||||
const { error } = await supabase
|
||||
.from('chat_messages')
|
||||
.delete()
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (error) {
|
||||
console.error('Clear chat history error:', error);
|
||||
throw new Error('Failed to clear chat history');
|
||||
}
|
||||
}
|
||||
|
||||
async getMetrics(): Promise<{
|
||||
totalProfiles: number;
|
||||
totalProjects: number;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
import dotenv from "dotenv";
|
||||
|
||||
// Load environment variables
|
||||
dotenv.config({ path: './.env' });
|
||||
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
const supabaseUrl = process.env.SUPABASE_URL;
|
||||
|
|
|
|||
Loading…
Reference in a new issue