89 lines
2.9 KiB
JavaScript
89 lines
2.9 KiB
JavaScript
|
|
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;
|