@christianriedl/utils 1.0.138 → 1.0.140

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
@@ -1,6 +1,6 @@
1
1
  import { InjectionKey } from 'vue';
2
2
  import { ILogger } from './iLogger';
3
- import { Dictionary } from './types';
3
+ import { Dictionary, IDataItem, ItemType } from './types';
4
4
  export declare const getOpenAISymbol: InjectionKey<() => IOpenAIService>;
5
5
  export interface IResultAnnotation {
6
6
  file_id?: string;
@@ -78,7 +78,7 @@ export interface IFunctionTool extends ITool {
78
78
  export interface IComparisonFilter {
79
79
  key: string;
80
80
  type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte';
81
- value: string | number | boolean;
81
+ value: ItemType;
82
82
  }
83
83
  export interface ICompoundFilter {
84
84
  filters: IComparisonFilter[] | unknown;
@@ -112,17 +112,23 @@ export interface IOpenAIServiceWithTools extends IOpenAIService {
112
112
  addFunctionTool(tool: IFunctionTool, toolFunction: ToolFunction): void;
113
113
  getToolFunctions(tool: string): Promise<IResponseResult>;
114
114
  }
115
+ export interface IVectorFile {
116
+ id: string;
117
+ filename: string;
118
+ attributes: Dictionary<ItemType> | null;
119
+ }
115
120
  export interface IVectorStore {
116
121
  id: string;
117
122
  name: string;
118
- files: Dictionary<string>;
123
+ metadata: Dictionary<string> | null;
124
+ files: Dictionary<IVectorFile>;
119
125
  }
120
126
  export interface IVectorSearchContent {
121
127
  type: 'text';
122
128
  text: string;
123
129
  }
124
130
  export interface IVectorSearchResult {
125
- attributes: Dictionary<string | number | boolean> | null;
131
+ attributes: Dictionary<ItemType> | null;
126
132
  content: IVectorSearchContent[];
127
133
  file_id: string;
128
134
  filename: string;
@@ -130,14 +136,17 @@ export interface IVectorSearchResult {
130
136
  }
131
137
  export interface IOpenAIServiceWithVectorStore extends IOpenAIServiceWithTools {
132
138
  vectorStore?: Dictionary<IVectorStore>;
139
+ vsMetadata: IDataItem[];
140
+ fileAttributes: IDataItem[];
133
141
  initializeVectorStore(): Promise<boolean>;
134
142
  getVectorStore(vectorStoreId: string): IVectorStore | undefined;
135
- addVectorStore(vectorStoreName: string): Promise<boolean>;
136
- addFile(fileUrl: string | File, vectorStoreName: string, wait?: boolean): Promise<boolean>;
143
+ addVectorStore(vectorStoreName: string, metadata?: Dictionary<string>): Promise<boolean>;
144
+ addFile(fileUrl: string | File, vectorStoreName: string, attributes?: Dictionary<ItemType>, wait?: boolean): Promise<boolean>;
145
+ setAttributes(vectorStoreName: string, fileId: string | null, attributes: Dictionary<ItemType>): Promise<boolean>;
137
146
  deleteFile(fileId: string): Promise<boolean>;
138
- deleteVectorStore(vectorStoreId: string): Promise<boolean>;
147
+ deleteVectorStore(vectorStoreName: string): Promise<boolean>;
139
148
  searchVectoreStore(vectorStoreName: string, query: string | string[], rewriteQuery?: boolean, maxNumResults?: number, filters?: ICompoundFilter | IComparisonFilter): Promise<IVectorSearchResult[]>;
140
- getFileId(fileUrl: string): string | undefined;
149
+ getFile(fileUrl: string): IVectorFile | undefined;
141
150
  }
142
151
  export interface IOpenAIAppConfig {
143
152
  officeAITools: string;
package/dist/types.d.ts CHANGED
@@ -104,12 +104,14 @@ export interface IAppState extends IAppInfo {
104
104
  toggleFullScreen(): Promise<boolean>;
105
105
  }
106
106
  export type ItemType = string | number | boolean;
107
- export interface IConfigItem {
107
+ export interface IDataItem {
108
108
  name: string;
109
- description: string;
110
109
  values?: string[];
111
110
  value: ItemType;
112
111
  default: ItemType;
112
+ }
113
+ export interface IConfigItem extends IDataItem {
114
+ description: string;
113
115
  doNotChange: boolean;
114
116
  scopes: EScope;
115
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@christianriedl/utils",
3
- "version": "1.0.138",
3
+ "version": "1.0.140",
4
4
  "description": "Interfaces, local storage, service worker, configuration, application state",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -2,6 +2,7 @@
2
2
  import { inject, ref, reactive } from 'vue';
3
3
  import { appConfigSymbol, AppConfig, Dictionary } from '@christianriedl/utils';
4
4
  import { getOpenAISymbol, IOpenAIServiceWithVectorStore, IOpenAIAppConfig, IOpenAIOptions, ITool, IMcpTool, IFileSearchTool } from '@christianriedl/utils';
5
+ import OpenAIMetaData from '@christianriedl/utils/src/components/OpenAIMetaData.vue';
5
6
 
6
7
  interface IFunction {
7
8
  name: string;
@@ -30,6 +31,9 @@
30
31
  const selectedVectorStoreName = ref('');
31
32
  const selectedVectorStoreFile = ref('');
32
33
  const showFunctions = ref(false);
34
+ const showMetaData = ref(false);
35
+ const editVectorStore = ref(false);
36
+ const metadata = ref<Dictionary<ItemType>>({});
33
37
  const toolName = ref('');
34
38
  const toolFunctions = reactive<IFunction[]>([]);
35
39
  let fileHandle: FileSystemFileHandle | null = null;
@@ -172,8 +176,16 @@
172
176
  }
173
177
  initializeTools();
174
178
  }
179
+ async function editVectorStore() {
180
+ const vs = openAI.vectorStore![selectedVectorStoreName.value];
181
+ if (vs) {
182
+ editVectorStore.value = true;
183
+ metadata.value = vs.metadata ? vs.metadata : openAI.vsMetadata;
184
+ showMetaData.value = true;
185
+ }
186
+ }
175
187
  async function addFile() {
176
- if (openAI.getFileId(selectedVectorStoreFile.value)) {
188
+ if (openAI.getFile(selectedVectorStoreFile.value)) {
177
189
  alert('File already exists, add a new file path or url !');
178
190
  return;
179
191
  }
@@ -189,30 +201,42 @@
189
201
  }
190
202
  }
191
203
  async function deleteFile() {
192
- const fileId = openAI.getFileId(selectedVectorStoreFile.value);
193
- if (!fileId) {
204
+ const file = openAI.getFile(selectedVectorStoreFile.value);
205
+ if (!file) {
194
206
  alert('File not existing !');
195
207
  return;
196
208
  }
197
- if (!await openAI.deleteFile(fileId)) {
209
+ if (!await openAI.deleteFile(file.id)) {
198
210
  alert('File not deleted, error ! ');
199
211
  }
200
212
  else {
201
213
  vectorStoreSelected();
202
214
  }
203
215
  }
204
- async function searchFile() {
205
- let files: FileSystemFileHandle[] = [];
206
- try {
207
- files = await (window as any).showOpenFilePicker();
208
- if (files.length > 0) {
209
- fileHandle = files[0];
210
- selectedVectorStoreFile.value = fileHandle.name;
211
- }
216
+ async function editFile() {
217
+ const file = openAI.getFile(selectedVectorStoreFile.value);
218
+ if (file) {
219
+ editVectorStore.value = false;
220
+ metadata.value = file.attributes ? file.attributes : openAI.fileAttributes;
221
+ showMetaData.value = true;
212
222
  }
213
- catch (e) {
214
- console.error('Error opening file picker:', e);
215
- return;
223
+ }
224
+ async function saveMetaData(items?: Dictionary<ItemType>) {
225
+ showMetaData.value = false;
226
+ if (items) {
227
+ if (editVectorStore.value) {
228
+ if (await openAI.setAttributes(selectedVectorStoreName.value, null, items as Dictionary<string>)) {
229
+ vs.metadata = items;
230
+ }
231
+ }
232
+ else {
233
+ const file = openAI.getFile(selectedVectorStoreFile.value);
234
+ if (file) {
235
+ if (await openAI.setAttributes(selectedVectorStoreName.value, file.id, items)) {
236
+ file.attributes = items;
237
+ }
238
+ }
239
+ }
216
240
  }
217
241
  }
218
242
  </script>
@@ -222,7 +246,7 @@
222
246
  <h4>OpenAI Settings</h4>
223
247
  <v-row dense align="center">
224
248
  <v-col cols="3">
225
- <v-select v-model="options.model" :items="openAI.modelNames" hide-details density="compact"
249
+ <v-select v-model="options.model" :items="openAI.modelNames" hide-details density="compact"
226
250
  label="Model" @update:modelValue="onOptionChange">
227
251
  </v-select>
228
252
  </v-col>
@@ -312,27 +336,32 @@
312
336
  </template>
313
337
  <v-row dense align="center">
314
338
  <v-col cols="2">
315
- <v-btn class="bg-office" @click="emits('back')">BACK
339
+ <v-btn class="bg-office" @click="emits('back')">
340
+ BACK
316
341
  <v-icon icon="$back"></v-icon>
317
342
  </v-btn>
318
343
  </v-col>
319
344
  <v-col cols="2">
320
- <v-btn :disabled="!optionsChanged && !toolsChanged" class="bg-office" @click="onSave">SAVE
345
+ <v-btn :disabled="!optionsChanged && !toolsChanged" class="bg-office" @click="onSave">
346
+ SAVE
321
347
  <v-icon icon="$save"></v-icon>
322
348
  </v-btn>
323
349
  </v-col>
324
350
  <v-col cols="2">
325
- <v-btn :disabled="!useChanged" class="bg-office" @click="onSaveUsage">SAVE TOOL USE
351
+ <v-btn :disabled="!useChanged" class="bg-office" @click="onSaveUsage">
352
+ SAVE TOOL USE
326
353
  <v-icon icon="$save"></v-icon>
327
354
  </v-btn>
328
355
  </v-col>
329
356
  <v-col cols="2">
330
- <v-btn class="bg-office" @click="onAddMcp">ADD MCP
357
+ <v-btn class="bg-office" @click="onAddMcp">
358
+ ADD MCP
331
359
  <v-icon icon="$plus"></v-icon>
332
360
  </v-btn>
333
361
  </v-col>
334
362
  <v-col cols="2">
335
- <v-btn class="bg-office" @click="onAddSearch">ADD SEARCH
363
+ <v-btn class="bg-office" @click="onAddSearch">
364
+ ADD SEARCH
336
365
  <v-icon icon="$plus"></v-icon>
337
366
  </v-btn>
338
367
  </v-col>
@@ -345,11 +374,10 @@
345
374
  <v-col cols="2">
346
375
  <v-combobox v-model="selectedVectorStoreName" :items="vectorStoreNames" hide-details density="compact" @update:modelValue="vectorStoreSelected()"></v-combobox>
347
376
  </v-col>
348
- <v-col cols="1">
349
- <v-btn variant="text" prepend-icon="$delete" @click="deleteVectorStore">VS</v-btn>
350
- </v-col>
351
- <v-col cols="1">
352
- <v-btn variant="text" prepend-icon="$plus" @click="addVectorStore">VS</v-btn>
377
+ <v-col cols="2">
378
+ <v-btn disabled="!selectedVectorStoreName" variant="text" prepend-icon="$delete" @click="deleteVectorStore">VS</v-btn>
379
+ <v-btn disabled="!selectedVectorStoreName" variant="text" prepend-icon="$plus" @click="addVectorStore">VS</v-btn>
380
+ <v-btn disabled="!selectedVectorStoreName" variant="text" prepend-icon="$pencil" @click="editVectorStore">VS</v-btn>
353
381
  </v-col>
354
382
  <v-col cols="5">
355
383
  <v-combobox v-model="selectedVectorStoreFile" :items="vectorStoreFiles" hide-details density="compact"></v-combobox>
@@ -358,13 +386,15 @@
358
386
  <v-btn variant="text" prepend-icon="$search" @click="searchFile">FILE</v-btn>
359
387
  </v-col>
360
388
  <v-col cols="1">
361
- <v-btn variant="text" prepend-icon="$delete" @click="deleteFile">FILE</v-btn>
362
- </v-col>
363
- <v-col cols="1">
364
- <v-btn variant="text" prepend-icon="$plus" @click="addFile">FILE</v-btn>
389
+ <v-btn disabled="!selectedVectorStoreFile" variant="text" prepend-icon="$delete" @click="deleteFile">FILE</v-btn>
390
+ <v-btn disabled="!selectedVectorStoreFile" variant="text" prepend-icon="$plus" @click="addFile">FILE</v-btn>
391
+ <v-btn disabled="!selectedVectorStoreFile" variant="text" prepend-icon="$pencil" @click="editFile">VS</v-btn>
365
392
  </v-col>
366
393
  </v-row>
367
394
  </template>
395
+ <v-dialog v-model="showMetaData">
396
+ <OpenAIMetaData :items="metadata" :vectorstore="editVectorStore" @back="saveMetaData"></OpenAIMetaData>
397
+ </v-dialog>
368
398
  <v-dialog v-model="showFunctions">
369
399
  <v-container fluid class="bg-office overflow-y-auto">
370
400
  <h4>{{toolName + " functions"}}</h4>
@@ -374,7 +404,8 @@
374
404
  </v-row>
375
405
  <v-row dense align="center">
376
406
  <v-col cols="2">
377
- <v-btn class="bg-office" @click="showFunctions = false">BACK
407
+ <v-btn class="bg-office" @click="showFunctions = false">
408
+ BACK
378
409
  <v-icon icon="$back"></v-icon>
379
410
  </v-btn>
380
411
  </v-col>
@@ -0,0 +1,55 @@
1
+ <script setup lang="ts">
2
+ import { inject, computed, ref, StyleValue } from 'vue';
3
+ import { IDataItem, Dictionary } from '@christianriedl/utils'
4
+ import SettingsLine from '../components/SettingsLine.vue';
5
+
6
+ const props = defineProps<{ items: IDataItem[], vectorstore: boolean }>();
7
+ const emits = defineEmits<{ (e: 'back', items?: IDataItem[]): void }>();
8
+ const items: IDataItem[] = [];
9
+ for (const it of props.items) {
10
+ items.push(Object.assign({}, it);
11
+ }
12
+ const header = props.vectorstore ? "Vector Store Metadata" : "File Attributes";
13
+ const changedItems = new Set<string>();
14
+ const changed = ref(false);
15
+
16
+ function onChange(item: IDataItem, changed: boolean) {
17
+ if (changed)
18
+ changedItems.add(item.name);
19
+ else
20
+ changedItems.delete(item.name);
21
+ changed.value = changedItems.size > 0;
22
+ }
23
+ function onBack(save: boolean) {
24
+ if (save) {
25
+ emits('back', items);
26
+ }
27
+ else {
28
+ emits('back');
29
+ }
30
+
31
+ </script>
32
+
33
+ <template>
34
+ <v-container fluid >
35
+ <h4>{{header}}</h4>
36
+ <v-table>
37
+ <thead>
38
+ <tr>
39
+ <th style="width:50%">Name</th>
40
+ <th style="width:50%">Value</th>
41
+ </tr>
42
+ </thead>
43
+ <tbody>
44
+ <settings-line v-for="item in items" :key="item.name" :item="item" @change="onChange(item, true)" @clear="onChange(item, false)"></settings-line>
45
+ <tr>
46
+ <td style="width:50%">
47
+ <v-btn @click="onBack(false)">BACK</v-btn>
48
+ <v-btn v-if="changed" @click="onBack(true)">SAVE</v-btn>
49
+ </td>
50
+ <td style="width:50%"></td>
51
+ </tr>
52
+ </tbody>
53
+ </v-table>
54
+ </v-container>
55
+ </template>
@@ -1,36 +1,41 @@
1
1
  <script setup lang="ts">
2
2
  import { reactive } from 'vue';
3
- import { IConfigItem, ItemType, EScope } from '@christianriedl/utils';
3
+ import { IConfigItem, IDataItem, ItemType, EScope } from '@christianriedl/utils';
4
4
 
5
- const props = defineProps<{item: IConfigItem; scopes: EScope }>();
6
- const emits = defineEmits<{ (e: 'change', value: any): void }>();
5
+ const props = defineProps<{ item: IConfigItem | IDataItem; scopes?: EScope, clearable?: boolean }>();
6
+ const emits = defineEmits<{ (e: 'change'): void, (e: 'clear'): void }>();
7
7
 
8
8
  const item = reactive(props.item);
9
9
  const isString = typeof item.default === 'string' && !item.values;
10
10
  const isEnum = typeof item.default === 'string' && item.values;
11
11
  const isNumber = typeof item.default === 'number';
12
12
  const isBoolean = typeof item.default === 'boolean';
13
- const isDisabled = item.doNotChange;
14
- const isVisible = (item.scopes & props.scopes) != 0;
13
+ const isDisabled = (item as IConfigItem).doNotChange;
14
+ const isVisible = !props.scopes || ((item as IConfigItem).scopes & props.scopes) != 0;
15
15
  const enumValues: ItemType[] = item.values!;
16
+ const description = (item as IConfigItem).description || item.name;
16
17
 
17
18
  function onChange() {
18
- emits('change', true);
19
+ emits('change');
20
+ }
21
+ function onClear() {
22
+ item.value = item.default;
23
+ emits('clear');
19
24
  }
20
25
  </script>
21
26
 
22
27
  <template>
23
28
  <tr v-if="isVisible" class="settingsline">
24
- <td style="width:50%">{{item.description}}</td>
29
+ <td style="width:50%">{{description}}</td>
25
30
  <td style="width:50%">
26
- <v-switch v-if="isBoolean" v-model="item.value" :disabled="isDisabled" density="compact" hide-details marg color="primary" @change="onChange"></v-switch>
27
- <v-text-field v-if="isString" v-model="item.value" :disabled="isDisabled" density="compact" hide-details type="string" @change="onChange"></v-text-field>
28
- <v-text-field v-if="isNumber" v-model="item.value" :disabled="isDisabled" density="compact" hide-details type="number" @change="onChange"></v-text-field>
29
- <v-select v-if="isEnum" name="enum" density="compact" v-model="item.value" :disabled="isDisabled"
30
- :items="enumValues"
31
- persistent-hint
32
- @update:modelValue="onChange"
33
- dense solo hide-details single-line>
31
+ <v-switch v-if="isBoolean" v-model="item.value" :disabled="isDisabled" density="compact" hide-details color="primary"
32
+ :append-icon="props.clearable ? '$clear' : undefined" @update:modelValue="onChange" @click:append="onClear"></v-switch>
33
+ <v-text-field v-if="isString" v-model="item.value" :disabled="isDisabled" :clearable="props.clearable" density="compact"
34
+ hide-details type="string" @update:modelValue="onChange" @click:clear="onClear"></v-text-field>
35
+ <v-text-field v-if="isNumber" v-model="item.value" :disabled="isDisabled" :clearable="props.clearable" density="compact"
36
+ hide-details type="number" @update:modelValue="onChange" @click:clear="onClear"></v-text-field>
37
+ <v-select v-if="isEnum" name="enum" density="compact" v-model="item.value" :disabled="isDisabled" :clearable="props.clearable"
38
+ :items="enumValues" persistent-hint @update:modelValue="onChange" @click:clear="onClear" dense solo hide-details single-line>
34
39
  </v-select>
35
40
  </td>
36
41
  </tr>