mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-20 13:47:15 +08:00
feat(voice): enable TTS on Weixin / DingTalk / WeCom Bot with text-then-voice delivery
- Clear NOT_SUPPORT_REPLYTYPE on weixin, wecom_bot, dingtalk so TTS replies are actually synthesized for these channels. - Wire desire_rtype=VOICE in weixin and wecom_bot _compose_context so the always_reply_voice / voice_reply_voice toggles take effect. - DingTalk: send native sampleAudio (mediaId + duration). The media API only accepts ogg/amr, so convert TTS mp3/wav to amr on the fly. - WeCom Bot: send native voice msgtype via ws (respond + active push), converting TTS audio to amr before upload. - Weixin (ilink): no outbound voice item, deliver TTS as a file attachment. - chat_channel: when a TEXT reply is converted to VOICE, stash original text in context["voice_reply_text"] and send a text bubble before the voice reply. Skipped for feishu_streamed and wechatcom_app, which already render text alongside the voice.
This commit is contained in:
@@ -60,6 +60,9 @@ def _save_credentials(cred_path: str, data: dict):
|
||||
@singleton
|
||||
class WeixinChannel(ChatChannel):
|
||||
|
||||
# ilink bot protocol has no outbound voice item; deliver TTS as a file.
|
||||
NOT_SUPPORT_REPLYTYPE = []
|
||||
|
||||
LOGIN_STATUS_IDLE = "idle"
|
||||
LOGIN_STATUS_WAITING = "waiting_scan"
|
||||
LOGIN_STATUS_SCANNED = "scanned"
|
||||
@@ -464,6 +467,14 @@ class WeixinChannel(ChatChannel):
|
||||
else:
|
||||
context.type = ContextType.TEXT
|
||||
context.content = content.strip()
|
||||
if "desire_rtype" not in context and conf().get("always_reply_voice"):
|
||||
context["desire_rtype"] = ReplyType.VOICE
|
||||
|
||||
elif ctype == ContextType.VOICE:
|
||||
if "desire_rtype" not in context and (
|
||||
conf().get("voice_reply_voice") or conf().get("always_reply_voice")
|
||||
):
|
||||
context["desire_rtype"] = ReplyType.VOICE
|
||||
|
||||
return context
|
||||
|
||||
@@ -486,6 +497,9 @@ class WeixinChannel(ChatChannel):
|
||||
self._send_file(reply.content, receiver, context_token)
|
||||
elif reply.type in (ReplyType.VIDEO, ReplyType.VIDEO_URL):
|
||||
self._send_video(reply.content, receiver, context_token)
|
||||
elif reply.type == ReplyType.VOICE:
|
||||
# ilink has no outbound voice item; deliver TTS as a file attachment.
|
||||
self._send_file(reply.content, receiver, context_token)
|
||||
else:
|
||||
logger.warning(f"[Weixin] Unsupported reply type: {reply.type}, fallback to text")
|
||||
self._send_text(str(reply.content), receiver, context_token)
|
||||
|
||||
Reference in New Issue
Block a user