Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: send media from QQBot #1427

Merged
merged 1 commit into from
Mar 9, 2025
Merged

Conversation

lss233
Copy link
Owner

@lss233 lss233 commented Mar 9, 2025

好的,这是将 pull request 总结翻译成中文的结果:

Sourcery 总结

添加了通过 QQBot 适配器发送媒体消息(图片、语音和视频)的支持。这包括修改消息发送逻辑以处理不同的消息元素类型,并添加了 post_file 方法的补丁版本来处理文件上传。

新功能:

  • 添加了通过 QQBot 适配器发送媒体消息(图片、语音和视频)的支持。
  • 添加了 patched_post_file 方法来处理文件上传到 QQBot。
  • 添加了对消息中 MentionElement 的支持,以在 QQBot 消息中提及用户。
  • 添加了通过 QQBot 适配器发送媒体消息(图片、语音和视频)的支持。
  • 添加了 patched_post_file 方法来处理文件上传到 QQBot。
  • 添加了对消息中 MentionElement 的支持,以在 QQBot 消息中提及用户。
Original summary in English

Summary by Sourcery

Adds support for sending media messages (images, voice, and video) through the QQBot adapter. This includes modifying the message sending logic to handle different message element types and adding a patched version of the post_file method to handle file uploads.

New Features:

  • Adds support for sending media messages (images, voice, and video) through the QQBot adapter.
  • Adds patched_post_file method to handle file uploads to QQBot.
  • Adds support for MentionElement in messages to mention users in QQBot messages.
  • Adds support for sending media messages (images, voice, and video) through the QQBot adapter.
  • Adds patched_post_file method to handle file uploads to QQBot.
  • Adds support for MentionElement in messages to mention users in QQBot messages.

…pload support

- Add patched file upload method for QQBot API
- Implement comprehensive message sending logic supporting text, images, voice, and video
- Support message sequencing and multi-element message composition
- Add base64 encoding for file uploads
- Improve message conversion and handling for different message types
Copy link
Contributor

sourcery-ai bot commented Mar 9, 2025

## Sourcery 评审者指南

此 Pull Request 引入了通过 QQBot 适配器发送媒体消息(图片、语音和视频)的功能。它包括对消息发送逻辑的修改,以处理不同的消息元素类型,包括文本、提及和媒体。使用 `post_file` 方法的修补版本来处理具有特定文件类型的文件上传。

#### 发送带媒体消息的序列图

```mermaid
sequenceDiagram
    participant User
    participant IMMessage
    participant QQBotAdapter
    participant QQBotAPI

    User->>IMMessage: 创建包含文本和媒体的消息 (ImageMessage/VoiceMessage/VideoElement)
    User->>QQBotAdapter: send_message(message, recipient)
    QQBotAdapter->>QQBotAdapter: 迭代 message.message_elements
    alt TextMessage
        QQBotAdapter->>QQBotAdapter: 将文本附加到 current_text
    else ImageMessage/VoiceMessage/VideoElement
        QQBotAdapter->>QQBotAdapter: 通过 post_message_func 发送 current_text(如果有)
        QQBotAdapter->>QQBotAdapter: 使用 patched_post_file 上传媒体
        QQBotAdapter->>QQBotAPI: patched_post_file(file_type, file_data, recipient)
        QQBotAPI-->>QQBotAdapter: 返回媒体对象
        QQBotAdapter->>QQBotAdapter: 通过 post_message_func 发送媒体对象,msg_type=7
        QQBotAPI->>QQBotAPI: post_c2c_message 或 post_group_message
    end
    QQBotAdapter->>QQBotAdapter: 通过 post_message_func 发送剩余文本(如果有)

文件级别变更

变更 详情 文件
实现了 QQBot 的媒体发送功能,包括图像、语音消息和视频元素。
  • 添加了 patched_post_file 以处理文件上传到 QQBot。
  • 修改了 send_message 以处理媒体元素并通过 QQBot 的 API 发送它们。
  • 添加了区分图像、语音和视频消息的逻辑。
  • 实现了文本缓冲以将文本消息分组在一起。
  • 添加了对提及元素的支持。
  • 向 post_file 方法添加了 file_type 参数。
kirara_ai/plugins/im_qqbot_adapter/adapter.py
修补了 QQBotAdapter 中的 post_file 方法以包含文件类型信息。
  • patched_post_c2c_filepatched_post_group_file 添加到 QQBotAdapter 类。
  • 这些方法被分配给 QQBotAdapter 实例的 api 对象。
  • patched_post_file 函数现在接受 file_type 参数。
kirara_ai/plugins/im_qqbot_adapter/adapter.py

提示和命令

与 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 以触发新的审查!
  • 为 issue 生成行动计划: 在 issue 上评论 @sourcery-ai plan 以为其生成行动计划。

自定义您的体验

访问您的 仪表板 以:

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

获得帮助

```
Original review guide in English

Reviewer's Guide by Sourcery

This pull request introduces the capability to send media messages (images, voice, and video) via the QQBot adapter. It includes modifications to the message sending logic to handle different message element types, including text, mentions, and media. A patched version of the post_file method is used to handle file uploads with specific file types.

Sequence diagram for sending a message with media

