@fengyunxuezhang/tiez 0.1.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.
Files changed (63) hide show
  1. package/README.md +77 -0
  2. package/bin/tiez.js +50 -0
  3. package/dist/api/auth-routes.d.ts +3 -0
  4. package/dist/api/auth-routes.d.ts.map +1 -0
  5. package/dist/api/auth-routes.js +29 -0
  6. package/dist/api/auth-routes.js.map +1 -0
  7. package/dist/api/billing-routes.d.ts +3 -0
  8. package/dist/api/billing-routes.d.ts.map +1 -0
  9. package/dist/api/billing-routes.js +20 -0
  10. package/dist/api/billing-routes.js.map +1 -0
  11. package/dist/api/chat.d.ts +3 -0
  12. package/dist/api/chat.d.ts.map +1 -0
  13. package/dist/api/chat.js +70 -0
  14. package/dist/api/chat.js.map +1 -0
  15. package/dist/api/models.d.ts +3 -0
  16. package/dist/api/models.d.ts.map +1 -0
  17. package/dist/api/models.js +11 -0
  18. package/dist/api/models.js.map +1 -0
  19. package/dist/api/server.d.ts +2 -0
  20. package/dist/api/server.d.ts.map +1 -0
  21. package/dist/api/server.js +88 -0
  22. package/dist/api/server.js.map +1 -0
  23. package/dist/cli/commands.d.ts +19 -0
  24. package/dist/cli/commands.d.ts.map +1 -0
  25. package/dist/cli/commands.js +66 -0
  26. package/dist/cli/commands.js.map +1 -0
  27. package/dist/cli/index.d.ts +3 -0
  28. package/dist/cli/index.d.ts.map +1 -0
  29. package/dist/cli/index.js +145 -0
  30. package/dist/cli/index.js.map +1 -0
  31. package/dist/config.d.ts +10 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +24 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/db/index.d.ts +4 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +80 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/index.d.ts +7 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +51 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/middleware/auth.d.ts +3 -0
  44. package/dist/middleware/auth.d.ts.map +1 -0
  45. package/dist/middleware/auth.js +32 -0
  46. package/dist/middleware/auth.js.map +1 -0
  47. package/dist/services/billing.d.ts +11 -0
  48. package/dist/services/billing.d.ts.map +1 -0
  49. package/dist/services/billing.js +45 -0
  50. package/dist/services/billing.js.map +1 -0
  51. package/dist/services/llm.d.ts +11 -0
  52. package/dist/services/llm.d.ts.map +1 -0
  53. package/dist/services/llm.js +29 -0
  54. package/dist/services/llm.js.map +1 -0
  55. package/dist/services/model-router.d.ts +7 -0
  56. package/dist/services/model-router.d.ts.map +1 -0
  57. package/dist/services/model-router.js +39 -0
  58. package/dist/services/model-router.js.map +1 -0
  59. package/dist/services/user.d.ts +44 -0
  60. package/dist/services/user.d.ts.map +1 -0
  61. package/dist/services/user.js +73 -0
  62. package/dist/services/user.js.map +1 -0
  63. package/package.json +42 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # 铁子 (Tiez) — 嵌入式开发 AI 助手
