@eeacms/volto-eea-chatbot 1.0.12 → 2.0.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 +27 -1
- package/DEVELOP.md +28 -26
- package/README.md +19 -7
- package/docker-compose.yml +1 -1
- package/jest-addon.config.js +16 -4
- package/package.json +1 -1
- package/src/ChatBlock/hocs/withOnyxData.jsx +6 -2
- package/src/ChatBlock/packets/renderers/ImageToolRenderer.tsx +2 -2
- package/src/ChatBlock/tests/AIMessage.test.jsx +1 -1
- package/src/ChatBlock/tests/BlinkingDot.test.jsx +1 -1
- package/src/ChatBlock/tests/ChatMessage.test.jsx +1 -1
- package/src/ChatBlock/tests/Citation.test.jsx +1 -1
- package/src/ChatBlock/tests/ClaimModal.test.jsx +1 -1
- package/src/ChatBlock/tests/ClaimSegments.test.jsx +1 -1
- package/src/ChatBlock/tests/CustomToolRenderer.test.jsx +1 -1
- package/src/ChatBlock/tests/EmptyState.test.jsx +1 -1
- package/src/ChatBlock/tests/FeedbackModal.test.jsx +1 -1
- package/src/ChatBlock/tests/FetchToolRenderer.test.jsx +1 -1
- package/src/ChatBlock/tests/ImageToolRenderer.test.jsx +1 -1
- package/src/ChatBlock/tests/QualityCheckToggle.test.jsx +1 -1
- package/src/ChatBlock/tests/RelatedQuestions.test.jsx +1 -1
- package/src/ChatBlock/tests/RenderClaimView.test.jsx +1 -1
- package/src/ChatBlock/tests/SearchToolRenderer.test.jsx +1 -1
- package/src/ChatBlock/tests/Source.test.jsx +1 -1
- package/src/ChatBlock/tests/SourceChip.test.jsx +1 -1
- package/src/ChatBlock/tests/Spinner.test.jsx +1 -1
- package/src/ChatBlock/tests/UserActionsToolbar.test.jsx +1 -1
- package/src/ChatBlock/tests/UserMessage.test.jsx +1 -1
- package/src/ChatBlock/tests/WebResultIcon.test.jsx +1 -1
- package/src/ChatBlock/tests/index.test.js +1 -1
- package/src/ChatBlock/tests/schema.test.js +1 -1
- package/src/ChatBlock/tests/useDeepCompareMemoize.test.js +1 -1
- package/src/ChatBlock/tests/utils.test.jsx +1 -1
- package/src/ChatBlock/tests/withOnyxData.test.jsx +1 -1
- package/src/halloumi/filtering.js +12 -6
- package/src/halloumi/generative.js +12 -7
- package/src/halloumi/middleware.js +1 -0
- package/src/middleware.js +11 -6
- package/src/middleware.test.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,38 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [2.0.0](https://github.com/eea/volto-eea-chatbot/compare/1.0.13...2.0.0) - 16 March 2026
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: Volto 18 support - refs #287700 [Alin Voinea - [`e37ee8e`](https://github.com/eea/volto-eea-chatbot/commit/e37ee8e97e43c6108f336a341f31c4411fb22141)]
|
|
12
|
+
|
|
13
|
+
#### :bug: Bug Fixes
|
|
14
|
+
|
|
15
|
+
- fix(withOnyxData): handle API errors gracefully and set proper HTTP status codes [Claudia Ifrim - [`eec4e22`](https://github.com/eea/volto-eea-chatbot/commit/eec4e220649634714165857e5e14a6a444de4f92)]
|
|
16
|
+
|
|
17
|
+
#### :house: Internal changes
|
|
18
|
+
|
|
19
|
+
- style: Automated code fix [eea-jenkins - [`0579cad`](https://github.com/eea/volto-eea-chatbot/commit/0579cadfeb3f6f092f4bc66ffacebe59232e8650)]
|
|
20
|
+
|
|
21
|
+
#### :hammer_and_wrench: Others
|
|
22
|
+
|
|
23
|
+
- tests: Fix Sonar Qube tags - refs #297339 [Alin Voinea - [`958cd4f`](https://github.com/eea/volto-eea-chatbot/commit/958cd4f97fdd6892aa248083fb13bdf9313727bb)]
|
|
24
|
+
### [1.0.13](https://github.com/eea/volto-eea-chatbot/compare/1.0.12...1.0.13) - 4 March 2026
|
|
25
|
+
|
|
26
|
+
#### :house: Internal changes
|
|
27
|
+
|
|
28
|
+
- style: Automated code fix [eea-jenkins - [`8a8c3c4`](https://github.com/eea/volto-eea-chatbot/commit/8a8c3c4172a4f669661378cf1b5a3569d85609e6)]
|
|
29
|
+
|
|
30
|
+
#### :hammer_and_wrench: Others
|
|
31
|
+
|
|
32
|
+
- update [Miu Razvan - [`04e6c3f`](https://github.com/eea/volto-eea-chatbot/commit/04e6c3f776bb9920b89a014cc97f8e5dbb284a48)]
|
|
33
|
+
- update [Miu Razvan - [`f9e9beb`](https://github.com/eea/volto-eea-chatbot/commit/f9e9beb0676b215a50226a0db8c5be7c540f26ff)]
|
|
7
34
|
### [1.0.12](https://github.com/eea/volto-eea-chatbot/compare/1.0.11...1.0.12) - 23 February 2026
|
|
8
35
|
|
|
9
36
|
#### :house: Internal changes
|
|
10
37
|
|
|
11
38
|
- style: Automated code fix [eea-jenkins - [`fdcd884`](https://github.com/eea/volto-eea-chatbot/commit/fdcd8848fd4c3f990ca5ea021f407487aebd6010)]
|
|
12
|
-
- chore: [JENKINSFILE] use sonarqube branches [EEA Jenkins - [`3d428d7`](https://github.com/eea/volto-eea-chatbot/commit/3d428d72f32c3d05452b0961c76f5db1c416e05c)]
|
|
13
39
|
|
|
14
40
|
#### :hammer_and_wrench: Others
|
|
15
41
|
|
package/DEVELOP.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# volto-
|
|
1
|
+
# volto-eea-chatbot
|
|
2
2
|
|
|
3
3
|
## Develop
|
|
4
4
|
|
|
5
5
|
1. Make sure you have `docker` and `docker compose` installed and running on your machine:
|
|
6
6
|
|
|
7
7
|
```Bash
|
|
8
|
-
git clone https://github.com/eea/volto-
|
|
9
|
-
cd volto-
|
|
8
|
+
git clone https://github.com/eea/volto-eea-chatbot.git
|
|
9
|
+
cd volto-eea-chatbot
|
|
10
10
|
git checkout -b bugfix-123456 develop
|
|
11
11
|
make
|
|
12
12
|
make start
|
|
@@ -24,64 +24,66 @@
|
|
|
24
24
|
|
|
25
25
|
1. Happy hacking!
|
|
26
26
|
|
|
27
|
-
### Or add @eeacms/volto-
|
|
27
|
+
### Or add @eeacms/volto-eea-chatbot to your Volto project
|
|
28
28
|
|
|
29
|
-
Before starting make sure your development environment is properly set. See [Volto
|
|
29
|
+
Before starting make sure your development environment is properly set. See the official Plone documentation for [creating a project with Cookieplone](https://6.docs.plone.org/install/create-project-cookieplone.html) and [installing an add-on in development mode in Volto 18 and 19](https://6.docs.plone.org/volto/development/add-ons/install-an-add-on-dev-18.html).
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
For new Volto 18+ projects, use Cookieplone. It includes `mrs-developer` by default.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
1. Create a new Volto project with Cookieplone
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
yo @plone/volto my-volto-project --addon @eeacms/volto-addon-template --skip-install
|
|
38
|
-
cd my-volto-project
|
|
35
|
+
uvx cookieplone project
|
|
36
|
+
cd project-title
|
|
39
37
|
|
|
40
38
|
1. Add the following to `mrs.developer.json`:
|
|
41
39
|
|
|
42
40
|
{
|
|
43
|
-
"volto-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
41
|
+
"volto-eea-chatbot": {
|
|
42
|
+
"output": "packages",
|
|
43
|
+
"url": "https://github.com/eea/volto-eea-chatbot.git",
|
|
44
|
+
"package": "@eeacms/volto-eea-chatbot",
|
|
46
45
|
"branch": "develop",
|
|
47
46
|
"path": "src"
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
1.
|
|
50
|
+
1. Add `@eeacms/volto-eea-chatbot` to the `addons` key in your project `package.json`
|
|
51
|
+
|
|
52
|
+
1. Install or refresh the project setup
|
|
52
53
|
|
|
53
|
-
make
|
|
54
|
-
yarn
|
|
54
|
+
make install
|
|
55
55
|
|
|
56
|
-
1. Start backend
|
|
56
|
+
1. Start backend in one terminal
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
make backend-start
|
|
59
59
|
|
|
60
|
-
...wait for backend to setup and start
|
|
60
|
+
...wait for backend to setup and start, ending with `Ready to handle requests`
|
|
61
61
|
|
|
62
62
|
...you can also check http://localhost:8080/Plone
|
|
63
63
|
|
|
64
|
-
1. Start frontend
|
|
64
|
+
1. Start frontend in a second terminal
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
make frontend-start
|
|
67
67
|
|
|
68
68
|
1. Go to http://localhost:3000
|
|
69
69
|
|
|
70
70
|
1. Happy hacking!
|
|
71
71
|
|
|
72
|
-
cd
|
|
72
|
+
cd packages/volto-eea-chatbot
|
|
73
|
+
|
|
74
|
+
For legacy Volto 17 projects, keep using the yarn-based workflow from the Volto 17 documentation.
|
|
73
75
|
|
|
74
76
|
## Cypress
|
|
75
77
|
|
|
76
78
|
To run cypress locally, first make sure you don't have any Volto/Plone running on ports `8080` and `3000`.
|
|
77
79
|
|
|
78
80
|
You don't have to be in a `clean-volto-project`, you can be in any Volto Frontend
|
|
79
|
-
project where you added `volto-
|
|
81
|
+
project where you added `volto-eea-chatbot` to `mrs.developer.json`
|
|
80
82
|
|
|
81
83
|
Go to:
|
|
82
84
|
|
|
83
85
|
```BASH
|
|
84
|
-
cd
|
|
86
|
+
cd packages/volto-eea-chatbot/
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
Start:
|
|
@@ -91,7 +93,7 @@ make
|
|
|
91
93
|
make start
|
|
92
94
|
```
|
|
93
95
|
|
|
94
|
-
This will build and start with Docker a clean `Plone backend` and `Volto Frontend` with `volto-
|
|
96
|
+
This will build and start with Docker a clean `Plone backend` and `Volto Frontend` with `volto-eea-chatbot` block installed.
|
|
95
97
|
|
|
96
98
|
Open Cypress Interface:
|
|
97
99
|
|
package/README.md
CHANGED
|
@@ -67,6 +67,11 @@ make start
|
|
|
67
67
|
|
|
68
68
|
Go to http://localhost:3000
|
|
69
69
|
|
|
70
|
+
`make start` now defaults to Volto 18. To run the same setup against Volto 17, use:
|
|
71
|
+
|
|
72
|
+
VOLTO_VERSION=17 make
|
|
73
|
+
VOLTO_VERSION=17 make start
|
|
74
|
+
|
|
70
75
|
### Add volto-eea-chatbot to your Volto project
|
|
71
76
|
|
|
72
77
|
1. Make sure you have a [Plone backend](https://plone.org/download) up-and-running at http://localhost:8080/Plone
|
|
@@ -89,21 +94,28 @@ Go to http://localhost:3000
|
|
|
89
94
|
}
|
|
90
95
|
```
|
|
91
96
|
|
|
92
|
-
- If not, create one
|
|
97
|
+
- If not, create one with Cookieplone, as recommended by the official Plone documentation for Volto 18+:
|
|
93
98
|
|
|
94
99
|
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
cd my-volto-project
|
|
100
|
+
uvx cookieplone project
|
|
101
|
+
cd project-title
|
|
98
102
|
```
|
|
99
103
|
|
|
100
|
-
1. Install
|
|
104
|
+
1. Install or update dependencies, then start the project:
|
|
101
105
|
|
|
102
106
|
```
|
|
103
|
-
|
|
104
|
-
yarn start
|
|
107
|
+
make install
|
|
105
108
|
```
|
|
106
109
|
|
|
110
|
+
For a Cookieplone project, start the backend and frontend in separate terminals:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
make backend-start
|
|
114
|
+
make frontend-start
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For a legacy Volto 17 project, install the package with `yarn` and restart the frontend as usual.
|
|
118
|
+
|
|
107
119
|
## Environment Configuration
|
|
108
120
|
|
|
109
121
|
To properly configure the middleware and authenticate with the Onyx service, ensure that the following environment variables are set:
|
package/docker-compose.yml
CHANGED
package/jest-addon.config.js
CHANGED
|
@@ -27,6 +27,20 @@ const addonName =
|
|
|
27
27
|
? pathParts[addonsIdx + 1]
|
|
28
28
|
: path.basename(path.dirname(__filename)); // Fallback to folder name
|
|
29
29
|
const addonBasePath = `src/addons/${addonName}/src`;
|
|
30
|
+
const voltoSlatePath = fs.existsSync(
|
|
31
|
+
path.join(
|
|
32
|
+
__dirname,
|
|
33
|
+
'..',
|
|
34
|
+
'..',
|
|
35
|
+
'..',
|
|
36
|
+
'node_modules',
|
|
37
|
+
'@plone',
|
|
38
|
+
'volto-slate',
|
|
39
|
+
'src',
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
? '<rootDir>/node_modules/@plone/volto-slate/src'
|
|
43
|
+
: '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src';
|
|
30
44
|
|
|
31
45
|
// --- Performance caches ---
|
|
32
46
|
const fileSearchCache = new Map();
|
|
@@ -421,10 +435,8 @@ module.exports = {
|
|
|
421
435
|
'@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
|
|
422
436
|
'@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
|
|
423
437
|
'@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
|
|
424
|
-
'@plone/volto-slate$':
|
|
425
|
-
|
|
426
|
-
'@plone/volto-slate/(.*)$':
|
|
427
|
-
'<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
|
|
438
|
+
'@plone/volto-slate$': voltoSlatePath,
|
|
439
|
+
'@plone/volto-slate/(.*)$': `${voltoSlatePath}/$1`,
|
|
428
440
|
'~/(.*)$': '<rootDir>/src/$1',
|
|
429
441
|
'load-volto-addons':
|
|
430
442
|
'<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
|
package/package.json
CHANGED
|
@@ -25,8 +25,12 @@ export default function withOnyxData(callback) {
|
|
|
25
25
|
React.useEffect(() => {
|
|
26
26
|
async function handler() {
|
|
27
27
|
if (fetcher) {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetcher;
|
|
30
|
+
setState({ [name]: response.body });
|
|
31
|
+
} catch (error) {
|
|
32
|
+
setState({ [`${name}-error`]: error.message, [name]: null });
|
|
33
|
+
}
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
handler();
|
|
@@ -45,9 +45,9 @@ export const ImageToolRenderer: MessageRenderer<ImageGenerationToolPacket> = ({
|
|
|
45
45
|
alt={image.revised_prompt}
|
|
46
46
|
className={`image-shape-${image.shape || 'square'}`}
|
|
47
47
|
/>
|
|
48
|
-
{image.revised_prompt
|
|
48
|
+
{image.revised_prompt ? (
|
|
49
49
|
<div className="image-prompt">{image.revised_prompt}</div>
|
|
50
|
-
)}
|
|
50
|
+
) : null}
|
|
51
51
|
</div>
|
|
52
52
|
))}
|
|
53
53
|
</div>
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import { AIMessage } from '../chat/AIMessage';
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import { BlinkingDot } from '../components/BlinkingDot';
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import { ChatMessage } from '../chat/ChatMessage';
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import { Citation } from '../components/markdown/Citation';
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { CustomToolRenderer } from '../packets/renderers/CustomToolRenderer';
|
|
5
5
|
import { PacketType } from '../types/streamingModels';
|
|
6
6
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import EmptyState from '../components/EmptyState';
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { FetchToolRenderer } from '../packets/renderers/FetchToolRenderer';
|
|
5
5
|
import { PacketType } from '../types/streamingModels';
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { ImageToolRenderer } from '../packets/renderers/ImageToolRenderer';
|
|
5
5
|
import { PacketType } from '../types/streamingModels';
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import QualityCheckToggle from '../components/QualityCheckToggle';
|
|
5
5
|
|
|
6
6
|
describe('QualityCheckToggle', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import RelatedQuestions from '../components/RelatedQuestions';
|
|
5
5
|
|
|
6
6
|
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer from 'react-test-renderer';
|
|
3
3
|
import { render, screen } from '@testing-library/react';
|
|
4
|
-
import '@testing-library/jest-dom
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
5
|
import { RenderClaimView } from '../components/markdown/RenderClaimView';
|
|
6
6
|
|
|
7
7
|
describe('RenderClaimView', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
import { SearchToolRenderer } from '../packets/renderers/SearchToolRenderer';
|
|
5
5
|
import { PacketType } from '../types/streamingModels';
|
|
6
6
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import SourceDetails from '../components/Source';
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
3
|
import { render, fireEvent, screen } from '@testing-library/react';
|
|
4
|
-
import '@testing-library/jest-dom
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
5
|
import { SourceChip } from '../components/SourceChip';
|
|
6
6
|
|
|
7
7
|
describe('SourceChip', () => {
|
|
@@ -3,7 +3,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
3
3
|
import configureStore from 'redux-mock-store';
|
|
4
4
|
import renderer from 'react-test-renderer';
|
|
5
5
|
import { render, fireEvent, screen } from '@testing-library/react';
|
|
6
|
-
import '@testing-library/jest-dom
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
7
|
import { Provider } from 'react-intl-redux';
|
|
8
8
|
import UserActionsToolbar from '../components/UserActionsToolbar';
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|
|
2
2
|
import configureStore from 'redux-mock-store';
|
|
3
3
|
import renderer from 'react-test-renderer';
|
|
4
4
|
|
|
5
|
-
import '@testing-library/jest-dom
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
6
|
import { Provider } from 'react-intl-redux';
|
|
7
7
|
import { UserMessage } from '../chat/UserMessage';
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer from 'react-test-renderer';
|
|
3
3
|
import { render, fireEvent, screen } from '@testing-library/react';
|
|
4
|
-
import '@testing-library/jest-dom
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
5
|
import { WebResultIcon } from '../components/WebResultIcon';
|
|
6
6
|
|
|
7
7
|
describe('WebResultIcon', () => {
|
|
@@ -13,7 +13,7 @@ const filterModel = {
|
|
|
13
13
|
apiKey: LLMGW_API_KEY,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export async function callLLM(apiUrl, apiKey, requestBody) {
|
|
16
|
+
export async function callLLM(apiUrl, apiKey, requestBody, { ip } = {}) {
|
|
17
17
|
const headers = {
|
|
18
18
|
'Content-Type': 'application/json',
|
|
19
19
|
accept: 'application/json',
|
|
@@ -21,6 +21,9 @@ export async function callLLM(apiUrl, apiKey, requestBody) {
|
|
|
21
21
|
if (apiKey) {
|
|
22
22
|
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
23
23
|
}
|
|
24
|
+
if (ip) {
|
|
25
|
+
headers['X-Forwarded-For'] = ip;
|
|
26
|
+
}
|
|
24
27
|
|
|
25
28
|
const response = await fetch(apiUrl, {
|
|
26
29
|
method: 'POST',
|
|
@@ -92,24 +95,26 @@ export function parseExcludeIndices(content, maxIndex) {
|
|
|
92
95
|
return excludeIndices;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
async function callFilterModel(prompt) {
|
|
98
|
+
async function callFilterModel(prompt, { ip } = {}) {
|
|
96
99
|
const data = {
|
|
97
100
|
messages: [{ role: 'user', content: prompt }],
|
|
98
101
|
temperature: 0.0,
|
|
99
102
|
model: filterModel.name,
|
|
100
103
|
};
|
|
101
|
-
const jsonData = await callLLM(filterModel.apiUrl, filterModel.apiKey, data
|
|
104
|
+
const jsonData = await callLLM(filterModel.apiUrl, filterModel.apiKey, data, {
|
|
105
|
+
ip,
|
|
106
|
+
});
|
|
102
107
|
return jsonData.choices?.[0]?.message?.content || '';
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
export async function excludeClaimSentences(sentences) {
|
|
110
|
+
export async function excludeClaimSentences(sentences, { ip } = {}) {
|
|
106
111
|
if (sentences.length === 0) {
|
|
107
112
|
return new Set();
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
try {
|
|
111
116
|
const prompt = buildClaimFilterPrompt(sentences);
|
|
112
|
-
const content = await callFilterModel(prompt);
|
|
117
|
+
const content = await callFilterModel(prompt, { ip });
|
|
113
118
|
const excludedIndices = parseExcludeIndices(content, sentences.length);
|
|
114
119
|
log('Claim filter response', excludedIndices.size);
|
|
115
120
|
return excludedIndices;
|
|
@@ -122,6 +127,7 @@ export async function excludeClaimSentences(sentences) {
|
|
|
122
127
|
export async function excludeContextSentences(
|
|
123
128
|
contextSentences,
|
|
124
129
|
claimSentences,
|
|
130
|
+
{ ip } = {},
|
|
125
131
|
) {
|
|
126
132
|
if (contextSentences.length <= MIN_CONTEXT_SENTENCES_FOR_FILTERING) {
|
|
127
133
|
return new Set();
|
|
@@ -129,7 +135,7 @@ export async function excludeContextSentences(
|
|
|
129
135
|
|
|
130
136
|
try {
|
|
131
137
|
const prompt = buildContextFilterPrompt(contextSentences, claimSentences);
|
|
132
|
-
const content = await callFilterModel(prompt);
|
|
138
|
+
const content = await callFilterModel(prompt, { ip });
|
|
133
139
|
const excludedIndices = parseExcludeIndices(
|
|
134
140
|
content,
|
|
135
141
|
contextSentences.length,
|
|
@@ -52,7 +52,12 @@ function mergeChunkClaims(chunkResults) {
|
|
|
52
52
|
return Array.from(claimMap.values());
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export async function getVerifyClaimResponse(
|
|
55
|
+
export async function getVerifyClaimResponse(
|
|
56
|
+
model,
|
|
57
|
+
sources,
|
|
58
|
+
answer,
|
|
59
|
+
{ ip } = {},
|
|
60
|
+
) {
|
|
56
61
|
const emptyResponse = {
|
|
57
62
|
claims: [],
|
|
58
63
|
segments: {},
|
|
@@ -67,7 +72,7 @@ export async function getVerifyClaimResponse(model, sources, answer) {
|
|
|
67
72
|
|
|
68
73
|
// Filter claims and context in parallel
|
|
69
74
|
const [excludeResponseIndices] = await Promise.all([
|
|
70
|
-
excludeClaimSentences(responseSentences),
|
|
75
|
+
excludeClaimSentences(responseSentences, { ip }),
|
|
71
76
|
]);
|
|
72
77
|
|
|
73
78
|
const contextSentences = [];
|
|
@@ -109,7 +114,7 @@ export async function getVerifyClaimResponse(model, sources, answer) {
|
|
|
109
114
|
const chunkResults = await Promise.all(
|
|
110
115
|
prompts.map((chunkPrompt, i) => {
|
|
111
116
|
log(`Chunk ${i + 1} request`);
|
|
112
|
-
return halloumiGenerativeAPI(model, chunkPrompt);
|
|
117
|
+
return halloumiGenerativeAPI(model, chunkPrompt, { ip });
|
|
113
118
|
}),
|
|
114
119
|
);
|
|
115
120
|
|
|
@@ -166,7 +171,7 @@ export async function getVerifyClaimResponse(model, sources, answer) {
|
|
|
166
171
|
* - `DUMP_HALLOUMI_REQ_FILE_PATH`: If set, the LLM request (URL and parameters) is dumped to the specified file path.
|
|
167
172
|
* - `DUMP_HALLOUMI_FILE_PATH`: If set, the LLM response is dumped to the specified file path.
|
|
168
173
|
*/
|
|
169
|
-
async function getLLMResponse(model, prompt) {
|
|
174
|
+
async function getLLMResponse(model, prompt, { ip } = {}) {
|
|
170
175
|
let jsonData;
|
|
171
176
|
|
|
172
177
|
if (process.env.MOCK_HALLOUMI_FILE_PATH) {
|
|
@@ -194,7 +199,7 @@ async function getLLMResponse(model, prompt) {
|
|
|
194
199
|
log(`Dumped halloumi request: ${filePath}`);
|
|
195
200
|
}
|
|
196
201
|
|
|
197
|
-
jsonData = await callLLM(model.apiUrl, model.apiKey, data);
|
|
202
|
+
jsonData = await callLLM(model.apiUrl, model.apiKey, data, { ip });
|
|
198
203
|
|
|
199
204
|
if (process.env.DUMP_HALLOUMI_FILE_PATH) {
|
|
200
205
|
const filePath = process.env.DUMP_HALLOUMI_FILE_PATH;
|
|
@@ -210,8 +215,8 @@ async function getLLMResponse(model, prompt) {
|
|
|
210
215
|
* @param response A string containing all claims and their information.
|
|
211
216
|
* @returns A list of claim objects.
|
|
212
217
|
*/
|
|
213
|
-
export async function halloumiGenerativeAPI(model, prompt) {
|
|
214
|
-
const jsonData = await getLLMResponse(model, prompt);
|
|
218
|
+
export async function halloumiGenerativeAPI(model, prompt, { ip } = {}) {
|
|
219
|
+
const jsonData = await getLLMResponse(model, prompt, { ip });
|
|
215
220
|
|
|
216
221
|
// Todo: restore log
|
|
217
222
|
// log('Generative response', jsonData);
|
package/src/middleware.js
CHANGED
|
@@ -151,6 +151,7 @@ async function send_onyx_request(
|
|
|
151
151
|
res,
|
|
152
152
|
{ username, password, api_key, url, is_related_question },
|
|
153
153
|
) {
|
|
154
|
+
const forwardedFor = req.headers['x-forwarded-for'] || req.ip;
|
|
154
155
|
let headers = {};
|
|
155
156
|
if (!api_key) {
|
|
156
157
|
await login(username, password);
|
|
@@ -166,11 +167,13 @@ async function send_onyx_request(
|
|
|
166
167
|
headers = {
|
|
167
168
|
Cookie: cached_auth_cookie,
|
|
168
169
|
'Content-Type': 'application/json',
|
|
170
|
+
'X-Forwarded-For': forwardedFor,
|
|
169
171
|
};
|
|
170
172
|
} else {
|
|
171
173
|
headers = {
|
|
172
174
|
Authorization: 'Bearer ' + api_key,
|
|
173
175
|
'Content-Type': 'application/json',
|
|
176
|
+
'X-Forwarded-For': forwardedFor,
|
|
174
177
|
};
|
|
175
178
|
}
|
|
176
179
|
|
|
@@ -237,9 +240,9 @@ export default async function middleware(req, res, next) {
|
|
|
237
240
|
|
|
238
241
|
const api_key = process.env.ONYX_API_KEY;
|
|
239
242
|
if (!api_key) {
|
|
240
|
-
res.
|
|
241
|
-
|
|
242
|
-
});
|
|
243
|
+
res.statusCode = 500;
|
|
244
|
+
res.statusMessage = MSG_INVALID_CONFIGURATION;
|
|
245
|
+
res.send({ error: MSG_INVALID_CONFIGURATION });
|
|
243
246
|
return;
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -251,8 +254,10 @@ export default async function middleware(req, res, next) {
|
|
|
251
254
|
});
|
|
252
255
|
} catch (error) {
|
|
253
256
|
// eslint-disable-next-line
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
res.
|
|
257
|
+
const errorMessage = `Onyx error: ${error?.response?.text || 'error'}`;
|
|
258
|
+
console.error(MSG_ERROR_REQUEST, errorMessage);
|
|
259
|
+
res.statusCode = 500;
|
|
260
|
+
res.statusMessage = errorMessage;
|
|
261
|
+
res.send({ error: errorMessage });
|
|
257
262
|
}
|
|
258
263
|
}
|