sg-paisou 0.0.0 → 0.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.
Files changed (79) hide show
  1. package/README.npm.md +322 -0
  2. package/dist/ai-chat-sdk.es.js +22610 -0
  3. package/dist/ai-chat-sdk.es.js.map +1 -0
  4. package/dist/ai-chat-sdk.umd.js +300 -0
  5. package/dist/ai-chat-sdk.umd.js.map +1 -0
  6. package/dist/style.css +1 -0
  7. package/dist/types/index.d.ts +48 -0
  8. package/package.json +58 -11
  9. package/.idea/GitCommitMessageStorage.xml +0 -8
  10. package/.idea/modules.xml +0 -8
  11. package/.idea/sg-paisou-web.iml +0 -12
  12. package/.idea/vcs.xml +0 -6
  13. package/.vscode/settings.json +0 -2
  14. package/auto-imports.d.ts +0 -10
  15. package/components.d.ts +0 -18
  16. package/index.html +0 -21
  17. package/src/App.vue +0 -38
  18. package/src/assets/images/Camera-icon.png +0 -0
  19. package/src/assets/images/anger.png +0 -0
  20. package/src/assets/images/answer-icon.png +0 -0
  21. package/src/assets/images/back.png +0 -0
  22. package/src/assets/images/bg-img.png +0 -0
  23. package/src/assets/images/collect.png +0 -0
  24. package/src/assets/images/collected.png +0 -0
  25. package/src/assets/images/empty-bookmark.png +0 -0
  26. package/src/assets/images/empty-history.png +0 -0
  27. package/src/assets/images/feedback-thinkie-img.png +0 -0
  28. package/src/assets/images/history.png +0 -0
  29. package/src/assets/images/image 5.png +0 -0
  30. package/src/assets/images/insolubility.png +0 -0
  31. package/src/assets/images/key-points.png +0 -0
  32. package/src/assets/images/photograph-icon.png +0 -0
  33. package/src/assets/images/praise-icon.png +0 -0
  34. package/src/assets/images/praiseing-icon.png +0 -0
  35. package/src/assets/images/question.png +0 -0
  36. package/src/assets/images/smiling.png +0 -0
  37. package/src/assets/images/solution-icon.png +0 -0
  38. package/src/assets/images/star-icon.png +0 -0
  39. package/src/assets/images/trample-icon.png +0 -0
  40. package/src/assets/images/trampleing-icon.png +0 -0
  41. package/src/assets/images/volume-icon.png +0 -0
  42. package/src/assets/images/volumeing-icon.png +0 -0
  43. package/src/components/AIChatSDK/AIChatComponent.vue +0 -963
  44. package/src/components/AIChatSDK/component/Dialogs.vue +0 -340
  45. package/src/components/AIChatSDK/component/SpecialQuestions.vue +0 -208
  46. package/src/components/AIChatSDK/index.ts +0 -146
  47. package/src/components/AIChatSDK/style.scss +0 -432
  48. package/src/components/AIChatSDK/utils/imageUtils.ts +0 -61
  49. package/src/components/AIChatSDK/utils/latex.ts +0 -34
  50. package/src/components/AIChatSDK/utils/mergeConfig.ts +0 -125
  51. package/src/components/ImagePreview.vue +0 -62
  52. package/src/components/PageHeader/index.vue +0 -121
  53. package/src/config.ts +0 -11
  54. package/src/env.d.ts +0 -11
  55. package/src/main.ts +0 -12
  56. package/src/router.ts +0 -20
  57. package/src/style.css +0 -33
  58. package/src/type.ts +0 -106
  59. package/src/utils/TTS_README.md +0 -232
  60. package/src/utils/bridge.ts +0 -42
  61. package/src/utils/index.ts +0 -8
  62. package/src/utils/listenOsEvent.ts +0 -3
  63. package/src/utils/messageToast.ts +0 -43
  64. package/src/utils/render.ts +0 -81
  65. package/src/utils/request.ts +0 -87
  66. package/src/utils/tts.ts +0 -319
  67. package/src/utils/typewriter.ts +0 -61
  68. package/src/utils/useSSE.ts +0 -113
  69. package/src/views/History/index.vue +0 -419
  70. package/src/views/QuestionChatPage/index.vue +0 -480
  71. package/src/vite-env.d.ts +0 -1
  72. package/tsconfig.app.json +0 -24
  73. package/tsconfig.json +0 -7
  74. package/tsconfig.node.json +0 -22
  75. package/vite.config.ts +0 -41
  76. /package/{public → dist}/mathjax/all-packages.js +0 -0
  77. /package/{public → dist}/mathjax/talEditorConfig.js +0 -0
  78. /package/{public → dist}/mathjax/tex-svg.js +0 -0
  79. /package/{src/components/AIChatSDK/types.ts → dist/types/types.d.ts} +0 -0
