Spaces:
Sleeping
Sleeping
| import express from 'express'; | |
| import cors from 'cors'; | |
| import path from 'path'; | |
| import { fileURLToPath } from 'url'; | |
| import sqlite3 from 'sqlite3'; | |
| import bcrypt from 'bcryptjs'; | |
| const app = express(); | |
| const port = process.env.PORT || 7860; | |
| // --- Database Initialization --- | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const dbPath = path.join(__dirname, 'database.db'); | |
| const db = new sqlite3.Database(dbPath); | |
| db.serialize(() => { | |
| db.run(` | |
| CREATE TABLE IF NOT EXISTS users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| username TEXT UNIQUE NOT NULL, | |
| password_hash TEXT NOT NULL, | |
| role TEXT DEFAULT 'Standard Node', | |
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| `); | |
| db.run(` | |
| CREATE TABLE IF NOT EXISTS messages ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id INTEGER, | |
| role TEXT NOT NULL, | |
| content TEXT NOT NULL, | |
| timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY(user_id) REFERENCES users(id) | |
| ) | |
| `); | |
| }); | |
| let activeSession = null; | |
| // Mock Citi Data | |
| const CITI_ACCOUNTS = { | |
| accountGroupDetails: [{ | |
| accountGroup: "CHECKING", | |
| checkingAccountsDetails: [{ | |
| productName: "Corporate Mastery Checking", | |
| accountNickname: "Main Ops Node", | |
| accountDescription: "Corporate Mastery Checking - 9594", | |
| balanceType: "ASSET", | |
| displayAccountNumber: "XXXXXX9594", | |
| accountId: "citi_acc_99201", | |
| currencyCode: "USD", | |
| accountStatus: "ACTIVE", | |
| currentBalance: 1245000.50, | |
| availableBalance: 1240000.00 | |
| }], | |
| totalCurrentBalance: { localCurrencyCode: "USD", localCurrencyBalanceAmount: 1245000.50 }, | |
| totalAvailableBalance: { localCurrencyCode: "USD", localCurrencyBalanceAmount: 1240000.00 } | |
| }], | |
| customer: { customerId: "citi_cust_884102" } | |
| }; | |
| app.use(cors()); | |
| app.use(express.json()); | |
| app.use(express.urlencoded({ extended: true })); | |
| // Auth API | |
| app.get('/api/auth/me', (req, res) => res.json({ isAuthenticated: !!activeSession, user: activeSession })); | |
| app.post('/api/auth/login', (req, res) => { | |
| const { username, password } = req.body; | |
| db.get('SELECT * FROM users WHERE username = ?', [username], async (err, user) => { | |
| if (err || !user) return res.status(401).json({ success: false, message: 'Invalid node' }); | |
| const match = await bcrypt.compare(password, user.password_hash); | |
| if (match) { | |
| activeSession = { id: `USR-${user.id}`, dbId: user.id, name: user.username, role: user.role, lastLogin: new Date().toISOString() }; | |
| res.json({ success: true, user: activeSession }); | |
| } else { | |
| res.status(401).json({ success: false }); | |
| } | |
| }); | |
| }); | |
| app.post('/api/auth/logout', (req, res) => { activeSession = null; res.json({ success: true }); }); | |
| // Gemini REST Proxy (Exact Implementation as per user's curl requirement) | |
| app.post('/api/gemini/generate', async (req, res) => { | |
| try { | |
| // Hugging Face secrets are available via process.env | |
| const apiKey = process.env.GEMINI_API_KEY; | |
| if (!apiKey) { | |
| console.error("FATAL: GEMINI_API_KEY secret is not configured in Hugging Face Space."); | |
| return res.status(500).json({ error: 'GEMINI_API_KEY missing from environment secrets.' }); | |
| } | |
| const { contents } = req.body; | |
| // User requested specifically gemini-2.5-flash in the URL | |
| const targetUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent'; | |
| const proxyUrl = `https://corsproxy.io/?url=${encodeURIComponent(targetUrl)}`; | |
| const response = await fetch(proxyUrl, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'x-goog-api-key': apiKey | |
| }, | |
| body: JSON.stringify({ | |
| contents: contents | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (data.error) { | |
| console.error("Gemini API returned error:", data.error); | |
| return res.status(response.status || 500).json({ error: data.error.message || 'Upstream Error' }); | |
| } | |
| // Standardize text response for frontend consumption | |
| const text = data.candidates?.[0]?.content?.parts?.[0]?.text || ''; | |
| res.json({ text, candidates: data.candidates }); | |
| } catch (error) { | |
| console.error("Server proxy error:", error); | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| // Citi Proxy | |
| app.get('/api/accounts/account-transactions/partner/v1/accounts/details', (req, res) => res.json(CITI_ACCOUNTS)); | |
| // Serve Frontend | |
| const __dist = path.join(__dirname, 'dist'); | |
| app.use(express.static(__dist)); | |
| // SPA Fallback | |
| app.use((req, res) => { | |
| if (req.path.startsWith('/api')) return res.status(404).json({ error: 'Endpoint missing' }); | |
| res.sendFile(path.join(__dist, 'index.html')); | |
| }); | |
| app.listen(port, '0.0.0.0', () => console.log(`[Lumina Proxy] Node Online on Port ${port}`)); | |