Skip to content

refactor: 使用 xsai 替换 openai sdk 以减小包体积#1024

Open
Hoshino-Yumetsuki wants to merge 3 commits into
twikoojs:mainfrom
Hoshino-Yumetsuki:main
Open

refactor: 使用 xsai 替换 openai sdk 以减小包体积#1024
Hoshino-Yumetsuki wants to merge 3 commits into
twikoojs:mainfrom
Hoshino-Yumetsuki:main

Conversation

@Hoshino-Yumetsuki

@Hoshino-Yumetsuki Hoshino-Yumetsuki commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary by Sourcery

在 Twikoo 垃圾检测中将 OpenAI SDK 的使用替换为 xsai,以减小依赖体积,并相应调整 LLM 客户端配置。

增强内容:

  • 将垃圾检测的 LLM 调用从 OpenAI chat completions 切换为 xsai generateText,并更新响应格式的处理逻辑。
  • 更新 Twikoo 的 OpenAI 客户端辅助函数,改为使用 xsai createXSClient,并修订 DeepSeek API 的基础 URL。
  • 在 Twikoo 的 package.json 中用 xsai 替代 OpenAI 依赖,以精简整体包体积。
Original summary in English

Summary by Sourcery

Replace OpenAI SDK usage in Twikoo spam detection with xsai to reduce dependency size and adjust LLM client configuration accordingly.

Enhancements:

  • Switch spam-check LLM calls from OpenAI chat completions to xsai generateText with updated response format handling.
  • Update Twikoo OpenAI client helper to use xsai createXSClient with revised DeepSeek API base URL.
  • Replace OpenAI dependency with xsai in Twikoo package.json to slim down the package.

@sourcery-ai

sourcery-ai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
Reviewer's guide (collapsed on small PRs)

审阅者指南

重构 Twikoo 的垃圾信息检查逻辑,改为使用轻量级 xsai SDK 替代 OpenAI SDK,并相应更新客户端创建、LLM 调用、响应处理以及依赖项。

使用 xsai 进行更新后 LLM 垃圾信息检查的序列图

sequenceDiagram
  participant SpamChecker as checkByLLM
  participant XSClient as openai
  participant XSGenerate as generateText

  SpamChecker->>SpamChecker: buildMessages(comment, lastError)
  SpamChecker->>XSClient: chat(config.LLM_MODEL || deepseek-chat)
  XSClient-->>SpamChecker: model
  SpamChecker->>XSGenerate: generateText({ model, responseFormat, messages })
  XSGenerate-->>SpamChecker: chatCompletion.text
  SpamChecker->>SpamChecker: extractJson(rawText)
  SpamChecker->>SpamChecker: repairJson(extracted)
Loading

文件级变更

Change Details Files
将垃圾信息检查中的 OpenAI SDK 使用替换为 xsai 的 generateText,包括模型选择和响应解析。
  • 在基于 LLM 的垃圾信息检查函数中从 xsai 引入 generateText。
  • 通过 openai.chat 以及 json_object 的 responseFormat,使用配置的模型调用 generateText。
  • 调整 LLM 响应处理逻辑,改为使用 chatCompletion.text,而不是 OpenAI 风格的 choices[0].message.content。
  • 保留消息构造以及后续的 JSON 提取/修复逻辑。
src/server/function/twikoo/utils/spam.js
将 OpenAI 客户端实例化替换为 xsai 客户端工厂,并更新基础 URL。
  • 从 xsai 引入 createXSClient,而不是 OpenAI。
  • 通过 createXSClient,使用 apiKey 和 baseURL 设置来实例化客户端。
  • 将默认的 DeepSeek base URL 修改为 /v1 端点。
src/server/function/twikoo/utils/lib.js
更新 Twikoo 包依赖,移除 openai,添加 xsai。
  • 从 dependencies 中移除 openai。
  • 添加 xsai 作为依赖,版本为 ^0.2.2。
  • 除了一些轻微的逗号格式调整外,保持其他依赖不变。
src/server/function/twikoo/package.json

Tips and commands

