@movevom/create-ai-api-manager 1.0.0

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.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/bin.js'
3
+
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from 'node:fs';
3
+ import { copyFile, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+ import { fileURLToPath } from 'node:url';
7
+ const DEFAULT_TEMPLATE = 'vue-tauri';
8
+ const parseArgs = (argv) => {
9
+ const args = argv.slice(2);
10
+ let targetDir = '';
11
+ let template = DEFAULT_TEMPLATE;
12
+ let force = false;
13
+ let install = true;
14
+ let depVersion = 'latest';
15
+ const take = (i) => {
16
+ const v = args[i + 1];
17
+ if (!v)
18
+ throw new Error(`missing value for ${args[i]}`);
19
+ return v;
20
+ };
21
+ for (let i = 0; i < args.length; i++) {
22
+ const a = args[i] || '';
23
+ if (!a)
24
+ continue;
25
+ if (a === '-h' || a === '--help') {
26
+ printHelp();
27
+ process.exit(0);
28
+ }
29
+ if (a === '--template' || a === '-t') {
30
+ const v = take(i);
31
+ i++;
32
+ if (v !== 'vue-tauri')
33
+ throw new Error(`unknown template: ${v}`);
34
+ template = v;
35
+ continue;
36
+ }
37
+ if (a === '--force' || a === '-f') {
38
+ force = true;
39
+ continue;
40
+ }
41
+ if (a === '--no-install') {
42
+ install = false;
43
+ continue;
44
+ }
45
+ if (a === '--install') {
46
+ install = true;
47
+ continue;
48
+ }
49
+ if (a === '--dep-version') {
50
+ depVersion = take(i);
51
+ i++;
52
+ continue;
53
+ }
54
+ if (a.startsWith('-'))
55
+ throw new Error(`unknown option: ${a}`);
56
+ if (!targetDir) {
57
+ targetDir = a;
58
+ continue;
59
+ }
60
+ throw new Error(`unexpected argument: ${a}`);
61
+ }
62
+ if (!targetDir)
63
+ targetDir = '.';
64
+ return {
65
+ targetDir,
66
+ template,
67
+ force,
68
+ install,
69
+ depVersion,
70
+ };
71
+ };
72
+ const printHelp = () => {
73
+ const lines = [
74
+ 'Usage:',
75
+ ' npm create @movevom/ai-api-manager@latest [dir] -- [options]',
76
+ '',
77
+ 'Options:',
78
+ ' -t, --template <id> Template id (default: vue-tauri)',
79
+ ' -f, --force Allow non-empty target dir',
80
+ ' --dep-version <range> Dependency version or tag (default: latest)',
81
+ ' --no-install Do not run npm install',
82
+ ' --install Run npm install (default)',
83
+ ' -h, --help Show help',
84
+ '',
85
+ 'Examples:',
86
+ ' npm create @movevom/ai-api-manager@latest my-app',
87
+ ' npm create @movevom/ai-api-manager@latest my-app -- --no-install',
88
+ ' npm create @movevom/ai-api-manager@latest my-app -- --dep-version latest',
89
+ ];
90
+ process.stdout.write(lines.join('\n') + '\n');
91
+ };
92
+ const isDirEmpty = async (dir) => {
93
+ if (!existsSync(dir))
94
+ return true;
95
+ const list = (await readdir(dir));
96
+ const visible = list.filter((x) => x !== '.DS_Store');
97
+ return visible.length === 0;
98
+ };
99
+ const toKebab = (s) => s
100
+ .trim()
101
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
102
+ .replace(/[^a-zA-Z0-9]+/g, '-')
103
+ .replace(/^-+|-+$/g, '')
104
+ .toLowerCase() || 'ai-api-manager-app';
105
+ const toSnake = (s) => toKebab(s).replace(/-/g, '_');
106
+ const toIdentifierSegment = (s) => toKebab(s).replace(/[^a-z0-9-]/g, '');
107
+ const applyReplacements = (content, vars) => {
108
+ let out = content;
109
+ for (const [k, v] of Object.entries(vars)) {
110
+ out = out.split(k).join(v);
111
+ }
112
+ return out;
113
+ };
114
+ const shouldTreatAsText = (filePath) => /\.(json|ts|tsx|js|jsx|vue|html|css|md|toml|rs|yml|yaml|txt|conf)$/i.test(filePath);
115
+ const copyDir = async (srcDir, dstDir, vars) => {
116
+ await mkdir(dstDir, { recursive: true });
117
+ const entries = await readdir(srcDir, { withFileTypes: true });
118
+ for (const ent of entries) {
119
+ const name = ent.name;
120
+ if (name === '.DS_Store')
121
+ continue;
122
+ const src = path.join(srcDir, name);
123
+ const dst = path.join(dstDir, name);
124
+ if (ent.isDirectory()) {
125
+ await copyDir(src, dst, vars);
126
+ continue;
127
+ }
128
+ if (ent.isFile()) {
129
+ if (shouldTreatAsText(name)) {
130
+ const buf = await readFile(src);
131
+ const replaced = applyReplacements(buf.toString('utf8'), vars);
132
+ await writeFile(dst, replaced);
133
+ }
134
+ else {
135
+ await copyFile(src, dst);
136
+ }
137
+ continue;
138
+ }
139
+ const st = await stat(src);
140
+ if (st.isDirectory()) {
141
+ await copyDir(src, dst, vars);
142
+ }
143
+ else {
144
+ await copyFile(src, dst);
145
+ }
146
+ }
147
+ };
148
+ const templateRootFromBin = () => {
149
+ const here = fileURLToPath(new URL('.', import.meta.url));
150
+ return path.resolve(here, '../templates');
151
+ };
152
+ const runNpmInstall = async (cwd) => {
153
+ const { spawn } = await import('node:child_process');
154
+ await new Promise((resolve, reject) => {
155
+ const p = spawn('npm', ['install'], { cwd, stdio: 'inherit' });
156
+ p.on('exit', (code) => {
157
+ if (code === 0)
158
+ resolve();
159
+ else
160
+ reject(new Error(`npm install failed with code ${code ?? 'unknown'}`));
161
+ });
162
+ p.on('error', reject);
163
+ });
164
+ };
165
+ const main = async () => {
166
+ const opts = parseArgs(process.argv);
167
+ const absTarget = path.resolve(process.cwd(), opts.targetDir);
168
+ const isEmpty = await isDirEmpty(absTarget);
169
+ if (!isEmpty && !opts.force) {
170
+ throw new Error(`target dir is not empty: ${opts.targetDir} (use --force)`);
171
+ }
172
+ const projectName = toKebab(path.basename(absTarget));
173
+ const tauriPackageName = toKebab(projectName);
174
+ const tauriLibName = `${toSnake(projectName)}_lib`;
175
+ const identifier = `com.example.${toIdentifierSegment(projectName) || 'app'}`;
176
+ const vars = {
177
+ __PROJECT_NAME__: projectName,
178
+ __PRODUCT_NAME__: projectName,
179
+ __IDENTIFIER__: identifier,
180
+ __TAURI_PACKAGE_NAME__: tauriPackageName,
181
+ __TAURI_LIB_NAME__: tauriLibName,
182
+ __AIM_DEP_VERSION__: opts.depVersion,
183
+ };
184
+ const templatesRoot = templateRootFromBin();
185
+ const srcTemplateDir = path.join(templatesRoot, opts.template);
186
+ await copyDir(srcTemplateDir, absTarget, vars);
187
+ process.stdout.write(`\nCreated ${opts.template} project in ${opts.targetDir}\n`);
188
+ process.stdout.write(`\nNext:\n`);
189
+ process.stdout.write(` cd ${opts.targetDir}\n`);
190
+ if (!opts.install) {
191
+ process.stdout.write(` npm install\n`);
192
+ }
193
+ process.stdout.write(` npm run tauri:dev\n\n`);
194
+ if (opts.install) {
195
+ await runNpmInstall(absTarget);
196
+ }
197
+ };
198
+ main().catch((e) => {
199
+ process.stderr.write(String(e?.message || e) + '\n');
200
+ process.exit(1);
201
+ });
202
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@movevom/create-ai-api-manager",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/zuoguyoupan/ai-api-manager.git"
9
+ },
10
+ "keywords": [
11
+ "create",
12
+ "scaffold",
13
+ "cli",
14
+ "template",
15
+ "ai",
16
+ "llm",
17
+ "tauri",
18
+ "vue",
19
+ "vite"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "type": "module",
25
+ "bin": {
26
+ "create-ai-api-manager": "./bin/create-ai-api-manager.js"
27
+ },
28
+ "files": [
29
+ "bin",
30
+ "dist",
31
+ "templates"
32
+ ],
33
+ "engines": {
34
+ "node": ">=18"
35
+ }
36
+ }
@@ -0,0 +1,2 @@
1
+ /// <reference types="vite/client" />
2
+
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>__PRODUCT_NAME__</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
13
+
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "type-check": "vue-tsc --build",
8
+ "tauri": "tauri",
9
+ "tauri:dev": "tauri dev",
10
+ "tauri:build": "tauri build"
11
+ },
12
+ "dependencies": {
13
+ "@movevom/ai-api-catalog": "__AIM_DEP_VERSION__",
14
+ "@movevom/ai-api-manager-adapters-web": "__AIM_DEP_VERSION__",
15
+ "@movevom/ai-api-manager-agent-kit": "__AIM_DEP_VERSION__",
16
+ "@movevom/ai-api-manager-core": "__AIM_DEP_VERSION__",
17
+ "@movevom/ai-api-manager-providers-anthropic": "__AIM_DEP_VERSION__",
18
+ "@movevom/ai-api-manager-providers-openai": "__AIM_DEP_VERSION__",
19
+ "vue": "^3.5.22"
20
+ },
21
+ "devDependencies": {
22
+ "@tauri-apps/api": "^2.0.0",
23
+ "@tauri-apps/cli": "^2.0.0",
24
+ "@tsconfig/node22": "^22.0.2",
25
+ "@types/node": "^22.18.11",
26
+ "@vitejs/plugin-vue": "^6.0.1",
27
+ "@vue/tsconfig": "^0.8.1",
28
+ "typescript": "~5.9.0",
29
+ "vite": "^7.1.11",
30
+ "vue-tsc": "^3.1.1"
31
+ }
32
+ }
@@ -0,0 +1,528 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref, watch } from 'vue'
3
+ import type { AiRouter, Catalog, KeyProvider, PolicyEngine } from '@movevom/ai-api-manager-core'
4
+ import {
5
+ createAdapterRegistry,
6
+ createAgfModePolicyEngine,
7
+ createAiRouter,
8
+ createFixedPolicyEngine,
9
+ createPricePolicyEngine,
10
+ createQualityPolicyEngine,
11
+ createSpeedPolicyEngine,
12
+ } from '@movevom/ai-api-manager-core'
13
+ import { createAiAgent } from '@movevom/ai-api-manager-agent-kit'
14
+ import { getCatalog } from '@movevom/ai-api-catalog'
15
+ import {
16
+ createFetchHttpClient,
17
+ createLocalStorageKeyProvider,
18
+ createLocalStorageMetricStore,
19
+ } from '@movevom/ai-api-manager-adapters-web'
20
+ import { createAnthropicAdapter } from '@movevom/ai-api-manager-providers-anthropic'
21
+ import { createOpenAIAdapter } from '@movevom/ai-api-manager-providers-openai'
22
+
23
+ type StrategyMode = 'agf_mode' | 'fixed' | 'speed' | 'price' | 'quality'
24
+ type RunnerMode = 'router' | 'agent'
25
+
26
+ const catalog = getCatalog() as Catalog
27
+ const allProviders = catalog.providers.map((p) => p.id)
28
+ const supportedAdapterProviderIds = new Set<string>([
29
+ 'chatgpt',
30
+ 'grok',
31
+ 'gemini',
32
+ 'deepseek',
33
+ 'chatglm',
34
+ 'minimax',
35
+ 'moonshot',
36
+ 'qwen',
37
+ 'claude',
38
+ ])
39
+ const callableProviders = catalog.providers
40
+ .map((p) => p.id)
41
+ .filter((id) => supportedAdapterProviderIds.has(id))
42
+
43
+ const aiMode = ref<'official' | 'user'>('official')
44
+ const countryCode = ref<string>('CN')
45
+ const strategyMode = ref<StrategyMode>('agf_mode')
46
+ const runnerMode = ref<RunnerMode>('router')
47
+
48
+ const preferredProviderId = ref<string>(callableProviders[0] || allProviders[0] || '')
49
+ const preferredModelId = ref<string>('')
50
+
51
+ const apiKey = ref<string>('')
52
+ const keyForProviderId = ref<string>(allProviders[0] || '')
53
+ const keyStatus = ref<Record<string, boolean>>({})
54
+
55
+ const systemPrompt = ref<string>('你是一个简洁且严谨的 AI 助手。')
56
+ const userPrompt = ref<string>('请用一句话解释“什么是 Model Context Protocol (MCP)”。')
57
+
58
+ const running = ref(false)
59
+ const streaming = ref(false)
60
+ const outputText = ref<string>('')
61
+ const errorText = ref<string>('')
62
+
63
+ const abortCtrl = ref<AbortController | null>(null)
64
+
65
+ const keyProvider: KeyProvider = createLocalStorageKeyProvider({ prefix: 'ai-api-manager:key:' })
66
+ const metricStore = createLocalStorageMetricStore({ prefix: 'ai-api-manager:metrics:' })
67
+
68
+ const modelsForPreferredProvider = computed(() =>
69
+ catalog.models.filter((m) => m.providerId === preferredProviderId.value).map((m) => m.id),
70
+ )
71
+
72
+ const lockModelSelection = computed(
73
+ () => aiMode.value === 'official' && strategyMode.value === 'agf_mode',
74
+ )
75
+
76
+ const refreshKeyStatus = async () => {
77
+ const entries = await Promise.all(
78
+ allProviders.map(async (providerId) => {
79
+ const v = await keyProvider.getKey({ providerId })
80
+ return [providerId, !!v] as const
81
+ }),
82
+ )
83
+ keyStatus.value = Object.fromEntries(entries)
84
+ }
85
+
86
+ const loadKey = async () => {
87
+ apiKey.value = (await keyProvider.getKey({ providerId: keyForProviderId.value })) || ''
88
+ await refreshKeyStatus()
89
+ }
90
+
91
+ const saveKey = async () => {
92
+ await keyProvider.setKey({ providerId: keyForProviderId.value }, apiKey.value.trim())
93
+ await refreshKeyStatus()
94
+ }
95
+
96
+ const clearKey = async () => {
97
+ await keyProvider.deleteKey({ providerId: keyForProviderId.value })
98
+ apiKey.value = ''
99
+ await refreshKeyStatus()
100
+ }
101
+
102
+ const wrapKeyAwarePolicy = (base: PolicyEngine, opts: { maxFallbacks?: number }): PolicyEngine => {
103
+ const maxFallbacks = Math.max(0, Math.floor(opts.maxFallbacks ?? 3))
104
+ return {
105
+ async pickPlan(input, ctx) {
106
+ const plan = await base.pickPlan(input, ctx)
107
+ const list = [plan.primary, ...plan.fallbacks]
108
+ const checks = await Promise.all(
109
+ list.map(async (k) => ({
110
+ k,
111
+ hasKey: !!(await keyProvider.getKey({ providerId: k.providerId })),
112
+ })),
113
+ )
114
+ const withKey = checks.filter((x) => x.hasKey).map((x) => x.k)
115
+ if (!withKey.length) return plan
116
+
117
+ const primaryOk = checks.find(
118
+ (x) =>
119
+ x.hasKey &&
120
+ x.k.providerId === plan.primary.providerId &&
121
+ x.k.modelId === plan.primary.modelId &&
122
+ x.k.endpointKind === plan.primary.endpointKind,
123
+ )?.k
124
+
125
+ const primary = primaryOk ?? withKey[0]!
126
+ const fallbacks = withKey
127
+ .filter(
128
+ (k) =>
129
+ !(
130
+ k.providerId === primary.providerId &&
131
+ k.modelId === primary.modelId &&
132
+ k.endpointKind === primary.endpointKind
133
+ ),
134
+ )
135
+ .slice(0, maxFallbacks)
136
+ return { primary, fallbacks }
137
+ },
138
+ }
139
+ }
140
+
141
+ const buildEnv = (): { router: AiRouter; policy: PolicyEngine } => {
142
+ const adapters = createAdapterRegistry([
143
+ ...Array.from(supportedAdapterProviderIds)
144
+ .filter((providerId) => providerId !== 'claude')
145
+ .map((providerId) => createOpenAIAdapter({ providerId })),
146
+ createAnthropicAdapter({ providerId: 'claude' }),
147
+ ])
148
+
149
+ const defaultModel = {
150
+ providerId: preferredProviderId.value,
151
+ modelId: preferredModelId.value || modelsForPreferredProvider.value[0] || '',
152
+ }
153
+
154
+ const basePolicy: PolicyEngine =
155
+ strategyMode.value === 'agf_mode'
156
+ ? createAgfModePolicyEngine({
157
+ keys: keyProvider,
158
+ officialCn: { providerId: 'deepseek', modelId: 'deepseek-chat' },
159
+ officialIntl: { providerId: 'chatgpt', modelId: 'gpt-4o-mini' },
160
+ defaultUser: defaultModel.modelId ? defaultModel : undefined,
161
+ maxFallbacks: 3,
162
+ fallbackProviderOrder: [
163
+ 'deepseek',
164
+ 'chatgpt',
165
+ 'moonshot',
166
+ 'qwen',
167
+ 'gemini',
168
+ 'chatglm',
169
+ 'minimax',
170
+ 'grok',
171
+ 'claude',
172
+ ],
173
+ })
174
+ : strategyMode.value === 'speed'
175
+ ? createSpeedPolicyEngine({
176
+ defaultModel,
177
+ windowMs: 6 * 60 * 60 * 1000,
178
+ fallbackCount: 3,
179
+ })
180
+ : strategyMode.value === 'price'
181
+ ? createPricePolicyEngine({
182
+ defaultModel,
183
+ windowMs: 6 * 60 * 60 * 1000,
184
+ fallbackCount: 3,
185
+ })
186
+ : strategyMode.value === 'quality'
187
+ ? createQualityPolicyEngine({
188
+ defaultModel,
189
+ windowMs: 6 * 60 * 60 * 1000,
190
+ fallbackCount: 3,
191
+ })
192
+ : createFixedPolicyEngine({ defaultModel })
193
+
194
+ const policy = wrapKeyAwarePolicy(basePolicy, { maxFallbacks: 3 })
195
+
196
+ const router = createAiRouter({
197
+ catalog: { getCatalog },
198
+ adapters,
199
+ keys: keyProvider,
200
+ metrics: metricStore,
201
+ policy,
202
+ http: createFetchHttpClient(),
203
+ defaultStrategy: 'fixed',
204
+ })
205
+ return { router, policy }
206
+ }
207
+
208
+ const makeMessages = () => [
209
+ { role: 'system' as const, content: systemPrompt.value.trim() },
210
+ { role: 'user' as const, content: userPrompt.value.trim() },
211
+ ]
212
+
213
+ const stop = () => {
214
+ if (!abortCtrl.value) return
215
+ abortCtrl.value.abort()
216
+ }
217
+
218
+ const runOnce = async () => {
219
+ if (running.value) return
220
+ running.value = true
221
+ streaming.value = false
222
+ outputText.value = ''
223
+ errorText.value = ''
224
+ abortCtrl.value = new AbortController()
225
+
226
+ try {
227
+ const { router } = buildEnv()
228
+ const pick = {
229
+ strategy: strategyMode.value === 'agf_mode' ? 'fixed' : strategyMode.value,
230
+ mode: aiMode.value,
231
+ countryCode: countryCode.value.trim() || undefined,
232
+ preferredModel:
233
+ preferredProviderId.value && preferredModelId.value
234
+ ? { providerId: preferredProviderId.value, modelId: preferredModelId.value }
235
+ : undefined,
236
+ }
237
+
238
+ if (runnerMode.value === 'agent') {
239
+ const agent = createAiAgent({ router, maxSteps: 6 })
240
+ const res = await agent.run({
241
+ messages: makeMessages(),
242
+ pick,
243
+ abortSignal: abortCtrl.value.signal,
244
+ })
245
+ outputText.value = res.text
246
+ return
247
+ }
248
+
249
+ const res = await router.chat({
250
+ messages: makeMessages(),
251
+ pick,
252
+ abortSignal: abortCtrl.value.signal,
253
+ })
254
+ outputText.value = res.text
255
+ } catch (e) {
256
+ errorText.value = String((e as Error)?.message || e)
257
+ } finally {
258
+ abortCtrl.value = null
259
+ running.value = false
260
+ }
261
+ }
262
+
263
+ const runStream = async () => {
264
+ if (running.value) return
265
+ running.value = true
266
+ streaming.value = true
267
+ outputText.value = ''
268
+ errorText.value = ''
269
+ abortCtrl.value = new AbortController()
270
+
271
+ try {
272
+ const { router } = buildEnv()
273
+ const pick = {
274
+ strategy: strategyMode.value === 'agf_mode' ? 'fixed' : strategyMode.value,
275
+ mode: aiMode.value,
276
+ countryCode: countryCode.value.trim() || undefined,
277
+ preferredModel:
278
+ preferredProviderId.value && preferredModelId.value
279
+ ? { providerId: preferredProviderId.value, modelId: preferredModelId.value }
280
+ : undefined,
281
+ }
282
+
283
+ if (runnerMode.value === 'agent') {
284
+ const agent = createAiAgent({ router, maxSteps: 6 })
285
+ for await (const ev of agent.runStream({
286
+ messages: makeMessages(),
287
+ pick,
288
+ abortSignal: abortCtrl.value.signal,
289
+ })) {
290
+ if (ev.type === 'token') outputText.value += ev.token
291
+ }
292
+ return
293
+ }
294
+
295
+ for await (const ev of router.chatStream({
296
+ messages: makeMessages(),
297
+ pick,
298
+ abortSignal: abortCtrl.value.signal,
299
+ })) {
300
+ if (ev.type === 'token') outputText.value += ev.token
301
+ }
302
+ } catch (e) {
303
+ errorText.value = String((e as Error)?.message || e)
304
+ } finally {
305
+ abortCtrl.value = null
306
+ running.value = false
307
+ streaming.value = false
308
+ }
309
+ }
310
+
311
+ watch(
312
+ () => preferredProviderId.value,
313
+ () => {
314
+ const ms = modelsForPreferredProvider.value
315
+ preferredModelId.value = ms[0] || ''
316
+ },
317
+ { immediate: true },
318
+ )
319
+
320
+ watch(
321
+ () => keyForProviderId.value,
322
+ async () => {
323
+ await loadKey()
324
+ },
325
+ )
326
+
327
+ onMounted(async () => {
328
+ await loadKey()
329
+ })
330
+ </script>
331
+
332
+ <template>
333
+ <div class="wrap">
334
+ <div class="title">ai-api-manager · vue-tauri</div>
335
+
336
+ <div class="grid">
337
+ <div class="card">
338
+ <div class="sectionTitle">路由</div>
339
+
340
+ <div class="row">
341
+ <label class="label">Mode</label>
342
+ <select v-model="aiMode" class="control">
343
+ <option value="official">official</option>
344
+ <option value="user">user</option>
345
+ </select>
346
+ </div>
347
+
348
+ <div class="row">
349
+ <label class="label">Country</label>
350
+ <input v-model="countryCode" class="control" />
351
+ </div>
352
+
353
+ <div class="row">
354
+ <label class="label">Strategy</label>
355
+ <select v-model="strategyMode" class="control">
356
+ <option value="agf_mode">agf_mode</option>
357
+ <option value="fixed">fixed</option>
358
+ <option value="speed">speed</option>
359
+ <option value="price">price</option>
360
+ <option value="quality">quality</option>
361
+ </select>
362
+ </div>
363
+
364
+ <div class="row">
365
+ <label class="label">Runner</label>
366
+ <select v-model="runnerMode" class="control">
367
+ <option value="router">router</option>
368
+ <option value="agent">agent</option>
369
+ </select>
370
+ </div>
371
+
372
+ <div class="row">
373
+ <label class="label">Provider</label>
374
+ <select v-model="preferredProviderId" class="control" :disabled="lockModelSelection">
375
+ <option v-for="p in callableProviders" :key="p" :value="p">{{ p }}</option>
376
+ </select>
377
+ </div>
378
+
379
+ <div class="row">
380
+ <label class="label">Model</label>
381
+ <select v-model="preferredModelId" class="control" :disabled="lockModelSelection">
382
+ <option v-for="m in modelsForPreferredProvider" :key="m" :value="m">{{ m }}</option>
383
+ </select>
384
+ </div>
385
+ </div>
386
+
387
+ <div class="card">
388
+ <div class="sectionTitle">Key</div>
389
+ <div class="row">
390
+ <label class="label">Provider</label>
391
+ <select v-model="keyForProviderId" class="control">
392
+ <option v-for="p in allProviders" :key="p" :value="p">
393
+ {{ p }}{{ keyStatus[p] ? ' (saved)' : '' }}
394
+ </option>
395
+ </select>
396
+ </div>
397
+
398
+ <div class="row">
399
+ <label class="label">API Key</label>
400
+ <input v-model="apiKey" class="control" type="password" />
401
+ </div>
402
+
403
+ <div class="row">
404
+ <div class="spacer"></div>
405
+ <button class="btn" @click="saveKey">保存</button>
406
+ <button class="btn btnGhost" @click="clearKey">清空</button>
407
+ </div>
408
+ </div>
409
+
410
+ <div class="card">
411
+ <div class="sectionTitle">Prompt</div>
412
+
413
+ <div class="row">
414
+ <label class="label">System</label>
415
+ <textarea v-model="systemPrompt" class="control textarea"></textarea>
416
+ </div>
417
+
418
+ <div class="row">
419
+ <label class="label">User</label>
420
+ <textarea v-model="userPrompt" class="control textarea"></textarea>
421
+ </div>
422
+
423
+ <div class="row">
424
+ <div class="spacer"></div>
425
+ <button class="btn" :disabled="running" @click="runOnce">非流式</button>
426
+ <button class="btn" :disabled="running" @click="runStream">流式</button>
427
+ <button class="btn btnGhost" :disabled="!running" @click="stop">停止</button>
428
+ </div>
429
+ </div>
430
+
431
+ <div class="card">
432
+ <div class="sectionTitle">输出</div>
433
+ <pre class="output">{{ outputText }}</pre>
434
+ <div v-if="errorText" class="error">{{ errorText }}</div>
435
+ </div>
436
+ </div>
437
+ </div>
438
+ </template>
439
+
440
+ <style scoped>
441
+ .wrap {
442
+ font-family:
443
+ ui-sans-serif,
444
+ system-ui,
445
+ -apple-system,
446
+ BlinkMacSystemFont,
447
+ 'Segoe UI',
448
+ sans-serif;
449
+ padding: 16px;
450
+ }
451
+ .title {
452
+ font-size: 16px;
453
+ font-weight: 700;
454
+ margin-bottom: 12px;
455
+ }
456
+ .grid {
457
+ display: grid;
458
+ grid-template-columns: repeat(2, minmax(0, 1fr));
459
+ gap: 12px;
460
+ }
461
+ .card {
462
+ border: 1px solid rgba(0, 0, 0, 0.12);
463
+ border-radius: 10px;
464
+ padding: 12px;
465
+ }
466
+ .sectionTitle {
467
+ font-weight: 700;
468
+ margin-bottom: 10px;
469
+ }
470
+ .row {
471
+ display: flex;
472
+ align-items: center;
473
+ gap: 8px;
474
+ margin-bottom: 8px;
475
+ }
476
+ .label {
477
+ width: 72px;
478
+ color: rgba(0, 0, 0, 0.7);
479
+ font-size: 12px;
480
+ }
481
+ .control {
482
+ flex: 1;
483
+ font-size: 13px;
484
+ padding: 6px 8px;
485
+ border-radius: 8px;
486
+ border: 1px solid rgba(0, 0, 0, 0.12);
487
+ outline: none;
488
+ }
489
+ .textarea {
490
+ min-height: 60px;
491
+ resize: vertical;
492
+ }
493
+ .spacer {
494
+ flex: 1;
495
+ }
496
+ .btn {
497
+ font-size: 13px;
498
+ padding: 6px 10px;
499
+ border-radius: 8px;
500
+ border: 1px solid rgba(0, 0, 0, 0.12);
501
+ background: #111;
502
+ color: #fff;
503
+ }
504
+ .btn:disabled {
505
+ opacity: 0.6;
506
+ }
507
+ .btnGhost {
508
+ background: transparent;
509
+ color: #111;
510
+ }
511
+ .output {
512
+ white-space: pre-wrap;
513
+ word-break: break-word;
514
+ font-size: 13px;
515
+ line-height: 1.4;
516
+ margin: 0;
517
+ }
518
+ .error {
519
+ margin-top: 10px;
520
+ color: #b00020;
521
+ font-size: 13px;
522
+ }
523
+ @media (max-width: 860px) {
524
+ .grid {
525
+ grid-template-columns: 1fr;
526
+ }
527
+ }
528
+ </style>
@@ -0,0 +1,5 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+
4
+ createApp(App).mount('#app')
5
+
@@ -0,0 +1,9 @@
1
+ declare module '*.vue' {
2
+ import type { DefineComponent } from 'vue'
3
+ const __createAiApiManagerVueSfc: DefineComponent<
4
+ Record<string, unknown>,
5
+ Record<string, unknown>,
6
+ unknown
7
+ >
8
+ export default __createAiApiManagerVueSfc
9
+ }
@@ -0,0 +1,20 @@
1
+ [package]
2
+ name = "__TAURI_PACKAGE_NAME__"
3
+ version = "0.1.0"
4
+ description = "ai-api-manager vue-tauri app"
5
+ authors = ["you"]
6
+ edition = "2021"
7
+
8
+ [lib]
9
+ name = "__TAURI_LIB_NAME__"
10
+ crate-type = ["staticlib", "cdylib", "rlib"]
11
+
12
+ [build-dependencies]
13
+ tauri-build = { version = "2", features = [] }
14
+
15
+ [dependencies]
16
+ tauri = { version = "2", features = [] }
17
+ tauri-plugin-shell = "2"
18
+ serde = { version = "1", features = ["derive"] }
19
+ serde_json = "1"
20
+
@@ -0,0 +1,4 @@
1
+ fn main() {
2
+ tauri_build::build()
3
+ }
4
+
@@ -0,0 +1,7 @@
1
+ #[cfg_attr(mobile, tauri::mobile_entry_point)]
2
+ pub fn run() {
3
+ tauri::Builder::default()
4
+ .run(tauri::generate_context!())
5
+ .expect("error while running tauri application");
6
+ }
7
+
@@ -0,0 +1,6 @@
1
+ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2
+
3
+ fn main() {
4
+ __TAURI_LIB_NAME__::run()
5
+ }
6
+
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://schema.tauri.app/config/2",
3
+ "productName": "__PRODUCT_NAME__",
4
+ "version": "0.1.0",
5
+ "identifier": "__IDENTIFIER__",
6
+ "build": {
7
+ "beforeDevCommand": "npm run dev",
8
+ "beforeBuildCommand": "",
9
+ "devUrl": "http://localhost:1420",
10
+ "frontendDist": "../dist"
11
+ },
12
+ "app": {
13
+ "windows": [
14
+ {
15
+ "title": "__PRODUCT_NAME__",
16
+ "width": 1100,
17
+ "height": 760
18
+ }
19
+ ],
20
+ "security": {
21
+ "csp": null
22
+ }
23
+ }
24
+ }
25
+
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "@vue/tsconfig/tsconfig.dom.json",
3
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
4
+ "exclude": [],
5
+ "compilerOptions": {
6
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
7
+ "noUncheckedIndexedAccess": false,
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
12
+ }
13
+ }
14
+
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "./tsconfig.app.json",
3
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue"]
4
+ }
5
+
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "@tsconfig/node22/tsconfig.json",
3
+ "include": ["vite.config.*"],
4
+ "compilerOptions": {
5
+ "noEmit": true,
6
+ "module": "ESNext",
7
+ "moduleResolution": "Bundler",
8
+ "types": ["node"]
9
+ }
10
+ }
11
+
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+
4
+ export default defineConfig({
5
+ plugins: [vue()],
6
+ clearScreen: false,
7
+ server: {
8
+ port: 1420,
9
+ strictPort: true,
10
+ },
11
+ })
12
+