sequenceDiagram
    participant User
    participant IMMessage
    participant QQBotAdapter
    participant QQBotAPI

    User->>IMMessage: Creates a message with text and media (ImageMessage/VoiceMessage/VideoElement)
    User->>QQBotAdapter: send_message(message, recipient)
    QQBotAdapter->>QQBotAdapter: Iterates through message.message_elements
    alt TextMessage
        QQBotAdapter->>QQBotAdapter: Appends text to current_text
    else ImageMessage/VoiceMessage/VideoElement
        QQBotAdapter->>QQBotAdapter: Sends current_text (if any) via post_message_func
        QQBotAdapter->>QQBotAdapter: Uploads media using patched_post_file
        QQBotAdapter->>QQBotAPI: patched_post_file(file_type, file_data, recipient)
        QQBotAPI-->>QQBotAdapter: Returns media object
        QQBotAdapter->>QQBotAdapter: Sends media object via post_message_func with msg_type=7
        QQBotAPI->>QQBotAPI: post_c2c_message or post_group_message
    end
    QQBotAdapter->>QQBotAdapter: Sends remaining text (if any) via post_message_func
Loading

File-Level Changes

Change Details Files
Implemented media sending functionality for QQBot, including images, voice messages, and video elements.
  • Added patched_post_file to handle file uploads to QQBot.
  • Modified send_message to process media elements and send them via QQBot's API.
  • Added logic to differentiate between image, voice, and video messages.
  • Implemented text buffering to group text messages together.
  • Added support for mention elements.
  • Added file_type parameter to post_file method.
kirara_ai/plugins/im_qqbot_adapter/adapter.py
Patched the post_file methods in the QQBotAdapter to include file type information.
  • Added patched_post_c2c_file and patched_post_group_file to the QQBotAdapter class.
  • These methods are assigned to the api object of the QQBotAdapter instance.
  • The patched_post_file function now accepts a file_type parameter.
kirara_ai/plugins/im_qqbot_adapter/adapter.py

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!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

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

Copy link

codecov bot commented Mar 9, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 68.42%. Comparing base (a8ebdd1) to head (55a18a3).
Report is 6 commits behind head on master.

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1427      +/-   ##
==========================================
+ Coverage   66.75%   68.42%   +1.67%     
==========================================
  Files         105      105              
  Lines        4666     4821     +155     
==========================================
+ Hits         3115     3299     +184     
+ Misses       1551     1522      -29     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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 @lss233 - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Flagging hardcoded app secret. (link)

Overall Comments:

  • Consider adding type hints to the file_data parameter in patched_post_file for better clarity.
  • The logic for sending different types of media could be simplified by using a dictionary to map element types to file types.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🔴 Security: 1 blocking issue
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

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.

elif isinstance(element, VideoElement):
file_type = 2
media = await upload_func(file_type=file_type, file_data=await element.get_data())
print(media)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Remove or replace debug print statement.

The print(media) statement appears to be a leftover debugging artifact. It might be better to use a logger or remove it to avoid unintended console output in production.

@@ -100,10 +133,59 @@ async def send_message(self, message: IMMessage, recipient: ChatSender):
:param message: 要发送的消息对象。
:param recipient: 接收消息的目标对象。
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider refactoring the complex loop in send_message into helper functions and merging duplicated logic in patched_post_file to improve readability and reduce nested conditionals and duplicated logic..

Consider refactoring the intricate loop in send_message into small helper functions to improve readability and remove some of the nested conditionals. For example, extract the routine that flushes the current text buffer and the one that sends media elements:

async def flush_text_buffer(post_message_func, text_buffer: str, msg_seq: int) -> (str, int):
    if text_buffer:
        await post_message_func(content=text_buffer, msg_seq=msg_seq)
        msg_seq += 1
    return "", msg_seq

async def send_media_element(upload_func, post_message_func, element, msg_seq: int):
    if isinstance(element, ImageMessage):
        file_type = 1
    elif isinstance(element, VoiceMessage):
        file_type = 3
    elif isinstance(element, VideoElement):
        file_type = 2
    media = await upload_func(file_type=file_type, file_data=await element.get_data())
    await post_message_func(media=media, msg_seq=msg_seq, msg_type=7)
    return msg_seq + 1

Then simplify your main loop in send_message by invoking these helpers:

# ...
current_text = ""
msg_seq = 0

for element in message.message_elements:
    if isinstance(element, TextMessage):
        current_text += element.text
        current_text, msg_seq = await flush_text_buffer(post_message_func, current_text, msg_seq)
    elif isinstance(element, MentionElement):
        current_text += f'<qqbot-at-user id="{element.target.user_id}" />'
    elif isinstance(element, (ImageMessage, VoiceMessage, VideoElement)):
        # Flush any accumulated text before handling media.
        current_text, msg_seq = await flush_text_buffer(post_message_func, current_text, msg_seq)
        msg_seq = await send_media_element(upload_func, post_message_func, element, msg_seq)

# Final flush if text remains
if current_text:
    await post_message_func(content=current_text)

Additionally, consider merging any duplicated logic in patched_post_file into the API if possible. These changes keep all functionality intact while reducing the internal complexity of your control flow.

@@ -35,7 +39,8 @@ class QQBotConfig(BaseModel):
app_secret: str = Field(title="App Secret", description="机器人的 App Secret。")
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 issue (security): Flagging hardcoded app secret.

The app_secret field in the QQBotConfig model should not be hardcoded. It should be read from an environment variable or a secure configuration file.

elif isinstance(element, MentionElement):
# 添加提及标记到当前文本缓冲区
current_text += f'<qqbot-at-user id="{element.target.user_id}" />'
elif isinstance(element, ImageMessage) or isinstance(element, VoiceMessage) or isinstance(element, VideoElement):
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Merge isinstance calls [×2] (merge-isinstance)

Suggested change
elif isinstance(element, ImageMessage) or isinstance(element, VoiceMessage) or isinstance(element, VideoElement):
elif isinstance(element, (ImageMessage, VoiceMessage, VideoElement)):

@lss233 lss233 merged commit 07208e2 into master Mar 9, 2025
7 checks passed
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