IA Assistant version initiale
This commit is contained in:
1 parent
3e8508d48b
commit
662003fdd3
29 files changed
+4253
-10
No files matched your search
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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: [...] }.");
|
||||
Reference in new issue
Block a user