81 lines
4.3 KiB
Python
81 lines
4.3 KiB
Python
from pathlib import Path
|
|
import shutil
|
|
|
|
helper = ''' def _wait_for_database_voice(self, fp, *, visible_voice=False):
|
|
"""Yield this task while local ASR works; unrelated conversations continue."""
|
|
from voice_messages import voice_batch_status
|
|
state = self._pending_reply_state(fp)
|
|
context = getattr(self, "_last_database_read", None)
|
|
bound = isinstance(context, dict) and context.get("fp_hex") == bytes(fp or b"").hex()
|
|
voice = voice_batch_status(context) if bound else {"status": "none"}
|
|
if visible_voice and voice["status"] == "none":
|
|
voice = {"status": "pending", "key": "visible-voice:" + bytes(fp or b"").hex(),
|
|
"reason": "等待语音对应的本机消息库和音频文件"}
|
|
if voice["status"] in {"none", "ready"}:
|
|
if state:
|
|
state.pop("voice_wait_key", None)
|
|
state.pop("voice_wait_started_at", None)
|
|
return False
|
|
if state is None:
|
|
return True # No durable task identity: never guess or answer an unheard voice.
|
|
now = time.time()
|
|
if state.get("voice_wait_key") != voice.get("key"):
|
|
state.update(voice_wait_key=voice.get("key"), voice_wait_started_at=now)
|
|
waiting = voice["status"] == "pending" and now - float(state.get("voice_wait_started_at") or now) < 180
|
|
if waiting:
|
|
state["ready_at"] = now + 2
|
|
self._set_task_stage(fp, "voice_transcribing", detail=voice.get("reason") or "语音正在本机转文字")
|
|
else:
|
|
reason = voice.get("reason") if voice["status"] == "error" else "语音转文字等待超时,尚未取得可核验文字,请人工处理"
|
|
state.update(manual_required=True, manual_reason=reason, awaiting_review=False,
|
|
reply_text="", staged_reply_text="", chat_text=str((context or {}).get("text") or ""))
|
|
self._set_task_stage(fp, "error", detail="语音需要人工核对", error=reason)
|
|
self._register_assistant_review(fp)
|
|
self._persist_pending_replies()
|
|
return True
|
|
|
|
'''
|
|
|
|
for label, project in [('source', Path('C:/kefu/wechat_rpa')), ('production', Path('C:/wechat_rpa'))]:
|
|
path = project / 'wechat_bot.py'
|
|
backup = Path(__file__).parent / 'before-voice-integration' / label
|
|
backup.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy2(path, backup / path.name)
|
|
text = path.read_text(encoding='utf-8')
|
|
needle = ' def _database_message_direction(self, fp: bytes, text: str):\n'
|
|
assert text.count(needle) == 1
|
|
text = text.replace(needle, helper + needle)
|
|
needle = ''' database_text = self._database_chat_text(fp)
|
|
if database_text:
|
|
chat_text = database_text
|
|
'''
|
|
assert text.count(needle) == 1
|
|
text = text.replace(needle, needle + ''' if self._wait_for_database_voice(fp):
|
|
return None
|
|
from voice_messages import voice_batch_status
|
|
database_voice_ready = bool(database_text and voice_batch_status(getattr(self, "_last_database_read", None))["status"] == "ready")
|
|
''')
|
|
needle = ''' first_untrusted_batch = bool(
|
|
first_record_batch and not first_explicit_customer_text
|
|
)
|
|
'''
|
|
assert text.count(needle) == 1
|
|
text = text.replace(needle, ''' first_untrusted_batch = bool(
|
|
first_record_batch and not first_explicit_customer_text and not database_voice_ready
|
|
)
|
|
if database_voice_ready:
|
|
# Exact database identity and successful ASR make voice text available to normal model/risk processing.
|
|
reliable_text_pending = True
|
|
force_media_check = False
|
|
''')
|
|
needle = ''' self.report_operation("AI 准备", 2, 3, "语音没有转写,生成安全追问", fp)
|
|
print(" [AI] 检测到未转写语音,使用不猜测内容的安全回复")
|
|
ai_reply = safe_media_reply(media_types)
|
|
'''
|
|
assert text.count(needle) == 1
|
|
text = text.replace(needle, ''' self._wait_for_database_voice(fp, visible_voice=True)
|
|
return None
|
|
''')
|
|
path.write_text(text, encoding='utf-8')
|
|
print('Visual voice waiting/model flow integrated with targeted edits in both variants.')
|