与 Sourcery 互动

  • 触发新的审阅: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 通过回复某条审阅评论,请 Sourcery 从该评论创建一个 issue。你也可以在审阅评论中回复 @sourcery-ai issue 来从该评论创建 issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来随时(重新)生成标题。
  • 生成 Pull Request 摘要: 在 Pull Request 正文的任意位置写上 @sourcery-ai summary,即可在该位置生成 PR 摘要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来随时(重新)生成摘要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可随时(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 撤销所有 Sourcery 审阅: 在 Pull Request 中评论 @sourcery-ai dismiss,即可撤销所有现有的 Sourcery 审阅。特别适用于你想从一次全新审阅开始——别忘了评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的控制面板来:

  • 启用或禁用审阅功能,例如 Sourcery 自动生成的 Pull Request 摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Refactors the Twikoo spam-checking logic to use the lightweight xsai SDK instead of the OpenAI SDK, updating client creation, LLM invocation, response handling, and dependencies accordingly.

Sequence diagram for updated LLM spam check using xsai

sequenceDiagram
  participant SpamChecker as checkByLLM
  participant XSClient as openai
  participant XSGenerate as generateText

  SpamChecker->>SpamChecker: buildMessages(comment, lastError)
  SpamChecker->>XSClient: chat(config.LLM_MODEL || deepseek-chat)
  XSClient-->>SpamChecker: model
  SpamChecker->>XSGenerate: generateText({ model, responseFormat, messages })
  XSGenerate-->>SpamChecker: chatCompletion.text
  SpamChecker->>SpamChecker: extractJson(rawText)
  SpamChecker->>SpamChecker: repairJson(extracted)
Loading

File-Level Changes

Change Details Files
Replace OpenAI SDK usage in spam checking with xsai generateText, including model selection and response parsing.
  • Require generateText from xsai inside the LLM-based spam check function.
  • Invoke generateText with the configured model via openai.chat and json_object responseFormat.
  • Adjust handling of the LLM response to use chatCompletion.text instead of OpenAI-style choices[0].message.content.
  • Preserve message construction and downstream JSON extraction/repair logic.
src/server/function/twikoo/utils/spam.js
Swap OpenAI client instantiation with xsai client factory and update base URL.
  • Require createXSClient from xsai instead of OpenAI.
  • Instantiate the client via createXSClient with apiKey and baseURL settings.
  • Change the default DeepSeek base URL to the /v1 endpoint.
src/server/function/twikoo/utils/lib.js
Update Twikoo package dependencies to drop openai and add xsai.
  • Remove openai from dependencies.
  • Add xsai as a dependency with version ^0.2.2.
  • Keep other dependencies unchanged aside from minor comma formatting.
src/server/function/twikoo/package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并提供了一些整体反馈:

  • checkByLLM 中,每次调用函数时都会在函数内部 require 一次 generateText;建议将 require('xsai') 移到模块作用域,避免重复加载模块,并让代码风格与其他导入保持一致。
  • 重构把模型标识从 deepseek-v4-pro 改成了 deepseek-chat,并且把 base URL 改成包含 /v1;请仔细确认这些值是否是有意为之,并且与现有的配置键和支持的端点保持一致,以避免出现意外行为。
  • 新的 generateText 调用使用了 responseFormat 并期望返回 chatCompletion.text,这和之前 OpenAI SDK 的响应结构不同;请确认这是否符合实际的 xsai 响应结构和可用选项,如果返回格式与预期不符,考虑增加错误/边缘情况处理。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `checkByLLM`, `generateText` is required inside the function on each call; consider moving the `require('xsai')` to the module scope to avoid repeated module loading and make the code more consistent with other imports.
- The refactor changes the model identifier from `deepseek-v4-pro` to `deepseek-chat` and alters the base URL to include `/v1`; double-check that these values are intentional and aligned with the existing configuration keys and supported endpoints to avoid unexpected behavior.
- The new `generateText` call uses `responseFormat` and expects `chatCompletion.text`, which differs from the previous OpenAI SDK response structure; verify that this matches the actual `xsai` response shape and options, and consider handling error/edge cases if the returned format is not as expected.

## Individual Comments

### Comment 1
<location path="src/server/function/twikoo/utils/spam.js" line_range="146-149" />
<code_context>
-        model: config.LLM_MODEL || 'deepseek-v4-pro',
-        response_format: { type: 'json_object' },
+      const { generateText } = require('xsai')
+      const chatCompletion = await generateText({
+        model: openai.chat(config.LLM_MODEL || 'deepseek-chat'),
+        responseFormat: { type: 'json_object' },
         messages
       })

</code_context>
<issue_to_address>
**issue (bug_risk):** `generateText``model` 参数看起来被错误指定了,可能会导致运行时失败。

这里你传入的是 `model: openai.chat(config.LLM_MODEL || 'deepseek-chat')``model` 选项应该是一个模型标识字符串(例如 `config.LLM_MODEL || 'deepseek-chat'`),而不是 `openai.chat(...)` 的结果,后者很可能是一个函数或 Promise。请直接传入模型名称,并依赖通过 `getOpenAIClient` 配置好的客户端来完成调用。
</issue_to_address>

### Comment 2
<location path="src/server/function/twikoo/utils/lib.js" line_range="75-77" />
<code_context>
     return xml2js
   },
   getOpenAIClient (config) {
-    const OpenAI = require('openai') // OpenAI 的 SDK,用于反垃圾
-    const openaiClient = new OpenAI({
+    const { createXSClient } = require('xsai') // xsai SDK
+    const openaiClient = createXSClient({
       apiKey: config.LLM_API_KEY,
-      baseURL: config.LLM_API_ENDPOINT || 'https://api.deepseek.com'
</code_context>
<issue_to_address>
**suggestion:** 辅助函数名 `getOpenAIClient` 现在已经与底层的 xsai 客户端不匹配,可能会造成困惑。

这个函数现在通过 `createXSClient` 实例化的是 xsai 客户端,但函数名(`getOpenAIClient`)和变量名(`openaiClient`)仍然引用 OpenAI。请将它们重命名以体现 xsai(或者使用更通用的名字,如 `getLLMClient`),以保持抽象层清晰并减少混淆。

Suggested implementation:

```javascript
  getLLMClient (config) {
    const { createXSClient } = require('xsai') // xsai SDK
    const llmClient = createXSClient({
      apiKey: config.LLM_API_KEY,
      baseURL: config.LLM_API_ENDPOINT || 'https://api.deepseek.com/v1'
    })
    return llmClient
  }

```

1. 将代码库中所有对 `getOpenAIClient(...)` 的调用更新为 `getLLMClient(...)`2. 如果有任何类型定义、文档或注释引用了 `getOpenAIClient``openaiClient`,也请统一重命名为 `getLLMClient` / `llmClient`,保持命名一致。

Sourcery 对开源项目是免费的——如果你觉得我们的代码评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进之后的评审。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In checkByLLM, generateText is required inside the function on each call; consider moving the require('xsai') to the module scope to avoid repeated module loading and make the code more consistent with other imports.
  • The refactor changes the model identifier from deepseek-v4-pro to deepseek-chat and alters the base URL to include /v1; double-check that these values are intentional and aligned with the existing configuration keys and supported endpoints to avoid unexpected behavior.
  • The new generateText call uses responseFormat and expects chatCompletion.text, which differs from the previous OpenAI SDK response structure; verify that this matches the actual xsai response shape and options, and consider handling error/edge cases if the returned format is not as expected.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `checkByLLM`, `generateText` is required inside the function on each call; consider moving the `require('xsai')` to the module scope to avoid repeated module loading and make the code more consistent with other imports.
- The refactor changes the model identifier from `deepseek-v4-pro` to `deepseek-chat` and alters the base URL to include `/v1`; double-check that these values are intentional and aligned with the existing configuration keys and supported endpoints to avoid unexpected behavior.
- The new `generateText` call uses `responseFormat` and expects `chatCompletion.text`, which differs from the previous OpenAI SDK response structure; verify that this matches the actual `xsai` response shape and options, and consider handling error/edge cases if the returned format is not as expected.

## Individual Comments

### Comment 1
<location path="src/server/function/twikoo/utils/spam.js" line_range="146-149" />
<code_context>
-        model: config.LLM_MODEL || 'deepseek-v4-pro',
-        response_format: { type: 'json_object' },
+      const { generateText } = require('xsai')
+      const chatCompletion = await generateText({
+        model: openai.chat(config.LLM_MODEL || 'deepseek-chat'),
+        responseFormat: { type: 'json_object' },
         messages
       })

</code_context>
<issue_to_address>
**issue (bug_risk):** The `model` argument to `generateText` looks mis-specified and may cause runtime failures.

Here you’re passing `model: openai.chat(config.LLM_MODEL || 'deepseek-chat')`. The `model` option should be a model identifier string (e.g. `config.LLM_MODEL || 'deepseek-chat'`), not the result of `openai.chat(...)`, which is likely a function or Promise. Please pass the model name directly and rely on the client configured via `getOpenAIClient` instead.
</issue_to_address>

### Comment 2
<location path="src/server/function/twikoo/utils/lib.js" line_range="75-77" />
<code_context>
     return xml2js
   },
   getOpenAIClient (config) {
-    const OpenAI = require('openai') // OpenAI 的 SDK,用于反垃圾
-    const openaiClient = new OpenAI({
+    const { createXSClient } = require('xsai') // xsai SDK
+    const openaiClient = createXSClient({
       apiKey: config.LLM_API_KEY,
-      baseURL: config.LLM_API_ENDPOINT || 'https://api.deepseek.com'
</code_context>
<issue_to_address>
**suggestion:** The helper name `getOpenAIClient` no longer matches the underlying xsai client, which could cause confusion.

This function now instantiates an xsai client via `createXSClient`, but both the function (`getOpenAIClient`) and variable (`openaiClient`) names still reference OpenAI. Please rename them to reflect xsai (or use a generic name like `getLLMClient`) to keep the abstraction clear and reduce confusion.

Suggested implementation:

```javascript
  getLLMClient (config) {
    const { createXSClient } = require('xsai') // xsai SDK
    const llmClient = createXSClient({
      apiKey: config.LLM_API_KEY,
      baseURL: config.LLM_API_ENDPOINT || 'https://api.deepseek.com/v1'
    })
    return llmClient
  }

```

1. Update all call sites of `getOpenAIClient(...)` in the codebase to use `getLLMClient(...)` instead.
2. If there are any type definitions, documentation, or comments referencing `getOpenAIClient` or `openaiClient`, rename them to `getLLMClient` / `llmClient` to keep naming consistent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/server/function/twikoo/utils/spam.js
Comment thread src/server/function/twikoo/utils/lib.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant