victor HF Staff commited on
Commit
31b3f19
·
1 Parent(s): d1218ba

Add initValue to settings store and refactor model settings init

Browse files

Introduced an initValue method to the settings store for initializing nested settings keys only if undefined. Refactored the settings page to use this method for initializing customPrompts, multimodalOverrides, and hidePromptExamples, improving consistency and preventing unnecessary overwrites.

src/lib/stores/settings.ts CHANGED
@@ -20,6 +20,11 @@ type SettingsStore = {
20
 
21
  type SettingsStoreWritable = Writable<SettingsStore> & {
22
  instantSet: (settings: Partial<SettingsStore>) => Promise<void>;
 
 
 
 
 
23
  };
24
 
25
  export function useSettingsStore() {
@@ -30,6 +35,7 @@ export function createSettingsStore(initialValue: Omit<SettingsStore, "recentlyS
30
  const baseStore = writable({ ...initialValue, recentlySaved: false });
31
 
32
  let timeoutId: NodeJS.Timeout;
 
33
 
34
  async function setSettings(settings: Partial<SettingsStore>) {
35
  baseStore.update((s) => ({
@@ -38,6 +44,7 @@ export function createSettingsStore(initialValue: Omit<SettingsStore, "recentlyS
38
  }));
39
 
40
  if (browser) {
 
41
  clearTimeout(timeoutId);
42
  timeoutId = setTimeout(async () => {
43
  await fetch(`${base}/settings`, {
@@ -45,28 +52,86 @@ export function createSettingsStore(initialValue: Omit<SettingsStore, "recentlyS
45
  headers: {
46
  "Content-Type": "application/json",
47
  },
48
- body: JSON.stringify({
49
- ...get(baseStore),
50
- ...settings,
51
- }),
52
  });
53
 
54
  invalidate(UrlDependency.ConversationList);
55
- // set savedRecently to true for 3s
56
- baseStore.update((s) => ({
57
- ...s,
58
- recentlySaved: true,
59
- }));
60
- setTimeout(() => {
61
  baseStore.update((s) => ({
62
  ...s,
63
- recentlySaved: false,
64
  }));
65
- }, 3000);
 
 
 
 
 
 
 
 
66
  }, 300);
67
  // debounce server calls by 300ms
68
  }
69
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  async function instantSet(settings: Partial<SettingsStore>) {
71
  baseStore.update((s) => ({
72
  ...s,
@@ -92,6 +157,7 @@ export function createSettingsStore(initialValue: Omit<SettingsStore, "recentlyS
92
  subscribe: baseStore.subscribe,
93
  set: setSettings,
94
  instantSet,
 
95
  update: (fn: (s: SettingsStore) => SettingsStore) => {
96
  setSettings(fn(get(baseStore)));
97
  },
 
20
 
21
  type SettingsStoreWritable = Writable<SettingsStore> & {
22
  instantSet: (settings: Partial<SettingsStore>) => Promise<void>;
23
+ initValue: <K extends keyof SettingsStore>(
24
+ key: K,
25
+ nestedKey: string,
26
+ value: any
27
+ ) => Promise<void>;
28
  };
29
 
30
  export function useSettingsStore() {
 
35
  const baseStore = writable({ ...initialValue, recentlySaved: false });
36
 
37
  let timeoutId: NodeJS.Timeout;
38
+ let showSavedOnNextSync = false;
39
 
40
  async function setSettings(settings: Partial<SettingsStore>) {
41
  baseStore.update((s) => ({
 
44
  }));
45
 
46
  if (browser) {
47
+ showSavedOnNextSync = true; // User edit, should show "Saved"
48
  clearTimeout(timeoutId);
49
  timeoutId = setTimeout(async () => {
50
  await fetch(`${base}/settings`, {
 
52
  headers: {
53
  "Content-Type": "application/json",
54
  },
55
+ body: JSON.stringify(get(baseStore)),
 
 
 
56
  });
57
 
58
  invalidate(UrlDependency.ConversationList);
59
+
60
+ if (showSavedOnNextSync) {
61
+ // set savedRecently to true for 3s
 
 
 
62
  baseStore.update((s) => ({
63
  ...s,
64
+ recentlySaved: true,
65
  }));
66
+ setTimeout(() => {
67
+ baseStore.update((s) => ({
68
+ ...s,
69
+ recentlySaved: false,
70
+ }));
71
+ }, 3000);
72
+ }
73
+
74
+ showSavedOnNextSync = false;
75
  }, 300);
76
  // debounce server calls by 300ms
77
  }
78
  }
79
+
80
+ async function initValue<K extends keyof SettingsStore>(
81
+ key: K,
82
+ nestedKey: string,
83
+ value: any
84
+ ) {
85
+ const currentStore = get(baseStore);
86
+ const currentNestedObject = currentStore[key] as Record<string, any>;
87
+
88
+ // Only initialize if undefined
89
+ if (currentNestedObject?.[nestedKey] !== undefined) {
90
+ return;
91
+ }
92
+
93
+ // Update the store
94
+ const newNestedObject = {
95
+ ...(currentNestedObject || {}),
96
+ [nestedKey]: value,
97
+ };
98
+
99
+ baseStore.update((s) => ({
100
+ ...s,
101
+ [key]: newNestedObject,
102
+ }));
103
+
104
+ // Save to server (debounced) - note: we don't set showSavedOnNextSync
105
+ if (browser) {
106
+ clearTimeout(timeoutId);
107
+ timeoutId = setTimeout(async () => {
108
+ await fetch(`${base}/settings`, {
109
+ method: "POST",
110
+ headers: {
111
+ "Content-Type": "application/json",
112
+ },
113
+ body: JSON.stringify(get(baseStore)),
114
+ });
115
+
116
+ invalidate(UrlDependency.ConversationList);
117
+
118
+ if (showSavedOnNextSync) {
119
+ baseStore.update((s) => ({
120
+ ...s,
121
+ recentlySaved: true,
122
+ }));
123
+ setTimeout(() => {
124
+ baseStore.update((s) => ({
125
+ ...s,
126
+ recentlySaved: false,
127
+ }));
128
+ }, 3000);
129
+ }
130
+
131
+ showSavedOnNextSync = false;
132
+ }, 300);
133
+ }
134
+ }
135
  async function instantSet(settings: Partial<SettingsStore>) {
136
  baseStore.update((s) => ({
137
  ...s,
 
157
  subscribe: baseStore.subscribe,
158
  set: setSettings,
159
  instantSet,
160
+ initValue,
161
  update: (fn: (s: SettingsStore) => SettingsStore) => {
162
  setSettings(fn(get(baseStore)));
163
  },
src/routes/settings/(nav)/[...model]/+page.svelte CHANGED
@@ -21,13 +21,9 @@
21
  type RouterProvider = { provider: string } & Record<string, unknown>;
22
 
23
  $effect(() => {
24
- if ($settings.customPrompts[page.params.model] === undefined) {
25
- $settings.customPrompts = {
26
- ...$settings.customPrompts,
27
- [page.params.model]:
28
- page.data.models.find((el: BackendModel) => el.id === page.params.model)?.preprompt || "",
29
- };
30
- }
31
  });
32
 
33
  let hasCustomPreprompt = $derived(
@@ -40,31 +36,15 @@
40
 
41
  // Initialize multimodal override for this model if not set yet
42
  $effect(() => {
43
- if (!$settings.multimodalOverrides) {
44
- $settings.multimodalOverrides = {};
45
- }
46
- const modelId = page.params.model;
47
- if ($settings.multimodalOverrides[modelId] === undefined && model) {
48
  // Default to the model's advertised capability
49
- $settings.multimodalOverrides = {
50
- ...$settings.multimodalOverrides,
51
- [modelId]: !!model.multimodal,
52
- };
53
  }
54
  });
55
 
56
  // Ensure hidePromptExamples has an entry for this model so the switch can bind safely
57
  $effect(() => {
58
- if (!$settings.hidePromptExamples) {
59
- $settings.hidePromptExamples = {};
60
- }
61
- const modelId = page.params.model;
62
- if ($settings.hidePromptExamples[modelId] === undefined) {
63
- $settings.hidePromptExamples = {
64
- ...$settings.hidePromptExamples,
65
- [modelId]: false,
66
- };
67
- }
68
  });
69
  </script>
70
 
 
21
  type RouterProvider = { provider: string } & Record<string, unknown>;
22
 
23
  $effect(() => {
24
+ const defaultPreprompt =
25
+ page.data.models.find((el: BackendModel) => el.id === page.params.model)?.preprompt || "";
26
+ settings.initValue("customPrompts", page.params.model, defaultPreprompt);
 
 
 
 
27
  });
28
 
29
  let hasCustomPreprompt = $derived(
 
36
 
37
  // Initialize multimodal override for this model if not set yet
38
  $effect(() => {
39
+ if (model) {
 
 
 
 
40
  // Default to the model's advertised capability
41
+ settings.initValue("multimodalOverrides", page.params.model, !!model.multimodal);
 
 
 
42
  }
43
  });
44
 
45
  // Ensure hidePromptExamples has an entry for this model so the switch can bind safely
46
  $effect(() => {
47
+ settings.initValue("hidePromptExamples", page.params.model, false);
 
 
 
 
 
 
 
 
 
48
  });
49
  </script>
50