Skip to content

Commit f8f641b

Browse files
Azure Open AI V1 (#515)
* Azure Open AI V1 * Slash check * Deployment url add * code reviewed and removed duplication by extending azureOpenAi with OpenAiClient * Resolving Review * Solve smells --------- Co-authored-by: Alfred Rubin <[email protected]>
1 parent fbc5158 commit f8f641b

File tree

12 files changed

+249
-27
lines changed

12 files changed

+249
-27
lines changed

cypress/support/index.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// ***********************************************************
2+
// This example support/index.js is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands';
18+
19+
// Alternatively you can use CommonJS syntax:
20+
// require('./commands')

docs/modules/ROOT/pages/user-guide/extensions/natural-language-queries.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ To enable Natural Language Queries in NeoDash, follow these configuration steps:
1111
1. Open NeoDash and navigate to the "Extensions" section in the left sidebar.
1212
2. Locate the "Natural Language Queries" extension and click on it to activate it.
1313
3. Once activated, a new button will appear in the sidebar(see image below). Click on the button to open the configuration window.
14-
4. In the configuration window, you will be prompted to provide the necessary information to connect to the Language Model (LLM). Enter the model provider, API key, and select the desired model to use.
14+
4. In the configuration window, you will be prompted to provide the necessary information to connect to the Language Model (LLM). Enter the model provider, API key, deployment url if needed by the model provider, and select the desired model to use.
1515
5. After providing the required information, click on the "Start Querying" button to finalize the configuration.
1616

1717
image::extensionbutton.png[Extension Button enables Natural Language Queries button in the sidebar]

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"keywords": [],
3535
"author": "Neo4j Labs",
3636
"dependencies": {
37+
"@azure/openai": "^1.0.0-beta.2",
3738
"@codemirror/lang-markdown": "^6.1.1",
3839
"@codemirror/language-data": "^6.3.1",
3940
"@mui/icons-material": "^5.11.16",

src/dashboard/drawer/DashboardDrawer.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@ export const NeoDrawer = ({
5151
function renderDrawerExtensionsButtons() {
5252
const res = (
5353
<>
54-
{Object.keys(EXTENSIONS_DRAWER_BUTTONS).map((name) => {
54+
{Object.keys(EXTENSIONS_DRAWER_BUTTONS).map((name, idx) => {
5555
const Component = extensions[name] ? EXTENSIONS_DRAWER_BUTTONS[name] : '';
56-
return Component ? <Component database={connection.database} navItemClass={navItemClass} /> : <></>;
56+
return Component ? (
57+
<Component key={`ext-${ idx}`} database={connection.database} navItemClass={navItemClass} />
58+
) : (
59+
<></>
60+
);
5761
})}
5862
</>
5963
);

src/extensions/query-translator/QueryTranslatorConfig.ts

+28-23
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { OpenAiClient } from './clients/OpenAi/OpenAiClient';
44

55
// TODO: implement VertexAiClient
66
import { VertexAiClient } from './clients/VertexAiClient';
7+
import { AzureOpenAiClient } from './clients/AzureOpenAi/AzureOpenAiClient';
78

89
interface ClientSettingEntry {
910
label: string;
@@ -58,29 +59,33 @@ export const QUERY_TRANSLATOR_CONFIG: QueryTranslatorConfig = {
5859
},
5960
},
6061
},
61-
// vertexAi: {
62-
// clientName: "vertexAi",
63-
// clientClass: VertexAiClient,
64-
// settings: {
65-
// apiKey: {
66-
// label: 'Api Key to authenticate the client',
67-
// type: SELECTION_TYPES.TEXT,
68-
// default: '',
69-
// },
70-
// modelType: {
71-
// label: 'Select from the possible model types',
72-
// type: SELECTION_TYPES.LIST,
73-
// needsStateValues: true,
74-
// default: "Insert your Api Key first",
75-
// },
76-
// region: {
77-
// label: 'GCP Region',
78-
// type: SELECTION_TYPES.LIST,
79-
// needsStateValues: true,
80-
// default: [],
81-
// }
82-
// }
83-
// },
62+
AzureOpenAI: {
63+
clientName: 'AzureOpenAI',
64+
clientClass: AzureOpenAiClient,
65+
settings: {
66+
endpoint: {
67+
label: 'Azure OpenAI EndPoint',
68+
type: SELECTION_TYPES.TEXT,
69+
default: '',
70+
hasAuthButton: false,
71+
authentication: true,
72+
},
73+
apiKey: {
74+
label: 'Subscription Key',
75+
type: SELECTION_TYPES.TEXT,
76+
default: '',
77+
hasAuthButton: true,
78+
authentication: true,
79+
},
80+
modelType: {
81+
label: 'Model',
82+
type: SELECTION_TYPES.LIST,
83+
methodFromClient: 'getListModels',
84+
default: '',
85+
authentication: false,
86+
},
87+
},
88+
},
8489
},
8590
};
8691

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { AzureKeyCredential, OpenAIClient } from '@azure/openai';
2+
3+
import { OpenAiClient } from '../OpenAi/OpenAiClient';
4+
5+
const consoleLogAsync = async (message: string, other?: any) => {
6+
await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other));
7+
};
8+
9+
export class AzureOpenAiClient extends OpenAiClient {
10+
modelType: string | undefined;
11+
12+
createSystemMessage: any;
13+
14+
modelClient!: OpenAIClient;
15+
16+
driver: any;
17+
18+
constructor(settings) {
19+
super(settings);
20+
}
21+
22+
/**
23+
* Function used to create the OpenAiApi object.
24+
* */
25+
setModelClient() {
26+
if (typeof this.endpoint === 'string') {
27+
this.modelClient = new OpenAIClient(this.endpoint, new AzureKeyCredential(this.apiKey));
28+
}
29+
}
30+
31+
async getListModels() {
32+
let res;
33+
try {
34+
if (!this.modelClient) {
35+
throw new Error('no client defined');
36+
}
37+
38+
const response = await fetch(
39+
`${this.endpoint + (this.endpoint?.endsWith('/') ? '' : '/')}openai/deployments?api-version=2023-03-15-preview`,
40+
{
41+
method: 'GET',
42+
mode: 'cors',
43+
headers: {
44+
'Api-Key': this.apiKey,
45+
},
46+
}
47+
);
48+
const req = await response.json();
49+
res = req.data.filter((x) => x.model.startsWith('gpt-')).map((x) => x.id);
50+
} catch (e) {
51+
consoleLogAsync('Error while loading the model list: ', e);
52+
res = [];
53+
}
54+
this.setListAvailableModels(res);
55+
return res;
56+
}
57+
58+
async chatCompletion(history) {
59+
let completion;
60+
if (typeof this.modelType === 'string') {
61+
completion = await this.modelClient.getChatCompletions(this.modelType, history);
62+
}
63+
// If the status is correct
64+
if (completion?.choices?.[0]?.message || false) {
65+
let { message } = completion.choices[0];
66+
return message;
67+
}
68+
throw Error(`Request returned with status: ${completion.id}`);
69+
}
70+
}
Loading

src/extensions/query-translator/clients/ModelClient.ts

+3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ export abstract class ModelClient {
2121

2222
driver: any;
2323

24+
endpoint: string | undefined;
25+
2426
constructor(settings) {
2527
this.apiKey = settings.apiKey;
2628
this.modelType = settings.modelType;
2729
this.listAvailableModels = [];
30+
this.endpoint = settings.endpoint;
2831
this.setModelClient();
2932
}
3033

src/extensions/query-translator/clients/OpenAi/OpenAiClient.ts

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export class OpenAiClient extends ModelClient {
8383
consoleLogAsync('Error while loading the model list: ', e);
8484
res = [];
8585
}
86+
this.setListAvailableModels(res);
8687
return res;
8788
}
8889

src/extensions/query-translator/component/ClientSettings.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export const ClientSettings = ({
118118
// Prevent authentication if all required fields are not full (EX: look at checkIfDisabled)
119119
const authButton = (
120120
<IconButton
121+
key={'auth-setting'}
121122
aria-label='connect'
122123
onClick={(e) => {
123124
e.preventDefault();
@@ -152,7 +153,7 @@ export const ClientSettings = ({
152153
.map((setting) => {
153154
let disabled = checkIfDisabled(setting);
154155
return (
155-
<ListItem style={{ padding: 0 }}>
156+
<ListItem key={`list-${ setting}`} style={{ padding: 0 }}>
156157
<NeoSetting
157158
key={setting}
158159
style={{ marginLeft: 0, marginRight: 0 }}

tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"noEmit": true,
1616
"jsx": "react",
1717
"noImplicitAny": false,
18+
"useDefineForClassFields": false,
1819
"noFallthroughCasesInSwitch": true
1920
},
2021
"include": ["src"]

0 commit comments

Comments
 (0)