@fidusia/question-engine-dynamic 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/ai-questions-loader.d.ts +43 -0
- package/dist/ai-questions-loader.d.ts.map +1 -0
- package/dist/ai-questions-loader.js +131 -0
- package/dist/config-loader.d.ts +134 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +80 -0
- package/dist/engine.d.ts +81 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +1243 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/types.d.ts +143 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +98 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @aimi/question-engine
|
|
2
|
+
|
|
3
|
+
Moteur de questions partagé pour la plateforme Aimi.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Le package est automatiquement disponible dans tous les projets du monorepo via npm workspaces.
|
|
8
|
+
|
|
9
|
+
## Utilisation
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { QuestionEngine, resetQuestionEngine, type I18nFunctions } from "@aimi/question-engine"
|
|
13
|
+
import { t, getQuestionOptions } from "@/lib/i18n"
|
|
14
|
+
|
|
15
|
+
// Créer une instance avec injection de dépendances i18n
|
|
16
|
+
const i18n: I18nFunctions = { t, getQuestionOptions }
|
|
17
|
+
const engine = resetQuestionEngine(i18n)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Structure
|
|
21
|
+
|
|
22
|
+
- `engine.ts` : Classe principale QuestionEngine
|
|
23
|
+
- `types.ts` : Types TypeScript
|
|
24
|
+
- `config-loader.ts` : Chargement de configuration
|
|
25
|
+
- `ai-questions-loader.ts` : Chargement des questions IA
|
|
26
|
+
|
|
27
|
+
## Dépendances Externes
|
|
28
|
+
|
|
29
|
+
Le package nécessite que les projets consommateurs fournissent les fonctions i18n via injection :
|
|
30
|
+
- `t(key, params?, lang?)` : Fonction de traduction
|
|
31
|
+
- `getQuestionOptions(questionId, lang?)` : Récupération des options de question
|
|
32
|
+
|
|
33
|
+
## Modification
|
|
34
|
+
|
|
35
|
+
Pour modifier QuestionEngine :
|
|
36
|
+
1. Modifier les fichiers dans `packages/question-engine/src/`
|
|
37
|
+
2. Tous les projets utilisent automatiquement la nouvelle version
|
|
38
|
+
3. Tester dans chaque projet
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ModuleQuestion } from './types';
|
|
2
|
+
export interface AIQuestion {
|
|
3
|
+
id: string;
|
|
4
|
+
sectorId: string;
|
|
5
|
+
questionId: string;
|
|
6
|
+
questionText: string;
|
|
7
|
+
questionType: string;
|
|
8
|
+
options?: string[] | null;
|
|
9
|
+
placeholder?: string | null;
|
|
10
|
+
minValue?: number | null;
|
|
11
|
+
maxValue?: number | null;
|
|
12
|
+
conditions: Record<string, any>;
|
|
13
|
+
isActive: boolean;
|
|
14
|
+
parentQuestionId?: string | null;
|
|
15
|
+
nextQuestionId?: string | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Charge les questions IA actives pour un secteur et filtre selon les conditions
|
|
19
|
+
* Utilise l'API backend externe
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadAIQuestionsForSector(sectorId: string, formData: Record<string, any>): Promise<AIQuestion[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Convertit une question IA en ModuleQuestion
|
|
24
|
+
*/
|
|
25
|
+
export declare function convertAIQuestionToModuleQuestion(aiQuestion: AIQuestion): ModuleQuestion;
|
|
26
|
+
/**
|
|
27
|
+
* Trouve l'index d'une question dans un module
|
|
28
|
+
*/
|
|
29
|
+
export declare function findQuestionIndexInModule(module: {
|
|
30
|
+
questions: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
}>;
|
|
33
|
+
}, questionId: string): number;
|
|
34
|
+
/**
|
|
35
|
+
* Charge toutes les questions IA actives pour un secteur (sans filtrage par formData)
|
|
36
|
+
* Utilise l'API backend externe
|
|
37
|
+
*/
|
|
38
|
+
export declare function loadAllAIQuestionsForSector(sectorId: string, chatbotId?: string): Promise<AIQuestion[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Vérifie si les conditions d'une question IA sont remplies par le formData
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkConditions(conditions: Record<string, any> | null, formData: Record<string, any>): boolean;
|
|
43
|
+
//# sourceMappingURL=ai-questions-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-questions-loader.d.ts","sourceRoot":"","sources":["../src/ai-questions-loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,SAAS,CAAC;AAE5D,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,OAAO,CAAC,UAAU,EAAE,CAAC,CA2BvB;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,UAAU,GAAG,cAAc,CAoBxF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE;IAAE,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,EAC5C,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CA8BvB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,OAAO,CAgCT"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// LOADER DE QUESTIONS IA
|
|
3
|
+
// Charge et filtre les questions générées par IA
|
|
4
|
+
// Utilise une API route car le Question Engine s'exécute côté client
|
|
5
|
+
// =====================================================
|
|
6
|
+
/**
|
|
7
|
+
* Charge les questions IA actives pour un secteur et filtre selon les conditions
|
|
8
|
+
* Utilise l'API backend externe
|
|
9
|
+
*/
|
|
10
|
+
export async function loadAIQuestionsForSector(sectorId, formData) {
|
|
11
|
+
try {
|
|
12
|
+
// Utiliser une route API proxy locale (même domaine)
|
|
13
|
+
// La route proxy dans le projet chatbot fera le pont vers le backend
|
|
14
|
+
const url = `/api/sectors/${sectorId}/questions/ai/active`;
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { 'Content-Type': 'application/json' },
|
|
18
|
+
body: JSON.stringify({ formData })
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
console.error('[AI Questions Loader] API error:', response.statusText);
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
if (data.success) {
|
|
26
|
+
return data.questions || [];
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('[AI Questions Loader] Error loading AI questions:', error);
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Convertit une question IA en ModuleQuestion
|
|
37
|
+
*/
|
|
38
|
+
export function convertAIQuestionToModuleQuestion(aiQuestion) {
|
|
39
|
+
return {
|
|
40
|
+
id: aiQuestion.questionId,
|
|
41
|
+
text: aiQuestion.questionText,
|
|
42
|
+
type: aiQuestion.questionType,
|
|
43
|
+
options: aiQuestion.options || undefined,
|
|
44
|
+
placeholder: aiQuestion.placeholder || undefined,
|
|
45
|
+
min: aiQuestion.minValue || undefined,
|
|
46
|
+
max: aiQuestion.maxValue || undefined,
|
|
47
|
+
nextInModule: aiQuestion.nextQuestionId || null,
|
|
48
|
+
isRequired: true,
|
|
49
|
+
// Préserver les métadonnées pour l'export JSON
|
|
50
|
+
aiQuestionMetadata: {
|
|
51
|
+
conditions: aiQuestion.conditions || null,
|
|
52
|
+
parentQuestionId: aiQuestion.parentQuestionId || null,
|
|
53
|
+
nextQuestionId: aiQuestion.nextQuestionId || null,
|
|
54
|
+
sectorId: aiQuestion.sectorId,
|
|
55
|
+
isActive: aiQuestion.isActive
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Trouve l'index d'une question dans un module
|
|
61
|
+
*/
|
|
62
|
+
export function findQuestionIndexInModule(module, questionId) {
|
|
63
|
+
return module.questions.findIndex(q => q.id === questionId);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Charge toutes les questions IA actives pour un secteur (sans filtrage par formData)
|
|
67
|
+
* Utilise l'API backend externe
|
|
68
|
+
*/
|
|
69
|
+
export async function loadAllAIQuestionsForSector(sectorId, chatbotId) {
|
|
70
|
+
try {
|
|
71
|
+
// Utiliser une route API proxy locale (même domaine)
|
|
72
|
+
// La route proxy dans le projet chatbot fera le pont vers le backend
|
|
73
|
+
let url = `/api/sectors/${sectorId}/questions/ai`;
|
|
74
|
+
if (chatbotId) {
|
|
75
|
+
url += `?chatbotId=${encodeURIComponent(chatbotId)}`;
|
|
76
|
+
}
|
|
77
|
+
const response = await fetch(url, {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
headers: { 'Content-Type': 'application/json' }
|
|
80
|
+
});
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
console.error('[AI Questions Loader] API error:', response.statusText);
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const data = await response.json();
|
|
86
|
+
if (data.success) {
|
|
87
|
+
// Filtrer seulement les questions actives
|
|
88
|
+
return (data.questions || []).filter((q) => q.isActive);
|
|
89
|
+
}
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error('[AI Questions Loader] Error loading all AI questions:', error);
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Vérifie si les conditions d'une question IA sont remplies par le formData
|
|
99
|
+
*/
|
|
100
|
+
export function checkConditions(conditions, formData) {
|
|
101
|
+
// Si pas de conditions (null ou {}), la question s'affiche toujours
|
|
102
|
+
if (!conditions || Object.keys(conditions).length === 0) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
// Vérifier chaque condition
|
|
106
|
+
for (const [key, value] of Object.entries(conditions)) {
|
|
107
|
+
const formValue = formData[key];
|
|
108
|
+
// Si la valeur attendue est un tableau, vérifier si formValue est dans le tableau
|
|
109
|
+
if (Array.isArray(value)) {
|
|
110
|
+
if (!Array.isArray(formValue)) {
|
|
111
|
+
// Si formValue n'est pas un tableau mais value en est un, vérifier si formValue est dans value
|
|
112
|
+
if (!value.includes(formValue)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Si les deux sont des tableaux, vérifier si au moins un élément de formValue est dans value
|
|
118
|
+
if (!formValue.some((v) => value.includes(v))) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Comparaison simple
|
|
125
|
+
if (formValue !== value) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface pour la configuration complète d'un chatbot
|
|
3
|
+
*/
|
|
4
|
+
export interface ChatbotConfig {
|
|
5
|
+
systemIds?: {
|
|
6
|
+
budgetPriorityQuestionId?: string;
|
|
7
|
+
contactCorrectionQuestionId?: string;
|
|
8
|
+
continueOtherSectorsQuestionId?: string;
|
|
9
|
+
finalModuleId?: string;
|
|
10
|
+
introModuleId?: string;
|
|
11
|
+
continueOtherSectorsModuleId?: string;
|
|
12
|
+
};
|
|
13
|
+
priorityMappings?: Record<string, string[]>;
|
|
14
|
+
priorityBoosts?: Record<string, Array<{
|
|
15
|
+
moduleId: string;
|
|
16
|
+
boost: number;
|
|
17
|
+
}>>;
|
|
18
|
+
basePriorities?: Record<string, number>;
|
|
19
|
+
bookedProviderMappings?: Record<string, {
|
|
20
|
+
moduleId: string;
|
|
21
|
+
skipQuestion: string;
|
|
22
|
+
}>;
|
|
23
|
+
priorityToBookedProviders?: Record<string, string[]>;
|
|
24
|
+
priorityCalculation?: {
|
|
25
|
+
base?: number;
|
|
26
|
+
step?: number;
|
|
27
|
+
};
|
|
28
|
+
specialBehaviors?: {
|
|
29
|
+
budgetPriority?: {
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
filterOptionsByBookedProviders?: boolean;
|
|
32
|
+
};
|
|
33
|
+
contactCorrection?: {
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
detectEmailFrom?: string[];
|
|
36
|
+
};
|
|
37
|
+
continueOtherSectors?: {
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
skipToFinalOnNo?: boolean;
|
|
40
|
+
skipModulesWithPriority?: number;
|
|
41
|
+
insertBetweenPriorityAndNonPriority?: boolean;
|
|
42
|
+
};
|
|
43
|
+
transitions?: {
|
|
44
|
+
excludeModules?: string[];
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
dynamicParams?: Record<string, {
|
|
48
|
+
source: 'formData';
|
|
49
|
+
field?: string;
|
|
50
|
+
type?: 'string' | 'number';
|
|
51
|
+
logic?: {
|
|
52
|
+
type: 'conditional';
|
|
53
|
+
condition?: {
|
|
54
|
+
field: string;
|
|
55
|
+
operator: 'equals' | 'exists';
|
|
56
|
+
value?: any;
|
|
57
|
+
};
|
|
58
|
+
ifTrue?: any;
|
|
59
|
+
ifFalse?: any;
|
|
60
|
+
fallback?: {
|
|
61
|
+
check: string;
|
|
62
|
+
ifExists: any;
|
|
63
|
+
else: any;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Obtient les IDs système avec fallback vers les valeurs par défaut
|
|
70
|
+
*/
|
|
71
|
+
export declare function getSystemIds(config: ChatbotConfig): {
|
|
72
|
+
budgetPriorityQuestionId: string;
|
|
73
|
+
contactCorrectionQuestionId: string;
|
|
74
|
+
continueOtherSectorsQuestionId: string;
|
|
75
|
+
finalModuleId: string;
|
|
76
|
+
introModuleId: string;
|
|
77
|
+
continueOtherSectorsModuleId: string;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Obtient les mappings de priorité avec fallback vers les valeurs par défaut
|
|
81
|
+
*/
|
|
82
|
+
export declare function getPriorityMappings(config: ChatbotConfig): Record<string, string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Obtient les mappings de prestataires avec fallback vers les valeurs par défaut
|
|
85
|
+
*/
|
|
86
|
+
export declare function getBookedProviderMappings(config: ChatbotConfig): Record<string, {
|
|
87
|
+
moduleId: string;
|
|
88
|
+
skipQuestion: string;
|
|
89
|
+
}>;
|
|
90
|
+
/**
|
|
91
|
+
* Obtient les priorités de base avec fallback vers les valeurs par défaut
|
|
92
|
+
*/
|
|
93
|
+
export declare function getBasePriorities(config: ChatbotConfig): Record<string, number>;
|
|
94
|
+
/**
|
|
95
|
+
* Obtient les boosts de priorité avec fallback vers les valeurs par défaut
|
|
96
|
+
*/
|
|
97
|
+
export declare function getPriorityBoosts(config: ChatbotConfig): Record<string, Array<{
|
|
98
|
+
moduleId: string;
|
|
99
|
+
boost: number;
|
|
100
|
+
}>>;
|
|
101
|
+
/**
|
|
102
|
+
* Obtient le mapping priorité -> prestataires avec fallback
|
|
103
|
+
*/
|
|
104
|
+
export declare function getPriorityToBookedProviders(config: ChatbotConfig): Record<string, string[]>;
|
|
105
|
+
/**
|
|
106
|
+
* Obtient la configuration du calcul de priorité
|
|
107
|
+
*/
|
|
108
|
+
export declare function getPriorityCalculation(config: ChatbotConfig): {
|
|
109
|
+
base: number;
|
|
110
|
+
step: number;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Obtient les comportements spéciaux avec fallbacks
|
|
114
|
+
*/
|
|
115
|
+
export declare function getSpecialBehaviors(config: ChatbotConfig): {
|
|
116
|
+
budgetPriority: {
|
|
117
|
+
enabled: boolean;
|
|
118
|
+
filterOptionsByBookedProviders: boolean;
|
|
119
|
+
};
|
|
120
|
+
contactCorrection: {
|
|
121
|
+
enabled: boolean;
|
|
122
|
+
detectEmailFrom: string[];
|
|
123
|
+
};
|
|
124
|
+
continueOtherSectors: {
|
|
125
|
+
enabled: boolean;
|
|
126
|
+
skipToFinalOnNo: boolean;
|
|
127
|
+
skipModulesWithPriority: number;
|
|
128
|
+
insertBetweenPriorityAndNonPriority: boolean;
|
|
129
|
+
};
|
|
130
|
+
transitions: {
|
|
131
|
+
excludeModules: string[];
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { PRIORITY_TO_MODULES, BOOKED_PROVIDER_TO_MODULE, BASE_PRIORITIES, PRIORITY_BOOSTS, PRIORITY_TO_BOOKED_PROVIDERS } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Obtient les IDs système avec fallback vers les valeurs par défaut
|
|
4
|
+
*/
|
|
5
|
+
export function getSystemIds(config) {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
7
|
+
return {
|
|
8
|
+
budgetPriorityQuestionId: (_b = (_a = config.systemIds) === null || _a === void 0 ? void 0 : _a.budgetPriorityQuestionId) !== null && _b !== void 0 ? _b : "budget_priority",
|
|
9
|
+
contactCorrectionQuestionId: (_d = (_c = config.systemIds) === null || _c === void 0 ? void 0 : _c.contactCorrectionQuestionId) !== null && _d !== void 0 ? _d : "contact_correction",
|
|
10
|
+
continueOtherSectorsQuestionId: (_f = (_e = config.systemIds) === null || _e === void 0 ? void 0 : _e.continueOtherSectorsQuestionId) !== null && _f !== void 0 ? _f : "continue_other_sectors_question",
|
|
11
|
+
finalModuleId: (_h = (_g = config.systemIds) === null || _g === void 0 ? void 0 : _g.finalModuleId) !== null && _h !== void 0 ? _h : "final",
|
|
12
|
+
introModuleId: (_k = (_j = config.systemIds) === null || _j === void 0 ? void 0 : _j.introModuleId) !== null && _k !== void 0 ? _k : "intro",
|
|
13
|
+
continueOtherSectorsModuleId: (_m = (_l = config.systemIds) === null || _l === void 0 ? void 0 : _l.continueOtherSectorsModuleId) !== null && _m !== void 0 ? _m : "continue_other_sectors",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Obtient les mappings de priorité avec fallback vers les valeurs par défaut
|
|
18
|
+
*/
|
|
19
|
+
export function getPriorityMappings(config) {
|
|
20
|
+
return config.priorityMappings || PRIORITY_TO_MODULES;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Obtient les mappings de prestataires avec fallback vers les valeurs par défaut
|
|
24
|
+
*/
|
|
25
|
+
export function getBookedProviderMappings(config) {
|
|
26
|
+
return config.bookedProviderMappings || BOOKED_PROVIDER_TO_MODULE;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Obtient les priorités de base avec fallback vers les valeurs par défaut
|
|
30
|
+
*/
|
|
31
|
+
export function getBasePriorities(config) {
|
|
32
|
+
return config.basePriorities || BASE_PRIORITIES;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Obtient les boosts de priorité avec fallback vers les valeurs par défaut
|
|
36
|
+
*/
|
|
37
|
+
export function getPriorityBoosts(config) {
|
|
38
|
+
return config.priorityBoosts || PRIORITY_BOOSTS;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Obtient le mapping priorité -> prestataires avec fallback
|
|
42
|
+
*/
|
|
43
|
+
export function getPriorityToBookedProviders(config) {
|
|
44
|
+
return config.priorityToBookedProviders || PRIORITY_TO_BOOKED_PROVIDERS;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Obtient la configuration du calcul de priorité
|
|
48
|
+
*/
|
|
49
|
+
export function getPriorityCalculation(config) {
|
|
50
|
+
var _a, _b, _c, _d;
|
|
51
|
+
return {
|
|
52
|
+
base: (_b = (_a = config.priorityCalculation) === null || _a === void 0 ? void 0 : _a.base) !== null && _b !== void 0 ? _b : -500,
|
|
53
|
+
step: (_d = (_c = config.priorityCalculation) === null || _c === void 0 ? void 0 : _c.step) !== null && _d !== void 0 ? _d : 100,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Obtient les comportements spéciaux avec fallbacks
|
|
58
|
+
*/
|
|
59
|
+
export function getSpecialBehaviors(config) {
|
|
60
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
|
|
61
|
+
return {
|
|
62
|
+
budgetPriority: {
|
|
63
|
+
enabled: (_c = (_b = (_a = config.specialBehaviors) === null || _a === void 0 ? void 0 : _a.budgetPriority) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : true,
|
|
64
|
+
filterOptionsByBookedProviders: (_f = (_e = (_d = config.specialBehaviors) === null || _d === void 0 ? void 0 : _d.budgetPriority) === null || _e === void 0 ? void 0 : _e.filterOptionsByBookedProviders) !== null && _f !== void 0 ? _f : true,
|
|
65
|
+
},
|
|
66
|
+
contactCorrection: {
|
|
67
|
+
enabled: (_j = (_h = (_g = config.specialBehaviors) === null || _g === void 0 ? void 0 : _g.contactCorrection) === null || _h === void 0 ? void 0 : _h.enabled) !== null && _j !== void 0 ? _j : true,
|
|
68
|
+
detectEmailFrom: (_m = (_l = (_k = config.specialBehaviors) === null || _k === void 0 ? void 0 : _k.contactCorrection) === null || _l === void 0 ? void 0 : _l.detectEmailFrom) !== null && _m !== void 0 ? _m : ["Par email", "contact_email"],
|
|
69
|
+
},
|
|
70
|
+
continueOtherSectors: {
|
|
71
|
+
enabled: (_q = (_p = (_o = config.specialBehaviors) === null || _o === void 0 ? void 0 : _o.continueOtherSectors) === null || _p === void 0 ? void 0 : _p.enabled) !== null && _q !== void 0 ? _q : true,
|
|
72
|
+
skipToFinalOnNo: (_t = (_s = (_r = config.specialBehaviors) === null || _r === void 0 ? void 0 : _r.continueOtherSectors) === null || _s === void 0 ? void 0 : _s.skipToFinalOnNo) !== null && _t !== void 0 ? _t : true,
|
|
73
|
+
skipModulesWithPriority: (_w = (_v = (_u = config.specialBehaviors) === null || _u === void 0 ? void 0 : _u.continueOtherSectors) === null || _v === void 0 ? void 0 : _v.skipModulesWithPriority) !== null && _w !== void 0 ? _w : 0,
|
|
74
|
+
insertBetweenPriorityAndNonPriority: (_z = (_y = (_x = config.specialBehaviors) === null || _x === void 0 ? void 0 : _x.continueOtherSectors) === null || _y === void 0 ? void 0 : _y.insertBetweenPriorityAndNonPriority) !== null && _z !== void 0 ? _z : true,
|
|
75
|
+
},
|
|
76
|
+
transitions: {
|
|
77
|
+
excludeModules: (_2 = (_1 = (_0 = config.specialBehaviors) === null || _0 === void 0 ? void 0 : _0.transitions) === null || _1 === void 0 ? void 0 : _1.excludeModules) !== null && _2 !== void 0 ? _2 : ["intro", "final", "continue_other_sectors"],
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { QuestionModule, ModuleQuestion, QueueState, AnsweredQuestion, UserPriority, I18nFunctions } from "./types";
|
|
2
|
+
import type { ChatbotConfig } from './config-loader';
|
|
3
|
+
export declare class QuestionEngine {
|
|
4
|
+
private modules;
|
|
5
|
+
private state;
|
|
6
|
+
private listeners;
|
|
7
|
+
private advancedByTrigger;
|
|
8
|
+
private aiQuestionsCache;
|
|
9
|
+
private config;
|
|
10
|
+
private i18n;
|
|
11
|
+
private chatbotId;
|
|
12
|
+
constructor(i18n: I18nFunctions);
|
|
13
|
+
/**
|
|
14
|
+
* Définit l'ID du chatbot pour filtrer les questions IA
|
|
15
|
+
*/
|
|
16
|
+
setChatbotId(chatbotId: string | undefined): void;
|
|
17
|
+
private createInitialState;
|
|
18
|
+
registerModule(module: QuestionModule): void;
|
|
19
|
+
registerModules(modules: QuestionModule[]): void;
|
|
20
|
+
/**
|
|
21
|
+
* Définit la configuration du chatbot
|
|
22
|
+
* Doit être appelée avant initialize() pour que la configuration soit utilisée
|
|
23
|
+
*/
|
|
24
|
+
setConfig(config: ChatbotConfig): void;
|
|
25
|
+
initialize(): Promise<void>;
|
|
26
|
+
reset(): void;
|
|
27
|
+
restoreState(savedState: QueueState): Promise<void>;
|
|
28
|
+
private buildQueue;
|
|
29
|
+
private buildModuleQuestions;
|
|
30
|
+
/**
|
|
31
|
+
* Charge toutes les questions IA pour tous les secteurs une seule fois
|
|
32
|
+
* Utilise la version serveur si disponible (API routes), sinon la version fetch (client)
|
|
33
|
+
* OU extrait depuis les métadonnées des modules si disponibles (pour JSON)
|
|
34
|
+
*/
|
|
35
|
+
private loadAllAIQuestions;
|
|
36
|
+
/**
|
|
37
|
+
* Extrait les questions IA depuis les métadonnées des modules (pour import JSON)
|
|
38
|
+
* Retourne une Map<sectorId, AIQuestion[]>
|
|
39
|
+
*/
|
|
40
|
+
private extractAIQuestionsFromModules;
|
|
41
|
+
/**
|
|
42
|
+
* Injecte les questions IA depuis le cache selon les conditions actuelles
|
|
43
|
+
* Évite les doublons en vérifiant si la question est déjà dans la queue
|
|
44
|
+
* Gère l'injection récursive des questions IA qui dépendent d'autres questions IA
|
|
45
|
+
*/
|
|
46
|
+
private injectAIQuestionsFromCache;
|
|
47
|
+
private shouldHideModule;
|
|
48
|
+
private evaluateModuleTrigger;
|
|
49
|
+
private activateFirstQuestion;
|
|
50
|
+
getCurrentQuestion(): ModuleQuestion | null;
|
|
51
|
+
getCurrentModule(): QuestionModule | null;
|
|
52
|
+
getModuleById(moduleId: string): QuestionModule | null;
|
|
53
|
+
private checkHasQuestionSkip;
|
|
54
|
+
private getSkipDestination;
|
|
55
|
+
submitAnswer(answer: string | string[] | number | boolean): Promise<ModuleQuestion | null>;
|
|
56
|
+
private generateDynamicSubQuestions;
|
|
57
|
+
private generateSubQuestionsFromFormData;
|
|
58
|
+
private getNextQuestionId;
|
|
59
|
+
private advanceToNextModule;
|
|
60
|
+
private executeQuestionTriggers;
|
|
61
|
+
private evaluateQuestionTrigger;
|
|
62
|
+
private executeAction;
|
|
63
|
+
applyUserPriority(priority: UserPriority): void;
|
|
64
|
+
private recalculateQueue;
|
|
65
|
+
getState(): QueueState;
|
|
66
|
+
getFormData(): Record<string, any>;
|
|
67
|
+
getAnsweredQuestions(): AnsweredQuestion[];
|
|
68
|
+
getProgress(): {
|
|
69
|
+
current: number;
|
|
70
|
+
total: number;
|
|
71
|
+
percent: number;
|
|
72
|
+
};
|
|
73
|
+
getCurrentModuleName(): string;
|
|
74
|
+
isComplete(): boolean;
|
|
75
|
+
private applyPriorityOrder;
|
|
76
|
+
subscribe(listener: (state: QueueState) => void): () => void;
|
|
77
|
+
private notifyListeners;
|
|
78
|
+
}
|
|
79
|
+
export declare function getQuestionEngine(i18n: I18nFunctions): QuestionEngine;
|
|
80
|
+
export declare function resetQuestionEngine(i18n: I18nFunctions): QuestionEngine;
|
|
81
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,UAAU,EAGV,gBAAgB,EAChB,YAAY,EAIZ,aAAa,EACd,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AA8CpD,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,SAAS,CAAgC;gBAErC,IAAI,EAAE,aAAa;IAK/B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAQjD,OAAO,CAAC,kBAAkB;IAe1B,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAI5C,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI;IAIhD;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAIhC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAejC,KAAK,IAAI,IAAI;IAKP,YAAY,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAgDzD,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,oBAAoB;IAc5B;;;;OAIG;YACW,kBAAkB;IA2BhC;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAsCrC;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAkMlC,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,qBAAqB;IAyB7B,OAAO,CAAC,qBAAqB;IAsB7B,kBAAkB,IAAI,cAAc,GAAG,IAAI;IAmF3C,gBAAgB,IAAI,cAAc,GAAG,IAAI;IAKzC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAMtD,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,kBAAkB;IAYpB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqMhG,OAAO,CAAC,2BAA2B;IAiHnC,OAAO,CAAC,gCAAgC;IAgGxC,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,mBAAmB;IAsI3B,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,uBAAuB;IAoC/B,OAAO,CAAC,aAAa;IA2DrB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAmB/C,OAAO,CAAC,gBAAgB;IA6BxB,QAAQ,IAAI,UAAU;IAItB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAIlC,oBAAoB,IAAI,gBAAgB,EAAE;IAI1C,WAAW,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAclE,oBAAoB,IAAI,MAAM;IAK9B,UAAU,IAAI,OAAO;IAQrB,OAAO,CAAC,kBAAkB;IA0C1B,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAK5D,OAAO,CAAC,eAAe;CAIxB;AAKD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,CAKrE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,CAGvE"}
|