docs: add complete guide, env files, fix docker-compose
- Add GUIDE.md: complete user documentation covering installation, Docker deployment, AI providers, MCP server, N8N integration, email config, admin panel, env var reference, troubleshooting - Add mcp-server/.env.example with all MCP-specific variables - Update .env.docker.example with all 42 environment variables - Fix docker-compose.yml: parameterize PostgreSQL credentials, add missing env vars (CUSTOM_OPENAI, AI_PROVIDER_CHAT, ALLOW_REGISTRATION, RESEND_API_KEY) - Track memento-note/.env.example
This commit is contained in:
@@ -40,17 +40,17 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
tags: z.array(z.object({
|
||||
tag: z.string().describe('Le nom du tag, court et en minuscules'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
tag: z.string().describe('Short tag name in lowercase'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: `Analyse la note suivante et suggère entre 1 et 5 tags pertinents.
|
||||
Contenu de la note: "${content}"`,
|
||||
prompt: `Analyze the following note and suggest 1 to 5 relevant tags.
|
||||
Note content: "${content}"`,
|
||||
});
|
||||
|
||||
return object.tags;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération tags Custom OpenAI:', e);
|
||||
console.error('Error generating tags (Custom OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
});
|
||||
return embedding;
|
||||
} catch (e) {
|
||||
console.error('Erreur embeddings Custom OpenAI:', e);
|
||||
console.error('Error generating embeddings (Custom OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -74,8 +74,8 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
titles: z.array(z.object({
|
||||
title: z.string().describe('Le titre suggéré'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
title: z.string().describe('Suggested title'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: prompt,
|
||||
@@ -83,7 +83,7 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
|
||||
return object.titles;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération titres Custom OpenAI:', e);
|
||||
console.error('Error generating titles (Custom OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
|
||||
return text.trim();
|
||||
} catch (e) {
|
||||
console.error('Erreur génération texte Custom OpenAI:', e);
|
||||
console.error('Error generating text (Custom OpenAI):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export class CustomOpenAIProvider implements AIProvider {
|
||||
|
||||
return { text: text.trim() };
|
||||
} catch (e) {
|
||||
console.error('Erreur chat Custom OpenAI:', e);
|
||||
console.error('Error in chat (Custom OpenAI):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ export class DeepSeekProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
tags: z.array(z.object({
|
||||
tag: z.string().describe('Le nom du tag, court et en minuscules'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
tag: z.string().describe('Short tag name in lowercase'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: `Analyse la note suivante et suggère entre 1 et 5 tags pertinents.
|
||||
Contenu de la note: "${content}"`,
|
||||
prompt: `Analyze the following note and suggest 1 to 5 relevant tags.
|
||||
Note content: "${content}"`,
|
||||
});
|
||||
|
||||
return object.tags;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération tags DeepSeek:', e);
|
||||
console.error('Error generating tags (DeepSeek):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export class DeepSeekProvider implements AIProvider {
|
||||
});
|
||||
return embedding;
|
||||
} catch (e) {
|
||||
console.error('Erreur embeddings DeepSeek:', e);
|
||||
console.error('Error generating embeddings (DeepSeek):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -58,8 +58,8 @@ export class DeepSeekProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
titles: z.array(z.object({
|
||||
title: z.string().describe('Le titre suggéré'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
title: z.string().describe('Suggested title'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: prompt,
|
||||
@@ -67,7 +67,7 @@ export class DeepSeekProvider implements AIProvider {
|
||||
|
||||
return object.titles;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération titres DeepSeek:', e);
|
||||
console.error('Error generating titles (DeepSeek):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class DeepSeekProvider implements AIProvider {
|
||||
|
||||
return text.trim();
|
||||
} catch (e) {
|
||||
console.error('Erreur génération texte DeepSeek:', e);
|
||||
console.error('Error generating text (DeepSeek):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export class DeepSeekProvider implements AIProvider {
|
||||
|
||||
return { text: text.trim() };
|
||||
} catch (e) {
|
||||
console.error('Erreur chat DeepSeek:', e);
|
||||
console.error('Error in chat (DeepSeek):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ Note content: "${content}"`;
|
||||
return JSON.parse(jsonMatch[0]);
|
||||
}
|
||||
|
||||
// Support pour le format { "tags": [...] }
|
||||
// Support for { "tags": [...] } format
|
||||
const objectMatch = text.match(/\{\s*"tags"\s*:\s*(\[[\s\S]*\])\s*\}/);
|
||||
if (objectMatch && objectMatch[1]) {
|
||||
return JSON.parse(objectMatch[1]);
|
||||
@@ -83,7 +83,7 @@ Note content: "${content}"`;
|
||||
|
||||
return [];
|
||||
} catch (e) {
|
||||
console.error('Erreur API directe Ollama:', e);
|
||||
console.error('Error in Ollama API:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ Note content: "${content}"`;
|
||||
const data = await response.json();
|
||||
return data.embedding;
|
||||
} catch (e) {
|
||||
console.error('Erreur embeddings directs Ollama:', e);
|
||||
console.error('Error generating embeddings (Ollama):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ Note content: "${content}"`;
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
model: this.modelName,
|
||||
prompt: `${prompt}\n\nRéponds UNIQUEMENT sous forme de tableau JSON : [{"title": "string", "confidence": number}]`,
|
||||
prompt: `${prompt}\n\nRespond ONLY as a JSON array: [{"title": "string", "confidence": number}]`,
|
||||
stream: false,
|
||||
}),
|
||||
});
|
||||
@@ -126,7 +126,7 @@ Note content: "${content}"`;
|
||||
const data = await response.json();
|
||||
const text = data.response;
|
||||
|
||||
// Extraire le JSON de la réponse
|
||||
// Extract JSON from response
|
||||
const jsonMatch = text.match(/\[\s*\{[\s\S]*\}\s*\]/);
|
||||
if (jsonMatch) {
|
||||
return JSON.parse(jsonMatch[0]);
|
||||
@@ -134,7 +134,7 @@ Note content: "${content}"`;
|
||||
|
||||
return [];
|
||||
} catch (e) {
|
||||
console.error('Erreur génération titres Ollama:', e);
|
||||
console.error('Error generating titles (Ollama):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ Note content: "${content}"`;
|
||||
const data = await response.json();
|
||||
return data.response.trim();
|
||||
} catch (e) {
|
||||
console.error('Erreur génération texte Ollama:', e);
|
||||
console.error('Error generating text (Ollama):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ Note content: "${content}"`;
|
||||
const data = await response.json();
|
||||
return { text: data.message?.content?.trim() || '' };
|
||||
} catch (e) {
|
||||
console.error('Erreur chat Ollama:', e);
|
||||
console.error('Error in chat (Ollama):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ export class OpenAIProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
tags: z.array(z.object({
|
||||
tag: z.string().describe('Le nom du tag, court et en minuscules'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
tag: z.string().describe('Short tag name in lowercase'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: `Analyse la note suivante et suggère entre 1 et 5 tags pertinents.
|
||||
Contenu de la note: "${content}"`,
|
||||
prompt: `Analyze the following note and suggest 1 to 5 relevant tags.
|
||||
Note content: "${content}"`,
|
||||
});
|
||||
|
||||
return object.tags;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération tags OpenAI:', e);
|
||||
console.error('Error generating tags (OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export class OpenAIProvider implements AIProvider {
|
||||
});
|
||||
return embedding;
|
||||
} catch (e) {
|
||||
console.error('Erreur embeddings OpenAI:', e);
|
||||
console.error('Error generating embeddings (OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -58,8 +58,8 @@ export class OpenAIProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
titles: z.array(z.object({
|
||||
title: z.string().describe('Le titre suggéré'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
title: z.string().describe('Suggested title'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: prompt,
|
||||
@@ -67,7 +67,7 @@ export class OpenAIProvider implements AIProvider {
|
||||
|
||||
return object.titles;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération titres OpenAI:', e);
|
||||
console.error('Error generating titles (OpenAI):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class OpenAIProvider implements AIProvider {
|
||||
|
||||
return text.trim();
|
||||
} catch (e) {
|
||||
console.error('Erreur génération texte OpenAI:', e);
|
||||
console.error('Error generating text (OpenAI):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export class OpenAIProvider implements AIProvider {
|
||||
|
||||
return { text: text.trim() };
|
||||
} catch (e) {
|
||||
console.error('Erreur chat OpenAI:', e);
|
||||
console.error('Error in chat (OpenAI):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ export class OpenRouterProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
tags: z.array(z.object({
|
||||
tag: z.string().describe('Le nom du tag, court et en minuscules'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
tag: z.string().describe('Short tag name in lowercase'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: `Analyse la note suivante et suggère entre 1 et 5 tags pertinents.
|
||||
Contenu de la note: "${content}"`,
|
||||
prompt: `Analyze the following note and suggest 1 to 5 relevant tags.
|
||||
Note content: "${content}"`,
|
||||
});
|
||||
|
||||
return object.tags;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération tags OpenRouter:', e);
|
||||
console.error('Error generating tags (OpenRouter):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export class OpenRouterProvider implements AIProvider {
|
||||
});
|
||||
return embedding;
|
||||
} catch (e) {
|
||||
console.error('Erreur embeddings OpenRouter:', e);
|
||||
console.error('Error generating embeddings (OpenRouter):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -58,8 +58,8 @@ export class OpenRouterProvider implements AIProvider {
|
||||
model: this.model,
|
||||
schema: z.object({
|
||||
titles: z.array(z.object({
|
||||
title: z.string().describe('Le titre suggéré'),
|
||||
confidence: z.number().min(0).max(1).describe('Le niveau de confiance entre 0 et 1')
|
||||
title: z.string().describe('Suggested title'),
|
||||
confidence: z.number().min(0).max(1).describe('Confidence level between 0 and 1')
|
||||
}))
|
||||
}),
|
||||
prompt: prompt,
|
||||
@@ -67,7 +67,7 @@ export class OpenRouterProvider implements AIProvider {
|
||||
|
||||
return object.titles;
|
||||
} catch (e) {
|
||||
console.error('Erreur génération titres OpenRouter:', e);
|
||||
console.error('Error generating titles (OpenRouter):', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class OpenRouterProvider implements AIProvider {
|
||||
|
||||
return text.trim();
|
||||
} catch (e) {
|
||||
console.error('Erreur génération texte OpenRouter:', e);
|
||||
console.error('Error generating text (OpenRouter):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export class OpenRouterProvider implements AIProvider {
|
||||
|
||||
return { text: text.trim() };
|
||||
} catch (e) {
|
||||
console.error('Erreur chat OpenRouter:', e);
|
||||
console.error('Error in chat (OpenRouter):', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,32 +29,32 @@ export interface ToolCallResult {
|
||||
|
||||
export interface AIProvider {
|
||||
/**
|
||||
* Analyse le contenu et suggère des tags pertinents.
|
||||
* Analyze content and suggest relevant tags.
|
||||
*/
|
||||
generateTags(content: string, language?: string): Promise<TagSuggestion[]>;
|
||||
|
||||
/**
|
||||
* Génère un vecteur d'embeddings pour la recherche sémantique.
|
||||
* Generate an embedding vector for semantic search.
|
||||
*/
|
||||
getEmbeddings(text: string): Promise<number[]>;
|
||||
|
||||
/**
|
||||
* Génère des suggestions de titres basées sur le contenu.
|
||||
* Generate title suggestions based on content.
|
||||
*/
|
||||
generateTitles(prompt: string): Promise<TitleSuggestion[]>;
|
||||
|
||||
/**
|
||||
* Génère du texte basé sur un prompt.
|
||||
* Generate text based on a prompt.
|
||||
*/
|
||||
generateText(prompt: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* Fournit une réponse de chat (utilisé pour le système agentique)
|
||||
* Provide a chat response (used for the agentic system)
|
||||
*/
|
||||
chat(messages: any[], systemPrompt?: string): Promise<any>;
|
||||
|
||||
/**
|
||||
* Retourne le modèle AI SDK pour le streaming direct (utilisé par l'API route)
|
||||
* Return the AI SDK model for direct streaming (used by API route)
|
||||
*/
|
||||
getModel(): any;
|
||||
|
||||
@@ -69,7 +69,7 @@ export type AIProviderType = 'openai' | 'ollama';
|
||||
export interface AIConfig {
|
||||
provider: AIProviderType;
|
||||
apiKey?: string;
|
||||
baseUrl?: string; // Utile pour Ollama
|
||||
baseUrl?: string; // Used for Ollama
|
||||
model?: string;
|
||||
embeddingModel?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user