Files

89 lines
2.9 KiB
JavaScript
Raw Permalink Normal View History

const express = require('express');
const router = express.Router();
const {
PROVIDER_PRESETS, getProviders, getProvider, saveProvider, deleteProvider,
maskKey, chatCompletion, syncAiConfigFile
} = require('../lib/ai');
const { logAudit } = require('../db');
router.get('/', (req, res) => {
const providers = getProviders().map(p => ({
...p,
api_key_masked: maskKey(getProvider(p.id)?.api_key)
}));
res.render('ai-providers', {
providers,
presets: PROVIDER_PRESETS,
saved: req.query.saved === '1',
tested: req.query.tested,
error: req.query.error || null
});
});
router.post('/save', (req, res) => {
const { id, name, provider_type, api_key, base_url, default_model, is_active, is_default } = req.body;
const preset = PROVIDER_PRESETS[provider_type] || PROVIDER_PRESETS.custom;
let key = api_key;
if (id && (!key || key.includes('••••'))) {
const existing = getProvider(id);
key = existing?.api_key || '';
}
saveProvider({
id: id ? parseInt(id, 10) : null,
name: name || preset.label,
provider_type: provider_type || 'openrouter',
api_key: key,
base_url: base_url || preset.base_url,
default_model: default_model || preset.models[0] || '',
is_active: is_active === '1',
is_default: is_default === '1'
});
logAudit(req.session.userId, req.session.username, 'ai_provider_saved', 'ai_provider', id || null, name);
res.redirect('/ai?saved=1');
});
router.post('/delete/:id', (req, res) => {
deleteProvider(req.params.id);
logAudit(req.session.userId, req.session.username, 'ai_provider_deleted', 'ai_provider', req.params.id, '');
res.redirect('/ai?saved=1');
});
router.post('/sync', (req, res) => {
syncAiConfigFile();
res.redirect('/ai?saved=1');
});
router.post('/test/:id', async (req, res) => {
try {
const result = await chatCompletion(
[{ role: 'user', content: 'Antwoord met exact: Mek-Tech AI verbinding OK' }],
{ providerId: parseInt(req.params.id, 10), max_tokens: 50 }
);
const text = result.choices?.[0]?.message?.content || 'OK';
res.redirect('/ai?tested=' + encodeURIComponent(text.slice(0, 80)));
} catch (e) {
res.redirect('/ai?error=' + encodeURIComponent(e.message));
}
});
router.post('/chat', async (req, res) => {
try {
const { messages, provider_id, model, client_id } = req.body;
const result = await chatCompletion(messages, {
providerId: provider_id ? parseInt(provider_id, 10) : null,
model
});
const content = result.choices?.[0]?.message?.content || '';
if (client_id) {
const { getDb } = require('../db');
getDb().prepare('INSERT INTO client_notes (client_id, content, created_by) VALUES (?, ?, ?)')
.run(client_id, `[AI] ${content.slice(0, 2000)}`, req.session.username || 'ai');
}
res.json({ success: true, content, model: result.model });
} catch (e) {
res.status(500).json({ success: false, error: e.message });
}
});
module.exports = router;