from pathlib import Path import ast,json,hashlib,shutil root=Path('C:/wechat_rpa');folder=Path(__file__).resolve().parent;payload=folder/'payload' payload.mkdir(exist_ok=True) names=['wechat_gui_qt.py','assets/ui/console-app.js','assets/ui/zhenyang-ai-console.html','assets/ui/console-responsive.css'] manifest=[] for name in names: p=payload/name;p.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(root/name,p) manifest.append({'path':name,'before_sha256':hashlib.sha256((root/name).read_bytes()).hexdigest()}) (folder/'before.json').write_text(json.dumps(manifest,indent=2),encoding='utf-8') p=payload/'wechat_gui_qt.py';s=p.read_text(encoding='utf-8') # Snapshot only the visible page; off-page state remains cached by the web shell. start=s.index(' people = self._console_sort_people(self._console_people())',s.index(' def _console_snapshot(')) end=s.index(' return snapshot',start) replacement=''' view = snapshot["view"] system = dict(getattr(self, "_console_system_cache", {}) or {}) system.update(scale=self.runtime_settings.get("scale_ratio") or "自动", tray=bool(self.runtime_settings.get("minimize_on_close", True))) snapshot["system"] = system people = [] if view in {"auto", "queue", "logs"}: people = self._console_sort_people(self._console_people()) if people and not snapshot["selectedKey"]: snapshot["selectedKey"] = people[0]["key"] for item in people: item["active"] = item.get("key") == snapshot["selectedKey"] snapshot["people"] = people if view in {"auto", "queue", "archive", "logs"}: logs = self._console_logs() snapshot.update(logs=logs, activities=self._console_activities(logs)) snapshot["metrics"] = self._console_metrics(people, logs) if view in {"auto", "queue"}: journey = self._console_journey(people) snapshot.update(task=self._console_task(people), journey=journey, journeyTotal=self._console_journey_total(journey), chain=self._console_chain(people), windowStats=self._console_window_stats(wecom, people)) if view == "archive": archives = self._console_archives() if archives and not snapshot["selectedArchive"]: snapshot["selectedArchive"] = archives[0]["key"] snapshot.update(archives=archives, chat=self._console_chat(), memory=self._console_memory(), settle=self._console_settle()) elif view == "ai": snapshot["ai"] = self._console_ai_state() elif view == "automation": snapshot["automation"] = self._console_automation_state(wecom) elif view == "wechatdb": snapshot["wechatDb"] = self._wechat_database_console_state() elif view == "system": snapshot["system"] = self._console_system_state() self._console_system_cache = snapshot["system"] elif view == "logs": snapshot.update(logDetail=self._console_log_detail(logs), chain=self._console_chain(people), exceptions={"sendFail":int(getattr(self.log_page,"_send_fail_count",0) or 0), "timeout":int(getattr(self.log_page,"_timeout_count",0) or 0), "windowLost":int(getattr(self.log_page,"_window_lost_count",0) or 0)}) ''' s=s[:start]+replacement+s[end:] s=s.replace(' self.stack.setCurrentIndexAnimated(index)', ''' if getattr(self, "console_shell", None) is None: self.stack.setCurrentIndexAnimated(index) else: self.stack.setCurrentIndex(index)''') # An explicit save consumes the pending native debounce, not a second disk write. point=''' def _emit_save(self) -> None: # 手动点''' assert point in s;s=s.replace(point,''' def _emit_save(self) -> None: self.save_timer.stop() # 手动点''',1) old=''' self.host.persona_page.rounds.setValue(int(float(data["context"]))) self.host.persona_page.save_config()''' new=''' rounds = int(float(data["context"])) if rounds != self.host.persona_page.rounds.value(): self.host.persona_page.rounds.setValue(rounds) self.host.persona_page.save_config()''' assert old in s;s=s.replace(old,new) # Drain a bounded amount each tick, allowing input and painting between bursts. point=''' def _process_queue(self) -> None: try: while True:''' new=''' def _process_queue(self) -> None: deadline = time.perf_counter() + 0.008 processed = 0 try: while processed < 64 and time.perf_counter() < deadline: processed += 1''' assert point in s;s=s.replace(point,new) point=''' if self._start_time and self._running: elapsed =''' new=''' timer = getattr(self, "queue_timer", None) if timer is not None: timer.setInterval(16 if not self._queue.empty() else 140) if self._start_time and self._running: elapsed =''' assert s.count(point)==1;s=s.replace(point,new) ast.parse(s);p.write_text(s,encoding='utf-8',newline='\n') print('Prepared visible-page snapshots and bounded UI work')