dsh-model 0.22.3 → 0.23.2
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/README.en.md +39 -16
- package/README.md +40 -17
- package/dist/daemon/core.js +4 -1
- package/dist/integrations/workbuddy.js +24 -0
- package/package.json +4 -2
- package/plugin/client.js +18 -9
package/README.en.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-model
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**📅 Daily check-in credits claimed for you · 🔁 one address that relays every model · 🧩 free and subscription models, your pick**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Install once and all three are taken care of. dsh gets a management page; without dsh, the command line does everything.
|
|
8
8
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="LICENSE"><img src="https://img.shields.io/github/license/AIcivilization/dsh-model" alt="MIT license"></a>
|
|
@@ -19,22 +19,45 @@ English · [中文](README.md)
|
|
|
19
19
|
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 📅 1. Daily check-in: credits land on their own
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**The most hands-off part: no more remembering to claim the daily check-in credits.**
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
| Product | How it connects | Every day |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| **Trae** | Detected automatically if Trae is installed and signed in; nothing to do | Check-in credits (200 a day in testing) |
|
|
29
|
+
| **Qoder** | Paste a personal access token once (China or international) | That day's check-in credits |
|
|
30
|
+
| **WorkBuddy (China)** | Sign in once | Check-in credits |
|
|
31
|
+
|
|
32
|
+
- **Automatic by default**: done at a random 5–55 minutes after midnight Beijing time; failures retry an hour later; if the computer was off, it catches up within a minute of starting.
|
|
33
|
+
- **You can see it**: one line at the top of the settings page, "Checked in today: …", with a one-click "Check in all" for anything missed, plus a one-time notice in the corner of dsh.
|
|
34
|
+
- **Check-in only, credits untouched**: they stay on your account for use in each product's own app. Command line: `dsh-model checkin`.
|
|
35
|
+
|
|
36
|
+
## 🔁 2. Relay: one address, one key, every model
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
38
|
+
Your model sources each have their own API and sign-in. dsh-model puts them behind **one OpenAI-compatible address**:
|
|
39
|
+
|
|
40
|
+
- **Shows up in dsh**: every model, grouped by source, with nothing to configure.
|
|
41
|
+
- **Works in other tools**: Cline, Continue, Cherry Studio, scripts: anything that speaks the OpenAI API uses the same address and key.
|
|
42
|
+
- **Rate limits are not the end**: build a combo (say Codex → Kimi → Gemini) and the next model takes over on a rate limit, used-up quota or error.
|
|
43
|
+
- **Know where you stand**: plan usage with reset countdowns, success rate and speed per model, recent failures with what to do, and a notice when quota runs low.
|
|
44
|
+
- **Secure by default**: a key is always required, one per device, revocable any time; every sign-in happens on your own machine.
|
|
45
|
+
- **Laptop or server**: Windows, macOS, Linux; on a VPS (with [dsh-vps](https://github.com/AIcivilization/dsh-vps)) it opens an https address you can use from anywhere. Uninstall restores dsh's config byte for byte.
|
|
46
|
+
|
|
47
|
+
## 🧩 3. Models: free or subscription, connect what you have
|
|
48
|
+
|
|
49
|
+
| Kind | Sources |
|
|
50
|
+
|---|---|
|
|
51
|
+
| **Free (suggested)** | **SiliconFlow** (reachable from China; some models free after identity verification), **Gemini** (if you can reach Google; the best free models) |
|
|
52
|
+
| Free · limited | Groq, OpenRouter (`:free` models) |
|
|
53
|
+
| Local | Ollama, LM Studio: appear once started, no sign-in |
|
|
54
|
+
| Subscription | Codex (ChatGPT Plus / Pro), Kimi Code, Grok, Muse, Devin: sign in from the management page |
|
|
55
|
+
| Pay as you go | DeepSeek official, OpenCode Zen, any OpenAI-compatible service |
|
|
56
|
+
|
|
57
|
+
Every source is tagged Free / Free · limited / Paid; see [Sources and cost](#sources-and-cost) below. dsh-model only connects; it provides no quota of its own.
|
|
58
|
+
|
|
59
|
+
> WorkBuddy: since 2026-10 it recognises conversations sent by dsh and blocks them, so dsh-model uses it for check-in only and does not connect its models by default.
|
|
36
60
|
|
|
37
|
-
No dsh? It still works: the command line manages everything; dsh just adds a management page.
|
|
38
61
|
|
|
39
62
|
## Quick start
|
|
40
63
|
|
|
@@ -48,7 +71,7 @@ On a dsh-vps server, use `sudo dsh-model setup`. On Windows, run it in a normal
|
|
|
48
71
|
`setup` is safe to re-run. It:
|
|
49
72
|
|
|
50
73
|
1. downloads and verifies the engine and runs it on `127.0.0.1:8317/v1`, with key auth enforced;
|
|
51
|
-
2.
|
|
74
|
+
2. starts dsh-model's daemon (the management page, check-in and sign-ins run on it). Setup asks for no keys: for a free source we suggest **SiliconFlow** (reachable from China) or **Gemini** (if you can reach Google), added from the management page. WorkBuddy is used for check-in only; its models are not connected to dsh by default;
|
|
52
75
|
3. installs the management page into dsh and syncs the models into dsh;
|
|
53
76
|
4. on a VPS, also opens a public address `https://<dsh's domain>:9443/v1` (or `<IP>.sslip.io` when there is no domain).
|
|
54
77
|
|
|
@@ -56,12 +79,12 @@ On a dsh-vps server, use `sudo dsh-model setup`. On Windows, run it in a normal
|
|
|
56
79
|
|
|
57
80
|
| Section | What it holds |
|
|
58
81
|
|---|---|
|
|
82
|
+
| **Daily check-in** | WorkBuddy (China), Qoder and Trae are checked in automatically every day (or with one click); the card shows what you got today |
|
|
59
83
|
| **Endpoint** | Local and public addresses, each with a Copy button |
|
|
60
84
|
| **Sources** | One switch per provider: on connects (and signs in if needed), off pauses and keeps the sign-in. Each row is tagged Free / Free · limited / Paid and shows plan usage with reset countdowns, or remaining credits and the next batch to expire; a used-up plan shows when it comes back |
|
|
61
85
|
| **Models** | Pick which models of each source appear in dsh (5 suggested per source by default); the rest stay available through the endpoint; a "Test" button per model |
|
|
62
86
|
| **Combos** | Put several models in order and it becomes one model in dsh: the first is used, and the next takes over on a rate limit, used-up quota or error. Other tools use the model name `combo/<id>` |
|
|
63
87
|
| **Auto switch** | When a model is offered by several sources, dsh gets an "Auto switch (multiple sources)" group that moves to another source when one is rate-limited or failing |
|
|
64
|
-
| **Daily check-in** | WorkBuddy (China), Qoder and Trae are checked in automatically every day (or with one click); the card shows what you got today |
|
|
65
88
|
| **Recent failures** | Failed requests in the last 24 hours: which model, why, and what to do (no conversation content kept) |
|
|
66
89
|
| **API keys** | OpenAI-style, one per device. Requests, success rate, latency and speed over 24 hours; copy, rotate, revoke |
|
|
67
90
|
| **Model stats** | Success rate, latency and speed per model |
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-model
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**📅 每天自动签到领积分 · 🔁 一个地址中转所有模型 · 🧩 免费和订阅模型随你接**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
装一次,三件事都替你做好。dsh 里有图形管理页,没有 dsh 也能用命令行。
|
|
8
8
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="LICENSE"><img src="https://img.shields.io/github/license/AIcivilization/dsh-model" alt="MIT license"></a>
|
|
@@ -19,22 +19,45 @@
|
|
|
19
19
|
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 📅 1. 每日签到:积分自动到账
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**最省心的一件事:每天的签到积分,不用再记着去领。**
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
| 产品 | 怎么接入 | 每天 |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| **Trae** | 本机装了 Trae 并登录过,自动识别,什么都不用做 | 签到送积分(实测每天 200) |
|
|
29
|
+
| **Qoder** | 粘贴一次个人访问令牌(国内版、国际版都行) | 领当天的签到积分 |
|
|
30
|
+
| **WorkBuddy 国内版** | 登录一次 | 签到送积分 |
|
|
31
|
+
|
|
32
|
+
- **自动签到默认打开**:北京时间零点后随机延后 5–55 分钟签好;失败的一小时后重试;电脑关机错过了,开机一分钟内补签。
|
|
33
|
+
- **结果看得见**:设置页顶部一行「今日已完成签到:…」,没签上的可以「一键签到」;签完在 dsh 右下角提示一次。
|
|
34
|
+
- **只签到,不碰积分**:积分留在你的账号里,照常在各家官方软件里用。命令行:`dsh-model checkin`。
|
|
35
|
+
|
|
36
|
+
## 🔁 2. 中转:一个地址、一把 key,用上所有模型
|
|
27
37
|
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
38
|
+
你手上的模型来源,各家接口、登录方式都不一样。dsh-model 把它们合成**一个 OpenAI 兼容地址**:
|
|
39
|
+
|
|
40
|
+
- **dsh 里自动出现**:全部模型按来源分组,不用手动配置。
|
|
41
|
+
- **其他软件也能用**:Cline、Continue、Cherry Studio、脚本……凡是支持 OpenAI 接口的,填同一个地址和 key 就行。
|
|
42
|
+
- **不怕限流**:自己排一个组合(如 Codex → Kimi → Gemini),一个限流、额度用完或出错,就自动换下一个。
|
|
43
|
+
- **心里有数**:套餐用量和重置倒计时、每个模型的成功率和速度、最近失败的原因和该怎么办;额度快用完时提醒。
|
|
44
|
+
- **默认安全**:始终要求 key,每台设备一把,可随时吊销;登录全在本机完成。
|
|
45
|
+
- **电脑和服务器都行**:Windows、macOS、Linux;装在 VPS 上(配合 [dsh-vps](https://github.com/AIcivilization/dsh-vps))自动开一个 https 地址,电脑、手机随处用。卸载时把 dsh 的配置逐字节还原。
|
|
46
|
+
|
|
47
|
+
## 🧩 3. 模型提供:免费的、订阅的都能接
|
|
48
|
+
|
|
49
|
+
| 类型 | 来源 |
|
|
50
|
+
|---|---|
|
|
51
|
+
| **免费(推荐)** | **硅基流动**(国内直连,实名后部分模型免费)、**Gemini**(能上外网,免费模型里质量最好) |
|
|
52
|
+
| 免费 · 额度少 | Groq、OpenRouter(`:free` 模型) |
|
|
53
|
+
| 本机 | Ollama、LM Studio:启动后自动出现,不用登录 |
|
|
54
|
+
| 订阅 | Codex(ChatGPT Plus / Pro)、Kimi Code、Grok、Muse、Devin:在管理页里登录即可 |
|
|
55
|
+
| 按量付费 | DeepSeek 官方、OpenCode Zen、任意 OpenAI 兼容服务 |
|
|
56
|
+
|
|
57
|
+
每个来源都标出「免费 / 免费·额度少 / 需付费」,详见下面的[来源与费用](#来源与费用)。dsh-model 只负责转接,不提供额度。
|
|
58
|
+
|
|
59
|
+
> WorkBuddy:2026-10 起它会认出 dsh 发出的对话并拦下,所以 dsh-model 只用它来签到,模型默认不接进 dsh。
|
|
36
60
|
|
|
37
|
-
没有 dsh 也能用:命令行就能管理全部功能,dsh 里多一个图形管理页而已。
|
|
38
61
|
|
|
39
62
|
## 快速开始
|
|
40
63
|
|
|
@@ -48,7 +71,7 @@ dsh-model setup
|
|
|
48
71
|
`setup` 可以重复执行,它会依次:
|
|
49
72
|
|
|
50
73
|
1. 下载并校验引擎,在本机 `127.0.0.1:8317/v1` 上运行,强制 key 鉴权;
|
|
51
|
-
2.
|
|
74
|
+
2. 启动 dsh-model 的守护进程(管理页、签到、登录都靠它)。安装时不问任何 key:免费来源推荐**硅基流动**(国内直连)或 **Gemini**(能上外网),装好后在管理页里填 key。WorkBuddy 只用来签到,模型默认不接进 dsh;
|
|
52
75
|
3. 把管理页装进 dsh,把模型同步进 dsh;
|
|
53
76
|
4. 在 VPS 上,额外开通对外地址 `https://<dsh 的域名>:9443/v1`(没有域名时用 `<IP>.sslip.io`)。
|
|
54
77
|
|
|
@@ -56,12 +79,12 @@ dsh-model setup
|
|
|
56
79
|
|
|
57
80
|
| 区块 | 内容 |
|
|
58
81
|
|---|---|
|
|
82
|
+
| **每日签到** | WorkBuddy 国内版、Qoder、Trae 每天自动签到(也可一键签到),卡片显示今天领了多少 |
|
|
59
83
|
| **访问地址** | 本机地址和外网地址,各带「复制」按钮 |
|
|
60
|
-
| **来源** | 每家一个开关:打开就接入(没登录会弹出登录框),关闭只停用、保留登录。每行标出「免费 / 免费·额度少 /
|
|
84
|
+
| **来源** | 每家一个开关:打开就接入(没登录会弹出登录框),关闭只停用、保留登录。每行标出「免费 / 免费·额度少 / 需付费」;没登录的、关掉的收进折叠列表。下面显示套餐用量和重置倒计时,或剩余积分和最近到期的一批;额度用完会标出多久后恢复 |
|
|
61
85
|
| **选模型** | 每个来源选哪些模型显示在 dsh 里,默认每家推荐 5 个,其余的经统一地址照样可用;每个模型旁边有「测一下」 |
|
|
62
86
|
| **组合切换** | 把几个模型按顺序排成一个组合,在 dsh 里就是一个模型:先用第一个,限流、额度用完或出错就换下一个。其他软件用模型名 `combo/<id>` |
|
|
63
87
|
| **自动切换** | 同一个模型在几个来源都有时,dsh 里多一组「自动切换(多来源)」,一个来源限流或出错就自动换另一个 |
|
|
64
|
-
| **每日签到** | WorkBuddy 国内版、Qoder、Trae 每天自动签到(也可一键签到),卡片显示今天领了多少 |
|
|
65
88
|
| **最近失败** | 最近 24 小时失败的请求:哪个模型、为什么、该怎么办(不记录对话内容) |
|
|
66
89
|
| **API key** | OpenAI 格式,每台设备一把。显示 24 小时内的请求数、成功率、延迟和速度,可复制、轮换、吊销 |
|
|
67
90
|
| **模型统计** | 按模型显示成功率、延迟和速度 |
|
package/dist/daemon/core.js
CHANGED
|
@@ -30,7 +30,7 @@ import { Mgmt } from '../engine/mgmt.js';
|
|
|
30
30
|
import { DshModelError, isDshModelError } from '../errors.js';
|
|
31
31
|
import { L } from '../i18n.js';
|
|
32
32
|
import { refreshOpencodeModels, removeOpencodeKey, saveOpencodeKey, validateKeyShape, verifyOpencodeKey } from '../integrations/opencode.js';
|
|
33
|
-
import { riskNotice as workbuddyRiskNotice } from '../integrations/workbuddy.js';
|
|
33
|
+
import { blockedNotice as workbuddyBlockedNotice, riskNotice as workbuddyRiskNotice } from '../integrations/workbuddy.js';
|
|
34
34
|
import { DSH_KEY_NAME, addKey, findActive, loadKeys, revokeKey, rotateKey, saveKeys } from '../keys.js';
|
|
35
35
|
import { applyKeyChange, dshCandidates, dshKey, loadAll, saveAll, syncAll } from '../ops.js';
|
|
36
36
|
import { defaultPick, pickedFor } from '../dsh/pick.js';
|
|
@@ -301,6 +301,9 @@ export class Daemon {
|
|
|
301
301
|
return { enabled: false, riskNotice: upstreamRiskNotice(getUpstream(def.id)) };
|
|
302
302
|
return { enabled: false, login: await this.startLogin(def) };
|
|
303
303
|
}
|
|
304
|
+
// WorkBuddy 会拦 dsh 的对话:从关着打开时先提醒一次
|
|
305
|
+
if (def.kind === 'workbuddy' && !state.enabled && !opts.acceptRisk)
|
|
306
|
+
return { enabled: false, riskNotice: workbuddyBlockedNotice() };
|
|
304
307
|
if (def.kind === 'engine') {
|
|
305
308
|
const m = await this.mgmt();
|
|
306
309
|
for (const c of credsFor(await m.credentials(), def))
|
|
@@ -37,7 +37,31 @@ async function waitCatalogs(ctx, since, expected, timeoutMs = 45_000) {
|
|
|
37
37
|
return cats;
|
|
38
38
|
}
|
|
39
39
|
/** 检测 App → 首次打印说明 → bridge 配置与服务 → 等目录。返回目录(调用方随后 syncAll) */
|
|
40
|
+
export const WORKBUDDY_SOURCES = ['workbuddy', 'workbuddy-ai'];
|
|
41
|
+
/** WorkBuddy 会拦 dsh 发出的对话时的提醒(新装默认关、从页面打开前都显示) */
|
|
42
|
+
export function blockedNotice() {
|
|
43
|
+
return L('WorkBuddy 现在会认出 dsh 发出的对话并拦下(「请求被拦截」),在 dsh 里基本用不了;「测一下」能通也不代表能用。dsh-model 不会去绕开这个限制,继续调用有封号风险。签到不受影响。仍要把它的模型接进 dsh 吗?', 'WorkBuddy now recognises conversations sent by dsh and blocks them ("请求被拦截"), so it barely works in dsh; a passing Test does not mean it works. dsh-model will not try to get around this, and continuing risks the account. Check-in is not affected. Connect its models to dsh anyway?');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 只签到(设计 §14.18):第一次装时把 WorkBuddy 的模型关掉,签到照常(签到不看来源开关)。
|
|
47
|
+
* 以前装过的(已有 riskNoticeAt)保持原样;只做一次,之后用户自己打开的不改回去。
|
|
48
|
+
*/
|
|
49
|
+
export function applyWorkbuddyDefault(all) {
|
|
50
|
+
if (all.config.workbuddyDefault)
|
|
51
|
+
return;
|
|
52
|
+
if (all.config.bridge?.riskNoticeAt) {
|
|
53
|
+
all.config.workbuddyDefault = 'kept';
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const off = new Set(all.config.disabledSources ?? []);
|
|
57
|
+
for (const id of WORKBUDDY_SOURCES)
|
|
58
|
+
off.add(id);
|
|
59
|
+
all.config.disabledSources = [...off];
|
|
60
|
+
all.config.workbuddyDefault = 'checkin-only';
|
|
61
|
+
info(L('WorkBuddy 只用来签到:它现在会拦 dsh 的对话,所以模型默认不接进 dsh(要用可在「来源」里打开)', 'WorkBuddy is used for check-in only: it now blocks conversations from dsh, so its models are not connected by default (turn it on under Sources if you want)'));
|
|
62
|
+
}
|
|
40
63
|
export async function enableWorkbuddy(ctx, all) {
|
|
64
|
+
applyWorkbuddyDefault(all);
|
|
41
65
|
const variants = await availableVariants(ctx.paths.home);
|
|
42
66
|
if (!variants.length) {
|
|
43
67
|
skip(ctx.platform === 'darwin'
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-model",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.23.2",
|
|
4
|
+
"description": "Daily check-in credits claimed for you (Trae, Qoder, WorkBuddy China), one OpenAI-compatible address that relays every model, and free or subscription model sources (SiliconFlow, Gemini, Codex, Kimi, Ollama…). For DeepSeek Harness (dsh) and any OpenAI-compatible tool. 每天自动签到领积分 · 一个地址中转所有模型 · 免费和订阅模型随你接。",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"siliconflow",
|
|
7
|
+
"checkin",
|
|
6
8
|
"dsh-plugin",
|
|
7
9
|
"dsh-plugins",
|
|
8
10
|
"dsh",
|
package/plugin/client.js
CHANGED
|
@@ -462,8 +462,9 @@ window.__ModuleLoader__.load({
|
|
|
462
462
|
try { await api('POST', `/sources/${s.id}/logout`); await reload() } catch (e) { setErr(e.message) }
|
|
463
463
|
}
|
|
464
464
|
// 已登录的照常列出;没登录的收进一个可折叠的列表(默认收起;一个都没登录时默认展开)
|
|
465
|
-
|
|
466
|
-
const
|
|
465
|
+
// 顶部只放正在用的(已登录且打开);没登录的、关掉的都收进折叠列表
|
|
466
|
+
const signedIn = visible.filter((s) => s.loggedIn && s.enabled)
|
|
467
|
+
const rest = visible.filter((s) => !(s.loggedIn && s.enabled))
|
|
467
468
|
const [restPref, setRestPref] = useState(readShowRest)
|
|
468
469
|
const openRest = restPref ?? signedIn.length === 0
|
|
469
470
|
const toggleRest = (v) => {
|
|
@@ -509,7 +510,7 @@ window.__ModuleLoader__.load({
|
|
|
509
510
|
showRisky ? h('p', { style: { ...S.note, color: C.warn } }, L('高风险来源(Claude、Antigravity):服务商有封禁第三方使用订阅的先例,账号可能被封。仅在你清楚风险时使用。', 'High-risk sources (Claude, Antigravity): the providers have banned third-party use of subscriptions before; your account may be suspended. Use only if you accept the risk.')) : null,
|
|
510
511
|
signedIn.length ? h('div', { style: S.card }, signedIn.map(row)) : h('div', { style: { ...S.note, margin: '0 0 8px' } }, L('还没有接入任何来源:展开下面的列表挑一个。', 'No source connected yet: open the list below and pick one.')),
|
|
511
512
|
rest.length ? h('button', { type: 'button', style: { ...S.btn, marginTop: 10 }, 'aria-expanded': openRest, onClick: () => toggleRest(!openRest) },
|
|
512
|
-
openRest ? L(`▾
|
|
513
|
+
openRest ? L(`▾ 收起没在用的来源(${rest.length} 个:未登录或已关闭)`, `▾ Hide sources not in use (${rest.length}: signed out or off)`) : L(`▸ 没在用的来源(${rest.length} 个:未登录或已关闭)`, `▸ Sources not in use (${rest.length}: signed out or off)`)) : null,
|
|
513
514
|
openRest && rest.length ? h('div', { style: { ...S.card, marginTop: 8 } }, rest.map(row)) : null)
|
|
514
515
|
}
|
|
515
516
|
|
|
@@ -1089,9 +1090,15 @@ window.__ModuleLoader__.load({
|
|
|
1089
1090
|
/** 刚装好、接入的来源少于两个时显示:先接一个免费来源 → 模型已经挑好 → 去 dsh 里用 */
|
|
1090
1091
|
function Guide({ sources, onConnect }) {
|
|
1091
1092
|
const [done, setDone] = useState(readGuideDone)
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1093
|
+
// WorkBuddy 只签到(它拦 dsh 的对话),不算"已接入"
|
|
1094
|
+
const connected = sources.filter((s) => s.loggedIn && s.enabled && s.kind !== 'workbuddy')
|
|
1095
|
+
if (done || connected.length >= 1) return null
|
|
1096
|
+
// 只推两家:国内直连的硅基流动、能上外网的 Gemini
|
|
1097
|
+
const PICKS = [
|
|
1098
|
+
{ id: 'siliconflow', why: () => L('国内直连,不用代理;实名认证后部分模型免费', 'Reachable from China without a proxy; some models are free after identity verification') },
|
|
1099
|
+
{ id: 'gemini', why: () => L('能上外网就选它:免费模型里质量最好,每天有次数上限', 'If you can reach Google: the best free models, with a daily limit') },
|
|
1100
|
+
]
|
|
1101
|
+
const picks = PICKS.map((p) => ({ ...p, s: sources.find((s) => s.id === p.id) })).filter((p) => p.s)
|
|
1095
1102
|
const hide = () => {
|
|
1096
1103
|
setDone(true)
|
|
1097
1104
|
try { window.localStorage.setItem(GUIDE_KEY, '1') } catch { /* 无痕模式:只在本次生效 */ }
|
|
@@ -1106,9 +1113,11 @@ window.__ModuleLoader__.load({
|
|
|
1106
1113
|
h('button', { type: 'button', style: S.btn, onClick: hide }, L('我知道了,不再显示', 'Got it, hide this'))),
|
|
1107
1114
|
step(1, L('接入一个免费来源', 'Connect a free source'),
|
|
1108
1115
|
h('div', null,
|
|
1109
|
-
h('div', { style: S.meta }, L('
|
|
1110
|
-
h('div', { style: {
|
|
1111
|
-
|
|
1116
|
+
h('div', { style: S.meta }, L('接一个就能用:去对方网站领一把免费 key,点下面的按钮粘贴进来。', 'One is enough: get a free key from their website, then click below and paste it.')),
|
|
1117
|
+
picks.map((p) => h('div', { key: p.id, style: { ...S.line, marginTop: 6, flexWrap: 'wrap' } },
|
|
1118
|
+
h('button', { type: 'button', style: S.btn, onClick: () => onConnect(p.s) }, p.s.label),
|
|
1119
|
+
h('span', { style: { ...S.meta, ...S.grow } }, p.why()),
|
|
1120
|
+
p.s.subscribeUrl ? h('a', { href: p.s.subscribeUrl, target: '_blank', rel: 'noopener noreferrer', style: { color: C.accent, fontSize: 12 } }, L('去领 key ↗', 'Get a key ↗')) : null)))),
|
|
1112
1121
|
step(2, L('模型已经替你挑好', 'Models are picked for you'),
|
|
1113
1122
|
h('div', { style: S.meta }, L('每个来源默认挑 5 个放进 dsh(免费的优先)。想换就在下面「来源」里点「选模型」。', 'Each source puts 5 suggested models into dsh (free ones first). Change them with "Models" under Sources below.'))),
|
|
1114
1123
|
step(3, L('去用', 'Use it'),
|