mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-10-26 01:54:36 +08:00
chat_channel.py hands an agent-produced video to channels as
Reply(ReplyType.VIDEO, "file://" + path). WechatKfChannel.send dispatches
ReplyType.VIDEO_URL but never ReplyType.VIDEO, so a locally generated video
fell through to the trailing else and was only logged as
[wechat_kf] unsupported reply type: VIDEO
send() is the whole outbound contract for this channel and _send_reply() has
no per-type fallback, so the user received nothing at all -- not even the raw
file:// path the other channels used to leak before they were fixed.
The asymmetry is unique to wechat_kf: every sibling that dispatches VIDEO_URL
also dispatches VIDEO (weixin, wechatcom, wechatmp, wecom_bot, qq), and the
three channels that used to share this gap got the same one-line treatment
(#3289 discord, slack/telegram). _send_video() already exists and the video
branch already reads through _read_media(), which loads a file:// path from
disk and size-caps a genuine http(s) download, so no new plumbing is needed.
Tests: a file:// VIDEO reply is uploaded as "video" and handed to
_send_video(), and requests.get is never called for it; a remote VIDEO_URL
reply keeps its existing download-and-send behaviour.
89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
# encoding:utf-8
|
|
"""wechat_kf must upload a locally generated video instead of dropping it.
|
|
|
|
``ChatChannel`` hands an agent-produced video over as
|
|
``Reply(ReplyType.VIDEO, "file://" + path)``. ``send()`` dispatches
|
|
``VIDEO_URL`` but never ``VIDEO``, so the reply hit the trailing ``else`` and
|
|
was only logged as ``unsupported reply type``: the user received nothing at
|
|
all. Every other channel that dispatches ``VIDEO_URL`` also dispatches
|
|
``VIDEO`` (weixin / wechatcom / wechatmp / wecom_bot / qq), and the three that
|
|
shared this gap were fixed the same way (#3289 discord, slack/telegram).
|
|
|
|
``_read_media`` is the helper the FILE branch already uses: it reads a
|
|
``file://`` path from disk and size-caps a real http(s) download.
|
|
"""
|
|
import io
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
from bridge.reply import Reply, ReplyType
|
|
from channel.wechat_kf.wechat_kf_channel import WechatKfChannel
|
|
|
|
|
|
class _Ctx(dict):
|
|
"""``send()`` reads ``context.kwargs.get("msg")``; nothing else is touched."""
|
|
|
|
def __init__(self, *a, **k):
|
|
super().__init__(*a, **k)
|
|
self.kwargs = {}
|
|
|
|
|
|
def _channel():
|
|
"""Only what ``send()`` needs: ``@singleton`` hides the class behind
|
|
``__wrapped__``, and ``__init__`` would need real WeChat credentials."""
|
|
cls = WechatKfChannel.__wrapped__
|
|
channel = cls.__new__(cls)
|
|
channel.client = MagicMock()
|
|
channel.client.media.upload.return_value = {"media_id": "media-1"}
|
|
return channel
|
|
|
|
|
|
def _ctx():
|
|
return _Ctx({"receiver": "user-1", "external_userid": "ext-1", "open_kfid": "kf-1"})
|
|
|
|
|
|
def test_local_video_reply_is_uploaded_from_disk():
|
|
"""A ``file://`` VIDEO reply is uploaded as a video, then sent."""
|
|
channel = _channel()
|
|
sent = []
|
|
channel._send_video = lambda *a, **k: sent.append(a)
|
|
clip = Path(__file__).with_suffix(".mp4")
|
|
clip.write_bytes(b"fake-mp4-bytes")
|
|
|
|
try:
|
|
# requests.get cannot open a file:// path; it must not be tried.
|
|
with patch(
|
|
"channel.wechat_kf.wechat_kf_channel.requests.get",
|
|
side_effect=AssertionError("requests.get must not run for file://"),
|
|
):
|
|
channel.send(Reply(ReplyType.VIDEO, "file://{}".format(clip)), _ctx())
|
|
finally:
|
|
clip.unlink()
|
|
|
|
media_type, payload = channel.client.media.upload.call_args.args
|
|
assert media_type == "video"
|
|
assert isinstance(payload, io.BytesIO)
|
|
# _send_video(self, external_userid, open_kfid, media_id)
|
|
assert sent == [("ext-1", "kf-1", "media-1")]
|
|
|
|
|
|
def test_video_url_reply_still_downloads_and_sends():
|
|
"""Regression: a remote VIDEO_URL keeps its existing behaviour."""
|
|
channel = _channel()
|
|
sent = []
|
|
channel._send_video = lambda *a, **k: sent.append(a)
|
|
|
|
with patch(
|
|
"channel.wechat_kf.wechat_kf_channel.download_bytes",
|
|
return_value=b"remote-mp4-bytes",
|
|
) as download:
|
|
channel.send(Reply(ReplyType.VIDEO_URL, "https://example.com/clip.mp4"), _ctx())
|
|
|
|
assert download.call_args.args[0] == "https://example.com/clip.mp4"
|
|
assert channel.client.media.upload.call_args.args[0] == "video"
|
|
assert sent == [("ext-1", "kf-1", "media-1")]
|