@textbus/xnote 0.3.9 → 1.0.1

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/ai.service.ts ADDED
@@ -0,0 +1,124 @@
1
+ import { Observable } from '@textbus/core'
2
+
3
+ import { LLMService, LLMParams, LLMTranslateParams } from './src/services/llm.service'
4
+
5
+ export class AiService extends LLMService {
6
+ private baseUrl = '/api/llm'
7
+
8
+ /**
9
+ * 创建 SSE 流式请求(使用 POST 方法支持长内容)
10
+ */
11
+ private createSSEStream(endpoint: string, params: LLMParams | LLMTranslateParams): Observable<string> {
12
+ return new Observable<string>(observer => {
13
+ const url = `${this.baseUrl}${endpoint}`
14
+ let isComplete = false
15
+
16
+ // 使用 fetch API 支持 POST 请求和 SSE 流
17
+ fetch(url, {
18
+ method: 'POST',
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ 'Accept': 'text/event-stream',
22
+ 'x-api-key': 'xnote'
23
+ },
24
+ body: JSON.stringify(params)
25
+ })
26
+ .then(response => {
27
+ if (!response.ok) {
28
+ throw new Error(`HTTP error! status: ${response.status}`)
29
+ }
30
+
31
+ const reader = response.body?.getReader()
32
+ if (!reader) {
33
+ throw new Error('Response body is not readable')
34
+ }
35
+
36
+ const decoder = new TextDecoder()
37
+ let buffer = ''
38
+
39
+ const readStream = () => {
40
+ reader.read().then(({ done, value }) => {
41
+ if (done || isComplete) {
42
+ observer.complete()
43
+ return
44
+ }
45
+
46
+ // 解码并处理 SSE 数据
47
+ buffer += decoder.decode(value, { stream: true })
48
+
49
+ // 解析 SSE 格式的数据
50
+ const lines = buffer.split('\n')
51
+ buffer = lines.pop() || '' // 保留最后一个不完整的行
52
+
53
+ for (const line of lines) {
54
+ if (line.startsWith('data: ')) {
55
+ const data = line.slice(6)
56
+ // 检查是否是结束标记
57
+ if (data === '[DONE]') {
58
+ isComplete = true
59
+ observer.complete()
60
+ return
61
+ }
62
+ observer.next(data)
63
+ } else if (line.startsWith('event: error')) {
64
+ // 处理错误事件
65
+ const errorLine = lines[lines.indexOf(line) + 1]
66
+ if (errorLine && errorLine.startsWith('data: ')) {
67
+ observer.error(new Error(errorLine.slice(6)))
68
+ }
69
+ isComplete = true
70
+ observer.complete()
71
+ return
72
+ }
73
+ }
74
+
75
+ // 继续读取流
76
+ readStream()
77
+ }).catch(error => {
78
+ observer.error(error)
79
+ })
80
+ }
81
+
82
+ readStream()
83
+ })
84
+ .catch(error => {
85
+ observer.error(error)
86
+ })
87
+
88
+ // 返回清理函数
89
+ return () => {
90
+ isComplete = true
91
+ }
92
+ })
93
+ }
94
+
95
+ /** 续写 */
96
+ continue(params: LLMParams): Observable<string> {
97
+ return this.createSSEStream('/continue', params)
98
+ }
99
+
100
+ /** 润色内容 */
101
+ polish(params: LLMParams): Observable<string> {
102
+ return this.createSSEStream('/polish', params)
103
+ }
104
+
105
+ /** 简化内容 */
106
+ simplify(params: LLMParams): Observable<string> {
107
+ return this.createSSEStream('/simplify', params)
108
+ }
109
+
110
+ /** 丰富内容 */
111
+ enrich(params: LLMParams): Observable<string> {
112
+ return this.createSSEStream('/enrich', params)
113
+ }
114
+
115
+ /** 翻译内容 */
116
+ translate(params: LLMTranslateParams): Observable<string> {
117
+ return this.createSSEStream('/translate', params)
118
+ }
119
+
120
+ /** 总结内容 */
121
+ summarize(params: LLMParams): Observable<string> {
122
+ return this.createSSEStream('/summarize', params)
123
+ }
124
+ }