@klarkxy/dsh-zhihu 0.2.0 → 0.2.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.md +29 -12
- package/docs/README.zh-CN.md +36 -12
- package/lib/client.js +216 -148
- package/lib/contracts.d.ts +3 -2
- package/lib/contracts.js +3 -2
- package/lib/contracts.js.map +1 -1
- package/lib/index.d.ts +11 -1
- package/lib/index.js +13 -5
- package/lib/index.js.map +1 -1
- package/lib/open-platform.js +203 -7
- package/lib/open-platform.js.map +1 -1
- package/lib/tools.js +5 -5
- package/lib/tools.js.map +1 -1
- package/package.json +7 -3
package/lib/client.js
CHANGED
|
@@ -9,6 +9,92 @@ let react = require("react");
|
|
|
9
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
11
|
//#region src/client-locale.ts
|
|
12
|
+
const responseErrors = {
|
|
13
|
+
"RPC 返回格式无效。": "Invalid RPC response format.",
|
|
14
|
+
"开放平台响应格式无效。": "Invalid Open Platform response format.",
|
|
15
|
+
"响应额度项无效。": "Invalid quota item in the response.",
|
|
16
|
+
"分页响应格式无效。": "Invalid paging response format.",
|
|
17
|
+
"请求已取消": "Request cancelled",
|
|
18
|
+
"查询不超过 4000 字符": "The query must be non-empty and no longer than 4,000 characters",
|
|
19
|
+
"缺少文件内容。": "File content is missing.",
|
|
20
|
+
"文件内容无效或超过 20 MB": "File content is invalid or exceeds 20 MB",
|
|
21
|
+
"搜索词不能为空。": "Search keywords cannot be empty.",
|
|
22
|
+
"知识库文件名不能为空。": "The knowledge base file name cannot be empty.",
|
|
23
|
+
"知识库文件名不能包含控制字符。": "The knowledge base file name cannot contain control characters.",
|
|
24
|
+
"知识库文件名不能超过 255 个 UTF-8 字节。": "The knowledge base file name cannot exceed 255 UTF-8 bytes.",
|
|
25
|
+
"知识库文件内容不能为空。": "The knowledge base file content cannot be empty.",
|
|
26
|
+
"知识库文件大小不能超过 20MB。": "The knowledge base file cannot exceed 20 MB.",
|
|
27
|
+
"当前环境没有可用的 fetch。": "No fetch implementation is available in this environment.",
|
|
28
|
+
"知乎响应缺少 {Code,Message,Data} 信封。": "The Zhihu response has no {Code,Message,Data} envelope.",
|
|
29
|
+
"知乎响应缺少有效的 Code 字段。": "The Zhihu response has no valid Code field.",
|
|
30
|
+
"知乎直答响应不是 OpenAI 兼容格式。": "The Zhihu direct answer response is not in an OpenAI-compatible format.",
|
|
31
|
+
"知乎直答返回为空。": "The Zhihu direct answer response is empty.",
|
|
32
|
+
"分页信息不完整:缺少有效的 Paging.IsEnd,请停止翻页。": "Paging is incomplete: no valid Paging.IsEnd. Stop paging.",
|
|
33
|
+
"分页信息不完整:NextOffset 缺失、无效或未前进,请停止翻页;不要按条数计算偏移。": "Paging is incomplete: NextOffset is missing, invalid or did not advance. Stop paging; do not calculate an offset from item counts.",
|
|
34
|
+
"只允许请求知乎开放平台。": "Only Zhihu Open Platform requests are allowed.",
|
|
35
|
+
"参数必须是对象。": "Parameters must be an object.",
|
|
36
|
+
"这些接口仅使用当前 Access Secret,不接受 token 参数或 OAuth 身份切换。": "These APIs use the current Access Secret only; token parameters and OAuth identity switching are not supported.",
|
|
37
|
+
"offset 超出 Int64 范围。": "offset exceeds the Int64 range.",
|
|
38
|
+
"questionUrl 不能为空。": "questionUrl cannot be empty.",
|
|
39
|
+
"contentUrl 不能为空。": "contentUrl cannot be empty.",
|
|
40
|
+
"知乎链接不能包含空白、控制字符或反斜线。": "Zhihu links cannot contain whitespace, control characters or backslashes.",
|
|
41
|
+
"不是有效的知乎 URL。": "Invalid Zhihu URL.",
|
|
42
|
+
"必须使用无账号密码、无非标准端口的 HTTPS 知乎链接。": "Use an HTTPS Zhihu link without credentials or a non-standard port.",
|
|
43
|
+
"questionUrl 仅支持 https://www.zhihu.com/question/{id}。": "questionUrl only supports https://www.zhihu.com/question/{id}.",
|
|
44
|
+
"contentUrl 仅支持知乎回答、专栏文章、想法或视频链接。": "contentUrl only supports Zhihu answer, article, pin or video links.",
|
|
45
|
+
"startDate 与 endDate 必须同时提供或同时省略。": "Provide both startDate and endDate, or omit both.",
|
|
46
|
+
"endDate 不得早于 startDate。": "endDate cannot be before startDate.",
|
|
47
|
+
"主题关键词不能为空;省略 query 才会按画像推荐。": "Topic keywords cannot be empty; omit query to get profile-based recommendations.",
|
|
48
|
+
"contentType 必须是 all、answer、article、pin 或 zvideo。": "contentType must be all, answer, article, pin or zvideo.",
|
|
49
|
+
"apiIds 包含未知官方额度项。": "apiIds contains unknown official quota items.",
|
|
50
|
+
"order 必须是 score、reverse 或 ascending。": "order must be score, reverse or ascending."
|
|
51
|
+
};
|
|
52
|
+
const operationLabels = {
|
|
53
|
+
"知乎搜索": "Zhihu search",
|
|
54
|
+
"知乎全网搜索": "Zhihu web search",
|
|
55
|
+
"知乎热榜": "Zhihu trending",
|
|
56
|
+
"知乎直答": "Zhihu direct answer",
|
|
57
|
+
"知乎知识库列表": "Zhihu knowledge base list",
|
|
58
|
+
"知乎知识库检索": "Zhihu knowledge base search",
|
|
59
|
+
"知乎知识库上传": "Zhihu knowledge base upload",
|
|
60
|
+
"适合回答的问题": "Questions to answer",
|
|
61
|
+
"问题回答摘要": "Answer summaries",
|
|
62
|
+
"本人创作全文": "My full content",
|
|
63
|
+
"本人创作评论": "Comments on my content",
|
|
64
|
+
"账号创作数据": "Account creator stats",
|
|
65
|
+
"单篇创作数据": "Per-post creator stats",
|
|
66
|
+
"官方每日额度": "Official daily quota"
|
|
67
|
+
};
|
|
68
|
+
function diagnosticText(text, t) {
|
|
69
|
+
if (responseErrors[text]) return t(text, responseErrors[text]);
|
|
70
|
+
const upstream = text.match(/^知乎开放平台返回错误(code=(\d+)):(.*)$/s);
|
|
71
|
+
if (upstream) return t(text, `Zhihu Open Platform returned an error (code=${upstream[1]}): ${upstream[2]}`);
|
|
72
|
+
const blocked = text.match(/^知乎开放平台被风控拒绝:(.*)。请不要立即重试。$/s);
|
|
73
|
+
if (blocked) return t(text, `Zhihu Open Platform rejected the request through risk control: ${blocked[1]}. Do not retry immediately.`);
|
|
74
|
+
for (const [label, english] of Object.entries(operationLabels)) {
|
|
75
|
+
if (!text.startsWith(label)) continue;
|
|
76
|
+
const detail = text.slice(label.length);
|
|
77
|
+
const http = detail.match(/^返回 HTTP (\d{3})。$/);
|
|
78
|
+
if (http) return t(text, `${english} returned HTTP ${http[1]}.`);
|
|
79
|
+
const timeout = detail.match(/^超时((\d+) 秒),请稍后再试。$/);
|
|
80
|
+
if (timeout) return t(text, `${english} timed out (${timeout[1]} seconds). Try again later.`);
|
|
81
|
+
if (detail === "响应不是合法 JSON。") return t(text, `${english} did not return valid JSON.`);
|
|
82
|
+
if (detail === "的 Data 必须是 JSON 对象。") return t(text, `${english} Data must be a JSON object.`);
|
|
83
|
+
if (detail.startsWith("失败:")) return t(text, `${english} failed: ${detail.slice(3)}`);
|
|
84
|
+
if (detail.startsWith("返回错误:")) return t(text, `${english} returned an error: ${detail.slice(5)}`);
|
|
85
|
+
}
|
|
86
|
+
return text;
|
|
87
|
+
}
|
|
88
|
+
function clientText(text, t) {
|
|
89
|
+
if (typeof text !== "string") return t(text[0], text[1]);
|
|
90
|
+
const separator = text.indexOf(":");
|
|
91
|
+
if (separator > 0 && /^[a-z-]+$/.test(text.slice(0, separator))) {
|
|
92
|
+
const code = text.slice(0, separator);
|
|
93
|
+
if (code === "token-missing") return t("未配置有效的知乎 Access Secret,请到设置页配置。", "A valid Zhihu Access Secret is missing. Configure it on the Settings tab.");
|
|
94
|
+
return `${code}: ${diagnosticText(text.slice(separator + 1), t)}`;
|
|
95
|
+
}
|
|
96
|
+
return diagnosticText(text, t);
|
|
97
|
+
}
|
|
12
98
|
function zhihuLocale(value) {
|
|
13
99
|
return String(value ?? "zh").startsWith("zh") ? "zh" : "en";
|
|
14
100
|
}
|
|
@@ -42,13 +128,14 @@ const ZHIHU_QUOTA_IDS = [
|
|
|
42
128
|
"global_search",
|
|
43
129
|
"zhihu_search",
|
|
44
130
|
"hot_list",
|
|
45
|
-
"
|
|
131
|
+
"question_discovery",
|
|
46
132
|
"zhida_openai",
|
|
47
133
|
"tools",
|
|
48
134
|
"knowledge",
|
|
49
135
|
"user_data",
|
|
50
136
|
"creator"
|
|
51
137
|
];
|
|
138
|
+
const normalizeZhihuQuotaId = (value) => value === "question_answers" ? "question_discovery" : value;
|
|
52
139
|
//#endregion
|
|
53
140
|
//#region src/client-state.ts
|
|
54
141
|
/**
|
|
@@ -387,7 +474,7 @@ ${scope} {
|
|
|
387
474
|
border: 0.5px solid var(--dsw-alias-border-l3);
|
|
388
475
|
border-radius: var(--dsw-radius-md);
|
|
389
476
|
background: var(--dsw-alias-bg-layer-1);
|
|
390
|
-
font-family: var(--ds-font-family-code
|
|
477
|
+
font-family: var(--ds-font-family-code);
|
|
391
478
|
font-size: 12px;
|
|
392
479
|
line-height: 20px;
|
|
393
480
|
color: var(--dsw-alias-label-secondary);
|
|
@@ -686,38 +773,14 @@ function zhihuQueryKeyDown(event, run) {
|
|
|
686
773
|
run.search();
|
|
687
774
|
}
|
|
688
775
|
}
|
|
689
|
-
function
|
|
690
|
-
|
|
691
|
-
const record = props;
|
|
692
|
-
const sources = [record];
|
|
693
|
-
if (record.owner && typeof record.owner === "object") sources.push(record.owner);
|
|
694
|
-
let Select;
|
|
695
|
-
let Dialog;
|
|
696
|
-
let Button;
|
|
697
|
-
let Input;
|
|
698
|
-
for (const source of sources) {
|
|
699
|
-
if (typeof source.Select === "function") Select = source.Select;
|
|
700
|
-
if (typeof source.Dialog === "function") Dialog = source.Dialog;
|
|
701
|
-
if (typeof source.Button === "function") Button = source.Button;
|
|
702
|
-
if (typeof source.Input === "function") Input = source.Input;
|
|
703
|
-
}
|
|
704
|
-
return {
|
|
705
|
-
Select,
|
|
706
|
-
Dialog,
|
|
707
|
-
Button,
|
|
708
|
-
Input
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
function renderInput(Input, props) {
|
|
712
|
-
if (Input) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, { ...props });
|
|
713
|
-
const { onChange, ref, ...rest } = props;
|
|
776
|
+
function renderInput(props) {
|
|
777
|
+
const { onChange, ...rest } = props;
|
|
714
778
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
715
779
|
...rest,
|
|
716
780
|
onChange: (event) => onChange(event.target.value)
|
|
717
781
|
});
|
|
718
782
|
}
|
|
719
|
-
function renderSelect(
|
|
720
|
-
if (Select) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, { ...props });
|
|
783
|
+
function renderSelect(props, className = "dsh-ui-select") {
|
|
721
784
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
722
785
|
id: props.id,
|
|
723
786
|
className,
|
|
@@ -731,28 +794,14 @@ function renderSelect(Select, props, className) {
|
|
|
731
794
|
}, option.value === "" ? "__empty" : option.value))
|
|
732
795
|
});
|
|
733
796
|
}
|
|
734
|
-
/**
|
|
735
|
-
* The host's own Button still wins whenever the slot supplies one, so a page
|
|
736
|
-
* rendered inside DSH keeps the surrounding chrome. Standalone there is no host
|
|
737
|
-
* to defer to, and the plugin renders the official primitive instead of a
|
|
738
|
-
* hand-rolled `<button>`: the two legacy variant names the call sites use are
|
|
739
|
-
* mapped onto it here. `danger` has no primitive variant, so it keeps the
|
|
740
|
-
* outlined appearance and takes its tone from a class in the plugin stylesheet
|
|
741
|
-
* — the way every other destructive action in the host reads.
|
|
742
|
-
*/
|
|
797
|
+
/** Map existing plugin variants onto the injected official Button. */
|
|
743
798
|
const BUTTON_VARIANT = {
|
|
744
799
|
default: "outline",
|
|
745
800
|
primary: "primary",
|
|
746
801
|
danger: "outline",
|
|
747
802
|
icon: "ghost"
|
|
748
803
|
};
|
|
749
|
-
const ZhihuButton = (0, react.forwardRef)(function ZhihuButton({
|
|
750
|
-
if (host) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(host, {
|
|
751
|
-
ref,
|
|
752
|
-
variant,
|
|
753
|
-
className,
|
|
754
|
-
...rest
|
|
755
|
-
});
|
|
804
|
+
const ZhihuButton = (0, react.forwardRef)(function ZhihuButton({ variant, className, ...rest }, ref) {
|
|
756
805
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
757
806
|
ref,
|
|
758
807
|
variant: BUTTON_VARIANT[variant ?? "default"],
|
|
@@ -795,7 +844,7 @@ const OPERATION_COPY = [
|
|
|
795
844
|
},
|
|
796
845
|
{
|
|
797
846
|
value: "quota",
|
|
798
|
-
zh: "
|
|
847
|
+
zh: "官方每日免费额度",
|
|
799
848
|
en: "Official daily quota"
|
|
800
849
|
}
|
|
801
850
|
];
|
|
@@ -901,6 +950,10 @@ function buildOpenPlatformParams(operation, form, t = translator()) {
|
|
|
901
950
|
}
|
|
902
951
|
}
|
|
903
952
|
if (operation === "quota") {
|
|
953
|
+
if (Array.isArray(form.apiIds)) form = {
|
|
954
|
+
...form,
|
|
955
|
+
apiIds: form.apiIds.map((value) => normalizeZhihuQuotaId(value))
|
|
956
|
+
};
|
|
904
957
|
if (!Array.isArray(form.apiIds) || form.apiIds.some((id) => !ZHIHU_QUOTA_IDS.includes(id))) throw new Error(t("包含未知的额度项。", "Contains an unknown quota item."));
|
|
905
958
|
if (form.apiIds.length) params.apiIds = [...new Set(form.apiIds)];
|
|
906
959
|
}
|
|
@@ -920,9 +973,12 @@ function parseOpenPlatformResponse(operation, raw) {
|
|
|
920
973
|
}
|
|
921
974
|
const value = raw.value;
|
|
922
975
|
if (!isRecord(value) || value.version !== 1 || value.operation !== operation || !isRecord(value.data) || !jsonValue(value.data)) throw new Error("开放平台响应格式无效。");
|
|
923
|
-
if (value.quotaId !== void 0 && !ZHIHU_QUOTA_IDS.includes(value.quotaId)) throw new Error("响应额度项无效。");
|
|
976
|
+
if (value.quotaId !== void 0 && !ZHIHU_QUOTA_IDS.includes(normalizeZhihuQuotaId(value.quotaId))) throw new Error("响应额度项无效。");
|
|
924
977
|
if (value.paging !== void 0 && (!isRecord(value.paging) || typeof value.paging.canContinue !== "boolean" || value.paging.isEnd !== void 0 && typeof value.paging.isEnd !== "boolean" || value.paging.warning !== void 0 && typeof value.paging.warning !== "string")) throw new Error("分页响应格式无效。");
|
|
925
|
-
return
|
|
978
|
+
return {
|
|
979
|
+
...value,
|
|
980
|
+
...value.quotaId === void 0 ? {} : { quotaId: normalizeZhihuQuotaId(value.quotaId) }
|
|
981
|
+
};
|
|
926
982
|
}
|
|
927
983
|
function openPlatformNextOffset(result, currentOffset) {
|
|
928
984
|
if (!result || !["question.answers", "content.comments"].includes(result.operation) || result.paging?.canContinue !== true || result.paging.isEnd === true) return null;
|
|
@@ -941,7 +997,7 @@ async function requestOpenPlatform(rpc, state, operation, params, publish) {
|
|
|
941
997
|
if (state.isCurrent(ticket)) publish({ error: error instanceof Error ? error.message : String(error) });
|
|
942
998
|
}
|
|
943
999
|
}
|
|
944
|
-
function ZhihuOpenPlatformSection({ rpc,
|
|
1000
|
+
function ZhihuOpenPlatformSection({ rpc, quotaOnly = false, selectedOperation }) {
|
|
945
1001
|
const t = useT();
|
|
946
1002
|
const [operation, setOperation] = (0, react.useState)(quotaOnly ? "quota" : "question.recommendations");
|
|
947
1003
|
const [form, setForm] = (0, react.useState)(createOpenPlatformForm);
|
|
@@ -992,7 +1048,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
992
1048
|
className: "dsh-ui-label",
|
|
993
1049
|
children: label
|
|
994
1050
|
}),
|
|
995
|
-
renderInput(
|
|
1051
|
+
renderInput({
|
|
996
1052
|
value: form[key],
|
|
997
1053
|
onChange: (value) => change(key, value),
|
|
998
1054
|
"aria-label": label,
|
|
@@ -1015,7 +1071,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1015
1071
|
className: "dsh-ui-label",
|
|
1016
1072
|
children: label
|
|
1017
1073
|
}),
|
|
1018
|
-
renderSelect(
|
|
1074
|
+
renderSelect({
|
|
1019
1075
|
value: form[key],
|
|
1020
1076
|
onChange: (value) => change(key, value),
|
|
1021
1077
|
"aria-label": label,
|
|
@@ -1034,9 +1090,17 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1034
1090
|
offset
|
|
1035
1091
|
};
|
|
1036
1092
|
try {
|
|
1037
|
-
params = buildOpenPlatformParams(activeOperation, nextForm
|
|
1038
|
-
} catch
|
|
1039
|
-
|
|
1093
|
+
params = buildOpenPlatformParams(activeOperation, nextForm);
|
|
1094
|
+
} catch {
|
|
1095
|
+
const message = (locale) => {
|
|
1096
|
+
try {
|
|
1097
|
+
buildOpenPlatformParams(activeOperation, nextForm, translator(locale));
|
|
1098
|
+
return "";
|
|
1099
|
+
} catch (cause) {
|
|
1100
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
setError([message("zh"), message("en")]);
|
|
1040
1104
|
return;
|
|
1041
1105
|
}
|
|
1042
1106
|
if (offset !== void 0) setForm(nextForm);
|
|
@@ -1054,7 +1118,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1054
1118
|
const paged = activeOperation === "question.answers" || activeOperation === "content.comments";
|
|
1055
1119
|
const dated = activeOperation === "creator.account.stats" || activeOperation === "creator.content.stats";
|
|
1056
1120
|
const options = openPlatformOptions(t);
|
|
1057
|
-
const title = quotaOnly ? t("
|
|
1121
|
+
const title = quotaOnly ? t("官方每日免费额度", "Official daily quota") : t("问题与创作", "Questions and creator");
|
|
1058
1122
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1059
1123
|
className: "zhihu-open-platform dsh-ui-stack",
|
|
1060
1124
|
"aria-label": title,
|
|
@@ -1067,7 +1131,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1067
1131
|
className: "dsh-ui-help",
|
|
1068
1132
|
children: quotaOnly ? t("查询知乎返回的官方额度,不推算余额。", "Shows the quota Zhihu reports; no balance is inferred.") : t("手动触发,不自动翻页或重试。", "Manual trigger only; no automatic paging or retry.")
|
|
1069
1133
|
}),
|
|
1070
|
-
!quotaOnly && selectedOperation === void 0 && renderSelect(
|
|
1134
|
+
!quotaOnly && selectedOperation === void 0 && renderSelect({
|
|
1071
1135
|
value: activeOperation,
|
|
1072
1136
|
options,
|
|
1073
1137
|
"aria-label": t("开放平台操作", "Open Platform operation"),
|
|
@@ -1156,23 +1220,20 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1156
1220
|
className: "dsh-ui-actions",
|
|
1157
1221
|
children: [
|
|
1158
1222
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
1159
|
-
host: Button,
|
|
1160
1223
|
variant: "primary",
|
|
1161
1224
|
disabled: loading,
|
|
1162
1225
|
onClick: () => run(),
|
|
1163
1226
|
children: activeOperation === "quota" ? t("查询官方额度", "Check quota") : t("执行请求", "Run request")
|
|
1164
1227
|
}),
|
|
1165
1228
|
loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
1166
|
-
host: Button,
|
|
1167
1229
|
onClick: () => {
|
|
1168
1230
|
state.cancel();
|
|
1169
1231
|
setLoading(false);
|
|
1170
|
-
setError(
|
|
1232
|
+
setError(["已取消;晚到的结果将被丢弃。", "Cancelled; a late response will be discarded."]);
|
|
1171
1233
|
},
|
|
1172
1234
|
children: t("取消请求", "Cancel")
|
|
1173
1235
|
}),
|
|
1174
1236
|
nextOffset !== null && !loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
1175
|
-
host: Button,
|
|
1176
1237
|
onClick: () => run(nextOffset),
|
|
1177
1238
|
children: t("下一页", "Next page")
|
|
1178
1239
|
})
|
|
@@ -1186,7 +1247,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1186
1247
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1187
1248
|
className: "dsh-ui-error",
|
|
1188
1249
|
role: "alert",
|
|
1189
|
-
children: error
|
|
1250
|
+
children: clientText(error, t)
|
|
1190
1251
|
}),
|
|
1191
1252
|
result && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1192
1253
|
className: "dsh-ui-stack",
|
|
@@ -1201,7 +1262,7 @@ function ZhihuOpenPlatformSection({ rpc, Button, Input, Select, quotaOnly = fals
|
|
|
1201
1262
|
}),
|
|
1202
1263
|
result.paging?.warning && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1203
1264
|
className: "dsh-ui-banner",
|
|
1204
|
-
children: result.paging.warning
|
|
1265
|
+
children: clientText(result.paging.warning, t)
|
|
1205
1266
|
}),
|
|
1206
1267
|
!stale && paged && result.paging?.canContinue && nextOffset === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1207
1268
|
className: "dsh-ui-banner",
|
|
@@ -1234,6 +1295,52 @@ function OpenPlatformDetails({ quotaOnly }) {
|
|
|
1234
1295
|
});
|
|
1235
1296
|
}
|
|
1236
1297
|
//#endregion
|
|
1298
|
+
//#region src/client-call-policy.tsx
|
|
1299
|
+
function ZhihuCallPolicySummary({ policy }) {
|
|
1300
|
+
const t = useT();
|
|
1301
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1302
|
+
className: "dsh-ui-help",
|
|
1303
|
+
children: t(`${policy.allowPaid ? "已显式允许付费" : "仅使用免费额度"} · 每日上限 ${policy.dailyCallLimit} 次(北京时间)`, `${policy.allowPaid ? "Paid calls explicitly enabled" : "Free allowance only"} · ${policy.dailyCallLimit} calls per Beijing day`)
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
function ZhihuCallPolicySection({ rpc }) {
|
|
1307
|
+
const t = useT();
|
|
1308
|
+
const [policy, setPolicy] = (0, react.useState)(null);
|
|
1309
|
+
const [failed, setFailed] = (0, react.useState)(false);
|
|
1310
|
+
(0, react.useEffect)(() => {
|
|
1311
|
+
let alive = true;
|
|
1312
|
+
rpc.call(ZHIHU_RPC_CHANNEL, "policy.status", {}).then((result) => {
|
|
1313
|
+
if (!alive) return;
|
|
1314
|
+
const value = result;
|
|
1315
|
+
if (value?.ok && typeof value.value?.allowPaid === "boolean" && typeof value.value.dailyCallLimit === "number") setPolicy(value.value);
|
|
1316
|
+
else setFailed(true);
|
|
1317
|
+
}, () => {
|
|
1318
|
+
if (alive) setFailed(true);
|
|
1319
|
+
});
|
|
1320
|
+
return () => {
|
|
1321
|
+
alive = false;
|
|
1322
|
+
};
|
|
1323
|
+
}, [rpc]);
|
|
1324
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1325
|
+
className: "dsh-ui-stack",
|
|
1326
|
+
"aria-label": t("调用保护", "Call protection"),
|
|
1327
|
+
children: [
|
|
1328
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
1329
|
+
className: "dsh-ui-heading",
|
|
1330
|
+
children: t("调用保护", "Call protection")
|
|
1331
|
+
}),
|
|
1332
|
+
policy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuCallPolicySummary, { policy }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1333
|
+
className: "dsh-ui-help",
|
|
1334
|
+
children: failed ? t("保护配置不可用;请检查插件配置。", "Protection settings unavailable. Check plugin configuration.") : t("读取保护配置…", "Loading protection settings…")
|
|
1335
|
+
}),
|
|
1336
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1337
|
+
className: "dsh-ui-hint",
|
|
1338
|
+
children: t("付费须在插件配置显式启用。未确认计费的能力仅允许使用已确认的免费额度。本地保护无法排除同账号其他客户端竞争导致的扣费;调用统计不是账单。", "Enable paid calls explicitly in plugin configuration. Unpriced capabilities require verified free allowance. Other clients on the same account can still cause charges; local counts are not billing.")
|
|
1339
|
+
})
|
|
1340
|
+
]
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
//#endregion
|
|
1237
1344
|
//#region src/client-quota.tsx
|
|
1238
1345
|
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1239
1346
|
const identityFields = /* @__PURE__ */ new Set([
|
|
@@ -1508,7 +1615,7 @@ function QuotaCharts({ data }) {
|
|
|
1508
1615
|
]
|
|
1509
1616
|
});
|
|
1510
1617
|
}
|
|
1511
|
-
function ZhihuQuotaSection({ rpc
|
|
1618
|
+
function ZhihuQuotaSection({ rpc }) {
|
|
1512
1619
|
const state = (0, react.useRef)(createZhihuClientState()).current;
|
|
1513
1620
|
const [snapshot, setSnapshot] = (0, react.useState)(null);
|
|
1514
1621
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
@@ -1537,7 +1644,7 @@ function ZhihuQuotaSection({ rpc, Button }) {
|
|
|
1537
1644
|
refresh();
|
|
1538
1645
|
return () => state.cancel();
|
|
1539
1646
|
}, [refresh, state]);
|
|
1540
|
-
const title = t("
|
|
1647
|
+
const title = t("官方免费额度用量", "Official quota");
|
|
1541
1648
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1542
1649
|
className: "dsh-ui-stack",
|
|
1543
1650
|
"aria-label": title,
|
|
@@ -1557,17 +1664,15 @@ function ZhihuQuotaSection({ rpc, Button }) {
|
|
|
1557
1664
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1558
1665
|
className: "dsh-ui-actions",
|
|
1559
1666
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
1560
|
-
host: Button,
|
|
1561
1667
|
variant: "primary",
|
|
1562
1668
|
disabled: loading,
|
|
1563
1669
|
onClick: refresh,
|
|
1564
1670
|
children: t("刷新官方额度", "Refresh quota")
|
|
1565
1671
|
}), loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
1566
|
-
host: Button,
|
|
1567
1672
|
onClick: () => {
|
|
1568
1673
|
state.cancel();
|
|
1569
1674
|
setLoading(false);
|
|
1570
|
-
setError(
|
|
1675
|
+
setError(["已取消;晚到的结果将被丢弃。", "Cancelled; a late response will be discarded."]);
|
|
1571
1676
|
},
|
|
1572
1677
|
children: t("取消请求", "Cancel")
|
|
1573
1678
|
})]
|
|
@@ -1580,7 +1685,7 @@ function ZhihuQuotaSection({ rpc, Button }) {
|
|
|
1580
1685
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1581
1686
|
className: "dsh-ui-error",
|
|
1582
1687
|
role: "alert",
|
|
1583
|
-
children: error
|
|
1688
|
+
children: clientText(error, t)
|
|
1584
1689
|
}),
|
|
1585
1690
|
snapshot && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1586
1691
|
className: "dsh-ui-stack",
|
|
@@ -1611,7 +1716,6 @@ const inject = [
|
|
|
1611
1716
|
];
|
|
1612
1717
|
const PACKAGE_NAME = "@klarkxy/dsh-zhihu";
|
|
1613
1718
|
const SLOT_ORDER = 120;
|
|
1614
|
-
const SLOT_LABEL = "知乎";
|
|
1615
1719
|
const activityDots = () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1616
1720
|
className: "zhihu-dots",
|
|
1617
1721
|
"aria-hidden": "true",
|
|
@@ -1651,21 +1755,21 @@ function safeUrl(url) {
|
|
|
1651
1755
|
return /^https?:\/\//i.test(url) ? url : null;
|
|
1652
1756
|
}
|
|
1653
1757
|
/** Credential absence and transport failure read differently from a plain bad request. */
|
|
1654
|
-
function failureOf(code, message
|
|
1758
|
+
function failureOf(code, message) {
|
|
1655
1759
|
if (code === "token-missing") return {
|
|
1656
1760
|
kind: "credential",
|
|
1657
|
-
text:
|
|
1761
|
+
text: ["未配置知乎 Access Secret 或凭证不可用,请到「设置」页配置。", "Zhihu Access Secret is missing or unavailable. Set it on the Settings tab."]
|
|
1658
1762
|
};
|
|
1659
1763
|
return {
|
|
1660
1764
|
kind: "request",
|
|
1661
|
-
text:
|
|
1765
|
+
text: [`请求失败:${clientText(message, translator("zh"))}`, `Request failed: ${clientText(message, translator("en"))}`]
|
|
1662
1766
|
};
|
|
1663
1767
|
}
|
|
1664
|
-
function networkFailure(cause
|
|
1768
|
+
function networkFailure(cause) {
|
|
1665
1769
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1666
1770
|
return {
|
|
1667
1771
|
kind: "network",
|
|
1668
|
-
text:
|
|
1772
|
+
text: [`网络或连接失败:${detail}`, `Network or connection failed: ${detail}`]
|
|
1669
1773
|
};
|
|
1670
1774
|
}
|
|
1671
1775
|
/**
|
|
@@ -1718,10 +1822,10 @@ function testOptions(t) {
|
|
|
1718
1822
|
})), ...openPlatformOptions(t).filter((option) => option.value !== "quota")];
|
|
1719
1823
|
}
|
|
1720
1824
|
const TEST_OPTIONS = testOptions(translator("zh"));
|
|
1721
|
-
function ZhihuTestSelector({ value, onChange
|
|
1825
|
+
function ZhihuTestSelector({ value, onChange }) {
|
|
1722
1826
|
const t = useT();
|
|
1723
1827
|
const options = testOptions(t);
|
|
1724
|
-
return renderSelect(
|
|
1828
|
+
return renderSelect({
|
|
1725
1829
|
"aria-label": t("测试功能", "Feature to test"),
|
|
1726
1830
|
value,
|
|
1727
1831
|
options,
|
|
@@ -2055,11 +2159,10 @@ function SettingsSection(props) {
|
|
|
2055
2159
|
if (state.status === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsShell, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2056
2160
|
className: "dsh-ui-error",
|
|
2057
2161
|
role: "alert",
|
|
2058
|
-
children: t(`读取失败:${state.error}`, `Could not load: ${state.error}`)
|
|
2162
|
+
children: t(`读取失败:${clientText(state.error, t)}`, `Could not load: ${clientText(state.error, t)}`)
|
|
2059
2163
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2060
2164
|
className: "dsh-ui-actions",
|
|
2061
2165
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2062
|
-
host: props.Button,
|
|
2063
2166
|
onClick: () => void load(),
|
|
2064
2167
|
children: t("重试", "Retry")
|
|
2065
2168
|
})
|
|
@@ -2088,7 +2191,7 @@ function SettingsSection(props) {
|
|
|
2088
2191
|
return;
|
|
2089
2192
|
}
|
|
2090
2193
|
setKeyDraft("");
|
|
2091
|
-
setNote(
|
|
2194
|
+
setNote(["已保存。", "Saved."]);
|
|
2092
2195
|
await load();
|
|
2093
2196
|
} catch (cause) {
|
|
2094
2197
|
if (!alive.current) return;
|
|
@@ -2111,7 +2214,7 @@ function SettingsSection(props) {
|
|
|
2111
2214
|
return;
|
|
2112
2215
|
}
|
|
2113
2216
|
setKeyDraft("");
|
|
2114
|
-
setNote(
|
|
2217
|
+
setNote(["已清除。", "Cleared."]);
|
|
2115
2218
|
await load();
|
|
2116
2219
|
} catch (cause) {
|
|
2117
2220
|
if (!alive.current) return;
|
|
@@ -2142,7 +2245,7 @@ function SettingsSection(props) {
|
|
|
2142
2245
|
children: t("获取密钥", "Get a key")
|
|
2143
2246
|
})]
|
|
2144
2247
|
}),
|
|
2145
|
-
renderInput(
|
|
2248
|
+
renderInput({
|
|
2146
2249
|
type: "password",
|
|
2147
2250
|
className: "zhihu-input",
|
|
2148
2251
|
value: keyDraft,
|
|
@@ -2161,24 +2264,22 @@ function SettingsSection(props) {
|
|
|
2161
2264
|
failure !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2162
2265
|
className: "dsh-ui-error",
|
|
2163
2266
|
role: "alert",
|
|
2164
|
-
children: failure
|
|
2267
|
+
children: clientText(failure, t)
|
|
2165
2268
|
}) : null,
|
|
2166
2269
|
note !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2167
2270
|
className: "dsh-ui-notice",
|
|
2168
2271
|
role: "status",
|
|
2169
|
-
children: note
|
|
2272
|
+
children: clientText(note, t)
|
|
2170
2273
|
}) : null,
|
|
2171
2274
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2172
2275
|
className: "dsh-ui-actions",
|
|
2173
2276
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2174
|
-
host: props.Button,
|
|
2175
2277
|
variant: "danger",
|
|
2176
2278
|
className: "zhihu-button-danger",
|
|
2177
2279
|
disabled: busy || keyLocked || !configured,
|
|
2178
2280
|
onClick: () => setConfirmClear(true),
|
|
2179
2281
|
children: pending === "clear" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [activityDots(), t("清除中…", "Clearing…")] }) : t("清除", "Clear")
|
|
2180
2282
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2181
|
-
host: props.Button,
|
|
2182
2283
|
variant: "primary",
|
|
2183
2284
|
disabled: busy || keyLocked || keyValue.length === 0 || draftFailure !== void 0,
|
|
2184
2285
|
onClick: () => void save(),
|
|
@@ -2194,11 +2295,9 @@ function SettingsSection(props) {
|
|
|
2194
2295
|
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2195
2296
|
className: "dsh-ui-actions",
|
|
2196
2297
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2197
|
-
host: props.Button,
|
|
2198
2298
|
onClick: () => setConfirmClear(false),
|
|
2199
2299
|
children: t("取消", "Cancel")
|
|
2200
2300
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2201
|
-
host: props.Button,
|
|
2202
2301
|
variant: "danger",
|
|
2203
2302
|
className: "zhihu-button-danger",
|
|
2204
2303
|
onClick: () => void clear(),
|
|
@@ -2434,7 +2533,7 @@ function UsageSection(props) {
|
|
|
2434
2533
|
if (!isUsageSummary(result.value)) {
|
|
2435
2534
|
setState({
|
|
2436
2535
|
status: "error",
|
|
2437
|
-
error: "
|
|
2536
|
+
error: ["响应格式与契约不符。", "The response does not match the expected shape."]
|
|
2438
2537
|
});
|
|
2439
2538
|
return;
|
|
2440
2539
|
}
|
|
@@ -2470,11 +2569,10 @@ function UsageSection(props) {
|
|
|
2470
2569
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2471
2570
|
className: "dsh-ui-error",
|
|
2472
2571
|
role: "alert",
|
|
2473
|
-
children: t(`读取失败:${state.error}`, `Could not load: ${state.error}`)
|
|
2572
|
+
children: t(`读取失败:${clientText(state.error, t)}`, `Could not load: ${clientText(state.error, t)}`)
|
|
2474
2573
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2475
2574
|
className: "dsh-ui-actions",
|
|
2476
2575
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2477
|
-
host: props.Button,
|
|
2478
2576
|
onClick: () => void load(),
|
|
2479
2577
|
children: t("重试", "Retry")
|
|
2480
2578
|
})
|
|
@@ -2495,7 +2593,6 @@ function UsageSection(props) {
|
|
|
2495
2593
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2496
2594
|
className: "dsh-ui-actions",
|
|
2497
2595
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2498
|
-
host: props.Button,
|
|
2499
2596
|
onClick: () => void load(),
|
|
2500
2597
|
children: t("刷新统计", "Refresh")
|
|
2501
2598
|
})
|
|
@@ -2656,7 +2753,7 @@ function KnowledgeSection(props) {
|
|
|
2656
2753
|
if (!result.ok) {
|
|
2657
2754
|
setList({
|
|
2658
2755
|
status: "error",
|
|
2659
|
-
failure: failureOf(result.error.code, result.error.message
|
|
2756
|
+
failure: failureOf(result.error.code, result.error.message)
|
|
2660
2757
|
});
|
|
2661
2758
|
return;
|
|
2662
2759
|
}
|
|
@@ -2665,7 +2762,7 @@ function KnowledgeSection(props) {
|
|
|
2665
2762
|
status: "error",
|
|
2666
2763
|
failure: {
|
|
2667
2764
|
kind: "request",
|
|
2668
|
-
text:
|
|
2765
|
+
text: ["响应格式与契约不符。", "The response does not match the expected shape."]
|
|
2669
2766
|
}
|
|
2670
2767
|
});
|
|
2671
2768
|
return;
|
|
@@ -2678,14 +2775,10 @@ function KnowledgeSection(props) {
|
|
|
2678
2775
|
if (!gate.isCurrent(ticket)) return;
|
|
2679
2776
|
setList({
|
|
2680
2777
|
status: "error",
|
|
2681
|
-
failure: networkFailure(cause
|
|
2778
|
+
failure: networkFailure(cause)
|
|
2682
2779
|
});
|
|
2683
2780
|
}
|
|
2684
|
-
}, [
|
|
2685
|
-
gate,
|
|
2686
|
-
rpc,
|
|
2687
|
-
t
|
|
2688
|
-
]);
|
|
2781
|
+
}, [gate, rpc]);
|
|
2689
2782
|
(0, react.useEffect)(() => {
|
|
2690
2783
|
load();
|
|
2691
2784
|
}, [load]);
|
|
@@ -2694,7 +2787,7 @@ function KnowledgeSection(props) {
|
|
|
2694
2787
|
setFailure(void 0);
|
|
2695
2788
|
setNote(void 0);
|
|
2696
2789
|
if (file.size > KB_MAX_BYTES) {
|
|
2697
|
-
setFailure(
|
|
2790
|
+
setFailure(["文件超过 20 MB 上限。", "The file exceeds the 20 MB limit."]);
|
|
2698
2791
|
return;
|
|
2699
2792
|
}
|
|
2700
2793
|
const { ticket, signal } = gate.begin();
|
|
@@ -2710,17 +2803,17 @@ function KnowledgeSection(props) {
|
|
|
2710
2803
|
if (!gate.isCurrent(ticket)) return;
|
|
2711
2804
|
const result = raw;
|
|
2712
2805
|
if (!result.ok) {
|
|
2713
|
-
setFailure(
|
|
2806
|
+
setFailure([`上传失败:${result.error.message}`, `Upload failed: ${result.error.message}`]);
|
|
2714
2807
|
return;
|
|
2715
2808
|
}
|
|
2716
|
-
setNote(
|
|
2809
|
+
setNote(["已上传到知乎知识库。", "Uploaded to the Zhihu knowledge base."]);
|
|
2717
2810
|
setFile(void 0);
|
|
2718
2811
|
setFileKey((key) => key + 1);
|
|
2719
2812
|
await load();
|
|
2720
2813
|
} catch (cause) {
|
|
2721
2814
|
if (!gate.isCurrent(ticket)) return;
|
|
2722
2815
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
2723
|
-
setFailure(
|
|
2816
|
+
setFailure([`上传失败:${detail}`, `Upload failed: ${detail}`]);
|
|
2724
2817
|
} finally {
|
|
2725
2818
|
setBusy(false);
|
|
2726
2819
|
}
|
|
@@ -2749,11 +2842,10 @@ function KnowledgeSection(props) {
|
|
|
2749
2842
|
list.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2750
2843
|
className: "dsh-ui-error",
|
|
2751
2844
|
role: "alert",
|
|
2752
|
-
children: list.failure.text
|
|
2845
|
+
children: clientText(list.failure.text, t)
|
|
2753
2846
|
}), list.failure.kind !== "credential" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2754
2847
|
className: "dsh-ui-actions",
|
|
2755
2848
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2756
|
-
host: props.Button,
|
|
2757
2849
|
onClick: () => void load(),
|
|
2758
2850
|
children: t("重试", "Retry")
|
|
2759
2851
|
})
|
|
@@ -2768,7 +2860,7 @@ function KnowledgeSection(props) {
|
|
|
2768
2860
|
}),
|
|
2769
2861
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2770
2862
|
className: "dsh-ui-row",
|
|
2771
|
-
children: [renderSelect(
|
|
2863
|
+
children: [renderSelect({
|
|
2772
2864
|
id: "zhihu-kb-base",
|
|
2773
2865
|
value: baseId,
|
|
2774
2866
|
disabled: busy,
|
|
@@ -2782,7 +2874,6 @@ function KnowledgeSection(props) {
|
|
|
2782
2874
|
label: t(`${base.name}${base.isDefault ? "(默认)" : ""} · ${base.contentCount} 篇`, `${base.name}${base.isDefault ? " (default)" : ""} · ${base.contentCount} docs`)
|
|
2783
2875
|
}))]
|
|
2784
2876
|
}, "dsh-ui-select"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2785
|
-
host: props.Button,
|
|
2786
2877
|
disabled: busy,
|
|
2787
2878
|
onClick: () => void load(),
|
|
2788
2879
|
children: t("刷新", "Refresh")
|
|
@@ -2832,7 +2923,6 @@ function KnowledgeSection(props) {
|
|
|
2832
2923
|
list.status === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2833
2924
|
className: "dsh-ui-actions",
|
|
2834
2925
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
2835
|
-
host: props.Button,
|
|
2836
2926
|
variant: "primary",
|
|
2837
2927
|
disabled: busy || !file,
|
|
2838
2928
|
onClick: () => void upload(),
|
|
@@ -2842,12 +2932,12 @@ function KnowledgeSection(props) {
|
|
|
2842
2932
|
note ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2843
2933
|
className: "dsh-ui-notice",
|
|
2844
2934
|
role: "status",
|
|
2845
|
-
children: note
|
|
2935
|
+
children: clientText(note, t)
|
|
2846
2936
|
}) : null,
|
|
2847
2937
|
failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2848
2938
|
className: "dsh-ui-error",
|
|
2849
2939
|
role: "alert",
|
|
2850
|
-
children: failure
|
|
2940
|
+
children: clientText(failure, t)
|
|
2851
2941
|
}) : null
|
|
2852
2942
|
]
|
|
2853
2943
|
});
|
|
@@ -2876,7 +2966,7 @@ function nextVisitedTabs(visited, next) {
|
|
|
2876
2966
|
return visited.includes(next) ? [...visited] : [...visited, next];
|
|
2877
2967
|
}
|
|
2878
2968
|
function ZhihuSettings(props) {
|
|
2879
|
-
const { rpc, credentials
|
|
2969
|
+
const { rpc, credentials } = props;
|
|
2880
2970
|
const t = useT();
|
|
2881
2971
|
const gateRef = (0, react.useRef)(null);
|
|
2882
2972
|
if (!gateRef.current) gateRef.current = createZhihuClientState();
|
|
@@ -2922,7 +3012,7 @@ function ZhihuSettings(props) {
|
|
|
2922
3012
|
if (!parsed) {
|
|
2923
3013
|
setFailure({
|
|
2924
3014
|
kind: "request",
|
|
2925
|
-
text:
|
|
3015
|
+
text: ["响应格式与契约不符。", "The response does not match the expected shape."]
|
|
2926
3016
|
});
|
|
2927
3017
|
setPhase("error");
|
|
2928
3018
|
return;
|
|
@@ -2932,12 +3022,12 @@ function ZhihuSettings(props) {
|
|
|
2932
3022
|
setPhase("done");
|
|
2933
3023
|
} else if (response.error.code === "cancelled") setPhase("idle");
|
|
2934
3024
|
else {
|
|
2935
|
-
setFailure(failureOf(response.error.code, response.error.message
|
|
3025
|
+
setFailure(failureOf(response.error.code, response.error.message));
|
|
2936
3026
|
setPhase("error");
|
|
2937
3027
|
}
|
|
2938
3028
|
} catch (cause) {
|
|
2939
3029
|
if (!gate.isCurrent(ticket)) return;
|
|
2940
|
-
setFailure(networkFailure(cause
|
|
3030
|
+
setFailure(networkFailure(cause));
|
|
2941
3031
|
setPhase("error");
|
|
2942
3032
|
}
|
|
2943
3033
|
}, [
|
|
@@ -3021,12 +3111,11 @@ function ZhihuSettings(props) {
|
|
|
3021
3111
|
className: "dsh-ui-field",
|
|
3022
3112
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuTestSelector, {
|
|
3023
3113
|
value: testOperation,
|
|
3024
|
-
onChange: onTestOperationChange
|
|
3025
|
-
Select
|
|
3114
|
+
onChange: onTestOperationChange
|
|
3026
3115
|
}), isSearchOperation ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
|
|
3027
3116
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3028
3117
|
className: "dsh-ui-row",
|
|
3029
|
-
children: mode === "ask" ? renderSelect(
|
|
3118
|
+
children: mode === "ask" ? renderSelect({
|
|
3030
3119
|
"aria-label": t("直答模型", "Answer model"),
|
|
3031
3120
|
value: askModel,
|
|
3032
3121
|
onChange: (next) => onAskModelChange(next),
|
|
@@ -3058,7 +3147,7 @@ function ZhihuSettings(props) {
|
|
|
3058
3147
|
id: "zhihu-scope-hint",
|
|
3059
3148
|
children: t("至少保留一个检索范围。", "Keep at least one scope selected.")
|
|
3060
3149
|
})] }) : null,
|
|
3061
|
-
renderInput(
|
|
3150
|
+
renderInput({
|
|
3062
3151
|
type: "search",
|
|
3063
3152
|
className: "zhihu-input",
|
|
3064
3153
|
"data-testid": "zhihu-query",
|
|
@@ -3072,14 +3161,12 @@ function ZhihuSettings(props) {
|
|
|
3072
3161
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3073
3162
|
className: "dsh-ui-actions",
|
|
3074
3163
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
3075
|
-
host: Button,
|
|
3076
3164
|
variant: "primary",
|
|
3077
3165
|
"data-testid": "zhihu-search",
|
|
3078
3166
|
disabled: searchDisabled,
|
|
3079
3167
|
onClick: () => void runSearch(),
|
|
3080
3168
|
children: mode === "hot" ? t("获取热榜", "Get trending") : t("搜索", "Search")
|
|
3081
3169
|
}), phase === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuButton, {
|
|
3082
|
-
host: Button,
|
|
3083
3170
|
onClick: () => {
|
|
3084
3171
|
gate.cancel();
|
|
3085
3172
|
setPhase("idle");
|
|
@@ -3095,7 +3182,7 @@ function ZhihuSettings(props) {
|
|
|
3095
3182
|
phase === "error" && failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3096
3183
|
className: "dsh-ui-error",
|
|
3097
3184
|
role: "alert",
|
|
3098
|
-
children: failure.text
|
|
3185
|
+
children: clientText(failure.text, t)
|
|
3099
3186
|
}) : null,
|
|
3100
3187
|
phase === "done" && outcome ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutcomeView, {
|
|
3101
3188
|
outcome,
|
|
@@ -3103,10 +3190,7 @@ function ZhihuSettings(props) {
|
|
|
3103
3190
|
}) : null
|
|
3104
3191
|
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuOpenPlatformSection, {
|
|
3105
3192
|
selectedOperation: testOperation,
|
|
3106
|
-
rpc
|
|
3107
|
-
Button,
|
|
3108
|
-
Input,
|
|
3109
|
-
Select
|
|
3193
|
+
rpc
|
|
3110
3194
|
}, testOperation)]
|
|
3111
3195
|
});
|
|
3112
3196
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -3115,24 +3199,10 @@ function ZhihuSettings(props) {
|
|
|
3115
3199
|
"aria-label": t("知乎", "Zhihu"),
|
|
3116
3200
|
children: [
|
|
3117
3201
|
tablist,
|
|
3118
|
-
panel("settings", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsSection, {
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
})),
|
|
3123
|
-
panel("usage", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageSection, {
|
|
3124
|
-
rpc,
|
|
3125
|
-
Button
|
|
3126
|
-
})),
|
|
3127
|
-
panel("quota", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuQuotaSection, {
|
|
3128
|
-
rpc,
|
|
3129
|
-
Button
|
|
3130
|
-
})),
|
|
3131
|
-
panel("knowledge", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KnowledgeSection, {
|
|
3132
|
-
rpc,
|
|
3133
|
-
Select,
|
|
3134
|
-
Button
|
|
3135
|
-
})),
|
|
3202
|
+
panel("settings", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsSection, { credentials }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuCallPolicySection, { rpc })] })),
|
|
3203
|
+
panel("usage", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageSection, { rpc })),
|
|
3204
|
+
panel("quota", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuQuotaSection, { rpc })),
|
|
3205
|
+
panel("knowledge", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KnowledgeSection, { rpc })),
|
|
3136
3206
|
panel("test", testPanel)
|
|
3137
3207
|
]
|
|
3138
3208
|
});
|
|
@@ -3158,17 +3228,15 @@ function apply(ctx) {
|
|
|
3158
3228
|
} catch {
|
|
3159
3229
|
locale = void 0;
|
|
3160
3230
|
}
|
|
3161
|
-
const settingsRender = (
|
|
3231
|
+
const settingsRender = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhihuSettingsRoot, {
|
|
3162
3232
|
rpc: client.connection.rpc,
|
|
3163
3233
|
credentials: wrapCredentials(client.remote.credentials),
|
|
3164
|
-
locale
|
|
3165
|
-
...hostComponentsFromRenderProps(props)
|
|
3234
|
+
locale
|
|
3166
3235
|
});
|
|
3167
3236
|
ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
|
|
3168
3237
|
name: "plugins.bundle.config",
|
|
3169
3238
|
key: PACKAGE_NAME,
|
|
3170
|
-
order: SLOT_ORDER
|
|
3171
|
-
label: SLOT_LABEL
|
|
3239
|
+
order: SLOT_ORDER
|
|
3172
3240
|
}, settingsRender)), "zhihu.settings");
|
|
3173
3241
|
}
|
|
3174
3242
|
//#endregion
|