🔑 Feat: Gestion interactive des clés API avec stockage sécurisé
Nouvelles fonctionnalités: - Demande interactive des clés API au premier lancement - Commandes pour gérer les clés: key set/remove, setup, keys - Stockage sécurisé des clés dans ~/.neuraterm/keys.json - Support variables d'environnement et rechargement à chaud - Gestion intelligente du provider par défaut selon les clés disponibles Commandes ajoutées: - `keys` - Afficher le statut des clés API - `key set <provider>` - Configurer une clé (openai/mistral) - `key remove <provider>` - Supprimer une clé - `setup` - Configuration interactive complète Plus besoin de configurer manuellement les clés avant le lancement! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0b9bab45a8
commit
b8369b89e6
@ -2,7 +2,8 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(git add:*)"
|
||||
"Bash(git add:*)",
|
||||
"Bash(git reset:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1 +1,5 @@
|
||||
.divers
|
||||
.divers
|
||||
node_modules/
|
||||
dist/
|
||||
*.log
|
||||
.env
|
53
README.md
53
README.md
@ -28,26 +28,50 @@ npm start
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Variables d'environnement
|
||||
### 🚀 Configuration automatique (recommandée)
|
||||
|
||||
Au premier lancement, NeuraTerm vous demandera vos clés API de manière interactive :
|
||||
|
||||
```bash
|
||||
neuraterm
|
||||
# Suivez les instructions pour configurer vos clés API
|
||||
```
|
||||
|
||||
### 🔑 Gestion des clés API
|
||||
|
||||
```bash
|
||||
# Afficher le statut des clés
|
||||
keys
|
||||
|
||||
# Configurer une nouvelle clé
|
||||
key set openai
|
||||
key set mistral
|
||||
|
||||
# Supprimer une clé
|
||||
key remove openai
|
||||
|
||||
# Reconfiguration complète
|
||||
setup
|
||||
```
|
||||
|
||||
### Variables d'environnement (optionnel)
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="votre_clé_openai"
|
||||
export MISTRAL_API_KEY="votre_clé_mistral"
|
||||
```
|
||||
|
||||
### Fichier de configuration
|
||||
### Fichier de configuration avancée
|
||||
|
||||
Créez `~/.neuraterm/config.json` :
|
||||
Créez `~/.neuraterm/config.json` pour une configuration avancée :
|
||||
|
||||
```json
|
||||
{
|
||||
"ai": {
|
||||
"openai": {
|
||||
"apiKey": "votre_clé_openai",
|
||||
"model": "gpt-4o-mini"
|
||||
},
|
||||
"mistral": {
|
||||
"apiKey": "votre_clé_mistral",
|
||||
"model": "mistral-large-latest"
|
||||
},
|
||||
"defaultProvider": "openai"
|
||||
@ -61,6 +85,8 @@ Créez `~/.neuraterm/config.json` :
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: Les clés API sont stockées séparément dans `~/.neuraterm/keys.json` pour plus de sécurité.
|
||||
|
||||
## 🎯 Utilisation
|
||||
|
||||
### Commandes de base
|
||||
@ -72,20 +98,27 @@ neuraterm
|
||||
# Aide
|
||||
help
|
||||
|
||||
# Gestion des clés API
|
||||
keys # Statut des clés
|
||||
key set openai # Configurer OpenAI
|
||||
key set mistral # Configurer Mistral
|
||||
setup # Configuration interactive
|
||||
|
||||
# Poser une question à l'IA
|
||||
Comment optimiser mon code Python ?
|
||||
|
||||
# Changer de provider
|
||||
provider mistral
|
||||
provider openai
|
||||
|
||||
# Voir les statistiques
|
||||
stats
|
||||
stats openai
|
||||
cost
|
||||
stats # Toutes les stats
|
||||
stats openai # Stats OpenAI uniquement
|
||||
cost # Coût total
|
||||
|
||||
# Configuration
|
||||
config
|
||||
providers
|
||||
config # Voir la configuration
|
||||
providers # Lister les providers
|
||||
```
|
||||
|
||||
### Exemples d'usage professionnel
|
||||
|
6974
package-lock.json
generated
Normal file
6974
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,20 +6,28 @@ import { AIClient } from './client.js';
|
||||
import { ProviderConfig } from './types.js';
|
||||
|
||||
export async function initAI(config: any, auth: any): Promise<AIClient> {
|
||||
const keyManager = auth.getKeyManager();
|
||||
const keys = keyManager.loadKeys();
|
||||
|
||||
const providerConfig: ProviderConfig = {
|
||||
openai: {
|
||||
apiKey: config.ai.openai?.apiKey || process.env.OPENAI_API_KEY || '',
|
||||
apiKey: keys.openai || '',
|
||||
model: config.ai.openai?.model || 'gpt-4o-mini',
|
||||
baseUrl: config.ai.openai?.baseUrl
|
||||
},
|
||||
mistral: {
|
||||
apiKey: config.ai.mistral?.apiKey || process.env.MISTRAL_API_KEY || '',
|
||||
apiKey: keys.mistral || '',
|
||||
model: config.ai.mistral?.model || 'mistral-large-latest',
|
||||
baseUrl: config.ai.mistral?.baseUrl
|
||||
},
|
||||
defaultProvider: config.ai.defaultProvider || 'openai'
|
||||
defaultProvider: keys.openai ? 'openai' : 'mistral'
|
||||
};
|
||||
|
||||
// Ajuster le provider par défaut selon les clés disponibles
|
||||
if (config.ai.defaultProvider && keys[config.ai.defaultProvider as keyof typeof keys]) {
|
||||
providerConfig.defaultProvider = config.ai.defaultProvider;
|
||||
}
|
||||
|
||||
return new AIClient(providerConfig);
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,40 @@
|
||||
/**
|
||||
* Gestion de l'authentification
|
||||
* Gestion de l'authentification et des clés API
|
||||
*/
|
||||
|
||||
import { KeyManager } from './keyManager.js';
|
||||
|
||||
export class AuthManager {
|
||||
constructor(private config: any) {}
|
||||
private keyManager: KeyManager;
|
||||
|
||||
constructor(private config: any) {
|
||||
this.keyManager = new KeyManager();
|
||||
}
|
||||
|
||||
isAuthenticated(): boolean {
|
||||
return true;
|
||||
return this.keyManager.hasValidKeys();
|
||||
}
|
||||
|
||||
async authenticate(): Promise<void> {
|
||||
return;
|
||||
if (!this.keyManager.hasValidKeys()) {
|
||||
await this.keyManager.promptForMissingKeys();
|
||||
}
|
||||
}
|
||||
|
||||
getKeyManager(): KeyManager {
|
||||
return this.keyManager;
|
||||
}
|
||||
}
|
||||
|
||||
export async function initAuthentication(config: any): Promise<AuthManager> {
|
||||
return new AuthManager(config);
|
||||
}
|
||||
const authManager = new AuthManager(config);
|
||||
|
||||
// Vérifier les clés au démarrage
|
||||
if (!authManager.isAuthenticated()) {
|
||||
await authManager.authenticate();
|
||||
}
|
||||
|
||||
return authManager;
|
||||
}
|
||||
|
||||
export { KeyManager } from './keyManager.js';
|
264
src/auth/keyManager.ts
Normal file
264
src/auth/keyManager.ts
Normal file
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Gestionnaire des clés API avec stockage sécurisé
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
||||
import { homedir } from 'os';
|
||||
import { join, dirname } from 'path';
|
||||
import * as readline from 'readline';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export interface APIKeys {
|
||||
openai?: string;
|
||||
mistral?: string;
|
||||
}
|
||||
|
||||
export class KeyManager {
|
||||
private configPath: string;
|
||||
private keysPath: string;
|
||||
|
||||
constructor() {
|
||||
const configDir = join(homedir(), '.neuraterm');
|
||||
this.configPath = join(configDir, 'config.json');
|
||||
this.keysPath = join(configDir, 'keys.json');
|
||||
|
||||
// Créer le dossier de configuration s'il n'existe pas
|
||||
if (!existsSync(configDir)) {
|
||||
mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les clés API depuis le fichier de configuration
|
||||
*/
|
||||
loadKeys(): APIKeys {
|
||||
const keys: APIKeys = {};
|
||||
|
||||
// Priorité 1: Variables d'environnement
|
||||
if (process.env.OPENAI_API_KEY) {
|
||||
keys.openai = process.env.OPENAI_API_KEY;
|
||||
}
|
||||
|
||||
if (process.env.MISTRAL_API_KEY) {
|
||||
keys.mistral = process.env.MISTRAL_API_KEY;
|
||||
}
|
||||
|
||||
// Priorité 2: Fichier de clés
|
||||
if (existsSync(this.keysPath)) {
|
||||
try {
|
||||
const fileKeys = JSON.parse(readFileSync(this.keysPath, 'utf8'));
|
||||
if (!keys.openai && fileKeys.openai) {
|
||||
keys.openai = fileKeys.openai;
|
||||
}
|
||||
if (!keys.mistral && fileKeys.mistral) {
|
||||
keys.mistral = fileKeys.mistral;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn('Erreur lors du chargement des clés:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde les clés API dans le fichier de configuration
|
||||
*/
|
||||
saveKeys(keys: APIKeys): void {
|
||||
try {
|
||||
// Ne sauvegarder que les clés non définies en variable d'environnement
|
||||
const keysToSave: APIKeys = {};
|
||||
|
||||
if (keys.openai && !process.env.OPENAI_API_KEY) {
|
||||
keysToSave.openai = keys.openai;
|
||||
}
|
||||
|
||||
if (keys.mistral && !process.env.MISTRAL_API_KEY) {
|
||||
keysToSave.mistral = keys.mistral;
|
||||
}
|
||||
|
||||
writeFileSync(this.keysPath, JSON.stringify(keysToSave, null, 2));
|
||||
logger.info('Clés API sauvegardées avec succès');
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la sauvegarde des clés:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si au moins une clé API est disponible
|
||||
*/
|
||||
hasValidKeys(): boolean {
|
||||
const keys = this.loadKeys();
|
||||
return !!(keys.openai || keys.mistral);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demande interactivement les clés API manquantes
|
||||
*/
|
||||
async promptForMissingKeys(): Promise<APIKeys> {
|
||||
const keys = this.loadKeys();
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
const question = (prompt: string): Promise<string> => {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(prompt, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('\n🔑 Configuration des clés API');
|
||||
console.log('─'.repeat(40));
|
||||
|
||||
if (!keys.openai) {
|
||||
console.log('\nOpenAI (ChatGPT) non configuré.');
|
||||
const wantOpenAI = await question('Voulez-vous configurer OpenAI ? (o/n): ');
|
||||
|
||||
if (wantOpenAI.toLowerCase() === 'o' || wantOpenAI.toLowerCase() === 'oui') {
|
||||
const openaiKey = await question('Entrez votre clé API OpenAI: ');
|
||||
if (openaiKey.trim()) {
|
||||
keys.openai = openaiKey.trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('✅ OpenAI configuré');
|
||||
}
|
||||
|
||||
if (!keys.mistral) {
|
||||
console.log('\nMistral AI non configuré.');
|
||||
const wantMistral = await question('Voulez-vous configurer Mistral AI ? (o/n): ');
|
||||
|
||||
if (wantMistral.toLowerCase() === 'o' || wantMistral.toLowerCase() === 'oui') {
|
||||
const mistralKey = await question('Entrez votre clé API Mistral: ');
|
||||
if (mistralKey.trim()) {
|
||||
keys.mistral = mistralKey.trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('✅ Mistral AI configuré');
|
||||
}
|
||||
|
||||
// Vérifier qu'au moins une clé est disponible
|
||||
if (!keys.openai && !keys.mistral) {
|
||||
console.log('\n❌ Erreur: Au moins une clé API est requise pour utiliser NeuraTerm.');
|
||||
console.log('Vous pouvez aussi définir les variables d\'environnement:');
|
||||
console.log(' export OPENAI_API_KEY="votre_clé"');
|
||||
console.log(' export MISTRAL_API_KEY="votre_clé"');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Sauvegarder les nouvelles clés
|
||||
this.saveKeys(keys);
|
||||
|
||||
console.log('\n✅ Configuration terminée !');
|
||||
|
||||
return keys;
|
||||
} finally {
|
||||
rl.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour une clé API spécifique
|
||||
*/
|
||||
async updateKey(provider: 'openai' | 'mistral'): Promise<void> {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
const question = (prompt: string): Promise<string> => {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(prompt, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
console.log(`\n🔑 Mise à jour de la clé ${provider.toUpperCase()}`);
|
||||
|
||||
if (process.env[`${provider.toUpperCase()}_API_KEY`]) {
|
||||
console.log(`⚠️ Attention: La clé ${provider.toUpperCase()} est définie en variable d'environnement.`);
|
||||
console.log('Cette modification ne sera effective que pour cette session.');
|
||||
}
|
||||
|
||||
const newKey = await question(`Entrez la nouvelle clé API ${provider}: `);
|
||||
|
||||
if (!newKey.trim()) {
|
||||
console.log('❌ Clé vide, annulation.');
|
||||
return;
|
||||
}
|
||||
|
||||
const keys = this.loadKeys();
|
||||
keys[provider] = newKey.trim();
|
||||
this.saveKeys(keys);
|
||||
|
||||
console.log(`✅ Clé ${provider.toUpperCase()} mise à jour avec succès !`);
|
||||
} finally {
|
||||
rl.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une clé API
|
||||
*/
|
||||
async removeKey(provider: 'openai' | 'mistral'): Promise<void> {
|
||||
const keys = this.loadKeys();
|
||||
|
||||
if (process.env[`${provider.toUpperCase()}_API_KEY`]) {
|
||||
console.log(`⚠️ La clé ${provider.toUpperCase()} est définie en variable d'environnement et ne peut pas être supprimée.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existsSync(this.keysPath)) {
|
||||
try {
|
||||
const fileKeys = JSON.parse(readFileSync(this.keysPath, 'utf8'));
|
||||
delete fileKeys[provider];
|
||||
writeFileSync(this.keysPath, JSON.stringify(fileKeys, null, 2));
|
||||
console.log(`✅ Clé ${provider.toUpperCase()} supprimée avec succès !`);
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la suppression de la clé:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche le statut des clés API
|
||||
*/
|
||||
displayKeysStatus(): void {
|
||||
const keys = this.loadKeys();
|
||||
|
||||
console.log('\n🔑 Statut des clés API:');
|
||||
console.log('─'.repeat(30));
|
||||
|
||||
// OpenAI
|
||||
if (keys.openai) {
|
||||
const source = process.env.OPENAI_API_KEY ? '(var. env.)' : '(fichier)';
|
||||
const masked = this.maskKey(keys.openai);
|
||||
console.log(`✅ OpenAI: ${masked} ${source}`);
|
||||
} else {
|
||||
console.log('❌ OpenAI: Non configuré');
|
||||
}
|
||||
|
||||
// Mistral
|
||||
if (keys.mistral) {
|
||||
const source = process.env.MISTRAL_API_KEY ? '(var. env.)' : '(fichier)';
|
||||
const masked = this.maskKey(keys.mistral);
|
||||
console.log(`✅ Mistral: ${masked} ${source}`);
|
||||
} else {
|
||||
console.log('❌ Mistral: Non configuré');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Masque une clé API pour l'affichage
|
||||
*/
|
||||
private maskKey(key: string): string {
|
||||
if (key.length <= 8) return '*'.repeat(key.length);
|
||||
return key.substring(0, 4) + '*'.repeat(key.length - 8) + key.substring(key.length - 4);
|
||||
}
|
||||
}
|
@ -98,6 +98,19 @@ export class CommandProcessor {
|
||||
this.showConfig();
|
||||
break;
|
||||
|
||||
// Nouvelles commandes pour les clés API
|
||||
case 'keys':
|
||||
this.showKeys();
|
||||
break;
|
||||
|
||||
case 'key':
|
||||
await this.manageKey(args);
|
||||
break;
|
||||
|
||||
case 'setup':
|
||||
await this.setupKeys();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Traiter comme une question à l'IA
|
||||
await this.handleAIQuery(command);
|
||||
@ -157,6 +170,100 @@ export class CommandProcessor {
|
||||
console.log(JSON.stringify(this.config, null, 2));
|
||||
}
|
||||
|
||||
private showKeys(): void {
|
||||
const keyManager = this.dependencies.auth.getKeyManager();
|
||||
keyManager.displayKeysStatus();
|
||||
}
|
||||
|
||||
private async manageKey(args: string[]): Promise<void> {
|
||||
const keyManager = this.dependencies.auth.getKeyManager();
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log('\n🔑 Gestion des clés API:');
|
||||
console.log('Usage:');
|
||||
console.log(' key set <provider> - Définir/mettre à jour une clé (openai, mistral)');
|
||||
console.log(' key remove <provider> - Supprimer une clé');
|
||||
console.log(' key status - Afficher le statut des clés');
|
||||
return;
|
||||
}
|
||||
|
||||
const [action, provider] = args;
|
||||
|
||||
switch (action.toLowerCase()) {
|
||||
case 'set':
|
||||
case 'update':
|
||||
if (!provider || !['openai', 'mistral'].includes(provider.toLowerCase())) {
|
||||
console.log('❌ Provider invalide. Utilisez: openai ou mistral');
|
||||
return;
|
||||
}
|
||||
await keyManager.updateKey(provider.toLowerCase() as 'openai' | 'mistral');
|
||||
// Redémarrer le client IA avec les nouvelles clés
|
||||
await this.reloadAIClient();
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
case 'delete':
|
||||
if (!provider || !['openai', 'mistral'].includes(provider.toLowerCase())) {
|
||||
console.log('❌ Provider invalide. Utilisez: openai ou mistral');
|
||||
return;
|
||||
}
|
||||
await keyManager.removeKey(provider.toLowerCase() as 'openai' | 'mistral');
|
||||
await this.reloadAIClient();
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
keyManager.displayKeysStatus();
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❌ Action invalide. Utilisez: set, remove, ou status');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async setupKeys(): Promise<void> {
|
||||
const keyManager = this.dependencies.auth.getKeyManager();
|
||||
await keyManager.promptForMissingKeys();
|
||||
await this.reloadAIClient();
|
||||
console.log('\n✅ Configuration terminée! Vous pouvez maintenant utiliser NeuraTerm.');
|
||||
}
|
||||
|
||||
private async reloadAIClient(): Promise<void> {
|
||||
try {
|
||||
// Recréer le client IA avec les nouvelles clés
|
||||
const keyManager = this.dependencies.auth.getKeyManager();
|
||||
const keys = keyManager.loadKeys();
|
||||
|
||||
// Vérifier qu'au moins une clé est disponible
|
||||
if (!keys.openai && !keys.mistral) {
|
||||
console.log('⚠️ Aucune clé API disponible. Le client IA ne peut pas être rechargé.');
|
||||
return;
|
||||
}
|
||||
|
||||
const providerConfig = {
|
||||
openai: {
|
||||
apiKey: keys.openai || '',
|
||||
model: this.config.ai.openai?.model || 'gpt-4o-mini',
|
||||
baseUrl: this.config.ai.openai?.baseUrl
|
||||
},
|
||||
mistral: {
|
||||
apiKey: keys.mistral || '',
|
||||
model: this.config.ai.mistral?.model || 'mistral-large-latest',
|
||||
baseUrl: this.config.ai.mistral?.baseUrl
|
||||
},
|
||||
defaultProvider: keys.openai ? 'openai' : 'mistral'
|
||||
};
|
||||
|
||||
// Recréer le client IA
|
||||
const { AIClient } = await import('../ai/client.js');
|
||||
this.dependencies.ai = new AIClient(providerConfig);
|
||||
|
||||
console.log('✅ Client IA rechargé avec les nouvelles clés');
|
||||
} catch (error) {
|
||||
console.log('❌ Erreur lors du rechargement:', error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
}
|
||||
|
||||
private async handleAIQuery(query: string): Promise<void> {
|
||||
try {
|
||||
const response = await this.dependencies.ai.generateResponse({
|
||||
|
@ -62,27 +62,12 @@ export async function loadConfig(options: any = {}): Promise<Config> {
|
||||
}
|
||||
}
|
||||
|
||||
// Charger depuis les variables d'environnement
|
||||
if (process.env.OPENAI_API_KEY) {
|
||||
config.ai.openai = {
|
||||
...config.ai.openai,
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.MISTRAL_API_KEY) {
|
||||
config.ai.mistral = {
|
||||
...config.ai.mistral,
|
||||
apiKey: process.env.MISTRAL_API_KEY
|
||||
};
|
||||
}
|
||||
// Les clés API seront gérées par KeyManager
|
||||
// On ne fait plus la validation ici car elle sera faite par AuthManager
|
||||
|
||||
// Fusionner avec les options passées en paramètre
|
||||
config = { ...config, ...options };
|
||||
|
||||
// Validation
|
||||
validateConfig(config);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -71,10 +71,16 @@ Commandes générales:
|
||||
exit, quit - Quitter NeuraTerm
|
||||
clear - Effacer l'écran
|
||||
|
||||
Gestion des clés API:
|
||||
keys - Afficher le statut des clés API
|
||||
key set <provider> - Définir/mettre à jour une clé (openai, mistral)
|
||||
key remove <provider> - Supprimer une clé
|
||||
key status - Afficher le statut des clés
|
||||
setup - Configuration interactive des clés
|
||||
|
||||
Gestion des providers:
|
||||
providers - Lister les providers disponibles
|
||||
provider <nom> - Changer de provider (openai, mistral)
|
||||
models - Lister les modèles disponibles
|
||||
|
||||
Statistiques:
|
||||
stats - Afficher les statistiques d'utilisation
|
||||
@ -84,9 +90,13 @@ Statistiques:
|
||||
|
||||
Configuration:
|
||||
config - Afficher la configuration actuelle
|
||||
set <param> <value> - Modifier un paramètre
|
||||
|
||||
Pour poser une question à l'IA, tapez simplement votre message.
|
||||
|
||||
Exemples:
|
||||
key set openai - Configurer votre clé OpenAI
|
||||
provider mistral - Basculer vers Mistral AI
|
||||
Comment optimiser ce code Python ?
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user