package/src/utils/tts.ts DELETED
@@ -1,319 +0,0 @@
1
- import { ENV_PATH_SSE } from "../config";
2
- import { getRequestHeader } from "./request";
3
-
4
- /**
5
- * TTS音频播放队列管理器
6
- */
7
- class TTSPlayer {
8
- private audioQueue: HTMLAudioElement[] = []
9
- private isPlaying = false
10
- private isMuted = false
11
- private currentAudio: HTMLAudioElement | null = null
12
- private manualPlayAudio: HTMLAudioElement | null = null // 手动播放的音频
13
- private manualPlayMessageId: string | null = null // 手动播放的消息ID
14
-
15
- /**
16
- * 添加音频到队列
17
- */
18
- addAudio(audioBlob: Blob) {
19
- if (this.isMuted) {
20
- console.log('[TTS] Skipping audio - player is muted')
21
- return
22
- }
23
-
24
- const audio = new Audio(URL.createObjectURL(audioBlob))
25
- this.audioQueue.push(audio)
26
- console.log(`[TTS] Audio added to queue. Queue length: ${this.audioQueue.length}`)
27
-
28
- // 如果当前没有播放且未静音,开始播放
29
- if (!this.isPlaying && !this.isMuted) {
30
- this.playNext()
31
- }
32
- }
33
-
34
- /**
35
- * 播放下一个音频
36
- */
37
- private playNext() {
38
- if (this.audioQueue.length === 0 || this.isMuted) {
39
- this.isPlaying = false
40
- this.currentAudio = null
41
- console.log('[TTS] Playback finished or muted')
42
- return
43
- }
44
-
45
- this.isPlaying = true
46
- this.currentAudio = this.audioQueue.shift()!
47
- console.log(`[TTS] Playing audio. Remaining in queue: ${this.audioQueue.length}`)
48
-
49
- this.currentAudio.onended = () => {
50
- console.log('[TTS] Audio ended')
51
- // 释放资源
52
- if (this.currentAudio) {
53
- URL.revokeObjectURL(this.currentAudio.src)
54
- }
55
- this.playNext()
56
- }
57
-
58
- this.currentAudio.onerror = (e) => {
59
- console.error('[TTS] Audio playback error:', e)
60
- if (this.currentAudio) {
61
- URL.revokeObjectURL(this.currentAudio.src)
62
- }
63
- this.playNext()
64
- }
65
-
66
- this.currentAudio.play().catch(err => {
67
- console.error('[TTS] Failed to play audio:', err)
68
- this.playNext()
69
- })
70
- }
71
-
72
- /**
73
- * 设置静音状态
74
- */
75
- setMuted(muted: boolean) {
76
- console.log(`[TTS] Setting muted state to: ${muted}`)
77
- this.isMuted = muted
78
-
79
- if (muted) {
80
- // 停止当前播放
81
- if (this.currentAudio) {
82
- this.currentAudio.pause()
83
- this.currentAudio.currentTime = 0
84
- URL.revokeObjectURL(this.currentAudio.src)
85
- this.currentAudio = null
86
- console.log('[TTS] Current audio stopped')
87
- }
88
-
89
- // 清空队列
90
- const queueLength = this.audioQueue.length
91
- this.audioQueue.forEach(audio => {
92
- URL.revokeObjectURL(audio.src)
93
- })
94
- this.audioQueue = []
95
- this.isPlaying = false
96
- console.log(`[TTS] Cleared ${queueLength} audio(s) from queue`)
97
- }
98
- }
99
-
100
- /**
101
- * 清空队列
102
- */
103
- clear() {
104
- this.setMuted(true)
105
- this.isMuted = false
106
- }
107
-
108
- /**
109
- * 手动播放单个消息的TTS
110
- * 优先级高于自动播放队列
111
- */
112
- playManual(audioBlob: Blob, messageId: string, onStart?: () => void, onEnd?: () => void) {
113
- // 停止当前手动播放
114
- if (this.manualPlayAudio) {
115
- this.manualPlayAudio.pause()
116
- URL.revokeObjectURL(this.manualPlayAudio.src)
117
- this.manualPlayAudio = null
118
- }
119
-
120
- // 暂停自动播放队列
121
- if (this.currentAudio && this.isPlaying) {
122
- this.currentAudio.pause()
123
- }
124
-
125
- this.manualPlayMessageId = messageId
126
- this.manualPlayAudio = new Audio(URL.createObjectURL(audioBlob))
127
-
128
- console.log(`[TTS Manual] Playing message: ${messageId}`)
129
- onStart?.()
130
-
131
- this.manualPlayAudio.onended = () => {
132
- console.log(`[TTS Manual] Playback ended for message: ${messageId}`)
133
- if (this.manualPlayAudio) {
134
- URL.revokeObjectURL(this.manualPlayAudio.src)
135
- }
136
- this.manualPlayAudio = null
137
- this.manualPlayMessageId = null
138
- onEnd?.()
139
-
140
- // 恢复自动播放队列
141
- if (this.currentAudio && this.isPlaying && !this.isMuted) {
142
- this.currentAudio.play().catch(err => {
143
- console.error('[TTS] Failed to resume auto-play:', err)
144
- this.playNext()
145
- })
146
- }
147
- }
148
-
149
- this.manualPlayAudio.onerror = (e) => {
150
- console.error('[TTS Manual] Playback error:', e)
151
- if (this.manualPlayAudio) {
152
- URL.revokeObjectURL(this.manualPlayAudio.src)
153
- }
154
- this.manualPlayAudio = null
155
- this.manualPlayMessageId = null
156
- onEnd?.()
157
- }
158
-
159
- this.manualPlayAudio.play().catch(err => {
160
- console.error('[TTS Manual] Failed to play:', err)
161
- onEnd?.()
162
- })
163
- }
164
-
165
- /**
166
- * 停止手动播放
167
- */
168
- stopManual(messageId?: string) {
169
- if (messageId && this.manualPlayMessageId !== messageId) {
170
- return
171
- }
172
-
173
- if (this.manualPlayAudio) {
174
- console.log(`[TTS Manual] Stopping playback`)
175
- this.manualPlayAudio.pause()
176
- URL.revokeObjectURL(this.manualPlayAudio.src)
177
- this.manualPlayAudio = null
178
- this.manualPlayMessageId = null
179
-
180
- // 恢复自动播放队列
181
- if (this.currentAudio && this.isPlaying && !this.isMuted) {
182
- this.currentAudio.play().catch(err => {
183
- console.error('[TTS] Failed to resume auto-play:', err)
184
- this.playNext()
185
- })
186
- }
187
- }
188
- }
189
-
190
- /**
191
- * 检查消息是否正在手动播放
192
- */
193
- isManualPlaying(messageId: string): boolean {
194
- return this.manualPlayMessageId === messageId && this.manualPlayAudio !== null
195
- }
196
- }
197
-
198
- // 创建全局TTS播放器实例
199
- export const ttsPlayer = new TTSPlayer()
200
-
201
- /**
202
- * 请求TTS音频流(支持流式响应)
203
- */
204
- export const fetchTTSAudio = async (
205
- sessionId: string,
206
- sessionDetailId: string,
207
- text: string
208
- ): Promise<Blob> => {
209
- const questionInfo = JSON.parse(sessionStorage.getItem('questionInfo') || '{}')
210
- const headerObj = getRequestHeader()
211
-
212
- const response = await fetch(`${ENV_PATH_SSE[questionInfo.envNumber]}/v1/sg/tts`, {
213
- method: 'POST',
214
- headers: {
215
- 'Content-Type': 'application/json',
216
- ...headerObj
217
- },
218
- body: JSON.stringify({
219
- sessionId,
220
- sessionDetailId,
221
- text
222
- })
223
- })
224
-
225
- if (!response.ok) {
226
- throw new Error(`TTS request failed: ${response.statusText}`)
227
- }
228
-
229
- // 如果是流式响应,读取完整的流
230
- if (response.body) {
231
- const reader = response.body.getReader()
232
- const chunks: Uint8Array[] = []
233
-
234
- while (true) {
235
- const { done, value } = await reader.read()
236
- if (done) break
237
- if (value) chunks.push(value)
238
- }
239
-
240
- // 合并所有chunks
241
- const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0)
242
- const result = new Uint8Array(totalLength)
243
- let offset = 0
244
- for (const chunk of chunks) {
245
- result.set(chunk, offset)
246
- offset += chunk.length
247
- }
248
-
249
- return new Blob([result], { type: 'audio/mpeg' })
250
- }
251
-
252
- return await response.blob()
253
- }
254
-
255
- /**
256
- * 请求并播放TTS音频(自动播放队列)
257
- */
258
- export const playTTSAudio = async (
259
- sessionId: string,
260
- sessionDetailId: string,
261
- text: string,
262
- isMuted: boolean
263
- ) => {
264
- if (isMuted || !text.trim()) {
265
- console.log('[TTS] Skipping TTS request - muted or empty text')
266
- return
267
- }
268
-
269
- console.log(`[TTS] Requesting TTS for text: "${text.substring(0, 50)}..."`)
270
-
271
- try {
272
- const audioBlob = await fetchTTSAudio(sessionId, sessionDetailId, text)
273
- console.log(`[TTS] Received audio blob, size: ${audioBlob.size} bytes`)
274
- ttsPlayer.addAudio(audioBlob)
275
- } catch (error) {
276
- console.error('[TTS] Failed to fetch TTS audio:', error)
277
- }
278
- }
279
-
280
- /**
281
- * 手动播放消息的TTS(用于播放按钮)
282
- */
283
- export const playMessageTTS = async (
284
- sessionId: string,
285
- messageId: string,
286
- text: string,
287
- onStart?: () => void,
288
- onEnd?: () => void
289
- ) => {
290
- if (!text.trim()) {
291
- console.log('[TTS Manual] Skipping - empty text')
292
- return
293
- }
294
-
295
- console.log(`[TTS Manual] Requesting TTS for message: ${messageId}`)
296
-
297
- try {
298
- const audioBlob = await fetchTTSAudio(sessionId, messageId, text)
299
- console.log(`[TTS Manual] Received audio blob, size: ${audioBlob.size} bytes`)
300
- ttsPlayer.playManual(audioBlob, messageId, onStart, onEnd)
301
- } catch (error) {
302
- console.error('[TTS Manual] Failed to fetch TTS audio:', error)
303
- onEnd?.()
304
- }
305
- }
306
-
307
- /**
308
- * 停止手动播放消息的TTS
309
- */
310
- export const stopMessageTTS = (messageId?: string) => {
311
- ttsPlayer.stopManual(messageId)
312
- }
313
-
314
- /**
315
- * 检查消息是否正在播放
316
- */
317
- export const isMessagePlaying = (messageId: string): boolean => {
318
- return ttsPlayer.isManualPlaying(messageId)
319
- }
@@ -1,61 +0,0 @@
1
- /**
2
- * 打字机效果工具函数
3
- * 按单词显示文本,而不是按字符
4
- */
5
-
6
- export interface TypewriterOptions {
7
- text: string
8
- onUpdate: (displayedText: string) => void
9
- onComplete: () => void
10
- wordDelay?: number // 每个单词的延迟时间(毫秒)
11
- }
12
-
13
- export class Typewriter {
14
- private words: string[]
15
- private currentIndex: number = 0
16
- private timer: number | null = null
17
- private options: TypewriterOptions
18
-
19
- constructor(options: TypewriterOptions) {
20
- this.options = {
21
- wordDelay: 1000, // 默认50ms
22
- ...options
23
- }
24
- // 按空格分割成单词
25
- this.words = this.options.text.split(/(\s+)/)
26
- }
27
-
28
- start() {
29
- this.displayNextWord()
30
- }
31
-
32
- private displayNextWord() {
33
- if (this.currentIndex >= this.words.length) {
34
- this.options.onComplete()
35
- return
36
- }
37
-
38
- const displayedText = this.words.slice(0, this.currentIndex + 1).join('')
39
- this.options.onUpdate(displayedText)
40
- this.currentIndex++
41
-
42
- this.timer = window.setTimeout(() => {
43
- this.displayNextWord()
44
- }, this.options.wordDelay)
45
- }
46
-
47
- stop() {
48
- if (this.timer) {
49
- clearTimeout(this.timer)
50
- this.timer = null
51
- }
52
- }
53
-
54
- skip() {
55
- this.stop()
56
- const fullText = this.words.join('')
57
- this.options.onUpdate(fullText)
58
- this.options.onComplete()
59
- }
60
- }
61
-
@@ -1,113 +0,0 @@
1
- import { fetchEventSource } from "@microsoft/fetch-event-source";
2
- import { getRequestHeader } from "./request";
3
- import { ENV_PATH_SSE } from "../config";
4
-
5
- const abortCtrl = new AbortController();
6
- const signal = abortCtrl.signal;
7
-
8
- const useSSE = <T = Record<string, unknown>>(
9
- url: string,
10
- payload: Record<string, unknown>,
11
- customHeader: Record<string, string>,
12
- method: "GET" | "POST",
13
- options: {
14
- onopen?: () => void;
15
- onmessage?: (data: T) => void;
16
- onerror?: (error: unknown) => void;
17
- onclose?: () => void;
18
- }
19
- ) => {
20
- const hash = payload.hash;
21
- const startSSE = async () => {
22
- await fetchEventSource(url, {
23
- method,
24
- signal,
25
- headers: {
26
- "Content-Type": "application/json",
27
- ...customHeader,
28
- },
29
- body: JSON.stringify(payload),
30
- onopen: async (response) => {
31
- if (!response.ok) {
32
- options.onerror?.(response.statusText);
33
- } else {
34
- options.onopen?.();
35
- }
36
- },
37
- onmessage: (e: any) => {
38
- try {
39
- if (e.event === 'finish') {
40
- options.onmessage?.({ type: e.event } as any);
41
- options.onclose?.();
42
- } else {
43
- const data = JSON.parse(e.data || '{}') as T;
44
- options.onmessage?.(payload.hash ? { ...data, hash, type: e.event } : { ...data, type: e.event });
45
- }
46
- } catch (error) {
47
- options.onerror?.(error);
48
- }
49
- },
50
- onerror: (error) => {
51
- abortCtrl.abort();
52
- options.onerror?.(error);
53
- throw new Error(`error->e: ${error}`);
54
- },
55
- openWhenHidden: true,
56
- onclose: () => {
57
- options.onclose?.();
58
- },
59
- });
60
- };
61
- return {
62
- startSSE,
63
- abortCtrl,
64
- };
65
- };
66
-
67
- // 新增:解释题目的流式请求
68
- export const explainQuestionSSE = (
69
- params: {
70
- sessionId: string
71
- content: string
72
- recommendQuestions?: boolean
73
- },
74
- onMessage: (e: {
75
- id?: string
76
- msgId?: string
77
- event: string
78
- data: any
79
- }) => void,
80
- onError: (e: any) => void,
81
- onClose: () => void
82
- ) => {
83
- const questionInfo = JSON.parse(sessionStorage.getItem('questionInfo') || '{}');
84
- console.log('explainQuestionSSE', params)
85
- const headerObj = getRequestHeader();
86
-
87
- const { startSSE, abortCtrl } = useSSE(
88
- `${ENV_PATH_SSE[questionInfo.envNumber]}/v1/sg/explain-question`,
89
- {
90
- sessionId: params.sessionId,
91
- content: params.content,
92
- recommendQuestions: params.recommendQuestions || false
93
- },
94
- headerObj as any,
95
- "POST",
96
- {
97
- onmessage: (e: any) => {
98
- onMessage(e);
99
- },
100
- onerror(e: any) {
101
- onError(e);
102
- },
103
- onclose() {
104
- onClose();
105
- },
106
- }
107
- );
108
-
109
- return {
110
- startSSE,
111
- abort: () => abortCtrl.abort()
112
- };
113
- };