2
+
3
+ **一行命令安装,零依赖:**
4
+
5
+ ```bash
6
+ npm install -g tiez
7
+ ```
8
+
9
+ 或者直接从源码安装:
10
+
11
+ ```bash
12
+ git clone https://gitee.com/fengyun-senior/tiez.git
13
+ cd tiez/03_source_node
14
+ npm install
15
+ npm link # 全局安装 tiez 命令
16
+ ```
17
+
18
+ ## 快速开始
19
+
20
+ ```bash
21
+ # 1. 初始化数据库
22
+ tiez init
23
+
24
+ # 2. 创建管理员
25
+ tiez admin admin@example.com 123456
26
+
27
+ # 3. 启动服务
28
+ DEEPSEEK_API_KEY="sk-your-deepseek-key" tiez
29
+
30
+ # 4. 浏览器打开管理后台
31
+ # http://localhost:8000/web/?api_key=刚才输出的Key
32
+
33
+ # 5. 新窗口打开交互式终端
34
+ # export TIEZ_API_KEY="刚才的Key"
35
+ # tiez chat
36
+ ```
37
+
38
+ ## 用法
39
+
40
+ ```bash
41
+ tiez 启动 API 服务
42
+ tiez chat 启动交互式 CLI 终端
43
+ tiez init 初始化数据库
44
+ tiez admin <email> <password> 创建管理员
45
+ tiez --help 帮助
46
+ ```
47
+
48
+ ## CLI 终端命令
49
+
50
+ | 命令 | 说明 | 示例 |
51
+ |------|------|------|
52
+ | `/chip <型号>` | 设置芯片 | `/chip stm32f103` |
53
+ | `/mode <模式>` | 切换模式 | `/mode deep` |
54
+ | `/load <文件>` | 加载代码 | `/load main.c` |
55
+ | `/save <文件>` | 保存回复 | `/save driver.c` |
56
+ | `/clear` | 清空对话 | `/clear` |
57
+ | `/help` | 帮助 | `/help` |
58
+ | `/exit` | 退出 | `/exit` |
59
+
60
+ ## API 调用
61
+
62
+ ```python
63
+ from openai import OpenAI
64
+ client = OpenAI(api_key="你的Key", base_url="http://localhost:8000/v1")
65
+ resp = client.chat.completions.create(
66
+ model="tiez-default",
67
+ messages=[{"role": "user", "content": "写一个 STM32F103 I2C 驱动"}]
68
+ )
69
+ ```
70
+
71
+ ## 环境变量
72
+
73
+ | 变量 | 说明 | 默认值 |
74
+ |------|------|--------|
75
+ | `DEEPSEEK_API_KEY` | DeepSeek API Key | - |
76
+ | `TIEZ_API_KEY` | 铁子 API Key(CLI 用) | - |
77
+ | `TIEZ_PORT` | 服务端口 | 8000 |
package/bin/tiez.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 铁子 (Tiez) — 嵌入式开发 AI 助手
4
+ *
5
+ * 用法:
6
+ * tiez 启动 API 服务
7
+ * tiez chat 启动交互式 CLI
8
+ * tiez init 初始化数据库
9
+ * tiez admin 创建管理员
10
+ * tiez --help 帮助
11
+ */
12
+ const path = require('path');
13
+ const { execSync } = require('child_process');
14
+
15
+ const BIN = path.resolve(__dirname, '..');
16
+ process.env.TIEZ_ROOT = BIN;
17
+
18
+ const cmd = process.argv[2] || 'start';
19
+
20
+ if (cmd === '--help' || cmd === '-h') {
21
+ console.log(`
22
+ 铁子 (Tiez) v0.1.0 — 嵌入式开发 AI 助手
23
+
24
+ 用法:
25
+ tiez 启动 API 服务 (http://localhost:8000)
26
+ tiez chat 启动交互式 CLI 终端
27
+ tiez init 初始化数据库并创建管理员
28
+
29
+ 环境变量:
30
+ DEEPSEEK_API_KEY DeepSeek API Key(必填)
31
+ TIEZ_PORT 服务端口 (默认 8000)
32
+ `);
33
+ process.exit(0);
34
+ }
35
+
36
+ const SCRIPT = path.join(BIN, 'dist', 'index.js');
37
+ const CLI_SCRIPT = path.join(BIN, 'dist', 'cli', 'index.js');
38
+
39
+ try {
40
+ require('fs').accessSync(SCRIPT);
41
+ } catch {
42
+ console.log('正在编译 TypeScript...');
43
+ execSync('npx tsc', { cwd: BIN, stdio: 'inherit' });
44
+ }
45
+
46
+ if (cmd === 'chat') {
47
+ require(CLI_SCRIPT);
48
+ } else {
49
+ require(SCRIPT);
50
+ }
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=auth-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-routes.d.ts","sourceRoot":"","sources":["../../src/api/auth-routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA0BxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const user_1 = require("../services/user");
5
+ const router = (0, express_1.Router)();
6
+ const userService = new user_1.UserService();
7
+ router.post('/v1/api-keys', (req, res) => {
8
+ const user = req.user;
9
+ const { name = '' } = req.body;
10
+ const { rawKey, apiKey } = userService.createApiKey(user.id, name);
11
+ res.json({ id: apiKey.id, key: rawKey, name: apiKey.name, prefix: apiKey.key_prefix, created_at: apiKey.created_at });
12
+ });
13
+ router.get('/v1/api-keys', (req, res) => {
14
+ const user = req.user;
15
+ const keys = userService.getApiKeys(user.id).map(k => ({
16
+ id: k.id, prefix: k.key_prefix, name: k.name, status: k.status,
17
+ last_used_at: k.last_used_at, created_at: k.created_at,
18
+ }));
19
+ res.json({ data: keys });
20
+ });
21
+ router.delete('/v1/api-keys/:keyId', (req, res) => {
22
+ const user = req.user;
23
+ const ok = userService.revokeApiKey(req.params.keyId, user.id);
24
+ if (!ok)
25
+ return res.status(404).json({ error: 'API Key not found' });
26
+ res.json({ status: 'revoked' });
27
+ });
28
+ exports.default = router;
29
+ //# sourceMappingURL=auth-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-routes.js","sourceRoot":"","sources":["../../src/api/auth-routes.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AACpD,2CAA+C;AAG/C,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AACxB,MAAM,WAAW,GAAG,IAAI,kBAAW,EAAE,CAAC;AAEtC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC1D,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACnE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AACxH,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACzD,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrD,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM;QAC9D,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU;KACvD,CAAC,CAAC,CAAC;IACJ,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACnE,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,MAAM,EAAE,GAAG,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACrE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=billing-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-routes.d.ts","sourceRoot":"","sources":["../../src/api/billing-routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAgBxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const billing_1 = require("../services/billing");
5
+ const user_1 = require("../services/user");
6
+ const router = (0, express_1.Router)();
7
+ router.get('/v1/billing/balance', (req, res) => {
8
+ const user = req.user;
9
+ const billing = new billing_1.BillingService();
10
+ res.json(billing.getUsageStats(user));
11
+ });
12
+ router.get('/v1/billing/plans', (_req, res) => {
13
+ const plans = Object.entries(user_1.PLAN_QUOTAS).map(([id, v]) => ({
14
+ id, name: id.charAt(0).toUpperCase() + id.slice(1),
15
+ price_rmb: v.price, tokens_monthly: v.tokens, rpm: v.rpm, tpm: v.tpm,
16
+ }));
17
+ res.json({ data: plans });
18
+ });
19
+ exports.default = router;
20
+ //# sourceMappingURL=billing-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-routes.js","sourceRoot":"","sources":["../../src/api/billing-routes.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AACpD,iDAAqD;AACrD,2CAAqD;AAErD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAChE,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,wBAAc,EAAE,CAAC;IACrC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACxC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG;KACrE,CAAC,CAAC,CAAC;IACJ,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/api/chat.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAuExB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const uuid_1 = require("uuid");
5
+ const llm_1 = require("../services/llm");
6
+ const billing_1 = require("../services/billing");
7
+ const model_router_1 = require("../services/model-router");
8
+ const router = (0, express_1.Router)();
9
+ router.post('/v1/chat/completions', async (req, res) => {
10
+ const user = req.user;
11
+ const { model = 'tiez-default', messages = [], stream = false, max_tokens = 4096, temperature = 0.3 } = req.body;
12
+ const estimated = billing_1.BillingService.estimateTokens(messages);
13
+ const billing = new billing_1.BillingService();
14
+ if (!billing.preAuth(user, estimated)) {
15
+ return res.status(402).json({
16
+ error: { message: `Insufficient balance. ${user.tokens_balance} tokens remaining.`, type: 'insufficient_quota', code: 402 },
17
+ });
18
+ }
19
+ const resolvedModel = (0, model_router_1.resolveModel)(model, user.plan);
20
+ const requestId = `chatcmpl-${(0, uuid_1.v4)().slice(0, 12)}`;
21
+ const llm = new llm_1.LLMService();
22
+ // 检查 DeepSeek Key 是否有效(非占位符)
23
+ const hasValidKey = !!process.env.DEEPSEEK_API_KEY && process.env.DEEPSEEK_API_KEY !== 'sk-placeholder';
24
+ try {
25
+ if (stream) {
26
+ res.setHeader('Content-Type', 'text/event-stream');
27
+ res.setHeader('Cache-Control', 'no-cache');
28
+ res.setHeader('Connection', 'keep-alive');
29
+ if (!hasValidKey) {
30
+ const mock = { id: requestId, object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000),
31
+ model: resolvedModel, choices: [{ index: 0, delta: { content: '铁子就绪,请设置 DEEPSEEK_API_KEY 以启用真实模型。' }, finish_reason: 'stop' }] };
32
+ res.write(`data: ${JSON.stringify(mock)}\n\n`);
33
+ res.write('data: [DONE]\n\n');
34
+ res.end();
35
+ billing.settle(user, 30, resolvedModel, requestId);
36
+ return;
37
+ }
38
+ const streamResp = await llm.complete(messages, resolvedModel, true, max_tokens, temperature);
39
+ let fullContent = '';
40
+ for await (const chunk of streamResp) {
41
+ const content = chunk.choices?.[0]?.delta?.content || '';
42
+ fullContent += content;
43
+ res.write(`data: ${JSON.stringify({
44
+ id: requestId, object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000),
45
+ model: resolvedModel, choices: [{ index: 0, delta: { content }, finish_reason: null }],
46
+ })}\n\n`);
47
+ }
48
+ res.write('data: [DONE]\n\n');
49
+ res.end();
50
+ billing.settle(user, Math.max(30, Math.ceil(fullContent.length * 1.5)), resolvedModel, requestId);
51
+ return;
52
+ }
53
+ const response = hasValidKey
54
+ ? await llm.complete(messages, resolvedModel, false, max_tokens, temperature)
55
+ : { choices: [{ message: { content: '铁子就绪,请设置 DEEPSEEK_API_KEY 以启用真实模型。' } }], usage: { prompt_tokens: 10, completion_tokens: 20, total_tokens: 30 } };
56
+ const usage = { prompt_tokens: response.usage?.prompt_tokens || 10, completion_tokens: response.usage?.completion_tokens || 20, total_tokens: response.usage?.total_tokens || 30 };
57
+ billing.settle(user, usage.total_tokens, resolvedModel, requestId);
58
+ res.json({
59
+ id: requestId, object: 'chat.completion', created: Math.floor(Date.now() / 1000),
60
+ model: resolvedModel,
61
+ choices: [{ index: 0, message: { role: 'assistant', content: response.choices?.[0]?.message?.content || '' }, finish_reason: 'stop' }],
62
+ usage,
63
+ });
64
+ }
65
+ catch (err) {
66
+ res.status(502).json({ error: { message: `LLM error: ${err.message}`, type: 'server_error', code: 502 } });
67
+ }
68
+ });
69
+ exports.default = router;
70
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/api/chat.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AACpD,+BAAoC;AACpC,yCAA6C;AAC7C,iDAAqD;AACrD,2DAAwD;AAGxD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACxE,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,MAAM,EAAE,KAAK,GAAG,cAAc,EAAE,QAAQ,GAAG,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE,UAAU,GAAG,IAAI,EAAE,WAAW,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IAEjH,MAAM,SAAS,GAAG,wBAAc,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,wBAAc,EAAE,CAAC;IACrC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,EAAE,OAAO,EAAE,yBAAyB,IAAI,CAAC,cAAc,oBAAoB,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,GAAG,EAAE;SAC5H,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GAAG,IAAA,2BAAY,EAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,YAAY,IAAA,SAAM,GAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,gBAAU,EAAE,CAAC;IAE7B,6BAA6B;IAC7B,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,gBAAgB,CAAC;IAExG,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,CAAC;YACX,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;YACnD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;YAC3C,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;YAE1C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;oBACnG,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,oCAAoC,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;gBACnI,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC/C,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBAC9B,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,CAAQ,CAAC;YACrG,IAAI,WAAW,GAAG,EAAE,CAAC;YACrB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;gBACrC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;gBACzD,WAAW,IAAI,OAAO,CAAC;gBACvB,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC;oBAChC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;oBACtF,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;iBACvF,CAAC,MAAM,CAAC,CAAC;YACZ,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC9B,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;YAClG,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW;YAC1B,CAAC,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,CAAQ;YACpF,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,oCAAoC,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,CAAC;QAEzJ,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,KAAK,EAAE,YAAY,IAAI,EAAE,EAAE,CAAC;QACnL,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QAEnE,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAChF,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;YACtI,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/api/models.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAOxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const model_router_1 = require("../services/model-router");
5
+ const router = (0, express_1.Router)();
6
+ router.get('/v1/models', (req, res) => {
7
+ const user = req.user;
8
+ res.json({ object: 'list', data: (0, model_router_1.getAvailableModels)(user?.plan || 'free') });
9
+ });
10
+ exports.default = router;
11
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/api/models.ts"],"names":[],"mappings":";;AAAA,qCAAoD;AACpD,2DAA8D;AAG9D,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACvD,MAAM,IAAI,GAAI,GAAW,CAAC,IAAY,CAAC;IACvC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAA,iCAAkB,EAAC,IAAI,EAAE,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function createApp(): import("express-serve-static-core").Express;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAQA,wBAAgB,SAAS,gDAoCxB"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createApp = createApp;
7
+ const express_1 = __importDefault(require("express"));
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const auth_1 = require("../middleware/auth");
10
+ const chat_1 = __importDefault(require("./chat"));
11
+ const models_1 = __importDefault(require("./models"));
12
+ const auth_routes_1 = __importDefault(require("./auth-routes"));
13
+ const billing_routes_1 = __importDefault(require("./billing-routes"));
14
+ function createApp() {
15
+ const app = (0, express_1.default)();
16
+ app.use((0, cors_1.default)());
17
+ app.use(express_1.default.json());
18
+ app.use(auth_1.authMiddleware);
19
+ // Health
20
+ app.get('/health', (_req, res) => res.json({ status: 'ok', version: '0.1.0' }));
21
+ // API routes
22
+ app.use(chat_1.default);
23
+ app.use(models_1.default);
24
+ app.use(auth_routes_1.default);
25
+ app.use(billing_routes_1.default);
26
+ // Web admin (simple HTML)
27
+ app.get('/web/', (req, res) => {
28
+ const user = req.user;
29
+ if (!user)
30
+ return res.status(401).json({ error: 'Not authenticated' });
31
+ const stats = new (require('../services/billing').BillingService)().getUsageStats(user);
32
+ const keys = new (require('../services/user').UserService)().getApiKeys(user.id);
33
+ res.send(renderDashboard(user, stats, keys));
34
+ });
35
+ app.get('/web/keys', (req, res) => {
36
+ const user = req.user;
37
+ if (!user)
38
+ return res.status(401).json({ error: 'Not authenticated' });
39
+ const keys = new (require('../services/user').UserService)().getApiKeys(user.id);
40
+ res.send(renderKeys(user, keys));
41
+ });
42
+ return app;
43
+ }
44
+ function renderDashboard(user, stats, keys) {
45
+ const pct = stats.monthly_quota > 0 ? (stats.monthly_used / stats.monthly_quota * 100).toFixed(1) : 0;
46
+ return `<!DOCTYPE html>
47
+ <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
48
+ <title>铁子管理后台</title><script src="https://cdn.tailwindcss.com"></script></head>
49
+ <body class="bg-gray-50">
50
+ <nav class="bg-white shadow-sm border-b"><div class="max-w-5xl mx-auto px-4 py-3 flex items-center justify-between">
51
+ <span class="text-lg font-bold text-gray-800">铁子</span>
52
+ <div class="flex items-center gap-6">
53
+ <a href="/web/" class="text-sm text-gray-600 hover:text-gray-900">用量看板</a>
54
+ <a href="/web/keys" class="text-sm text-gray-600 hover:text-gray-900">API Key</a></div>
55
+ <div class="text-sm text-gray-500">${user.email} &middot; ${user.plan}</div></div></nav>
56
+ <main class="max-w-5xl mx-auto px-4 py-6">
57
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
58
+ <div class="bg-white rounded-lg shadow p-4"><div class="text-sm text-gray-500">套餐</div><div class="text-2xl font-bold">${stats.plan}</div></div>
59
+ <div class="bg-white rounded-lg shadow p-4"><div class="text-sm text-gray-500">已用 / 月配额</div>
60
+ <div class="text-2xl font-bold">${stats.monthly_used.toLocaleString()} <span class="text-sm text-gray-400">/ ${stats.monthly_quota.toLocaleString()}</span></div>
61
+ <div class="w-full bg-gray-200 rounded-full h-2 mt-2"><div class="bg-blue-500 h-2 rounded-full" style="width:${pct}%"></div></div></div>
62
+ <div class="bg-white rounded-lg shadow p-4"><div class="text-sm text-gray-500">总余额</div><div class="text-2xl font-bold">${stats.balance.toLocaleString()}</div></div></div>
63
+ <div class="bg-white rounded-lg shadow p-4"><h2 class="text-lg font-bold mb-3">最近请求</h2>
64
+ ${stats.recent_requests?.length ? `<table class="w-full text-sm"><thead><tr class="text-left text-gray-500 border-b"><th class="pb-2">模型</th><th class="pb-2">Token</th><th class="pb-2">时间</th></tr></thead><tbody>
65
+ ${stats.recent_requests.map((r) => `<tr class="border-b border-gray-100"><td class="py-2">${r.model}</td><td class="py-2">${r.tokens}</td><td class="py-2 text-gray-500">${(r.time || '').slice(0, 19)}</td></tr>`).join('')}
66
+ </tbody></table>` : '<p class="text-gray-400 text-sm">暂无请求记录</p>'}</div></main></body></html>`;
67
+ }
68
+ function renderKeys(user, keys) {
69
+ return `<!DOCTYPE html>
70
+ <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
71
+ <title>API Key 管理 - 铁子</title><script src="https://cdn.tailwindcss.com"></script></head>
72
+ <body class="bg-gray-50">
73
+ <nav class="bg-white shadow-sm border-b"><div class="max-w-5xl mx-auto px-4 py-3 flex items-center justify-between">
74
+ <span class="text-lg font-bold text-gray-800">铁子</span>
75
+ <div class="flex items-center gap-6">
76
+ <a href="/web/" class="text-sm text-gray-600 hover:text-gray-900">用量看板</a>
77
+ <a href="/web/keys" class="text-sm text-gray-600 hover:text-gray-900">API Key</a></div>
78
+ <div class="text-sm text-gray-500">${user.email} &middot; ${user.plan}</div></div></nav>
79
+ <main class="max-w-5xl mx-auto px-4 py-6">
80
+ <div class="bg-white rounded-lg shadow p-4"><h2 class="text-lg font-bold mb-4">API Key 管理</h2>
81
+ ${keys.length ? `<table class="w-full text-sm"><thead><tr class="text-left text-gray-500 border-b"><th class="pb-2">名称</th><th class="pb-2">Key 前缀</th><th class="pb-2">状态</th><th class="pb-2">最后使用</th><th class="pb-2">创建时间</th></tr></thead><tbody>
82
+ ${keys.map(k => `<tr class="border-b border-gray-100"><td class="py-2">${k.name || '-'}</td><td class="py-2 font-mono text-xs">${k.prefix}...</td>
83
+ <td class="py-2"><span class="px-2 py-0.5 rounded-full text-xs ${k.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'}">${k.status}</span></td>
84
+ <td class="py-2 text-gray-500 text-xs">${k.last_used_at ? k.last_used_at.slice(0, 19) : '-'}</td>
85
+ <td class="py-2 text-gray-500 text-xs">${(k.created_at || '').slice(0, 19)}</td></tr>`).join('')}
86
+ </tbody></table>` : '<p class="text-gray-400 text-sm">暂无 API Key</p>'}</div></main></body></html>`;
87
+ }
88
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface CliState {
2
+ chip: string;
3
+ mode: string;
4
+ messages: {
5
+ role: string;
6
+ content: string;
7
+ }[];
8
+ loadedFiles: {
9
+ path: string;
10
+ content: string;
11
+ }[];
12
+ lastResponse: string;
13
+ }
14
+ export declare function handleCommand(text: string, state: CliState): {
15
+ handled: boolean;
16
+ message: string;
17
+ exit?: boolean;
18
+ };
19
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CA8DlH"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleCommand = handleCommand;
4
+ function handleCommand(text, state) {
5
+ const parts = text.trim().split(/\s+/);
6
+ const cmd = parts[0].toLowerCase();
7
+ const arg = parts.slice(1).join(' ');
8
+ switch (cmd) {
9
+ case '/chip':
10
+ if (!arg)
11
+ return { handled: true, message: `当前芯片: ${state.chip || '(未设置)'}` };
12
+ state.chip = arg;
13
+ return { handled: true, message: `已切换到芯片: ${arg}` };
14
+ case '/mode': {
15
+ const valid = ['quick', 'deep', 'review'];
16
+ if (!valid.includes(arg))
17
+ return { handled: true, message: `当前模式: ${state.mode} (可用: quick/deep/review)` };
18
+ state.mode = arg;
19
+ return { handled: true, message: `已切换到模式: ${arg}` };
20
+ }
21
+ case '/load': {
22
+ if (!arg)
23
+ return { handled: true, message: '用法: /load <文件路径>' };
24
+ try {
25
+ const fs = require('fs');
26
+ const content = fs.readFileSync(arg, 'utf-8');
27
+ state.loadedFiles.push({ path: arg, content });
28
+ return { handled: true, message: `已加载: ${arg} (${content.split('\n').length} 行)` };
29
+ }
30
+ catch (e) {
31
+ return { handled: true, message: `加载失败: ${e.message}` };
32
+ }
33
+ }
34
+ case '/save': {
35
+ if (!arg)
36
+ return { handled: true, message: '用法: /save <文件名>' };
37
+ if (!state.lastResponse)
38
+ return { handled: true, message: '没有可保存的内容' };
39
+ try {
40
+ require('fs').writeFileSync(arg, state.lastResponse, 'utf-8');
41
+ return { handled: true, message: `已保存到: ${arg}` };
42
+ }
43
+ catch (e) {
44
+ return { handled: true, message: `保存失败: ${e.message}` };
45
+ }
46
+ }
47
+ case '/clear':
48
+ state.messages = [];
49
+ return { handled: true, message: '对话已清空' };
50
+ case '/help':
51
+ return { handled: true, message: `
52
+ 可用命令:
53
+ /chip <型号> 设置芯片型号 (如 stm32f103, esp32)
54
+ /mode <模式> 切换模式 (quick 快速, deep 深度, review 审查)
55
+ /load <文件> 加载代码文件到上下文
56
+ /save <文件名> 保存回复到文件
57
+ /clear 清空对话历史
58
+ /help 显示帮助
59
+ /exit 退出` };
60
+ case '/exit':
61
+ return { handled: true, message: '再见!', exit: true };
62
+ default:
63
+ return { handled: false, message: `未知命令: ${cmd}。输入 /help 查看可用命令。` };
64
+ }
65
+ }
66
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}