@christianriedl/utils 1.0.131 → 1.0.133

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 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
- addFile(fileUrl: string, vectorStoreId: string, wait?: boolean): Promise<boolean>;
89
+ addVectorStore(vectorStoreName: string): Promise<boolean>;
90
+ addFile(fileUrl: string | File, 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@christianriedl/utils",
3
- "version": "1.0.131",
3
+ "version": "1.0.133",
4
4
  "description": "Interfaces, local storage, service worker, configuration, application state",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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[]>([]);
@@ -200,7 +201,7 @@
200
201
  <v-col cols="12">{{line}}</v-col>
201
202
  </v-row>
202
203
  <v-dialog v-model="showConfig">
203
- <OpenAIConfig :tools="props.tools" @use="onUse" @back="showConfig=false"></OpenAIConfig>
204
+ <OpenAIConfig :tools="props.tools" :ismobile="isMobile" @use="onUse" @back="showConfig=false"></OpenAIConfig>
204
205
  </v-dialog>
205
206
  </v-container>
206
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.push(key);
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 && props.tools && props.tools.includes(vs.name)) {
45
+ if (vs) {
45
46
  names.push(vs.name);
46
47
  }
47
48
  }
@@ -97,113 +98,205 @@
97
98
  emits('use', useTools, persist);
98
99
  useChanged.value = false;
99
100
  }
