@will1123/lx-ui-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +234 -0
- package/dist/dist/index.esm.js +618 -0
- package/dist/dist/index.esm.min.js +431 -0
- package/dist/dist/index.esm.min.js.map +1 -0
- package/dist/dist/index.umd.js +622 -0
- package/dist/dist/index.umd.min.js +14 -0
- package/dist/dist/index.umd.min.js.map +1 -0
- package/dist/es/index.js +15 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/markdown.js +286 -0
- package/dist/es/markdown.js.map +1 -0
- package/dist/es/sse.js +186 -0
- package/dist/es/sse.js.map +1 -0
- package/dist/es/thinking.js +153 -0
- package/dist/es/thinking.js.map +1 -0
- package/dist/lib/index.js +15 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/markdown.js +286 -0
- package/dist/lib/markdown.js.map +1 -0
- package/dist/lib/sse.js +186 -0
- package/dist/lib/sse.js.map +1 -0
- package/dist/lib/thinking.js +153 -0
- package/dist/lib/thinking.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/markdown.d.ts +115 -0
- package/dist/types/markdown.d.ts.map +1 -0
- package/dist/types/sse.d.ts +70 -0
- package/dist/types/sse.d.ts.map +1 -0
- package/dist/types/thinking.d.ts +64 -0
- package/dist/types/thinking.d.ts.map +1 -0
- package/package.json +45 -0
package/dist/lib/sse.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __spreadValues = (a, b) => {
|
|
8
|
+
for (var prop in b || (b = {}))
|
|
9
|
+
if (__hasOwnProp.call(b, prop))
|
|
10
|
+
__defNormalProp(a, prop, b[prop]);
|
|
11
|
+
if (__getOwnPropSymbols)
|
|
12
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
13
|
+
if (__propIsEnum.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
}
|
|
16
|
+
return a;
|
|
17
|
+
};
|
|
18
|
+
var __async = (__this, __arguments, generator) => {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
var fulfilled = (value) => {
|
|
21
|
+
try {
|
|
22
|
+
step(generator.next(value));
|
|
23
|
+
} catch (e) {
|
|
24
|
+
reject(e);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var rejected = (value) => {
|
|
28
|
+
try {
|
|
29
|
+
step(generator.throw(value));
|
|
30
|
+
} catch (e) {
|
|
31
|
+
reject(e);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
35
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
39
|
+
class SSEConnection {
|
|
40
|
+
constructor() {
|
|
41
|
+
this.controller = null;
|
|
42
|
+
this.eventSource = null;
|
|
43
|
+
this.timeoutTimer = null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 发起 SSE 请求
|
|
47
|
+
*/
|
|
48
|
+
request(config, handlers) {
|
|
49
|
+
return __async(this, null, function* () {
|
|
50
|
+
var _a, _b, _c, _d, _e;
|
|
51
|
+
const { url, method = "GET", headers = {}, body, timeout = 3e4 } = config;
|
|
52
|
+
this.controller = new AbortController();
|
|
53
|
+
try {
|
|
54
|
+
if (timeout > 0) {
|
|
55
|
+
this.timeoutTimer = setTimeout(() => {
|
|
56
|
+
var _a2;
|
|
57
|
+
this.close();
|
|
58
|
+
(_a2 = handlers.onError) == null ? void 0 : _a2.call(handlers, new Error(`Request timeout after ${timeout}ms`));
|
|
59
|
+
}, timeout);
|
|
60
|
+
}
|
|
61
|
+
const response = yield fetch(url, {
|
|
62
|
+
method,
|
|
63
|
+
headers: __spreadValues({
|
|
64
|
+
"Content-Type": "application/json"
|
|
65
|
+
}, headers),
|
|
66
|
+
body: method === "POST" ? JSON.stringify(body) : void 0,
|
|
67
|
+
signal: this.controller.signal
|
|
68
|
+
});
|
|
69
|
+
if (this.timeoutTimer) {
|
|
70
|
+
clearTimeout(this.timeoutTimer);
|
|
71
|
+
this.timeoutTimer = null;
|
|
72
|
+
}
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
const contentType = response.headers.get("content-type");
|
|
77
|
+
if (!(contentType == null ? void 0 : contentType.includes("text/event-stream"))) {
|
|
78
|
+
throw new Error("Response is not a Server-Sent Events stream");
|
|
79
|
+
}
|
|
80
|
+
(_a = handlers.onOpen) == null ? void 0 : _a.call(handlers);
|
|
81
|
+
const reader = (_b = response.body) == null ? void 0 : _b.getReader();
|
|
82
|
+
const decoder = new TextDecoder();
|
|
83
|
+
let buffer = "";
|
|
84
|
+
if (!reader) {
|
|
85
|
+
throw new Error("Response body is null");
|
|
86
|
+
}
|
|
87
|
+
while (true) {
|
|
88
|
+
const { done, value } = yield reader.read();
|
|
89
|
+
if (done) {
|
|
90
|
+
(_c = handlers.onClose) == null ? void 0 : _c.call(handlers);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
buffer += decoder.decode(value, { stream: true });
|
|
94
|
+
const lines = buffer.split("\n\n");
|
|
95
|
+
buffer = lines.pop() || "";
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
if (line.trim()) {
|
|
98
|
+
const message = this.parseMessage(line);
|
|
99
|
+
(_d = handlers.onMessage) == null ? void 0 : _d.call(handlers, message);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (this.timeoutTimer) {
|
|
105
|
+
clearTimeout(this.timeoutTimer);
|
|
106
|
+
this.timeoutTimer = null;
|
|
107
|
+
}
|
|
108
|
+
if (this.controller && !this.controller.signal.aborted) {
|
|
109
|
+
(_e = handlers.onError) == null ? void 0 : _e.call(handlers, error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 使用 EventSource 连接(仅支持 GET 请求)
|
|
116
|
+
*/
|
|
117
|
+
connect(url, handlers) {
|
|
118
|
+
this.eventSource = new EventSource(url);
|
|
119
|
+
this.eventSource.onopen = () => {
|
|
120
|
+
var _a;
|
|
121
|
+
(_a = handlers.onOpen) == null ? void 0 : _a.call(handlers);
|
|
122
|
+
};
|
|
123
|
+
this.eventSource.onmessage = (event) => {
|
|
124
|
+
var _a;
|
|
125
|
+
(_a = handlers.onMessage) == null ? void 0 : _a.call(handlers, {
|
|
126
|
+
data: event.data,
|
|
127
|
+
event: event.type
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
this.eventSource.onerror = (error) => {
|
|
131
|
+
var _a;
|
|
132
|
+
(_a = handlers.onError) == null ? void 0 : _a.call(handlers, new Error("EventSource error"));
|
|
133
|
+
this.close();
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 解析 SSE 消息
|
|
138
|
+
*/
|
|
139
|
+
parseMessage(line) {
|
|
140
|
+
const message = {
|
|
141
|
+
data: ""
|
|
142
|
+
};
|
|
143
|
+
const lines = line.split("\n");
|
|
144
|
+
for (const l of lines) {
|
|
145
|
+
if (l.startsWith("data: ")) {
|
|
146
|
+
message.data = l.slice(6);
|
|
147
|
+
} else if (l.startsWith("event: ")) {
|
|
148
|
+
message.event = l.slice(7);
|
|
149
|
+
} else if (l.startsWith("id: ")) {
|
|
150
|
+
message.id = l.slice(4);
|
|
151
|
+
} else if (l.startsWith("retry: ")) {
|
|
152
|
+
message.retry = parseInt(l.slice(7));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return message;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 关闭连接
|
|
159
|
+
*/
|
|
160
|
+
close() {
|
|
161
|
+
if (this.controller) {
|
|
162
|
+
this.controller.abort();
|
|
163
|
+
this.controller = null;
|
|
164
|
+
}
|
|
165
|
+
if (this.eventSource) {
|
|
166
|
+
this.eventSource.close();
|
|
167
|
+
this.eventSource = null;
|
|
168
|
+
}
|
|
169
|
+
if (this.timeoutTimer) {
|
|
170
|
+
clearTimeout(this.timeoutTimer);
|
|
171
|
+
this.timeoutTimer = null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function sse(config, handlers) {
|
|
176
|
+
const connection = new SSEConnection();
|
|
177
|
+
if (config.method === "POST" || config.timeout) {
|
|
178
|
+
connection.request(config, handlers);
|
|
179
|
+
} else {
|
|
180
|
+
connection.connect(config.url, handlers);
|
|
181
|
+
}
|
|
182
|
+
return connection;
|
|
183
|
+
}
|
|
184
|
+
exports.SSEConnection = SSEConnection;
|
|
185
|
+
exports.sse = sse;
|
|
186
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sources":["../../src/sse.ts"],"sourcesContent":["/**\r\n * SSE (Server-Sent Events) 请求配置\r\n */\r\nexport interface SSEConfig {\r\n /** 请求 URL */\r\n url: string\r\n /** 请求方法 */\r\n method?: 'GET' | 'POST'\r\n /** 请求头 */\r\n headers?: Record<string, string>\r\n /** 请求体(POST 请求时使用) */\r\n body?: any\r\n /** 请求超时时间(毫秒) */\r\n timeout?: number\r\n}\r\n\r\n/**\r\n * SSE 消息\r\n */\r\nexport interface SSEMessage {\r\n /** 数据内容 */\r\n data: string\r\n /** 事件类型 */\r\n event?: string\r\n /** ID */\r\n id?: string\r\n /** 重连时间(毫秒) */\r\n retry?: number\r\n}\r\n\r\n/**\r\n * SSE 事件处理器\r\n */\r\nexport interface SSEHandlers {\r\n /** 接收到消息时触发 */\r\n onMessage?: (message: SSEMessage) => void\r\n /** 连接打开时触发 */\r\n onOpen?: () => void\r\n /** 连接关闭时触发 */\r\n onClose?: () => void\r\n /** 发生错误时触发 */\r\n onError?: (error: Error) => void\r\n}\r\n\r\n/**\r\n * SSE 连接类\r\n */\r\nexport class SSEConnection {\r\n private controller: AbortController | null = null\r\n private eventSource: EventSource | null = null\r\n private timeoutTimer: NodeJS.Timeout | null = null\r\n\r\n /**\r\n * 发起 SSE 请求\r\n */\r\n async request(config: SSEConfig, handlers: SSEHandlers): Promise<void> {\r\n const { url, method = 'GET', headers = {}, body, timeout = 30000 } = config\r\n\r\n // 使用 AbortController 支持取消请求\r\n this.controller = new AbortController()\r\n\r\n try {\r\n // 设置超时\r\n if (timeout > 0) {\r\n this.timeoutTimer = setTimeout(() => {\r\n this.close()\r\n handlers.onError?.(new Error(`Request timeout after ${timeout}ms`))\r\n }, timeout)\r\n }\r\n\r\n // 发起请求\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...headers\r\n },\r\n body: method === 'POST' ? JSON.stringify(body) : undefined,\r\n signal: this.controller.signal\r\n })\r\n\r\n // 清除超时定时器\r\n if (this.timeoutTimer) {\r\n clearTimeout(this.timeoutTimer)\r\n this.timeoutTimer = null\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! status: ${response.status}`)\r\n }\r\n\r\n // 检查响应是否为 SSE 流\r\n const contentType = response.headers.get('content-type')\r\n if (!contentType?.includes('text/event-stream')) {\r\n throw new Error('Response is not a Server-Sent Events stream')\r\n }\r\n\r\n // 触发打开事件\r\n handlers.onOpen?.()\r\n\r\n // 读取流\r\n const reader = response.body?.getReader()\r\n const decoder = new TextDecoder()\r\n let buffer = ''\r\n\r\n if (!reader) {\r\n throw new Error('Response body is null')\r\n }\r\n\r\n while (true) {\r\n const { done, value } = await reader.read()\r\n\r\n if (done) {\r\n handlers.onClose?.()\r\n break\r\n }\r\n\r\n // 解码数据并添加到缓冲区\r\n buffer += decoder.decode(value, { stream: true })\r\n\r\n // 处理完整的消息\r\n const lines = buffer.split('\\n\\n')\r\n buffer = lines.pop() || ''\r\n\r\n for (const line of lines) {\r\n if (line.trim()) {\r\n const message = this.parseMessage(line)\r\n handlers.onMessage?.(message)\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n // 清除超时定时器\r\n if (this.timeoutTimer) {\r\n clearTimeout(this.timeoutTimer)\r\n this.timeoutTimer = null\r\n }\r\n\r\n // 如果不是主动取消,触发错误事件\r\n if (this.controller && !this.controller.signal.aborted) {\r\n handlers.onError?.(error as Error)\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 使用 EventSource 连接(仅支持 GET 请求)\r\n */\r\n connect(url: string, handlers: SSEHandlers): void {\r\n this.eventSource = new EventSource(url)\r\n\r\n this.eventSource.onopen = () => {\r\n handlers.onOpen?.()\r\n }\r\n\r\n this.eventSource.onmessage = event => {\r\n handlers.onMessage?.({\r\n data: event.data,\r\n event: event.type\r\n })\r\n }\r\n\r\n this.eventSource.onerror = error => {\r\n handlers.onError?.(new Error('EventSource error'))\r\n this.close()\r\n }\r\n }\r\n\r\n /**\r\n * 解析 SSE 消息\r\n */\r\n private parseMessage(line: string): SSEMessage {\r\n const message: SSEMessage = {\r\n data: ''\r\n }\r\n\r\n const lines = line.split('\\n')\r\n for (const l of lines) {\r\n if (l.startsWith('data: ')) {\r\n message.data = l.slice(6)\r\n } else if (l.startsWith('event: ')) {\r\n message.event = l.slice(7)\r\n } else if (l.startsWith('id: ')) {\r\n message.id = l.slice(4)\r\n } else if (l.startsWith('retry: ')) {\r\n message.retry = parseInt(l.slice(7))\r\n }\r\n }\r\n\r\n return message\r\n }\r\n\r\n /**\r\n * 关闭连接\r\n */\r\n close(): void {\r\n // 取消 fetch 请求\r\n if (this.controller) {\r\n this.controller.abort()\r\n this.controller = null\r\n }\r\n\r\n // 关闭 EventSource\r\n if (this.eventSource) {\r\n this.eventSource.close()\r\n this.eventSource = null\r\n }\r\n\r\n // 清除超时定时器\r\n if (this.timeoutTimer) {\r\n clearTimeout(this.timeoutTimer)\r\n this.timeoutTimer = null\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 发起 SSE 请求(便捷方法)\r\n */\r\nexport function sse(config: SSEConfig, handlers: SSEHandlers): SSEConnection {\r\n const connection = new SSEConnection()\r\n\r\n // POST 请求或自定义配置使用 fetch\r\n if (config.method === 'POST' || config.timeout) {\r\n connection.request(config, handlers)\r\n } else {\r\n // GET 请求使用 EventSource\r\n connection.connect(config.url, handlers)\r\n }\r\n\r\n return connection\r\n}\r\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function extractThinking(text, config = {}) {
|
|
4
|
+
const { tagName = "think", includeTags = false, removeRest = false } = config;
|
|
5
|
+
const openTag = `<${tagName}>`;
|
|
6
|
+
const closeTag = `</${tagName}>`;
|
|
7
|
+
const openIndex = text.indexOf(openTag);
|
|
8
|
+
const closeIndex = text.indexOf(closeTag);
|
|
9
|
+
if (openIndex === -1 || closeIndex === -1) {
|
|
10
|
+
return {
|
|
11
|
+
thinking: "",
|
|
12
|
+
rest: text,
|
|
13
|
+
hasThinking: false
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const thinkingStart = openIndex + openTag.length;
|
|
17
|
+
const thinkingEnd = closeIndex;
|
|
18
|
+
const thinkingContent = text.slice(thinkingStart, thinkingEnd);
|
|
19
|
+
const beforeContent = text.slice(0, openIndex);
|
|
20
|
+
const afterContent = text.slice(closeIndex + closeTag.length);
|
|
21
|
+
const restContent = beforeContent + afterContent;
|
|
22
|
+
return {
|
|
23
|
+
thinking: includeTags ? `${openTag}${thinkingContent}${closeTag}` : thinkingContent,
|
|
24
|
+
rest: removeRest ? "" : restContent,
|
|
25
|
+
hasThinking: true
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
class ThinkingStreamExtractor {
|
|
29
|
+
constructor(config = {}) {
|
|
30
|
+
this.isComplete = false;
|
|
31
|
+
this.config = {
|
|
32
|
+
tagName: config.tagName || "think",
|
|
33
|
+
includeTags: config.includeTags || false,
|
|
34
|
+
removeRest: config.removeRest || false
|
|
35
|
+
};
|
|
36
|
+
this.state = {
|
|
37
|
+
inThinking: false,
|
|
38
|
+
tagBuffer: "",
|
|
39
|
+
contentBuffer: "",
|
|
40
|
+
beforeContent: "",
|
|
41
|
+
afterContent: ""
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 追加文本并提取思考内容
|
|
46
|
+
*/
|
|
47
|
+
append(text) {
|
|
48
|
+
if (this.isComplete) {
|
|
49
|
+
return {
|
|
50
|
+
thinking: this.getThinking(),
|
|
51
|
+
rest: this.getRest(),
|
|
52
|
+
isComplete: true
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const { tagName } = this.config;
|
|
56
|
+
const openTag = `<${tagName}>`;
|
|
57
|
+
const closeTag = `</${tagName}>`;
|
|
58
|
+
for (let i = 0; i < text.length; i++) {
|
|
59
|
+
const char = text[i];
|
|
60
|
+
if (!this.state.inThinking) {
|
|
61
|
+
this.state.tagBuffer += char;
|
|
62
|
+
if (this.state.tagBuffer.endsWith(openTag)) {
|
|
63
|
+
const tagStart = this.state.tagBuffer.length - openTag.length;
|
|
64
|
+
this.state.beforeContent += this.state.tagBuffer.slice(0, tagStart);
|
|
65
|
+
this.state.tagBuffer = "";
|
|
66
|
+
this.state.inThinking = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (this.state.tagBuffer.length > openTag.length) {
|
|
70
|
+
this.state.beforeContent += this.state.tagBuffer.slice(0, 1);
|
|
71
|
+
this.state.tagBuffer = this.state.tagBuffer.slice(1);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
this.state.tagBuffer += char;
|
|
75
|
+
if (this.state.tagBuffer.endsWith(closeTag)) {
|
|
76
|
+
const tagEnd = this.state.tagBuffer.length - closeTag.length;
|
|
77
|
+
this.state.contentBuffer += this.state.tagBuffer.slice(0, tagEnd);
|
|
78
|
+
this.state.tagBuffer = "";
|
|
79
|
+
this.state.inThinking = false;
|
|
80
|
+
this.isComplete = true;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (this.state.tagBuffer.length > closeTag.length) {
|
|
84
|
+
const overflow = this.state.tagBuffer.slice(0, 1);
|
|
85
|
+
this.state.contentBuffer += overflow;
|
|
86
|
+
this.state.tagBuffer = this.state.tagBuffer.slice(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!this.state.inThinking && this.state.tagBuffer) {
|
|
91
|
+
if (this.isComplete) {
|
|
92
|
+
this.state.afterContent += this.state.tagBuffer;
|
|
93
|
+
} else {
|
|
94
|
+
this.state.beforeContent += this.state.tagBuffer;
|
|
95
|
+
}
|
|
96
|
+
this.state.tagBuffer = "";
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
thinking: this.getThinking(),
|
|
100
|
+
rest: this.getRest(),
|
|
101
|
+
isComplete: this.isComplete
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 获取当前提取的思考内容
|
|
106
|
+
*/
|
|
107
|
+
getThinking() {
|
|
108
|
+
const { tagName, includeTags } = this.config;
|
|
109
|
+
const openTag = `<${tagName}>`;
|
|
110
|
+
const closeTag = `</${tagName}>`;
|
|
111
|
+
const content = this.state.contentBuffer;
|
|
112
|
+
if (includeTags) {
|
|
113
|
+
return this.state.inThinking ? `${openTag}${content}` : `${openTag}${content}${closeTag}`;
|
|
114
|
+
}
|
|
115
|
+
return content;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 获取剩余内容
|
|
119
|
+
*/
|
|
120
|
+
getRest() {
|
|
121
|
+
const { removeRest } = this.config;
|
|
122
|
+
if (removeRest) {
|
|
123
|
+
return "";
|
|
124
|
+
}
|
|
125
|
+
return this.state.beforeContent + this.state.afterContent;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 是否已完成提取
|
|
129
|
+
*/
|
|
130
|
+
complete() {
|
|
131
|
+
return this.isComplete;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 重置提取器
|
|
135
|
+
*/
|
|
136
|
+
reset() {
|
|
137
|
+
this.state = {
|
|
138
|
+
inThinking: false,
|
|
139
|
+
tagBuffer: "",
|
|
140
|
+
contentBuffer: "",
|
|
141
|
+
beforeContent: "",
|
|
142
|
+
afterContent: ""
|
|
143
|
+
};
|
|
144
|
+
this.isComplete = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function createThinkingExtractor(config) {
|
|
148
|
+
return new ThinkingStreamExtractor(config);
|
|
149
|
+
}
|
|
150
|
+
exports.ThinkingStreamExtractor = ThinkingStreamExtractor;
|
|
151
|
+
exports.createThinkingExtractor = createThinkingExtractor;
|
|
152
|
+
exports.extractThinking = extractThinking;
|
|
153
|
+
//# sourceMappingURL=thinking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking.js","sources":["../../src/thinking.ts"],"sourcesContent":["/**\r\n * 思考过程提取配置\r\n */\r\nexport interface ThinkingExtractConfig {\r\n /** 思考标签名称(默认为 'think') */\r\n tagName?: string\r\n /** 是否提取完整标签内容(包含标签本身) */\r\n includeTags?: boolean\r\n /** 是否移除思考内容后的其余文本 */\r\n removeRest?: boolean\r\n}\r\n\r\n/**\r\n * 思考过程结果\r\n */\r\nexport interface ThinkingResult {\r\n /** 提取的思考内容 */\r\n thinking: string\r\n /** 移除思考后的剩余内容 */\r\n rest: string\r\n /** 是否找到思考内容 */\r\n hasThinking: boolean\r\n}\r\n\r\n/**\r\n * 思考标签匹配状态\r\n */\r\ninterface TagMatchState {\r\n /** 是否在思考标签内 */\r\n inThinking: boolean\r\n /** 已找到的标签部分 */\r\n tagBuffer: string\r\n /** 思考内容缓冲区 */\r\n contentBuffer: string\r\n /** 前置内容 */\r\n beforeContent: string\r\n /** 后置内容 */\r\n afterContent: string\r\n}\r\n\r\n/**\r\n * 从 AI 响应中提取思考过程(完整模式)\r\n */\r\nexport function extractThinking(\r\n text: string,\r\n config: ThinkingExtractConfig = {}\r\n): ThinkingResult {\r\n const { tagName = 'think', includeTags = false, removeRest = false } = config\r\n\r\n const openTag = `<${tagName}>`\r\n const closeTag = `</${tagName}>`\r\n\r\n const openIndex = text.indexOf(openTag)\r\n const closeIndex = text.indexOf(closeTag)\r\n\r\n // 没有找到思考标签\r\n if (openIndex === -1 || closeIndex === -1) {\r\n return {\r\n thinking: '',\r\n rest: text,\r\n hasThinking: false\r\n }\r\n }\r\n\r\n // 提取思考内容\r\n const thinkingStart = openIndex + openTag.length\r\n const thinkingEnd = closeIndex\r\n const thinkingContent = text.slice(thinkingStart, thinkingEnd)\r\n\r\n // 提取剩余内容\r\n const beforeContent = text.slice(0, openIndex)\r\n const afterContent = text.slice(closeIndex + closeTag.length)\r\n const restContent = beforeContent + afterContent\r\n\r\n // 返回结果\r\n return {\r\n thinking: includeTags\r\n ? `${openTag}${thinkingContent}${closeTag}`\r\n : thinkingContent,\r\n rest: removeRest ? '' : restContent,\r\n hasThinking: true\r\n }\r\n}\r\n\r\n/**\r\n * 流式提取思考过程(用于 SSE 流式响应)\r\n */\r\nexport class ThinkingStreamExtractor {\r\n private config: ThinkingExtractConfig\r\n private state: TagMatchState\r\n private isComplete: boolean = false\r\n\r\n constructor(config: ThinkingExtractConfig = {}) {\r\n this.config = {\r\n tagName: config.tagName || 'think',\r\n includeTags: config.includeTags || false,\r\n removeRest: config.removeRest || false\r\n }\r\n this.state = {\r\n inThinking: false,\r\n tagBuffer: '',\r\n contentBuffer: '',\r\n beforeContent: '',\r\n afterContent: ''\r\n }\r\n }\r\n\r\n /**\r\n * 追加文本并提取思考内容\r\n */\r\n append(text: string): { thinking: string; rest: string; isComplete: boolean } {\r\n if (this.isComplete) {\r\n return {\r\n thinking: this.getThinking(),\r\n rest: this.getRest(),\r\n isComplete: true\r\n }\r\n }\r\n\r\n const { tagName } = this.config\r\n const openTag = `<${tagName}>`\r\n const closeTag = `</${tagName}>`\r\n\r\n // 逐字符处理\r\n for (let i = 0; i < text.length; i++) {\r\n const char = text[i]\r\n\r\n if (!this.state.inThinking) {\r\n // 查找开始标签\r\n this.state.tagBuffer += char\r\n\r\n // 检查是否匹配到开始标签\r\n if (this.state.tagBuffer.endsWith(openTag)) {\r\n // 移除已匹配的标签部分\r\n const tagStart = this.state.tagBuffer.length - openTag.length\r\n this.state.beforeContent += this.state.tagBuffer.slice(0, tagStart)\r\n this.state.tagBuffer = ''\r\n this.state.inThinking = true\r\n continue\r\n }\r\n\r\n // 如果缓冲区过长,移除不匹配的部分\r\n if (this.state.tagBuffer.length > openTag.length) {\r\n this.state.beforeContent += this.state.tagBuffer.slice(0, 1)\r\n this.state.tagBuffer = this.state.tagBuffer.slice(1)\r\n }\r\n } else {\r\n // 查找结束标签\r\n this.state.tagBuffer += char\r\n\r\n // 检查是否匹配到结束标签\r\n if (this.state.tagBuffer.endsWith(closeTag)) {\r\n // 保存思考内容(不包含结束标签)\r\n const tagEnd = this.state.tagBuffer.length - closeTag.length\r\n this.state.contentBuffer += this.state.tagBuffer.slice(0, tagEnd)\r\n this.state.tagBuffer = ''\r\n this.state.inThinking = false\r\n this.isComplete = true\r\n break\r\n }\r\n\r\n // 如果缓冲区过长,将内容移到思考缓冲区\r\n if (this.state.tagBuffer.length > closeTag.length) {\r\n const overflow = this.state.tagBuffer.slice(0, 1)\r\n this.state.contentBuffer += overflow\r\n this.state.tagBuffer = this.state.tagBuffer.slice(1)\r\n }\r\n }\r\n }\r\n\r\n // 如果不在思考标签内,将缓冲区内容移到前置/后置内容\r\n if (!this.state.inThinking && this.state.tagBuffer) {\r\n if (this.isComplete) {\r\n this.state.afterContent += this.state.tagBuffer\r\n } else {\r\n this.state.beforeContent += this.state.tagBuffer\r\n }\r\n this.state.tagBuffer = ''\r\n }\r\n\r\n return {\r\n thinking: this.getThinking(),\r\n rest: this.getRest(),\r\n isComplete: this.isComplete\r\n }\r\n }\r\n\r\n /**\r\n * 获取当前提取的思考内容\r\n */\r\n getThinking(): string {\r\n const { tagName, includeTags } = this.config\r\n const openTag = `<${tagName}>`\r\n const closeTag = `</${tagName}>`\r\n\r\n const content = this.state.contentBuffer\r\n\r\n if (includeTags) {\r\n // 如果还在标签内,不添加闭合标签\r\n return this.state.inThinking\r\n ? `${openTag}${content}`\r\n : `${openTag}${content}${closeTag}`\r\n }\r\n\r\n return content\r\n }\r\n\r\n /**\r\n * 获取剩余内容\r\n */\r\n getRest(): string {\r\n const { removeRest } = this.config\r\n if (removeRest) {\r\n return ''\r\n }\r\n return this.state.beforeContent + this.state.afterContent\r\n }\r\n\r\n /**\r\n * 是否已完成提取\r\n */\r\n complete(): boolean {\r\n return this.isComplete\r\n }\r\n\r\n /**\r\n * 重置提取器\r\n */\r\n reset(): void {\r\n this.state = {\r\n inThinking: false,\r\n tagBuffer: '',\r\n contentBuffer: '',\r\n beforeContent: '',\r\n afterContent: ''\r\n }\r\n this.isComplete = false\r\n }\r\n}\r\n\r\n/**\r\n * 创建流式提取器实例\r\n */\r\nexport function createThinkingExtractor(\r\n config?: ThinkingExtractConfig\r\n): ThinkingStreamExtractor {\r\n return new ThinkingStreamExtractor(config)\r\n}\r\n"],"names":[],"mappings":";;AA2CO,SAAS,gBACd,MACA,SAAgC,IAChB;AAChB,QAAM,EAAE,UAAU,SAAS,cAAc,OAAO,aAAa,UAAU;AAEvE,QAAM,UAAU,IAAI,OAAO;AAC3B,QAAM,WAAW,KAAK,OAAO;AAE7B,QAAM,YAAY,KAAK,QAAQ,OAAO;AACtC,QAAM,aAAa,KAAK,QAAQ,QAAQ;AAGxC,MAAI,cAAc,MAAM,eAAe,IAAI;AACzC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,IAAA;AAAA,EAEjB;AAGA,QAAM,gBAAgB,YAAY,QAAQ;AAC1C,QAAM,cAAc;AACpB,QAAM,kBAAkB,KAAK,MAAM,eAAe,WAAW;AAG7D,QAAM,gBAAgB,KAAK,MAAM,GAAG,SAAS;AAC7C,QAAM,eAAe,KAAK,MAAM,aAAa,SAAS,MAAM;AAC5D,QAAM,cAAc,gBAAgB;AAGpC,SAAO;AAAA,IACL,UAAU,cACN,GAAG,OAAO,GAAG,eAAe,GAAG,QAAQ,KACvC;AAAA,IACJ,MAAM,aAAa,KAAK;AAAA,IACxB,aAAa;AAAA,EAAA;AAEjB;AAKO,MAAM,wBAAwB;AAAA,EAKnC,YAAY,SAAgC,IAAI;AAFhD,SAAQ,aAAsB;AAG5B,SAAK,SAAS;AAAA,MACZ,SAAS,OAAO,WAAW;AAAA,MAC3B,aAAa,OAAO,eAAe;AAAA,MACnC,YAAY,OAAO,cAAc;AAAA,IAAA;AAEnC,SAAK,QAAQ;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe;AAAA,MACf,eAAe;AAAA,MACf,cAAc;AAAA,IAAA;AAAA,EAElB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAuE;AAC5E,QAAI,KAAK,YAAY;AACnB,aAAO;AAAA,QACL,UAAU,KAAK,YAAA;AAAA,QACf,MAAM,KAAK,QAAA;AAAA,QACX,YAAY;AAAA,MAAA;AAAA,IAEhB;AAEA,UAAM,EAAE,YAAY,KAAK;AACzB,UAAM,UAAU,IAAI,OAAO;AAC3B,UAAM,WAAW,KAAK,OAAO;AAG7B,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,KAAK,CAAC;AAEnB,UAAI,CAAC,KAAK,MAAM,YAAY;AAE1B,aAAK,MAAM,aAAa;AAGxB,YAAI,KAAK,MAAM,UAAU,SAAS,OAAO,GAAG;AAE1C,gBAAM,WAAW,KAAK,MAAM,UAAU,SAAS,QAAQ;AACvD,eAAK,MAAM,iBAAiB,KAAK,MAAM,UAAU,MAAM,GAAG,QAAQ;AAClE,eAAK,MAAM,YAAY;AACvB,eAAK,MAAM,aAAa;AACxB;AAAA,QACF;AAGA,YAAI,KAAK,MAAM,UAAU,SAAS,QAAQ,QAAQ;AAChD,eAAK,MAAM,iBAAiB,KAAK,MAAM,UAAU,MAAM,GAAG,CAAC;AAC3D,eAAK,MAAM,YAAY,KAAK,MAAM,UAAU,MAAM,CAAC;AAAA,QACrD;AAAA,MACF,OAAO;AAEL,aAAK,MAAM,aAAa;AAGxB,YAAI,KAAK,MAAM,UAAU,SAAS,QAAQ,GAAG;AAE3C,gBAAM,SAAS,KAAK,MAAM,UAAU,SAAS,SAAS;AACtD,eAAK,MAAM,iBAAiB,KAAK,MAAM,UAAU,MAAM,GAAG,MAAM;AAChE,eAAK,MAAM,YAAY;AACvB,eAAK,MAAM,aAAa;AACxB,eAAK,aAAa;AAClB;AAAA,QACF;AAGA,YAAI,KAAK,MAAM,UAAU,SAAS,SAAS,QAAQ;AACjD,gBAAM,WAAW,KAAK,MAAM,UAAU,MAAM,GAAG,CAAC;AAChD,eAAK,MAAM,iBAAiB;AAC5B,eAAK,MAAM,YAAY,KAAK,MAAM,UAAU,MAAM,CAAC;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,MAAM,cAAc,KAAK,MAAM,WAAW;AAClD,UAAI,KAAK,YAAY;AACnB,aAAK,MAAM,gBAAgB,KAAK,MAAM;AAAA,MACxC,OAAO;AACL,aAAK,MAAM,iBAAiB,KAAK,MAAM;AAAA,MACzC;AACA,WAAK,MAAM,YAAY;AAAA,IACzB;AAEA,WAAO;AAAA,MACL,UAAU,KAAK,YAAA;AAAA,MACf,MAAM,KAAK,QAAA;AAAA,MACX,YAAY,KAAK;AAAA,IAAA;AAAA,EAErB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsB;AACpB,UAAM,EAAE,SAAS,YAAA,IAAgB,KAAK;AACtC,UAAM,UAAU,IAAI,OAAO;AAC3B,UAAM,WAAW,KAAK,OAAO;AAE7B,UAAM,UAAU,KAAK,MAAM;AAE3B,QAAI,aAAa;AAEf,aAAO,KAAK,MAAM,aACd,GAAG,OAAO,GAAG,OAAO,KACpB,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ;AAAA,IACrC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAkB;AAChB,UAAM,EAAE,eAAe,KAAK;AAC5B,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AACA,WAAO,KAAK,MAAM,gBAAgB,KAAK,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,WAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,QAAQ;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe;AAAA,MACf,eAAe;AAAA,MACf,cAAc;AAAA,IAAA;AAEhB,SAAK,aAAa;AAAA,EACpB;AACF;AAKO,SAAS,wBACd,QACyB;AACzB,SAAO,IAAI,wBAAwB,MAAM;AAC3C;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,OAAO,CAAA;AACrB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown 渲染配置
|
|
3
|
+
*/
|
|
4
|
+
export interface MarkdownRenderConfig {
|
|
5
|
+
/** 是否启用代码高亮(默认 false) */
|
|
6
|
+
highlight?: boolean;
|
|
7
|
+
/** 自定义代码高亮语言映射 */
|
|
8
|
+
highlightLanguages?: Record<string, string>;
|
|
9
|
+
/** 是否渲染任务列表(默认 true) */
|
|
10
|
+
taskList?: boolean;
|
|
11
|
+
/** 是否渲染表格(默认 true) */
|
|
12
|
+
table?: boolean;
|
|
13
|
+
/** 是否渲染链接(默认 true) */
|
|
14
|
+
link?: boolean;
|
|
15
|
+
/** 是否渲染图片(默认 true) */
|
|
16
|
+
image?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Markdown 流式更新配置
|
|
20
|
+
*/
|
|
21
|
+
export interface MarkdownStreamConfig extends MarkdownRenderConfig {
|
|
22
|
+
/** 更新回调函数 */
|
|
23
|
+
onUpdate?: (html: string) => void;
|
|
24
|
+
/** 完成回调函数 */
|
|
25
|
+
onComplete?: (html: string) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 简单的 Markdown 渲染器
|
|
29
|
+
*/
|
|
30
|
+
export declare class MarkdownRenderer {
|
|
31
|
+
private config;
|
|
32
|
+
constructor(config?: MarkdownRenderConfig);
|
|
33
|
+
/**
|
|
34
|
+
* 渲染 Markdown 为 HTML
|
|
35
|
+
*/
|
|
36
|
+
render(markdown: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* 转义 HTML 特殊字符
|
|
39
|
+
*/
|
|
40
|
+
private escapeHtml;
|
|
41
|
+
/**
|
|
42
|
+
* 渲染代码块
|
|
43
|
+
*/
|
|
44
|
+
private renderCodeBlocks;
|
|
45
|
+
/**
|
|
46
|
+
* 渲染标题
|
|
47
|
+
*/
|
|
48
|
+
private renderHeadings;
|
|
49
|
+
/**
|
|
50
|
+
* 渲染粗体和斜体
|
|
51
|
+
*/
|
|
52
|
+
private renderEmphasis;
|
|
53
|
+
/**
|
|
54
|
+
* 渲染任务列表
|
|
55
|
+
*/
|
|
56
|
+
private renderTaskLists;
|
|
57
|
+
/**
|
|
58
|
+
* 渲染无序列表
|
|
59
|
+
*/
|
|
60
|
+
private renderUnorderedLists;
|
|
61
|
+
/**
|
|
62
|
+
* 渲染有序列表
|
|
63
|
+
*/
|
|
64
|
+
private renderOrderedLists;
|
|
65
|
+
/**
|
|
66
|
+
* 渲染表格
|
|
67
|
+
*/
|
|
68
|
+
private renderTables;
|
|
69
|
+
/**
|
|
70
|
+
* 渲染链接
|
|
71
|
+
*/
|
|
72
|
+
private renderLinks;
|
|
73
|
+
/**
|
|
74
|
+
* 渲染图片
|
|
75
|
+
*/
|
|
76
|
+
private renderImages;
|
|
77
|
+
/**
|
|
78
|
+
* 渲染段落
|
|
79
|
+
*/
|
|
80
|
+
private renderParagraphs;
|
|
81
|
+
/**
|
|
82
|
+
* 渲染换行
|
|
83
|
+
*/
|
|
84
|
+
private renderLineBreaks;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 渲染 Markdown 为 HTML(便捷方法)
|
|
88
|
+
*/
|
|
89
|
+
export declare function renderMarkdown(markdown: string, config?: MarkdownRenderConfig): string;
|
|
90
|
+
/**
|
|
91
|
+
* 流式渲染 Markdown(用于 SSE 流式响应)
|
|
92
|
+
*/
|
|
93
|
+
export declare class MarkdownStreamRenderer {
|
|
94
|
+
private renderer;
|
|
95
|
+
private buffer;
|
|
96
|
+
private config;
|
|
97
|
+
constructor(config?: MarkdownStreamConfig);
|
|
98
|
+
/**
|
|
99
|
+
* 追加文本并渲染
|
|
100
|
+
*/
|
|
101
|
+
append(text: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* 完成渲染
|
|
104
|
+
*/
|
|
105
|
+
complete(): string;
|
|
106
|
+
/**
|
|
107
|
+
* 重置渲染器
|
|
108
|
+
*/
|
|
109
|
+
reset(): void;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 创建流式渲染器实例
|
|
113
|
+
*/
|
|
114
|
+
export declare function createMarkdownRenderer(config?: MarkdownStreamConfig): MarkdownStreamRenderer;
|
|
115
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/markdown.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yBAAyB;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,wBAAwB;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sBAAsB;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sBAAsB;IACtB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sBAAsB;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,aAAa;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,GAAE,oBAAyB;IAW7C;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAkDhC;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA2C5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,YAAY;IAwDpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAMzB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,oBAAoB,GAC5B,MAAM,CAGR;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,GAAE,oBAAyB;IAK7C;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAW5B;;OAEG;IACH,QAAQ,IAAI,MAAM;IAUlB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,CAAC,EAAE,oBAAoB,GAC5B,sBAAsB,CAExB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE (Server-Sent Events) 请求配置
|
|
3
|
+
*/
|
|
4
|
+
export interface SSEConfig {
|
|
5
|
+
/** 请求 URL */
|
|
6
|
+
url: string;
|
|
7
|
+
/** 请求方法 */
|
|
8
|
+
method?: 'GET' | 'POST';
|
|
9
|
+
/** 请求头 */
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
/** 请求体(POST 请求时使用) */
|
|
12
|
+
body?: any;
|
|
13
|
+
/** 请求超时时间(毫秒) */
|
|
14
|
+
timeout?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* SSE 消息
|
|
18
|
+
*/
|
|
19
|
+
export interface SSEMessage {
|
|
20
|
+
/** 数据内容 */
|
|
21
|
+
data: string;
|
|
22
|
+
/** 事件类型 */
|
|
23
|
+
event?: string;
|
|
24
|
+
/** ID */
|
|
25
|
+
id?: string;
|
|
26
|
+
/** 重连时间(毫秒) */
|
|
27
|
+
retry?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* SSE 事件处理器
|
|
31
|
+
*/
|
|
32
|
+
export interface SSEHandlers {
|
|
33
|
+
/** 接收到消息时触发 */
|
|
34
|
+
onMessage?: (message: SSEMessage) => void;
|
|
35
|
+
/** 连接打开时触发 */
|
|
36
|
+
onOpen?: () => void;
|
|
37
|
+
/** 连接关闭时触发 */
|
|
38
|
+
onClose?: () => void;
|
|
39
|
+
/** 发生错误时触发 */
|
|
40
|
+
onError?: (error: Error) => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* SSE 连接类
|
|
44
|
+
*/
|
|
45
|
+
export declare class SSEConnection {
|
|
46
|
+
private controller;
|
|
47
|
+
private eventSource;
|
|
48
|
+
private timeoutTimer;
|
|
49
|
+
/**
|
|
50
|
+
* 发起 SSE 请求
|
|
51
|
+
*/
|
|
52
|
+
request(config: SSEConfig, handlers: SSEHandlers): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* 使用 EventSource 连接(仅支持 GET 请求)
|
|
55
|
+
*/
|
|
56
|
+
connect(url: string, handlers: SSEHandlers): void;
|
|
57
|
+
/**
|
|
58
|
+
* 解析 SSE 消息
|
|
59
|
+
*/
|
|
60
|
+
private parseMessage;
|
|
61
|
+
/**
|
|
62
|
+
* 关闭连接
|
|
63
|
+
*/
|
|
64
|
+
close(): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 发起 SSE 请求(便捷方法)
|
|
68
|
+
*/
|
|
69
|
+
export declare function sse(config: SSEConfig, handlers: SSEHandlers): SSEConnection;
|
|
70
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/sse.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,aAAa;IACb,GAAG,EAAE,MAAM,CAAA;IACX,WAAW;IACX,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACvB,UAAU;IACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,sBAAsB;IACtB,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,iBAAiB;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS;IACT,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,eAAe;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,eAAe;IACf,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAA;IACzC,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,cAAc;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,cAAc;IACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,YAAY,CAA8B;IAElD;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA0FtE;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI;IAoBjD;;OAEG;IACH,OAAO,CAAC,YAAY;IAqBpB;;OAEG;IACH,KAAK,IAAI,IAAI;CAmBd;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,GAAG,aAAa,CAY3E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 思考过程提取配置
|
|
3
|
+
*/
|
|
4
|
+
export interface ThinkingExtractConfig {
|
|
5
|
+
/** 思考标签名称(默认为 'think') */
|
|
6
|
+
tagName?: string;
|
|
7
|
+
/** 是否提取完整标签内容(包含标签本身) */
|
|
8
|
+
includeTags?: boolean;
|
|
9
|
+
/** 是否移除思考内容后的其余文本 */
|
|
10
|
+
removeRest?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 思考过程结果
|
|
14
|
+
*/
|
|
15
|
+
export interface ThinkingResult {
|
|
16
|
+
/** 提取的思考内容 */
|
|
17
|
+
thinking: string;
|
|
18
|
+
/** 移除思考后的剩余内容 */
|
|
19
|
+
rest: string;
|
|
20
|
+
/** 是否找到思考内容 */
|
|
21
|
+
hasThinking: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 从 AI 响应中提取思考过程(完整模式)
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractThinking(text: string, config?: ThinkingExtractConfig): ThinkingResult;
|
|
27
|
+
/**
|
|
28
|
+
* 流式提取思考过程(用于 SSE 流式响应)
|
|
29
|
+
*/
|
|
30
|
+
export declare class ThinkingStreamExtractor {
|
|
31
|
+
private config;
|
|
32
|
+
private state;
|
|
33
|
+
private isComplete;
|
|
34
|
+
constructor(config?: ThinkingExtractConfig);
|
|
35
|
+
/**
|
|
36
|
+
* 追加文本并提取思考内容
|
|
37
|
+
*/
|
|
38
|
+
append(text: string): {
|
|
39
|
+
thinking: string;
|
|
40
|
+
rest: string;
|
|
41
|
+
isComplete: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* 获取当前提取的思考内容
|
|
45
|
+
*/
|
|
46
|
+
getThinking(): string;
|
|
47
|
+
/**
|
|
48
|
+
* 获取剩余内容
|
|
49
|
+
*/
|
|
50
|
+
getRest(): string;
|
|
51
|
+
/**
|
|
52
|
+
* 是否已完成提取
|
|
53
|
+
*/
|
|
54
|
+
complete(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 重置提取器
|
|
57
|
+
*/
|
|
58
|
+
reset(): void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 创建流式提取器实例
|
|
62
|
+
*/
|
|
63
|
+
export declare function createThinkingExtractor(config?: ThinkingExtractConfig): ThinkingStreamExtractor;
|
|
64
|
+
//# sourceMappingURL=thinking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking.d.ts","sourceRoot":"","sources":["../../src/thinking.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yBAAyB;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qBAAqB;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,cAAc;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe;IACf,WAAW,EAAE,OAAO,CAAA;CACrB;AAkBD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,qBAA0B,GACjC,cAAc,CAoChB;AAED;;GAEG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,UAAU,CAAiB;gBAEvB,MAAM,GAAE,qBAA0B;IAe9C;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE;IA6E7E;;OAEG;IACH,WAAW,IAAI,MAAM;IAiBrB;;OAEG;IACH,OAAO,IAAI,MAAM;IAQjB;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,KAAK,IAAI,IAAI;CAUd;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,CAAC,EAAE,qBAAqB,GAC7B,uBAAuB,CAEzB"}
|