"""Synthetic queue snapshots for voice progress and human-completed work.""" import json from pathlib import Path import tempfile import time from unittest import TestCase, mock from PySide6.QtWidgets import QApplication import wechat_gui_qt as qt import test_desktop_review_visibility as helpers from review_state import pending_attention_counts class ReviewVoiceUiTests(TestCase): @classmethod def setUpClass(cls): cls.app=QApplication.instance() or QApplication([]) def setUp(self): self.log_temp=tempfile.TemporaryDirectory() self.addCleanup(self.log_temp.cleanup) self.enterContext(mock.patch('queue_log.application_data_dir',return_value=Path(self.log_temp.name))) helpers.DesktopReviewTest.setUp(self) def seed_voice(self, **extra): state={'created_at':time.time(),'stage_started_at':time.time(),'display_name':'合成语音客户', 'stage':'voice_transcribing','detected_by':'protocol_db','confirmed_unread':True, 'staged_user_text':'[合成语音]','manual_required':False,'awaiting_review':False} state.update(extra) self.path.write_text(json.dumps({'pending':{'voice':state}}),encoding='utf-8') self.page.refresh_data() return state def test_voice_processing_filter_and_snapshot_do_not_claim_ai_generation_or_human_work(self): state=self.seed_voice() self.page._set_task_filter('处理中') people=self.host._console_people() self.assertEqual([person['key'] for person in people],['voice']) task=self.host._console_task(people) self.assertEqual(task['action'],'语音转文字') self.assertEqual(task['confidence'],'转文字中') self.assertEqual(task['steps'][1],['语音转文字','进行中']) self.assertFalse(task['needsHuman']);self.assertFalse(task['awaitingReview']);self.assertFalse(task['canApprove']) self.assertEqual(pending_attention_counts({'voice':state}),{'review':0,'human':0,'total':0}) metrics=self.host._console_metrics(people,[]) self.assertEqual(metrics['human'],'0');self.assertEqual(metrics['review'],'0') self.assertEqual(self.page.band_processing.text(),'1') self.assertEqual(self.page.detail_action.text(),'语音转文字') def test_failed_voice_moves_to_manual_filter_and_cannot_approve_empty_reply(self): self.seed_voice(stage='error',manual_required=True,manual_reason='合成语音无法转文字') self.page._set_task_filter('需人工') people=self.host._console_people();task=self.host._console_task(people) self.assertEqual([person['key'] for person in people],['voice']) self.assertTrue(task['needsHuman']);self.assertFalse(task['canApprove']) self.assertEqual(self.host._console_metrics(people,[])['human'],'1') def test_human_completed_event_does_not_increment_ai_sent_count(self): from queue_log import QueueLog self.seed_voice(stage='error',manual_required=True,manual_reason='合成需人工') QueueLog().append('voice','合成客户','人工已完成','已核验同账号人工回复') self.path.write_text(json.dumps({'pending':{}}),encoding='utf-8') self.page.refresh_data() self.assertEqual(self.host._console_people(),[]) metrics=self.host._console_metrics([],[]) self.assertEqual(metrics['human'],'0');self.assertEqual(metrics['review'],'0') self.assertEqual(self.page.sent_metric.value.text(),'0') action=self.page.history_table.item(0,2) self.assertEqual(action.text(),'人工已完成') self.assertEqual(action.foreground().color().name(),qt.COLORS['success'].lower()) def test_human_completion_log_is_successful_recognition_not_automatic_send(self): for marker in ('[协议人工已完成]','[人工已完成]','[协议已审核]','[已审核]'): with self.subTest(marker=marker): title,status,tone,category=qt.LogPage._classify_log(marker+' 合成客户 · 已人工回复,本轮旧AI草稿已丢弃','info') self.assertEqual((title,status,tone,category),('人工已完成','完成','success','识别')) def test_voice_progress_and_failure_logs_keep_distinct_tones(self): self.assertEqual(qt.LogPage._classify_log('[协议处理] 合成客户 · 语音转文字','info'), ('语音转文字','进行中','blue','识别')) self.assertEqual(qt.LogPage._classify_log('语音转文字失败,需人工处理','err')[2],'warning')