101
+ function vectorStoreSelected() {
102
+ const vs = openAI.vectorStore![selectedVectorStoreName.value];
103
+ vectorStoreFiles.value.splice(0, vectorStoreFiles.value.length);
104
+ if (vs) {
105
+ vectorStoreFiles.value.splice(0, 0, ...Object.values(vs.files) as string[]);
106
+ if (vectorStoreFiles.value.length > 0) {
107
+ selectedVectorStoreFile.value = vectorStoreFiles.value[0];
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 vs = openAI.vectorStore![selectedVectorStoreName.value];
124
+ if (!openAI.deleteVectorStore(vs.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
+ const file = await files[0].getFile();
155
+ selectedVectorStoreFile.value = file.name;
156
+ }
157
+ }
158
+ catch (e) {
159
+ console.error('Error opening file picker:', e);
160
+ return;
161
+ }
162
+ }
100
163
  </script>
101
164
 
102
165
  <template>
103
166
  <v-container fluid class="bg-office">
104
- <h2>OpenAI Settings</h2>
167
+ <h4>OpenAI Settings</h4>
105
168
  <v-row dense align="center">
106
169
  <v-col cols="3">
107
- <v-text-field v-model="options.model" type="string" label="Model" @change="onOptionChange"></v-text-field>
170
+ <v-text-field v-model="options.model" type="string" hide-details label="Model" density="compact" @change="onOptionChange"></v-text-field>
108
171
  </v-col>
109
172
  <v-col cols="2">
110
- <v-select v-model="options.outputFormat" :items="outputFormats" persistent-hint
111
- label="Format" @update:modelValue="onOptionChange" solo single-line>
173
+ <v-select v-model="options.outputFormat" :items="outputFormats" hide-details density="compact"
174
+ label="Format" @update:modelValue="onOptionChange">
112
175
  </v-select>
113
176
  </v-col>
114
177
  <v-col cols="2">
115
- <v-select v-model="options.reasoning_effort_level" :items="reasoningEffortLevels" persistent-hint
116
- label="Reasoning" @update:modelValue="onOptionChange" solo single-line>
178
+ <v-select v-model="options.reasoning_effort_level" :items="reasoningEffortLevels" hide-details density="compact"
179
+ label="Reasoning" @update:modelValue="onOptionChange">
117
180
  </v-select>
118
181
  </v-col>
119
182
  <v-col cols="2">
120
- <v-text-field v-model="options.max_output_tokens" type="number" label="Max Token" @change="onOptionChange"></v-text-field>
183
+ <v-text-field v-model="options.max_output_tokens" type="number" hide-details clearable label="Max Token" density="compact" @change="onOptionChange"></v-text-field>
121
184
  </v-col>
122
185
  <v-col cols="1">
123
- <v-text-field v-model="options.temperature" type="number" label="Temperature" @change="onOptionChange"></v-text-field>
186
+ <v-text-field v-model="options.temperature" type="number" hide-details clearable label="Temperature" density="compact" @change="onOptionChange"></v-text-field>
124
187
  </v-col>
125
188
  <v-col cols="1">
126
- <v-text-field v-model="options.top_p" type="number" label="Top P" @change="onOptionChange"></v-text-field>
189
+ <v-text-field v-model="options.top_p" type="number" hide-details clearable label="Top P" density="compact" @change="onOptionChange"></v-text-field>
127
190
  </v-col>
128
191
  <v-col cols="1">
129
- <v-checkbox v-model="options.store" label="Store" @change="onOptionChange"></v-checkbox>
192
+ <v-checkbox v-model="options.store" label="Store" density="compact" @change="onOptionChange"></v-checkbox>
130
193
  </v-col>
131
194
  </v-row>
132
195
  <v-row dense align="center">
133
196
  <v-col cols="12">
134
- <v-text-field v-model="options.instructions" type="string" label="System Message" @change="onOptionChange"></v-text-field>
197
+ <v-text-field v-model="options.instructions" type="string" hide-details clearable label="System Message" density="compact" @change="onOptionChange"></v-text-field>
135
198
  </v-col>
136
199
  </v-row>
137
200
  <template v-for="(tool, key) in tools">
138
201
  <v-row v-if="tool.type == 'mcp'" dense align="center">
139
202
  <v-col cols="2">
140
- <v-text-field v-model="tool.server_label" disabled type="string" label="mcp" @change="onToolChange"></v-text-field>
203
+ <v-text-field v-model="tool.server_label" disabled type="string" hide-details label="mcp" density="compact" @change="onToolChange"></v-text-field>
141
204
  </v-col>
142
205
  <v-col cols="4">
143
- <v-text-field v-model="tool.server_url" type="string" label="Url" @change="onToolChange"></v-text-field>
206
+ <v-text-field v-model="tool.server_url" type="string" hide-details clearable label="Url" density="compact" @change="onToolChange"></v-text-field>
144
207
  </v-col>
145
208
  <v-col cols="3">
146
- <v-text-field v-model="tool.server_description" type="string" label="Description" @change="onToolChange"></v-text-field>
209
+ <v-text-field v-model="tool.server_description" type="string" hide-details clearable label="Description" density="compact" @change="onToolChange"></v-text-field>
147
210
  </v-col>
148
211
  <v-col cols="2">
149
- <v-select v-model="tool.require_approval" :items="mcpApprovals" persistent-hint
150
- label="Approval" @update:modelValue="onToolChange" solo single-line>
212
+ <v-select v-model="tool.require_approval" :items="mcpApprovals" hide-details
213
+ density="compact" label="Approval" @update:modelValue="onToolChange">
151
214
  </v-select>
152
215
  </v-col>
153
216
  <v-col cols="1">
154
- <v-checkbox v-model="use[key]" label="Use" @update:modelValue="onUseChange"></v-checkbox>
217
+ <v-checkbox v-model="use[key]" label="Use" density="compact" @update:modelValue="onUseChange"></v-checkbox>
155
218
  </v-col>
156
219
  </v-row>
157
220
  <v-row v-if="tool.type == 'file_search'" dense align="center">
158
221
  <v-col cols="2">
159
- <v-text-field :model-value="key" disabled type="string" label="file_search" @change="onToolChange"></v-text-field>
222
+ <v-text-field :model-value="key" disabled type="string" hide-details label="file_search" density="compact" @change="onToolChange"></v-text-field>
160
223
  </v-col>
161
224
  <v-col cols="7">
162
- <v-select v-model="fileSearch[key]" :items="vectorStoreNames" multiple persistent-hint
163
- label="Vector Stores" @update:modelValue="onToolChange" solo single-line>
225
+ <v-select v-model="fileSearch[key]" :items="vectorStoreNames" density="compact" multiple hide-details 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" hide-details clearable 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" hide-details 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" hide-details clearable 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" hide-details clearable 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" hide-details clearable 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')">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">SAVE
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">SAVE TOOL USE
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
+ <template v-if="!props.ismobile && openAI.vectorStore">
274
+ <v-divider></v-divider>
275
+ <h4> </h4>
276
+ <h4>Vector Store</h4>
277
+ <v-row dense align="center">
278
+ <v-col cols="2">
279
+ <v-combobox v-model="selectedVectorStoreName" :items="vectorStoreNames" hide-details density="compact" @update:modelValue="vectorStoreSelected()"></v-combobox>
280
+ </v-col>
281
+ <v-col cols="1">
282
+ <v-btn variant="text" prepend-icon="$delete" @click="deleteVectorStore">VS</v-btn>
283
+ </v-col>
284
+ <v-col cols="1">
285
+ <v-btn variant="text" prepend-icon="$plus" @click="addVectorStore">VS</v-btn>
286
+ </v-col>
287
+ <v-col cols="5">
288
+ <v-combobox v-model="selectedVectorStoreFile" :items="vectorStoreFiles" hide-details density="compact"></v-combobox>
289
+ </v-col>
290
+ <v-col cols="1">
291
+ <v-btn variant="text" prepend-icon="$search" @click="searchFile">FILE</v-btn>
292
+ </v-col>
293
+ <v-col cols="1">
294
+ <v-btn variant="text" prepend-icon="$delete" @click="deleteFile">FILE</v-btn>
295
+ </v-col>
296
+ <v-col cols="1">
297
+ <v-btn variant="text" prepend-icon="$plus" @click="addFile">FILE</v-btn>
298
+ </v-col>
299
+ </v-row>
300
+ </template>
208
301
  </v-container>
209
302
  </template>