Skip to content

Conversation

@AnotiaWang
Copy link
Contributor

@AnotiaWang AnotiaWang commented Nov 2, 2025

💻 Change Type

  • ✨ feat
  • 🐛 fix
  • ♻️ refactor
  • 💄 style
  • 👷 build
  • ⚡️ perf
  • ✅ test
  • 📝 docs
  • 🔨 chore

🔗 Related Issue

🔀 Description of Change

新增模型

硅基流动新增了 MiniMax M2 和 KAT-Dev 模型

新增功能
  • 硅基流动的 Qwen3 VL 和 Qwen3 Omni 系列模型支持视频输入
  • 新增了 LLM_VISION_VIDEO_USE_BASE64 环境变量,启用后会将视频转换成 Base64 直接发送给模型,否则使用视频链接
  • 在 OpenAICompatibleFactory 里添加了 transformMessages 字段,允许 provider 自行组装消息内容

🧪 How to Test

  • Tested locally
  • Added/updated tests
  • No tests needed

📸 Screenshots / Videos

image

📝 Additional Information

Summary by Sourcery

Enable video input handling in the SiliconCloud provider, expose a hook for custom message transformations, add an environment variable to control video Base64 conversion, and introduce two new chat models (MiniMax M2 and KAT-Dev).

New Features:

  • Enable video input for Qwen3 VL and Qwen3 Omni series in SiliconCloud provider
  • Add transformMessages hook to OpenAICompatibleFactory for custom message transformations
  • Introduce LLM_VISION_VIDEO_USE_BASE64 environment variable to toggle Base64 encoding of video inputs
  • Add MiniMax M2 and KAT-Dev chat models to SiliconCloud catalog

Documentation:

  • Document the LLM_VISION_VIDEO_USE_BASE64 environment variable for video Base64 encoding

@vercel
Copy link

vercel bot commented Nov 2, 2025

@AnotiaWang is attempting to deploy a commit to the LobeHub OSS Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Nov 2, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 2, 2025

Reviewer's Guide

This PR adds support for video input in the SiliconCloud provider by introducing base64 conversion utilities, integrating a message transformation hook in the runtime, updating model definitions to include video capabilities (including two new models), and documenting a new environment variable for video encoding.

ER diagram for updated SiliconCloud chat models

