@shwfed/config 1.0.0 → 1.0.1
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/module.json +1 -1
- package/dist/module.mjs +117 -23
- package/dist/runtime/components/config/footer.vue +0 -2
- package/dist/runtime/components/config/index.vue +13 -3
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue +87 -11
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue +3 -0
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/runtime.vue +8 -0
- package/dist/runtime/components/form/index.vue +2 -2
- package/dist/runtime/components/table/ai/columns-button.vue +91 -98
- package/dist/runtime/components/table/ai/data-source-button.vue +88 -95
- package/dist/runtime/components/table/index.vue +5 -7
- package/dist/runtime/plugins/ai/index.d.ts +1 -5
- package/dist/runtime/plugins/ai/index.js +185 -441
- package/dist/runtime/plugins/cel/index.js +7 -0
- package/dist/runtime/vendor/cel-js/PROMPT.md +8 -0
- package/package.json +4 -4
- package/dist/chunks/index.mjs +0 -212742
- package/dist/runtime/components/ai/byok-button.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-button.vue +0 -48
- package/dist/runtime/components/ai/byok-button.vue.d.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.vue +0 -282
- package/dist/runtime/components/ai/byok-settings.vue.d.ts +0 -3
- package/dist/runtime/plugins/ai/gate.d.ts +0 -1
- package/dist/runtime/plugins/ai/gate.js +0 -8
- package/dist/runtime/plugins/ai/settings-state.d.ts +0 -1
- package/dist/runtime/plugins/ai/settings-state.js +0 -2
- package/dist/runtime/plugins/ai/store.d.ts +0 -17
- package/dist/runtime/plugins/ai/store.js +0 -40
- package/dist/shared/config.DW2OtAXe.mjs +0 -86529
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { useNuxtApp } from "#app";
|
|
3
|
-
import { Icon } from "@iconify/vue";
|
|
4
|
-
import { computed } from "vue";
|
|
5
|
-
import { isByokAllowed } from "../../plugins/ai/gate";
|
|
6
|
-
import { settingsOpen } from "../../plugins/ai/settings-state";
|
|
7
|
-
import ByokSettings from "./byok-settings.vue";
|
|
8
|
-
defineOptions({ name: "ShwfedAiByokButton" });
|
|
9
|
-
const { $ai } = useNuxtApp();
|
|
10
|
-
const allowed = isByokAllowed();
|
|
11
|
-
const status = computed(() => {
|
|
12
|
-
const c = $ai.config.value;
|
|
13
|
-
if (!c) {
|
|
14
|
-
return {
|
|
15
|
-
icon: "fluent:sparkle-20-regular",
|
|
16
|
-
label: "AI \u672A\u914D\u7F6E",
|
|
17
|
-
hint: "\u70B9\u51FB\u914D\u7F6E BYOK \u5BC6\u94A5"
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
icon: "fluent:magic-wand-20-regular",
|
|
22
|
-
label: "AI",
|
|
23
|
-
hint: c.model ?? "\u9ED8\u8BA4\u6A21\u578B"
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<template>
|
|
29
|
-
<template v-if="allowed">
|
|
30
|
-
<button
|
|
31
|
-
type="button"
|
|
32
|
-
class="byok-button"
|
|
33
|
-
:title="status.hint"
|
|
34
|
-
@click="settingsOpen = true"
|
|
35
|
-
>
|
|
36
|
-
<Icon
|
|
37
|
-
:icon="status.icon"
|
|
38
|
-
class="size-4 shrink-0"
|
|
39
|
-
/>
|
|
40
|
-
<span class="truncate">{{ status.label }}</span>
|
|
41
|
-
</button>
|
|
42
|
-
<ByokSettings />
|
|
43
|
-
</template>
|
|
44
|
-
</template>
|
|
45
|
-
|
|
46
|
-
<style scoped>
|
|
47
|
-
.byok-button{align-items:center;border-radius:.25rem;color:#71717a;display:inline-flex;font-size:.75rem;gap:.375rem;padding-block:.25rem;padding-inline:.5rem;transition:background-color .1s ease,color .1s ease}.byok-button:hover{background-color:#f4f4f5;color:#3f3f46}
|
|
48
|
-
</style>
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { useNuxtApp } from "#app";
|
|
3
|
-
import { Icon } from "@iconify/vue";
|
|
4
|
-
import { computed, ref, watch } from "vue";
|
|
5
|
-
import { toast } from "vue-sonner";
|
|
6
|
-
import ShwfedModal from "../modal.vue";
|
|
7
|
-
import { Button } from "../ui/button";
|
|
8
|
-
import { Field, FieldLabel, FieldDescription } from "../ui/field";
|
|
9
|
-
import { Input } from "../ui/input";
|
|
10
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
|
11
|
-
import { settingsOpen } from "../../plugins/ai/settings-state";
|
|
12
|
-
import { DEFAULT_MAX_TOKENS, PROVIDER_DEFAULTS } from "../../plugins/ai/store";
|
|
13
|
-
const ANTHROPIC_ENTRY = { value: "anthropic", label: "Anthropic \u517C\u5BB9", icon: "simple-icons:anthropic" };
|
|
14
|
-
const OPENAI_ENTRY = { value: "openai", label: "OpenAI \u517C\u5BB9", icon: "simple-icons:openai" };
|
|
15
|
-
const PROVIDER_ENTRIES = [ANTHROPIC_ENTRY, OPENAI_ENTRY];
|
|
16
|
-
defineOptions({ name: "ShwfedAiByokSettings" });
|
|
17
|
-
const { $ai } = useNuxtApp();
|
|
18
|
-
const provider = ref("anthropic");
|
|
19
|
-
const apiKey = ref("");
|
|
20
|
-
const showKey = ref(false);
|
|
21
|
-
const advanced = ref(false);
|
|
22
|
-
const model = ref("");
|
|
23
|
-
const endpoint = ref("");
|
|
24
|
-
const maxTokens = ref(void 0);
|
|
25
|
-
const testing = ref(false);
|
|
26
|
-
watch(settingsOpen, (open) => {
|
|
27
|
-
if (!open) return;
|
|
28
|
-
const c = $ai.config.value;
|
|
29
|
-
if (c) {
|
|
30
|
-
provider.value = c.provider;
|
|
31
|
-
apiKey.value = c.apiKey;
|
|
32
|
-
model.value = c.model ?? "";
|
|
33
|
-
endpoint.value = c.endpoint ?? "";
|
|
34
|
-
maxTokens.value = c.maxTokens;
|
|
35
|
-
advanced.value = !!(c.model || c.endpoint || c.maxTokens);
|
|
36
|
-
} else {
|
|
37
|
-
provider.value = "anthropic";
|
|
38
|
-
apiKey.value = "";
|
|
39
|
-
model.value = "";
|
|
40
|
-
endpoint.value = "";
|
|
41
|
-
maxTokens.value = void 0;
|
|
42
|
-
advanced.value = false;
|
|
43
|
-
}
|
|
44
|
-
showKey.value = false;
|
|
45
|
-
});
|
|
46
|
-
const placeholder = computed(() => PROVIDER_DEFAULTS[provider.value]);
|
|
47
|
-
const apiKeyPlaceholder = computed(() => provider.value === "anthropic" ? "sk-ant-..." : "sk-...");
|
|
48
|
-
function buildConfig() {
|
|
49
|
-
if (!apiKey.value.trim()) return null;
|
|
50
|
-
const mt = maxTokens.value;
|
|
51
|
-
return {
|
|
52
|
-
provider: provider.value,
|
|
53
|
-
apiKey: apiKey.value.trim(),
|
|
54
|
-
model: advanced.value && model.value.trim() ? model.value.trim() : void 0,
|
|
55
|
-
endpoint: advanced.value && endpoint.value.trim() ? endpoint.value.trim() : void 0,
|
|
56
|
-
maxTokens: advanced.value && typeof mt === "number" && Number.isFinite(mt) && mt > 0 ? Math.floor(mt) : void 0
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const canSave = computed(() => !!apiKey.value.trim());
|
|
60
|
-
function onSave() {
|
|
61
|
-
const next = buildConfig();
|
|
62
|
-
if (!next) return;
|
|
63
|
-
$ai.setConfig(next);
|
|
64
|
-
toast.success("AI \u914D\u7F6E\u5DF2\u4FDD\u5B58");
|
|
65
|
-
settingsOpen.value = false;
|
|
66
|
-
}
|
|
67
|
-
function onClear() {
|
|
68
|
-
$ai.setConfig(null);
|
|
69
|
-
apiKey.value = "";
|
|
70
|
-
model.value = "";
|
|
71
|
-
endpoint.value = "";
|
|
72
|
-
maxTokens.value = void 0;
|
|
73
|
-
toast.success("AI \u914D\u7F6E\u5DF2\u6E05\u9664");
|
|
74
|
-
settingsOpen.value = false;
|
|
75
|
-
}
|
|
76
|
-
async function onTest() {
|
|
77
|
-
const draft = buildConfig();
|
|
78
|
-
if (!draft) {
|
|
79
|
-
toast.error("\u8BF7\u5148\u586B\u5199 API Key");
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const previous = $ai.config.value;
|
|
83
|
-
$ai.setConfig(draft);
|
|
84
|
-
testing.value = true;
|
|
85
|
-
try {
|
|
86
|
-
const out = await $ai.generateText({ prompt: "ping" });
|
|
87
|
-
toast.success("\u8FDE\u63A5\u6210\u529F", { description: out.slice(0, 80) });
|
|
88
|
-
} catch (err) {
|
|
89
|
-
$ai.setConfig(previous);
|
|
90
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
91
|
-
toast.error("\u8FDE\u63A5\u5931\u8D25", { description: message });
|
|
92
|
-
} finally {
|
|
93
|
-
testing.value = false;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
<template>
|
|
99
|
-
<ShwfedModal
|
|
100
|
-
v-model:open="settingsOpen"
|
|
101
|
-
content-width="32rem"
|
|
102
|
-
:dismissible="!testing"
|
|
103
|
-
>
|
|
104
|
-
<template #title>
|
|
105
|
-
<span class="flex items-center gap-2">
|
|
106
|
-
<Icon
|
|
107
|
-
icon="fluent:sparkle-20-regular"
|
|
108
|
-
class="size-5"
|
|
109
|
-
/>
|
|
110
|
-
AI 配置 (BYOK)
|
|
111
|
-
</span>
|
|
112
|
-
</template>
|
|
113
|
-
<template #description>
|
|
114
|
-
使用您自己的 API Key 直接调用模型。仅本地有效,密钥保存在浏览器中,不会上传。
|
|
115
|
-
</template>
|
|
116
|
-
|
|
117
|
-
<form
|
|
118
|
-
class="flex flex-col gap-4 py-2"
|
|
119
|
-
autocomplete="off"
|
|
120
|
-
@submit.prevent="onSave"
|
|
121
|
-
>
|
|
122
|
-
<Field orientation="vertical">
|
|
123
|
-
<FieldLabel class="text-xs text-zinc-500">
|
|
124
|
-
供应商
|
|
125
|
-
</FieldLabel>
|
|
126
|
-
<Select
|
|
127
|
-
:model-value="provider"
|
|
128
|
-
@update:model-value="(v) => provider = v"
|
|
129
|
-
>
|
|
130
|
-
<SelectTrigger class="w-full">
|
|
131
|
-
<SelectValue />
|
|
132
|
-
</SelectTrigger>
|
|
133
|
-
<SelectContent>
|
|
134
|
-
<SelectItem
|
|
135
|
-
v-for="entry in PROVIDER_ENTRIES"
|
|
136
|
-
:key="entry.value"
|
|
137
|
-
:value="entry.value"
|
|
138
|
-
>
|
|
139
|
-
<span class="inline-flex items-center gap-2">
|
|
140
|
-
<Icon
|
|
141
|
-
:icon="entry.icon"
|
|
142
|
-
class="size-4 shrink-0"
|
|
143
|
-
/>
|
|
144
|
-
<span>{{ entry.label }}</span>
|
|
145
|
-
</span>
|
|
146
|
-
</SelectItem>
|
|
147
|
-
</SelectContent>
|
|
148
|
-
</Select>
|
|
149
|
-
</Field>
|
|
150
|
-
|
|
151
|
-
<Field orientation="vertical">
|
|
152
|
-
<FieldLabel class="text-xs text-zinc-500">
|
|
153
|
-
API Key
|
|
154
|
-
</FieldLabel>
|
|
155
|
-
<div class="relative">
|
|
156
|
-
<Input
|
|
157
|
-
v-model="apiKey"
|
|
158
|
-
:type="showKey ? 'text' : 'password'"
|
|
159
|
-
:placeholder="apiKeyPlaceholder"
|
|
160
|
-
autocomplete="off"
|
|
161
|
-
class="pr-10"
|
|
162
|
-
/>
|
|
163
|
-
<button
|
|
164
|
-
type="button"
|
|
165
|
-
class="absolute right-2 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600"
|
|
166
|
-
@click="showKey = !showKey"
|
|
167
|
-
>
|
|
168
|
-
<Icon
|
|
169
|
-
:icon="showKey ? 'fluent:eye-off-20-regular' : 'fluent:eye-20-regular'"
|
|
170
|
-
class="size-4"
|
|
171
|
-
/>
|
|
172
|
-
</button>
|
|
173
|
-
</div>
|
|
174
|
-
</Field>
|
|
175
|
-
|
|
176
|
-
<button
|
|
177
|
-
type="button"
|
|
178
|
-
class="flex w-fit items-center gap-1 text-xs text-zinc-500 hover:text-zinc-700"
|
|
179
|
-
@click="advanced = !advanced"
|
|
180
|
-
>
|
|
181
|
-
<Icon
|
|
182
|
-
:icon="advanced ? 'fluent:chevron-down-20-regular' : 'fluent:chevron-right-20-regular'"
|
|
183
|
-
class="size-3.5"
|
|
184
|
-
/>
|
|
185
|
-
高级
|
|
186
|
-
</button>
|
|
187
|
-
|
|
188
|
-
<div
|
|
189
|
-
v-if="advanced"
|
|
190
|
-
class="flex flex-col gap-4 rounded border border-zinc-100 bg-zinc-50/40 p-3"
|
|
191
|
-
>
|
|
192
|
-
<Field orientation="vertical">
|
|
193
|
-
<FieldLabel class="text-xs text-zinc-500">
|
|
194
|
-
模型
|
|
195
|
-
</FieldLabel>
|
|
196
|
-
<FieldDescription class="text-xs text-zinc-400">
|
|
197
|
-
留空使用默认:{{ placeholder.model }}
|
|
198
|
-
</FieldDescription>
|
|
199
|
-
<Input
|
|
200
|
-
v-model="model"
|
|
201
|
-
:placeholder="placeholder.model"
|
|
202
|
-
/>
|
|
203
|
-
</Field>
|
|
204
|
-
<Field orientation="vertical">
|
|
205
|
-
<FieldLabel class="text-xs text-zinc-500">
|
|
206
|
-
端点
|
|
207
|
-
</FieldLabel>
|
|
208
|
-
<FieldDescription class="text-xs text-zinc-400">
|
|
209
|
-
完整请求 URL,将被原样使用(如 OpenRouter 或后端代理)。留空使用默认:{{ placeholder.endpoint }}
|
|
210
|
-
</FieldDescription>
|
|
211
|
-
<Input
|
|
212
|
-
v-model="endpoint"
|
|
213
|
-
:placeholder="placeholder.endpoint"
|
|
214
|
-
/>
|
|
215
|
-
</Field>
|
|
216
|
-
<Field orientation="vertical">
|
|
217
|
-
<FieldLabel class="text-xs text-zinc-500">
|
|
218
|
-
最大输出 token
|
|
219
|
-
</FieldLabel>
|
|
220
|
-
<FieldDescription class="text-xs text-zinc-400">
|
|
221
|
-
单次响应可生成的最大 token 数;推理模型需要更高额度以容纳隐式思考。留空使用默认:{{ DEFAULT_MAX_TOKENS }}
|
|
222
|
-
</FieldDescription>
|
|
223
|
-
<Input
|
|
224
|
-
:model-value="maxTokens ?? ''"
|
|
225
|
-
type="number"
|
|
226
|
-
min="1"
|
|
227
|
-
:placeholder="String(DEFAULT_MAX_TOKENS)"
|
|
228
|
-
@update:model-value="(v) => {
|
|
229
|
-
const n = typeof v === 'number' ? v : Number(v);
|
|
230
|
-
maxTokens = Number.isFinite(n) && n > 0 ? Math.floor(n) : void 0;
|
|
231
|
-
}"
|
|
232
|
-
/>
|
|
233
|
-
</Field>
|
|
234
|
-
</div>
|
|
235
|
-
</form>
|
|
236
|
-
|
|
237
|
-
<template #footer>
|
|
238
|
-
<div class="flex items-center justify-between gap-3">
|
|
239
|
-
<Button
|
|
240
|
-
v-if="$ai.config.value"
|
|
241
|
-
type="button"
|
|
242
|
-
variant="ghost"
|
|
243
|
-
size="sm"
|
|
244
|
-
:disabled="testing"
|
|
245
|
-
@click="onClear"
|
|
246
|
-
>
|
|
247
|
-
<Icon icon="fluent:delete-20-regular" />
|
|
248
|
-
清除
|
|
249
|
-
</Button>
|
|
250
|
-
<span
|
|
251
|
-
v-else
|
|
252
|
-
class="flex-1"
|
|
253
|
-
/>
|
|
254
|
-
<div class="flex items-center gap-2">
|
|
255
|
-
<Button
|
|
256
|
-
type="button"
|
|
257
|
-
variant="default"
|
|
258
|
-
size="sm"
|
|
259
|
-
:disabled="!canSave || testing"
|
|
260
|
-
@click="onTest"
|
|
261
|
-
>
|
|
262
|
-
<Icon
|
|
263
|
-
:icon="testing ? 'fluent:arrow-sync-20-regular' : 'fluent:flash-20-regular'"
|
|
264
|
-
:class="testing ? 'animate-spin' : ''"
|
|
265
|
-
/>
|
|
266
|
-
测试
|
|
267
|
-
</Button>
|
|
268
|
-
<Button
|
|
269
|
-
type="button"
|
|
270
|
-
variant="primary"
|
|
271
|
-
size="sm"
|
|
272
|
-
:disabled="!canSave || testing"
|
|
273
|
-
@click="onSave"
|
|
274
|
-
>
|
|
275
|
-
<Icon icon="fluent:checkmark-20-regular" />
|
|
276
|
-
保存
|
|
277
|
-
</Button>
|
|
278
|
-
</div>
|
|
279
|
-
</div>
|
|
280
|
-
</template>
|
|
281
|
-
</ShwfedModal>
|
|
282
|
-
</template>
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function isByokAllowed(): boolean;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export function isByokAllowed() {
|
|
2
|
-
if (typeof window === "undefined") return false;
|
|
3
|
-
const h = window.location.hostname;
|
|
4
|
-
if (h === "localhost" || h === "127.0.0.1") return true;
|
|
5
|
-
if (h.startsWith("beta.")) return true;
|
|
6
|
-
if (h.includes(".beta.")) return true;
|
|
7
|
-
return false;
|
|
8
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const settingsOpen: import("vue").Ref<boolean, boolean>;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type Ref } from 'vue';
|
|
2
|
-
export type AiProvider = 'anthropic' | 'openai';
|
|
3
|
-
export interface AiConfig {
|
|
4
|
-
provider: AiProvider;
|
|
5
|
-
apiKey: string;
|
|
6
|
-
model?: string;
|
|
7
|
-
endpoint?: string;
|
|
8
|
-
maxTokens?: number;
|
|
9
|
-
}
|
|
10
|
-
export declare const DEFAULT_MAX_TOKENS = 8192;
|
|
11
|
-
export declare function loadConfig(): AiConfig | null;
|
|
12
|
-
export declare function saveConfig(config: AiConfig | null): void;
|
|
13
|
-
export declare function createConfigRef(): Ref<AiConfig | null>;
|
|
14
|
-
export declare const PROVIDER_DEFAULTS: Record<AiProvider, {
|
|
15
|
-
model: string;
|
|
16
|
-
endpoint: string;
|
|
17
|
-
}>;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ref, watch } from "vue";
|
|
2
|
-
export const DEFAULT_MAX_TOKENS = 8192;
|
|
3
|
-
const STORAGE_KEY = "shwfed:ai:byok";
|
|
4
|
-
function isProvider(v) {
|
|
5
|
-
return v === "anthropic" || v === "openai";
|
|
6
|
-
}
|
|
7
|
-
export function loadConfig() {
|
|
8
|
-
if (typeof window === "undefined") return null;
|
|
9
|
-
try {
|
|
10
|
-
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
11
|
-
if (!raw) return null;
|
|
12
|
-
const parsed = JSON.parse(raw);
|
|
13
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
14
|
-
if (typeof parsed.apiKey !== "string" || parsed.apiKey.length === 0) return null;
|
|
15
|
-
if (!isProvider(parsed.provider)) return null;
|
|
16
|
-
return {
|
|
17
|
-
provider: parsed.provider,
|
|
18
|
-
apiKey: parsed.apiKey,
|
|
19
|
-
model: typeof parsed.model === "string" && parsed.model ? parsed.model : void 0,
|
|
20
|
-
endpoint: typeof parsed.endpoint === "string" && parsed.endpoint ? parsed.endpoint : void 0,
|
|
21
|
-
maxTokens: typeof parsed.maxTokens === "number" && Number.isFinite(parsed.maxTokens) && parsed.maxTokens > 0 ? Math.floor(parsed.maxTokens) : void 0
|
|
22
|
-
};
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
export function saveConfig(config) {
|
|
28
|
-
if (typeof window === "undefined") return;
|
|
29
|
-
if (config === null) window.localStorage.removeItem(STORAGE_KEY);
|
|
30
|
-
else window.localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
|
|
31
|
-
}
|
|
32
|
-
export function createConfigRef() {
|
|
33
|
-
const r = ref(loadConfig());
|
|
34
|
-
watch(r, (next) => saveConfig(next), { deep: true });
|
|
35
|
-
return r;
|
|
36
|
-
}
|
|
37
|
-
export const PROVIDER_DEFAULTS = {
|
|
38
|
-
anthropic: { model: "claude-sonnet-4-5-20250929", endpoint: "https://api.anthropic.com/v1/messages" },
|
|
39
|
-
openai: { model: "gpt-4o-mini", endpoint: "https://api.openai.com/v1/chat/completions" }
|
|
40
|
-
};
|