@christianriedl/utils 1.0.130 → 1.0.132
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/dist/iOpenAI.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/OpenAI.vue +37 -1
- package/src/components/OpenAIConfig.vue +139 -36
package/dist/iOpenAI.d.ts
CHANGED
|
@@ -86,7 +86,8 @@ export interface IOpenAIServiceWithVectorStore extends IOpenAIServiceWithTools {
|
|
|
86
86
|
vectorStore?: Dictionary<IVectorStore>;
|
|
87
87
|
initializeVectorStore(): Promise<boolean>;
|
|
88
88
|
getVectorStore(vectorStoreId: string): IVectorStore | undefined;
|
|
89
|
-
|
|
89
|
+
addVectorStore(vectorStoreName: string): Promise<boolean>;
|
|
90
|
+
addFile(fileUrl: string, vectorStoreName: string, wait?: boolean): Promise<boolean>;
|
|
90
91
|
deleteFile(fileId: string): Promise<boolean>;
|
|
91
92
|
deleteVectorStore(vectorStoreId: string): Promise<boolean>;
|
|
92
93
|
getFileId(fileUrl: string): string | undefined;
|
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const getOpenAI = inject(getOpenAISymbol)!;
|
|
16
16
|
const openAI = getOpenAI();
|
|
17
17
|
const appState = inject(appStateSymbol)!;
|
|
18
|
+
const isMobile = appState.isMobile && (appState.device != EDevice.iPad);
|
|
18
19
|
const appConfig = inject(appConfigSymbol)!;
|
|
19
20
|
const question = toRef(props, "prompt");
|
|
20
21
|
const replyLines = ref<string[]>([]);
|
|
@@ -58,9 +59,23 @@
|
|
|
58
59
|
}
|
|
59
60
|
if (answer && answer.text) {
|
|
60
61
|
emits('result', answer.text);
|
|
62
|
+
if (openAI.options.outputFormat == 'markdown') {
|
|
63
|
+
const html = await markdownToHtml(answer.text);
|
|
64
|
+
if (html) {
|
|
65
|
+
htmlText.value = html;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
61
69
|
if (openAI.options.outputFormat == 'html') {
|
|
62
70
|
|
|
63
71
|
const tempDiv = document.createElement('div');
|
|
72
|
+
if (answer.text.startsWith('```html\n')) {
|
|
73
|
+
if (answer.text.endsWith('\n```')) {
|
|
74
|
+
answer.text = answer.text.substring(8, answer.text.length - 12);
|
|
75
|
+
} else {
|
|
76
|
+
answer.text = answer.text.substring(8);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
64
79
|
tempDiv.innerHTML = answer.text;
|
|
65
80
|
const body = tempDiv.querySelector('body');
|
|
66
81
|
if (body) {
|
|
@@ -114,6 +129,27 @@
|
|
|
114
129
|
function onUse(tools: string[], persist: boolean) {
|
|
115
130
|
emits('use', tools, persist);
|
|
116
131
|
}
|
|
132
|
+
// Move to some library
|
|
133
|
+
async function markdownToHtml(markdownText: string): Promise<string> {
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch('https://www.christian-riedl.com/media/apimedia/markdown2html', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'application/json'
|
|
139
|
+
},
|
|
140
|
+
body: JSON.stringify({ markdown: markdownText })
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new Error(`Server error: ${response.status}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return await response.text();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Error sending markdown:', error);
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
117
153
|
</script>
|
|
118
154
|
|
|
119
155
|
<template>
|
|
@@ -165,7 +201,7 @@
|
|
|
165
201
|
<v-col cols="12">{{line}}</v-col>
|
|
166
202
|
</v-row>
|
|
167
203
|
<v-dialog v-model="showConfig">
|
|
168
|
-
<OpenAIConfig :tools="props.tools" @use="onUse" @back="showConfig=false"></OpenAIConfig>
|
|
204
|
+
<OpenAIConfig :tools="props.tools" :ismobile="isMobile" @use="onUse" @back="showConfig=false"></OpenAIConfig>
|
|
169
205
|
</v-dialog>
|
|
170
206
|
</v-container>
|
|
171
207
|
</template>
|
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
import { appConfigSymbol, AppConfig, Dictionary } from '@christianriedl/utils';
|
|
4
4
|
import { getOpenAISymbol, IOpenAIServiceWithVectorStore, IOpenAIAppConfig, IOpenAIOptions, ITool } from '@christianriedl/utils';
|
|
5
5
|
|
|
6
|
-
const props = defineProps<{ tools?: string[] }>();
|
|
7
|
-
const emits = defineEmits<{
|
|
8
|
-
(e: 'use', tools: string[], persist: boolean): void,
|
|
9
|
-
(e: 'back'): void
|
|
10
|
-
}>();
|
|
6
|
+
const props = defineProps<{ tools?: string[], ismobile: boolean }>();
|
|
7
|
+
const emits = defineEmits<{ (e: 'use', tools: string[], persist: boolean): void, (e: 'back'): void }>();
|
|
11
8
|
|
|
12
9
|
const getOpenAI = inject(getOpenAISymbol)!;
|
|
13
10
|
const openAI = getOpenAI() as IOpenAIServiceWithVectorStore;
|
|
@@ -22,14 +19,18 @@
|
|
|
22
19
|
const outputFormats = ['text', 'markdown', 'html'];
|
|
23
20
|
const reasoningEffortLevels = ['minimum', 'low', 'medium', 'high', null];
|
|
24
21
|
const mcpApprovals = ['always', 'never', null];
|
|
25
|
-
const vectorStoreNames: string[] = [];
|
|
26
22
|
const fileSearch = reactive<Dictionary<string[]>>({});
|
|
23
|
+
const vectorStoreNames = ref<string[]>([]);
|
|
24
|
+
const vectorStoreFiles = ref<string[]>([]);
|
|
25
|
+
const selectedVectorStoreName = ref('');
|
|
26
|
+
const selectedVectorStoreFile = ref('');
|
|
27
27
|
|
|
28
28
|
initializeTools();
|
|
29
29
|
|
|
30
30
|
function initializeTools() {
|
|
31
|
+
vectorStoreNames.value.splice(0, vectorStoreNames.value.length);
|
|
31
32
|
for (const key in openAI.vectorStore) {
|
|
32
|
-
vectorStoreNames.
|
|
33
|
+
vectorStoreNames.value.splice(vectorStoreNames.value.length, 0, key);
|
|
33
34
|
}
|
|
34
35
|
for (const key in tools) {
|
|
35
36
|
const tool = tools[key];
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
const names = [];
|
|
42
43
|
for (let i = 0; i < tool.vector_store_ids.length; i++) {
|
|
43
44
|
const vs = openAI.getVectorStore(tool.vector_store_ids[i]);
|
|
44
|
-
if (vs
|
|
45
|
+
if (vs) {
|
|
45
46
|
names.push(vs.name);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -97,6 +98,67 @@
|
|
|
97
98
|
emits('use', useTools, persist);
|
|
98
99
|
useChanged.value = false;
|
|
99
100
|
}
|
|
101
|
+
function vectorStoreSelected() {
|
|
102
|
+
const vs = openAI.getVectorStore(selectedVectorStoreName.value);
|
|
103
|
+
vectorStoreFiles.value.splice(0, vectorStoreFiles.value.length;
|
|
104
|
+
if (vs) {
|
|
105
|
+
vectorStoreFiles.value.splice(0, 0, ...vs.files.map(file => file.name);
|
|
106
|
+
if (vs.files.length > 0) {
|
|
107
|
+
selectedVectorStoreFile.value = vs.files[0].name;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function addVectorStore() {
|
|
112
|
+
if (openAI.vectorStore![selectedVectorStoreName.value]) {
|
|
113
|
+
alert('Vector Store already exists, add a new name !');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!openAI.addVectorStore(selectedVectorStoreName.value)) {
|
|
117
|
+
alert('Vector Store not added, error ! ');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
initializeTools();
|
|
121
|
+
}
|
|
122
|
+
async function deleteVectorStore() {
|
|
123
|
+
const id = openAI.vectorStore![selectedVectorStoreName.value]);
|
|
124
|
+
if (!openAI.deleteVectorStore(id)) {
|
|
125
|
+
alert('Vector Store not deleted, error ! ');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
initializeTools();
|
|
129
|
+
}
|
|
130
|
+
async function addFile() {
|
|
131
|
+
if (openAI.getFileId(selectedVectorStoreFile.value)) {
|
|
132
|
+
alert('File already exists, add a new file path or url !');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!await openAI.addFile(selectedVectorStoreFile.value, selectedVectorStoreName.value)) {
|
|
136
|
+
alert('File not added, error ! ');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function deleteFile() {
|
|
140
|
+
const fileId = openAI.getFileId(selectedVectorStoreFile.value);
|
|
141
|
+
if (!fileId) {
|
|
142
|
+
alert('File not existing !');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!await openAI.deleteFile(fileId)) {
|
|
146
|
+
alert('File not deleted, error ! ');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function searchFile() {
|
|
150
|
+
let files: FileSystemFileHandle[] = [];
|
|
151
|
+
try {
|
|
152
|
+
files = await (window as any).showOpenFilePicker();
|
|
153
|
+
if (files.length > 0) {
|
|
154
|
+
selectedVectorStoreFile.value = files[0].name;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
console.error('Error opening file picker:', e);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
100
162
|
</script>
|
|
101
163
|
|
|
102
164
|
<template>
|
|
@@ -104,106 +166,147 @@
|
|
|
104
166
|
<h2>OpenAI Settings</h2>
|
|
105
167
|
<v-row dense align="center">
|
|
106
168
|
<v-col cols="3">
|
|
107
|
-
<v-text-field v-model="options.model" type="string" label="Model" @change="onOptionChange"></v-text-field>
|
|
169
|
+
<v-text-field v-model="options.model" type="string" label="Model" density="compact" @change="onOptionChange"></v-text-field>
|
|
108
170
|
</v-col>
|
|
109
171
|
<v-col cols="2">
|
|
110
|
-
<v-select v-model="options.outputFormat" :items="outputFormats" persistent-hint
|
|
111
|
-
label="Format" @update:modelValue="onOptionChange"
|
|
172
|
+
<v-select v-model="options.outputFormat" :items="outputFormats" persistent-hint density="compact"
|
|
173
|
+
label="Format" @update:modelValue="onOptionChange">
|
|
112
174
|
</v-select>
|
|
113
175
|
</v-col>
|
|
114
176
|
<v-col cols="2">
|
|
115
|
-
<v-select v-model="options.reasoning_effort_level" :items="reasoningEffortLevels" persistent-hint
|
|
116
|
-
label="Reasoning" @update:modelValue="onOptionChange"
|
|
177
|
+
<v-select v-model="options.reasoning_effort_level" :items="reasoningEffortLevels" persistent-hint density="compact"
|
|
178
|
+
label="Reasoning" @update:modelValue="onOptionChange">
|
|
117
179
|
</v-select>
|
|
118
180
|
</v-col>
|
|
119
181
|
<v-col cols="2">
|
|
120
|
-
<v-text-field v-model="options.max_output_tokens" type="number" label="Max Token" @change="onOptionChange"></v-text-field>
|
|
182
|
+
<v-text-field v-model="options.max_output_tokens" type="number" label="Max Token" density="compact" @change="onOptionChange"></v-text-field>
|
|
121
183
|
</v-col>
|
|
122
184
|
<v-col cols="1">
|
|
123
|
-
<v-text-field v-model="options.temperature" type="number" label="Temperature" @change="onOptionChange"></v-text-field>
|
|
185
|
+
<v-text-field v-model="options.temperature" type="number" label="Temperature" density="compact" @change="onOptionChange"></v-text-field>
|
|
124
186
|
</v-col>
|
|
125
187
|
<v-col cols="1">
|
|
126
|
-
<v-text-field v-model="options.top_p" type="number" label="Top P" @change="onOptionChange"></v-text-field>
|
|
188
|
+
<v-text-field v-model="options.top_p" type="number" label="Top P" density="compact" @change="onOptionChange"></v-text-field>
|
|
127
189
|
</v-col>
|
|
128
190
|
<v-col cols="1">
|
|
129
|
-
<v-checkbox v-model="options.store" label="Store" @change="onOptionChange"></v-checkbox>
|
|
191
|
+
<v-checkbox v-model="options.store" label="Store" density="compact" @change="onOptionChange"></v-checkbox>
|
|
130
192
|
</v-col>
|
|
131
193
|
</v-row>
|
|
132
194
|
<v-row dense align="center">
|
|
133
195
|
<v-col cols="12">
|
|
134
|
-
<v-text-field v-model="options.instructions" type="string" label="System Message" @change="onOptionChange"></v-text-field>
|
|
196
|
+
<v-text-field v-model="options.instructions" type="string" label="System Message" density="compact" @change="onOptionChange"></v-text-field>
|
|
135
197
|
</v-col>
|
|
136
198
|
</v-row>
|
|
137
199
|
<template v-for="(tool, key) in tools">
|
|
138
200
|
<v-row v-if="tool.type == 'mcp'" dense align="center">
|
|
139
201
|
<v-col cols="2">
|
|
140
|
-
<v-text-field v-model="tool.server_label" disabled type="string" label="mcp" @change="onToolChange"></v-text-field>
|
|
202
|
+
<v-text-field v-model="tool.server_label" disabled type="string" label="mcp" density="compact" @change="onToolChange"></v-text-field>
|
|
141
203
|
</v-col>
|
|
142
204
|
<v-col cols="4">
|
|
143
|
-
<v-text-field v-model="tool.server_url" type="string" label="Url" @change="onToolChange"></v-text-field>
|
|
205
|
+
<v-text-field v-model="tool.server_url" type="string" label="Url" density="compact" @change="onToolChange"></v-text-field>
|
|
144
206
|
</v-col>
|
|
145
207
|
<v-col cols="3">
|
|
146
|
-
<v-text-field v-model="tool.server_description" type="string" label="Description" @change="onToolChange"></v-text-field>
|
|
208
|
+
<v-text-field v-model="tool.server_description" type="string" label="Description" density="compact" density="compact" @change="onToolChange"></v-text-field>
|
|
147
209
|
</v-col>
|
|
148
210
|
<v-col cols="2">
|
|
149
211
|
<v-select v-model="tool.require_approval" :items="mcpApprovals" persistent-hint
|
|
150
|
-
label="Approval" @update:modelValue="onToolChange"
|
|
212
|
+
density="compact" label="Approval" @update:modelValue="onToolChange">
|
|
151
213
|
</v-select>
|
|
152
214
|
</v-col>
|
|
153
215
|
<v-col cols="1">
|
|
154
|
-
<v-checkbox v-model="use[key]" label="Use" @update:modelValue="onUseChange"></v-checkbox>
|
|
216
|
+
<v-checkbox v-model="use[key]" label="Use" density="compact" @update:modelValue="onUseChange"></v-checkbox>
|
|
155
217
|
</v-col>
|
|
156
218
|
</v-row>
|
|
157
219
|
<v-row v-if="tool.type == 'file_search'" dense align="center">
|
|
158
220
|
<v-col cols="2">
|
|
159
|
-
<v-text-field :model-value="key" disabled type="string" label="file_search" @change="onToolChange"></v-text-field>
|
|
221
|
+
<v-text-field :model-value="key" disabled type="string" label="file_search" density="compact" @change="onToolChange"></v-text-field>
|
|
160
222
|
</v-col>
|
|
161
223
|
<v-col cols="7">
|
|
162
|
-
<v-select v-model="fileSearch[key]" :items="vectorStoreNames" multiple persistent-hint
|
|
163
|
-
label="Vector Stores" @update:modelValue="onToolChange"
|
|
224
|
+
<v-select v-model="fileSearch[key]" :items="vectorStoreNames" density="compact" multiple persistent-hint
|
|
225
|
+
label="Vector Stores" @update:modelValue="onToolChange">
|
|
164
226
|
</v-select>
|
|
165
227
|
</v-col>
|
|
166
228
|
<v-col cols="2">
|
|
167
|
-
<v-text-field v-model="tool.max_num_results" type="string" label="Max Results" @change="onToolChange"></v-text-field>
|
|
229
|
+
<v-text-field v-model="tool.max_num_results" type="string" label="Max Results" density="compact" @change="onToolChange"></v-text-field>
|
|
168
230
|
</v-col>
|
|
169
231
|
<v-col cols="1">
|
|
170
|
-
<v-checkbox v-model="use[key]" label="Use" @update:modelValue="onUseChange"></v-checkbox>
|
|
232
|
+
<v-checkbox v-model="use[key]" label="Use" density="compact" @update:modelValue="onUseChange"></v-checkbox>
|
|
171
233
|
</v-col>
|
|
172
234
|
</v-row>
|
|
173
235
|
<v-row v-if="tool.type.startsWith('web_search')" dense align="center">
|
|
174
236
|
<v-col cols="2">
|
|
175
|
-
<v-text-field :model-value="key" disabled type="string" label="file_search" @change="onToolChange"></v-text-field>
|
|
237
|
+
<v-text-field :model-value="key" disabled type="string" label="file_search" density="compact" @change="onToolChange"></v-text-field>
|
|
176
238
|
</v-col>
|
|
177
239
|
<v-col cols="2">
|
|
178
|
-
<v-text-field v-model="tool.user_location.country" type="string" label="Country" @change="onToolChange"></v-text-field>
|
|
240
|
+
<v-text-field v-model="tool.user_location.country" type="string" label="Country" density="compact" @change="onToolChange"></v-text-field>
|
|
179
241
|
</v-col>
|
|
180
242
|
<v-col cols="3">
|
|
181
|
-
<v-text-field v-model="tool.user_location.city" type="string" label="City" @change="onToolChange"></v-text-field>
|
|
243
|
+
<v-text-field v-model="tool.user_location.city" type="string" label="City" density="compact" @change="onToolChange"></v-text-field>
|
|
182
244
|
</v-col>
|
|
183
245
|
<v-col cols="4">
|
|
184
|
-
<v-text-field v-model="tool.user_location.region" type="string" label="Region" @change="onToolChange"></v-text-field>
|
|
246
|
+
<v-text-field v-model="tool.user_location.region" type="string" label="Region" density="compact" @change="onToolChange"></v-text-field>
|
|
185
247
|
</v-col>
|
|
186
248
|
<v-col cols="1">
|
|
187
|
-
<v-checkbox v-model="use[key]" label="Use" @update:modelValue="onUseChange"></v-checkbox>
|
|
249
|
+
<v-checkbox v-model="use[key]" label="Use" density="compact" @update:modelValue="onUseChange"></v-checkbox>
|
|
188
250
|
</v-col>
|
|
189
251
|
</v-row>
|
|
190
252
|
</template>
|
|
191
253
|
<v-row dense align="center">
|
|
192
254
|
<v-col cols="2">
|
|
193
|
-
<v-btn class="bg-office" @click="emits('back')">
|
|
255
|
+
<v-btn class="bg-office" @click="emits('back')">
|
|
256
|
+
BACK
|
|
194
257
|
<v-icon icon="$back"></v-icon>
|
|
195
258
|
</v-btn>
|
|
196
259
|
</v-col>
|
|
197
260
|
<v-col cols="2">
|
|
198
|
-
<v-btn :disabled="!optionsChanged && !toolsChanged" class="bg-office" @click="onSave">
|
|
261
|
+
<v-btn :disabled="!optionsChanged && !toolsChanged" class="bg-office" @click="onSave">
|
|
262
|
+
SAVE
|
|
199
263
|
<v-icon icon="$save"></v-icon>
|
|
200
264
|
</v-btn>
|
|
201
265
|
</v-col>
|
|
202
266
|
<v-col cols="2">
|
|
203
|
-
<v-btn :disabled="!useChanged" class="bg-office" @click="onSaveUsage">
|
|
267
|
+
<v-btn :disabled="!useChanged" class="bg-office" @click="onSaveUsage">
|
|
268
|
+
SAVE TOOL USE
|
|
204
269
|
<v-icon icon="$save"></v-icon>
|
|
205
270
|
</v-btn>
|
|
206
271
|
</v-col>
|
|
207
272
|
</v-row>
|
|
273
|
+
<v-row v-if="!props.ismobile && openAI.vectoreStore" dense align="center">
|
|
274
|
+
<v-col cols="2">
|
|
275
|
+
<v-combobox v-model="selectedVectorStoreName" :items="vectorStoreNames" density="compact" @update:modelValue="vectorStoreSelected()"></v-combobox>
|
|
276
|
+
</v-col>
|
|
277
|
+
<v-col cols="1">
|
|
278
|
+
<v-btn :class="bg-office" @click="deleteVectorStore">
|
|
279
|
+
VS
|
|
280
|
+
<v-icon icon="$delete"></v-icon>
|
|
281
|
+
</v-btn>
|
|
282
|
+
</v-col>
|
|
283
|
+
<v-col cols="1">
|
|
284
|
+
<v-btn :class="bg-office" @click="addVectorStore">
|
|
285
|
+
VS
|
|
286
|
+
<v-icon icon="$plus"></v-icon>
|
|
287
|
+
</v-btn>
|
|
288
|
+
</v-col>
|
|
289
|
+
<v-col cols="5">
|
|
290
|
+
<v-combobox v-model="selectedVectorStoreFile" :items="vectorStoreFiles" density="compact"></v-combobox>
|
|
291
|
+
</v-col>
|
|
292
|
+
<v-col cols="1">
|
|
293
|
+
<v-btn :class="bg-office" @click="searchFile">
|
|
294
|
+
FILE
|
|
295
|
+
<v-icon icon="$search"></v-icon>
|
|
296
|
+
</v-btn>
|
|
297
|
+
</v-col>
|
|
298
|
+
<v-col cols="1">
|
|
299
|
+
<v-btn :class="bg-office" @click="deleteFile">
|
|
300
|
+
FILE
|
|
301
|
+
<v-icon icon="$delete"></v-icon>
|
|
302
|
+
</v-btn>
|
|
303
|
+
</v-col>
|
|
304
|
+
<v-col cols="1">
|
|
305
|
+
<v-btn :class="bg-office" @click="addFile">
|
|
306
|
+
FILE
|
|
307
|
+
<v-icon icon="add"></v-icon>
|
|
308
|
+
</v-btn>
|
|
309
|
+
</v-col>
|
|
310
|
+
</v-row>
|
|
208
311
|
</v-container>
|
|
209
312
|
</template>
|