@meaningfully/ui 0.0.8 → 0.0.10
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/App.svelte +4 -4
- package/dist/components/ApiKeyPage.svelte +3 -2
- package/dist/components/ApiKeyPage.svelte.d.ts +1 -0
- package/dist/components/CsvUpload.svelte +4 -2
- package/dist/components/CsvUpload.svelte.d.ts +1 -0
- package/dist/components/DatabaseConfig.svelte +38 -24
- package/dist/components/DatabaseConfig.svelte.d.ts +1 -0
- package/dist/components/FrontPage.svelte +3 -2
- package/dist/components/FrontPage.svelte.d.ts +1 -0
- package/dist/components/Results.svelte +5 -2
- package/dist/components/SearchPage.svelte +8 -7
- package/dist/components/SearchPage.svelte.d.ts +1 -0
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/dist/App.svelte
CHANGED
|
@@ -64,20 +64,20 @@
|
|
|
64
64
|
|
|
65
65
|
<main class="container mx-auto px-4 py-8">
|
|
66
66
|
<Route path="">
|
|
67
|
-
<FrontPage validApiKeysSet={validApiKeysSet} api={api} />
|
|
67
|
+
<FrontPage validApiKeysSet={validApiKeysSet} api={api} basepath={basepath_app} />
|
|
68
68
|
</Route>
|
|
69
69
|
<Route path="configure-upload">
|
|
70
|
-
<DatabaseConfig validApiKeysSet={validApiKeysSet} api={api} />
|
|
70
|
+
<DatabaseConfig validApiKeysSet={validApiKeysSet} api={api} basepath={basepath_app} />
|
|
71
71
|
</Route>
|
|
72
72
|
<Route path="search/:id" let:params>
|
|
73
|
-
<SearchPage validApiKeysSet={validApiKeysSet} documentSetId={Number(params.id)} api={api} />
|
|
73
|
+
<SearchPage validApiKeysSet={validApiKeysSet} documentSetId={Number(params.id)} api={api} basepath={basepath_app} />
|
|
74
74
|
</Route>
|
|
75
75
|
<Route path="help">
|
|
76
76
|
<HelpPage />
|
|
77
77
|
</Route>
|
|
78
78
|
<Route path="settings">
|
|
79
79
|
{#if settings}
|
|
80
|
-
<ApiKeyPage settings={settings} settingsUpdated={() => getSettings() } api={api} />
|
|
80
|
+
<ApiKeyPage settings={settings} settingsUpdated={() => getSettings() } api={api} basepath={basepath_app} />
|
|
81
81
|
{/if}
|
|
82
82
|
</Route>
|
|
83
83
|
</main>
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
settings: Settings;
|
|
7
7
|
settingsUpdated: () => void;
|
|
8
8
|
api: MeaningfullyAPI;
|
|
9
|
+
basepath: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
let { settings, settingsUpdated, api }: Props = $props();
|
|
12
|
+
let { settings, settingsUpdated, api, basepath }: Props = $props();
|
|
12
13
|
let openAIKey: string = $state(settings.openAIKey);
|
|
13
14
|
let oLlamaBaseURL: string = $state(settings.oLlamaBaseURL);
|
|
14
15
|
let azureOpenAIKey: string = $state(settings.azureOpenAIKey);
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
throw new Error('Failed to save settings');
|
|
35
36
|
}
|
|
36
37
|
settingsUpdated();
|
|
37
|
-
navigate("/");
|
|
38
|
+
navigate(basepath.replace(/\/+$/g, "") + "/");
|
|
38
39
|
} catch (error) {
|
|
39
40
|
console.error(error);
|
|
40
41
|
alert('Error saving settings');
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import { fileDataStore } from '../stores/fileDataStore.js';
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
|
-
validApiKeysSet
|
|
7
|
+
validApiKeysSet,
|
|
8
|
+
basepath
|
|
8
9
|
} = $props();
|
|
9
10
|
|
|
10
11
|
let error = $state('');
|
|
@@ -57,7 +58,8 @@
|
|
|
57
58
|
fileContent
|
|
58
59
|
});
|
|
59
60
|
// Navigate to configuration page
|
|
60
|
-
navigate(
|
|
61
|
+
navigate(basepath.replace(/\/+$/g, "") + "/configure-upload");
|
|
62
|
+
|
|
61
63
|
};
|
|
62
64
|
reader.readAsDataURL(file);
|
|
63
65
|
},
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
let {
|
|
15
15
|
validApiKeysSet,
|
|
16
|
-
api
|
|
16
|
+
api,
|
|
17
|
+
basepath
|
|
17
18
|
} = $props();
|
|
18
19
|
|
|
19
20
|
let fileData: any = $state(null);
|
|
@@ -28,14 +29,9 @@
|
|
|
28
29
|
let chunkSize = $state(defaultChunkSize);
|
|
29
30
|
let chunkOverlap = $state(defaultChunkOverlap);
|
|
30
31
|
|
|
31
|
-
// Model options grouped by provider
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"azure": ["text-embedding-3-small", "text-embedding-3-large"],
|
|
35
|
-
"ollama": ["mxbai-embed-large", "nomic-embed-text"],
|
|
36
|
-
"mistral": ["mistral-embed"],
|
|
37
|
-
"gemini": ["gemini-embedding-001"]
|
|
38
|
-
};
|
|
32
|
+
// Model options grouped by provider - fetched from API
|
|
33
|
+
let availableModelOptions: Record<string, string[]> = $state({});
|
|
34
|
+
let allModelOptions: Record<string, string[]> = $state({});
|
|
39
35
|
|
|
40
36
|
let modelProvider = $state("openai");
|
|
41
37
|
let modelName = $state("text-embedding-3-small");
|
|
@@ -49,8 +45,8 @@
|
|
|
49
45
|
|
|
50
46
|
// Update model name when provider changes
|
|
51
47
|
$effect(() => {
|
|
52
|
-
if (modelProvider &&
|
|
53
|
-
modelName =
|
|
48
|
+
if (modelProvider && availableModelOptions[modelProvider]) {
|
|
49
|
+
modelName = availableModelOptions[modelProvider][0];
|
|
54
50
|
}
|
|
55
51
|
});
|
|
56
52
|
|
|
@@ -77,11 +73,27 @@
|
|
|
77
73
|
return result;
|
|
78
74
|
};
|
|
79
75
|
|
|
80
|
-
onMount(() => {
|
|
76
|
+
onMount(async () => {
|
|
77
|
+
// Fetch available model options from API
|
|
78
|
+
try {
|
|
79
|
+
const modelOptionsData = await api.getAvailableModelOptions();
|
|
80
|
+
availableModelOptions = modelOptionsData.availableModelOptions;
|
|
81
|
+
allModelOptions = modelOptionsData.allModelOptions;
|
|
82
|
+
|
|
83
|
+
// Set default provider to first available one
|
|
84
|
+
const availableProviders = Object.keys(availableModelOptions);
|
|
85
|
+
if (availableProviders.length > 0) {
|
|
86
|
+
modelProvider = availableProviders[0];
|
|
87
|
+
modelName = availableModelOptions[modelProvider][0];
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.error('Error fetching available model options:', e);
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
// Subscribe to the file data store
|
|
82
|
-
const unsubscribe = fileDataStore.subscribe((data) => {
|
|
94
|
+
const unsubscribe = fileDataStore.subscribe((data: any) => {
|
|
83
95
|
if (!data) {
|
|
84
|
-
navigate(
|
|
96
|
+
navigate(basepath.replace(/\/+$/g, "") + "/"); // Redirect back to home if no file data
|
|
85
97
|
return;
|
|
86
98
|
}
|
|
87
99
|
fileData = data;
|
|
@@ -187,7 +199,8 @@
|
|
|
187
199
|
});
|
|
188
200
|
|
|
189
201
|
if (uploadResponse.success) {
|
|
190
|
-
navigate("/search/" + uploadResponse.documentSetId);
|
|
202
|
+
navigate(basepath.replace(/\/+$/g, "") + "/search/" + uploadResponse.documentSetId);
|
|
203
|
+
|
|
191
204
|
} else {
|
|
192
205
|
error = uploadResponse.message || 'Upload failed'; // fastify responses don't throw
|
|
193
206
|
}
|
|
@@ -237,7 +250,7 @@
|
|
|
237
250
|
});
|
|
238
251
|
|
|
239
252
|
const goBack = () => {
|
|
240
|
-
navigate(
|
|
253
|
+
navigate(basepath.replace(/\/+$/g, "") + "/");
|
|
241
254
|
};
|
|
242
255
|
</script>
|
|
243
256
|
|
|
@@ -282,15 +295,15 @@
|
|
|
282
295
|
<select
|
|
283
296
|
bind:value={modelProvider}
|
|
284
297
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-violet-500 focus:ring-violet-500">
|
|
285
|
-
<option value="openai">OpenAI</option>
|
|
286
|
-
<option value="azure">Azure OpenAI</option>
|
|
287
|
-
<option value="ollama">Ollama</option>
|
|
288
|
-
<option value="mistral">Mistral AI</option>
|
|
289
|
-
<option value="gemini">Google Gemini</option>
|
|
298
|
+
<option value="openai" disabled={!availableModelOptions.openai}>OpenAI</option>
|
|
299
|
+
<option value="azure" disabled={!availableModelOptions.azure}>Azure OpenAI</option>
|
|
300
|
+
<option value="ollama" disabled={!availableModelOptions.ollama}>Ollama</option>
|
|
301
|
+
<option value="mistral" disabled={!availableModelOptions.mistral}>Mistral AI</option>
|
|
302
|
+
<option value="gemini" disabled={!availableModelOptions.gemini}>Google Gemini</option>
|
|
290
303
|
</select>
|
|
291
304
|
</label>
|
|
292
305
|
<p class="text-xs text-gray-500">
|
|
293
|
-
The provider for the embedding model.
|
|
306
|
+
The provider for the embedding model. {Object.keys(availableModelOptions).length === 0 ? 'No providers are configured yet. Please set up API keys in the settings.' : ''}
|
|
294
307
|
</p>
|
|
295
308
|
</div>
|
|
296
309
|
|
|
@@ -299,8 +312,9 @@
|
|
|
299
312
|
What embedding model should we use?
|
|
300
313
|
<select
|
|
301
314
|
bind:value={modelName}
|
|
302
|
-
|
|
303
|
-
|
|
315
|
+
disabled={!availableModelOptions[modelProvider]}
|
|
316
|
+
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-violet-500 focus:ring-violet-500 disabled:opacity-50 disabled:cursor-not-allowed">
|
|
317
|
+
{#each (availableModelOptions[modelProvider] || allModelOptions[modelProvider] || []) as modelNameChoice}
|
|
304
318
|
<option value={modelNameChoice}>{modelNameChoice}</option>
|
|
305
319
|
{/each}
|
|
306
320
|
</select>
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
interface Props {
|
|
8
8
|
validApiKeysSet: boolean;
|
|
9
9
|
api: MeaningfullyAPI;
|
|
10
|
+
basepath: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
let { validApiKeysSet, api }: Props = $props();
|
|
13
|
+
let { validApiKeysSet, api, basepath }: Props = $props();
|
|
13
14
|
</script>
|
|
14
15
|
|
|
15
16
|
<div class="container mx-auto px-4 space-y-8">
|
|
16
|
-
<CsvUpload validApiKeysSet={validApiKeysSet} />
|
|
17
|
+
<CsvUpload validApiKeysSet={validApiKeysSet} basepath={basepath} />
|
|
17
18
|
<ExistingDatabases api={api} />
|
|
18
19
|
<div class="max-w-2xl mx-auto text-left leading-tight space-y-2">
|
|
19
20
|
Meaningfully is a semantic search tool for text data in spreadsheets. Search by the meaning of a sentence instead of keywords. <Link to="help" class="nav-link underline text-blue-600 hover:text-blue-800 visited:text-purple-600">Learn more</Link>.
|
|
@@ -95,8 +95,10 @@
|
|
|
95
95
|
link.setAttribute('download', 'results.csv');
|
|
96
96
|
document.body.appendChild(link);
|
|
97
97
|
link.click();
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
document.body.removeChild(link);
|
|
100
|
+
URL.revokeObjectURL(url);
|
|
101
|
+
}, 5000);
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
// Computed property for visible results
|
|
@@ -111,6 +113,7 @@
|
|
|
111
113
|
onclick={downloadCSV}
|
|
112
114
|
class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors flex items-center gap-2"
|
|
113
115
|
title="Download results as CSV"
|
|
116
|
+
data-testid="download-csv"
|
|
114
117
|
>
|
|
115
118
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
116
119
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { navigate } from 'svelte-routing';
|
|
2
|
+
import { navigate, Link } from 'svelte-routing';
|
|
3
3
|
import type { DocumentSet, MeaningfullyAPI } from '../types.js';
|
|
4
4
|
import Results from './Results.svelte';
|
|
5
5
|
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
validApiKeysSet: boolean;
|
|
8
8
|
documentSetId: number;
|
|
9
9
|
api: MeaningfullyAPI;
|
|
10
|
+
basepath: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
let { validApiKeysSet, documentSetId, api }: Props = $props();
|
|
13
|
+
let { validApiKeysSet, documentSetId, api, basepath }: Props = $props();
|
|
13
14
|
|
|
14
15
|
let documentSet: DocumentSet | null = $state(null);
|
|
15
16
|
let documentSetLoading = $state(true);
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
documentSetLoading = false;
|
|
37
38
|
}).catch(error => {
|
|
38
39
|
console.error('Error fetching document set:', error);
|
|
39
|
-
navigate(
|
|
40
|
+
navigate(basepath.replace(/\/+$/g, "") + "/");
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
const placeholderQueries = [
|
|
@@ -105,15 +106,15 @@
|
|
|
105
106
|
|
|
106
107
|
<div class="p-6 space-y-6">
|
|
107
108
|
<div class="flex items-center space-x-4">
|
|
108
|
-
<
|
|
109
|
+
<Link
|
|
109
110
|
class="text-blue-500 hover:text-blue-600 flex items-center space-x-1"
|
|
110
|
-
|
|
111
|
+
to=""
|
|
111
112
|
>
|
|
112
113
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
113
114
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
114
115
|
</svg>
|
|
115
116
|
<span>Back to Home</span>
|
|
116
|
-
</
|
|
117
|
+
</Link>
|
|
117
118
|
</div>
|
|
118
119
|
|
|
119
120
|
{#if documentSetLoading}
|
|
@@ -253,7 +254,7 @@
|
|
|
253
254
|
{/each}
|
|
254
255
|
</tbody>
|
|
255
256
|
</table>
|
|
256
|
-
<button class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" onclick={closeModal}>Close</button>
|
|
257
|
+
<button data-testid="modal-close-button" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" onclick={closeModal}>Close</button>
|
|
257
258
|
</div>
|
|
258
259
|
</div>
|
|
259
260
|
{/if}
|
package/dist/types.d.ts
CHANGED
|
@@ -57,4 +57,8 @@ export interface MeaningfullyAPI {
|
|
|
57
57
|
elapsedTimeMs: number;
|
|
58
58
|
estimatedTimeRemainingMs: number | null;
|
|
59
59
|
}>;
|
|
60
|
+
getAvailableModelOptions: () => Promise<{
|
|
61
|
+
availableModelOptions: Record<string, string[]>;
|
|
62
|
+
allModelOptions: Record<string, string[]>;
|
|
63
|
+
}>;
|
|
60
64
|
}
|