erDiagram
    AIChatModelCard {
        string id
        string displayName
        string description
        int contextWindowTokens
        bool enabled
        string type
    }
    Abilities {
        bool functionCall
        bool vision
        bool video
        bool reasoning
    }
    Pricing {
        string currency
    }
    Units {
        string name
        float rate
        string strategy
        string unit
    }
    AIChatModelCard ||--o| Abilities : has
    AIChatModelCard ||--o| Pricing : has
    Pricing ||--|{ Units : contains
Loading

Class diagram for SiliconCloud provider video input support

classDiagram
    class SiliconCloudModelCard {
        +id: string
    }
    class convertVideoToBase64 {
        +convertVideoToBase64(videoUrl: string): Promise<string>
    }
    class transformMessages {
        +transformMessages(messages: any[]): Promise<any[]>
    }
    SiliconCloudModelCard <.. transformMessages
    transformMessages o-- convertVideoToBase64

    class OpenAICompatibleFactoryOptions {
        +transformMessages?: (messages: ChatCompletionMessageParam[]) => Promise<ChatCompletionMessageParam[]> | ChatCompletionMessageParam[]
    }
    class createOpenAICompatibleRuntime {
        +createOpenAICompatibleRuntime<T>()
    }
    createOpenAICompatibleRuntime o-- OpenAICompatibleFactoryOptions
    OpenAICompatibleFactoryOptions <.. transformMessages
Loading

File-Level Changes

Change Details Files
Video to Base64 conversion and message transformation integration
  • Added convertVideoToBase64 util to fetch a video URL and encode it as base64
  • Implemented transformMessages to scan message contents and convert video_url entries based on env var
  • Injected transformMessages into SiliconCloud chatCompletion parameters
packages/model-runtime/src/providers/siliconcloud/index.ts
Extended OpenAICompatibleFactory to apply provider-specific transforms
  • Added transformMessages option in OpenAICompatibleFactoryOptions
  • Updated createOpenAICompatibleRuntime to call transformMessages before default message conversion
packages/model-runtime/src/core/openaiCompatibleFactory/index.ts
Enabled video ability and added new models in model-bank
  • Marked Qwen3 VL & Omni series models with video ability
  • Introduced MiniMax M2 and KAT-Dev model entries with abilities, metadata and pricing
packages/model-bank/src/aiModels/siliconcloud.ts
Documented environment variable for video base64 encoding
  • Defined LLM_VISION_VIDEO_USE_BASE64 in English docs
  • Added Chinese translation for LLM_VISION_VIDEO_USE_BASE64
docs/self-hosting/environment-variables/s3.mdx
docs/self-hosting/environment-variables/s3.zh-CN.mdx

Possibly linked issues

  • #[Request] 请求支持基于音频/视频文件内容与多模态模型对话: The PR adds video input support for SiliconCloud models, directly addressing the issue's request for multi-modal conversation with video content.

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

@lobehubbot
Copy link
Member

👍 @AnotiaWang

Thank you for raising your pull request and contributing to our Community
Please make sure you have followed our contributing guidelines. We will review it as soon as possible.
If you encounter any problems, please feel free to connect with us.

@gru-agent
Copy link
Contributor

gru-agent bot commented Nov 2, 2025

TestGru Assignment

Summary

Link CommitId Status Reason
Detail 8c0b068 ✅ Finished

History Assignment

Files

File Pull Request
packages/model-runtime/src/providers/siliconcloud/index.ts ❌ Failed (I failed to setup the environment.)

Tip

You can @gru-agent and leave your feedback. TestGru will make adjustments based on your input

@dosubot dosubot bot added the Model Provider Model provider related label Nov 2, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `packages/model-runtime/src/providers/siliconcloud/index.ts:32-73` </location>
<code_context>
  const transformedMessages = await Promise.all(
    messages.map(async (message) => {
      if (typeof message.content === 'string') {
        return message;
      }

      // 转换消息内容数组
      if (Array.isArray(message.content)) {
        const convertedContent = await Promise.all(
          message.content.map(async (content: any) => {
            if (content.type === 'video_url') {
              const isBase64 = content.video_url.url.startsWith('data:');

              if (!isBase64 && process.env.LLM_VISION_VIDEO_USE_BASE64 === '1') {
                try {
                  const convertedUrl = await convertVideoToBase64(content.video_url.url);
                  return {
                    ...content,
                    video_url: { url: convertedUrl },
                  };
                } catch (error) {
                  console.warn('Failed to convert video to base64:', error);
                  return content;
                }
              }
            }

            return content;
          }),
        );

        return {
          ...message,
          content: convertedContent,
        };
      }

      return message;
    }),
  );

  return transformedMessages;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
  return await Promise.all(
      messages.map(async (message) => {
        if (typeof message.content === 'string') {
          return message;
        }

        // 转换消息内容数组
        if (Array.isArray(message.content)) {
          const convertedContent = await Promise.all(
            message.content.map(async (content: any) => {
              if (content.type === 'video_url') {
                const isBase64 = content.video_url.url.startsWith('data:');

                if (!isBase64 && process.env.LLM_VISION_VIDEO_USE_BASE64 === '1') {
                  try {
                    const convertedUrl = await convertVideoToBase64(content.video_url.url);
                    return {
                      ...content,
                      video_url: { url: convertedUrl },
                    };
                  } catch (error) {
                    console.warn('Failed to convert video to base64:', error);
                    return content;
                  }
                }
              }

              return content;
            }),
          );

          return {
            ...message,
            content: convertedContent,
          };
        }

        return message;
      }),
    );

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</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.

@codecov
Copy link

codecov bot commented Nov 2, 2025

Codecov Report

❌ Patch coverage is 88.00000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.74%. Comparing base (bd071fa) to head (f9f2709).

Additional details and impacted files
@@            Coverage Diff             @@
##             next    #9988      +/-   ##
==========================================
+ Coverage   81.73%   81.74%   +0.01%     
==========================================
  Files         886      888       +2     
  Lines       55986    56085      +99     
  Branches     7634     7662      +28     
==========================================
+ Hits        45760    45847      +87     
- Misses      10226    10238      +12     
Flag Coverage Δ
app 74.35% <ø> (ø)
database 98.35% <ø> (ø)
packages/agent-runtime 98.37% <ø> (ø)
packages/context-engine 93.79% <ø> (ø)
packages/electron-server-ipc 93.76% <ø> (ø)
packages/file-loaders 92.21% <ø> (ø)
packages/model-bank 100.00% <ø> (ø)
packages/model-runtime 92.15% <88.00%> (-0.04%) ⬇️
packages/prompts 77.29% <ø> (ø)
packages/python-interpreter 96.50% <ø> (ø)
packages/utils 94.39% <ø> (ø)
packages/web-crawler 96.81% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Store 73.46% <ø> (ø)
Services 55.98% <ø> (ø)
Server 77.08% <ø> (ø)
Libs 36.66% <ø> (ø)
Utils 83.03% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vercel
Copy link

vercel bot commented Nov 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
lobehub Ready Ready Preview Comment Nov 2, 2025 5:17am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Model Provider Model provider related size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants