Skip to content

Commit 4be25a2

Browse files
authored
Merge pull request #8 from yusixian/dev
v0.1.5
2 parents 418e7f5 + 7361324 commit 4be25a2

File tree

3 files changed

+204
-116
lines changed

3 files changed

+204
-116
lines changed

hooks/useAiSummary.ts

Lines changed: 169 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { generateText } from "@xsai/generate-text"
12
import type { StreamTextChunkResult, StreamTextResult } from "@xsai/stream-text"
23
import { useCallback, useLayoutEffect, useState } from "react"
4+
import { isMobile } from "react-device-detect"
35
import { toast } from "react-toastify"
46

57
import { Storage } from "@plasmohq/storage"
@@ -214,141 +216,193 @@ export const useAiSummary = (
214216
processedPrompt = processTemplate(customPrompt, scrapedData)
215217
}
216218
debugLog("processedPrompt", processedPrompt)
217-
const result = await generateSummary(processedPrompt)
218-
if (result) {
219-
debugLog("generateSummaryText result获取成功", result)
220-
debugLog("streamText返回值结构:", {
221-
textStream: typeof result.textStream,
222-
stepStream: typeof result.stepStream,
223-
chunkStream: typeof result.chunkStream,
224-
hasTextStream: !!result.textStream,
225-
hasStepStream: !!result.stepStream,
226-
hasChunkStream: !!result.chunkStream
219+
220+
// 根据是否为移动端选择不同的生成方式
221+
if (isMobile) {
222+
// 移动端使用非流式生成
223+
// TODO: 移动端流式输出好像有问题,等后续 debug,先打补丁
224+
debugLog("检测到移动设备,使用直接生成方式")
225+
226+
// 获取AI配置信息
227+
const config = await getAiConfig()
228+
229+
// 调用generateText直接生成文本
230+
const { text, usage } = await generateText({
231+
apiKey: apiKey,
232+
baseURL: config.baseURL || "https://api.openai.com/v1/",
233+
messages: [
234+
{
235+
content: config.systemPrompt || "你是一个有用的助手",
236+
role: "system"
237+
},
238+
{
239+
content: processedPrompt + "\n\n内容: " + content,
240+
role: "user"
241+
}
242+
],
243+
model: config.model || "gpt-3.5-turbo"
227244
})
228245

229-
// 保存结果对象
230-
setResult(result)
231-
setUsage(null) // 初始化usage
246+
// 设置生成的文本
247+
fullText = text
248+
setSummary(text)
249+
setStreamingText(text)
250+
onSummaryGenerated?.(text)
251+
252+
// 设置token使用情况
253+
if (usage) {
254+
const newUsage = {
255+
total_tokens: usage.total_tokens,
256+
prompt_tokens: usage.prompt_tokens,
257+
completion_tokens: usage.completion_tokens
258+
}
259+
setUsage(newUsage)
260+
currentUsage = newUsage
261+
}
232262

233-
// 使用流式接收文本和处理 usage
234-
try {
235-
// 处理 usage 流
236-
const chunkStream =
237-
result.chunkStream as unknown as AsyncIterable<StreamTextChunkResult>
238-
// TODO: 流这块还得完善,现在只是能跑!
239-
// 单独启动一个异步任务处理 chunkStream
240-
const processChunkStream = async () => {
241-
debugLog("开始处理 chunkStream 获取 usage...")
263+
// 保存到历史记录
264+
await saveToHistory(text, currentUsage)
265+
savedToHistory = true
266+
setError(null)
267+
} else {
268+
// 桌面端使用流式生成
269+
const result = await generateSummary(processedPrompt)
270+
if (result) {
271+
debugLog("generateSummaryText result获取成功", result)
272+
debugLog("streamText返回值结构:", {
273+
textStream: typeof result.textStream,
274+
stepStream: typeof result.stepStream,
275+
chunkStream: typeof result.chunkStream,
276+
hasTextStream: !!result.textStream,
277+
hasStepStream: !!result.stepStream,
278+
hasChunkStream: !!result.chunkStream
279+
})
242280

243-
try {
244-
for await (const chunk of chunkStream) {
245-
// 如果 chunk 中有 usage 信息,则更新 usage 状态
246-
if (chunk.usage) {
247-
debugLog("接收到 usage 信息:", chunk.usage)
248-
const newUsage = {
249-
total_tokens: chunk.usage.total_tokens,
250-
prompt_tokens: chunk.usage.prompt_tokens,
251-
completion_tokens: chunk.usage.completion_tokens
281+
// 保存结果对象
282+
setResult(result)
283+
setUsage(null) // 初始化usage
284+
285+
// 使用流式接收文本和处理 usage
286+
try {
287+
// 处理 usage 流
288+
const chunkStream =
289+
result.chunkStream as unknown as AsyncIterable<StreamTextChunkResult>
290+
// TODO: 流这块还得完善,现在只是能跑!
291+
// 单独启动一个异步任务处理 chunkStream
292+
const processChunkStream = async () => {
293+
debugLog("开始处理 chunkStream 获取 usage...")
294+
295+
try {
296+
for await (const chunk of chunkStream) {
297+
// 如果 chunk 中有 usage 信息,则更新 usage 状态
298+
if (chunk.usage) {
299+
debugLog("接收到 usage 信息:", chunk.usage)
300+
const newUsage = {
301+
total_tokens: chunk.usage.total_tokens,
302+
prompt_tokens: chunk.usage.prompt_tokens,
303+
completion_tokens: chunk.usage.completion_tokens
304+
}
305+
setUsage(newUsage)
306+
currentUsage = newUsage
252307
}
253-
setUsage(newUsage)
254-
currentUsage = newUsage
255308
}
309+
debugLog("chunkStream 处理完成")
310+
} catch (chunkError) {
311+
console.error("chunkStream 处理出错:", chunkError)
312+
debugLog("chunkStream 处理详细错误:", {
313+
name: chunkError.name,
314+
message: chunkError.message,
315+
stack: chunkError.stack
316+
})
256317
}
257-
debugLog("chunkStream 处理完成")
258-
} catch (chunkError) {
259-
console.error("chunkStream 处理出错:", chunkError)
260-
debugLog("chunkStream 处理详细错误:", {
261-
name: chunkError.name,
262-
message: chunkError.message,
263-
stack: chunkError.stack
264-
})
265318
}
266-
}
267319

268-
// 启动异步处理,但不等待它完成
269-
processChunkStream()
320+
// 启动异步处理,但不等待它完成
321+
processChunkStream()
270322

271-
// 处理文本流
272-
const textStream =
273-
result.textStream as unknown as AsyncIterable<string>
323+
// 处理文本流
324+
const textStream =
325+
result.textStream as unknown as AsyncIterable<string>
274326

275-
// 处理文本流
276-
debugLog("开始处理textStream...")
277-
let chunkCount = 0
327+
// 处理文本流
328+
debugLog("开始处理textStream...")
329+
let chunkCount = 0
278330

279-
try {
280-
for await (const textPart of textStream) {
281-
chunkCount++
282-
// 每接收 20 个文本块打印一次日志,避免日志过多
283-
if (chunkCount % 20 === 0 || chunkCount <= 2) {
284-
debugLog(`接收到第${chunkCount}个文本块:`, {
285-
length: textPart.length,
286-
preview:
287-
textPart.slice(0, 20) + (textPart.length > 20 ? "..." : "")
288-
})
331+
try {
332+
for await (const textPart of textStream) {
333+
chunkCount++
334+
// 每接收 20 个文本块打印一次日志,避免日志过多
335+
if (chunkCount % 20 === 0 || chunkCount <= 2) {
336+
debugLog(`接收到第${chunkCount}个文本块:`, {
337+
length: textPart.length,
338+
preview:
339+
textPart.slice(0, 20) +
340+
(textPart.length > 20 ? "..." : "")
341+
})
342+
}
343+
344+
fullText += textPart
345+
setStreamingText((prev) => prev + textPart)
289346
}
290347

291-
fullText += textPart
292-
setStreamingText((prev) => prev + textPart)
348+
debugLog(
349+
`textStream 处理完成,共接收${chunkCount}个文本块,最终文本长度:${fullText?.length}`
350+
)
351+
} catch (textStreamError) {
352+
console.error("textStream 处理出错:", textStreamError)
353+
debugLog("textStream 处理详细错误:", {
354+
name: textStreamError.name,
355+
message: textStreamError.message,
356+
stack: textStreamError.stack
357+
})
358+
// 即使textStream出错,但如果我们已经收集了一些文本,我们也应该使用它
359+
debugLog(
360+
"尽管 textStream 出错,仍将使用已收集的文本,长度:",
361+
fullText.length
362+
)
293363
}
294364

295-
debugLog(
296-
`textStream 处理完成,共接收${chunkCount}个文本块,最终文本长度:${fullText?.length}`
297-
)
298-
} catch (textStreamError) {
299-
console.error("textStream 处理出错:", textStreamError)
300-
debugLog("textStream 处理详细错误:", {
301-
name: textStreamError.name,
302-
message: textStreamError.message,
303-
stack: textStreamError.stack
304-
})
305-
// 即使textStream出错,但如果我们已经收集了一些文本,我们也应该使用它
306-
debugLog(
307-
"尽管 textStream 出错,仍将使用已收集的文本,长度:",
308-
fullText.length
309-
)
310-
}
311-
312-
// 无论流处理是否成功,都使用收集的文本
313-
if (fullText) {
314-
// 流处理完成后使用收集的完整文本
315-
setSummary(fullText)
316-
onSummaryGenerated?.(fullText)
317-
debugLog("处理完成,最终文本长度:", fullText.length)
318-
319-
// 获取当前usage状态用于保存历史记录
320-
const usageForSave = currentUsage || usage || null
321-
322-
debugLog("准备保存历史记录,当前状态:", {
323-
fullTextLength: fullText?.length || 0,
324-
hasFullText: !!fullText,
325-
hasScrapedData: !!scrapedData,
326-
hasUrl: !!scrapedData?.url,
327-
usage: usageForSave
328-
})
365+
// 无论流处理是否成功,都使用收集的文本
366+
if (fullText) {
367+
// 流处理完成后使用收集的完整文本
368+
setSummary(fullText)
369+
onSummaryGenerated?.(fullText)
370+
debugLog("处理完成,最终文本长度:", fullText.length)
371+
372+
// 获取当前usage状态用于保存历史记录
373+
const usageForSave = currentUsage || usage || null
374+
375+
debugLog("准备保存历史记录,当前状态:", {
376+
fullTextLength: fullText?.length || 0,
377+
hasFullText: !!fullText,
378+
hasScrapedData: !!scrapedData,
379+
hasUrl: !!scrapedData?.url,
380+
usage: usageForSave
381+
})
329382

330-
// 保存到历史记录
331-
try {
332-
await saveToHistory(fullText, usageForSave)
333-
savedToHistory = true
334-
debugLog("成功保存到历史记录")
335-
} catch (saveError) {
336-
console.error("保存历史记录失败:", saveError)
337-
debugLog("保存历史记录失败:", saveError)
383+
// 保存到历史记录
384+
try {
385+
await saveToHistory(fullText, usageForSave)
386+
savedToHistory = true
387+
debugLog("成功保存到历史记录")
388+
} catch (saveError) {
389+
console.error("保存历史记录失败:", saveError)
390+
debugLog("保存历史记录失败:", saveError)
391+
}
338392
}
393+
} catch (streamError) {
394+
console.error("流处理出错:", streamError)
395+
debugLog("流处理详细错误:", {
396+
name: streamError.name,
397+
message: streamError.message,
398+
stack: streamError.stack
399+
})
339400
}
340-
} catch (streamError) {
341-
console.error("流处理出错:", streamError)
342-
debugLog("流处理详细错误:", {
343-
name: streamError.name,
344-
message: streamError.message,
345-
stack: streamError.stack
346-
})
347-
}
348401

349-
setError(null)
350-
} else {
351-
throw new Error("生成摘要失败")
402+
setError(null)
403+
} else {
404+
throw new Error("生成摘要失败")
405+
}
352406
}
353407
} catch (error) {
354408
setError(error.message || "未知错误")

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "moe-copy-ai",
33
"displayName": "Moe Copy AI",
4-
"version": "0.1.4",
4+
"version": "0.1.5",
55
"description": "✨ 萌萌哒的 AI 网页数据提取助手 ✨",
66
"author": "cos <i@cosine.ren>",
77
"scripts": {
@@ -14,6 +14,7 @@
1414
"@iconify/react": "^5.2.0",
1515
"@plasmohq/messaging": "^0.7.1",
1616
"@plasmohq/storage": "^1.15.0",
17+
"@xsai/generate-text": "0.2.0-beta.3",
1718
"@xsai/model": "0.2.0-beta.3",
1819
"@xsai/stream-text": "0.2.0-beta.3",
1920
"class-variance-authority": "^0.7.1",
@@ -24,6 +25,7 @@
2425
"pino": "^9.6.0",
2526
"plasmo": "0.90.3",
2627
"react": "18.2.0",
28+
"react-device-detect": "^2.2.3",
2729
"react-dom": "18.2.0",
2830
"react-responsive": "^10.0.0",
2931
"react-toastify": "^11.0.5",

0 commit comments

Comments
 (0)