Files

114 lines
4.1 KiB
JavaScript

/**
* ai-seed-provider.js — Configure un fournisseur IA en ligne de commande, en
* attendant le back-office admin (Task future : CRUD ai_providers dans
* Admin.jsx). Usage (depuis le dossier backend/) :
*
* node scripts/ai-seed-provider.js --email vous@exemple.fr --type anthropic \
* --model claude-sonnet-4-5 --key sk-ant-xxxxx [--nom "Anthropic (test)"]
*
* Effets :
* - crée/met à jour un fournisseur ai_providers (nom sert de clé d'upsert),
* le marque is_default=1 (et retire ce flag des autres fournisseurs)
* - active ai_config.actif (interrupteur global) — sauf --no-activate
* - active users.ai_enabled pour l'email donné — sauf --no-user-enable
*
* Nécessite AI_ENC_KEY dans .env (voir .env.example) — sinon échoue avec un
* message explicite (chiffrement de la clé API du fournisseur).
*/
import 'dotenv/config';
import db from '../src/db/index.js';
import { encryptSecret } from '../src/ai/crypto.js';
function parseArgs(argv) {
const args = {};
for (let i = 0; i < argv.length; i++) {
if (argv[i].startsWith('--')) {
const key = argv[i].slice(2);
const next = argv[i + 1];
if (next === undefined || next.startsWith('--')) {
args[key] = true; // flag booléen (ex. --no-activate)
} else {
args[key] = next;
i++;
}
}
}
return args;
}
const args = parseArgs(process.argv.slice(2));
const email = args.email;
const key = args.key;
const model = args.model;
const type = args.type || 'anthropic';
const nom = args.nom || (type === 'anthropic' ? 'Anthropic' : `${type} (via seed)`);
const baseUrl = args['base-url'] || null;
const activate = !args['no-activate'];
const enableUser = !args['no-user-enable'];
function fail(msg) {
console.error(`✗ ${msg}`);
process.exit(1);
}
if (!email) fail('--email requis (email du compte utilisateur à autoriser)');
if (!key) fail('--key requis (clé API du fournisseur, en clair — sera chiffrée avant stockage)');
if (!model) fail("--model requis (ex. claude-sonnet-4-5 pour l'adaptateur anthropic)");
if (!['anthropic', 'openai_compatible'].includes(type)) {
fail(`--type invalide (${type}) — attendu "anthropic" ou "openai_compatible"`);
}
if (type === 'openai_compatible' && !baseUrl) {
fail('--base-url requis pour --type openai_compatible (ex. https://openrouter.ai/api/v1)');
}
const user = db.prepare('SELECT id, email FROM users WHERE email = ?').get(email);
if (!user) fail(`Aucun utilisateur avec l'email "${email}"`);
let apiKeyChiffree;
try {
apiKeyChiffree = encryptSecret(key);
} catch (e) {
fail(e.message);
}
const tx = db.transaction(() => {
db.exec('UPDATE ai_providers SET is_default = 0');
const existing = db.prepare('SELECT id FROM ai_providers WHERE nom = ?').get(nom);
let providerId;
if (existing) {
db.prepare(`
UPDATE ai_providers
SET type = ?, base_url = ?, modele = ?, api_key_chiffree = ?, actif = 1, is_default = 1, updated_at = datetime('now')
WHERE id = ?
`).run(type, baseUrl, model, apiKeyChiffree, existing.id);
providerId = existing.id;
console.log(`✓ Fournisseur "${nom}" mis à jour (id=${providerId})`);
} else {
const info = db.prepare(`
INSERT INTO ai_providers (nom, type, base_url, modele, api_key_chiffree, actif, is_default)
VALUES (?, ?, ?, ?, ?, 1, 1)
`).run(nom, type, baseUrl, model, apiKeyChiffree);
providerId = info.lastInsertRowid;
console.log(`✓ Fournisseur "${nom}" créé (id=${providerId})`);
}
if (activate) {
db.prepare(`
UPDATE ai_config SET actif = 1, provider_defaut_id = ?, updated_at = datetime('now') WHERE id = 1
`).run(providerId);
console.log('✓ Interrupteur global IA activé (ai_config.actif = 1)');
}
if (enableUser) {
db.prepare('UPDATE users SET ai_enabled = 1 WHERE id = ?').run(user.id);
console.log(`✓ Accès IA activé pour ${user.email}`);
}
});
tx();
console.log('\nPrêt à tester : GET /api/ai/status devrait répondre { enabled: true } pour cet utilisateur,');
console.log("puis POST /api/ai/chat avec un en-tête X-Investisseur-Id valide et un body { messages: [...] }.");