@eeacms/volto-eea-chatbot 3.0.1 → 4.1.0
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/CHANGELOG.md +53 -4
- package/README.md +115 -12
- package/package.json +1 -1
- package/src/ChatBlock/ChatBlockView.jsx +7 -1
- package/src/ChatBlock/chat/AIMessage.tsx +79 -45
- package/src/ChatBlock/chat/ChatMessage.tsx +17 -10
- package/src/ChatBlock/chat/ChatWindow.tsx +11 -0
- package/src/ChatBlock/chat/MessageContext.ts +12 -0
- package/src/ChatBlock/chat/index.ts +1 -0
- package/src/ChatBlock/components/markdown/ClaimModal.jsx +3 -3
- package/src/ChatBlock/components/markdown/index.jsx +1 -0
- package/src/ChatBlock/hooks/useQualityMarkers.js +21 -4
- package/src/ChatBlock/index.js +9 -1
- package/src/ChatBlock/packets/RendererComponent.tsx +9 -0
- package/src/ChatBlock/packets/renderers/MessageTextRenderer.tsx +15 -3
- package/src/ChatBlock/schema.jsx +13 -0
- package/src/ChatBlock/services/messageProcessor.ts +9 -12
- package/src/ChatBlock/types/interfaces.ts +25 -0
- package/src/ChatBlock/utils/index.tsx +10 -0
- package/src/ChatBlock/variations.ts +44 -0
- package/src/halloumi/README.md +27 -1
- package/src/halloumi/middleware.js +41 -50
- package/src/halloumi/middleware.test.js +102 -103
- package/src/halloumi/filtering.js +0 -149
- package/src/halloumi/filtering.test.js +0 -242
- package/src/halloumi/generative.js +0 -324
- package/src/halloumi/generative.test.js +0 -386
- package/src/halloumi/markdown-splitter.js +0 -172
- package/src/halloumi/markdown-splitter.test.js +0 -133
- package/src/halloumi/postprocessing.js +0 -247
- package/src/halloumi/postprocessing.test.js +0 -441
- package/src/halloumi/preprocessing.js +0 -117
- package/src/halloumi/preprocessing.test.js +0 -184
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createChunkedHalloumiPrompts,
|
|
3
|
-
annotate,
|
|
4
|
-
getOffsets,
|
|
5
|
-
} from './preprocessing';
|
|
6
|
-
|
|
7
|
-
describe('annotate', () => {
|
|
8
|
-
it('should annotate multiple sentences correctly', () => {
|
|
9
|
-
const sentences = ['Sentence one.', 'Sentence two.'];
|
|
10
|
-
const annotationChar = 's';
|
|
11
|
-
const expected =
|
|
12
|
-
'<|s1|><Sentence one.><end||s><|s2|><Sentence two.><end||s>';
|
|
13
|
-
expect(annotate(sentences, annotationChar)).toEqual(expected);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should handle an empty array of sentences', () => {
|
|
17
|
-
const sentences = [];
|
|
18
|
-
const annotationChar = 's';
|
|
19
|
-
expect(annotate(sentences, annotationChar)).toEqual('');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should annotate a single sentence', () => {
|
|
23
|
-
const sentences = ['Single sentence.'];
|
|
24
|
-
const annotationChar = 'r';
|
|
25
|
-
const expected = '<|r1|><Single sentence.><end||r>';
|
|
26
|
-
expect(annotate(sentences, annotationChar)).toEqual(expected);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should use different annotation characters', () => {
|
|
30
|
-
const sentences = ['Hello.'];
|
|
31
|
-
const annotationChar = 'x';
|
|
32
|
-
const expected = '<|x1|><Hello.><end||x>';
|
|
33
|
-
expect(annotate(sentences, annotationChar)).toEqual(expected);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe('getOffsets', () => {
|
|
38
|
-
it('should calculate correct offsets for multiple sentences', () => {
|
|
39
|
-
const originalString = 'First sentence. Second sentence. Third sentence.';
|
|
40
|
-
const sentences = [
|
|
41
|
-
'First sentence. ',
|
|
42
|
-
'Second sentence. ',
|
|
43
|
-
'Third sentence.',
|
|
44
|
-
];
|
|
45
|
-
const expected = new Map([
|
|
46
|
-
[1, { startOffset: 0, endOffset: 16 }],
|
|
47
|
-
[2, { startOffset: 16, endOffset: 33 }],
|
|
48
|
-
[3, { startOffset: 33, endOffset: 48 }],
|
|
49
|
-
]);
|
|
50
|
-
expect(getOffsets(originalString, sentences)).toEqual(expected);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should handle empty original string and sentences', () => {
|
|
54
|
-
const originalString = '';
|
|
55
|
-
const sentences = [];
|
|
56
|
-
expect(getOffsets(originalString, sentences)).toEqual(new Map());
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should handle original string matching sentences exactly', () => {
|
|
60
|
-
const originalString = 'Hello world.';
|
|
61
|
-
const sentences = ['Hello world.'];
|
|
62
|
-
const expected = new Map([[1, { startOffset: 0, endOffset: 12 }]]);
|
|
63
|
-
expect(getOffsets(originalString, sentences)).toEqual(expected);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should handle original string with leading/trailing spaces', () => {
|
|
67
|
-
const originalString = ' Sentence one. Sentence two. ';
|
|
68
|
-
const sentences = ['Sentence one. ', 'Sentence two. '];
|
|
69
|
-
const expected = new Map([
|
|
70
|
-
[1, { startOffset: 2, endOffset: 17 }],
|
|
71
|
-
[2, { startOffset: 17, endOffset: 32 }],
|
|
72
|
-
]);
|
|
73
|
-
expect(getOffsets(originalString, sentences)).toEqual(expected);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should handle sentences with special characters', () => {
|
|
77
|
-
const originalString = 'Sentence with !@#$%^&*() special characters.';
|
|
78
|
-
const sentences = ['Sentence with !@#$%^&*() special characters.'];
|
|
79
|
-
const expected = new Map([[1, { startOffset: 0, endOffset: 44 }]]);
|
|
80
|
-
expect(getOffsets(originalString, sentences)).toEqual(expected);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('createChunkedHalloumiPrompts', () => {
|
|
85
|
-
it('should create a single chunk for small input', () => {
|
|
86
|
-
const indexedContextSentences = [
|
|
87
|
-
{ sentence: 'Context one.', sourceId: 1, globalId: 1 },
|
|
88
|
-
{ sentence: 'Context two.', sourceId: 1, globalId: 2 },
|
|
89
|
-
];
|
|
90
|
-
const responseSentences = ['Response one.', 'Response two.'];
|
|
91
|
-
const responseOffsets = new Map([
|
|
92
|
-
[1, { startOffset: 0, endOffset: 13 }],
|
|
93
|
-
[2, { startOffset: 14, endOffset: 28 }],
|
|
94
|
-
]);
|
|
95
|
-
|
|
96
|
-
const { prompts } = createChunkedHalloumiPrompts({
|
|
97
|
-
indexedContextSentences,
|
|
98
|
-
responseSentences,
|
|
99
|
-
responseOffsets,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
expect(prompts).toHaveLength(1);
|
|
103
|
-
expect(prompts[0].prompt).toContain('<|s1|><Context one.><end||s>');
|
|
104
|
-
expect(prompts[0].prompt).toContain('<|s2|><Context two.><end||s>');
|
|
105
|
-
expect(prompts[0].prompt).toContain('<|r1|><Response one.><end||r>');
|
|
106
|
-
expect(prompts[0].prompt).toContain('<|r2|><Response two.><end||r>');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should handle empty context', () => {
|
|
110
|
-
const responseSentences = ['Response.'];
|
|
111
|
-
const responseOffsets = new Map([[1, { startOffset: 0, endOffset: 9 }]]);
|
|
112
|
-
|
|
113
|
-
const { prompts } = createChunkedHalloumiPrompts({
|
|
114
|
-
indexedContextSentences: [],
|
|
115
|
-
responseSentences,
|
|
116
|
-
responseOffsets,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
expect(prompts).toHaveLength(1);
|
|
120
|
-
expect(prompts[0].prompt).toContain('<|context|><end||context>');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('should exclude response sentences based on excludeResponseIndices', () => {
|
|
124
|
-
const indexedContextSentences = [
|
|
125
|
-
{ sentence: 'Context.', sourceId: 1, globalId: 1 },
|
|
126
|
-
];
|
|
127
|
-
const responseSentences = ['Keep this.', 'Skip this.', 'Keep too.'];
|
|
128
|
-
const responseOffsets = new Map([
|
|
129
|
-
[1, { startOffset: 0, endOffset: 10 }],
|
|
130
|
-
[2, { startOffset: 11, endOffset: 21 }],
|
|
131
|
-
[3, { startOffset: 22, endOffset: 31 }],
|
|
132
|
-
]);
|
|
133
|
-
const excludeResponseIndices = new Set([2]);
|
|
134
|
-
|
|
135
|
-
const { prompts } = createChunkedHalloumiPrompts({
|
|
136
|
-
indexedContextSentences,
|
|
137
|
-
responseSentences,
|
|
138
|
-
responseOffsets,
|
|
139
|
-
excludeResponseIndices,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
expect(prompts[0].prompt).toContain('<|r1|><Keep this.><end||r>');
|
|
143
|
-
expect(prompts[0].prompt).not.toContain('Skip this.');
|
|
144
|
-
expect(prompts[0].prompt).toContain('<|r3|><Keep too.><end||r>');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('should keep sources together with bin packing', () => {
|
|
148
|
-
// 3 sources: 60 + 60 + 30 = 150 sentences
|
|
149
|
-
// Should pack into 2 chunks: (60+30) and (60) or similar
|
|
150
|
-
const indexed = [];
|
|
151
|
-
let gid = 1;
|
|
152
|
-
// Source 1: 60 sentences
|
|
153
|
-
for (let i = 0; i < 60; i++) {
|
|
154
|
-
indexed.push({ sentence: `S1-${i}`, sourceId: 1, globalId: gid++ });
|
|
155
|
-
}
|
|
156
|
-
// Source 2: 60 sentences
|
|
157
|
-
for (let i = 0; i < 60; i++) {
|
|
158
|
-
indexed.push({ sentence: `S2-${i}`, sourceId: 2, globalId: gid++ });
|
|
159
|
-
}
|
|
160
|
-
// Source 3: 30 sentences
|
|
161
|
-
for (let i = 0; i < 30; i++) {
|
|
162
|
-
indexed.push({ sentence: `S3-${i}`, sourceId: 3, globalId: gid++ });
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const { prompts } = createChunkedHalloumiPrompts({
|
|
166
|
-
indexedContextSentences: indexed,
|
|
167
|
-
responseSentences: ['Claim.'],
|
|
168
|
-
responseOffsets: new Map([[1, { startOffset: 0, endOffset: 6 }]]),
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
expect(prompts).toHaveLength(2);
|
|
172
|
-
|
|
173
|
-
// Each source should be entirely within one chunk
|
|
174
|
-
for (const prompt of prompts) {
|
|
175
|
-
const s1Count = (prompt.prompt.match(/S1-/g) || []).length;
|
|
176
|
-
const s2Count = (prompt.prompt.match(/S2-/g) || []).length;
|
|
177
|
-
const s3Count = (prompt.prompt.match(/S3-/g) || []).length;
|
|
178
|
-
|
|
179
|
-
if (s1Count > 0) expect(s1Count).toBe(60);
|
|
180
|
-
if (s2Count > 0) expect(s2Count).toBe(60);
|
|
181
|
-
if (s3Count > 0) expect(s3Count).toBe(30);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
});
|