From 075360f9f4bb874fc9a1c769f95ad853f9d17fe2 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Wed, 2 Sep 2026 10:25:40 +0800 Subject: [PATCH 1/6] feat: harness + CV funnel (from feature/esp32-ocr) --- extensions/assistive_harness/.gitignore | 4 + .../OPENGLASS_MIGRATION_MAP.md | 25 + extensions/assistive_harness/README.md | 60 + extensions/assistive_harness/__init__.py | 14 + extensions/assistive_harness/asr/__init__.py | 6 + extensions/assistive_harness/asr/base.py | 30 + .../assistive_harness/asr/energy_vad.py | 92 + .../assistive_harness/asr/funasr_engine.py | 84 + .../config/skills.example.yaml | 128 + extensions/assistive_harness/cv/README.md | 171 ++ extensions/assistive_harness/cv/__init__.py | 14 + extensions/assistive_harness/cv/base.py | 44 + extensions/assistive_harness/cv/noop.py | 60 + extensions/assistive_harness/cv/pipeline.py | 159 ++ extensions/assistive_harness/cv/registry.py | 89 + .../assistive_harness/cv/requirements-cv.txt | 2 + extensions/assistive_harness/cv/yolo_onnx.py | 220 ++ extensions/assistive_harness/echo_guard.py | 75 + extensions/assistive_harness/model_log.py | 72 + .../assistive_harness/package_phase_a.ps1 | 69 + .../assistive_harness/phase_b/README.md | 114 + .../assistive_harness/phase_b/__init__.py | 5 + .../assistive_harness/phase_b/bridge_ui.py | 337 +++ .../phase_b/cam_pipeline_v2.py | 2283 +++++++++++++++++ .../phase_b/esp32_runtime.py | 1851 +++++++++++++ .../assistive_harness/phase_b/funnel_gate.py | 218 ++ .../phase_b/realtime_session.py | 306 +++ .../phase_b/recorder_live.py | 860 +++++++ .../phase_b/requirements-phase-b.txt | 4 + .../assistive_harness/phase_b/rerun_source.py | 368 +++ .../phase_b/rokid_runtime.py | 1703 ++++++++++++ .../phase_b/session_recorder.py | 90 + .../phase_b/templates/live.html | 620 +++++ .../phase_b/templates/replay.html | 566 ++++ .../phase_b/templates/replay_index.html | 321 +++ .../assistive_harness/phase_b/timing_probe.py | 163 ++ .../assistive_harness/prompts/README.md | 43 + .../prompts/describe_scene_zh.txt | 8 + .../prompts/find_object_zh.txt | 9 + .../prompts/idle_chat_zh.txt | 8 + .../prompts/obstacle_avoidance_zh.txt | 9 + .../prompts/read_text_zh.txt | 7 + extensions/assistive_harness/registry.py | 117 + extensions/assistive_harness/router.py | 262 ++ extensions/assistive_harness/schemas.py | 67 + extensions/assistive_harness/server.py | 604 +++++ extensions/assistive_harness/state_machine.py | 115 + .../assistive_harness/summarize_reset_run.py | 97 + extensions/assistive_harness/telemetry.py | 67 + .../assistive_harness/tests/__init__.py | 0 .../assistive_harness/tests/test_core.py | 402 +++ .../assistive_harness/tests/test_cv_yolo.py | 41 + .../tests/test_phase_b_rokid.py | 352 +++ 53 files changed, 13435 insertions(+) create mode 100644 extensions/assistive_harness/.gitignore create mode 100644 extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md create mode 100644 extensions/assistive_harness/README.md create mode 100644 extensions/assistive_harness/__init__.py create mode 100644 extensions/assistive_harness/asr/__init__.py create mode 100644 extensions/assistive_harness/asr/base.py create mode 100644 extensions/assistive_harness/asr/energy_vad.py create mode 100644 extensions/assistive_harness/asr/funasr_engine.py create mode 100644 extensions/assistive_harness/config/skills.example.yaml create mode 100644 extensions/assistive_harness/cv/README.md create mode 100644 extensions/assistive_harness/cv/__init__.py create mode 100644 extensions/assistive_harness/cv/base.py create mode 100644 extensions/assistive_harness/cv/noop.py create mode 100644 extensions/assistive_harness/cv/pipeline.py create mode 100644 extensions/assistive_harness/cv/registry.py create mode 100644 extensions/assistive_harness/cv/requirements-cv.txt create mode 100644 extensions/assistive_harness/cv/yolo_onnx.py create mode 100644 extensions/assistive_harness/echo_guard.py create mode 100644 extensions/assistive_harness/model_log.py create mode 100644 extensions/assistive_harness/package_phase_a.ps1 create mode 100644 extensions/assistive_harness/phase_b/README.md create mode 100644 extensions/assistive_harness/phase_b/__init__.py create mode 100644 extensions/assistive_harness/phase_b/bridge_ui.py create mode 100644 extensions/assistive_harness/phase_b/cam_pipeline_v2.py create mode 100644 extensions/assistive_harness/phase_b/esp32_runtime.py create mode 100644 extensions/assistive_harness/phase_b/funnel_gate.py create mode 100644 extensions/assistive_harness/phase_b/realtime_session.py create mode 100644 extensions/assistive_harness/phase_b/recorder_live.py create mode 100644 extensions/assistive_harness/phase_b/requirements-phase-b.txt create mode 100644 extensions/assistive_harness/phase_b/rerun_source.py create mode 100644 extensions/assistive_harness/phase_b/rokid_runtime.py create mode 100644 extensions/assistive_harness/phase_b/session_recorder.py create mode 100644 extensions/assistive_harness/phase_b/templates/live.html create mode 100644 extensions/assistive_harness/phase_b/templates/replay.html create mode 100644 extensions/assistive_harness/phase_b/templates/replay_index.html create mode 100644 extensions/assistive_harness/phase_b/timing_probe.py create mode 100644 extensions/assistive_harness/prompts/README.md create mode 100644 extensions/assistive_harness/prompts/describe_scene_zh.txt create mode 100644 extensions/assistive_harness/prompts/find_object_zh.txt create mode 100644 extensions/assistive_harness/prompts/idle_chat_zh.txt create mode 100644 extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt create mode 100644 extensions/assistive_harness/prompts/read_text_zh.txt create mode 100644 extensions/assistive_harness/registry.py create mode 100644 extensions/assistive_harness/router.py create mode 100644 extensions/assistive_harness/schemas.py create mode 100644 extensions/assistive_harness/server.py create mode 100644 extensions/assistive_harness/state_machine.py create mode 100644 extensions/assistive_harness/summarize_reset_run.py create mode 100644 extensions/assistive_harness/telemetry.py create mode 100644 extensions/assistive_harness/tests/__init__.py create mode 100644 extensions/assistive_harness/tests/test_core.py create mode 100644 extensions/assistive_harness/tests/test_cv_yolo.py create mode 100644 extensions/assistive_harness/tests/test_phase_b_rokid.py diff --git a/extensions/assistive_harness/.gitignore b/extensions/assistive_harness/.gitignore new file mode 100644 index 0000000..e607f1c --- /dev/null +++ b/extensions/assistive_harness/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.pyc +runs/ +test_artifacts/ diff --git a/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md b/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md new file mode 100644 index 0000000..1110736 --- /dev/null +++ b/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md @@ -0,0 +1,25 @@ +# OpenGlass Migration Map + +Phase A deliberately separates portable policy from browser-specific transport. + +| Phase A component | OpenGlass-side destination | +|---|---| +| `schemas.py` | shared structured control-event schema | +| `router.py` | local deterministic voice-command router | +| `registry.py` + prompts | configurable Skill registry/prompt bundle | +| `echo_guard.py` | output/playback-aware ASR echo filter | +| `state_machine.py` | device-independent control priority and dedupe | +| `asr/` | phone/host local ASR service behind the same interface | +| `cv/base.py` | future advisory perception provider interface | +| `server.py` WS messages | replaceable host/phone transport adapter | +| `browser-session-adapter.js` | reference semantics for an OpenGlass session adapter | + +OpenGlass migration should keep `ControlEvent`, `SkillRegistry`, prompt SHA, +generation fence and STOP priority stable. Replace only AudioMirror capture, +session lifecycle calls, and the control transport. No dependency on ESP32, Rokid, +DOM layout or the MiniCPM private wire format exists in the Python core. + +The first Rokid implementation of this boundary now lives in +[`phase_b/`](phase_b/README.md). It consumes the existing APK JPEG/PCM endpoints, +reuses this Core and the existing Gateway, and implements the browser adapter's +STOP/RESUME/RESET/Skill generation contract in Python. diff --git a/extensions/assistive_harness/README.md b/extensions/assistive_harness/README.md new file mode 100644 index 0000000..8be88a5 --- /dev/null +++ b/extensions/assistive_harness/README.md @@ -0,0 +1,60 @@ +# Assistive Voice Skill Harness (Phase A) + +This directory is an optional, local sidecar for the MiniCPM-o browser Demo. It is +disabled by default and does not replace the native microphone/video path. + +Start the sidecar explicitly: + +```powershell +python -m extensions.assistive_harness.server --enabled ` + --model-path "C:\path\to\a\local\FunASR\model" +``` + +Then opt the browser tab in with `?assistive_harness=1`. Test-only transcript +injection additionally requires `--allow-test-injection`; it is never enabled by +the normal command above. + +The browser hook is deliberately thin. Control, ASR, prompt registry, echo guard, +state machine, metrics, and CV shadow interfaces live under this directory so the +module can later be moved behind another transport (for example OpenGlass). + +The first Rokid/OpenGlass transport is implemented in +[`phase_b/`](phase_b/README.md). It preserves this Core and the existing 8040 +Gateway while replacing browser microphone, camera, playback, and Session calls +with a Python device adapter. + +## User-editable Skills + +System prompts live in `extensions/assistive_harness/prompts/`. Existing prompt +files are read on every activation, so users can replace a prompt and activate +the Skill again without restarting the sidecar. Skill IDs, enable flags and +voice phrases are configured in `config/skills.example.yaml`; changing that YAML +does require restarting the sidecar. + +Enabled by default: + +- `帮我找<物体>` -> `find_object` -> hot Session restart with `{{target}}` +- `读一下` / `帮我识字` -> `read_text` -> hot Session restart +- `描述一下` / `看看周围` -> `describe_scene` -> hot Session restart +- `帮我避障` / `前面有障碍吗` -> `obstacle_avoidance` -> hot Session restart +- `回到聊天` / `恢复普通聊天` -> `idle_chat` -> hot Session restart + +`obstacle_avoidance` contains the frozen AAAI_SI prompt and is enabled only for +stationary, supervised validation. Its mobility safety has not been accepted; +never treat this Demo as a navigation or safety device. + +With the sidecar running, `GET http://127.0.0.1:8021/skills` reports the active +configuration and absolute prompt path for every registered Skill. + +## CV V1 shadow pipeline + +Browser JPEG mirrors enter a capacity-one latest-frame queue and are analyzed +on a dedicated single-thread worker. `cv_mode: disabled` drops frames before +inference; `cv_mode: shadow` writes `CVObservation` records without changing a +Skill or taking ownership of MiniCPM output. Slow, timed-out, or failed plugins +remain outside the audio/control receive path. + +`find_object` uses the local `yolo_onnx` reference provider. Other Skills keep +the `noop` provider until a task-specific plugin is registered. Provider setup, +the observation schema, and an OCR implementation template are documented in +[`cv/README.md`](cv/README.md). diff --git a/extensions/assistive_harness/__init__.py b/extensions/assistive_harness/__init__.py new file mode 100644 index 0000000..339e7b9 --- /dev/null +++ b/extensions/assistive_harness/__init__.py @@ -0,0 +1,14 @@ +"""Portable voice-controlled Skill Harness core for Phase A.""" + +from .router import RuleIntentRouter +from .registry import SkillRegistry +from .schemas import ASREvent, ControlEvent, ControlIntent + +__all__ = [ + "ASREvent", + "ControlEvent", + "ControlIntent", + "RuleIntentRouter", + "SkillRegistry", +] + diff --git a/extensions/assistive_harness/asr/__init__.py b/extensions/assistive_harness/asr/__init__.py new file mode 100644 index 0000000..6d88083 --- /dev/null +++ b/extensions/assistive_harness/asr/__init__.py @@ -0,0 +1,6 @@ +from .base import ASREngine, ASRResult +from .energy_vad import EnergyVAD, UtteranceAudio +from .funasr_engine import FunASREngine + +__all__ = ["ASREngine", "ASRResult", "EnergyVAD", "FunASREngine", "UtteranceAudio"] + diff --git a/extensions/assistive_harness/asr/base.py b/extensions/assistive_harness/asr/base.py new file mode 100644 index 0000000..a6fc73d --- /dev/null +++ b/extensions/assistive_harness/asr/base.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Protocol + +import numpy as np + + +@dataclass(frozen=True, slots=True) +class ASRResult: + text: str + confidence: float + model: str + device: str + + +class ASREngine(Protocol): + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + ... + + +class ScriptedASREngine: + def __init__(self, transcripts: list[str]): + self.transcripts = list(transcripts) + + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + del audio, sample_rate + text = self.transcripts.pop(0) if self.transcripts else "" + return ASRResult(text=text, confidence=1.0, model="scripted", device="cpu") + diff --git a/extensions/assistive_harness/asr/energy_vad.py b/extensions/assistive_harness/asr/energy_vad.py new file mode 100644 index 0000000..58cec2e --- /dev/null +++ b/extensions/assistive_harness/asr/energy_vad.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections import deque +from dataclasses import dataclass + +import numpy as np + + +@dataclass(frozen=True, slots=True) +class UtteranceAudio: + audio: np.ndarray + started_at_ms: float + ended_at_ms: float + + +class EnergyVAD: + """Small streaming endpoint detector; it does not perform recognition.""" + + def __init__( + self, + sample_rate: int = 16_000, + rms_threshold: float = 0.012, + min_speech_ms: int = 180, + end_silence_ms: int = 450, + max_utterance_ms: int = 8_000, + preroll_ms: int = 200, + ): + self.sample_rate = sample_rate + self.rms_threshold = rms_threshold + self.min_speech_ms = min_speech_ms + self.end_silence_ms = end_silence_ms + self.max_utterance_ms = max_utterance_ms + self.preroll_ms = preroll_ms + self._preroll: deque[tuple[np.ndarray, float]] = deque() + self._active: list[np.ndarray] = [] + self._started_at_ms: float | None = None + self._last_voice_ms: float | None = None + + def _duration_ms(self, audio: np.ndarray) -> float: + return float(audio.size) * 1000.0 / self.sample_rate + + def feed(self, audio: np.ndarray, frame_started_at_ms: float) -> UtteranceAudio | None: + frame = np.asarray(audio, dtype=np.float32).reshape(-1).copy() + if frame.size == 0: + return None + duration_ms = self._duration_ms(frame) + frame_end_ms = frame_started_at_ms + duration_ms + rms = float(np.sqrt(np.mean(np.square(frame, dtype=np.float64)))) + voiced = rms >= self.rms_threshold + + if self._started_at_ms is None: + self._preroll.append((frame, frame_started_at_ms)) + while self._preroll and frame_end_ms - self._preroll[0][1] > self.preroll_ms: + self._preroll.popleft() + if not voiced: + return None + self._started_at_ms = self._preroll[0][1] if self._preroll else frame_started_at_ms + self._active = [item[0] for item in self._preroll] + self._preroll.clear() + self._last_voice_ms = frame_end_ms + else: + self._active.append(frame) + if voiced: + self._last_voice_ms = frame_end_ms + + active_ms = frame_end_ms - float(self._started_at_ms) + silence_ms = frame_end_ms - float(self._last_voice_ms or frame_end_ms) + if active_ms >= self.max_utterance_ms or silence_ms >= self.end_silence_ms: + return self._finish(frame_end_ms) + return None + + def _finish(self, ended_at_ms: float) -> UtteranceAudio | None: + if self._started_at_ms is None or not self._active: + self.reset() + return None + audio = np.concatenate(self._active).astype(np.float32, copy=False) + started = self._started_at_ms + voiced_duration = max(0.0, float(self._last_voice_ms or ended_at_ms) - started) + self.reset() + if voiced_duration < self.min_speech_ms: + return None + return UtteranceAudio(audio=audio, started_at_ms=started, ended_at_ms=ended_at_ms) + + def flush(self, ended_at_ms: float) -> UtteranceAudio | None: + return self._finish(ended_at_ms) + + def reset(self) -> None: + self._preroll.clear() + self._active = [] + self._started_at_ms = None + self._last_voice_ms = None + diff --git a/extensions/assistive_harness/asr/funasr_engine.py b/extensions/assistive_harness/asr/funasr_engine.py new file mode 100644 index 0000000..c7a126d --- /dev/null +++ b/extensions/assistive_harness/asr/funasr_engine.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import threading +from pathlib import Path +from typing import Any + +import numpy as np + +from .base import ASRResult + + +class FunASREngine: + """Lazy local FunASR adapter. It never downloads a model implicitly.""" + + def __init__(self, model_path: str, device: str = "cpu", model_kwargs: dict[str, Any] | None = None): + path = Path(model_path).expanduser().resolve() + if not path.is_dir(): + raise FileNotFoundError(f"FunASR model path does not exist: {path}") + self.model_path = str(path) + self.device = device + self.model_kwargs = dict(model_kwargs or {}) + self._model: Any = None + self._load_lock = threading.Lock() + self._infer_lock = threading.Lock() + + @property + def loaded(self) -> bool: + return self._model is not None + + def ensure_loaded(self) -> None: + if self._model is not None: + return + with self._load_lock: + if self._model is not None: + return + from funasr import AutoModel + + self._model = AutoModel( + model=self.model_path, + device=self.device, + disable_update=True, + **self.model_kwargs, + ) + + def warm_up(self) -> None: + """Load the model and run one short silent inference before serving clients.""" + self.ensure_loaded() + silence = np.zeros(8_000, dtype=np.float32) + with self._infer_lock: + self._model.generate( + input=silence, + cache={}, + is_final=True, + batch_size_s=0, + ) + + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + if sample_rate != 16_000: + raise ValueError(f"FunASR Phase A requires 16 kHz audio, got {sample_rate}") + self.ensure_loaded() + waveform = np.asarray(audio, dtype=np.float32).reshape(-1) + with self._infer_lock: + results = self._model.generate( + input=waveform, + cache={}, + is_final=True, + batch_size_s=0, + ) + text = "" + confidence = 1.0 + if isinstance(results, list) and results: + first = results[0] + if isinstance(first, dict): + text = str(first.get("text") or "").strip() + if isinstance(first.get("confidence"), (int, float)): + confidence = float(first["confidence"]) + else: + text = str(first).strip() + return ASRResult( + text=text, + confidence=confidence, + model=self.model_path, + device=self.device, + ) diff --git a/extensions/assistive_harness/config/skills.example.yaml b/extensions/assistive_harness/config/skills.example.yaml new file mode 100644 index 0000000..4e589ff --- /dev/null +++ b/extensions/assistive_harness/config/skills.example.yaml @@ -0,0 +1,128 @@ +version: 2 +default_skill: idle_chat + +harness: + enabled: false + host: 127.0.0.1 + port: 8021 + allow_test_injection: false + +asr: + engine: funasr + model_path: "" + device: cpu + rms_threshold: 0.012 + min_speech_ms: 180 + end_silence_ms: 450 + max_utterance_ms: 8000 + preroll_ms: 200 + +echo_guard: + window_ms: 20000 + similarity_threshold: 0.86 + +cv: + mode: shadow + max_fps: 1 + queue_size: 1 + inference_timeout_ms: 2000 + providers: + noop: + type: noop + yolo_onnx: + type: yolo_onnx + # Resolved relative to this YAML. Keep weights outside the Core so the + # same plugin can be reused by the later OpenGlass Adapter. + model_path: ../../../../OmniHarness/mini_omni_harness/models/yolo26n.onnx + device: cpu + confidence: 0.25 + image_size: 640 + +control: + cooldown_ms: 1200 + stop_speech: + # `同一下` / `等一(一)下` are bounded aliases observed from the local + # FunASR model when the user clearly says the short command `停一下`. + # They are command-only aliases, not arbitrary substring anchors. + phrases: [停一下, 同一下, 等一下, 等一一下, 别说了, 闭嘴, 停止播报, 安静] + # Literal substring protocol: any transcript containing this anchor stops. + embedded_phrases: [停一下] + resume_speech: + # Literal substring protocol: any transcript containing this anchor resumes. + embedded_phrases: [恢复对话] + reset_session: + phrases: [重新开始] + # Literal substring protocol for real voice RESET. Product deployments can + # later prepend a wake name (for example "乐奇重新开始") without changing + # the deterministic router. + embedded_phrases: [重新开始] + return_to_chat: + phrases: [回到聊天, 回到普通聊天, 退出技能, 普通聊天, 恢复普通聊天] + cancel_skill: + phrases: [取消任务, 不找了, 不读了] + +skills: + idle_chat: + enabled: true + prompt_file: ../prompts/idle_chat_zh.txt + requires_session_restart: true + cooldown_ms: 1200 + cv_mode: disabled + cv_provider: noop + activation_phrases: [普通聊天, 回到聊天] + + find_object: + enabled: true + description: 使用第一视角画面寻找语音中指定的物体 + prompt_source: AAAI_SI/C1_OBJECT_FINDING + prompt_file: ../prompts/find_object_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: yolo_onnx + task_trigger: '请立即根据当前画面寻找“{{target}}”,只回答它的位置;如果没看到就说没看到。' + slot_schema: + target: {type: string, required: true} + activation_patterns: + - "帮我找(?:一下)?(?:我的)?(?P.+)" + - "帮我找(?P.+)" + - "(?P.+)在哪" + - "(?P.+)在哪里" + - "看到(?P.+)了吗" + - "有没有(?P.+)" + + read_text: + enabled: true + description: 读取当前画面中清晰可见的文字 + prompt_source: AAAI_SI/C1_TEXT_READING + prompt_file: ../prompts/read_text_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即读取当前画面中最明显的文字,只读看到的内容。 + activation_phrases: [读一下, 念一下, 帮我读一下, 帮我识字, 帮我读字, 上面写了什么, 这是什么字, 读文字] + + describe_scene: + enabled: true + prompt_file: ../prompts/describe_scene_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即用一两句话简短描述当前画面。 + activation_phrases: [描述一下, 帮我描述一下, 帮我描述场景, 前面有什么, 看看周围, 画面里有什么] + + obstacle_avoidance: + # Experimental: enabled only for stationary, supervised browser validation. + # It is not a mobility-safety guarantee and must not be used for navigation. + enabled: true + description: 识别前方可见障碍并给出保守提示(实验) + prompt_source: AAAI_SI/C1_OBSTACLE_AVOID_DIRECT_V1 + prompt_file: ../prompts/obstacle_avoidance_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即判断当前画面前方是否有明显障碍,并给出简短、保守的安全提示。 + activation_phrases: [帮我避障, 前面有障碍吗, 前面有没有障碍, 看一下前方障碍, 前面安全吗] diff --git a/extensions/assistive_harness/cv/README.md b/extensions/assistive_harness/cv/README.md new file mode 100644 index 0000000..6c986c2 --- /dev/null +++ b/extensions/assistive_harness/cv/README.md @@ -0,0 +1,171 @@ +# Lightweight CV provider framework (V1) + +This directory is the transport-neutral CV shadow path used by the Assistive +Harness. Browser and future OpenGlass Adapters only provide JPEG frames. They do +not call YOLO, OCR, depth estimation, or control rules directly. + +## V1 data flow + +```text +Browser / ESP32 Adapter + | + | FrameEnvelope(JPEG, timestamp, skill_id, slots) + v +CVPipeline.submit() # returns immediately + | + | capacity-one latest-frame queue (old queued frame is dropped) + v +single background worker + | + | provider.analyze() in a dedicated CPU thread + v +CVObservation -> cv_events.jsonl # shadow only; no control decision +``` + +The Router, state machine, Session Adapter, and MiniCPM audio/video path do not +depend on a concrete CV model. + +## Guarantees and deliberate limits + +- `submit()` never waits for inference. +- The queue is bounded and latest-frame wins; overload cannot grow memory + without limit. +- Only one inference call runs at a time per client pipeline. +- Provider errors become `CVObservation.error` and never escape to the control + socket. +- A timeout is recorded without blocking STOP/RESET. Python cannot kill an + already-running native ONNX call safely, so that one worker lane remains + occupied until the native call returns; new queued frames continue to + collapse to the latest frame. +- V1 accepts only `disabled` and `shadow`. Shadow observations never switch a + Skill, suppress MiniCPM, or speak to the user. +- Temporal voting, result fusion, navigation decisions, and accuracy tuning are + intentionally outside V1. + +## Configuration + +Providers are declared once under `cv.providers`. Each Skill selects one with +`cv_provider`: + +```yaml +cv: + max_fps: 1 + queue_size: 1 + inference_timeout_ms: 2000 + providers: + noop: + type: noop + yolo_onnx: + type: yolo_onnx + model_path: path/to/yolo.onnx + device: cpu + confidence: 0.25 + image_size: 640 + +skills: + find_object: + cv_mode: shadow + cv_provider: yolo_onnx +``` + +Relative model paths are resolved against the YAML directory. Weights are not +owned by the Core. The current local sample points to the previously validated +`OmniHarness/mini_omni_harness/models/yolo26n.onnx` file. + +## Provider contract + +A provider is synchronous. `CVPipeline` is responsible for running it outside +the asyncio/control loop: + +Provider instances are shared so model weights load only once. If a backend is +not safe for concurrent calls from multiple connected clients, the provider +must protect that backend with its own lock, as `YoloOnnxProvider` does. + +```python +from typing import Any +from extensions.assistive_harness.cv.base import CVObservation + + +class OcrOnnxProvider: + def __init__(self, model_path): + self.model_path = model_path + self._session = None # lazy-load on first frame + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + if not frame: + raise ValueError("OCR requires a JPEG frame") + # 1. Decode JPEG. + # 2. Lazy-load and run the local model. + # 3. Return JSON-serializable values only. + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="ocr_onnx", + values={ + "status": "ok", + "text": "recognized text", + "regions": [], + "latency_ms": 12.3, + "model": self.model_path.name, + "device": "cpu", + }, + ) +``` + +To add OCR: + +1. Put the implementation in `cv/ocr_onnx.py` and keep model-specific imports + inside that plugin. +2. Add one `ocr_onnx` factory branch in `build_provider_registry()` in + `cv/registry.py`. +3. Add its config under `cv.providers`. +4. Set `read_text.cv_provider: ocr_onnx`; leave `cv_mode: shadow` during tests. +5. Add a blank/synthetic inference smoke plus one recorded real-frame test. + +No changes are required in `router.py`, `state_machine.py`, the browser Adapter, +or the future ESP32 Frame Adapter. + +## Observation schema + +Every plugin produces the same envelope: + +```json +{ + "frame_id": "browser_123", + "timestamp_ms": 123.0, + "skill_id": "find_object", + "provider": "shadow:yolo_onnx", + "values": { + "status": "ok", + "found": true, + "detections": [], + "latency_ms": 31.1, + "pipeline_latency_ms": 42.0 + }, + "error": null +} +``` + +Plugin-specific data belongs under `values`; the outer keys stay stable for +logging, replay, and later OpenGlass migration. + +## Validation + +```powershell +python -m unittest ` + extensions.assistive_harness.tests.test_core ` + extensions.assistive_harness.tests.test_cv_yolo +``` + +The tests cover failure isolation, latest-frame dropping, timeout reporting, +non-blocking submission, and a real ONNX Runtime YOLO inference. A browser +acceptance run should additionally verify that `find_object` produces +`provider=shadow:yolo_onnx` records while STOP/RESET remain responsive. diff --git a/extensions/assistive_harness/cv/__init__.py b/extensions/assistive_harness/cv/__init__.py new file mode 100644 index 0000000..dec2042 --- /dev/null +++ b/extensions/assistive_harness/cv/__init__.py @@ -0,0 +1,14 @@ +from .base import CVObservation, FrameEnvelope, PerceptionProvider +from .noop import NoOpCVProvider, ShadowCVProvider +from .pipeline import CVPipeline +from .registry import CVProviderRegistry + +__all__ = [ + "CVObservation", + "CVPipeline", + "CVProviderRegistry", + "FrameEnvelope", + "NoOpCVProvider", + "PerceptionProvider", + "ShadowCVProvider", +] diff --git a/extensions/assistive_harness/cv/base.py b/extensions/assistive_harness/cv/base.py new file mode 100644 index 0000000..5c1e153 --- /dev/null +++ b/extensions/assistive_harness/cv/base.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from typing import Any, Protocol + + +@dataclass(slots=True) +class FrameEnvelope: + """Transport-neutral frame handed from an Adapter to the CV worker.""" + + frame: bytes | None + frame_id: str + timestamp_ms: float + skill_id: str + slots: dict[str, Any] = field(default_factory=dict) + mode: str = "shadow" + provider_id: str = "noop" + + +@dataclass(slots=True) +class CVObservation: + frame_id: str + timestamp_ms: float + skill_id: str + provider: str + values: dict[str, Any] = field(default_factory=dict) + error: str | None = None + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +class PerceptionProvider(Protocol): + """Synchronous plugin contract; CVPipeline always calls it off-loop.""" + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + ... diff --git a/extensions/assistive_harness/cv/noop.py b/extensions/assistive_harness/cv/noop.py new file mode 100644 index 0000000..1770c62 --- /dev/null +++ b/extensions/assistive_harness/cv/noop.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from typing import Any + +from .base import CVObservation, PerceptionProvider + + +class NoOpCVProvider: + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + del frame, slots + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="noop", + values={}, + ) + + +class ShadowCVProvider: + """Failure-isolated observer. Its result is never a control decision.""" + + def __init__( + self, + provider: PerceptionProvider | None = None, + provider_id: str | None = None, + ): + self.provider = provider or NoOpCVProvider() + self.provider_id = provider_id or type(self.provider).__name__ + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + try: + result = self.provider.analyze( + frame, frame_id, timestamp_ms, skill_id, slots + ) + result.provider = f"shadow:{result.provider}" + return result + except Exception as exc: # shadow failures must not escape + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider=f"shadow:{self.provider_id}", + values={}, + error=f"{type(exc).__name__}: {exc}", + ) diff --git a/extensions/assistive_harness/cv/pipeline.py b/extensions/assistive_harness/cv/pipeline.py new file mode 100644 index 0000000..f17f9cf --- /dev/null +++ b/extensions/assistive_harness/cv/pipeline.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import asyncio +import time +from concurrent.futures import ThreadPoolExecutor +from typing import Callable + +from .base import CVObservation, FrameEnvelope +from .registry import CVProviderRegistry + + +ObservationCallback = Callable[[CVObservation], None] +MetricCallback = Callable[[str, float], None] + + +class CVPipeline: + """Latest-frame-only worker that keeps CV inference off the control loop.""" + + def __init__( + self, + providers: CVProviderRegistry, + *, + on_observation: ObservationCallback, + on_metric: MetricCallback | None = None, + queue_size: int = 1, + inference_timeout_ms: float = 2000.0, + worker_name: str = "assistive-cv", + ) -> None: + if int(queue_size) != 1: + raise ValueError("CV V1 requires queue_size=1 (latest-frame-only)") + self.providers = providers + self.on_observation = on_observation + self.on_metric = on_metric + self.queue: asyncio.Queue[FrameEnvelope] = asyncio.Queue(maxsize=1) + self.inference_timeout_ms = max(1.0, float(inference_timeout_ms)) + self.executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix=worker_name) + self.worker_task: asyncio.Task[None] | None = None + self.closed = False + self.submitted_frames = 0 + self.processed_frames = 0 + self.dropped_frames = 0 + self.timeout_count = 0 + + def submit(self, envelope: FrameEnvelope) -> bool: + """Enqueue without awaiting inference; replace the oldest queued frame.""" + if self.closed or envelope.mode == "disabled": + return False + self._ensure_worker() + if self.queue.full(): + try: + self.queue.get_nowait() + self.queue.task_done() + self.dropped_frames += 1 + self._metric("cv_frames_dropped", 1.0) + except asyncio.QueueEmpty: + pass + self.queue.put_nowait(envelope) + self.submitted_frames += 1 + return True + + def snapshot(self) -> dict[str, int | bool]: + return { + "closed": self.closed, + "queued_frames": self.queue.qsize(), + "submitted_frames": self.submitted_frames, + "processed_frames": self.processed_frames, + "dropped_frames": self.dropped_frames, + "timeout_count": self.timeout_count, + } + + async def close(self) -> None: + if self.closed: + return + self.closed = True + if self.worker_task is not None: + self.worker_task.cancel() + await asyncio.gather(self.worker_task, return_exceptions=True) + self.executor.shutdown(wait=False, cancel_futures=True) + + def _ensure_worker(self) -> None: + if self.worker_task is None or self.worker_task.done(): + self.worker_task = asyncio.create_task(self._run()) + + async def _run(self) -> None: + loop = asyncio.get_running_loop() + while True: + envelope = await self.queue.get() + started = time.perf_counter() + future = loop.run_in_executor(self.executor, self.providers.analyze, envelope) + try: + observation = await asyncio.wait_for( + asyncio.shield(future), self.inference_timeout_ms / 1000.0 + ) + except asyncio.TimeoutError: + self.timeout_count += 1 + self._metric("cv_inference_timeout", 1.0) + self._emit( + CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={ + "status": "timeout", + "timeout_ms": self.inference_timeout_ms, + }, + error=( + "TimeoutError: CV inference exceeded " + f"{self.inference_timeout_ms:.0f} ms" + ), + ) + ) + # Python cannot safely kill an in-flight native inference call. + # Keep this one-worker lane occupied until it exits so timeouts + # never create concurrent calls or an unbounded executor queue. + try: + await future + except Exception: + pass + except asyncio.CancelledError: + raise + except Exception as exc: + self._emit( + CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={"status": "error"}, + error=f"{type(exc).__name__}: {exc}", + ) + ) + else: + observation.values.setdefault( + "pipeline_latency_ms", round((time.perf_counter() - started) * 1000, 1) + ) + self.processed_frames += 1 + self._metric( + "cv_pipeline_latency_ms", + float(observation.values["pipeline_latency_ms"]), + ) + self._emit(observation) + finally: + self.queue.task_done() + + def _emit(self, observation: CVObservation) -> None: + try: + self.on_observation(observation) + except Exception: + # Telemetry/consumer failures are also outside the control path. + pass + + def _metric(self, name: str, value: float) -> None: + if self.on_metric is None: + return + try: + self.on_metric(name, value) + except Exception: + pass diff --git a/extensions/assistive_harness/cv/registry.py b/extensions/assistive_harness/cv/registry.py new file mode 100644 index 0000000..dbe3b4e --- /dev/null +++ b/extensions/assistive_harness/cv/registry.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Any + +from .base import CVObservation, FrameEnvelope, PerceptionProvider +from .noop import NoOpCVProvider, ShadowCVProvider + + +class CVProviderRegistry: + """Small explicit registry shared by browser and future device Adapters.""" + + def __init__(self, providers: dict[str, PerceptionProvider] | None = None): + self.providers: dict[str, PerceptionProvider] = { + "noop": NoOpCVProvider(), + **(providers or {}), + } + self._shadow = { + provider_id: ShadowCVProvider(provider, provider_id) + for provider_id, provider in self.providers.items() + } + + def register(self, provider_id: str, provider: PerceptionProvider) -> None: + normalized = provider_id.strip() + if not normalized: + raise ValueError("provider_id cannot be empty") + self.providers[normalized] = provider + self._shadow[normalized] = ShadowCVProvider(provider, normalized) + + def analyze(self, envelope: FrameEnvelope) -> CVObservation: + if envelope.mode != "shadow": + return CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={"status": "skipped", "reason": "unsupported_cv_mode"}, + error=f"Unsupported cv_mode: {envelope.mode}", + ) + provider = self._shadow.get(envelope.provider_id) + if provider is None: + return CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"shadow:{envelope.provider_id}", + values={"status": "skipped", "reason": "unknown_provider"}, + error=f"Unknown CV provider: {envelope.provider_id}", + ) + return provider.analyze( + envelope.frame, + envelope.frame_id, + envelope.timestamp_ms, + envelope.skill_id, + envelope.slots, + ) + + +def build_provider_registry( + config: dict[str, Any], *, config_dir: Path +) -> CVProviderRegistry: + registry = CVProviderRegistry() + providers = dict((config.get("cv") or {}).get("providers") or {}) + for provider_id, raw_spec in providers.items(): + spec = dict(raw_spec or {}) + provider_type = str(spec.get("type") or provider_id) + if provider_type == "noop": + registry.register(str(provider_id), NoOpCVProvider()) + continue + if provider_type == "yolo_onnx": + from .yolo_onnx import YoloOnnxProvider + + raw_path = Path(str(spec.get("model_path") or "")) + model_path = raw_path if raw_path.is_absolute() else config_dir / raw_path + registry.register( + str(provider_id), + YoloOnnxProvider( + model_path.resolve(), + device=str(spec.get("device") or "cpu"), + confidence=float(spec.get("confidence", 0.25)), + image_size=int(spec.get("image_size", 640)), + target_aliases=dict(spec.get("target_aliases") or {}), + ), + ) + continue + raise ValueError( + f"Unsupported CV provider type {provider_type!r} for {provider_id!r}" + ) + return registry diff --git a/extensions/assistive_harness/cv/requirements-cv.txt b/extensions/assistive_harness/cv/requirements-cv.txt new file mode 100644 index 0000000..72c2319 --- /dev/null +++ b/extensions/assistive_harness/cv/requirements-cv.txt @@ -0,0 +1,2 @@ +opencv-python-headless +onnxruntime==1.21.0 diff --git a/extensions/assistive_harness/cv/yolo_onnx.py b/extensions/assistive_harness/cv/yolo_onnx.py new file mode 100644 index 0000000..01ca1c8 --- /dev/null +++ b/extensions/assistive_harness/cv/yolo_onnx.py @@ -0,0 +1,220 @@ +from __future__ import annotations + +import threading +import time +from pathlib import Path +from typing import Any + +import numpy as np + +from .base import CVObservation + + +COCO_NAMES = ( + "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", + "truck", "boat", "traffic light", "fire hydrant", "stop sign", + "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", + "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", + "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", + "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", + "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", + "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", + "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", + "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", + "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", + "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", + "teddy bear", "hair drier", "toothbrush", +) + +DEFAULT_TARGET_ALIASES = { + "手机": "cell phone", "电话": "cell phone", "智能手机": "cell phone", + "phone": "cell phone", "cellphone": "cell phone", "cell phone": "cell phone", + "书": "book", "书本": "book", "图书": "book", "book": "book", + "杯子": "cup", "水杯": "cup", "茶杯": "cup", "cup": "cup", + "瓶子": "bottle", "水瓶": "bottle", "bottle": "bottle", + "椅子": "chair", "chair": "chair", "人": "person", "行人": "person", + "person": "person", "电脑": "laptop", "笔记本电脑": "laptop", + "laptop": "laptop", "遥控器": "remote", "remote": "remote", + "键盘": "keyboard", "keyboard": "keyboard", "鼠标": "mouse", + "mouse": "mouse", "背包": "backpack", "书包": "backpack", + "backpack": "backpack", +} + + +class YoloOnnxProvider: + """CPU-first YOLO ONNX reference plugin with no control-side effects.""" + + def __init__( + self, + model_path: Path, + *, + device: str = "cpu", + confidence: float = 0.25, + image_size: int = 640, + target_aliases: dict[str, str] | None = None, + ) -> None: + if device.lower() != "cpu": + raise ValueError("CV V1 only accepts device=cpu") + self.model_path = Path(model_path).resolve() + self.device = "cpu" + self.confidence = float(confidence) + self.image_size = int(image_size) + self.target_aliases = { + **DEFAULT_TARGET_ALIASES, + **{str(k).lower(): str(v) for k, v in (target_aliases or {}).items()}, + } + self._session: Any = None + self._input_name: str | None = None + self._cv2: Any = None + self._lock = threading.Lock() + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + if not frame: + raise ValueError("YOLO requires a non-empty JPEG frame") + self._load() + target = str(slots.get("target") or "").strip() + target_label = self._resolve_target(target) if target else None + if target and target_label is None: + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="yolo_onnx", + values={ + "status": "skipped", + "reason": "unsupported_target", + "target": target, + }, + ) + + encoded = np.frombuffer(frame, dtype=np.uint8) + image = self._cv2.imdecode(encoded, self._cv2.IMREAD_COLOR) + if image is None: + raise ValueError("YOLO could not decode the JPEG frame") + height, width = image.shape[:2] + started = time.perf_counter() + tensor, scale, pad_x, pad_y = self._prepare_input(image) + with self._lock: + output = self._session.run(None, {self._input_name: tensor})[0] + latency_ms = (time.perf_counter() - started) * 1000.0 + if output.ndim != 3 or output.shape[0] != 1 or output.shape[2] != 6: + raise ValueError(f"Unexpected YOLO output shape: {output.shape}") + + target_id = COCO_NAMES.index(target_label) if target_label else None + detections: list[dict[str, Any]] = [] + for row in output[0]: + x1, y1, x2, y2, confidence, raw_class = row + class_id = round(float(raw_class)) + if float(confidence) < self.confidence or not 0 <= class_id < len(COCO_NAMES): + continue + if target_id is not None and class_id != target_id: + continue + left = max(0.0, min(width, (float(x1) - pad_x) / scale)) + top = max(0.0, min(height, (float(y1) - pad_y) / scale)) + right = max(0.0, min(width, (float(x2) - pad_x) / scale)) + bottom = max(0.0, min(height, (float(y2) - pad_y) / scale)) + if right <= left or bottom <= top: + continue + center_x = ((left + right) / 2.0) / width + center_y = ((top + bottom) / 2.0) / height + detections.append( + { + "label": COCO_NAMES[class_id], + "confidence": round(float(confidence), 4), + "bbox_xyxy": [round(left), round(top), round(right), round(bottom)], + "bbox_normalized": [ + round(left / width, 4), round(top / height, 4), + round(right / width, 4), round(bottom / height, 4), + ], + "center_normalized": [round(center_x, 4), round(center_y, 4)], + "position": self._position(center_x, center_y), + } + ) + detections.sort(key=lambda item: float(item["confidence"]), reverse=True) + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="yolo_onnx", + values={ + "status": "ok", + "found": bool(detections), + "target": target or None, + "canonical_label": target_label, + "best_detection": detections[0] if detections else None, + "detections": detections, + "image": {"width": width, "height": height}, + "latency_ms": round(latency_ms, 1), + "frame_age_ms": round(max(0.0, time.time() * 1000.0 - timestamp_ms), 1), + "model": self.model_path.name, + "device": self.device, + }, + ) + + def _load(self) -> None: + if self._session is not None: + return + if not self.model_path.is_file(): + raise FileNotFoundError(f"YOLO weights not found: {self.model_path}") + import cv2 + import onnxruntime as ort + + session = ort.InferenceSession( + str(self.model_path), providers=["CPUExecutionProvider"] + ) + model_input = session.get_inputs()[0] + if model_input.shape[-2:] != [self.image_size, self.image_size]: + raise ValueError( + f"YOLO input is {model_input.shape[-2:]}, expected " + f"[{self.image_size}, {self.image_size}]" + ) + self._cv2 = cv2 + self._session = session + self._input_name = model_input.name + + def _prepare_input( + self, image: np.ndarray + ) -> tuple[np.ndarray, float, float, float]: + height, width = image.shape[:2] + scale = min(self.image_size / width, self.image_size / height) + resized_width, resized_height = round(width * scale), round(height * scale) + resized = self._cv2.resize(image, (resized_width, resized_height)) + pad_x = (self.image_size - resized_width) / 2.0 + pad_y = (self.image_size - resized_height) / 2.0 + left, top = round(pad_x - 0.1), round(pad_y - 0.1) + right = self.image_size - resized_width - left + bottom = self.image_size - resized_height - top + padded = self._cv2.copyMakeBorder( + resized, top, bottom, left, right, + self._cv2.BORDER_CONSTANT, value=(114, 114, 114), + ) + rgb = self._cv2.cvtColor(padded, self._cv2.COLOR_BGR2RGB) + tensor = np.ascontiguousarray(rgb.transpose(2, 0, 1), dtype=np.float32) + return np.expand_dims(tensor / 255.0, axis=0), scale, float(left), float(top) + + def _resolve_target(self, target: str) -> str | None: + normalized = target.lower().replace(" ", "") + for alias in sorted(self.target_aliases, key=len, reverse=True): + if alias.lower().replace(" ", "") in normalized: + label = self.target_aliases[alias] + return label if label in COCO_NAMES else None + return None + + @staticmethod + def _position(center_x: float, center_y: float) -> str: + horizontal = "左" if center_x < 1 / 3 else "右" if center_x > 2 / 3 else "中" + vertical = "上" if center_y < 1 / 3 else "下" if center_y > 2 / 3 else "中" + return { + ("左", "上"): "左上方", ("中", "上"): "正上方", + ("右", "上"): "右上方", ("左", "中"): "左侧", + ("中", "中"): "中央", ("右", "中"): "右侧", + ("左", "下"): "左下方", ("中", "下"): "正下方", + ("右", "下"): "右下方", + }[(horizontal, vertical)] diff --git a/extensions/assistive_harness/echo_guard.py b/extensions/assistive_harness/echo_guard.py new file mode 100644 index 0000000..fc3d25e --- /dev/null +++ b/extensions/assistive_harness/echo_guard.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +import time +from collections import deque +from dataclasses import dataclass +from difflib import SequenceMatcher + +from .router import normalize_text +from .schemas import ControlIntent + + +@dataclass(frozen=True, slots=True) +class EchoDecision: + allow: bool + reason: str + similarity: float = 0.0 + + +class EchoGuard: + def __init__(self, window_ms: int = 20_000, similarity_threshold: float = 0.86): + self.window_ms = int(window_ms) + self.similarity_threshold = float(similarity_threshold) + self._model_text: deque[tuple[float, str]] = deque() + self.ai_speaking = False + + def note_model_text(self, text: str, at_ms: float | None = None) -> None: + normalized = normalize_text(text) + if not normalized: + return + now = at_ms if at_ms is not None else time.time() * 1000 + self._model_text.append((now, normalized)) + self._prune(now) + + def set_ai_speaking(self, active: bool) -> None: + self.ai_speaking = bool(active) + + def _prune(self, now_ms: float) -> None: + cutoff = now_ms - self.window_ms + while self._model_text and self._model_text[0][0] < cutoff: + self._model_text.popleft() + + def evaluate( + self, + utterance: str, + intent: ControlIntent, + at_ms: float | None = None, + ) -> EchoDecision: + now = at_ms if at_ms is not None else time.time() * 1000 + self._prune(now) + normalized = normalize_text(utterance) + if len(normalized) < 2: + return EchoDecision(False, "too_short") + + best = 0.0 + for _, model_text in self._model_text: + if normalized in model_text or model_text in normalized: + best = 1.0 + break + best = max(best, SequenceMatcher(None, normalized, model_text).ratio()) + if best >= self.similarity_threshold: + return EchoDecision(False, "matches_recent_model_echo", best) + + if self.ai_speaking and intent not in { + ControlIntent.STOP_SPEECH, + ControlIntent.RESUME_SPEECH, + ControlIntent.RESET_SESSION, + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + # A positively routed Skill command is also a control-plane + # interruption. Recent-model-text similarity is checked above, + # so model echo is still rejected before this exception applies. + ControlIntent.ACTIVATE_SKILL, + }: + return EchoDecision(False, "ordinary_skill_suppressed_while_ai_speaking", best) + return EchoDecision(True, "allowed", best) diff --git a/extensions/assistive_harness/model_log.py b/extensions/assistive_harness/model_log.py new file mode 100644 index 0000000..43045e4 --- /dev/null +++ b/extensions/assistive_harness/model_log.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + + +@dataclass(slots=True) +class ModelTurnAccumulator: + """Aggregate streamed Gateway fragments into auditable model turns.""" + + turn_index: int = 0 + _key: tuple[Any, ...] | None = None + _text: list[str] = field(default_factory=list) + _audio_ms: float = 0.0 + _metadata: dict[str, Any] = field(default_factory=dict) + + def _flush(self) -> dict[str, Any] | None: + if self._key is None: + return None + self.turn_index += 1 + record = { + "type": "model.turn", + "turn_index": self.turn_index, + **self._metadata, + "text": "".join(self._text), + "audio_ms": round(self._audio_ms, 1), + } + self._key = None + self._text.clear() + self._audio_ms = 0.0 + self._metadata = {} + return record + + def feed(self, message: dict[str, Any]) -> list[dict[str, Any]]: + state = str(message.get("state") or "unknown") + key = ( + message.get("session_id"), + int(message.get("generation") or 0), + str(message.get("skill_id") or ""), + state, + ) + completed: list[dict[str, Any]] = [] + if self._key is not None and key != self._key: + record = self._flush() + if record is not None: + completed.append(record) + + text = str(message.get("text") or "") + audio_ms = float(message.get("audio_ms") or 0.0) + end_of_turn = bool(message.get("end_of_turn")) + if self._key is None and (text or audio_ms > 0): + self._key = key + self._metadata = { + "role": "assistant" if state == "speak" else "listen", + "state": state, + "session_id": message.get("session_id"), + "generation": int(message.get("generation") or 0), + "skill_id": str(message.get("skill_id") or ""), + "slots": dict(message.get("slots") or {}), + } + if self._key is not None: + if text: + self._text.append(text) + self._audio_ms += max(0.0, audio_ms) + if end_of_turn: + record = self._flush() + if record is not None: + completed.append(record) + return completed + + def flush(self) -> dict[str, Any] | None: + return self._flush() diff --git a/extensions/assistive_harness/package_phase_a.ps1 b/extensions/assistive_harness/package_phase_a.ps1 new file mode 100644 index 0000000..8264580 --- /dev/null +++ b/extensions/assistive_harness/package_phase_a.ps1 @@ -0,0 +1,69 @@ +param( + [string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path, + [string]$Date = '2026-08-11' +) + +$ErrorActionPreference = 'Stop' +$deliverables = Join-Path $RepoRoot 'deliverables' +$packageName = "VOICE_SKILL_HARNESS_PHASE_A_CODEX_RETURN_$Date" +$stage = Join-Path $deliverables $packageName +$zipPath = Join-Path $deliverables "$packageName.zip" + +$resolvedRepo = (Resolve-Path $RepoRoot).Path.TrimEnd('\') +New-Item -ItemType Directory -Force -Path $deliverables | Out-Null +$resolvedDeliverables = (Resolve-Path $deliverables).Path +if (-not $resolvedDeliverables.StartsWith($resolvedRepo, [StringComparison]::OrdinalIgnoreCase)) { + throw "Unsafe delivery target: $resolvedDeliverables" +} +if (Test-Path $stage) { Remove-Item -LiteralPath $stage -Recurse -Force } +if (Test-Path $zipPath) { Remove-Item -LiteralPath $zipPath -Force } +New-Item -ItemType Directory -Force -Path $stage | Out-Null + +function Copy-TreeFiltered([string]$Source, [string]$Destination) { + Get-ChildItem -LiteralPath $Source -Recurse -File | Where-Object { + $_.FullName -notmatch '[\\/]runs[\\/]' -and + $_.FullName -notmatch '[\\/]__pycache__[\\/]' -and + $_.FullName -notmatch '[\\/]test_artifacts[\\/]' -and + $_.Extension -ne '.pyc' + } | ForEach-Object { + $relative = $_.FullName.Substring($Source.TrimEnd('\').Length).TrimStart('\') + $target = Join-Path $Destination $relative + New-Item -ItemType Directory -Force -Path (Split-Path $target) | Out-Null + Copy-Item -LiteralPath $_.FullName -Destination $target + } +} + +Copy-TreeFiltered (Join-Path $RepoRoot 'extensions\assistive_harness') (Join-Path $stage 'extensions\assistive_harness') +Copy-TreeFiltered (Join-Path $RepoRoot 'static\assistive_harness') (Join-Path $stage 'static\assistive_harness') +New-Item -ItemType Directory -Force -Path (Join-Path $stage 'static\omni') | Out-Null +Copy-Item -LiteralPath (Join-Path $RepoRoot 'static\omni\omni-app.js') -Destination (Join-Path $stage 'static\omni\omni-app.js') + +$docNames = @( + 'VOICE_SKILL_HARNESS_AUDIT.md', + 'VOICE_SKILL_HARNESS_DESIGN.md', + 'VOICE_SKILL_HARNESS_EXECUTION_REPORT.md', + 'VOICE_SKILL_HARNESS_GO_NO_GO.md', + 'VOICE_SKILL_HARNESS_RERUN_COMMANDS.md', + 'VOICE_SKILL_HARNESS_CHANGED_FILES.md' +) +$docTarget = Join-Path $stage '_codex_context' +New-Item -ItemType Directory -Force -Path $docTarget | Out-Null +foreach ($name in $docNames) { + $text = Get-Content -Raw -Encoding UTF8 (Join-Path $RepoRoot "_codex_context\$name") + $text = $text.Replace($env:USERPROFILE, '%USERPROFILE%') + Set-Content -Encoding UTF8 -NoNewline -Path (Join-Path $docTarget $name) -Value $text +} + +$manifest = [ordered]@{ + project = 'Voice-Controlled Skill Harness' + phase = 'A_MINICPMO_BROWSER' + date = $Date + ready_for_phase_b = $false + feature_default = 'off' + excluded = @('model weights', 'raw audio/video', 'runs', 'credentials', 'absolute user paths') +} +$manifest | ConvertTo-Json -Depth 5 | Set-Content -Encoding UTF8 (Join-Path $stage 'MANIFEST.json') + +Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $zipPath -CompressionLevel Optimal +$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $zipPath).Hash +[pscustomobject]@{Zip=$zipPath; SHA256=$hash} diff --git a/extensions/assistive_harness/phase_b/README.md b/extensions/assistive_harness/phase_b/README.md new file mode 100644 index 0000000..b7ffe10 --- /dev/null +++ b/extensions/assistive_harness/phase_b/README.md @@ -0,0 +1,114 @@ +# Rokid Phase B Adapter + +This adapter replaces the Phase A browser transport while preserving the +frozen Harness policy and the existing MiniCPM backend: + +```text +Rokid APK --JPEG/PCM over Wi-Fi--> Phase B Adapter :18080 + |-- audio.mirror/frame.shadow --> Harness :8021 + |-- audio_chunk + JPEG --------> Gateway :8040 + `-- MiniCPM audio -------------> PC speaker +``` + +The backend remains `llama.cpp-omni -> Worker -> Gateway :8040 -> MiniCPM-o +4.5`. The old ESP32 and Rokid bridge scripts remain reference implementations; +`demo_rokid_phase_b_harness.py` is the Phase B entry point. + +## Frozen control contract + +- `STOP`: block and flush PC playback immediately. Device PCM continues to + reach Harness ASR and Gateway with `force_listen=true`. +- `RESUME`: release the playback gate without replacing the Session. +- `RESET`: stop the old Gateway Session with light cleanup, increment the + generation, create a new Session using the idle prompt, and reject stale + output. After `restart_complete`, the PC plays a short two-note ready cue; + initial startup stays silent. Use `--no-session-ready-chime` to disable it, + or `--session-ready-chime-volume` (default `0.32`) to tune it. +- Skill activation, cancellation, and return-to-chat use the same replacement + flow with the prompt and slots supplied by Harness. +- After a Skill Session reaches `restart_complete`, Harness injects the + original one-shot task into that new Session. This makes read-text and + experimental obstacle activation answer once instead of only changing the + system prompt. +- Rokid PCM is repacketized into 100 ms float32 `audio.mirror` frames, matching + Phase A. A bounded drop-oldest queue prevents device capture from being + blocked by Gateway latency. +- PC speaker queue depth plus `--playback-echo-tail-s` (default `0.80`) keeps + EchoGuard active through buffered playback and its short acoustic tail. + +## Prerequisites + +Run the existing Worker/Gateway on port 8040 and the Assistive Harness on port +8021. Install optional adapter dependencies from `requirements-phase-b.txt` in +the same Python environment. + +The current Rokid APK must target the host computer on port 18080 and provide: + +- `POST /rokid/image` with raw JPEG bytes; +- `WS /rokid/audio` with 16 kHz mono signed PCM16 little-endian packets. + +## Start + +From the repository root: + +```powershell +python .\demo_rokid_phase_b_harness.py ` + --gateway localhost:8040 ` + --harness-url ws://127.0.0.1:8021/ws/control ` + --input-gain 12 ` + --image-rotate-cw 270 ` + --session-ready-chime-volume 0.32 ` + --playback-echo-tail-s 0.80 +``` + +The local Gateway currently uses plain `ws://`. Use `--gateway-tls` only when +the deployed Gateway endpoint actually serves `wss://`. First-round model audio +plays on the computer; `--no-play` disables playback for diagnostics. + +The Rokid SDK PCM observed on the current device is materially quieter than the +browser microphone signal. `--input-gain 12` is the initial device calibration; +gain is applied before both Harness and Gateway and saturates instead of wrapping +PCM16. Recalibrate from real-device RMS logs rather than lowering the shared +Phase A VAD threshold. + +The ready cue briefly suppresses Rokid PCM forwarding for the cue plus a short +guard interval so the laptop speaker notification is not immediately recycled +into Harness or MiniCPM-o. + +Streaming model text is aggregated by Session, generation and end-of-turn. It +is printed as `[AssistiveHarness][MODEL]` and written under the current run: + +- `model_events.jsonl` for structured records; +- `model_transcript.txt` for quick human review. + +This is generated model text, not ASR over the final TTS waveform. Keep a +session recording when exact spoken audio must be audited. + +Health and the normalized latest frame are available at: + +- `GET http://127.0.0.1:18080/health` +- `GET http://127.0.0.1:18080/capture` + +Healthy input is approximately 25 audio packets/s and 1 JPEG/s, with one audio +client, zero sustained queue drops, `harness_connected=true`, and +`gateway_status=running`. `device_input_ready=true` confirms that at least one +PCM packet or JPEG has reached this process. If `[ROKID][NO_INPUT]` appears, +restart Sensor Mode on the glasses (`STOP -> RUN`) after the PC listener is up; +an APK WebSocket disconnected by a PC restart may not reconnect by itself. + +Stop the adapter with `Ctrl+C` (or `Ctrl+Break` on Windows). The HTTP listener, +Rokid WebSocket handler, Gateway Session, Harness connection, and PC speaker are +closed with bounded waits. A 10-second process watchdog is the final fallback, +so a native audio cleanup stall cannot leave port 18080 occupied indefinitely. + +## First device acceptance order + +1. Ordinary speech produces a MiniCPM response on the PC speaker. +2. While it speaks, say `停一下`; playback must stop and Harness must ACK + `stop_speech`. +3. Say `恢复对话`; the same Session resumes. +4. Say `重新开始`; the Session ID and generation must change. +5. Activate `找物`, `识字`, `场景描述`, and supervised experimental `避障`; + each switch must complete with a new Session and no old-generation output. + +Experimental obstacle output is not a navigation or safety guarantee. diff --git a/extensions/assistive_harness/phase_b/__init__.py b/extensions/assistive_harness/phase_b/__init__.py new file mode 100644 index 0000000..80d861b --- /dev/null +++ b/extensions/assistive_harness/phase_b/__init__.py @@ -0,0 +1,5 @@ +"""Device adapters for the Phase B glasses runtime.""" + +from .rokid_runtime import PhaseBRokidRuntime, RokidRuntimeConfig + +__all__ = ["PhaseBRokidRuntime", "RokidRuntimeConfig"] diff --git a/extensions/assistive_harness/phase_b/bridge_ui.py b/extensions/assistive_harness/phase_b/bridge_ui.py new file mode 100644 index 0000000..c3940f8 --- /dev/null +++ b/extensions/assistive_harness/phase_b/bridge_ui.py @@ -0,0 +1,337 @@ +"""bridge_ui.py — ESP32 duplex bridge 的 Web 观测/回放服务 + +URL: + / 实时观测(摄像头 + 字幕 + 状态) + /replay session 列表 + /replay/ session 回放(直接播 live_session.mp4,字幕跟随) + +依赖 recorder_live.py v5+ 写到 session_dir 的成品: + live_session.mp4 ← 播放主体(ffmpeg 已对齐) + live_session.m4a ← 没有视频帧时的纯音频回退 + live_user.wav ← 诊断下载 + live_ai.wav ← 诊断下载 + events.jsonl ← 字幕/事件源 + meta.json ← 会话元信息 +""" + +from __future__ import annotations +from typing import Optional, Set, Callable +import json +import logging +from pathlib import Path +from typing import Optional, Set + +from aiohttp import web + +LOGGER = logging.getLogger("bridge_ui") + +# 模板目录(和 bridge_ui.py 同级的 templates/) +TEMPLATES_DIR = Path(__file__).parent / "templates" + +# 开发期想"改完刷新浏览器就生效"就设 True;生产环境设 False 只读一次 +HOT_RELOAD_TEMPLATES = True + +_template_cache: dict[str, str] = {} + +def _load_template(name: str) -> str: + """读取 templates/。HOT_RELOAD_TEMPLATES=True 时每次都重读。""" + if not HOT_RELOAD_TEMPLATES and name in _template_cache: + return _template_cache[name] + path = TEMPLATES_DIR / name + try: + text = path.read_text(encoding="utf-8") + except FileNotFoundError: + LOGGER.error("[UI] template not found: %s", path) + return f"

Template not found: {name}

" + _template_cache[name] = text + return text + + +# ============================================================ +# Server +# ============================================================ + +class WebUIServer: + def __init__(self, port: int = 8080, host: str = "0.0.0.0", + sessions_root: Path = Path("./sessions"), + stop_callback: Optional[Callable[[], None]] = None, + mode_info: Optional[dict] = None): + self.port = port + self.host = host + self.sessions_root = Path(sessions_root) + self.live_clients: Set[web.WebSocketResponse] = set() + self._runner: Optional[web.AppRunner] = None + self._stop_callback = stop_callback # ← 新增 + self._stop_fired = False # ← 新增,防重入 + self.mode_info = mode_info or {"mode": "live"} + + async def start(self) -> None: + app = web.Application() + app.router.add_get('/', self._h_live) + app.router.add_get('/replay', self._h_replay_index) + app.router.add_get('/replay/{sid}', self._h_replay) + app.router.add_get('/live_ws', self._h_live_ws) + app.router.add_get('/api/sessions', self._h_list) + app.router.add_get('/api/session/{sid}/events', self._h_events) + app.router.add_get('/api/session/{sid}/meta', self._h_meta) + # —— v2: 直接吐成品文件,FileResponse 自带 HTTP Range 支持 —— + app.router.add_get('/api/session/{sid}/video', self._h_video) + app.router.add_get('/api/session/{sid}/audio', self._h_audio_only) + app.router.add_get('/api/session/{sid}/user_audio.wav', self._h_user_wav) + app.router.add_get('/api/session/{sid}/ai_audio.wav', self._h_ai_wav) + # 兼容老路由(可能旧版 events.jsonl 引用 images/xxx.jpg) + app.router.add_get('/api/session/{sid}/{path:images/.+}', self._h_image_legacy) + app.router.add_get('/api/session/{sid}/{path:live_images/.+}', self._h_image_live) + app.router.add_post('/api/stop', self._h_stop) + self._runner = web.AppRunner(app) + await self._runner.setup() + site = web.TCPSite(self._runner, self.host, self.port) + await site.start() + LOGGER.info("[UI] http://%s:%d (live + replay)", self.host, self.port) + + async def stop(self) -> None: + for ws in list(self.live_clients): + try: await ws.close() + except Exception: pass + if self._runner: + await self._runner.cleanup() + + async def emit(self, evt: dict) -> None: + if not self.live_clients: + return + msg = json.dumps(evt, ensure_ascii=False) + dead = [] + for ws in list(self.live_clients): + try: await ws.send_str(msg) + except Exception: dead.append(ws) + for ws in dead: + self.live_clients.discard(ws) + + # ---- handlers ---- + async def _h_live(self, request): + return web.Response(text=_load_template("live.html"), content_type='text/html') + + async def _h_stop(self, request): + if self._stop_fired: + return web.json_response({"ok": True, "already": True}) + self._stop_fired = True + LOGGER.info("[UI] /api/stop triggered by browser") + # 通知所有 live 客户端"要关了",前端可以把按钮改成"Saving..." + try: + await self.emit({"type": "stopping"}) + except Exception: + pass + if self._stop_callback is not None: + try: + self._stop_callback() + except Exception as e: + LOGGER.warning("[UI] stop_callback err: %s", e) + return web.json_response({"ok": True}) + + async def _h_replay_index(self, request): + return web.Response(text=_load_template("replay_index.html"), content_type='text/html') + + async def _h_replay(self, request): + return web.Response(text=_load_template("replay.html"), content_type='text/html') + + async def _h_live_ws(self, request): + ws = web.WebSocketResponse(heartbeat=30) + await ws.prepare(request) + self.live_clients.add(ws) + + LOGGER.info("[UI] live client +1 (total=%d)", len(self.live_clients)) + try: + await ws.send_str(json.dumps( + {"type": "mode", **self.mode_info}, ensure_ascii=False)) + except Exception: + pass + + try: + async for _ in ws: pass + finally: + self.live_clients.discard(ws) + LOGGER.info("[UI] live client -1 (total=%d)", len(self.live_clients)) + return ws + + async def _h_list(self, request): + sessions = [] + if self.sessions_root.exists(): + for d in sorted(self.sessions_root.iterdir(), reverse=True): + if not d.is_dir(): + continue + meta_p = d / "meta.json" + meta = {} + if meta_p.exists(): + try: + meta = json.loads(meta_p.read_text(encoding='utf-8')) + except Exception: + pass + if (d / "live_session.mp4").exists(): + media = "mp4" + elif (d / "live_session.m4a").exists(): + media = "m4a" + else: + media = None + sessions.append({ + "id": d.name, + "tag": meta.get("session_tag", d.name), + "start_time": meta.get("start_time"), + "end_time": meta.get("end_time"), + "stats": meta.get("stats", {}), + "media": media, + }) + return web.json_response({"sessions": sessions}) + + def _safe(self, sid: str) -> Optional[Path]: + if "/" in sid or ".." in sid: + return None + p = (self.sessions_root / sid).resolve() + try: + p.relative_to(self.sessions_root.resolve()) + except ValueError: + return None + if not p.is_dir(): + return None + return p + + async def _h_meta(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.json_response({"error": "not found"}, status=404) + meta = p / "meta.json" + if not meta.exists(): + return web.json_response({"error": "no meta"}, status=404) + return web.json_response(json.loads(meta.read_text(encoding='utf-8'))) + + async def _h_events(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.json_response({"error": "not found"}, status=404) + ev = p / "events.jsonl" + if not ev.exists(): + return web.json_response({"events": []}) + out = [] + for line in ev.read_text(encoding='utf-8').splitlines(): + line = line.strip() + if not line: + continue + try: + out.append(json.loads(line)) + except Exception: + pass + return web.json_response({"events": out}) + + # ---- 媒体:直接 FileResponse(支持 Range,可拖动进度条)---- + + async def _h_video(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + mp4 = p / "live_session.mp4" + if not mp4.exists(): + return web.Response(status=404, text="no live_session.mp4") + return web.FileResponse(mp4, headers={"Content-Type": "video/mp4"}) + + async def _h_audio_only(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + m4a = p / "live_session.m4a" + if not m4a.exists(): + return web.Response(status=404, text="no live_session.m4a") + return web.FileResponse(m4a, headers={"Content-Type": "audio/mp4"}) + + async def _h_user_wav(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + w = p / "live_user.wav" + if not w.exists(): + return web.Response(status=404) + return web.FileResponse(w, headers={"Content-Type": "audio/wav"}) + + async def _h_ai_wav(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + w = p / "live_ai.wav" + if not w.exists(): + return web.Response(status=404) + return web.FileResponse(w, headers={"Content-Type": "audio/wav"}) + + async def _h_image_live(self, request): + return await self._serve_image(request, subdir="live_images") + + async def _h_image_legacy(self, request): + return await self._serve_image(request, subdir="images") + + async def _serve_image(self, request, subdir: str): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + rel = request.match_info['path'] + # rel 形如 "live_images/img_00001.jpg" 或 "images/xxx.jpg" + # 这里只取末尾文件名,防穿越 + name = Path(rel).name + if "/" in name or ".." in name or not name: + return web.Response(status=400) + img = p / subdir / name + if not img.exists(): + return web.Response(status=404) + return web.FileResponse(img, headers={"Content-Type": "image/jpeg"}) + + +# ============================================================ +# Standalone entry +# ============================================================ + +def _main() -> None: + import argparse + import asyncio + + parser = argparse.ArgumentParser( + description="Bridge UI — standalone replay server (no ESP32 / no model)" + ) + parser.add_argument("--port", type=int, default=8080) + parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--sessions", default="./sessions", + help="sessions 根目录(默认 ./sessions)") + args = parser.parse_args() + + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", + ) + + sessions_root = Path(args.sessions).resolve() + if not sessions_root.exists(): + LOGGER.warning("[UI] sessions dir 不存在: %s(之后录到这里就能看见)", + sessions_root) + + server = WebUIServer( + port=args.port, + host=args.host, + sessions_root=sessions_root + ) + + async def _run(): + await server.start() + LOGGER.info("[UI] standalone mode — replay only") + LOGGER.info("[UI] sessions root: %s", sessions_root) + LOGGER.info("[UI] open http://localhost:%d/replay", args.port) + try: + while True: + await asyncio.sleep(3600) + except (KeyboardInterrupt, asyncio.CancelledError): + pass + finally: + await server.stop() + + try: + asyncio.run(_run()) + except KeyboardInterrupt: + print("\n[UI] bye.") + + +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/cam_pipeline_v2.py b/extensions/assistive_harness/phase_b/cam_pipeline_v2.py new file mode 100644 index 0000000..fdd2b8c --- /dev/null +++ b/extensions/assistive_harness/phase_b/cam_pipeline_v2.py @@ -0,0 +1,2283 @@ +# -*- coding: utf-8 -*- +"""cam_tuner.py — ESP32 相机调参台 (形态1: 纯调参, 不接模型) + +目的: 一边看 TCP live 画面, 一边热调分辨率/对焦/quality, 实时看每帧的 + 拉普拉斯清晰度分 + 亮度 —— 为三级漏斗一级标定阈值。 + +用法: + python cam_tuner.py --ip 10.100.7.68 + 浏览器开 http://localhost:8080 + +注意 (硬约束): + 固件 TCP 5000 是单客户端串行。本工具独占 TCP —— 调参时不要同时跑主程序 + (pc_vlm / demo_esp32), 否则抢同一条 TCP 连接会错位。 + +依赖: aiohttp, opencv-python(cv2), numpy, requests +""" + +from __future__ import annotations + +import argparse +import asyncio +import socket +import struct +import threading +import time +from pathlib import Path +from typing import Optional + +import cv2 +import numpy as np +import requests +from aiohttp import web + + +# ============================================================ +# TCP 5000 抓帧 (复用已验证协议; 单连接 + 锁, 后台线程持有) +# ============================================================ +class TCPImageClient: + def __init__(self, ip: str, port: int = 5000, timeout: float = 2.0): + self.ip, self.port, self.timeout = ip, port, timeout + self._sock = None + self._lock = threading.Lock() + + def _connect_locked(self) -> bool: + try: + self._sock = socket.create_connection((self.ip, self.port), timeout=self.timeout) + self._sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + self._sock.settimeout(self.timeout) + return True + except Exception: + self._sock = None + return False + + def _recv_exactly(self, n: int) -> Optional[bytes]: + buf = b"" + while len(buf) < n: + chunk = self._sock.recv(n - len(buf)) + if not chunk: + return None + buf += chunk + return buf + + def capture(self) -> Optional[bytes]: + with self._lock: + for attempt in (1, 2): + if self._sock is None and not self._connect_locked(): + return None + try: + self._sock.sendall(b"\x01") + hdr = self._recv_exactly(20) + if not hdr: + raise ConnectionError("no header") + magic = struct.unpack_from(" bool: + try: + r = self.sess.get(f"{self.base}/control", + params={"var": var, "val": val}, timeout=self.timeout) + return r.status_code == 200 + except Exception: + return False + + def set_resolution(self, name: str) -> bool: + v = FRAMESIZE.get(name.upper()) + return self.control("framesize", v) if v is not None else False + + def set_quality(self, q: int) -> bool: + return self.control("quality", max(0, min(63, int(q)))) + + def trigger_af(self) -> bool: + # 单次对焦: 直接写 OV5640 寄存器 0x3022=0x03 (single auto focus)。 + # 固件用标准 esp32-camera web server, 没有实现 /control?var=af (af 非标准变量), + # 之前先试 control("af") 会"假成功"(固件忽略)而不真对焦 —— 故直接走 /reg。 + # 固件端应设 g_auto_af=false, 关掉每秒定时硬对焦, 对焦完全由此按需触发。 + try: + r = self.sess.get(f"{self.base}/reg", + params={"reg": 0x3022, "mask": 0xff, "val": 0x03}, + timeout=self.timeout) + return r.status_code == 200 + except Exception: + return False + + +def rotate_jpeg(jpg: bytes, deg: int) -> bytes: + """后端真旋转 (顺时针 deg∈{0,90,180,270})。返回旋转后的 JPEG bytes。 + 真转而非只转显示: 因为最终自动旋转策略判断后会真喂给模型, 数据路径要一致; + 且清晰度分基于转后图算, 可验证'旋转不改变清晰度'(锐利度与朝向正交)。""" + d = deg % 360 + if d == 0: + return jpg + arr = np.frombuffer(jpg, dtype=np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_COLOR) + if img is None: + return jpg + if d == 90: + img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) + elif d == 180: + img = cv2.rotate(img, cv2.ROTATE_180) + elif d == 270: + img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) + else: + return jpg + ok, enc = cv2.imencode(".jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 90]) + return enc.tobytes() if ok else jpg + + +def _decode_gray(jpg: bytes): + arr = np.frombuffer(jpg, dtype=np.uint8) + return cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + + +def frame_motion(jpg_a: bytes, jpg_b: bytes) -> float: + """两帧灰度平均绝对差 (0-255)。大 = 画面在动 (快速移动/转头)。 + **先高斯模糊再算差**: 抹掉密集文字的高频细节, 只保留宏观位移 —— + 否则密集文字面(成分面)手持轻微移动时每个小字边缘都产生大量像素差, motion 虚高, + 把可读的图误判成"在动"(真机+OCR校准证实成分面可读却被全拒)。 + 漏斗二级用: 一批帧相邻 diff 都大 -> 画面不稳 -> 拒绝(念字必错, 让用户停稳)。""" + a, b = _decode_gray(jpg_a), _decode_gray(jpg_b) + if a is None or b is None: + return 0.0 + if a.shape != b.shape: + b = cv2.resize(b, (a.shape[1], a.shape[0])) + a = cv2.GaussianBlur(a, (7, 7), 0) + b = cv2.GaussianBlur(b, (7, 7), 0) + return float(np.abs(a.astype(np.int16) - b.astype(np.int16)).mean()) + + +def optical_flow_motion(jpg_a: bytes, jpg_b: bytes, downscale: float = 0.35) -> float: + """两帧稠密光流(Farneback)的平均位移幅度(像素)。物理含义明确、可解释: + 画面整体移动了多少像素。用于【严重晃动一刀切】—— 相机大幅位移时光流幅度大。 + 比 frame_motion(逐像素差)更鲁棒: 光流看运动矢量场, 不被密集文字的高频细节干扰 + (密集字轻微移动 -> 光流一致小位移; 逐像素差却虚高)。降采样提速(判"严重"够用)。""" + a, b = _decode_gray(jpg_a), _decode_gray(jpg_b) + if a is None or b is None: + return 0.0 + if a.shape != b.shape: + b = cv2.resize(b, (a.shape[1], a.shape[0])) + if downscale != 1.0: + a = cv2.resize(a, None, fx=downscale, fy=downscale, interpolation=cv2.INTER_AREA) + b = cv2.resize(b, None, fx=downscale, fy=downscale, interpolation=cv2.INTER_AREA) + flow = cv2.calcOpticalFlowFarneback(a, b, None, + pyr_scale=0.5, levels=3, winsize=15, + iterations=3, poly_n=5, poly_sigma=1.2, flags=0) + mag = np.sqrt(flow[..., 0] ** 2 + flow[..., 1] ** 2) + # 位移幅度按降采样比例还原到原图尺度, 便于用原图像素单位设阈值 + return float(mag.mean() / max(downscale, 1e-6)) + + +def bg_signals(jpg_bytes): + """候选'背景干扰'信号(都可解释, 检测画面有额外背景 -> 提示拿近/对准)。 + 干净白纸标签: 大片均匀白 + 中间少量黑字; 有背景(灯管/工位/天花板)时信号异常。 + 也含清晰度类(local_sharp/worst_block/sharp_ratio)供评分。返回 dict。""" + arr = np.frombuffer(jpg_bytes, np.uint8) + g = cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + if g is None: + return {} + h, w = g.shape + # 信号1: 亮度直方图熵 —— 干净标签(白底+黑字)分布集中熵低; 背景杂->熵高 + hist = cv2.calcHist([g], [0], None, [32], [0, 256]).flatten() + p = hist / (hist.sum() + 1e-9) + entropy = float(-np.sum(p * np.log2(p + 1e-12))) + # 信号2: 最大均匀(低方差)区占比 —— 白纸有大片均匀白; 占比低=画面杂乱 + blur = cv2.GaussianBlur(g, (5, 5), 0) + localvar = cv2.blur((g.astype(np.float32) - blur.astype(np.float32)) ** 2, (15, 15)) + lowvar = (localvar < 30).astype(np.uint8) + n, labels, stats, _ = cv2.connectedComponentsWithStats(lowvar) + max_uniform = float(stats[1:, cv2.CC_STAT_AREA].max() / g.size) if n > 1 else 0.0 + # 信号3: 边缘空间分布 —— 干净标签边缘集中中间(文字); 背景使边缘散布/落外围 + edges = cv2.Canny(g, 50, 150) + ys, xs = np.where(edges > 0) + if len(xs) > 10: + cx, cy = w / 2, h / 2 + d = np.sqrt(((xs - cx) / w) ** 2 + ((ys - cy) / h) ** 2) + edge_spread = float(d.mean()) + edge_periph = float((d > 0.35).mean()) # 边缘落外围(远离中心)比例 + else: + edge_spread = 0.0; edge_periph = 0.0 + # 信号4: local_sharp / worst_block —— 有高对比背景(灯管)时 local虚高而整体糊 + lap = cv2.Laplacian(g, cv2.CV_64F) + local_sharp = float(lap.var()) + grid = 6 + vals = [] + for i in range(grid): + for j in range(grid): + blk = g[i*h//grid:(i+1)*h//grid, j*w//grid:(j+1)*w//grid] + if blk.size == 0: + continue + e = cv2.Canny(blk, 50, 150) + if (e > 0).mean() < 0.006: + continue + vals.append(float(cv2.Laplacian(blk, cv2.CV_64F).var())) + worst = min(vals) if vals else 0.0 + sharp_ratio = float(local_sharp / (worst + 1e-6)) if worst > 0 else 0.0 + return { + "bright_entropy": round(entropy, 2), + "max_uniform": round(max_uniform, 3), + "edge_spread": round(edge_spread, 3), + "edge_periph": round(edge_periph, 3), + "sharp_ratio": round(sharp_ratio, 1), + "local_sharp": round(local_sharp, 1), + "worst_block": round(worst, 1), + } + + +# ============================================================ +# 三级漏斗 (形态2核心) +# 输入: 一批 N 帧 (bytes list) +# 一级 单帧质量筛: 太糊/太暗/空白 的帧标记不合格 +# 二级 稳定性判定: 相邻帧 motion 都过大 -> 整批拒绝 (画面不稳) +# 三级 选优: 合格帧里选 sharpness 最高的 = best +# 全不合格 / 不稳 -> 返回拒绝 (安全闸, 不喂模型) +# +# 阈值说明: 分辨率固定 HD 后针对 HD 标定。这里给的是初始默认值, +# 你戴眼镜实测后按 CSV 数据调 (尤其 SHARP_MIN / MOTION_MAX)。 +# sharp 低 + edge 低 = 空白(拒绝, 说"没看到文字"); 用 EDGE_MIN 兜。 +# ============================================================ +import math + + +def _g_sat(x: float, x0: float) -> float: + """Michaelis-Menten 饱和: x/(x+x0) -> [0,1)。x0=半饱和点。""" + x = max(0.0, x) + return x / (x + x0) if (x + x0) > 0 else 0.0 + + +def _g_light(b: float, lo: float, hi: float, soft: float) -> float: + """亮度响应: 太暗/过曝降分, 中间平台=1。两 sigmoid 相夹。""" + def sig(z): + try: + return 1.0 / (1.0 + math.exp(-z)) + except OverflowError: + return 0.0 if z < 0 else 1.0 + return sig((b - lo) / soft) * (1 - sig((b - hi) / soft)) + + +def frame_score(metrics: dict, rel_change: float, cfg: "FunnelConfig") -> dict: + """对一帧算 quality + focus_gain + 各分量 (供解释/记录)。 + rel_change: 该帧相对上一帧的 sharp 相对变化 (稳定性输入); 首帧传 0。""" + # 清晰度用 worst_block(最糊的有内容块) 而非全局 sharpness —— + # 全局拉普拉斯被大面积白底稀释(白底无边缘, 拉普拉斯低), 把"清晰的白盒子标签"误判成糊, + # 触发假的 need_focus。worst_block 只看有内容的最糊块, 不被白底拉低。 + # 真机+OCR校准: 不可读帧 worst_block<4.6, 可读>5.5 -> 分界~5, 故 x0 用 worst_x0(~5量级)。 + worst = metrics.get("worst_block", None) + if worst is None: + worst = metrics.get("sharpness", 0.0) # 兜底: 无 worst_block 时退回全局 + g_sharp = _g_sat(worst, cfg.worst_x0) + g_stable = max(0.0, 1.0 - min(1.0, rel_change)) # rel_change 已归一化到[0,1] + g_content = _g_sat(metrics.get("edge_density", 0.0), cfg.edge_x0) + g_light = _g_light(metrics.get("brightness", 0.0), cfg.light_lo, cfg.light_hi, cfg.light_soft) + + wsum = cfg.w_sharp + cfg.w_stable + cfg.w_content + cfg.w_light + base = (cfg.w_sharp * g_sharp + cfg.w_stable * g_stable + + cfg.w_content * g_content + cfg.w_light * g_light) / wsum + sharp_gate = g_sharp ** cfg.sharp_gate_gamma # 念字硬要求: 糊则压分 + quality = base * sharp_gate + # focus_gain: 稳 + 糊 时该对焦。对 content 用"温和依赖"(sqrt)而非硬乘 —— + # 重度失焦会把边缘也糊没(g_content 低), 但它恰恰最该对焦, 不能因此归零; + # sqrt 让低内容时 focus_gain 降低但保留触发机会。真空白由 g_content 极低 + + # g_stable 高的组合另行识别(见 run_funnel 拒绝归因)。 + focus_gain = g_stable * (1 - g_sharp) * math.sqrt(max(0.0, g_content)) + return { + "quality": round(quality, 3), + "focus_gain": round(focus_gain, 3), + "g_sharp": round(g_sharp, 3), + "g_stable": round(g_stable, 3), + "g_content": round(g_content, 3), + "g_light": round(g_light, 3), + } + + +class FunnelConfig: + """评分函数 f 的参数 (替代硬阈值 if)。每帧算一个连续 quality 分 + focus_gain, + 决策基于分数而非离散阈值 —— 可解释、可 ablation、可用数据校准。 + + quality = [Σ wi·gi] · g_sharp^gamma (sharp 作乘性门, 念字硬要求) + g_sharp = sharp/(sharp+sharp_x0) 清晰度饱和响应 + g_stable = 1 - min(1, rel_change/change_ref) 帧间相对变化越小越稳 + g_content = edge/(edge+edge_x0) 有无内容(区分糊/空) + g_light = 亮度双sigmoid(暗/过曝都降) + focus_gain = g_stable·(1-g_sharp)·g_content 稳+糊+有内容 -> 该对焦 + 决策: max(quality) >= ACCEPT_Q -> 选该帧; 否则看 max(focus_gain) >= FOCUS_G + -> 触发对焦再采; 都低 -> 拒绝。 + 参数是物理动机初值, 戴眼镜采数据后可校准/拟合 (方法 vs 调参的区别)。 + """ + # g 响应形状 (半饱和点/参考值) + sharp_x0 = 120.0 # (记录用) 全局清晰度半饱和点; g_sharp 现改用 worst_block + worst_x0 = 6.5 # worst_block 半饱和点。调严(原5.0)要求更清晰。真机+OCR: 不可读<4.6/可读>5.5。 + # g_sharp = worst/(worst+worst_x0): worst=5时g_sharp=0.5, 白盒清晰标签 + # worst 正常(不被白底稀释)故不误判need_focus。阈值待白标签标准数据精校。 + change_ref = 0.5 # (旧, 已弃用: 稳定性改用帧间像素差) + motion_ref = 15.0 # 帧间模糊后平均像素差达此视为"完全在动"。校准依据: OCR证实可读的 + # 成分面(密集字)模糊后 motion 达~8.4 仍可读, 须能过; 故 ref 上调到15, + # 使可读帧 stable>=0.44 通过, 同时剧烈晃动(>15)仍被拒。下界待补采晃动样本精校。 + edge_x0 = 0.01 # 边缘密度半饱和 (区分有内容/空白) + light_lo = 40.0 # 亮度下沿 + light_hi = 220.0 # 亮度上沿(过曝) + light_soft = 25.0 # 亮度软边宽度 + # 权重 (语义清晰, 可做 ablation) + w_sharp = 1.0 + w_stable = 1.0 + w_content = 0.6 + w_light = 0.4 + sharp_gate_gamma = 0.5 # sharp 乘性门强度 (0=不否决, 大=糊帧强烈压分) + # 决策阈值 (作用在归一化综合分上, 只此两个, 远少于原来一堆硬阈值) + ACCEPT_Q = 0.55 # 可用性门: 调严(原0.40太松, 放过模糊图)。0.55 要求更清晰才放行。 + # 宁拒绝不念错: 送下游的必须够清晰, 模糊的宁可让用户重拍。 + # 放宽的理由(数据得出): 全局quality分不开'能OCR'与'轻微糊', + # 那是任务层的精判(局部/文字区清晰度), 通用层不越俎代庖。 + FOCUS_G = 0.35 # (保留) focus_gain 参考 + # 稳定性优先三出口的门限 (段级中位数上判定; 待真机 rerun 校准) + STABLE_MIN = 0.35 # 出口A: g_stable 低于此 = 持续在动 -> "请拿稳" (第一闸)。 + # 从0.45降到0.35: 配合 motion_ref=15, 让OCR证实可读的密集字面通过, 修复误拒。 + SEVERE_FLOW = 8.0 # 出口A0: 段级光流位移(像素)>=此 = 严重晃动一刀切拒绝。初值8, + # 待 shake 样本校准("多大位移算严重"); 光流位移物理可解释。 + LIGHT_MIN = 0.35 # 出口D(留): g_light 低于此且为最差 -> 太暗 + CONTENT_MIN = 0.30 # 出口E(留): g_content 低于此 + SHARP_OK_FOR_E = 0.45 # 出口E(留): 判"没对准"要求 sharp 够高(清晰却没字才算对错) + MIN_QUALIFIED = 1 + + +# ============================================================ +# 场景配置 (核心: 机制一套, 参数按场景标定 —— "权重由场景物理特征+安全等级决定") +# 药盒(medicine): 小字/高危/白底 -> 偏拒绝、要求清晰、零容忍。= 默认 FunnelConfig。 +# 文具(stationery): 中大字/低危/彩色包装 -> 可放松、允许更多放行。 +# 固有机制(对焦/多帧筛选/倒置/光流晃动)完全一致, 只有下面这些判定参数不同。 +# ============================================================ +def make_scene_config(scene: str = "medicine") -> "FunnelConfig": + """按场景返回标定好的 FunnelConfig。机制代码不变, 只改参数。""" + cfg = FunnelConfig() + if scene in ("medicine", "药盒", "drug"): + return cfg # 药盒 = 现有默认(小字/高危/严) + if scene in ("stationery", "文具", "supplies", "生活用品"): + # 生活用品/文具: 安全等级低(念错关系不大) -> 放行阈值放松, 少拒绝、少打扰。 + # 参数依据: 网络摄像头 clip_windows csv (routing 分析) + 安全等级。 + cfg.worst_x0 = 5.0 # 松(药盒6.5): 拦截判据, 药盒严文具松(安全等级低)。 + # 手动定: csv里 worst_block 对ok/blur区分很弱(图都较清晰, + # AUC~0.52), 算不出可靠值, 按"文具比药盒松"手动定松一档。 + cfg.ACCEPT_Q = 0.48 # 略放松(药盒0.55): 安全低, 容错高一点。 + cfg.SEVERE_FLOW = 8.0 # 沿用药盒: csv 里 seg_flow 是最强判据(AUC~0.71), >8 后 + # ok率骤降, 与药盒一致。晃动是通用物理约束, 不随场景放松。 + return cfg + # 未知场景 -> 退回药盒默认, 并提示 + print(f"[scene] 未知场景 '{scene}', 用药盒默认配置") + return cfg + + +class FunnelResult: + def __init__(self): + self.accepted = False + self.need_focus = False # 稳但糊: 上层应触发AF再采一批 + self.reject_reason = "" + self.best_index = -1 + self.best_jpg = None + self.per_frame = [] + self.motions = [] # 这里存 rel_change 序列 + self.components = {} # 段级各 gi 分量 (归因用) + self.timings = {} + + def to_dict(self): + def _fmt(v): + if isinstance(v, (int, float)): + return round(v, 1) + return v # list 之类原样 (如 grab_per_frame_ms) + return { + "accepted": self.accepted, + "need_focus": self.need_focus, + "reject_reason": self.reject_reason, + "best_index": self.best_index, + "per_frame": self.per_frame, + "rel_changes": [round(m, 3) for m in self.motions], + "components": self.components, + "timings": {k: _fmt(v) for k, v in self.timings.items()}, + } + + +def run_funnel(frames: list[bytes], cfg: FunnelConfig = FunnelConfig()) -> FunnelResult: + """评分函数版漏斗: + 1) 每帧算 metrics(sharp/亮度/edge) + 2) 帧间相对变化 -> 每帧 quality + focus_gain (连续分, 非硬阈值) + 3) 决策: max(quality)>=ACCEPT_Q -> 选该帧(选优); + 否则 max(focus_gain)>=FOCUS_G -> 建议对焦(need_focus); + 都低 -> 拒绝。 + 返回里带 need_focus 标志, 供上层决定"稳但糊->触发AF->再采"。""" + r = FunnelResult() + if not frames: + r.reject_reason = "no_frames" + return r + + # 1) 单帧 metrics + t0 = time.monotonic() + metrics_list = [frame_metrics(j) for j in frames] + r.timings["level1_metrics_ms"] = (time.monotonic() - t0) * 1000 + + # 2) 帧间"运动"(稳定性输入) + 每帧评分 + # 稳定性用真正的帧间像素差分(frame_motion)衡量 —— 位移/转动会改变画面内容, + # 但不一定改变清晰度, 故不能用 sharp 变化代替。归一化到 [0,1] 的 rel。 + t1 = time.monotonic() + per = [] + prev_jpg = None + flow_mags = [] # 相邻帧光流位移幅度(严重晃动一刀切用) + for i, m in enumerate(metrics_list): + if prev_jpg is None: + motion = 0.0 + else: + motion = frame_motion(prev_jpg, frames[i]) # 平均绝对像素差 0-255 + flow_mags.append(optical_flow_motion(prev_jpg, frames[i])) # 光流位移(像素) + prev_jpg = frames[i] + rel = min(1.0, motion / cfg.motion_ref) # 归一: motion>=motion_ref 视为完全在动 + sc = frame_score(m, rel, cfg) + per.append({**m, "rel_change": round(rel, 3), "motion": round(motion, 2), **sc}) + r.motions.append(rel) + r.per_frame = per + # 段级光流: 用中位数抗单帧噪声。大 = 整段相机在大幅移动 = 严重晃动。 + seg_flow = float(sorted(flow_mags)[len(flow_mags) // 2]) if flow_mags else 0.0 + r.timings["level2_score_ms"] = (time.monotonic() - t1) * 1000 + + # 3) 决策: 稳定性优先的三出口 (A/B/C), argmin(gi) 归因, D/E 留接口 + t2 = time.monotonic() + qualities = [p["quality"] for p in per] + # 段级聚合各分量 (用中位数抗单帧噪声) + def med(key): + vals = sorted(p[key] for p in per) + n = len(vals) + return vals[n // 2] if n % 2 else (vals[n // 2 - 1] + vals[n // 2]) / 2 + seg_stable = med("g_stable") + seg_sharp = med("g_sharp") + seg_content = med("g_content") + seg_light = med("g_light") + # best 帧选择: 只按【清晰度】选最能读的一帧, 不用综合 quality。 + # 原因: quality 含 stable 分量, 会让"晃动某瞬间恰好帧间motion低(转折点)但画面糊"的帧 + # quality 虚高, 压过"稍动但清晰可读"的帧 -> best 选成糊的(真机验证: f0糊被选/f2清晰没选)。 + # 念字能不能读只取决于清晰度, 与该帧瞬时稳不稳无关; 稳定性只用于整段是否拒绝(出口A)。 + # 用 worst_block(最糊有内容块)选: 选"最糊处也最清晰"的那帧 = 最可读。 + def _clarity(i): + return per[i].get("worst_block", per[i].get("sharpness", 0.0)) + best_q = max(range(len(per)), key=_clarity) + # quality 仍保留供出口B的接受阈值判断(下面 qualities[best_q]>=ACCEPT_Q) + r.timings["level3_decide_ms"] = (time.monotonic() - t2) * 1000 + + # 归因分量表 (供 argmin 路由 + 记录) + r.components = {"stable": round(seg_stable, 3), "sharp": round(seg_sharp, 3), + "content": round(seg_content, 3), "light": round(seg_light, 3), + "flow": round(seg_flow, 2)} # 段级光流位移(像素) + + # ---- 出口 A0: 严重晃动一刀切 —— 光流位移过大 = 相机大幅移动, 不看别的直接拒 ---- + # 可解释: 画面整段平均移动 >SEVERE_FLOW 像素 = 明显在晃, 念字必糊, 让用户停稳。 + # 光流比逐像素差鲁棒(不被密集字伪运动骗); 阈值待 shake 样本校准。 + if seg_flow >= cfg.SEVERE_FLOW: + r.reject_reason = "severe_shake" # 出口 A0: "晃得厉害, 请拿稳" + r.need_focus = False + r.best_index = best_q + return r + + # ---- 出口 A: 稳定性优先 —— 持续在动, 不看清晰度, 直接请拿稳 ---- + # (动的时候对焦也没用, 且用户没老实, 不该浪费时间去挑图) + if seg_stable < cfg.STABLE_MIN: + r.reject_reason = "unstable" # 出口 A: "请拿稳/对准" + r.need_focus = False + r.best_index = best_q # 仅供参考, 不喂模型 + return r + + # ---- 稳定。看有没有帧够清晰 ---- + if qualities[best_q] >= cfg.ACCEPT_Q: + # ---- 出口 B: 稳 + 有清晰帧 -> 给最清晰的 ---- + r.accepted = True + r.best_index = best_q + r.best_jpg = frames[best_q] + r.need_focus = False + return r + + # ---- 稳但没有够清晰的帧: 归因 argmin, 决定是 C(对焦) 还是 D/E ---- + # 在"稳定"前提下, 看哪个分量最拖累: sharp低=失焦(C); light低=暗(D); + # content低但sharp高=清晰却没内容=没对准(E)。argmin 连续路由, 非硬堆阈值。 + cand = {"sharp": seg_sharp, "light": seg_light, "content": seg_content} + worst = min(cand, key=cand.get) + + if worst == "light" and seg_light < cfg.LIGHT_MIN: + # 出口 D (留接口, 未激活干预): 太暗 -> 未来 CLAHE 数字增强 / 提示到亮处 + r.reject_reason = "too_dark" # TODO: 接 CLAHE 后改为可救 + r.need_focus = False + r.best_index = best_q + return r + + # 出口 E(aimed_wrong)已弃用:原设计(-v/OCR)用"清晰但无内容结构"判"没对准", + # 目的是排除背景干扰。但 -o 不受背景影响、完全没字时会老实说"没看到字", + # 不需要漏斗拦。故这种帧直接放行,交给模型自己判断,避免误判打断。 + # (真正危险的"像字又不是字"是另一个问题,待 720p 数据用别的信号重做。) + if worst == "content" and seg_sharp >= cfg.SHARP_OK_FOR_E and seg_content < cfg.CONTENT_MIN: + r.accepted = True + r.best_index = best_q + r.best_jpg = frames[best_q] + r.need_focus = False + return r + + # ---- 出口 C: 稳但糊 (sharp 主导拖累) -> 触发AF重采 ---- + r.accepted = False + r.need_focus = True + r.reject_reason = "need_focus" # 上层触发AF+重采, 仍不行才最终拒绝 + r.best_index = best_q + return r + + +# ============================================================ +# 方向处理 & 推理 —— 留桩, 下一步填 +# ============================================================ +def _center_crop(gray, frac=0.6): + """取画面中心区, 排掉四周背景(手/桌面/墙)。用户会把目标大致对准中心, + 故中心区更可能是文字主体; 在其上算判据可显著减轻背景污染。""" + h, w = gray.shape[:2] + y0, y1 = int(h * (1 - frac) / 2), int(h * (1 + frac) / 2) + x0, x1 = int(w * (1 - frac) / 2), int(w * (1 + frac) / 2) + return gray[y0:y1, x0:x1] + + +def _binv_fg(gray): + _, b = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) + return (b > 0).astype(np.float64) + + +def _detect_sideways(gray): + """90°/270°侧向: 水平投影方差 vs 垂直投影方差。多档中心区(0.5/0.6/0.7)投票, + 比单一比例更稳(文字不在正中心时不易被单档背景污染带偏)。 + 返回 (verdict, ratio): 'upright'/'sideways'/'ambiguous'。ratio 取中位数。""" + ratios = [] + for frac in (0.5, 0.6, 0.7): + b = _binv_fg(_center_crop(gray, frac)) + hvar = float(np.var(b.sum(axis=1))) + vvar = float(np.var(b.sum(axis=0))) + ratios.append(hvar / (vvar + 1e-6)) + ratios.sort() + med = ratios[1] # 中位数, 抗单档异常 + votes = ["sideways" if r < 0.67 else ("upright" if r > 1.5 else "ambiguous") + for r in ratios] + # 多数票: 3档里≥2档一致才定, 否则 ambiguous + for v in ("sideways", "upright"): + if votes.count(v) >= 2: + return v, round(med, 2) + return "ambiguous", round(med, 2) + + +def _detect_upside_down(gray): + """180°正倒: '注水容量'判据(资料方法, 真图验证对中文有效)。 + 对每列: 最高文字点上方空白(top_cap) vs 最低文字点下方空白(bot_cap)。 + 正立版面文字整体下方留白多 -> (bot-top)>0; 倒置翻转 -> <0。 + **看版面级上下留白, 不依赖单字对称性, 绕开中文字对称死结。** + 真图验证: 正立+0.66/倒置-0.48, 抗±8°倾斜、抗裁剪比例(0.5~0.9)。必须裁剪(整图会被背景淹)。 + 返回 (verdict, score): 'upright'/'flipped'/'ambiguous'。""" + b = _binv_fg(_center_crop(gray, 0.7)) + h, w = b.shape + tc = bc = cnt = 0 + for x in range(0, w, 3): + col = np.where(b[:, x] > 0)[0] + if len(col) < 2: + continue + tc += col[0] + bc += (h - 1 - col[-1]) + cnt += 1 + if cnt < 10: + return "ambiguous", 0.0 + score = (bc - tc) / (bc + tc + 1e-9) + if score > 0.15: + return "upright", round(score, 3) + if score < -0.15: + return "flipped", round(score, 3) + return "ambiguous", round(score, 3) + + +def _detect_truncation(gray, margin=10): + # 先确认中心区有文字主体; 否则不判截断(避免背景边缘误报) + cb = _binv_fg(_center_crop(gray, 0.6)) + if cb.mean() < 0.01: + return {}, {} # 中心没内容, 不谈截断 + b = _binv_fg(gray) + edges = {"top": b[:margin, :].mean(), "bottom": b[-margin:, :].mean(), + "left": b[:, :margin].mean(), "right": b[:, -margin:].mean()} + overall = b.mean() + if overall < 1e-4: + return {}, {} + # 贴边判据收紧: 边缘密度需 >= 整图的一定比例, 且 >= 中心密度的一定比例 + # (排掉"背景纹理贴边但中心才是文字"的误报) + center_d = cb.mean() + touched = {k: (v >= overall * 0.6 and v >= center_d * 0.4 and v > 0.02) + for k, v in edges.items()} + return {k: round(v, 4) for k, v in edges.items()}, {k: t for k, t in touched.items() if t} + + +_PAN_HINT = {"top": "请向上看一点", "bottom": "请向下看一点", + "left": "请向左看一点", "right": "请向右看一点"} + + +_ORI_CLS = None # 方向分类器单例(全局只加载一次) +_ORI_CLS_TRIED = False # 是否已尝试加载(避免反复重试失败) + +def _get_orient_classifier(): + """懒加载 PaddleOCR 文档方向分类器(PP-LCNet, 6.75MB, 0/90/180/270)。 + 单例: 只在首次调用时加载一次(几秒), 之后每次推理仅几ms。 + 降级: 未安装/加载失败 -> 返回 None, process_orientation 回退到轻量CV判据, 不崩。""" + global _ORI_CLS, _ORI_CLS_TRIED + if _ORI_CLS is not None: + return _ORI_CLS + if _ORI_CLS_TRIED: + return None # 之前试过且失败, 不再重试 + _ORI_CLS_TRIED = True + # 加载方向分类器。优先用最简单的写法(实测 SmartGlasses 环境可用, 与 torch 不冲突 —— + # 当初冲突的是完整 PaddleOCR-GPU 识别, 不是这个轻量方向分类器)。 + # 若想显式指定设备, 后面的参数变体作为备选依次尝试。 + from paddleocr import DocImgOrientationClassification + last_err = None + for kw in (dict(model_name="PP-LCNet_x1_0_doc_ori"), # 最简单(原来能用的) + dict(model_name="PP-LCNet_x1_0_doc_ori", device="cpu"), # 显式CPU(可选) + dict()): # 全默认兜底 + try: + _ORI_CLS = DocImgOrientationClassification(**kw) + print(f"[orient] PaddleOCR 方向分类器已加载 (PP-LCNet, 参数={list(kw) or 'default'})") + return _ORI_CLS + except Exception as e: + last_err = e + continue # 这个参数组合不行, 换下一个 + print(f"[orient] 方向分类器加载失败, 回退到轻量CV判据: {last_err}") + _ORI_CLS = None + return None + + +# 文档方向标签(图像被顺时针旋转的角度) -> (状态, 给用户的转向提示) +# 注意: "图像旋转角"与"用户转药盒方向"相反。文案先按标准定义, 实机核对后固定。 +# 90°: 画面顺时针转了90° = 药盒被逆时针放了 -> 用户应顺时针转回? 需实机核对, 故保留 raw 标签调试。 +_ORIENT_MAP = { + "0": ("upright", None), + "90": ("sideways", "请把药盒顺时针转90°"), + "270": ("sideways", "请把药盒逆时针转90°"), + "180": ("flipped", "药盒拿反了,请上下翻转"), +} + + +def _classify_orientation(img_bgr): + """用分类器判方向。返回 (raw_label, conf) 或 (None, 0) 若不可用/低置信。""" + cls = _get_orient_classifier() + if cls is None: + return None, 0.0 + try: + res = cls.predict(img_bgr) # 传 ndarray, 免落盘 + r = res[0] + labels = r.get("label_names") or [str(x) for x in r.get("class_ids", [])] + scores = r.get("scores", [0.0]) + raw = str(labels[0]).replace("_degree", "").strip() + conf = float(max(scores)) if scores else 0.0 + return raw, conf + except Exception as e: + print(f"[orient] 推理失败: {e}") + return None, 0.0 + + +def process_orientation(best_jpg: bytes): + """第2级(方向) + 第3级(取景完整) —— 只对清晰的 best 帧做一次。 + 方向: 优先用 PaddleOCR 轻量方向分类器(PP-LCNet, 真图验证0/90/180/270全准, 置信~0.92); + 未装/低置信 -> 回退轻量CV判据。180°走多帧一致性('请确认正反'在handler触发)。 + 返回 (jpg, diag)。diag 含方向反馈 + 截断反馈 + incomplete 标志(传下游prompt)。 + [留桩] 圆柱曲面矫正 = 独立课题, 不在此处。""" + arr = np.frombuffer(best_jpg, np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_COLOR) + if img is None: + return best_jpg, {"ok": False} + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + orient_hint = None + orient_state = "upright" + ud_score = 0.0 + side_ratio = "" + orient_raw = "" + orient_conf = 0.0 + CONF_MIN = 0.60 # 置信门控: 低于此不硬判, 走uncertain/兜底 + + raw, conf = _classify_orientation(img) + orient_raw, orient_conf = (raw or ""), conf + if raw is not None and conf >= CONF_MIN and raw in _ORIENT_MAP: + # 分类器可用且置信足够 -> 直接按映射给状态+提示 + # (实测180 conf~0.93很确定, 不会与0混淆, 故即时提示; 若需滤噪声在簇内多帧投票层做) + orient_state, orient_hint = _ORIENT_MAP[raw] + elif raw is not None: + # 分类器给了结果但低置信 -> 不硬判 + orient_state = "uncertain" + else: + # 分类器不可用 -> 回退轻量CV判据(整块投影/注水容量) + side, side_ratio = _detect_sideways(gray) + if side == "sideways": + orient_state, orient_hint = "sideways", "请把药盒转90°" + else: + ud, ud_score = _detect_upside_down(gray) + orient_state = {"flipped": "flipped", "upright": "upright"}.get(ud, "uncertain") + + # 取景完整性(截断) —— 显示层暂关, 接口保留 + edges, truncated = _detect_truncation(gray) + pan_hint = None + if truncated: + worst = max(truncated, key=lambda k: edges.get(k, 0)) + pan_hint = _PAN_HINT.get(worst) + + diag = { + "ok": True, + "orient_state": orient_state, # upright/sideways/flipped/uncertain + "orient_hint": orient_hint, # 侧向即时提示; 180的"请确认"由多帧一致性在handler加 + "orient_raw": orient_raw, # 分类器原始标签(0/90/180/270), 实机核对转向用 + "orient_conf": round(orient_conf, 3), + "sideways_ratio": side_ratio, + "flipped_frame": orient_state == "flipped", # 供多帧一致性累积 + "ud_score": ud_score, + "truncated_edges": list(truncated.keys()), + "pan_hint": pan_hint, + "incomplete": bool(truncated), # 传下游prompt: 只念可见部分 + } + return best_jpg, diag # 第一版不自动转正, 只诊断+提示(方向由用户调) + + +def infer(frame_jpg: bytes) -> Optional[str]: + """[留桩] 未来: 把 best 帧喂给 -v (或 Qwen-VL) 做念字/识别。 + 现在返回 None。接推理时把这里换成真的模型调用。""" + return None + + +# ============================================================ +# CV 指标: 拉普拉斯方差(清晰度) + 平均亮度 +# 这两个就是三级漏斗一级的判据; 在这里实时显示以标定阈值。 +# ============================================================ +def frame_metrics(jpg: bytes) -> dict: + """返回一帧的 CV 指标字典。记录器会动态把所有 key 当作 CSV 列 —— + 以后 CV 那步加新指标(如帧间差分测晃动、方向检测分), 只需在这里往 + dict 里加 key, CSV 自动多列, 记录代码不用改。""" + arr = np.frombuffer(jpg, dtype=np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + if img is None: + return {"sharpness": 0.0, "brightness": 0.0, "kb": round(len(jpg) / 1024, 1)} + lap_var = cv2.Laplacian(img, cv2.CV_64F).var() + edges = cv2.Canny(img, 80, 160) + edge_density = float((edges > 0).mean()) + + # --- 附加指标: 先记录不判定, 采数据后用 ok/blur 标注看哪个最能对齐可读性 --- + # local_sharp: N×N 分块取最清晰块。抓"局部有清晰区"; 但会被高频背景(木纹)骗高。 + ls = _local_sharp(img, grid=4) + # text_sharp / text_ratio: MSER 类文字候选区的清晰度 + 面积占比。 + # text_ratio 说"有没有像字的区域"(高频背景 ratio≈0, 骗不过它); + # 但糊到一定程度 MSER 找不到字 -> ratio→0 (自我矛盾, 已离线证实)。 + # 与 local_sharp 组合: local高+ratio低=清晰但非字; 两者皆低=糊。 + ts, tr = _text_sharp(img) + # worst_block / block_var: 匹配"一处糊即不可用(OCR 标准)"的悲观判据。 + # worst_block = 有内容的块里最糊的清晰度 (看最差, 非最好); + # block_std = 块间清晰度标准差 (大 = 部分清晰部分糊 = 局部糊)。 + # 对 OCR: 决定成败的是最糊的文字区, 不是最清晰的 —— 故看 worst 而非 best。 + wb, bstd = _block_sharp_stats(img, grid=4) + # contrast / dark_ratio: 区分"糊"与"暗/低对比"。暗+低对比时全局sharp假性偏低, + # 但 contrast 低会揭示真因 -> 对应"数字增强(CLAHE)"而非"对焦"这条干预路径。 + contrast = float(img.std()) + dark_ratio = float((img < 50).mean()) + + # [CLAHE 接口预留] 未来暗环境念字: 若 contrast 低 / dark_ratio 高, 可在此对 img + # 做 CLAHE/gamma 增强后重算指标, 作为"数字层干预"(区别于对焦的"物理层干预")。 + # 现在不实现 —— 待有暗环境测试条件再填。示意: + # if contrast < TH: img_enh = cv2.createCLAHE(...).apply(img); 重算 lap_var ... + + return { + "sharpness": round(float(lap_var), 1), # 全局拉普拉斯方差 + "brightness": round(float(img.mean()), 1), + "edge_density": round(edge_density, 4), + "local_sharp": round(float(ls), 1), # 最清晰块 (乐观, 记录) + "worst_block": round(float(wb), 1), # 最糊的有内容块 (悲观, 匹配OCR标准) + "block_std": round(float(bstd), 1), # 块间清晰度std (大=局部糊) + "text_sharp": round(float(ts), 1), # 文字区清晰度 (记录) + "text_ratio": round(float(tr), 4), # 文字区面积占比 (记录) + "contrast": round(contrast, 1), # 对比度(std) (记录) + "dark_ratio": round(dark_ratio, 4), # 暗像素占比 (记录) + "kb": round(len(jpg) / 1024, 1), + } + + +def _block_sharp_stats(gray, grid: int = 4): + """分块清晰度的 (最糊有内容块, 块间std)。 + 只统计"有内容"的块(edge 非极低), 避免纯背景块干扰; + worst = 有内容块里最低清晰度 (对应'一处糊即失败'); + std = 块间清晰度离散度 (局部糊 -> 大)。""" + h, w = gray.shape[:2] + vals = [] + for i in range(grid): + for j in range(grid): + blk = gray[i * h // grid:(i + 1) * h // grid, j * w // grid:(j + 1) * w // grid] + if blk.size == 0: + continue + # 只算"有文字/边缘结构"的块。关键: 用【边缘密度】而非 std 判有内容 —— + # std 只反映明暗起伏, 白纸的折痕/阴影/渐变 std 也 >8, 会被误当"内容块", + # 而白纸拉普拉斯极低(~1) -> 把 worst_block 拉到假性极低 -> 清晰标签被误判糊。 + # 文字块有大量边缘, 白纸光影块几乎无边缘 -> 用 Canny 边缘占比区分。 + edges = cv2.Canny(blk, 50, 150) + edge_frac = float((edges > 0).mean()) + if edge_frac < 0.006: # 边缘太少 = 无文字结构(白纸/背景) -> 跳过 + continue + vals.append(float(cv2.Laplacian(blk, cv2.CV_64F).var())) + if not vals: + return 0.0, 0.0 + worst = min(vals) + std = float(np.std(vals)) if len(vals) > 1 else 0.0 + return worst, std + + +def _local_sharp(gray, grid: int = 4) -> float: + """N×N 分块, 取最清晰块的拉普拉斯方差。""" + h, w = gray.shape[:2] + best = 0.0 + for i in range(grid): + for j in range(grid): + blk = gray[i * h // grid:(i + 1) * h // grid, j * w // grid:(j + 1) * w // grid] + if blk.size: + best = max(best, float(cv2.Laplacian(blk, cv2.CV_64F).var())) + return best + + +def _text_sharp(gray): + """MSER 找类文字候选区, 在候选区上算清晰度。返回 (清晰度, 面积占比)。 + 找不到 -> (0,0)。占比=0 提示'没找到字'(可能糊/无字), 与 local_sharp 组合判读。""" + try: + mser = cv2.MSER_create(delta=5, min_area=60, max_area=14400) + regions, _ = mser.detectRegions(gray) + except Exception: + return 0.0, 0.0 + if not regions: + return 0.0, 0.0 + mask = np.zeros(gray.shape[:2], np.uint8) + for pts in regions: + x, y, bw, bh = cv2.boundingRect(pts.reshape(-1, 1, 2)) + ar = bw / max(bh, 1) + if 0.1 < ar < 10 and bw < gray.shape[1] * 0.9: + cv2.fillPoly(mask, [cv2.convexHull(pts.reshape(-1, 1, 2))], 255) + area_ratio = float((mask > 0).mean()) + if area_ratio < 0.001: + return 0.0, area_ratio + lap = cv2.Laplacian(gray, cv2.CV_64F) + return float(lap[mask > 0].var()), area_ratio + + +# ============================================================ +# 后台抓帧线程: 独占 TCP, 持续抓最新帧 (供 /frame 取用) +# 前端按自己的刷新率来取, 后端只维护"最新一帧+指标"。 +# ============================================================ +class Recorder: + """记录一段一段的指标序列。每段带一个 label(触发来源, 如 af / res:UXGA / manual), + 每帧一行, 动态列(跟随 frame_metrics 的 key)。存磁盘 + 供前端下载。 + + 两种触发: (a) 点控制按钮自动录 duration 秒; (b) 手动开始/停止。 + 记录挂在后端抓帧线程上(每抓一帧记一行), 与前端显示刷新率解耦, 密度=真实抓帧率。""" + + def __init__(self, out_dir: Path): + self.out_dir = Path(out_dir) + self.out_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + self._rows: list[dict] = [] # 所有已记录的行 (跨段, 全量) + self._active = False + self._seg_label = "" + self._seg_start_mono = 0.0 + self._seg_deadline = 0.0 # >0 表示定时录; 0 表示手动录(无限直到 stop) + self._seg_index = 0 + self._columns: list[str] = [] # 动态列, 首次记录时按 metrics key 确定 + + def start_segment(self, label: str, duration_s: float = 0.0): + """duration_s>0: 定时录; =0: 手动录(直到 stop_segment)。""" + with self._lock: + self._active = True + self._seg_index += 1 + self._seg_label = label + self._seg_start_mono = time.monotonic() + self._seg_deadline = (self._seg_start_mono + duration_s) if duration_s > 0 else 0.0 + + def stop_segment(self): + with self._lock: + self._active = False + + def feed(self, metrics: dict, grab_ms: float, res: str, rotate: int): + """抓帧线程每帧调一次。仅在 active 且未超时时记录。""" + with self._lock: + if not self._active: + return + now = time.monotonic() + if self._seg_deadline > 0 and now >= self._seg_deadline: + self._active = False + return + if not self._columns: + # 首次: 固定前缀列 + metrics 的动态列 + self._columns = (["seg", "label", "t_ms", "grab_ms", "res", "rotate"] + + list(metrics.keys())) + row = { + "seg": self._seg_index, + "label": self._seg_label, + "t_ms": round((now - self._seg_start_mono) * 1000, 1), + "grab_ms": round(grab_ms, 1), + "res": res, + "rotate": rotate, + } + row.update(metrics) + self._rows.append(row) + + def status(self) -> dict: + with self._lock: + remain = 0.0 + if self._active and self._seg_deadline > 0: + remain = max(0.0, self._seg_deadline - time.monotonic()) + return { + "active": self._active, + "label": self._seg_label, + "remain_s": round(remain, 1), + "n_rows": len(self._rows), + "n_segments": self._seg_index, + } + + def to_csv(self) -> str: + import csv, io + with self._lock: + rows = list(self._rows) + cols = list(self._columns) if self._columns else ["seg"] + # 动态列可能因未来指标增删而不齐: 用所有行 key 的并集补齐 + allcols = list(cols) + for r in rows: + for k in r: + if k not in allcols: + allcols.append(k) + buf = io.StringIO() + w = csv.DictWriter(buf, fieldnames=allcols, extrasaction="ignore") + w.writeheader() + for r in rows: + w.writerow(r) + return buf.getvalue() + + def save_disk(self) -> Optional[Path]: + csv_text = self.to_csv() + stamp = time.strftime("%Y%m%d_%H%M%S") + path = self.out_dir / f"tuning_{stamp}.csv" + try: + path.write_text(csv_text, encoding="utf-8-sig") # BOM 便于 Excel 直接开 + return path + except Exception as e: + print(f"[REC] 存盘失败: {e}") + return None + + def clear(self): + with self._lock: + self._rows.clear() + self._seg_index = 0 + self._columns = [] + self._active = False + + +class FrameGrabber: + def __init__(self, tcp: TCPImageClient, recorder: "Recorder", ctl_state: dict): + self.tcp = tcp + self.recorder = recorder + self.ctl_state = ctl_state # {"res":..., "rotate":...} 供记录标注当前状态 + self._latest_jpg: Optional[bytes] = None + self._latest_metrics: dict = {} + self._latest_grab_ms: float = 0.0 + self._rotate_deg = 0 + self._lock = threading.Lock() + self._stop = threading.Event() + self._thread = threading.Thread(target=self._run, daemon=True) + + def set_rotation(self, deg: int): + with self._lock: + self._rotate_deg = deg % 360 + + def start(self): + self._thread.start() + + def _run(self): + while not self._stop.is_set(): + t0 = time.monotonic() + jpg = self.tcp.capture() + dt = (time.monotonic() - t0) * 1000 + if jpg: + with self._lock: + deg = self._rotate_deg + if deg: + jpg = rotate_jpeg(jpg, deg) # 真转, 指标基于转后图 + mtr = frame_metrics(jpg) + with self._lock: + self._latest_jpg = jpg + self._latest_metrics = mtr + self._latest_grab_ms = dt + # 喂记录器 (仅在 active 时真记); 带当前分辨率/旋转状态 + self.recorder.feed(mtr, dt, + res=self.ctl_state.get("res", "?"), + rotate=deg) + else: + time.sleep(0.05) + + def latest(self): + with self._lock: + return self._latest_jpg, dict(self._latest_metrics), self._latest_grab_ms + + def grab_batch(self, n: int, rotate_apply: bool = True): + """连抓 n 帧 (复用 TCP 连接, 串行)。返回 (frames_list, grab_ms_list)。 + 对应真实链路 ASR 后'抓 N 张'那一步。""" + frames, lats = [], [] + with self._lock: + deg = self._rotate_deg + for _ in range(n): + t0 = time.monotonic() + jpg = self.tcp.capture() + dt = (time.monotonic() - t0) * 1000 + if jpg: + if rotate_apply and deg: + jpg = rotate_jpeg(jpg, deg) + frames.append(jpg) + lats.append(dt) + return frames, lats + + def stop(self): + self._stop.set() + self._thread.join(timeout=2.0) + self.tcp.close() + + +# ============================================================ +# Web 服务 +# ============================================================ +PAGE = r""" + + + + +相机调参台 + + + +
+
+ +
+
Laplacian variance · 清晰度
+
+
+
+
+ +
等待画面…
+
+
+
+
漏斗选出的 BEST 帧 (喂给模型的那张)
+ +
+
+ + + + + + +""" + + +class PipelineStats: + """漏斗运行统计: 接受/拒绝计数(按原因)+ best帧存盘 + 最近 best 缓存。 + 拒绝率是安全指标的雏形: 该拒的拒了多少、各什么原因。""" + + def __init__(self, out_dir: Path): + self.out_dir = Path(out_dir) + self.out_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + self.n_total = 0 + self.n_accepted = 0 + self.reasons: dict = {} # reason -> count + self.last_best: Optional[bytes] = None + self._batch_i = 0 + self._runs: list[dict] = [] # 每次抓拍一行汇总 (供标定用) + + def add_run_row(self, scene: str, res, focused: bool, best_path: str = "", geom: dict = None): + """每次抓拍追加一行汇总, 带用户标注的场景标签 + best帧路径。 + best_path: 供你事后人工看这张 best 清不清楚, 在 manual_label 列标真值 —— + 用人工判断(而非抓拍前意图标签)当 ground truth 校准阈值, 绕开标签错位。""" + per = res.per_frame or [] + max_q = max((p.get("quality", 0) for p in per), default=0) + max_fg = max((p.get("focus_gain", 0) for p in per), default=0) + # best 帧的完整 CV 指标 (供标定: 一张汇总表就能对比各指标 vs ok/blur) + bm = {} + if 0 <= res.best_index < len(per): + bm = per[res.best_index] + best_sharp = bm.get("sharpness", 0) + t = res.timings or {} + import os as _os + row = { + "time": time.strftime("%H:%M:%S"), + "scene": scene, + "manual_label": "", # ← 你看完 best 帧后手填: ok / blur (真值) + "n_frames": len(per), + "accepted": int(res.accepted), + "need_focus": int(res.need_focus), + "focused": int(focused), + "reject_reason": res.reject_reason, + "best_index": res.best_index, + "best_sharp": round(best_sharp, 1), + "best_local": bm.get("local_sharp", ""), + "best_worst_block": bm.get("worst_block", ""), + "best_block_std": bm.get("block_std", ""), + "best_text_sharp": bm.get("text_sharp", ""), + "best_text_ratio": bm.get("text_ratio", ""), + "best_contrast": bm.get("contrast", ""), + "best_dark_ratio": bm.get("dark_ratio", ""), + "seg_stable": (res.components or {}).get("stable", ""), + "seg_sharp": (res.components or {}).get("sharp", ""), + "seg_content": (res.components or {}).get("content", ""), + "seg_light": (res.components or {}).get("light", ""), + "max_quality": round(max_q, 3), + "max_focus_gain": round(max_fg, 3), + "grab_batch_ms": round(t.get("grab_batch_ms", 0), 1), + "funnel_ms": round(t.get("level1_metrics_ms", 0) + + t.get("level2_score_ms", 0) + + t.get("level3_decide_ms", 0), 1), + "total_ms": round(t.get("total_ms", 0), 1), + "best_file": _os.path.basename(best_path) if best_path else "", + "best_path": best_path, + # 方向分类器原始输出(定位方向不准: raw标签 vs 你实际摆放) + "orient_raw": (geom or {}).get("orient_raw", ""), + "orient_conf": (geom or {}).get("orient_conf", ""), + "orient_state": (geom or {}).get("orient_state", ""), + "orient_hint": (geom or {}).get("orient_hint", "") or "", + } + with self._lock: + self._runs.append(row) + + def runs_csv(self) -> str: + import csv, io + with self._lock: + runs = list(self._runs) + cols = ["time", "scene", "manual_label", "n_frames", "accepted", "need_focus", + "focused", "reject_reason", "best_index", "best_sharp", + "best_local", "best_worst_block", "best_block_std", + "best_text_sharp", "best_text_ratio", "best_contrast", "best_dark_ratio", + "seg_stable", "seg_sharp", "seg_content", "seg_light", + "max_quality", "max_focus_gain", "grab_batch_ms", "funnel_ms", "total_ms", + "orient_raw", "orient_conf", "orient_state", "orient_hint", + "best_file", "best_path"] + # 未来新字段自动并入 + for r in runs: + for k in r: + if k not in cols: + cols.append(k) + buf = io.StringIO() + w = csv.DictWriter(buf, fieldnames=cols, extrasaction="ignore") + w.writeheader() + for r in runs: + w.writerow(r) + return buf.getvalue() + + def save_runs_csv(self) -> Optional[Path]: + stamp = time.strftime("%Y%m%d_%H%M%S") + path = self.out_dir / f"pipeline_runs_{stamp}.csv" + try: + path.write_text(self.runs_csv(), encoding="utf-8-sig") + return path + except Exception as e: + print(f"[PSTATS] runs csv 存盘失败: {e}") + return None + + def record(self, accepted: bool, reason: str): + with self._lock: + self.n_total += 1 + if accepted: + self.n_accepted += 1 + else: + self.reasons[reason] = self.reasons.get(reason, 0) + 1 + + def set_last_best(self, jpg: bytes): + with self._lock: + self.last_best = jpg + + def save_batch(self, frames: list[bytes], best_index: int, res): + """存整批 N 帧 + 标出 best, 供人工核对。返回 (目录, best帧路径)。""" + with self._lock: + self._batch_i += 1 + bi = self._batch_i + d = self.out_dir / f"batch_{time.strftime('%H%M%S')}_{bi:03d}" + best_path = "" + try: + d.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(frames): + tag = "_BEST" if i == best_index else "" + sharp = res.per_frame[i]["sharpness"] if i < len(res.per_frame) else 0 + fp = d / f"f{i}_sharp{sharp:.0f}{tag}.jpg" + fp.write_bytes(jpg) + if i == best_index: + best_path = str(fp) + import json + (d / "funnel.json").write_text( + json.dumps(res.to_dict(), ensure_ascii=False, indent=2), encoding="utf-8") + return str(d), best_path + except Exception as e: + print(f"[PSTATS] save_batch 失败: {e}") + return "", "" + + def summary(self) -> dict: + with self._lock: + rej = self.n_total - self.n_accepted + return { + "total": self.n_total, + "accepted": self.n_accepted, + "rejected": rej, + "accept_rate": round(self.n_accepted / self.n_total, 3) if self.n_total else 0, + "reject_reasons": dict(self.reasons), + } + + +def make_app(grabber: FrameGrabber, ctl: CamControl, + recorder: Recorder, ctl_state: dict, default_dur: float, + funnel_cfg: "FunnelConfig", pstats: "PipelineStats") -> web.Application: + app = web.Application() + + async def h_index(request): + return web.Response(text=PAGE, content_type="text/html") + + async def h_frame(request): + jpg, m, grab_ms = grabber.latest() + if not jpg: + return web.Response(status=503, text="no frame") + headers = { + "X-Sharpness": str(m.get("sharpness", 0)), + "X-Brightness": str(m.get("brightness", 0)), + "X-Kb": str(m.get("kb", 0)), + "X-Grab-Ms": str(round(grab_ms, 0)), + "Cache-Control": "no-store", + } + return web.Response(body=jpg, content_type="image/jpeg", headers=headers) + + async def h_ctl(request): + op = request.query.get("op", "") + val = request.query.get("val", "") + dur = float(request.query.get("dur", default_dur) or default_dur) + loop = asyncio.get_event_loop() + label = None + if op == "res": + ok = await loop.run_in_executor(None, ctl.set_resolution, val) + ctl_state["res"] = val + label = f"res:{val}" + elif op == "af": + ok = await loop.run_in_executor(None, ctl.trigger_af) + label = "af" + elif op == "quality": + ok = await loop.run_in_executor(None, ctl.set_quality, int(val or 10)) + label = f"quality:{val}" + elif op == "rotate": + grabber.set_rotation(int(val or 0)) + ctl_state["rotate"] = int(val or 0) + ok = True + label = f"rotate:{val}" + else: + return web.json_response({"ok": False, "err": "unknown op"}, status=400) + # 控制操作自动开一段定时记录 (看该操作的效果曲线) + if label and dur > 0: + recorder.start_segment(label, dur) + return web.json_response({"ok": bool(ok), "recording": label, "dur": dur}) + + # ---- 记录控制 ---- + async def h_rec_start(request): + label = request.query.get("label", "manual") + dur = float(request.query.get("dur", 0) or 0) # 0=手动(直到 stop) + recorder.start_segment(label, dur) + return web.json_response({"ok": True, **recorder.status()}) + + async def h_rec_stop(request): + recorder.stop_segment() + return web.json_response({"ok": True, **recorder.status()}) + + async def h_rec_status(request): + return web.json_response(recorder.status()) + + async def h_rec_save(request): + path = recorder.save_disk() + return web.json_response({"ok": path is not None, + "path": str(path) if path else None, + **recorder.status()}) + + async def h_rec_download(request): + csv_text = recorder.to_csv() + recorder.save_disk() # 下载同时也存盘一份, 双保险 + return web.Response( + body=csv_text.encode("utf-8-sig"), + headers={"Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": "attachment; filename=tuning.csv"}) + + async def h_rec_clear(request): + recorder.clear() + return web.json_response({"ok": True, **recorder.status()}) + + # ---- 形态2: 抓批 -> 评分漏斗 -> (稳但糊则对焦再采) -> best/拒绝 ---- + async def h_pipeline_run(request): + n = int(request.query.get("n", 5) or 5) + focus_n = int(request.query.get("focus_n", 3) or 3) # 对焦后补采几帧 + af_settle_ms = int(request.query.get("af_settle_ms", 120) or 120) # 对焦生效等待(ms) + # OV5640 单次对焦(0x3022=0x03)锁定通常在~100ms量级(目标近焦时更快), 非几百ms。 + # 默认120ms为初值, 实测用 ?af_settle_ms=N 扫描找最短有效等待。 + scene = request.query.get("scene", "") # 用户标注场景 + loop = asyncio.get_event_loop() + + def _work(): + t0 = time.monotonic() + frames, grab_lats = grabber.grab_batch(n) + grab_ms = (time.monotonic() - t0) * 1000 + if not frames: + return {"ok": False, "err": "no_frames"}, None, None + + res = run_funnel(frames, funnel_cfg) + focused = False + af_on = ctl_state.get("af_enabled", True) + # "自动对焦"开关 af_enabled 的语义(用户设计): + # ON(默认): 自主判断+按需触发对焦(路线A, 正常使用)。 + # OFF: 不自动触发对焦, 只保留 res.need_focus 的判断结果 —— + # 用于录制实验时验证"判据说该对焦"这个判断本身对不对, 不让对焦动作干扰。 + # (手动"触发单次AF"按钮走 /op?op=af, 不受此开关限制, 任何时候可手动触发。) + # 固件侧须 g_auto_af=false, 否则固件每秒硬对焦会架空此开关。 + if res.need_focus and af_on: + tf = time.monotonic() + ctl.trigger_af() # 写 /reg 0x3022=0x03 单次对焦 + # 等对焦生效再抓 —— trigger_af 后马达物理对焦需时间(OV5640单次对焦~100ms量级), + # 立刻 grab_batch 会抓到"对焦过程中"的糊帧。af_settle_ms 可调, 实测最短有效等待。 + if af_settle_ms > 0: + time.sleep(af_settle_ms / 1000.0) # _work 在 executor 线程, sleep 不阻塞事件循环 + extra, extra_lats = grabber.grab_batch(focus_n) + res.timings["focus_af_regrab_ms"] = (time.monotonic() - tf) * 1000 + if extra: + frames = frames + extra + grab_lats = grab_lats + extra_lats + res = run_funnel(frames, funnel_cfg) + focused = True + + res.timings["grab_batch_ms"] = grab_ms + res.timings["grab_per_frame_ms"] = [round(x, 1) for x in grab_lats] + res.timings["focused"] = 1 if focused else 0 + + infer_text = None + # 可读性多帧一致性: 本窗口 accepted 只是"候选送下游"; 复用方向那套跨窗口累积, + # 连续窗口多数都候选送, 才真正送下游 —— 滤掉"单窗口偶然可读"(晃动中偶抓清晰帧)。 + # 严重晃动(severe_shake)已在 run_funnel 单窗口即拒, 不进这里, 不受一致性影响。 + # 纯CV判定累积(不喂下游), 与方向一致性同机制。N=3 多数。 + rhist = ctl_state.setdefault("readable_hist", []) + rhist.append(1 if res.accepted else 0) + del rhist[:-3] # 只留最近3窗口 + readable_consistent = (len(rhist) >= 3 and sum(rhist) > 3 / 2) # 3窗口多数 + res_dict_extra = {"readable_hist": list(rhist), + "readable_consistent": readable_consistent} + if res.accepted and res.best_jpg is not None and readable_consistent: + to = time.monotonic() + oriented, geom_diag = process_orientation(res.best_jpg) + res.timings["orientation_ms"] = (time.monotonic() - to) * 1000 + # 多帧一致性(方向): 累积最近若干次抓拍的"疑似倒置"标志, 连续/多数才弹"请确认正反"。 + # 纯CV判据的多帧累积(不喂VLM/OCR), 滤单帧噪声, 避免正常图偶发误报。 + if geom_diag and geom_diag.get("ok"): + hist = ctl_state.setdefault("flip_hist", []) + hist.append(1 if geom_diag.get("flipped_frame") else 0) + del hist[:-5] # 只留最近5次 + # 5次里≥3次疑似倒置, 且本次也疑似 -> 才弹确认(多数一致) + if len(hist) >= 3 and sum(hist) >= 3 and geom_diag.get("flipped_frame"): + if not geom_diag.get("orient_hint"): + geom_diag["orient_hint"] = "请确认药盒正反" + geom_diag["flip_consistent"] = True + geom_diag["flip_hist"] = list(hist) + ti = time.monotonic() + infer_text = infer(oriented) + res.timings["infer_ms"] = (time.monotonic() - ti) * 1000 + pstats.record(accepted=True, reason="") + saved_dir, best_path = pstats.save_batch(frames, res.best_index, res) + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + rd = res.to_dict(); rd.update(res_dict_extra) + return ({"ok": True, "result": rd, "focused": focused, + "infer": infer_text, "geom": geom_diag, "saved_dir": saved_dir}, + res.best_jpg, (res, focused, best_path)) + elif res.accepted and not readable_consistent: + # 本窗口看着可读, 但连续一致性未达(可能偶然/刚开始) -> 暂不送下游, 等确认 + pstats.record(accepted=False, reason="await_consistency") + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + rd = res.to_dict(); rd.update(res_dict_extra) + rd["reject_reason"] = "await_consistency" + return ({"ok": True, "result": rd, "focused": focused, + "infer": None, "await_consistency": True}, + res.best_jpg, (res, focused, None)) + else: + # 若对焦后仍 need_focus, 归为最终拒绝(对焦也没救回来) + reason = res.reject_reason if res.reject_reason != "need_focus" else "all_blurry" + pstats.record(accepted=False, reason=reason) + res.reject_reason = reason + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + # 拒绝时也存证 + 显示本次批次里最清晰的一帧(而非留旧图), + # 让你能看到"系统这次面对的到底是什么画面", 复盘判定冤不冤。 + rej_best = res.best_index if 0 <= res.best_index < len(frames) else 0 + saved_dir, best_path = pstats.save_batch(frames, rej_best, res) + show_jpg = frames[rej_best] if frames else None + return ({"ok": True, "result": res.to_dict(), "focused": focused, + "infer": None, "geom": None, "rejected_shown": True, + "saved_dir": saved_dir}, show_jpg, (res, focused, best_path)) + + result = await loop.run_in_executor(None, _work) + if len(result) == 3: + payload, best_jpg, run_info = result + else: + payload, best_jpg, run_info = result[0], result[1], None + if best_jpg is not None: + pstats.set_last_best(best_jpg) + if run_info is not None: + res_obj, focused, best_path = run_info + pstats.add_run_row(scene, res_obj, focused, best_path, payload.get("geom")) + return web.json_response({**payload, "stats": pstats.summary()}) + + async def h_pipeline_best(request): + jpg = pstats.last_best + if not jpg: + return web.Response(status=404) + return web.Response(body=jpg, content_type="image/jpeg", + headers={"Cache-Control": "no-store"}) + + async def h_pipeline_stats(request): + return web.json_response(pstats.summary()) + + async def h_pipeline_download(request): + csv_text = pstats.runs_csv() + pstats.save_runs_csv() # 同时存盘 + return web.Response( + body=csv_text.encode("utf-8-sig"), + headers={"Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": "attachment; filename=pipeline_runs.csv"}) + + # ---- 录制一段纯原始帧流(按秒, 不掺对焦), 供 rerun 看过程判定(问题1) ---- + async def h_record(request): + name = request.query.get("name", "").strip() or time.strftime("clip_%H%M%S") + dur = float(request.query.get("dur", 8) or 8) + dur = max(2.0, min(30.0, dur)) + safe = "".join(ch for ch in name if ch.isalnum() or ch in "_-") + clip_dir = pstats.out_dir.parent / "clips" / safe + loop = asyncio.get_event_loop() + try: + rec = await loop.run_in_executor( + None, record_stream, grabber, clip_dir, dur) + except Exception as e: + return web.json_response({"ok": False, "err": str(e)}, status=500) + return web.json_response({ + "ok": True, "dir": str(rec.dir), "name": safe, + "n_frames": len(rec.frames), "duration_s": dur, + }) + + app.router.add_get("/", h_index) + app.router.add_get("/frame", h_frame) + app.router.add_get("/ctl", h_ctl) + app.router.add_get("/rec/start", h_rec_start) + app.router.add_get("/rec/stop", h_rec_stop) + app.router.add_get("/rec/status", h_rec_status) + app.router.add_get("/rec/save", h_rec_save) + app.router.add_get("/rec/download", h_rec_download) + app.router.add_get("/rec/clear", h_rec_clear) + app.router.add_get("/pipeline/run", h_pipeline_run) + app.router.add_get("/pipeline/best", h_pipeline_best) + app.router.add_get("/pipeline/stats", h_pipeline_stats) + async def h_af_toggle(request): + val = request.query.get("on", "") + if val in ("1", "true", "on"): + ctl_state["af_enabled"] = True + elif val in ("0", "false", "off"): + ctl_state["af_enabled"] = False + return web.json_response({"ok": True, "af_enabled": ctl_state.get("af_enabled", True)}) + + app.router.add_get("/pipeline/download", h_pipeline_download) + app.router.add_get("/record", h_record) + app.router.add_get("/af_toggle", h_af_toggle) + return app + + +# ============================================================ +# 录制 + rerun (受控对比基础) +# 录制: 采一段(未对焦) -> 触发真AF -> 再采一段(对焦后), 两段都存, 标对焦点。 +# rerun: 从录制回放帧喂 run_funnel, 同一段反复扫参数, 输入固定=受控对比。 +# 解法一: 对焦效果也录进去(对焦后的帧真实存在), 故 C 出口的对焦可受控复现。 +# ============================================================ +class Recording: + """一段录制: 原始帧序列 + 每帧时间戳 + 对焦触发点标记。""" + + def __init__(self, clip_dir: Path): + self.dir = Path(clip_dir) + self.frames: list[bytes] = [] + self.timestamps: list[float] = [] + self.af_index = -1 # 对焦触发点: 此索引及之后的帧是"对焦后" + self.meta = {} + + def save(self): + self.dir.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(self.frames): + (self.dir / f"frame_{i:04d}.jpg").write_bytes(jpg) + import json + meta = { + "n_frames": len(self.frames), + "timestamps": self.timestamps, + "af_index": self.af_index, # -1=无对焦点 + **self.meta, + } + (self.dir / "meta.json").write_text( + json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8") + return self.dir + + @classmethod + def load(cls, clip_dir): + import json + d = Path(clip_dir) + rec = cls(d) + meta = json.loads((d / "meta.json").read_text(encoding="utf-8")) + rec.af_index = meta.get("af_index", -1) + rec.timestamps = meta.get("timestamps", []) + rec.meta = meta + n = meta.get("n_frames", 0) + for i in range(n): + fp = d / f"frame_{i:04d}.jpg" + if fp.exists(): + rec.frames.append(fp.read_bytes()) + return rec + + def pre_af_frames(self): + """对焦前的帧 (rerun 时先用这些跑漏斗)。""" + if self.af_index < 0: + return self.frames + return self.frames[:self.af_index] + + def post_af_frames(self): + """对焦后的帧 (rerun 时 C 出口触发对焦后回放这些)。""" + if self.af_index < 0: + return [] + return self.frames[self.af_index:] + + +def record_stream(grabber: "FrameGrabber", clip_dir: Path, + duration_s: float = 8.0, gap_s: float = 0.05) -> Recording: + """按秒录一段纯原始帧流 (不掺对焦)。专为问题1: rerun 回放看整个过程的 + 判定序列, 验证 CV 判的'该对焦'对不对。af_index=-1 表示无对焦点。""" + rec = Recording(clip_dir) + rec.af_index = -1 + t0 = time.monotonic() + while (time.monotonic() - t0) < duration_s: + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + rec.meta["duration_s"] = duration_s + rec.meta["kind"] = "stream" # 区别于对焦对比的 clip + rec.save() + return rec + + +def rerun_stream(clip_dir, cfg: "FunnelConfig" = None, n: int = 5, stride: int = 3): + """对一段连续录制, 滑动窗口跑判定, 输出'整个过程的判定序列'。 + 每 stride 帧滑一次, 窗口大小 n。看物品进->停->出时判定(A/B/C)怎么变。 + 对焦命令天然关闭(回放死图), 即问题1: 验证'该对焦'的判断对不对。 + + 产出(供人工核对): 每窗口存 best 帧(文件名带判定) + 一个 CSV(每窗口一行, + 带判定/各分量/best帧路径)。你筛 reason=need_focus 的行, 点开原图看是否真需调焦。""" + import csv, json + cfg = cfg or FunnelConfig() + rec = Recording.load(clip_dir) + frames = rec.frames + out_dir = Path(clip_dir) / "rerun" + out_dir.mkdir(parents=True, exist_ok=True) + print(f"\n=== 过程判定序列 {Path(clip_dir).name} " + f"({len(frames)}帧, ~{rec.meta.get('duration_s','?')}s, 窗口N={n} 步长={stride}) ===") + print(f"{'win':<5}{'t(s)':<7}{'判定':<10}{'reason':<14}{'stable':<8}{'sharp':<8}{'content':<8}{'best图'}") + print("-" * 78) + rows = [] + i = 0 + win = 0 + flip_hist = [] # 跨窗口多帧一致性: 累积"疑似倒置"标志 + while i + n <= len(frames): + window = frames[i:i + n] + res = run_funnel(window, cfg) + t = rec.timestamps[i] if i < len(rec.timestamps) else i * 0.05 + comp = res.components or {} + if res.accepted: + verdict = "B_usable" + elif res.reject_reason == "need_focus": + verdict = "C_needfocus" + elif res.reject_reason == "unstable": + verdict = "A_moving" + else: + verdict = res.reject_reason + # 存 best 帧 (窗口内 best_index; 拒绝时也存参考帧) + bidx = res.best_index if 0 <= res.best_index < len(window) else 0 + best_name = f"w{win:03d}_t{t:.1f}_{verdict}.jpg" + (out_dir / best_name).write_bytes(window[bidx]) + # best 帧的完整指标 + bm = res.per_frame[bidx] if 0 <= bidx < len(res.per_frame) else {} + # === 方向判据 (只对被接受的 best 帧跑; 拒绝的帧朝向无意义) === + orient_state = ""; ud_score = ""; side_ratio = ""; orient_hint = ""; flip_consistent = "" + if res.accepted: + _, gd = process_orientation(window[bidx]) + if gd.get("ok"): + orient_state = gd.get("orient_state", "") + ud_score = gd.get("ud_score", "") + side_ratio = gd.get("sideways_ratio", "") + orient_hint = gd.get("orient_hint") or "" + # 多帧一致性(按窗口顺序累积, 与 live 同逻辑): 5窗内≥3窗疑倒置且本窗也疑 -> 触发 + flip_hist.append(1 if gd.get("flipped_frame") else 0) + del flip_hist[:-5] + if len(flip_hist) >= 3 and sum(flip_hist) >= 3 and gd.get("flipped_frame"): + flip_consistent = 1 + if not orient_hint: + orient_hint = "请确认药盒正反" + else: + flip_consistent = 0 + print(f"{win:<5}{t:<7.1f}{verdict:<10}{res.reject_reason:<14}" + f"{comp.get('stable',0):<8.2f}{comp.get('sharp',0):<8.2f}{comp.get('content',0):<8.2f}{best_name}") + rows.append({ + "win": win, "t_s": round(t, 2), "verdict": verdict, + "reject_reason": res.reject_reason, "accepted": int(res.accepted), + "need_focus": int(res.need_focus), + "g_stable": comp.get("stable", ""), "g_sharp": comp.get("sharp", ""), + "g_content": comp.get("content", ""), "g_light": comp.get("light", ""), + "seg_flow": comp.get("flow", ""), + "best_sharp": bm.get("sharpness", ""), "best_local": bm.get("local_sharp", ""), + "best_worst_block": bm.get("worst_block", ""), "best_text_ratio": bm.get("text_ratio", ""), + "best_frame": best_name, + # 方向判据输出 (供核对方向准确性) + "orient_state": orient_state, "ud_score": ud_score, + "sideways_ratio": side_ratio, "flip_consistent": flip_consistent, + "orient_hint": orient_hint, + "manual_check": "", # ← 你看完 best 图后填: 该对焦的真该吗? ok/wrong + "manual_orient": "", # ← 你填这窗 best 的真实朝向: upright/sideways/flipped + }) + i += stride + win += 1 + # 存 CSV + cols = ["win", "t_s", "verdict", "reject_reason", "accepted", "need_focus", + "g_stable", "g_sharp", "g_content", "g_light", "seg_flow", + "best_sharp", "best_local", "best_worst_block", "best_text_ratio", + "best_frame", + "orient_state", "ud_score", "sideways_ratio", "flip_consistent", "orient_hint", + "manual_check", "manual_orient"] + csv_path = out_dir / "sequence.csv" + with open(csv_path, "w", encoding="utf-8-sig", newline="") as f: + w = csv.DictWriter(f, fieldnames=cols) + w.writeheader() + w.writerows(rows) + from collections import Counter + cnt = Counter(r["verdict"] for r in rows) + print(f"\n判定分布: {dict(cnt)}") + print(f"CSV: {csv_path}") + print(f"best图: {out_dir}/ (筛 need_focus 的窗口, 看对应 best图是否真需调焦)") + return rows + + +def record_clip(grabber: "FrameGrabber", ctl: "CamControl", clip_dir: Path, + pre_n: int = 8, post_n: int = 8, gap_s: float = 0.05) -> Recording: + """录一段: 抓 pre_n 帧(未对焦) -> 触发真AF -> 抓 post_n 帧(对焦后)。 + 含对焦点标记, 供 rerun 复现 C 出口对焦效果 (解法一)。""" + rec = Recording(clip_dir) + t0 = time.monotonic() + # 未对焦段 + for _ in range(pre_n): + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + # 触发真 AF + rec.af_index = len(rec.frames) + ctl.trigger_af() + time.sleep(0.2) # 给对焦一点生效时间 + # 对焦后段 + for _ in range(post_n): + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + rec.meta["pre_n"] = pre_n + rec.meta["post_n"] = post_n + rec.save() + return rec + + +def rerun_clip(rec: "Recording", cfg: "FunnelConfig", n: int, focus_n: int = 3) -> dict: + """对一段录制跑漏斗: 用前 n 帧(对焦前); 若判 need_focus, 用对焦后帧重评。 + 输入固定, 只变 cfg/n/focus_n -> 受控对比。返回判定 + 是否用了对焦。""" + pre = rec.pre_af_frames() + if len(pre) < n: + n = len(pre) + batch = pre[:n] + res = run_funnel(batch, cfg) + focused = False + if res.need_focus: + post = rec.post_af_frames() + if post: + extra = post[:focus_n] + res = run_funnel(batch + extra, cfg) # 合并重评, best 应来自对焦后帧 + focused = True + return { + "accepted": res.accepted, + "reject_reason": res.reject_reason, + "need_focus": res.need_focus, + "focused": focused, + "best_index": res.best_index, + "components": res.components, + "n": n, "focus_n": focus_n, + } + + +def rerun_sweep(clip_dir, cfg: "FunnelConfig" = None, + n_values=(3, 5, 7), focus_values=(0, 3)): + """对一段录制扫参数, 打印结果表 (找 N 拐点 / 对焦是否值得)。 + 受控对比: 同一段帧, 只变 N 和 focus_n。""" + cfg = cfg or FunnelConfig() + rec = Recording.load(clip_dir) + print(f"\n=== rerun 扫参 {Path(clip_dir).name} " + f"({len(rec.frames)}帧, 对焦点@{rec.af_index}) ===") + print(f"{'N':<5}{'focus_n':<9}{'判定':<12}{'用对焦':<8}{'best':<6}{'原因'}") + print("-" * 50) + for n in n_values: + for fn in focus_values: + r = rerun_clip(rec, cfg, n, fn) + verdict = "接受" if r["accepted"] else "拒绝" + print(f"{n:<5}{fn:<9}{verdict:<12}{'是' if r['focused'] else '否':<8}" + f"{r['best_index']:<6}{r['reject_reason']}") + return rec + + +def main(): + ap = argparse.ArgumentParser(description="ESP32 相机流水线台 (形态2: 漏斗+录制+rerun)") + ap.add_argument("--ip", help="眼镜 IP (live/record 模式必需)") + ap.add_argument("--tcp-port", type=int, default=5000) + ap.add_argument("--port", type=int, default=8080, help="网页端口") + ap.add_argument("--record-dir", default="./tuning_logs", help="CSV/批次 存盘目录") + ap.add_argument("--duration", type=float, default=5.0, help="点控制按钮后自动记录秒数") + ap.add_argument("--quality", type=int, default=4, help="启动默认 JPEG 质量(小=清晰, 默认4最高)") + # 录制 / rerun 模式 + ap.add_argument("--record", metavar="CLIP_DIR", help="录一段(含对焦点)到指定目录, 然后退出") + ap.add_argument("--pre-n", type=int, default=8, help="录制: 对焦前帧数") + ap.add_argument("--post-n", type=int, default=8, help="录制: 对焦后帧数") + ap.add_argument("--rerun", metavar="CLIP_DIR", help="对一段录制扫参数(N/focus_n), 然后退出") + args = ap.parse_args() + + # ---- rerun 模式: 纯离线, 不连眼镜 ---- + if args.rerun: + rec = Recording.load(args.rerun) + if rec.meta.get("kind") == "stream" or rec.af_index < 0: + rerun_stream(args.rerun) # 连续过程 -> 过程判定序列(问题1) + else: + rerun_sweep(args.rerun) # 对焦对比 clip -> 扫参数 + return + + # ---- record 模式: 连眼镜录一段 ---- + if args.record: + if not args.ip: + print("record 模式需要 --ip"); return + tcp = TCPImageClient(args.ip, args.tcp_port) + grabber = FrameGrabber(tcp, Recorder(Path(args.record_dir)), {"res": "HD", "rotate": 0}) + grabber.start(); time.sleep(0.3) + ctl = CamControl(args.ip) + print(f"[REC] 录制中: {args.pre_n}帧(未对焦) -> AF -> {args.post_n}帧(对焦后)...") + rec = record_clip(grabber, ctl, Path(args.record), args.pre_n, args.post_n) + print(f"[REC] 已存 {rec.dir} ({len(rec.frames)}帧, 对焦点@{rec.af_index})") + print(f"[REC] rerun: python cam_pipeline.py --rerun {rec.dir}") + grabber.stop() + return + + # ---- live 模式: 网页 ---- + if not args.ip: + print("live 模式需要 --ip"); return + recorder = Recorder(Path(args.record_dir)) + ctl_state = {"res": "HD", "rotate": 0, "af_enabled": True} + funnel_cfg = FunnelConfig() + pstats = PipelineStats(Path(args.record_dir) / "batches") + + tcp = TCPImageClient(args.ip, args.tcp_port) + grabber = FrameGrabber(tcp, recorder, ctl_state) + grabber.start() + ctl = CamControl(args.ip) + # 启动默认: HD + 最高画质(quality=4), 省得每次进网页手调 + ctl.set_resolution("HD"); ctl_state["res"] = "HD" + ctl.set_quality(args.quality) + time.sleep(0.15); ctl.trigger_af() # 切完补一次对焦 + print(f"[PIPE] 启动默认: HD + quality={args.quality} + 对焦") + + app = make_app(grabber, ctl, recorder, ctl_state, args.duration, funnel_cfg, pstats) + print(f"[PIPE] http://localhost:{args.port} (TCP {args.ip}:{args.tcp_port})") + print(f"[PIPE] 录制受控对比: python cam_pipeline.py --ip {args.ip} --record clips/case1") + print("[PIPE] 独占 TCP: 调参时不要同时跑主程序") + try: + web.run_app(app, host="0.0.0.0", port=args.port, print=None) + finally: + grabber.stop() + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py new file mode 100644 index 0000000..1a7d4cc --- /dev/null +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -0,0 +1,1851 @@ +"""ESP32 Phase B Harness runtime. + +复用 rokid_runtime 的全部 harness 骨架(HarnessClient / GatewaySessionManager / +GatewayDuplexSession / PCSpeaker / OutputGate / 控制逻辑),只把设备 I/O 从 +"PC 起 web server 等 Rokid 推" 换成 "PC 主动连 ESP32 拉音视频"。 + +数据方向对比: + Rokid : 眼镜(APK) --push--> PC 的 aiohttp server + ESP32 : PC --pull--> ESP32(CameraWebServer, /ws_audio_v2 + TCP:5000) + +汇聚点完全一致: + 音频 -> audio_queue(给 gateway session) + harness.send_audio(镜像给 8021 ASR) + 图像 -> latest_frame.set() + harness.send_frame(镜像给 8021) + AI 音频输出 -> PCSpeaker +""" +from __future__ import annotations + +import argparse +import asyncio +import json +import logging +import signal +import ssl +import struct +import base64 +import os +import time +from pathlib import Path +from typing import Any, Optional + +import aiohttp +import numpy as np + +from .timing_probe import TimingProbe +from .funnel_gate import FunnelGate +from .session_recorder import SessionRecorder +from .recorder_live import LiveRecorder +try: + from .bridge_ui import WebUIServer +except Exception: + WebUIServer = None + +# ── 复用 rokid_runtime 的 harness 骨架(一个字不改)────────────────────── +from .rokid_runtime import ( + RokidRuntimeConfig, + GatewaySessionManager, + GatewayDuplexSession, + HarnessClient, + PCSpeaker, + NullSpeaker, + OutputGate, + DropOldestAudioQueue, + AudioMirrorChunker, + LatestFrame, + RuntimeStats, + CtrlCExitWatchdog, + SkillRegistry, + default_skills_config, + pcm16le_to_float32, + apply_pcm16_gain, + now_ms, + SAMPLE_RATE_IN, +) + +LOG = logging.getLogger("assistive_harness.phase_b.esp32") + +# ESP32 音频包头: = seq(4) ts_ms(4) n_samples(2) reserved(2) +# 注意:第4字段是 reserved(pad),固件真丢包计数 g_ring_drops 未发到 wire, +# PC 端用 seq 跳变推断真丢包。 +ESP32_PKT_HDR = 12 +# TCP 图像帧头 magic +_TCP_IMG_MAGIC = 0x55AA55AA + +# 句子边界标点(作为"保护单位"的边界) +def _install_asr_tap(harness, live_rec) -> None: + """把 8021 的 asr.transcript 截下来落盘(评分取提问时刻 t0 用)。 + + 为什么不是另开一条连接:8021 每个 client_id 有独立的 runtime 和 outbound 队列, + asr.transcript 只投递给"送音频进来的那个 client"(即 esp32-phase-b), + 另开的 esp32-asr-tap 虽然能连上,但永远收不到任何消息。 + 所以只能挂在同一条 HarnessClient 上——rokid_runtime 里加了个可选的 on_message + 旁路(默认 None,不影响原行为),这里赋值即可。 + + 8021 推的字段(server.py 148-154): + {"type":"asr.transcript", "asr_event_id":..., "utterance":"这上面写的是什么", + "confidence":..., "final_at_ms":..., + "suppressed": true/false, "reason": "..."} ← 被回声抑制时带这两个 + 注意:**被 echo drop 的也照样推**(抑制发生在 route/echo 之后),所以这里全都记, + 由评分侧按问句筛,不在这里过滤。 + """ + if live_rec is None or harness is None: + return + + def _on_message(payload): + if not isinstance(payload, dict): + return + if payload.get("type") != "asr.transcript": + return + utt = str(payload.get("utterance") or "").strip() + if not utt: + return + try: + live_rec.log_asr(utt, payload.get("final_at_ms"), + payload.get("confidence")) + LOG.info("[ASR] %s%s", utt, + " (suppressed)" if payload.get("suppressed") else "") + except Exception as e: + LOG.warning("[ASR] 落盘失败: %s", e) + + harness.on_message = _on_message + LOG.info("[ASR] transcript 旁路已挂在 HarnessClient 上") + + +class TurnPrinter: + """把逐 chunk 的 text 碎片聚合成整段 turn(移植自 demo_esp32_duplex_0703)。 + + -o 每个 chunk 只吐几个字,评分要的是"这次回答说了什么"。规则: + text 非空 且(不在 turn 内 或 listen/speak 发生切换)→ 开新 turn,turn_idx +1 + end_of_turn → 返回 (turn_idx, 整段文本, is_listen) 并结束本 turn + is_listen=True 的 turn 是 8021 ASR 识别出的用户说话(用于取提问结束时刻 t0)。 + """ + + def __init__(self) -> None: + self.turn_idx = 0 + self._in_turn = False + self._turn_is_listen = None + self._turn_text: list[str] = [] + + def _reset(self) -> None: + self._in_turn = False + self._turn_text.clear() + + def feed(self, is_listen: bool, end_of_turn: bool, text: str): + """返回 (turn_idx, 完整文本或"", is_listen)。 + + 除 end_of_turn 外,**listen/speak 切换时也会把上一段吐出来** —— + 原实现在切换时直接 _reset() 丢掉,模型一路流式说、end_of_turn 迟迟不来时 + 整段就没了(bare 组实测 transcript 全空)。 + """ + flushed = None + if text: + if (not self._in_turn) or (self._turn_is_listen != is_listen): + if self._in_turn and self._turn_text: + flushed = (self.turn_idx, "".join(self._turn_text), + bool(self._turn_is_listen)) + self._reset() + self.turn_idx += 1 + self._in_turn = True + self._turn_is_listen = is_listen + self._turn_text.append(text) + if flushed is not None and not end_of_turn: + return flushed + if end_of_turn: + full_text = "".join(self._turn_text) + cur_idx = self.turn_idx + cur_listen = bool(self._turn_is_listen) + self._reset() + return cur_idx, full_text, cur_listen + return self.turn_idx, "", is_listen + + +_SENT_PUNCT = ",。!?,.!?" + + +def _emit_chunk_img(web_ui, jpeg: bytes, idx: int, img_sent: bool, age_ms: int = 0): + """把一帧图推给 bridge_ui 第一视角(type=chunk, img_b64)。无客户端时零负担。""" + if web_ui is None or not getattr(web_ui, "live_clients", None): + return + try: + b64 = base64.b64encode(jpeg).decode("ascii") if jpeg else None + import asyncio as _a + _a.create_task(web_ui.emit({ + "type": "chunk", + "idx": int(idx), + "img_b64": b64, + "img_sent": bool(img_sent), + "img_age_ms": int(age_ms), + })) + except Exception: + pass + + +class SentenceTracker: + """跟踪模型输出的句子边界,供漏斗"标点保护"策略用。 + + handle_result 每个 chunk 调 update():检测句末标点,累计标点序号。 + image_loop:reject 挂起时 snapshot() 记当前标点序号;之后 + boundary_reached(snap, speaker) 判断"自挂起后是否出现了新句末标点, + 且该段语音已经播完(speaker 队列基本清空)"。 + + 关键:模型文字生成远快于语音播放,文字标点会早于语音到达。所以"语音播到 + 标点"不能靠文字标点时刻或墙钟估算,而要看 speaker.pending_ms —— 队列里还 + 没播的语音降到很低时,才说明当前这段(含标点前的字)真的播完了。这样打断点 + 落在句末标点、语音播完那一刻,不会把句子从中间截断。 + """ + def __init__(self): + self._speaking = False + self._punct_seq = 0 # 句末标点计数(每出现一个 +1) + + def update(self, text: str, audio_ms: float, is_listen: bool): + self._speaking = not is_listen + if text and any(p in text for p in _SENT_PUNCT): + self._punct_seq += 1 + + @property + def speaking(self) -> bool: + return self._speaking + + def snapshot(self): + return {"punct_seq": self._punct_seq} + + def boundary_reached(self, snap, speaker=None): + """自 snap 之后:出现了新句末标点,且该段语音已播完(speaker 队列近空)。""" + if self._punct_seq <= snap["punct_seq"]: + return False # 还没出现新的句末标点 → 仍在保护当前句 + # 出现了新标点:等语音真的播到这里(speaker 队列基本清空) + if speaker is not None: + try: + if speaker.pending_ms() > 150.0: # 还有 >150ms 没播完 → 语音还没到标点 + return False + except Exception: + pass + return True + +# ── 强制措施:播放离线预生成的 reject 提示 wav(模型音色,运行时不碰 chat/KV)── +_REJECT_WAV_CACHE = {} # reason -> float32 ndarray(进程内缓存,只读一次盘) + + +def _load_reject_wav(wav_dir, reason): + """读预生成的 {reason}.wav(24kHz 16-bit mono)→ float32 ndarray,带缓存。 + 找不到返回 None(跳过播报,不阻断主流程)。""" + import wave as _wave + if reason in _REJECT_WAV_CACHE: + return _REJECT_WAV_CACHE[reason] + path = os.path.join(wav_dir, str(reason) + ".wav") + if not os.path.isfile(path): + _REJECT_WAV_CACHE[reason] = None + return None + try: + with _wave.open(path, "rb") as wf: + n = wf.getnframes() + raw = wf.readframes(n) + pcm16 = np.frombuffer(raw, dtype=np.int16) + pcm = (pcm16.astype(np.float32) / 32768.0) + _REJECT_WAV_CACHE[reason] = pcm + return pcm + except Exception: + _REJECT_WAV_CACHE[reason] = None + return None + +# ── 强制措施(防幻觉):reject 时用模型音色念提示 ───────────────────────── +# 复用 test_tts_speak 验证过的链路:走 gateway 的 /ws/chat(wss),zero-shot TTS, +# 模型音色念任意文本,返回 float32 24kHz 音频 → PCSpeaker 播。 +# 停/恢复走 8021(funnel.stop/funnel.resume),和真人「停一下」同一条 controller。 +_TTS_SYS_PROMPT = ( + "模仿音频样本的音色并生成新的内容。请用这种声音风格来为用户提供帮助。" + "直接作答,不要有冗余内容。" +) + + +async def _speak_hint_via_chat( + gateway_host: str, + gateway_port: int, + hint_text: str, + speaker, + ssl_ctx, +) -> bool: + """用 chat zero-shot TTS 让模型用自己音色念 hint_text,播到 PCSpeaker。 + + 返回 True=念出并已入队播放;False=失败(不阻断主流程)。 + """ + url = f"wss://{gateway_host}:{gateway_port}/ws/chat" + req = { + "messages": [ + {"role": "system", "content": _TTS_SYS_PROMPT}, + {"role": "user", "content": "请朗读以下内容:" + hint_text}, + ], + "streaming": False, + "generation": {"max_new_tokens": 128, "length_penalty": 1.1}, + "tts": {"enabled": True}, + "use_tts_template": True, + "omni_mode": False, + } + try: + async with aiohttp.ClientSession() as sess: + async with sess.ws_connect(url, ssl=ssl_ctx, max_msg_size=128 * 1024 * 1024) as ws: + await ws.send_json(req) + audio_b64 = None + sr = 24000 + # 加超时:念提示走 /ws/chat,若 duplex 占着 worker 会排队。 + # 超时返回,避免永久阻塞 image_loop(否则后续抓图全停)。 + deadline = time.monotonic() + 8.0 + while True: + remaining = deadline - time.monotonic() + if remaining <= 0: + LOG.warning("[强制措施] 念提示超时(可能 /ws/chat 排队,duplex 占用 worker)") + return False + try: + msg = await asyncio.wait_for(ws.receive(), timeout=remaining) + except asyncio.TimeoutError: + LOG.warning("[强制措施] 念提示超时(等 chat 响应)") + return False + if msg.type != aiohttp.WSMsgType.TEXT: + if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + return False + continue + data = json.loads(msg.data) + if data.get("type") == "done": + audio_b64 = data.get("audio_data") + sr = data.get("audio_sample_rate") or 24000 + break + if data.get("type") == "error": + LOG.warning("[强制措施] chat TTS error: %s", data.get("error")) + return False + if not audio_b64: + LOG.warning("[强制措施] chat TTS 无音频返回") + return False + # audio_data 是 float32 base64(24kHz mono)→ PCSpeaker(也是 24kHz float32) + import base64 as _b64 + pcm = np.frombuffer(_b64.b64decode(audio_b64), dtype=np.float32) + # block_and_flush 之后 PCSpeaker.blocked=True,enqueue 会被丢;先 resume 解除 + await speaker.resume() + await speaker.enqueue(pcm, generation=0) + LOG.info("[强制措施] 念提示: %r (%d samples, %.2fs)", + hint_text, pcm.size, pcm.size / float(sr)) + return True + except Exception as e: + LOG.warning("[强制措施] 念提示失败: %s", e) + return False + + +# ============================================================ +# ESP32 音频输入:PC 主动连 ESP32 的 /ws_audio_v2,收 int16 PCM +# (摘自 demo_esp32_duplex_0703 的 esp32_audio_reader,去掉 ring/live_rec, +# 直接把每包音频喂给 harness 骨架的 audio_queue + harness.send_audio) +# ============================================================ +async def esp32_audio_reader( + host: str, + port: int, + manager: GatewaySessionManager, + harness: HarnessClient, + audio_queue: DropOldestAudioQueue, + audio_mirror: AudioMirrorChunker, + stats: RuntimeStats, + input_gain: float, + stop_evt: asyncio.Event, + probe=None, + live_rec=None, +) -> None: + url = f"ws://{host}:{port}/ws_audio_v2" + LOG.info("[ESP32] audio WS: %s", url) + backoff = 1.0 + last_log = time.monotonic() + + while not stop_evt.is_set(): + try: + async with aiohttp.ClientSession() as session: + async with session.ws_connect(url, heartbeat=30, max_msg_size=0) as ws: + LOG.info("[ESP32] audio WS connected") + backoff = 1.0 + stats.audio_clients = 1 + async for msg in ws: + if stop_evt.is_set(): + break + if msg.type != aiohttp.WSMsgType.BINARY: + if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + break + continue + data = msg.data + if len(data) < ESP32_PKT_HDR: + continue + # 固件包头: seq(4) ts_ms(4) n_samples(2) reserved(2) + # 注意: 第4字段是 reserved(pad),不是丢包数;真丢包用 seq 跳变推断 + seq, ts_ms, n_samples, reserved = struct.unpack(" 0.0: + stats.non_silent_audio_packets += 1 + amplified = apply_pcm16_gain(raw, input_gain) + audio_queue.put_nowait(amplified) # -> gateway session + for frame in audio_mirror.feed(amplified): + await harness.send_audio(frame) # -> 8021 ASR 镜像 + # -o record:录 user 音(原始 samples,未放大) + if live_rec is not None: + try: + live_rec.feed_user_raw(samples) + except Exception: + pass + + if probe is not None: + probe.mark_audio(seq, n_samples, packet_rms) + + now = time.monotonic() + if now - last_log >= 5.0: + LOG.info( + "[ESP32] rx=%d pkts seq=%d ts=%d rsv=%d rms=%.4f", + stats.audio_packets, seq, ts_ms, reserved, stats.audio_rms, + ) + last_log = now + except asyncio.CancelledError: + raise + except (aiohttp.ClientError, asyncio.TimeoutError, OSError) as e: + LOG.warning("[ESP32] audio WS error: %s, retry in %.1fs", e, backoff) + finally: + stats.audio_clients = 0 + if not stop_evt.is_set(): + try: + await asyncio.wait_for(stop_evt.wait(), timeout=backoff) + except asyncio.TimeoutError: + pass + backoff = min(backoff * 2, 10.0) + + LOG.info("[ESP32] audio reader stopped") + + +# ============================================================ +# rerun 音频 reader:读 live_user.wav,按 40ms 包喂 audio_queue + harness +# (移植自 rerun_source.local_pcm_reader,下游从 ring 改为 esp32 的 +# audio_queue + harness,其余节奏/回放逻辑一致) +# ============================================================ +async def rerun_audio_reader( + session_dir: str, + manager: GatewaySessionManager, + harness: HarnessClient, + audio_queue: DropOldestAudioQueue, + audio_mirror: AudioMirrorChunker, + stats: RuntimeStats, + input_gain: float, + stop_evt: asyncio.Event, + speed: float = 1.0, + live_rec=None, + ready_evt: Optional[asyncio.Event] = None, + replay_t0=None, + hard_stop: Optional[asyncio.Event] = None, + done_evt: Optional[asyncio.Event] = None, +) -> None: + if hard_stop is None: + hard_stop = stop_evt + # 等 duplex session 就绪再推,否则排队期间的音频全丢(见 _wait_gateway_ready) + if ready_evt is not None: + await ready_evt.wait() + import wave as _wave + wav_path = os.path.join(session_dir, "live_user.wav") + if not os.path.isfile(wav_path): + LOG.error("[RERUN] live_user.wav 不存在: %s", wav_path) + stop_evt.set() + return + with _wave.open(wav_path, "rb") as w: + sr_in = w.getframerate() + pcm_i16 = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16) + _SR = 16000 + _PKT = 640 # 40ms @16k + total = pcm_i16.size + LOG.info("[RERUN] audio: %s samples=%d dur=%.2fs sr=%d", + wav_path, total, total / _SR, sr_in) + + packet_interval = (_PKT / _SR) / max(speed, 0.01) + ts_ms = 0 + cursor = 0 + pkt = 0 + # next_tick 必须是"本函数真正开始推包的那一刻"。 + # 曾经这里写成 replay_t0()(就绪门放行的时刻),但那之后还要经过任务调度、 + # 读 wav、打日志,等跑到循环里时 next_tick 已经是过去时刻 → + # sleep_for 恒为负 → 每轮都不 sleep → 564 个包在几十毫秒内全灌进 audio_queue + # → 队列容量 96、DropOldest 把开头的提问全丢了,模型只听到最后 3.8 秒的尾音。 + # (stats 里的 audio=25.0pps 统计的是"推进队列"的数量,正好掩盖了这个问题。) + # 图那边按 frames.jsonl 的 t 等待、以 replay_t0 为零点,两边起点差几十毫秒, + # 对 1s 粒度的 chunk 没有影响。 + next_tick = time.monotonic() + # 只受 hard_stop 控制,不再被 stop_evt 掐断。 + # 原来是 `while cursor < total and not stop_evt.is_set()`: + # 图那条路径放完图会 set stop_evt,而素材的图轮数常少于音频秒数 + # (drugbox 16 轮图 vs 22.5s 音频)→ 图先放完就把音频推送掐了, + # 后半段提问根本没进模型。两条流应各自跑完自己的。 + while cursor < total and not hard_stop.is_set(): + end = min(cursor + _PKT, total) + chunk_i16 = pcm_i16[cursor:end] + cursor = end + pkt += 1 + raw = chunk_i16.astype(" 0: + # 这里等的是 hard_stop,不是 stop_evt。 + # 之前 while 条件改成了 hard_stop,但循环体里仍 await stop_evt 并 break, + # 等于没改——图放完 set stop_evt 照样把音频推送掐断。 + try: + await asyncio.wait_for(hard_stop.wait(), timeout=sleep_for) + break + except asyncio.TimeoutError: + pass + + if done_evt is not None: + done_evt.set() + LOG.info("[RERUN] audio 推完 %d 包 (%.2fs),等模型说完…", pkt, ts_ms / 1000.0) + # 音频推完不立即 stop。注意:这里**不能** await stop_evt 就 break —— + # 图那条路径放完图也会 set stop_evt,两条互相踩,结果谁先到谁把另一条掐了 + # (图少的素材尤其明显:图很快放完 → 直接收工 → 模型话没说完)。 + # 这里独立按时间等,让模型有机会把最后一句说完;真正的结束由 image_loop + # 的静默判据 + 尾巴决定,或走这里的兜底。 + waited = 0.0 + while waited < 120.0: + if stop_evt.is_set(): + # 另一条已判定结束,再宽限一小段让 TTS 播完 + await asyncio.sleep(2.0) + break + await asyncio.sleep(0.5) + waited += 0.5 + if not stop_evt.is_set(): + stop_evt.set() + LOG.info("[RERUN] audio reader stopped") + + +# ============================================================ +# rerun 图像 loop:用 LocalImageSource 按 chunk 顺序读 best 图,直接喂模型 +# (-o rerun 不重跑 funnel——best 已是筛过的,直接 send_frame) +# ============================================================ +async def rerun_image_loop( + session_dir: str, + latest_frame, + harness: HarnessClient, + stats: RuntimeStats, + interval_s: float, + stop_evt: asyncio.Event, + web_ui=None, + live_rec=None, + ready_evt: Optional[asyncio.Event] = None, + replay_t0=None, + done_evt: Optional[asyncio.Event] = None, + peer_done: Optional[asyncio.Event] = None, + speaker=None, + sent_tracker=None, + tail_wait_s: float = 30.0, +) -> None: + if ready_evt is not None: + await ready_evt.wait() + try: + from .rerun_source import LocalImageSource + except Exception as e: + LOG.error("[RERUN] 无法导入 LocalImageSource: %s", e) + stop_evt.set() + return + from pathlib import Path as _Path + try: + src = LocalImageSource(_Path(session_dir)) + except Exception as e: + LOG.error("[RERUN] LocalImageSource 初始化失败: %s", e) + stop_evt.set() + return + # 按 chunk_idx 升序回放 + idxs = sorted(src._map.keys()) + LOG.info("[RERUN] image loop: %d 帧待回放", len(idxs)) + for cidx in idxs: + if stop_evt.is_set(): + break + jpeg = await src.capture(cidx) + if jpeg: + ts = now_ms() + latest_frame.set(jpeg, ts) + stats.image_count += 1 + await harness.send_frame(jpeg, latest_frame.sequence, ts) + LOG.info("[RERUN] send frame idx=%d (%d bytes)", cidx, len(jpeg)) + _emit_chunk_img(web_ui, jpeg, latest_frame.sequence, True) + if live_rec is not None: + try: + live_rec.on_frame(jpeg, latest_frame.sequence) + except Exception: + pass + try: + await asyncio.wait_for(stop_evt.wait(), timeout=interval_s) + break + except asyncio.TimeoutError: + pass + LOG.info("[RERUN] image loop 回放完毕") + if done_evt is not None: + done_evt.set() + # -o rerun 的收尾。之前这条路径图放完就什么都不做,结束全靠 + # rerun_audio_reader 里 `while waited < 120.0` 的兜底干等两分钟 + #(日志表现:音频推完后一串 audio=0.0pps 的 STATS,两分钟才退), + # 而且 --rerun-tail-wait-s 对它无效。 + # 判定与 esp32_image_loop 保持一致:先等音频也推完,再看模型说完没有 + #(队列空 且 不在 speak,连续保持 2s 才算),最后加 2s 尾巴。 + if peer_done is not None and not peer_done.is_set(): + LOG.info("[RERUN] 图放完,等音频推完…") + try: + await asyncio.wait_for(peer_done.wait(), timeout=180.0) + except asyncio.TimeoutError: + LOG.warning("[RERUN] 等音频超时") + _QUIET_HOLD_S, _TAIL_S = 2.0, 2.0 + _quiet_since = None + _deadline = time.monotonic() + tail_wait_s + while time.monotonic() < _deadline and not stop_evt.is_set(): + try: + pending = speaker.pending_ms() if speaker is not None else 0.0 + except Exception: + pending = 0.0 + speaking = bool(getattr(sent_tracker, "speaking", False)) if sent_tracker else False + if pending <= 50 and not speaking: + if _quiet_since is None: + _quiet_since = time.monotonic() + elif time.monotonic() - _quiet_since >= _QUIET_HOLD_S: + break + else: + _quiet_since = None + await asyncio.sleep(0.25) + try: + await asyncio.wait_for(stop_evt.wait(), timeout=_TAIL_S) + except asyncio.TimeoutError: + pass + LOG.info("[RERUN] 结束(静默保持%.1fs + 尾巴%.1fs)", _QUIET_HOLD_S, _TAIL_S) + stop_evt.set() + + +# ============================================================ +# ESP32 图像输入:TCP 5000 持久连接,请求-响应取裸 JPEG +# (摘自 demo_esp32_duplex_0703 的 TcpImageClient,接口不变) +# 帧头(20B 小端): magic(4) frame_id(4) w(2) h(2) fmt(1) reserved(3) len(4) +# ============================================================ +_ROTATE_MAP = None + + +def _rotate_jpeg(jpeg: bytes, deg: int) -> bytes: + """把相机原始帧按顺时针 deg 转正。deg ∈ {0,90,180,270},0 直接原样返回。 + + 为什么要在这里转:眼镜的摄像头是**物理侧装/倒装**的(devices.json 的 rotate), + 出来的帧本身就是歪的。不转正的话,漏斗的方向分类器会把"相机侧装" + 误判成"用户把盒子拿反了"并提示用户翻转 —— 用户翻了反而更歪。 + 取景截断的上下左右语义、_PAN_HINT 的"向上看/向下看"也全都会反。 + 所以必须在**进漏斗之前**转,转法照搬 demo_esp32_duplex_0703。 + + 注意 PIL 按逆时针算:顺时针 90° 要用 ROTATE_270。 + """ + if not deg or not jpeg: + return jpeg + global _ROTATE_MAP + try: + from PIL import Image + import io + except Exception: + return jpeg + if _ROTATE_MAP is None: + _ROTATE_MAP = { + 90: Image.Transpose.ROTATE_270, # 顺时针 90° = PIL 的 ROTATE_270 + 180: Image.Transpose.ROTATE_180, + 270: Image.Transpose.ROTATE_90, + } + op = _ROTATE_MAP.get(int(deg) % 360) + if op is None: + return jpeg + try: + im = Image.open(io.BytesIO(jpeg)) + im = im.transpose(op) + buf = io.BytesIO() + im.save(buf, format="JPEG", quality=92) + return buf.getvalue() + except Exception as e: + LOG.warning("[ROTATE] 转正失败(%d°),用原图: %r", deg, e) + return jpeg + + +class TcpImageClient: + def __init__(self, host: str, port: int = 5000, rotate: int = 0): + self.host = host + self.port = port + self.rotate = int(rotate) % 360 + self._reader: Optional[asyncio.StreamReader] = None + self._writer: Optional[asyncio.StreamWriter] = None + self._lock = asyncio.Lock() + + async def _ensure_conn(self, timeout_s: float) -> bool: + if self._reader is not None and self._writer is not None and not self._writer.is_closing(): + return True + try: + self._reader, self._writer = await asyncio.wait_for( + asyncio.open_connection(self.host, self.port), timeout=timeout_s) + sock = self._writer.get_extra_info("socket") + if sock is not None: + import socket as _s + sock.setsockopt(_s.IPPROTO_TCP, _s.TCP_NODELAY, 1) + LOG.info("[TCP-IMG] connected to %s:%d", self.host, self.port) + return True + except Exception as e: + LOG.debug("[TCP-IMG] connect failed: %s", e) + await self._close() + return False + + async def _close(self) -> None: + if self._writer is not None: + try: + self._writer.close() + except Exception: + pass + self._reader = None + self._writer = None + + async def capture(self, timeout_s: float = 1.0) -> Optional[bytes]: + async with self._lock: + if not await self._ensure_conn(timeout_s): + return None + try: + self._writer.write(b"C") + await self._writer.drain() + hdr = await asyncio.wait_for(self._reader.readexactly(20), timeout=timeout_s) + magic, frame_id, w, h = struct.unpack_from(" 4 * 1024 * 1024: + LOG.warning("[TCP-IMG] insane len=%d, reconnect", length) + await self._close() + return None + data = await asyncio.wait_for(self._reader.readexactly(length), timeout=timeout_s) + # 转正后再交给上层:latest_frame / 漏斗 / 录制拿到的都是正图, + # rerun 时不必再转(否则会转两次)。 + return _rotate_jpeg(bytes(data), self.rotate) + except asyncio.CancelledError: + raise + except Exception as e: + LOG.warning("[TCP-IMG] capture failed: %r, reconnect", e) + await self._close() + return None + + +# ============================================================ +# funnel rerun:把录制的整簇多帧当图源,复用 esp32_image_loop 重跑漏斗+播报 +# RecordedImageClient.capture() 按 frames.jsonl 每轮整簇顺序吐帧, +# funnel.run_once 调 N 次凑一簇 → 重判 send/reject → 播报/标点保护,逻辑全复用。 +# ============================================================ +class RecordedImageClient: + def __init__(self, session_dir: str, n_frames: int, no_funnel: bool = False): + import json as _json + self.dir = session_dir + self.images_dir = os.path.join(session_dir, "images") + self.n_frames = max(1, int(n_frames)) + self._rounds = [] # 每轮: [jpg_bytes, ...] + fr_path = os.path.join(session_dir, "frames.jsonl") + self._round_names = [] # 每轮的帧文件名(供 record 复用) + self._round_t = [] # 每轮录制时刻 t(秒),用于按原始时间轴回放 + with open(fr_path, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + rec = _json.loads(line) + except Exception: + continue + names = rec.get("frames") or [] + jpgs = [] + keep_names = [] + for nm in names: + p = os.path.join(self.images_dir, nm) + if os.path.isfile(p): + with open(p, "rb") as fp: + jpgs.append(fp.read()) + keep_names.append(nm) + if jpgs: + self._rounds.append(jpgs) + self._round_names.append(keep_names) + self._round_t.append(float(rec.get("t", len(self._rounds) - 1))) + LOG.info("[RERUN-IMG] 载入 %d 轮,每轮≤%d帧%s", + len(self._rounds), self.n_frames, + "(无漏斗:每轮取中间张代表帧)" if no_funnel else "(funnel:整簇逐帧)") + self._round_i = 0 + self._frame_i = 0 + self._no_funnel = no_funnel + self.exhausted = False + self._t0 = None # 回放起点(优先用外部注入的统一零点) + self.replay_t0 = None # 由 runtime 注入,与音频共用 + # 整份 record 一张图都没有(图像链路当时丢了 / 手动删空 images): + # 这是有效素材(对照:无漏斗→模型 0 图编场景;有漏斗→全程 reject no_frames)。 + # 此时不能置 exhausted,否则会被当成"图放完了"秒退;让音频推完来结束整场。 + self._no_images = (len(self._rounds) == 0) + if self._no_images: + LOG.info("[RERUN-IMG] 这份 record 没有可用图像 → 全程无图回放" + "(由音频长度决定结束)") + + def current_round_cluster(self): + """返回当前轮的整簇 (jpg_list, name_list),供无漏斗 rerun 存 record 用。""" + i = self._round_i + if 0 <= i < len(self._rounds): + return self._rounds[i], self._round_names[i] + return [], [] + + async def _wait_round_time(self): + """按录制时刻回放:等到墙钟走到本轮的 t 再吐这一轮的帧。 + + 录制时每轮耗时并不均匀(对焦轮 ~1.9s、reject 播报轮 2.3~4s),若 rerun 按 + image_loop 的固定 interval_s 匀速吃图,就会以数倍速把图吃光(实测 33s 的录制 + 11s 就放完)。音频是按真实时长回放的,用 frames.jsonl 的 t 对齐,两边同一条 + 时间轴。 + """ + if self._t0 is None: + # 优先用统一回放零点(与音频同源);没有才退回"第一次 capture 那一刻" + self._t0 = self.replay_t0 if self.replay_t0 is not None else time.monotonic() + i = self._round_i + if 0 <= i < len(self._round_t): + target = self._round_t[i] + delay = target - (time.monotonic() - self._t0) + if delay > 0: + await asyncio.sleep(min(delay, 10.0)) + + async def capture(self, timeout_s: float = 1.0): + if self._no_images: + # 全程无图:一直返回 None,但不置 exhausted(不提前结束)。 + # 有漏斗 → run_once 拿到 0 帧 → reject(no_frames) → 播"没有拿到画面"; + # 无漏斗 → 不 send → 模型 0 图 → 暴露编场景。 + await asyncio.sleep(0.05) + return None + if self._round_i >= len(self._rounds): + self.exhausted = True + return None + # 只在一轮的第一帧上等待,同一轮内的多帧连续吐(模拟原始高频抓帧) + if self._frame_i == 0: + await self._wait_round_time() + rnd = self._rounds[self._round_i] + if self._no_funnel: + # 无漏斗(对照组):每轮取一张代表帧(中间张,模拟"随手抓一张就发"), + # 每次 capture 直接进入下一轮。含模糊图会照发 → 暴露幻觉。 + jpg = rnd[len(rnd) // 2] + self._round_i += 1 + return jpg + # funnel:一帧帧吐整簇,供 run_once 调 N 次凑一簇 + jpg = rnd[self._frame_i % len(rnd)] + self._frame_i += 1 + if self._frame_i >= self.n_frames: + self._frame_i = 0 + self._round_i += 1 + return jpg + + async def _close(self): + pass + + +# ============================================================ +# ESP32 图像轮询循环:定时用 TCP 取图 -> latest_frame + harness.send_frame +# ============================================================ +async def esp32_image_loop( + client: TcpImageClient, + latest_frame: LatestFrame, + harness: HarnessClient, + stats: RuntimeStats, + interval_s: float, + timeout_s: float, + stop_evt: asyncio.Event, + probe=None, + funnel=None, + recorder=None, + speaker=None, + gateway_host: str = "127.0.0.1", + gateway_port: int = 8040, + ssl_ctx=None, + force_measure: bool = False, + manager=None, + reject_wav_dir: str = "assets/reject_wav", + sent_tracker=None, + live_rec=None, + web_ui=None, + ready_evt: Optional[asyncio.Event] = None, + tail_wait_s: float = 30.0, + no_reject: bool = False, + peer_done: Optional[asyncio.Event] = None, + done_evt: Optional[asyncio.Event] = None, +) -> None: + if ready_evt is not None: + await ready_evt.wait() + LOG.info("[ESP32] image loop start (interval=%.2fs, funnel=%s)", + interval_s, "on" if funnel else "off") + _last_grab_mono = None + + # ── 强制措施状态 ── + _funnel_stopped = False # 是否已发过 funnel.stop(在停住态,等好图 resume) + _last_hint_mono = 0.0 # 上次念提示的时刻(节流用) + _HINT_THROTTLE_S = 5.0 # 同类连续 reject 的念提示节流间隔 + _pending_reject = None # 标点保护:挂起中的 reject(等标点/超时再复查) + # ── 「持续坏」检测:3s 窗口内 reject≥2 → 判定输出基于坏图=幻觉,直接打断+压制 ── + # 覆盖"错错错对"场景(前半也错,标点保护不适用)。窗口单位=判定/chunk(每≈1s)。 + # 依据:模型拿图→输出约 1-1.5s;2s 都坏则幻觉必已在输出,必须闭嘴。 + _judge_history = [] # 最近判定时刻+是否reject: [(mono, is_reject), ...] + _WINDOW_S = 3.0 # 窗口长度 + _BAD_THRESH = 2 # 窗口内 reject≥此 → 持续坏,直接打断(跳过标点保护) + # _funnel_active:念提示临界区标志(预留给兜底:念提示那几秒真人喊话的处理) + # TODO(兜底,下次实现): 念提示期间若收到真人 STOP/RESUME/RESET, + # 先掐掉提示音(speaker.block_and_flush)+清此标志,再执行真人指令,避免撞车。 + # 当前只占位,不实现逻辑。 + _funnel_active = False # noqa: F841 (预留) + + async def _capture_one(): + return await client.capture(timeout_s=timeout_s) + + while not stop_evt.is_set(): + t0 = time.monotonic() + # funnel rerun:录制的整簇多帧放完了 → 优雅结束(不报 no_frames) + if getattr(client, "exhausted", False): + LOG.info("[FUNNEL-RERUN] 录制图已放完") + # 图轮数常少于音频秒数(drugbox 16 轮 vs 22.5s),不能图一放完就收工, + # 否则后半段音频(可能正含提问)根本没推给模型。先等音频也推完。 + if peer_done is not None and not peer_done.is_set(): + LOG.info("[FUNNEL-RERUN] 等音频推完…") + try: + await asyncio.wait_for(peer_done.wait(), timeout=180.0) + except asyncio.TimeoutError: + LOG.warning("[FUNNEL-RERUN] 等音频超时") + LOG.info("[FUNNEL-RERUN] 两条流都完事,等模型说完后结束") + # 等模型把话说完再 stop。判据不能只看"队列空"——模型是流式产出的, + # 某一瞬间队列排空只是"下一段还没到",不代表这轮结束(图少的素材尤其明显: + # 图很快放完,恰好撞上队列空,就把还没说完的话掐了)。 + # 改为:队列必须连续 _QUIET_HOLD_S 保持空,且 sent_tracker 不在 speak 中, + # 再加一段固定尾巴,给最后一句 TTS 留出播放时间。 + _QUIET_HOLD_S = 2.0 + _TAIL_S = 2.0 + _quiet_since = None + _deadline = time.monotonic() + tail_wait_s + while time.monotonic() < _deadline and not stop_evt.is_set(): + try: + pending = speaker.pending_ms() if speaker is not None else 0.0 + except Exception: + pending = 0.0 + speaking = False + if sent_tracker is not None: + speaking = bool(getattr(sent_tracker, "speaking", False)) + if pending <= 50 and not speaking: + if _quiet_since is None: + _quiet_since = time.monotonic() + elif time.monotonic() - _quiet_since >= _QUIET_HOLD_S: + break + else: + _quiet_since = None + await asyncio.sleep(0.25) + # 尾巴:让最后一句 TTS 播完,也给模型一点补充的机会 + try: + await asyncio.wait_for(stop_evt.wait(), timeout=_TAIL_S) + except asyncio.TimeoutError: + pass + LOG.info("[FUNNEL-RERUN] 结束(静默保持%.1fs + 尾巴%.1fs)", + _QUIET_HOLD_S, _TAIL_S) + stop_evt.set() + break + try: + if funnel is None: + # ── 无漏斗:取 1 帧直发(含模糊图,暴露幻觉)── + # record 仍存整簇(mp4 用全部采集帧,和有漏斗一致,只是无 reject 标注) + cluster_jpgs, cluster_names = ([], []) + if hasattr(client, "current_round_cluster"): + cluster_jpgs, cluster_names = client.current_round_cluster() + jpeg = await client.capture(timeout_s=timeout_s) + grab_ms = (time.monotonic() - t0) * 1000.0 + if jpeg: + ts = now_ms() + latest_frame.set(jpeg, ts) + stats.image_count += 1 + await harness.send_frame(jpeg, latest_frame.sequence, ts) + _emit_chunk_img(web_ui, jpeg, latest_frame.sequence, True) + if probe is not None: + since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 + probe.mark_grab(latest_frame.sequence, grab_ms, len(jpeg), since_last) + _last_grab_mono = t0 + # 存 record(无漏斗:send=True 无 reason)。 + # rerun 时图源是 RecordedImageClient,有 current_round_cluster(), + # 能拿到整簇;**实机时图源是 TcpImageClient,没有这个方法**, + # cluster_jpgs 恒为空 —— 原来写 `and cluster_jpgs` 就把实机的 + # 录制整个跳过了(实测 frames.jsonl 0 rounds、images/ 空)。 + # 实机 no_funnel 本来就是每轮一张图,拿不到整簇就用这一帧当一轮。 + if live_rec is not None: + _frames = cluster_jpgs if cluster_jpgs else [jpeg] + _dec = type("D", (), {"frames": _frames, + "best_index": len(_frames) // 2, + "send": True, "reason": ""})() + try: + await asyncio.to_thread( + live_rec.on_funnel_round, _dec, latest_frame.sequence) + # best 图也存一份(events.jsonl + img_*.jpg,供 -o rerun) + await asyncio.to_thread( + live_rec.on_frame, jpeg, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_funnel_round(no-funnel) err: %s", e) + else: + # ── 有漏斗:一轮判定,合格才 send_frame ── + decision = await funnel.run_once(_capture_one) + # 统一 record:每轮整簇多帧 + 判定 → live_rec(供三种 rerun)。 + # 必须放在所有分支之前:持续坏分支末尾有 continue,放在最后会把 + # 触发压制的那些轮整簇漏录(实测 42s 只落下 8 轮)。录制是原始素材, + # 不该因为走了哪条处理路径而缺失。 + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_funnel_round, decision, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_funnel_round err: %s", e) + grab_ms = decision.timings.get("grab_ms", 0.0) + async def _do_reject_interrupt(reason): + """真正执行打断:停 duplex → 播 wav → 恢复。""" + wav_pcm = _load_reject_wav(reject_wav_dir, reason) + if wav_pcm is None: + LOG.warning("[强制措施] 无 %s.wav,跳过播报", reason) + return + try: + await harness.send({"type": "funnel.stop", "reason": reason}) + LOG.info("[强制措施] funnel.stop 已发 (%s)", reason) + except Exception as e: + LOG.warning("[强制措施] funnel.stop 失败: %s", e) + await asyncio.sleep(0.35) # 等 STOP 经 8021→rokid→block_and_flush + try: + await speaker.resume() + await speaker.enqueue(wav_pcm, generation=0) + dur = len(wav_pcm) / 24000.0 + LOG.info("[强制措施] 播 reject wav: %s (%.2fs)", reason, dur) + if live_rec is not None: + live_rec.log_event("HINT", f"{reason} ({dur:.2f}s)") + await asyncio.sleep(dur + 0.2) + except Exception as e: + LOG.warning("[强制措施] 播 wav 失败: %s", e) + try: + await harness.send({"type": "funnel.resume", "reason": "hint_done"}) + LOG.info("[强制措施] funnel.resume 已发(提示播完)") + except Exception as e: + LOG.warning("[强制措施] funnel.resume 失败: %s", e) + + # ── 消融用:选 best 但永远放行(关闭工作③的拒绝/播报)── + # 用途:把"多帧选 best"(工作②)的收益从"拒绝坏图"(工作③)里剥出来。 + # 对照 bare(每轮取中间帧直发),本 arm 每轮取 best 直发, + # 下游模型侧完全一致,差异只来自选图。 + if no_reject: + _b = decision.best + if _b: + ts = now_ms() + latest_frame.set(_b, ts) + stats.image_count += 1 + await harness.send_frame(_b, latest_frame.sequence, ts) + _emit_chunk_img(web_ui, _b, latest_frame.sequence, True) + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_frame, _b, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_frame err: %s", e) + LOG.info("[漏斗-放行] best (原判定=%s)", decision.reason) + # 消融 arm 不执行拒绝,但**判别结果要留痕**: + # 这一轮漏斗本来会不会拦、拦的理由是什么,是分析判别倾向的依据。 + if live_rec is not None and not decision.send: + live_rec.log_event( + "WOULD-REJECT", + f"{decision.reason} {decision.hint or ''}") + else: + LOG.info("[漏斗-放行] 本轮无 best(%s),跳过", decision.reason) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + + # ── 「持续坏」检测(优先于标点保护)── + # 3s 窗口内"真坏"reject≥2 → 输出基于坏图=幻觉。此时不走标点保护 + # (前半也错,不值得保护),直接触发"停→播提示→恢复"。 + # need_focus 不算坏:它是系统正在对焦(run_once 已发 /reg 重抓), + # 属于内部自愈,不是用户造成的持续坏,算进去会误判、干扰对焦流程。 + # "真坏" = reject 且 reason 不是 need_focus(severe_shake/unstable/ + # too_dark/orient 等,要用户动手的)。 + _now = time.monotonic() + _is_real_bad = (not decision.send) and (decision.reason != "need_focus") + _judge_history.append((_now, _is_real_bad)) + _judge_history[:] = [(t, r) for (t, r) in _judge_history + if _now - t <= _WINDOW_S] + _bad_in_window = sum(1 for (_t, r) in _judge_history if r) + + if _bad_in_window >= _BAD_THRESH and _is_real_bad: + _pending_reject = None # 持续坏优先,取消标点保护挂起 + # 到这里必是"真坏"(severe_shake/unstable/too_dark/orient)。 + # 直接触发完整"停→播提示→恢复"(复用 _do_reject_interrupt, + # 停模型输出不杀死、播完恢复)。耗时≈播报时长,天然间隔。 + LOG.info("[持续坏] 3s内%d次真坏reject,打断+播提示(停→播→恢复)", + _bad_in_window) + if live_rec is not None: + live_rec.log_event( + "PERSIST-BAD", + f"3s内{_bad_in_window}次真坏 → 打断 ({decision.reason})") + await _do_reject_interrupt(decision.reason) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + + # ── 「标点保护」核心:突发 reject 不立即打断,保护当前段语音播放到 + # 下一个句末标点,到标点那一刻复查当时判定;仍 reject 才打断,否则无事。 + # 挂起期间的 send/reject 都不算数,只看"到标点那一刻"的判定。 + # (snapshot 记标点序号,boundary_reached 判断新标点+其语音已播完) + if force_measure and speaker is not None and _pending_reject is not None: + # 正在保护中:只判断"是否到标点(语音播完)或超时",到了才用当时判定复查 + now_mono = time.monotonic() + reached = (sent_tracker is not None + and sent_tracker.boundary_reached( + _pending_reject["snap"], speaker)) + timed_out = (now_mono - _pending_reject["since"]) >= 1.5 + if reached or timed_out: + # 到标点/超时 → 复查此刻判定 + if decision.send: + LOG.info("[标点保护] %s,此刻已恢复(send),无事发生", + "到标点" if reached else "超时1.5s") + _pending_reject = None + elif decision.reason == "need_focus": + _pending_reject = None # 复查是对焦,静默 + else: + # 仍 reject → 打断(受节流约束) + LOG.info("[标点保护] %s,仍 reject(%s),打断", + "到标点" if reached else "超时1.5s", decision.reason) + if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + _last_hint_mono = now_mono + _pending_reject = None + await _do_reject_interrupt(decision.reason) + else: + _pending_reject = None # 被节流 + + if decision.send and decision.best: + ts = now_ms() + latest_frame.set(decision.best, ts) + stats.image_count += 1 + await harness.send_frame(decision.best, latest_frame.sequence, ts) + LOG.info("[漏斗] send (%s)", decision.reason) + _emit_chunk_img(web_ui, decision.best, latest_frame.sequence, True) + # -o record:只录真发送给模型的 best 图(chunk_idx = sequence) + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_frame, decision.best, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_frame err: %s", e) + # 注意:send 不清 _pending_reject,保护期只看到标点那一刻 + else: + LOG.info("[漏斗] reject(%s) -> hint: %s", + decision.reason, decision.hint) + if live_rec is not None: + live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") + if force_measure and speaker is not None and decision.reason != "need_focus": + now_mono = time.monotonic() + if _pending_reject is not None: + pass # 已在保护中,上面已处理,不重复挂起 + elif sent_tracker is not None and sent_tracker.speaking: + # 模型正念字:挂起,保护到下一个标点再复查 + _pending_reject = { + "since": now_mono, + "reason": decision.reason, + "snap": sent_tracker.snapshot(), + } + LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", + decision.reason) + else: + # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) + if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + _last_hint_mono = now_mono + await _do_reject_interrupt(decision.reason) + if probe is not None: + since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 + jb = len(decision.best) if decision.best else 0 + tm = decision.timings + probe.mark_grab( + latest_frame.sequence, grab_ms, jb, since_last, + reason=decision.reason, + judge_ms=tm.get("judge_ms"), + af_ms=tm.get("af_ms"), + n_frames=tm.get("n_frames"), + ) + _last_grab_mono = t0 + except Exception as e: + LOG.warning("[ESP32] image loop error: %s", e, exc_info=True) + # 控制取图节奏 + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + LOG.info("[ESP32] image loop stopped") + + +# ============================================================ +# ESP32 Runtime:继承 rokid 的 PhaseBRokidRuntime,复用全部 harness 骨架, +# 只覆盖 start():不起 web server,改起两个 ESP32 主动拉取 task。 +# ============================================================ +from .rokid_runtime import PhaseBRokidRuntime + + +def _insecure_ssl_for_wss(url: str) -> Optional[ssl.SSLContext]: + """wss:// 且自签名证书时,返回一个不校验证书的 ssl context;ws:// 返回 None。 + + 与 rokid GatewayDuplexSession._ssl_context 同款做法(check_hostname=False, + verify_mode=CERT_NONE),用于连本地自签名的 8021。""" + if not url.lower().startswith("wss://"): + return None + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + return ctx + + +class TlsHarnessClient(HarnessClient): + """与 HarnessClient 完全一致,仅在 ws_connect 时对 wss:// 传入自签名 ssl。 + + 覆盖 run():逐行照抄父类,唯一区别是 ws_connect 多了 ssl= 参数。""" + + async def run(self) -> None: + ssl_ctx = _insecure_ssl_for_wss(self.url) + while not self._stop.is_set(): + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + self.url, heartbeat=30, max_msg_size=0, ssl=ssl_ctx + ) as ws: + self.ws = ws + self.connected = True + LOG.info("Harness connected: %s", self.url) + async for message in ws: + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in ( + aiohttp.WSMsgType.CLOSED, + aiohttp.WSMsgType.ERROR, + ): + break + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "harness.ready": + await self.manager.emit_recovery_sync() + elif message_type == "control.intent": + task = asyncio.create_task( + self.manager.handle_control(payload) + ) + self._control_tasks.add(task) + task.add_done_callback(self._control_tasks.discard) + except asyncio.CancelledError: + raise + except Exception as exc: + if not self._stop.is_set(): + LOG.warning("Harness connection failed: %s", exc) + finally: + self.connected = False + self.ws = None + if not self._stop.is_set(): + await asyncio.sleep(self.reconnect_s) + + +class PhaseBEsp32Runtime(PhaseBRokidRuntime): + """ESP32 版 runtime:I/O 从 'PC 起 server 被动收' 换成 'PC 主动拉 ESP32'。 + + __init__ / close / health / _initial_session_loop / _stats_loop 全部继承。 + 仅覆盖 start():把 Rokid 的 web server 换成 esp32_audio_reader + esp32_image_loop。 + """ + + def __init__(self, config, esp32_host, esp32_port, image_tcp_port, + image_interval_s, image_timeout_s, probe=None, + funnel=None, recorder=None, force_measure=False, + gateway_host="127.0.0.1", gateway_port=8040, + reject_wav_dir="assets/reject_wav", + live_record_dir=None, rerun_from=None, + funnel_rerun_from=None, web_ui_port=None, + record_no_media: bool = False, + rerun_tail_wait_s: float = 30.0, + no_reject: bool = False, + rotate: int = 0, **kwargs): + super().__init__(config, **kwargs) + # 用支持自签名 wss 的 harness client 替换父类建好的普通 HarnessClient, + # 并同步更新 manager.harness 引用(发遥测/镜像走同一个)。 + self.harness = TlsHarnessClient( + config.harness_url, + config.harness_client_id, + self.manager, + config.reconnect_s, + ) + self.manager.harness = self.harness + self._esp32_host = esp32_host + self._esp32_port = esp32_port + self._image_tcp_port = image_tcp_port + self._image_interval_s = image_interval_s + self._image_timeout_s = image_timeout_s + self._tcp_img = TcpImageClient(esp32_host, image_tcp_port, + rotate=int(rotate) % 360) + self._stop_evt = asyncio.Event() + self._probe = probe + self._funnel = funnel + self._recorder = recorder + self._force_measure = force_measure + self._reject_wav_dir = reject_wav_dir + self._gateway_host = gateway_host + self._gateway_port = gateway_port + # 念提示走 gateway wss /ws/chat,自签名证书 → 复用同款 insecure ssl + self._chat_ssl = _insecure_ssl_for_wss(f"wss://{gateway_host}:{gateway_port}/ws/chat") + + self._rerun_from = rerun_from + self._funnel_rerun_from = funnel_rerun_from + self._rerun_tail_wait_s = rerun_tail_wait_s + self._no_reject = no_reject + self._rotate = int(rotate) % 360 + self._replay_t0 = None # rerun 统一回放零点(就绪时设) + self._rec_client = None + # 回放两条流各自的完成标志:图轮数常少于音频秒数,谁先完都不能掐死对方 + self._audio_done = asyncio.Event() + self._image_done = asyncio.Event() + # bridge_ui 第一视角(8080)。live/rerun/funnel-rerun 都可推 img_b64。 + self._web_ui = None + if web_ui_port and WebUIServer is not None: + try: + self._web_ui = WebUIServer( + port=web_ui_port, + sessions_root=Path(live_record_dir).parent if live_record_dir + else Path("live_sessions"), + mode_info={"mode": "rerun" if (rerun_from or funnel_rerun_from) + else "live"}, + ) + except Exception as e: + LOG.warning("[UI] WebUIServer 创建失败: %s", e) + self._web_ui = None + # -o record(音+图,只存真发送的 best):和漏斗 record 并存。 + self.live_rec = (LiveRecorder(live_record_dir, no_media=record_no_media) + if live_record_dir else None) + if self.live_rec is not None: + try: + self.live_rec.attach_to_player(self.speaker) # 录 AI 音 + except Exception as e: + LOG.warning("[LIVE] attach_to_player 失败: %s", e) + + # 句子边界追踪器:包装 manager.handle_result,每个模型 chunk 更新句子/语音进度, + # 供 image_loop 的"标点保护"策略读取(reject 时保护当前段到下一个标点再复查)。 + self.sent_tracker = SentenceTracker() + self._turn_printer = TurnPrinter() + self._turn_start_ms = None # 当前 turn 的起点(session 内相对 ms) + _orig_handle_result = self.manager.handle_result + + async def _wrapped_handle_result(session, result): + try: + is_listen = bool(result.get("is_listen")) + text = str(result.get("text") or "") + end_of_turn = bool(result.get("end_of_turn")) + ab64 = str(result.get("audio_data") or "") + audio_ms = 0.0 + if ab64 and not is_listen: + n = len(base64.b64decode(ab64)) // 4 # float32 + audio_ms = n * 1000.0 / 24000.0 + self.sent_tracker.update(text, audio_ms, is_listen) + + # ── 评分用:把 chunk 碎片聚合成整段 turn,落 transcript/subtitles ── + if self.live_rec is not None: + # 先记原始逐 chunk(不依赖 end_of_turn,保证一定有东西可评分) + self.live_rec.log_model_chunk(text, is_listen, end_of_turn, audio_ms) + prev_idx = self._turn_printer.turn_idx + turn_idx_cur, full_text, turn_listen = self._turn_printer.feed( + is_listen, end_of_turn, text) + if text and self._turn_printer.turn_idx > prev_idx: + self._turn_start_ms = self.live_rec.session_ms() + # 只要拿到完整段就落盘(end_of_turn 或 listen/speak 切换冲出的) + if full_text: + end_ms = self.live_rec.session_ms() + 800 # 多挂 0.8s + start_ms = (self._turn_start_ms + if self._turn_start_ms is not None + else max(end_ms - 3000, 0)) + self.live_rec.log_turn_text(turn_idx_cur, full_text, turn_listen) + self.live_rec.log_subtitle( + start_ms=start_ms, end_ms=end_ms, text=full_text, + is_listen=turn_listen, turn_idx=turn_idx_cur) + self._turn_start_ms = None + + # 推模型文字到 bridge_ui 第一视角(type=result) + if self._web_ui is not None and getattr(self._web_ui, "live_clients", None): + asyncio.create_task(self._web_ui.emit({ + "type": "result", + "is_listen": is_listen, + "end_of_turn": end_of_turn, + "text": text, + })) + except Exception: + pass + return await _orig_handle_result(session, result) + + self.manager.handle_result = _wrapped_handle_result + + async def _gate_open_when_ready(self, ready_evt: asyncio.Event) -> None: + """等 gateway 就绪后放行回放任务。""" + try: + await self._wait_gateway_ready() + finally: + # 录制的 t0 必须和回放起点一致,否则 frames.jsonl/subtitles 的时间轴 + # 会把排队那几十秒也算进去,两个 arm 无法对齐。 + if self.live_rec is not None: + self.live_rec.start() + LOG.info("[LIVE] rerun 录制已开(就绪后启动,结束自动出 mp4)") + # 统一回放零点:音频按 40ms 绝对时钟推、图按 frames.jsonl 的 t 等待, + # 两者必须用同一个 t0,否则各自以"自己被调度到的那一刻"为零点, + # 起跑差多少全看事件循环,音图就对不齐。 + self._replay_t0 = time.monotonic() + _rc = getattr(self, "_rec_client", None) + if _rc is not None: + _rc.replay_t0 = self._replay_t0 + ready_evt.set() + + async def _wait_gateway_ready(self, timeout_s: float = 180.0) -> bool: + """等 duplex session 真正 prepared 之后再开始回放。 + + 实测:连着跑两次 rerun 时,后一次会在 gateway 排队([GW] queue position=1) + 长达 17 秒才 prepared。而回放任务从第 0 秒就推音频和图 —— 这 17 秒的输入 + 全部推给一个还不存在的 session,直接丢掉,提问就在里面,模型自然没反应。 + 更要命的是两个 arm 被吞掉的长度不一样,配对设计直接失效,而且事后从结果上 + 看不出来(长得就像"模型没回答")。所以回放前必须等就绪。 + """ + t0 = time.monotonic() + warned = False + while time.monotonic() - t0 < timeout_s: + if self._stop_evt.is_set(): + return False + try: + status = str(self.manager.health().get("gateway_status") or "") + except Exception: + status = "" + if status == "running": + waited = time.monotonic() - t0 + if waited > 1.0: + LOG.info("[RERUN] gateway 就绪(等了 %.1fs),开始回放", waited) + return True + if not warned and time.monotonic() - t0 > 3.0: + warned = True + LOG.info("[RERUN] 等 gateway session 就绪…(status=%s)", status or "?") + await asyncio.sleep(0.25) + LOG.warning("[RERUN] 等 gateway 就绪超时 %.0fs,仍开始回放(本次结果可能不可用)", + timeout_s) + return False + + async def start(self) -> None: + await self.speaker.start() + _install_asr_tap(self.harness, self.live_rec) + if self._web_ui is not None: + try: + await self._web_ui.start() + LOG.info("[UI] bridge_ui 第一视角已启动: http://localhost:%d", + self._web_ui.port) + except Exception as e: + LOG.warning("[UI] bridge_ui 启动失败: %s", e) + self._web_ui = None + # 方向分类器预热(原设计,-o 迁移时漏了):首次 process_orientation 含模型加载+ + # oneDNN 编译(~2s,甚至 5s+)。不预热的话它会推迟到第一次 accept 才现场加载, + # 卡住那一轮,且在此之前链路出不了 send(模型长时间拿不到图)。 + if self._funnel is not None: + try: + ms = await asyncio.to_thread(self._funnel.warmup_orient) + LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + except Exception as e: + LOG.warning("[预热] 方向分类器预热跳过: %s", e) + # ── rerun 模式:用录制的 session 回放(音频+best图)重跑 -o,不接实时设备 ── + if self._rerun_from: + LOG.info("[RERUN] 模式启动,回放 session: %s", self._rerun_from) + _ready = asyncio.Event() + asyncio.create_task(self._gate_open_when_ready(_ready)) + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + asyncio.create_task(rerun_audio_reader( + self._rerun_from, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._audio_done, + )), + asyncio.create_task(rerun_image_loop( + self._rerun_from, self.latest_frame, self.harness, + self.stats, self._image_interval_s, self._stop_evt, + web_ui=self._web_ui, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._image_done, + peer_done=self._audio_done, + speaker=self.speaker, sent_tracker=self.sent_tracker, + tail_wait_s=self._rerun_tail_wait_s, + )), + ] + return + # ── funnel rerun:录制的整簇多帧重跑漏斗;不加 --funnel 则为无漏斗对照组 ── + if self._funnel_rerun_from: + no_funnel = (self._funnel is None) + _ready = asyncio.Event() + asyncio.create_task(self._gate_open_when_ready(_ready)) + LOG.info("[RERUN] %s 模式启动: %s", + "无漏斗对照组" if no_funnel else "funnel 重跑漏斗+播报", + self._funnel_rerun_from) + n_frames = getattr(self._funnel, "n_frames", 3) if self._funnel else 3 + rec_client = RecordedImageClient(self._funnel_rerun_from, n_frames, + no_funnel=no_funnel) + self._rec_client = rec_client # 就绪时注入统一零点 + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + asyncio.create_task(rerun_audio_reader( + self._funnel_rerun_from, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._audio_done, + )), + # 复用完整 esp32_image_loop(run_once 重判 + reject 停播恢复 + 标点保护), + # 只把图源从 TCP 换成 RecordedImageClient(读录制整簇多帧)。 + asyncio.create_task(esp32_image_loop( + rec_client, self.latest_frame, self.harness, self.stats, + self._image_interval_s, self._image_timeout_s, self._stop_evt, + probe=self._probe, funnel=self._funnel, recorder=None, + speaker=self.speaker, + gateway_host=self._gateway_host, gateway_port=self._gateway_port, + ssl_ctx=self._chat_ssl, force_measure=self._force_measure, + manager=self.manager, + reject_wav_dir=self._reject_wav_dir, + sent_tracker=self.sent_tracker, + live_rec=self.live_rec, # 开 --record-live 则录 rerun 输出→自动出 mp4 + web_ui=self._web_ui, ready_evt=_ready, + tail_wait_s=self._rerun_tail_wait_s, + no_reject=self._no_reject, + peer_done=self._audio_done, done_evt=self._image_done, + )), + ] + return + # 设 ESP32 分辨率为 HD(1280×720)。固件默认 SVGA(800×600),但漏斗阈值是按 HD + # 标定的(cam_pipeline_v2 注释:分辨率固定 HD 后针对 HD 标定)。-o 迁移时漏了这步, + # 导致一直跑 SVGA、画质与阈值不匹配。这里启动时补上。 + if self._funnel is not None: + ok = await asyncio.to_thread(self._funnel.set_resolution_hd) + LOG.info("[ESP32] 设分辨率 1280×720(UXGA档): %s", + "成功" if ok else "失败(检查ESP32 /control)") + await asyncio.sleep(0.3) # 切分辨率后固件重配,稍等 + if self.live_rec is not None: + self.live_rec.start() + LOG.info("[LIVE] -o record started") + self._tasks = [ + # ── 继承自 rokid 的三个骨架 task ── + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + # ── ESP32 特有:主动拉取音视频 ── + asyncio.create_task(esp32_audio_reader( + self._esp32_host, self._esp32_port, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + probe=self._probe, + live_rec=self.live_rec, + )), + asyncio.create_task(esp32_image_loop( + self._tcp_img, self.latest_frame, self.harness, self.stats, + self._image_interval_s, self._image_timeout_s, self._stop_evt, + probe=self._probe, funnel=self._funnel, recorder=self._recorder, + speaker=self.speaker, + gateway_host=self._gateway_host, gateway_port=self._gateway_port, + ssl_ctx=self._chat_ssl, force_measure=self._force_measure, + manager=self.manager, + reject_wav_dir=self._reject_wav_dir, + sent_tracker=self.sent_tracker, + live_rec=self.live_rec, + web_ui=self._web_ui, + no_reject=self._no_reject, + )), + ] + + async def close(self) -> None: + self._stop_evt.set() + if self._web_ui is not None: + try: + await self._web_ui.stop() + except Exception: + pass + if self.live_rec is not None: + try: + # 冲掉还没等到 end_of_turn 的那段(bare 组常见:模型一路流式说, + # 没有 stop/resume 打断,end_of_turn 迟迟不来 → 整段丢失) + tp = getattr(self, "_turn_printer", None) + if tp is not None and getattr(tp, "_in_turn", False): + pending = "".join(getattr(tp, "_turn_text", [])) + if pending: + end_ms = self.live_rec.session_ms() + start_ms = (self._turn_start_ms + if self._turn_start_ms is not None + else max(end_ms - 3000, 0)) + self.live_rec.log_turn_text(tp.turn_idx, pending, + bool(tp._turn_is_listen)) + self.live_rec.log_subtitle( + start_ms=start_ms, end_ms=end_ms, text=pending, + is_listen=bool(tp._turn_is_listen), turn_idx=tp.turn_idx) + LOG.info("[LIVE] 冲出未收尾的 turn #%d (%d字)", + tp.turn_idx, len(pending)) + except Exception as e: + LOG.warning("[LIVE] flush pending turn err: %s", e) + try: + self.live_rec.stop() + LOG.info("[LIVE] -o record stopped") + except Exception as e: + LOG.warning("[LIVE] stop err: %s", e) + await self._tcp_img._close() + if self._probe is not None: + self._probe.close() + if self._recorder is not None: + self._recorder.close() + await super().close() + + +def parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser(description="ESP32 Phase B Harness runtime") + # ── ESP32 设备 ── + p.add_argument("--esp32-host", required=True, help="ESP32 IP address") + p.add_argument("--rotate", type=int, default=0, choices=(0, 90, 180, 270), + help="摄像头顺时针旋转角度,按眼镜侧装方向填" + "(取自 devices.json 的 rotate)。在进漏斗前转正," + "否则方向检测会把相机侧装误判成用户拿反了。") + p.add_argument("--esp32-port", type=int, default=80, help="ESP32 HTTP/WS port") + p.add_argument("--image-tcp-port", type=int, default=5000, help="ESP32 TCP image port") + p.add_argument("--image-interval-s", type=float, default=1.0, help="取图间隔(秒)") + p.add_argument("--image-timeout-s", type=float, default=1.0, help="单次取图超时(秒)") + # ── gateway / harness(与 rokid 一致)── + p.add_argument("--gateway", default="localhost:8040") + p.add_argument("--gateway-proto", default="auto", + choices=("auto", "duplex", "realtime"), + help="gateway 协议。duplex=/ws/duplex(V1);" + "realtime=/v1/realtime(V2,V2 gateway 只有这个端点," + "连 /ws/duplex 会被 403 拒绝);" + "auto=按端口猜(8006→realtime,其余→duplex)") + p.add_argument("--gateway-tls", action="store_true", default=True) + p.add_argument("--no-tls", dest="gateway_tls", action="store_false") + p.add_argument("--harness-url", default="ws://127.0.0.1:8021/ws/control") + p.add_argument("--client-id", default="esp32-phase-b") + p.add_argument("--skills-config", default=default_skills_config()) + p.add_argument("--cleanup-mode", choices=("light", "full"), default="light") + p.add_argument("--chunk-ms", type=int, default=1_000) + p.add_argument("--force-listen-count", type=int, default=3) + p.add_argument("--audio-queue-packets", type=int, default=96) + p.add_argument("--input-gain", type=float, default=12.0) + p.add_argument("--prompt", default=None, help="system prompt(可选)") + p.add_argument("--no-play", action="store_true") + p.add_argument("--log-level", default="INFO") + # ── 时序探针(纯旁路)── + p.add_argument("--timing-probe", action="store_true", help="开启时序探针,写 CSV") + p.add_argument("--timing-csv", default=None, help="探针 CSV 路径(默认自动带时间戳)") + # ── CV 漏斗 ── + p.add_argument("--funnel", action="store_true", help="开启 CV 漏斗(抓N帧判定,合格才送模型)") + p.add_argument("--scene", default="medicine", choices=("medicine", "stationery"), + help="漏斗场景参数") + p.add_argument("--funnel-frames", type=int, default=3, help="每轮抓帧数(3选2)") + p.add_argument("--no-focus", dest="funnel_focus", action="store_false", default=True, + help="关闭漏斗内的自动对焦触发") + # ── session 录制(对齐 -v 格式)── + p.add_argument("--record", action="store_true", help="录 session(整簇帧+判定到 sessions/)") + p.add_argument("--sessions-root", default="sessions", help="session 根目录") + p.add_argument("--no-reject", action="store_true", + help="消融:漏斗只选 best、永远放行,不拒绝不播报" + "(用于把工作②选图的收益与工作③拒绝分开)") + p.add_argument("--rerun-tail-wait-s", type=float, default=30.0, + help="rerun 图放完后,最多再等模型说完的秒数(默认30)") + p.add_argument("--record-no-media", action="store_true", + help="批量评分用:只写 wav+jsonl+transcript,跳过 jpg 落盘和 mp4 拼接") + p.add_argument("--record-live", action="store_true", + help="-o record:录音+图(只存真发送的best)到 live_sessions/,供 -o rerun") + p.add_argument("--rerun-from", default=None, + help="-o rerun:从 live_sessions/ 回放(音+best图)重跑 -o 模型") + p.add_argument("--funnel-rerun-from", default=None, + help="funnel rerun:从 live_sessions/ 回放(音+整簇多帧)重跑漏斗+播报+-o") + p.add_argument("--web-ui-port", type=int, default=None, + help="开 bridge_ui 第一视角(如 8080),live/rerun/funnel-rerun 都可看") + # ── 强制措施(防幻觉):reject 时用模型音色念提示 + 停/恢复走 8021 ── + p.add_argument("--force-measure", action="store_true", + help="开启强制措施:reject→停duplex→播预生成wav→恢复duplex") + p.add_argument("--reject-wav-dir", default="assets/reject_wav", + help="预生成的 reject 提示 wav 目录(gen_reject_wavs.py 生成)") + return p.parse_args() + + +def main() -> None: + args = parse_args() + logging.basicConfig( + level=getattr(logging, args.log_level.upper(), logging.INFO), + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + force=True, + ) + config = RokidRuntimeConfig( + gateway=args.gateway, + gateway_tls=args.gateway_tls, + harness_url=args.harness_url, + harness_client_id=args.client_id, + skills_config=args.skills_config, + cleanup_mode=args.cleanup_mode, + chunk_ms=args.chunk_ms, + force_listen_count=args.force_listen_count, + audio_queue_packets=args.audio_queue_packets, + input_gain=args.input_gain, + play_audio=not args.no_play, + ) + probe = TimingProbe( + enabled=args.timing_probe, + path=args.timing_csv, + chunk_ms=args.chunk_ms, + ) + funnel = None + if args.funnel: + # rerun 时强制关对焦:rerun 没有真实相机,trigger_af 对录制的图无意义, + # 且对焦重抓会让 run_once 多抓一簇 → RecordedImageClient 多消耗一个 round + # → 图提前用光(有漏斗比无漏斗先用光的根因)。 + _is_rerun = bool(args.rerun_from or args.funnel_rerun_from) + _focus = args.funnel_focus and not _is_rerun + funnel = FunnelGate( + args.esp32_host, + scene=args.scene, + n_frames=args.funnel_frames, + enable_focus=_focus, + ) + LOG.info("CV 漏斗已开启: scene=%s frames=%d focus=%s%s", + args.scene, args.funnel_frames, _focus, + "(rerun 强制关对焦)" if (_is_rerun and args.funnel_focus) else "") + recorder = None # 旧 SessionRecorder 已废弃,统一走 LiveRecorder + # 统一 record(音+整簇多帧+best标记):--record 或 --record-live 都触发。 + live_record_dir = None + if args.record or args.record_live or args.record_no_media: + import time as _t + live_record_dir = os.path.join("live_sessions", _t.strftime("%Y%m%d_%H%M%S")) + # 日志同时落进 session 目录:评分时要按时间轴对齐 reject/播报/模型输出, + # 控制台日志是滚动的、和 session 分离,跑多组 rerun 极易对错。 + try: + os.makedirs(live_record_dir, exist_ok=True) + _fh = logging.FileHandler( + os.path.join(live_record_dir, "run.log"), encoding="utf-8") + _fh.setFormatter(logging.Formatter( + "%(asctime)s %(levelname)s %(name)s: %(message)s")) + logging.getLogger().addHandler(_fh) + LOG.info("[LIVE] 日志同时写入 %s", os.path.join(live_record_dir, "run.log")) + except Exception as e: + LOG.warning("[LIVE] run.log 创建失败: %s", e) + os.makedirs(live_record_dir, exist_ok=True) + LOG.info("统一 record 已开启: %s(音+整簇多帧+best标记,供三种 rerun)", live_record_dir) + # 解析 gateway "host:port"(念提示的 chat TTS 走同一个 gateway 的 wss) + _gw = args.gateway.split("://")[-1] + _gw_host, _, _gw_port = _gw.partition(":") + _gw_host = _gw_host or "127.0.0.1" + _gw_port = int(_gw_port or "8040") + # 选 gateway 协议。V2 gateway 只有 /v1/realtime(连 /ws/duplex 会 403), + # V1 只有 /ws/duplex。auto 按端口猜:8006 是 V2 的默认端口。 + _proto = args.gateway_proto + if _proto == "auto": + _proto = "realtime" if _gw_port == 8006 else "duplex" + _factory = None + if _proto == "realtime": + from .realtime_session import RealtimeDuplexSession as _factory + LOG.info("[GW] 协议: /v1/realtime (V2)") + else: + LOG.info("[GW] 协议: /ws/duplex (V1)") + + runtime = PhaseBEsp32Runtime( + config, + **({"session_factory": _factory} if _factory else {}), + esp32_host=args.esp32_host, + esp32_port=args.esp32_port, + image_tcp_port=args.image_tcp_port, + image_interval_s=args.image_interval_s, + image_timeout_s=args.image_timeout_s, + probe=probe, + funnel=funnel, + recorder=recorder, + force_measure=args.force_measure, + reject_wav_dir=args.reject_wav_dir, + gateway_host=_gw_host, + gateway_port=_gw_port, + live_record_dir=live_record_dir, + rerun_from=args.rerun_from, + funnel_rerun_from=args.funnel_rerun_from, + web_ui_port=args.web_ui_port, + record_no_media=args.record_no_media, + rerun_tail_wait_s=args.rerun_tail_wait_s, + no_reject=args.no_reject, + rotate=args.rotate, + ) + if args.force_measure: + LOG.info("强制措施已开启: reject→funnel.stop+念提示, good→funnel.resume " + "(节流5s, chat TTS via wss://%s:%d)", _gw_host, _gw_port) + + LOG.info("ESP32 Phase B input: ws://%s:%d/ws_audio_v2 + TCP:%d", + args.esp32_host, args.esp32_port, args.image_tcp_port) + LOG.info("Harness: %s", config.harness_url) + LOG.info("Gateway: %s://%s", "wss" if config.gateway_tls else "ws", config.gateway) + if args.rotate: + LOG.info("[ROTATE] 摄像头顺时针 %d° 转正(进漏斗前)", args.rotate) + + async def _run() -> None: + await runtime.start() + stop = asyncio.Event() + + def _sig(*_a): + stop.set() + try: + loop = asyncio.get_running_loop() + for s in (signal.SIGINT, getattr(signal, "SIGBREAK", signal.SIGINT)): + try: + loop.add_signal_handler(s, stop.set) + except (NotImplementedError, ValueError): + signal.signal(s, _sig) + except Exception: + signal.signal(signal.SIGINT, _sig) + # 等"信号(Ctrl+C)"或"runtime 内部 stop_evt(rerun 图放完自动结束)"任一触发 + _internal = getattr(runtime, "_stop_evt", None) + waiters = [asyncio.create_task(stop.wait())] + if _internal is not None: + waiters.append(asyncio.create_task(_internal.wait())) + await asyncio.wait(waiters, return_when=asyncio.FIRST_COMPLETED) + for w in waiters: + w.cancel() + await runtime.close() + + try: + asyncio.run(_run()) + except KeyboardInterrupt: + LOG.info("Interrupted; shutting down") + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/funnel_gate.py b/extensions/assistive_harness/phase_b/funnel_gate.py new file mode 100644 index 0000000..fe683a7 --- /dev/null +++ b/extensions/assistive_harness/phase_b/funnel_gate.py @@ -0,0 +1,218 @@ +"""漏斗闸门(接入 -o 链路)。 + +把 cam_pipeline_v2 的 run_funnel / process_orientation / CamControl 封装成 +"一轮漏斗判定",供 esp32_runtime 在图像循环里调用: + + gate = FunnelGate(esp32_host, scene="medicine", n_frames=3) + result = await gate.run_once(capture_fn) # capture_fn: async ()->Optional[bytes] + +返回 FunnelDecision: + send : bool 是否放行给模型 + best : bytes|None 放行的最佳帧(已做倒置纠正) + reason : str 决策原因(accepted/severe_shake/unstable/need_focus/orient...) + hint : str|None 拒绝时给用户的提示文本(先输出 text,TTS 通道待定) + timings: dict grab_ms / judge_ms / orient_ms / af_ms / n_frames + +设计依据(防漂移文档 + cam_pipeline_v2): + - 判定唯一 = run_funnel 的 frame_score 三出口 + argmin 归因 + - need_focus → 触发单次 AF(0x3022) → 等 AF_SETTLE_MS → 重抓一簇 → 重判 + - 倒置 = process_orientation,flipped 时纠正或提示 + - 拒绝 reason → HINTS 文本 +本模块只做"输入端把关+引导",不碰模型输出侧(那是 harness 的事)。 +""" +from __future__ import annotations + +import asyncio +import time +from typing import Awaitable, Callable, Optional + +from . import cam_pipeline_v2 as cp + +AF_SETTLE_MS = 120 # OV5640 单次对焦 settle(与 v5 一致) + +# reject_reason -> 用户提示(先输出 text;TTS 通道确定后接同一份文本) +HINTS = { + "no_frames": "没有拿到画面,请稍等", + "severe_shake": "画面晃得厉害,请先保持不动", + "unstable": "画面还在晃动,请保持不动一会儿", + "too_dark": "光线太暗,请到亮一点的地方", + "aimed_wrong": "好像没对准,请对准目标", + "need_focus": "对焦中,请拿稳一下", + "orient": "画面好像反了,请倒过来", +} + + +class FunnelDecision: + __slots__ = ("send", "best", "reason", "hint", "timings", + "frames", "best_index", "af_triggered", "af_ok") + + def __init__(self, send, best, reason, hint, timings, + frames=None, best_index=-1, af_triggered=False, af_ok=None): + self.send = send + self.best = best + self.reason = reason + self.hint = hint + self.timings = timings + self.frames = frames or [] # 整簇帧(存 session 用) + self.best_index = best_index # best 在簇里的下标 + self.af_triggered = af_triggered # 本轮有没有触发 AF + self.af_ok = af_ok # AF /reg 请求是否返回成功(None=没触发) + + +class FunnelGate: + def __init__(self, esp32_host: str, scene: str = "medicine", + n_frames: int = 3, frame_gap_s: float = 0.0, + enable_focus: bool = True): + self.scene = scene + self.n_frames = n_frames + self.frame_gap_s = frame_gap_s + self.enable_focus = enable_focus + self._cfg = (cp.make_scene_config(scene) + if hasattr(cp, "make_scene_config") else cp.FunnelConfig()) + # 相机 HTTP 控制走 /control、/reg 到 ESP32(同 esp32_host)。 + # camctl 总是构造:分辨率(set_resolution)独立于对焦,即使不对焦也要设 HD。 + # 对焦(trigger_af)另受 enable_focus 控制。 + self._camctl = cp.CamControl(esp32_host) + self._last_af_mono = 0.0 # 上次真正触发对焦的时刻(冷却用) + self._af_cooldown_s = 2.0 # 对焦冷却:2s 内最多触发 1 次(避免每秒对焦) + + def warmup_orient(self) -> float: + """方向分类器预热(同步,调用方放线程里)。 + + 原设计(-v pc_vlm_v5_funnel):首次 process_orientation 含模型加载 + oneDNN + 编译开销(实测 ~2s,本次日志里甚至 5.76s),启动时先跑一张假图,把这笔一次性 + 开销挪到启动阶段,运行时 orient_ms 就是纯推理(md 记录:2143ms → 9ms)。 + -o 迁移时漏了这步 → orient 直到第一次 accept 才现场加载,卡住那一轮, + 且在此之前链路出不了 send。返回首次耗时(ms)。 + """ + import numpy as _np + import cv2 as _cv2 + _warm = _np.full((480, 640, 3), 255, dtype=_np.uint8) + ok, buf = _cv2.imencode(".jpg", _warm) + if not ok: + return -1.0 + t0 = time.monotonic() + cp.process_orientation(buf.tobytes()) + return (time.monotonic() - t0) * 1000.0 + + def set_resolution_hd(self, retries: int = 5, gap_s: float = 0.6) -> bool: + """设 1280×720(UXGA档,这块 OV5640 枚举非标准,HD(11)无效、UXGA(13)才 720p)。 + live 启动时 ESP32 可能刚就绪,/control 偶发失败 → 重试几次,避免要手动进网页设。 + 失败时打详细原因(status/异常),不再静默。""" + import logging as _lg + _log = _lg.getLogger("funnel_gate") + for i in range(max(1, retries)): + try: + ok = self._camctl.set_resolution("UXGA") + if ok: + if i > 0: + _log.info("[funnel_gate] set_resolution(UXGA) 第%d次重试成功", i + 1) + return True + _log.warning("[funnel_gate] set_resolution(UXGA) 返回非200 (第%d/%d次)", + i + 1, retries) + except Exception as e: + _log.warning("[funnel_gate] set_resolution(UXGA) 异常 (第%d/%d次): %r", + i + 1, retries, e) + time.sleep(gap_s) + return False + + async def _grab_burst( + self, capture_fn: Callable[[], Awaitable[Optional[bytes]]], n: int + ) -> list[bytes]: + frames: list[bytes] = [] + for i in range(n): + jpeg = await capture_fn() + if jpeg: + frames.append(jpeg) + if self.frame_gap_s > 0 and i < n - 1: + await asyncio.sleep(self.frame_gap_s) + return frames + + async def run_once( + self, capture_fn: Callable[[], Awaitable[Optional[bytes]]] + ) -> FunnelDecision: + """跑一轮漏斗:抓 N 帧 -> run_funnel -> (need_focus 则对焦重抓) -> 倒置 -> 决策。""" + timings: dict = {} + + # 1) 抓一簇 + t0 = time.monotonic() + frames = await self._grab_burst(capture_fn, self.n_frames) + timings["grab_ms"] = round((time.monotonic() - t0) * 1000, 1) + timings["n_frames"] = len(frames) + if not frames: + return FunnelDecision(False, None, "no_frames", HINTS["no_frames"], timings) + + # 2) run_funnel 判定(run_funnel 是同步的,放线程池避免阻塞事件循环) + tj = time.monotonic() + res = await asyncio.to_thread(cp.run_funnel, frames, self._cfg) + timings["judge_ms"] = round((time.monotonic() - tj) * 1000, 1) + timings["af_ms"] = 0.0 + af_triggered = False + af_ok = None + + # 3) need_focus -> 触发单次 AF -> 等 settle -> 重抓 -> 重判 + # 对焦冷却:need_focus 但距上次对焦 < _af_cooldown_s(2s) 时不重复触发, + # 给对焦时间生效(每秒对焦太快,马达反复动反而对不好)。冷却内仍 need_focus + # 就用当前帧判定(该 reject 就 reject,不重抓)。 + if res.need_focus and self.enable_focus and self._camctl is not None: + _now = time.monotonic() + if _now - self._last_af_mono >= self._af_cooldown_s: + self._last_af_mono = _now + taf = _now + af_triggered = True + af_ok = await asyncio.to_thread(self._camctl.trigger_af) # True/False + await asyncio.sleep(AF_SETTLE_MS / 1000.0) + frames2 = await self._grab_burst(capture_fn, self.n_frames) + if frames2: + res = await asyncio.to_thread(cp.run_funnel, frames2, self._cfg) + frames = frames2 + timings["af_ms"] = round((time.monotonic() - taf) * 1000, 1) + timings["n_frames"] = len(frames) + else: + # 冷却期内:不重复对焦,用当前判定结果 + timings["af_cooldown"] = round(self._af_cooldown_s - (_now - self._last_af_mono), 2) + timings["af_ok"] = af_ok + + def _mk(send, best, reason, hint): + bi = frames.index(best) if (best in frames) else -1 + return FunnelDecision(send, best, reason, hint, timings, + frames=frames, best_index=bi, + af_triggered=af_triggered, af_ok=af_ok) + + # 4) 拒绝出口 + if not res.accepted: + reason = res.reject_reason or "reject" + # cam_pipeline 的拒绝出口只设 best_index(注释:仅供参考, 不喂模型), + # 不设 best_jpg —— 这是原设计意图:拒绝就不送图。 + # 但消融 arm(--no-reject:只选 best、永远放行)需要拿到这一帧, + # 所以这里按 best_index 把帧补出来。**send 仍然是 False**, + # 正常链路完全不受影响:只有显式开了 --no-reject 才会去用它。 + _bj = res.best_jpg + if _bj is None: + bi = getattr(res, "best_index", -1) + if isinstance(bi, int) and 0 <= bi < len(frames): + _bj = frames[bi] + return _mk(False, _bj, reason, + HINTS.get(reason, "看不清楚,请调整一下")) + + # 5) 接受帧的方向检测(OCR 方向分类器优先,见 cam_pipeline.process_orientation) + # 原则「宁拒绝不念错」:方向不正 -> 拒绝 + 提示用户转正,绝不自动纠正、绝不送倒图。 + # process_orientation 只诊断方向、返回的 jpg 未旋转,故不能拿它当"纠正后"送模型。 + best = res.best_jpg + to_ = time.monotonic() + try: + _jpg, geom = await asyncio.to_thread(cp.process_orientation, best) + except Exception: + geom = {"ok": False} + timings["orient_ms"] = round((time.monotonic() - to_) * 1000, 1) + + orient_state = geom.get("orient_state") if isinstance(geom, dict) else None + orient_hint = geom.get("orient_hint") if isinstance(geom, dict) else None + + # upright 才放行;flipped/sideways 拒绝并提示;uncertain 也放行(不硬拦,避免误拒) + if orient_state in ("flipped", "sideways"): + hint = orient_hint or HINTS["orient"] + return _mk(False, best, "orient_" + orient_state, hint) + + # upright / uncertain / 检测不可用 -> 放行原图(不做任何旋转) + return _mk(True, best, "send", None) diff --git a/extensions/assistive_harness/phase_b/realtime_session.py b/extensions/assistive_harness/phase_b/realtime_session.py new file mode 100644 index 0000000..c0e4435 --- /dev/null +++ b/extensions/assistive_harness/phase_b/realtime_session.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +realtime_session.py —— 把 duplex 会话接到 V2 gateway 的 /v1/realtime 协议。 + +为什么需要它 +------------ +V1 gateway 有 `/ws/duplex/{session_id}`;**V2 gateway 只有 `/v1/realtime`** +(实测:V2 gateway.py 里唯一的 @app.websocket 是 /v1/realtime, + 连 /ws/duplex/... 会被 FastAPI 直接 403 拒绝握手)。 +所以 rokid_runtime / esp32_runtime 里那套 GatewayDuplexSession 在 V2 下连不上, +demo_esp32_duplex_0703 同样连不上(它连的也是 /ws/duplex)。 + +做法 +---- +`GatewaySessionManager` 有现成的替换点 `session_factory`, +所以这里**继承 GatewayDuplexSession,只覆盖协议相关的方法**, +其余(音频攒块、状态管理、start/_run 骨架、stop 的收尾)全部复用。 +rokid_runtime.py 和 esp32_runtime.py 都不用改,只在构造 manager 时传入本类。 + +协议对照(V1 内部 → V2 对外) +------------------------------ + 连接 URL 带 session_id → 连上后 session.init,服务端回 session.created + 排队 queued / queue_done → session.queued / session.queue_done + 上行 audio_chunk → input.append + audio_base64 → input.audio + frame_base64_list → input.video_frames + force_listen → input.force_listen + 下行 {is_listen,text,audio_data}→ response.output.delta 的 kind: listen/text/audio + 结束 stop → session.close + +注意 +---- +· V2 的 session_id 由服务端在 session.created 里给,客户端不能自己指定。 + 但 manager/日志里到处用 self.session_id,所以保留本地生成的那个作为占位, + 拿到服务端的之后覆盖掉。 +· full-duplex 下没有 response.done(文档说它只用于 mode=chat), + turn 边界靠 delta 里的 turn_id 变化判断。 +· kind=audio 的 PCM 是 24kHz mono float32 base64,和 V1 的 audio_data 同格式, + 所以 on_result 那一侧不用改。 +""" +from __future__ import annotations + +import asyncio +import base64 +import json +import time +from typing import Any + +import aiohttp +import numpy as np + +from .rokid_runtime import ( + LOG, + GatewayDuplexSession, + SAMPLE_RATE_IN, + float32_to_base64, + now_ms, +) + + +class RealtimeDuplexSession(GatewayDuplexSession): + """V2 /v1/realtime 协议版的 duplex 会话。构造签名与父类完全一致。""" + + # ------------------------------------------------------------ 连接 + async def _run(self) -> None: + scheme = "wss" if self.config.gateway_tls else "ws" + # mode=video:连续音频 + 可带视频帧,300s 上限。 + # mode=audio 是纯音频(600s),我们要送图所以用 video。 + url = f"{scheme}://{self.config.gateway}/v1/realtime?mode=video" + self.status = "connecting" + LOG.info("[GW] connecting generation=%d %s (realtime)", + self.spec.generation, url) + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + url, + heartbeat=30, + ssl=self._ssl_context(), + max_msg_size=0, + ) as ws: + self.ws = ws + await self._prepare(ws) + self.status = "running" + if self._ready is not None and not self._ready.done(): + self._ready.set_result(None) + await asyncio.gather( + self._send_loop(ws), + self._receive_loop(ws), + ) + except asyncio.CancelledError: + raise + except Exception as exc: # noqa: BLE001 + self.status = "failed" + self.last_error = str(exc) + LOG.warning("[GW] session %s failed: %s", self.session_id, exc) + if self._ready is not None and not self._ready.done(): + self._ready.set_exception(exc) + finally: + self._stopped.set() + if self.status not in ("failed",): + self.status = "closed" + + # ------------------------------------------------------------ 握手 + async def _prepare(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """等 session.queue_done → 发 session.init → 等 session.created。 + + 文档明确要求:**必须等 queue_done 再发 session.init**。 + 没有排队时服务端会立刻下发 queue_done。 + """ + self.status = "queued" + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while queued") + continue + payload = json.loads(message.data) + mtype = payload.get("type") + if mtype == "session.queue_done": + break + if mtype == "error": + raise RuntimeError( + (payload.get("error") or {}).get("message") + if isinstance(payload.get("error"), dict) + else payload.get("error") or "gateway queue error" + ) + if mtype in ("session.queued", "session.queue_update"): + LOG.info("[GW] queue position=%s eta=%s", + payload.get("position"), + payload.get("estimated_wait_s")) + + self.status = "preparing" + init_payload: dict[str, Any] = { + "system_prompt": self.spec.system_prompt, + "config": { + "force_listen_count": self.config.force_listen_count, + "chunk_ms": self.config.chunk_ms, + "generate_audio": True, + "max_new_speak_tokens_per_chunk": ( + self.config.max_new_speak_tokens_per_chunk + ), + "length_penalty": self.config.length_penalty, + }, + } + await self._send_json({"type": "session.init", "payload": init_payload}) + + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while preparing") + continue + payload = json.loads(message.data) + mtype = payload.get("type") + if mtype == "session.created": + # session_id 由服务端给,覆盖本地占位的那个 + sid = payload.get("session_id") + if sid: + self.session_id = sid + LOG.info("[GW] prepared session=%s generation=%d skill=%s mode=%s", + self.session_id, self.spec.generation, + self.spec.skill_id, payload.get("mode")) + return + if mtype == "error": + raise RuntimeError( + (payload.get("error") or {}).get("message") + if isinstance(payload.get("error"), dict) + else payload.get("error") or "gateway prepare error" + ) + + # ------------------------------------------------------------ 上行 + async def _send_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """攒 1s 音频 + 带上最新帧,发 input.append。 + + 攒块、取帧、force_listen 的判断逻辑与父类完全一致,只换消息外壳。 + """ + carry = bytearray() + last_frame_sequence = -1 + last_frame_sent = 0.0 + sent = 0 + while not self._closing: + audio = await self._next_audio_chunk(carry) + if audio is None: + continue + inp: dict[str, Any] = { + "audio": float32_to_base64(audio), + "max_slice_nums": self.config.max_slice_nums, + } + if self.gate.speech_hold_active: + inp["force_listen"] = True + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + frame_due = time.monotonic() - last_frame_sent >= self.config.image_resend_s + if ( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + and (frame.sequence != last_frame_sequence or frame_due) + ): + inp["video_frames"] = [base64.b64encode(frame.jpeg).decode("ascii")] + last_frame_sequence = frame.sequence + last_frame_sent = time.monotonic() + sent += 1 + LOG.debug("[GW-SEND] #%d audio=%.2fs lvl=%.4f frame=%s hold=%s", + sent, len(audio) / SAMPLE_RATE_IN, + float(np.abs(audio).mean()), + "video_frames" in inp, self.gate.speech_hold_active) + await self._send_json({"type": "input.append", "input": inp}) + + # ------------------------------------------------------------ 下行 + async def _receive_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """把 response.output.delta 翻译回 {is_listen, text, audio_data}。 + + 父类的 on_result 拿到的是 V1 那套字段,这里保持不变, + 所以 handle_result / TurnPrinter / speaker 那一侧一行都不用改。 + """ + cur_turn = None + async for message in ws: + if self._closing: + break + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + break + continue + payload = json.loads(message.data) + mtype = payload.get("type") + + if mtype == "response.output.delta": + kind = payload.get("kind") + turn = payload.get("turn_id") + # full-duplex 没有 response.done,用 turn_id 变化当边界 + end_of_turn = (cur_turn is not None and turn is not None + and turn != cur_turn) + if turn is not None: + cur_turn = turn + result: dict[str, Any] = { + "type": "result", + "is_listen": kind == "listen", + "text": payload.get("text") or "", + "audio_data": payload.get("audio") or "", + "end_of_turn": end_of_turn, + "turn_id": turn, + } + await self.on_result(self, result) + continue + + if mtype == "response.done": + # 实测:full-duplex 下**也会**发 response.done(文档说只用于 chat, + # 与实际不符),而且它的 text 是这一段的**完整文本** —— + # 前面 delta 已经把这些字逐块传下去了,这里再传一次就是重复 + # (实测每段都被记两遍,只差 1~2ms)。 + # 所以这里只标记 turn 结束,**不再传 text**。 + await self.on_result(self, { + "type": "result", "is_listen": False, + "text": "", "audio_data": "", + "end_of_turn": True, "turn_id": cur_turn, + }) + continue + + if mtype == "session.closed": + LOG.info("[GW] session.closed reason=%s", payload.get("reason")) + break + + if mtype == "error": + err = payload.get("error") + msg = err.get("message") if isinstance(err, dict) else str(err) + LOG.warning("[GW] error: %s", msg) + self.last_error = msg or "gateway error" + continue + + if mtype == "debug": + # V2 自带的阶段追踪(llm.chunk / tts.chunk / t2w.chunk,带 ts)。 + # 平时不打,需要时 --log-level DEBUG 打开看服务端各阶段耗时。 + LOG.debug("[GW-DEBUG] %s", json.dumps(payload, ensure_ascii=False)[:200]) + continue + + # ------------------------------------------------------------ 结束 + async def stop(self, cleanup_mode: str) -> None: + self._closing = True + if self.ws is not None and not self.ws.closed: + try: + await self._send_json({"type": "session.close", + "reason": cleanup_mode or "user_stop"}) + except Exception: + pass + try: + await asyncio.wait_for(self._stopped.wait(), + timeout=self.config.close_timeout_s) + except asyncio.TimeoutError: + pass + if self.ws is not None and not self.ws.closed: + await self.ws.close() + if self._task and not self._task.done(): + self._task.cancel() + await asyncio.gather(self._task, return_exceptions=True) + + # ------------------------------------------------------------ 文本注入 + async def inject_task(self, text: str) -> bool: + """V2 的 input.append 没有 inject_text 字段,暂不支持。 + + 父类靠它实现"技能切换时把指令文本塞给模型"。V2 协议里没有对应字段, + 硬塞会被服务端忽略或报错,所以明确返回 False 让调用方走别的路径, + 而不是假装成功。 + """ + LOG.info("[GW] inject_task 在 /v1/realtime 协议下暂不支持,跳过: %s", text[:30]) + return False diff --git a/extensions/assistive_harness/phase_b/recorder_live.py b/extensions/assistive_harness/phase_b/recorder_live.py new file mode 100644 index 0000000..3e17528 --- /dev/null +++ b/extensions/assistive_harness/phase_b/recorder_live.py @@ -0,0 +1,860 @@ +"""recorder_live.py — 录屏式实时录制器 v5.0 +================================================= + +v5.0 改动:user 轨从"ring buffer 切片拼接"改成"WS 原始包直录"。 +和蓝牙耳机录通话语义一致:丢包 = 该段缺失,不再补零去对齐墙钟。 +和 AI 轨完全对称——AI 轨录的是 PortAudio DAC 实际写出的样本。 + +调用顺序: + live_rec = LiveRecorder(session_dir) + live_rec.attach_to_player(speaker) # 必须在 speaker.start() 之前 + speaker.start() + live_rec.start() # 此后 user/ai/frame 才会被记录 + + # ESP32 reader 每收一包就调: + live_rec.feed_user_raw(pcm_f32) # 16kHz 原始,丢包就丢 + + # 每发一个 chunk 配的图: + live_rec.on_frame(jpeg, chunk_idx) + + live_rec.stop() + live_rec.finalize_mp4() +""" + +from __future__ import annotations + +import json +import logging +import shutil +import subprocess +import threading +import time +import wave +from pathlib import Path +from typing import Optional + +import numpy as np + +LOGGER = logging.getLogger("recorder_live") + + +class LiveRecorder: + def __init__( + self, + session_dir: Optional[Path], + user_sr: int = 16000, + ai_sr: int = 24000, + no_media: bool = False, + ): + self.enabled = session_dir is not None + self.dir: Optional[Path] = Path(session_dir) if session_dir else None + self.user_sr = user_sr + self.ai_sr = ai_sr + # no_media:批量 rerun 评分只需要 wav + jsonl + transcript, + # 跳过 jpg 落盘和 mp4 拼接(150 次 rerun 会重复复制整簇图、跑 450 次 ffmpeg)。 + self.no_media = bool(no_media) + + self._t0: Optional[float] = None + + # User 轨:ESP32 WS 来的原始 PCM,丢包 = 缺失,不补零 + self._user_t_start: Optional[float] = None + # self._user_chunks: list[np.ndarray] = [] + self._user_chunks: list[tuple[float, np.ndarray]] = [] + # AI 轨:PortAudio DAC 实际输出(含 underrun 时填的零) + self._ai_t_start: Optional[float] = None + #self._ai_chunks: list[np.ndarray] = [] + self._ai_chunks: list[tuple[float, np.ndarray]] = [] + # Frames + self._frames: list[tuple[float, str, int]] = [] + self._funnel_rounds: list[dict] = [] # 每轮整簇多帧+判定(统一record) + self._round_counter: int = -1 # on_funnel_round 轮次计数(qid,每轮+1) + self._transcript = None # transcript.txt 句柄 + self._subtitles = None # subtitles.jsonl 句柄 + self._chunks_f = None # model_chunks.jsonl 句柄 + + self._lock = threading.Lock() + self._started = threading.Event() + self._stopping = threading.Event() + + self._user_calls = 0 + self._ai_calls = 0 + + # ------------------------------------------------------------ + # Lifecycle + # ------------------------------------------------------------ + + def attach_to_player(self, player) -> None: + if not self.enabled: + return + orig_enqueue = player.enqueue + rec = self + + # PCSpeaker.enqueue 是 async,签名 (pcm, generation)。包装必须同签名 + async, + # 否则模型音频 enqueue 报 "takes 1 positional argument but 2 were given", + # 导致 AI 音播不出、也录不进(live 听不到声音)。 + async def wrapped_enqueue(pcm_f32, generation=0): + await orig_enqueue(pcm_f32, generation) + if (not rec._started.is_set() or rec._stopping.is_set() + or rec._t0 is None or pcm_f32 is None or pcm_f32.size == 0): + return + try: + pcm = pcm_f32 if pcm_f32.dtype == np.float32 else pcm_f32.astype(np.float32) + pcm = pcm.copy() + t = max(0.0, time.monotonic() - rec._t0) + with rec._lock: + if rec._ai_t_start is None: + rec._ai_t_start = t + rec._ai_chunks.append((t, pcm)) + rec._ai_calls += 1 + except Exception as e: + LOGGER.warning("[LIVE] enqueue hook err: %r", e) + + player.enqueue = wrapped_enqueue + player._orig_enqueue = orig_enqueue # 暴露原始方法,绕过 hook 的场景使用 + LOGGER.info("[LIVE] attached to SPK enqueue (async, pcm+generation)") + + def start(self) -> None: + if not self.enabled or self._started.is_set(): + return + assert self.dir is not None + self.dir.mkdir(parents=True, exist_ok=True) + #(self.dir / "live_images").mkdir(exist_ok=True) + self._t0 = time.monotonic() + self._started.set() + # 评分用:模型/用户的成段文本 + 时间轴(移植自 demo_esp32_duplex_0703 的 + # SessionRecorder.log_turn_text / log_subtitle)。 + # transcript.txt —— 人读,[AI #n] / [LISTEN #n] 整段 + # subtitles.jsonl —— 机读,{start_ms,end_ms,text,is_listen,turn_idx} + # is_listen=True 的 turn 就是 8021 ASR 识别出的用户说话 → 提问结束时刻 t0 从这拿 + try: + self._transcript = (self.dir / "transcript.txt").open("w", encoding="utf-8") + self._transcript.write(f"# session {self.dir.name}\n") + self._transcript.flush() + self._subtitles = (self.dir / "subtitles.jsonl").open("w", encoding="utf-8") + self._chunks_f = (self.dir / "model_chunks.jsonl").open("w", encoding="utf-8") + except Exception as e: + LOGGER.warning("[LIVE] transcript/subtitles 打开失败: %s", e) + self._transcript = None + self._subtitles = None + self._chunks_f = None + LOGGER.info( + "[LIVE] recording started: %s (user=%dHz ai=%dHz)", + self.dir, self.user_sr, self.ai_sr, + ) + + def session_ms(self) -> int: + """session 内相对毫秒(与 frames.jsonl 的 t 同一条时间轴)。""" + if self._t0 is None: + return 0 + return int((time.monotonic() - self._t0) * 1000.0) + + def log_model_chunk(self, text: str, is_listen: bool, end_of_turn: bool, + audio_ms: float = 0.0) -> None: + """逐 chunk 原始记录 —— **一条都不过滤**。 + + 这是诊断用的原始流水:-o 是 1Hz 决策,listen 期间大量 chunk 是 + text="" 且 end_of_turn=False。之前这里写了 + if not text and not end_of_turn: return + 把它们全扔了,结果 24 秒的会话只剩 5 条,看上去像"模型 5.7 秒才出一个 + chunk / 输入分块坏了"——那是记录函数造出来的假象,不是事实。 + 要判断模型节奏是否正常,必须看到每一个 chunk。 + """ + if not self.enabled or not self._started.is_set() or self.dir is None: + return + if self._chunks_f is None: + return + try: + self._chunks_f.write(json.dumps({ + "session_ms": self.session_ms(), + "text": text, + "is_listen": bool(is_listen), + "end_of_turn": bool(end_of_turn), + "audio_ms": round(float(audio_ms), 1), + }, ensure_ascii=False) + "\n") + self._chunks_f.flush() + except Exception: + pass + + def log_event(self, tag: str, text: str) -> None: + """把漏斗侧事件写进 transcript,和 USER/AI 同一条时间轴。 + + 评分时要判"这次拦截对应哪次回答",三者必须在同一条人读时间轴上: + [USER @12480ms] 这上面写的是什么 + [REJECT @13520ms] severe_shake 画面晃得厉害,请先保持不动 + [HINT @13900ms] severe_shake (2.52s) + [AI #3 @16100ms] 上面写着阿莫西林胶囊... + 机读的一份仍在 frames.jsonl(每轮 send/reason)。 + """ + if not self.enabled or not self._started.is_set() or self._transcript is None: + return + try: + self._transcript.write(f"[{tag} @{self.session_ms()}ms] {text}\n") + self._transcript.flush() + except Exception: + pass + + def log_asr(self, utterance: str, final_at_ms=None, confidence=None) -> None: + """8021 ASR 识别出的用户说话。评分取 t0 用。 + + 写两处:transcript.txt 的 [USER] 行(人读)、subtitles.jsonl 的 + is_listen=true 记录(机读,与模型 turn 同一条时间轴、同一个 session_ms 基准)。 + final_at_ms 是 8021 侧的时钟,和本 session 的 _t0 不同源,只作参考存进 + asr_events.jsonl;对齐一律用本地 session_ms()。 + """ + if not self.enabled or not self._started.is_set(): + return + t_ms = self.session_ms() + try: + if self._transcript is not None: + self._transcript.write(f"[USER @{t_ms}ms] {utterance}\n") + self._transcript.flush() + except Exception: + pass + # 复用 subtitles 的 turn 序列(负数 turn_idx 标识 ASR,避免和模型 turn 撞号) + self._asr_seq = getattr(self, "_asr_seq", 0) + 1 + self.log_subtitle(start_ms=t_ms, end_ms=t_ms, text=utterance, + is_listen=True, turn_idx=-self._asr_seq) + try: + if self.dir is not None: + with (self.dir / "asr_events.jsonl").open("a", encoding="utf-8") as f: + f.write(json.dumps({ + "session_ms": t_ms, + "utterance": utterance, + "harness_final_at_ms": final_at_ms, + "confidence": confidence, + }, ensure_ascii=False) + "\n") + except Exception: + pass + + def log_turn_text(self, turn_idx: int, text: str, is_listen: bool) -> None: + if not self.enabled or self._transcript is None: + return + tag = "LISTEN" if is_listen else "AI" + try: + self._transcript.write(f"[{tag} #{turn_idx} @{self.session_ms()}ms] {text}\n") + self._transcript.flush() + except Exception: + pass + + def log_subtitle(self, start_ms: int, end_ms: int, text: str, + is_listen: bool, turn_idx: int) -> None: + if not self.enabled or self._subtitles is None: + return + try: + self._subtitles.write(json.dumps({ + "start_ms": int(start_ms), + "end_ms": int(end_ms), + "text": text, + "is_listen": bool(is_listen), + "turn_idx": int(turn_idx), + }, ensure_ascii=False) + "\n") + self._subtitles.flush() + except Exception: + pass + + def stop(self) -> None: + if not self.enabled or not self._started.is_set() or self._stopping.is_set(): + return + self._stopping.set() + assert self._t0 is not None and self.dir is not None + total = time.monotonic() - self._t0 + + with self._lock: + user_chunks = list(self._user_chunks) + user_t_start = self._user_t_start + ai_chunks = list(self._ai_chunks) + ai_t_start = self._ai_t_start + n_frames = len(self._frames) + + u_path = self.dir / "live_user.wav" + a_path = self.dir / "live_ai.wav" + u_dur = self._write_track_wav(u_path, user_t_start, user_chunks, + self.user_sr, total) + a_dur = self._write_track_wav(a_path, ai_t_start, ai_chunks, + self.ai_sr, total) + + u_size = u_path.stat().st_size if u_path.exists() else 0 + a_size = a_path.stat().st_size if a_path.exists() else 0 + + # 写 events.jsonl(供 rerun 的 LocalImageSource 读:chunk_idx → img 映射) + try: + import json as _json + with self._lock: + frames_snap = list(self._frames) + ev_path = self.dir / "events.jsonl" + with ev_path.open("w", encoding="utf-8") as ef: + for (ft, frel, fidx) in frames_snap: + ef.write(_json.dumps( + {"kind": "chunk_sent", "idx": int(fidx), + "img": Path(frel).name, "t": round(ft, 3)}, + ensure_ascii=False) + "\n") + LOGGER.info("[LIVE] events.jsonl written: %d frames", len(frames_snap)) + except Exception as e: + LOGGER.warning("[LIVE] write events.jsonl err: %r", e) + + # 写 frames.jsonl(整簇多帧 + 判定,供 funnel rerun 重判 / 无漏斗 rerun 取代表帧) + try: + import json as _json2 + with self._lock: + rounds_snap = list(self._funnel_rounds) + fr_path = self.dir / "frames.jsonl" + with fr_path.open("w", encoding="utf-8") as ff: + for rec in rounds_snap: + ff.write(_json2.dumps(rec, ensure_ascii=False) + "\n") + LOGGER.info("[LIVE] frames.jsonl written: %d rounds", len(rounds_snap)) + except Exception as e: + LOGGER.warning("[LIVE] write frames.jsonl err: %r", e) + + u_nz = self._nonzero_ratio(user_chunks) + a_nz = self._nonzero_ratio(ai_chunks) + + LOGGER.info( + "[LIVE] stopped: wall=%.2fs " + "user(calls=%d audio=%.2fs t_start=%.2fs nonzero=%.1f%%) " + "ai(calls=%d audio=%.2fs t_start=%.2fs nonzero=%.1f%%) " + "frames=%d user_wav=%dB ai_wav=%dB", + total, + self._user_calls, u_dur, + user_t_start if user_t_start is not None else -1, u_nz * 100, + self._ai_calls, a_dur, + ai_t_start if ai_t_start is not None else -1, a_nz * 100, + n_frames, u_size, a_size, + ) + + if self._user_calls == 0: + LOGGER.warning( + "[LIVE] feed_user_raw() was NEVER called — " + "esp32_audio_reader 没把 live_rec 接进来。" + ) + if self._ai_calls == 0: + LOGGER.warning( + "[LIVE] AI callback NEVER fired — attach_to_player 没装上、" + "speaker 未启动、或开了 --no-play。" + ) + + # 关闭评分用文本落盘 + for _fh in (self._transcript, self._subtitles, self._chunks_f): + try: + if _fh is not None: + _fh.close() + except Exception: + pass + self._transcript = None + self._subtitles = None + self._chunks_f = None + + # 结束自动落盘 mp4(不用手动): + # ① 整簇多帧 + 角落 reject 标注(演示主用,流畅 + 可视化漏斗决策) + # ② best 1fps 版(兼容旧用途) + try: + self.finalize_multiframe_mp4() + except Exception as e: + LOGGER.warning("[LIVE] multiframe mp4 finalize failed: %s", e) + try: + self.finalize_mp4() + except Exception as e: + LOGGER.warning("[LIVE] mp4 finalize failed: %s", e) + + # ------------------------------------------------------------ + # Inputs + # ------------------------------------------------------------ + + def feed_user_raw(self, pcm_f32: np.ndarray,t_override: Optional[float] = None) -> None: + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or self._t0 is None): + return + if pcm_f32 is None or pcm_f32.size == 0: + return + if pcm_f32.dtype != np.float32: + pcm_f32 = pcm_f32.astype(np.float32) + # 新增:允许调用者提供精确的音频时间轴 t 戳(rerun 场景); + # 否则按 wall clock 来(ESP32 场景) + if t_override is not None: + t = max(0.0, t_override) + else: + t = max(0.0, time.monotonic() - self._t0) + #t = max(0.0, time.monotonic() - self._t0) + with self._lock: + if self._user_t_start is None: + self._user_t_start = t + rms = float(np.sqrt(np.mean(pcm_f32 ** 2))) + LOGGER.info("[LIVE] first feed_user_raw(): %d samples rms=%.4f t=%.2fs", + pcm_f32.size, rms, t) + self._user_chunks.append((t, pcm_f32.copy())) + self._user_calls += 1 + + def on_frame(self, jpeg_bytes: Optional[bytes], chunk_idx: int) -> None: + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or not jpeg_bytes + or self._t0 is None or self.dir is None): + return + t = time.monotonic() - self._t0 + rel = f"images/img_{chunk_idx:05d}.jpg" + # 实际写 jpg 落盘(供 rerun 的 LocalImageSource 读)。 + try: + img_dir = self.dir / "images" + img_dir.mkdir(parents=True, exist_ok=True) + if not self.no_media: + (self.dir / rel).write_bytes(jpeg_bytes) + except Exception as e: + LOGGER.warning("[LIVE] write frame jpg err: %r", e) + return + with self._lock: + self._frames.append((t, rel, int(chunk_idx))) + + def on_funnel_round(self, decision, chunk_idx: int, text: str = "") -> None: + """存漏斗一轮:整簇多帧(筛前原始)落盘 q{NNN}_f{MM}.jpg + frames.jsonl 记一条。 + 统一 record 的核心:一份 record 供三种 rerun—— + 无漏斗 rerun(每轮取代表帧)/ funnel rerun(整簇重判)/ -o rerun(取当时best)。 + """ + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or self._t0 is None or self.dir is None): + return + t = time.monotonic() - self._t0 + frames = getattr(decision, "frames", None) + if not frames: + b = getattr(decision, "best", None) or getattr(decision, "best_jpg", None) + frames = [b] if b else [] + # qid 用独立轮次计数(每轮 +1),不能用 latest_frame.sequence—— + # 那个只在 send 时递增,一直 reject(晃动/糊)时不变 → qid 不变 → 整簇 jpg + # 反复用同名 q{同值}_fNN 覆盖旧图,record 存不下、rerun 没图。 + self._round_counter = getattr(self, "_round_counter", -1) + 1 + qid = self._round_counter + frame_names = [] + try: + img_dir = self.dir / "images" + img_dir.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(frames): + if not jpg: + continue + name = f"q{qid:05d}_f{i:02d}.jpg" + if not self.no_media: + (img_dir / name).write_bytes(jpg) + frame_names.append(name) + except Exception as e: + LOGGER.warning("[LIVE] on_funnel_round write err: %r", e) + return + rec = { + "qid": qid, + "t": round(t, 3), + "chunk_idx": int(chunk_idx), + "frames": frame_names, + "best_index": getattr(decision, "best_index", None), + "send": bool(getattr(decision, "send", False)), + "reason": getattr(decision, "reason", ""), + "text": text, + } + with self._lock: + self._funnel_rounds.append(rec) + + # ------------------------------------------------------------ + # WAV writing + # ------------------------------------------------------------ + + @staticmethod + def _nonzero_ratio(chunks: list[tuple[float, np.ndarray]]) -> float: + if not chunks: + return 0.0 + total, nz = 0, 0 + for _, pcm in chunks: + total += pcm.size + nz += int(np.sum(np.abs(pcm) > 1e-4)) + return (nz / total) if total > 0 else 0.0 + + @staticmethod + def _write_track_wav( + path: Path, + t_start: Optional[float], # 仅用于日志兼容,不再决定起点 + chunks: list[tuple[float, np.ndarray]], + sr: int, + wall_dur: float, + ) -> float: + """录屏式写盘:每个 chunk 落在它真实的 arrival 时间上,空隙留 0。""" + if not chunks: + n_total = max(int(wall_dur * sr), 1) + track = np.zeros(n_total, dtype=np.float32) + audio_dur = 0.0 + else: + # 计算总长 = max(最后一段尾巴, wall_dur) + end_time = max(t + pcm.size / sr for t, pcm in chunks) + n_total = max(int(max(end_time, wall_dur) * sr), 1) + track = np.zeros(n_total, dtype=np.float32) + audio_dur = 0.0 # 这里改为"有效样本"的累计,不再是 concat 长度 + prev_end_samp = 0 + for t, pcm in chunks: + i = max(0, int(t * sr)) + # 防止下一段的 arrival time 小于上一段结束——重叠时按上一段尾巴顺延 + i = max(i, prev_end_samp) + j = min(i + pcm.size, n_total) + if j > i: + track[i:j] = pcm[: j - i] + prev_end_samp = j + audio_dur += (j - i) / sr + + i16 = np.clip(track * 32768.0, -32768, 32767).astype(np.int16) + with wave.open(str(path), "wb") as w: + w.setnchannels(1); + w.setsampwidth(2); + w.setframerate(sr) + w.writeframes(i16.tobytes()) + return audio_dur + + # ------------------------------------------------------------ + # MP4 finalize + # ------------------------------------------------------------ + + def finalize_mp4(self) -> Optional[Path]: + if self.no_media: + return None + if not self.enabled or self.dir is None: + return None + if shutil.which("ffmpeg") is None: + LOGGER.warning("[LIVE] ffmpeg not found. WAV/帧已保存在 %s。", self.dir) + return None + main_out = None + + + try: + main_out = self._do_finalize_mp4() + except Exception as e: + LOGGER.warning("[LIVE] mp4 finalize failed: %s", e) + # 额外合成一份 user-only,用于 gateway 8006 视频输入测试 + try: + self._do_finalize_useronly_mp4() + except Exception as e: + LOGGER.warning("[LIVE] useronly mp4 finalize failed: %s", e) + return main_out + + def _do_finalize_useronly_mp4(self) -> Optional[Path]: + """额外合成一份只含 user 音轨的 mp4,用于给 gateway 的 8006 视频输入端做 fixture 测试。""" + d = self.dir + assert d is not None + user_wav = d / "live_user.wav" + if not user_wav.exists(): + LOGGER.info("[LIVE] no user wav, skip useronly mp4") + return None + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + if u_dur <= 0.5: + LOGGER.info("[LIVE] user too short (%.2fs), skip useronly mp4", u_dur) + return None + + with self._lock: + frames = list(self._frames) + + concat_txt = d / "_useronly_frames.txt" + if frames: + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = frames[0][0] + if first_t > 0.05: + f.write(f"file '{frames[0][1]}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, (rt, p, _idx) in enumerate(frames): + f.write(f"file '{p}'\n") + if i + 1 < len(frames): + dur = max(0.04, frames[i + 1][0] - rt) + else: + dur = max(0.5, u_dur - rt) + f.write(f"duration {dur:.3f}\n") + f.write(f"file '{frames[-1][1]}'\n") + + if not frames: + out = d / "live_useronly.m4a" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-i", str(user_wav), + "-c:a", "aac", "-b:a", "192k", + "-ac", "1", + "-t", f"{u_dur:.3f}", + str(out), + ] + else: + out = d / "live_useronly.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), + "-map", "0:v", "-map", "1:a", + "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-ac", "1", + "-t", f"{u_dur:.3f}", + str(out), + ] + + LOGGER.info( + "[LIVE] assembling useronly: frames=%d u_dur=%.1fs → %s", + len(frames), u_dur, out.name, + ) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning("[LIVE] useronly ffmpeg rc=%d stderr tail:\n%s", + r.returncode, r.stderr[-1200:]) + return None + if out.exists(): + LOGGER.info("[LIVE] ✅ saved %s (%.1f MB, %.1fs)", + out, out.stat().st_size / 1e6, u_dur) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] useronly ffmpeg timeout (>10min)") + return None + finally: + try: + if concat_txt.exists(): + concat_txt.unlink() + except Exception: + pass + def _do_finalize_mp4(self) -> Optional[Path]: + d = self.dir + assert d is not None + user_wav = d / "live_user.wav" + ai_wav = d / "live_ai.wav" + if not (user_wav.exists() and ai_wav.exists()): + LOGGER.info("[LIVE] no wav files, skip mp4") + return None + + with self._lock: + frames = list(self._frames) + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + with wave.open(str(ai_wav), "rb") as w: + a_dur = w.getnframes() / w.getframerate() + total_dur = max(u_dur, a_dur) + if total_dur <= 0.5: + LOGGER.info("[LIVE] session too short (%.2fs), skip mp4", total_dur) + return None + + concat_txt = d / "_live_frames.txt" + if frames: + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = frames[0][0] + if first_t > 0.05: + f.write(f"file '{frames[0][1]}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, (rt, p, _idx) in enumerate(frames): + f.write(f"file '{p}'\n") + if i + 1 < len(frames): + dur = max(0.04, frames[i + 1][0] - rt) + else: + dur = max(0.5, total_dur - rt) + f.write(f"duration {dur:.3f}\n") + f.write(f"file '{frames[-1][1]}'\n") + + # apad + -t 让短的一轨自动补尾静音对齐到 mp4 总时长 + if not frames: + out = d / "live_session.m4a" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[0:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[1:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "[aout]", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + else: + out = d / "live_session.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[1:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[2:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "0:v", "-map", "[aout]", + #"-c:v", "libx264", "-preset", "veryfast", "-pix_fmt", "yuv420p", + "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + + LOGGER.info( + "[LIVE] assembling: frames=%d total=%.1fs (u=%.1fs a=%.1fs) → %s", + len(frames), total_dur, u_dur, a_dur, out.name, + ) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning( + "[LIVE] ffmpeg rc=%d stderr tail:\n%s", + r.returncode, r.stderr[-1200:], + ) + return None + if out.exists(): + LOGGER.info( + "[LIVE] ✅ saved %s (%.1f MB, %.1fs)", + out, out.stat().st_size / 1e6, total_dur, + ) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] ffmpeg timeout (>10min)") + return None + finally: + try: + if concat_txt.exists(): + concat_txt.unlink() + except Exception: + pass + + + # ------------------------------------------------------------ + # 整簇多帧 mp4(演示用):用每轮整簇多帧拼,比 1fps best 流畅; + # 角落用 ass 字幕标注每轮 send/reject + reason,直接可视化漏斗决策。 + # 对比无漏斗/有漏斗两份 mp4,即可证明"模糊图被拒、不进模型"的正确性。 + # ------------------------------------------------------------ + def _ass_escape(self, s: str) -> str: + return (s or "").replace("\\", "\\\\").replace("{", "(").replace("}", ")") + + def _gen_reject_ass(self, rounds, total_dur: float) -> Optional[Path]: + """生成角落标注字幕:每轮时间段显示 SEND / REJECT:reason。""" + d = self.dir + if d is None or not rounds: + return None + def _fmt(t): + t = max(0.0, t) + h = int(t // 3600); m = int((t % 3600) // 60) + s = t % 60 + return f"{h:d}:{m:02d}:{s:05.2f}" + ass = d / "_reject_notes.ass" + header = ( + "[Script Info]\nScriptType: v4.00+\nPlayResX: 1280\nPlayResY: 720\n\n" + "[V4+ Styles]\n" + "Format: Name, Fontname, Fontsize, PrimaryColour, Bold, Alignment, " + "MarginL, MarginR, MarginV, BorderStyle, Outline, Shadow\n" + # Alignment 9 = 右上角;红=&H000000FF 绿=&H0000FF00 (ASS 是 &HAABBGGRR) + "Style: REJ,Arial,36,&H000000FF,1,9,20,20,20,1,2,0\n" + "Style: SND,Arial,36,&H0000FF00,1,9,20,20,20,1,2,0\n\n" + "[Events]\nFormat: Layer, Start, End, Style, Text\n" + ) + lines = [] + for i, rec in enumerate(rounds): + t0 = float(rec.get("t", i)) + t1 = float(rounds[i + 1].get("t", t0 + 1.0)) if i + 1 < len(rounds) else total_dur + if t1 <= t0: + t1 = t0 + 0.3 + send = bool(rec.get("send")) + reason = self._ass_escape(rec.get("reason", "")) + if send: + style, txt = "SND", "SEND ✓" + else: + style, txt = "REJ", f"REJECT ✗ {reason}" + lines.append(f"Dialogue: 0,{_fmt(t0)},{_fmt(t1)},{style},,{txt}") + try: + ass.write_text(header + "\n".join(lines) + "\n", encoding="utf-8") + return ass + except Exception as e: + LOGGER.warning("[LIVE] write reject ass err: %r", e) + return None + + def finalize_multiframe_mp4(self) -> Optional[Path]: + if self.no_media: + return None + """整簇多帧 mp4 + 角落 reject 标注。演示用,比 best 1fps 流畅。""" + if not self.enabled or self.dir is None: + return None + if shutil.which("ffmpeg") is None: + LOGGER.warning("[LIVE] ⚠ ffmpeg 未安装,无法生成 mp4!" + "装法: conda install -c conda-forge ffmpeg。" + "帧和 wav 已存在 %s,可手动拼。", self.dir) + return None + d = self.dir + user_wav = d / "live_user.wav" + ai_wav = d / "live_ai.wav" + if not (user_wav.exists() and ai_wav.exists()): + return None + with self._lock: + rounds = list(self._funnel_rounds) + if not rounds: + LOGGER.info("[LIVE] no funnel rounds, skip multiframe mp4") + return None + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + with wave.open(str(ai_wav), "rb") as w: + a_dur = w.getnframes() / w.getframerate() + total_dur = max(u_dur, a_dur) + if total_dur <= 0.5: + return None + + # 整簇多帧 concat:每轮的 t 到下一轮的 t 之间,均分给该轮的 N 帧(高 fps) + concat_txt = d / "_multiframe.txt" + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = float(rounds[0].get("t", 0.0)) + if first_t > 0.05 and rounds[0].get("frames"): + f.write(f"file 'images/{Path(rounds[0]['frames'][0]).name}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, rec in enumerate(rounds): + names = rec.get("frames") or [] + if not names: + continue + t0 = float(rec.get("t", i)) + t1 = float(rounds[i + 1].get("t", t0 + 1.0)) if i + 1 < len(rounds) else total_dur + round_dur = max(0.12, t1 - t0) + per = round_dur / len(names) # 整簇内多帧均分 → 高 fps + for nm in names: + f.write(f"file 'images/{Path(nm).name}'\n") + f.write(f"duration {max(0.03, per):.3f}\n") + # 末帧兜底 + last_names = rounds[-1].get("frames") or [] + if last_names: + f.write(f"file 'images/{Path(last_names[-1]).name}'\n") + + ass = self._gen_reject_ass(rounds, total_dur) + vf = "format=yuv420p" + if ass is not None: + safe = str(ass.name) # 相对 cwd 需在 dir 下运行;用绝对更稳 + abs_ass = str(ass.resolve()).replace("\\", "/").replace(":", "\\:") + vf = f"ass='{abs_ass}',format=yuv420p" + + out = d / "live_multiframe.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[1:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[2:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "0:v", "-map", "[aout]", + "-vf", vf, + "-c:v", "libx264", "-preset", "medium", "-crf", "20", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + LOGGER.info("[LIVE] assembling multiframe mp4: rounds=%d total=%.1fs → %s", + len(rounds), total_dur, out.name) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning("[LIVE] multiframe ffmpeg rc=%d stderr:\n%s", + r.returncode, r.stderr[-1200:]) + return None + if out.exists(): + LOGGER.info("[LIVE] ✅ multiframe mp4 saved %s (%.1f MB)", + out, out.stat().st_size / 1e6) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] multiframe ffmpeg timeout") + return None + finally: + for p in (concat_txt, ass): + try: + if p is not None and p.exists(): + p.unlink() + except Exception: + pass diff --git a/extensions/assistive_harness/phase_b/requirements-phase-b.txt b/extensions/assistive_harness/phase_b/requirements-phase-b.txt new file mode 100644 index 0000000..a247f64 --- /dev/null +++ b/extensions/assistive_harness/phase_b/requirements-phase-b.txt @@ -0,0 +1,4 @@ +aiohttp>=3.13 +Pillow>=10 +sounddevice>=0.5 + diff --git a/extensions/assistive_harness/phase_b/rerun_source.py b/extensions/assistive_harness/phase_b/rerun_source.py new file mode 100644 index 0000000..448862d --- /dev/null +++ b/extensions/assistive_harness/phase_b/rerun_source.py @@ -0,0 +1,368 @@ +"""rerun_source.py — 用已录制 session 当输入重跑模型 + +替换主脚本里的两个网络输入函数: + - esp32_audio_reader → local_pcm_reader + - esp32_capture_image → LocalImageSource.capture +""" + +from __future__ import annotations + +import asyncio +import json +import logging +import time +from pathlib import Path +from typing import Optional + +import numpy as np +import sounddevice as sd +import threading + + +LOGGER = logging.getLogger("rerun_source") + +_PACKET_MS = 40 +_PACKET_SAMPLES = 640 +_SAMPLE_RATE = 16000 + + +class _UserMonitor: + """独立 PortAudio OutputStream,用于 rerun 时播放 user 监听音频。 + + 为什么不复用主 SpeakerPlayer:主 speaker 是单 FIFO ring, + AI 和 user 两路 enqueue 共享同一个 ring 时,DAC 按入队顺序消费会 + 导致 AI 音频被 user 音频"插队"——听感是 AI 输出卡顿。 + + 独立 OutputStream 由 OS 端混音(同一声卡时钟驱动),物理上不互相挤压。 + """ + + def __init__(self, sample_rate: int = 24000, ring_capacity_s: float = 2.0): + self.sr = int(sample_rate) + self.ring_cap = int(ring_capacity_s * self.sr) + self._buf = np.zeros(self.ring_cap, dtype=np.float32) + self._r = 0 + self._w = 0 + self._size = 0 + self._lock = threading.Lock() + self._dropped = 0 + try: + self._stream = sd.OutputStream( + samplerate=self.sr, channels=1, dtype="float32", + blocksize=0, callback=self._cb, + ) + self._stream.start() + LOGGER.info("[RERUN-MON] user monitor stream started: sr=%d ring=%.1fs", + self.sr, ring_capacity_s) + except Exception as e: + LOGGER.warning("[RERUN-MON] failed to open OutputStream: %r", e) + self._stream = None + + def _cb(self, outdata, frames, time_info, status): + with self._lock: + avail = min(frames, self._size) + if avail > 0: + first = min(avail, self.ring_cap - self._r) + outdata[:first, 0] = self._buf[self._r:self._r + first] + if avail > first: + outdata[first:avail, 0] = self._buf[:avail - first] + self._r = (self._r + avail) % self.ring_cap + self._size -= avail + if avail < frames: + outdata[avail:, 0] = 0.0 + + def enqueue(self, pcm_f32: np.ndarray) -> None: + if self._stream is None or pcm_f32 is None or pcm_f32.size == 0: + return + if pcm_f32.dtype != np.float32: + pcm_f32 = pcm_f32.astype(np.float32) + n = pcm_f32.size + if n > self.ring_cap: + pcm_f32 = pcm_f32[-self.ring_cap:] + n = pcm_f32.size + with self._lock: + if self._size + n > self.ring_cap: + drop = (self._size + n) - self.ring_cap + self._r = (self._r + drop) % self.ring_cap + self._size -= drop + self._dropped += drop + first = min(n, self.ring_cap - self._w) + self._buf[self._w:self._w + first] = pcm_f32[:first] + if n > first: + self._buf[:n - first] = pcm_f32[first:n] + self._w = (self._w + n) % self.ring_cap + self._size += n + + def stop(self) -> None: + if self._stream is None: + return + try: + self._stream.stop() + self._stream.close() + except Exception as e: + LOGGER.warning("[RERUN-MON] stop err: %r", e) + finally: + self._stream = None + LOGGER.info("[RERUN-MON] user monitor stopped (dropped=%d samples)", + self._dropped) + + + +async def local_pcm_reader( + pcm_path: Path, + ring, + stop_evt: asyncio.Event, + stats, + live_rec=None, + speaker=None, # ← 新增 + speaker_sr: int = 24000, # ← 新增:speaker 期望的采样率 + speed: float = 1.0, + drain_s: float = 5.0, + prefill_s: float = 0.0, +) -> None: + pcm_path = Path(pcm_path) + if not pcm_path.exists(): + LOGGER.error("[RERUN] pcm not found: %s", pcm_path) + stop_evt.set() + return + + # 优先用 live_user.wav (LiveRecorder 直接写的,干净); + # 回退用 user_raw.pcm (主循环 ring.slice 落盘的,带 40% 零填充) + import wave + wav_path = pcm_path.parent / "live_user.wav" + pcm_i16 = None + src_label = "" + if wav_path.exists(): + try: + with wave.open(str(wav_path), "rb") as w: + sr_in = w.getframerate() + nch = w.getnchannels() + sw = w.getsampwidth() + if sr_in == _SAMPLE_RATE and nch == 1 and sw == 2: + pcm_i16 = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16) + src_label = f"live_user.wav (clean, {sr_in}Hz mono int16)" + else: + LOGGER.warning( + "[RERUN] live_user.wav format unexpected (sr=%d ch=%d sw=%d), " + "fallback to user_raw.pcm", sr_in, nch, sw, + ) + except Exception as e: + LOGGER.warning("[RERUN] failed to read live_user.wav: %r, fallback to user_raw.pcm", e) + pcm_i16 = None + + if pcm_i16 is None: + raw = pcm_path.read_bytes() + pcm_i16 = np.frombuffer(raw, dtype=np.int16) + src_label = "user_raw.pcm (may contain ring.slice zero-padding)" + + total_samples = pcm_i16.size + total_dur = total_samples / _SAMPLE_RATE + LOGGER.info("[RERUN] audio source: %s", src_label) + # rerun 用户监听:独立 OutputStream,避免和 AI 共用 ring 导致互相卡顿 + user_mon = None + if speaker is not None: + try: + user_mon = _UserMonitor(sample_rate=speaker_sr) + except Exception as e: + LOGGER.warning("[RERUN] failed to create user monitor: %r", e) + user_mon = None + + + LOGGER.info( + "[RERUN] pcm loaded: %s samples=%d dur=%.2fs speed=%.2fx prefill=%.1fs", + pcm_path, total_samples, total_dur, speed, prefill_s, + ) + + packet_interval = (_PACKET_MS / 1000.0) / max(speed, 0.01) + ts_ms = 0 + cursor = 0 + pkt_count = 0 + prefill_packets = int(prefill_s * 1000 / _PACKET_MS) + next_tick = time.monotonic() # ← 改:不再 + prefill_s + audio_t_start = None + while cursor < total_samples and not stop_evt.is_set(): + end = min(cursor + _PACKET_SAMPLES, total_samples) + chunk_i16 = pcm_i16[cursor:end] + cursor = end + pkt_count += 1 + + try: + stats["rx_pkts"] = pkt_count + stats["esp_drops"] = 0 + except Exception: + pass + + try: + await ring.write(ts_ms, chunk_i16) + except Exception as e: + LOGGER.warning("[RERUN] ring.write err: %r", e) + + if live_rec is not None: + try: + # ↓ 关键改动:用"累计音频时长"作为 t 戳,而不是 wall clock + # 这样 LiveRecorder 写盘时 t * sr 算出来的 i 与 pcm.size 完美对齐 + if audio_t_start is None: + audio_t_start = time.monotonic() - live_rec._t0 if live_rec._t0 else 0.0 + audio_t = audio_t_start + ts_ms / 1000.0 + live_rec.feed_user_raw( + chunk_i16.astype(np.float32) / 32768.0, + t_override=audio_t, + ) + # rerun 模式:把 user 音频也推给扬声器,这样能听到原录制的用户在说什么 + # (live 模式不这么做,因为用户本人就在那说话,会和扬声器叠加。 + # rerun 是事后回放,没回声风险,等同 8006 浏览器播 mp4 的体验) + if user_mon is not None: + try: + chunk_f32 = chunk_i16.astype(np.float32) / 32768.0 + if speaker_sr != _SAMPLE_RATE: + ratio = speaker_sr / _SAMPLE_RATE + new_len = int(chunk_f32.size * ratio) + x_old = np.linspace(0, 1, chunk_f32.size, endpoint=False) + x_new = np.linspace(0, 1, new_len, endpoint=False) + chunk_resampled = np.interp(x_new, x_old, chunk_f32).astype(np.float32) + else: + chunk_resampled = chunk_f32 + # 关键:走原始 enqueue,不走 LiveRecorder hook + # (hook 会把这条用户音频错误地累积进 _ai_chunks, + # 导致 mp4 的 ai 轨里也有用户声音,听起来像"用户被录了两次") + user_mon.enqueue(chunk_resampled) + except Exception as e: + LOGGER.warning("[RERUN] speaker.enqueue err: %r", e) + + #live_rec.feed_user_raw(chunk_i16.astype(np.float32) / 32768.0) + except Exception as e: + LOGGER.warning("[RERUN] live_rec.feed_user_raw err: %r", e) + + ts_ms += _PACKET_MS + + # prefill 阶段:让出事件循环但不真睡 + if pkt_count <= prefill_packets: + await asyncio.sleep(0) + continue + + # prefill → realtime 切换那一刻,重置基线 + if pkt_count == prefill_packets + 1: + LOGGER.info( + "[RERUN] prefill done (%d packets, %.2fs audio in ring), " + "switching to realtime pacing", + prefill_packets, prefill_packets * _PACKET_MS / 1000.0, + ) + next_tick = time.monotonic() # ← 关键:基线重置到此刻 + + next_tick += packet_interval + sleep_for = next_tick - time.monotonic() + if sleep_for > 0: + try: + await asyncio.wait_for(stop_evt.wait(), timeout=sleep_for) + break # 被外部 stop:跳出推流循环,仍走下面的 drain(等模型说完) + except asyncio.TimeoutError: + pass + + try: + stats["audio_done"] = True + stats["audio_done_ts"] = time.monotonic() + except Exception: + pass + + LOGGER.info( + "[RERUN] pcm exhausted: pushed=%d packets (%.2fs audio). draining...", + pkt_count, ts_ms / 1000.0, + ) + + # 音频已推完并标记 audio_done。结束的裁决权交给主 send loop: + # 它会在 audio_done 后等模型说完(轮询 last_speak_ts)再 set stop_evt。 + # reader 这里只需等待那个信号;带兜底上限防止异常卡死。 + max_wait_s = 120.0 + waited = 0.0 + while waited < max_wait_s and not stop_evt.is_set(): + try: + await asyncio.wait_for(stop_evt.wait(), timeout=0.2) + break + except asyncio.TimeoutError: + waited += 0.2 + if waited >= max_wait_s: + LOGGER.warning("[RERUN] drain 达到上限 %.0fs,强制结束", max_wait_s) + + if user_mon is not None: + user_mon.stop() + + if not stop_evt.is_set(): + LOGGER.info("[RERUN] drain done, signaling stop") + stop_evt.set() + + +class LocalImageSource: + def __init__(self, session_dir: Path): + self.session_dir = Path(session_dir) + self.images_dir = self.session_dir / "images" + self.events_path = self.session_dir / "events.jsonl" + + if not self.images_dir.exists(): + raise FileNotFoundError(f"images/ not found: {self.images_dir}") + if not self.events_path.exists(): + raise FileNotFoundError(f"events.jsonl not found: {self.events_path}") + + self._map: dict[int, Optional[str]] = {} + self._build_map() + + n_total = len(self._map) + n_with_img = sum(1 for v in self._map.values() if v) + LOGGER.info( + "[RERUN] image map: total_chunks=%d with_image=%d (missing=%d) from %s", + n_total, n_with_img, n_total - n_with_img, self.events_path.name, + ) + if n_total == 0: + # ← 新增:诊断空 events.jsonl + n_files = len(list(self.images_dir.glob("img_*.jpg"))) + LOGGER.warning( + "[RERUN] events.jsonl has NO chunk_sent entries! " + "but images/ has %d files. Falling back to filename-order matching.", + n_files, + ) + self._fallback_filename_order(n_files) + + def _build_map(self) -> None: + with self.events_path.open("r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + evt = json.loads(line) + except Exception: + continue + # ← 改 1:看实际 events.jsonl 用什么 kind 字段 + kind = evt.get("kind") or evt.get("type") or "" + if kind != "chunk_sent": + continue + # ← 改 2:chunk_idx 字段名兼容 + idx = evt.get("idx", evt.get("chunk_idx")) + img = evt.get("img") + if idx is None: + continue + self._map[int(idx)] = img if img else None + + def _fallback_filename_order(self, n_files: int) -> None: + """events.jsonl 是空的时候的兜底:按 img_NNNNN.jpg 文件名映射 chunk_idx。""" + for p in sorted(self.images_dir.glob("img_*.jpg")): + try: + # 文件名形如 img_00007.jpg → 7 + idx = int(p.stem.split("_")[-1]) + self._map[idx] = p.name + except Exception: + pass + LOGGER.info("[RERUN] fallback map built: %d chunks (filename-order)", + len(self._map)) + + async def capture(self, chunk_idx: int) -> Optional[bytes]: + rel = self._map.get(int(chunk_idx)) + if not rel: + return None + name = Path(rel).name + path = self.images_dir / name + if not path.exists(): + return None + try: + return path.read_bytes() + except Exception as e: + LOGGER.warning("[RERUN] image read err: %r", e) + return None \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/rokid_runtime.py b/extensions/assistive_harness/phase_b/rokid_runtime.py new file mode 100644 index 0000000..af9f8cc --- /dev/null +++ b/extensions/assistive_harness/phase_b/rokid_runtime.py @@ -0,0 +1,1703 @@ +from __future__ import annotations + +import argparse +import asyncio +import base64 +import io +import json +import logging +import os +import signal +import ssl +import threading +import time +import uuid +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Awaitable, Callable, Protocol + +import aiohttp +from aiohttp import web +import numpy as np + +from ..registry import SkillRegistry + +try: + from PIL import Image +except Exception: # pragma: no cover - optional at import time + Image = None + + +LOG = logging.getLogger("assistive_harness.phase_b.rokid") +SAMPLE_RATE_IN = 16_000 +SAMPLE_RATE_OUT = 24_000 +PCM16_WIDTH = 2 +CTRL_C_HARD_EXIT_S = 10.0 + + +def now_ms() -> float: + return time.time() * 1000.0 + + +class CtrlCExitWatchdog: + """Guarantee that a Windows Ctrl+C cannot leave the Rokid port behind.""" + + def __init__(self, hard_exit_s: float = CTRL_C_HARD_EXIT_S): + self.hard_exit_s = max(1.0, float(hard_exit_s)) + self._armed = False + self._lock = threading.Lock() + + @property + def armed(self) -> bool: + return self._armed + + def arm(self) -> None: + with self._lock: + if self._armed: + return + self._armed = True + LOG.info( + "Console interrupt received; closing Rokid listener and runtime " + "(hard cutoff %.1fs)", + self.hard_exit_s, + ) + threading.Thread( + target=self._force_exit_after_deadline, + name="rokid-ctrl-c-watchdog", + daemon=True, + ).start() + + def _force_exit_after_deadline(self) -> None: + time.sleep(self.hard_exit_s) + LOG.error( + "Rokid shutdown exceeded %.1fs; forcing process exit so port 18080 " + "cannot remain occupied", + self.hard_exit_s, + ) + logging.shutdown() + os._exit(130) + + +def pcm16le_to_float32(raw: bytes) -> np.ndarray: + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + if not raw: + return np.zeros(0, dtype=np.float32) + return ( + np.frombuffer(raw, dtype=" bytes: + """Apply device-specific gain with saturation while preserving PCM16 LE.""" + if gain <= 0: + raise ValueError("input gain must be greater than zero") + if gain == 1.0 or not raw: + return raw + samples = np.frombuffer(raw, dtype=" np.ndarray: + """Return a short, non-speech two-note cue for restart_complete.""" + + amplitude = min(1.0, max(0.0, float(amplitude))) + + def tone(frequency_hz: float, duration_s: float) -> np.ndarray: + count = max(2, int(sample_rate * duration_s)) + phase = np.arange(count, dtype=np.float32) / float(sample_rate) + envelope = np.sin(np.linspace(0.0, np.pi, count, dtype=np.float32)) ** 2 + return ( + amplitude + * envelope + * np.sin(2.0 * np.pi * frequency_hz * phase) + ).astype(np.float32) + + gap = np.zeros(max(1, int(sample_rate * 0.030)), dtype=np.float32) + return np.concatenate((tone(880.0, 0.080), gap, tone(1174.66, 0.105))) + + +def float32_to_base64(samples: np.ndarray) -> str: + return base64.b64encode( + samples.astype(np.float32, copy=False).tobytes() + ).decode("ascii") + + +def same_slots(left: dict[str, Any], right: dict[str, Any]) -> bool: + return {str(key): str(value) for key, value in left.items()} == { + str(key): str(value) for key, value in right.items() + } + + +def rotate_jpeg_clockwise(jpeg: bytes, degrees: int, quality: int = 95) -> bytes: + degrees %= 360 + if degrees == 0 or Image is None: + return jpeg + methods = { + 90: Image.Transpose.ROTATE_270, + 180: Image.Transpose.ROTATE_180, + 270: Image.Transpose.ROTATE_90, + } + method = methods.get(degrees) + if method is None: + raise ValueError("image rotation must be 0, 90, 180, or 270") + with Image.open(io.BytesIO(jpeg)) as image: + output = io.BytesIO() + image.convert("RGB").transpose(method).save( + output, format="JPEG", quality=quality + ) + return output.getvalue() + + +class DropOldestAudioQueue: + """Bounded device-audio queue that always preserves the newest packets.""" + + def __init__(self, max_packets: int): + self._queue: asyncio.Queue[bytes] = asyncio.Queue(maxsize=max(1, max_packets)) + self.dropped_packets = 0 + + @property + def size(self) -> int: + return self._queue.qsize() + + def put_nowait(self, raw: bytes) -> None: + if self._queue.full(): + try: + self._queue.get_nowait() + self.dropped_packets += 1 + except asyncio.QueueEmpty: + pass + self._queue.put_nowait(raw) + + async def get(self, timeout_s: float) -> bytes | None: + try: + return await asyncio.wait_for(self._queue.get(), timeout=timeout_s) + except asyncio.TimeoutError: + return None + + def clear(self) -> int: + cleared = 0 + while True: + try: + self._queue.get_nowait() + cleared += 1 + except asyncio.QueueEmpty: + return cleared + + +class AudioMirrorChunker: + """Repacketize Rokid PCM into the same 100 ms frames used in Phase A.""" + + def __init__(self, samples_per_frame: int = 1_600): + self.target_bytes = max(1, samples_per_frame) * PCM16_WIDTH + self._carry = bytearray() + + def feed(self, raw: bytes) -> list[np.ndarray]: + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + self._carry.extend(raw) + frames: list[np.ndarray] = [] + while len(self._carry) >= self.target_bytes: + frame = bytes(self._carry[: self.target_bytes]) + del self._carry[: self.target_bytes] + frames.append(pcm16le_to_float32(frame)) + return frames + + def clear(self) -> None: + self._carry.clear() + + +@dataclass(slots=True) +class LatestFrame: + jpeg: bytes | None = None + timestamp_ms: float = 0.0 + sequence: int = 0 + + def set(self, jpeg: bytes, timestamp_ms: float) -> None: + self.jpeg = jpeg + self.timestamp_ms = timestamp_ms + self.sequence += 1 + + +@dataclass(slots=True) +class OutputGate: + generation: int = 0 + current_skill: str = "idle_chat" + current_slots: dict[str, Any] | None = None + speech_hold_active: bool = False + drop_output_until_listen: bool = False + restart_in_progress: bool = False + dropped_old_text: int = 0 + dropped_old_audio: int = 0 + stop_count: int = 0 + local_cue_mute_until_mono: float = 0.0 + + def __post_init__(self) -> None: + if self.current_slots is None: + self.current_slots = {} + + def stop(self) -> None: + self.stop_count += 1 + self.speech_hold_active = True + self.drop_output_until_listen = True + + def resume(self) -> None: + self.speech_hold_active = False + self.drop_output_until_listen = False + + def replacement_ready(self) -> None: + self.speech_hold_active = False + self.drop_output_until_listen = False + self.restart_in_progress = False + + +class SpeakerSink(Protocol): + async def start(self) -> None: ... + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: ... + + async def block_and_flush(self) -> None: ... + + async def resume(self) -> None: ... + + async def close(self) -> None: ... + + def pending_ms(self) -> float: ... + + +class NullSpeaker: + async def start(self) -> None: + return None + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: + return None + + async def block_and_flush(self) -> None: + return None + + async def resume(self) -> None: + return None + + async def close(self) -> None: + return None + + def pending_ms(self) -> float: + return 0.0 + + +class PCSpeaker: + """Interruptible 24 kHz PC playback with a short write quantum.""" + + def __init__(self, block_ms: int = 50): + self.block_samples = max(240, int(SAMPLE_RATE_OUT * block_ms / 1000)) + self.queue: asyncio.Queue[tuple[int, int, np.ndarray]] = asyncio.Queue(maxsize=32) + self.blocked = False + self.epoch = 0 + self._stream: Any = None + self._worker: asyncio.Task[None] | None = None + self._io_lock = asyncio.Lock() + self._pending_samples = 0 + + def _open_stream(self) -> None: + import sounddevice as sd # type: ignore + + stream = sd.OutputStream( + samplerate=SAMPLE_RATE_OUT, + channels=1, + dtype="float32", + blocksize=self.block_samples, + latency="low", + ) + stream.start() + self._stream = stream + + def _close_stream(self) -> None: + stream = self._stream + self._stream = None + if stream is None: + return + try: + stream.abort() + finally: + stream.close() + + async def start(self) -> None: + try: + await asyncio.to_thread(self._open_stream) + self._worker = asyncio.create_task(self._play_loop()) + LOG.info("PC speaker output ready") + except Exception as exc: # pragma: no cover - hardware dependent + self._stream = None + LOG.warning("PC speaker disabled: %s", exc) + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: + if self._stream is None or self.blocked or pcm.size == 0: + return + if self.queue.full(): + try: + _epoch, _generation, dropped = self.queue.get_nowait() + self._pending_samples = max( + 0, self._pending_samples - int(dropped.size) + ) + except asyncio.QueueEmpty: + pass + copied = pcm.astype(np.float32, copy=True) + self._pending_samples += int(copied.size) + self.queue.put_nowait((self.epoch, generation, copied)) + + async def _play_loop(self) -> None: + while True: + epoch, _generation, pcm = await self.queue.get() + try: + for offset in range(0, pcm.size, self.block_samples): + if self.blocked or epoch != self.epoch or self._stream is None: + break + chunk = pcm[offset : offset + self.block_samples].reshape(-1, 1) + stream = self._stream + try: + async with self._io_lock: + if self.blocked or epoch != self.epoch or self._stream is not stream: + break + await asyncio.to_thread(stream.write, chunk) + except asyncio.CancelledError: + raise + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker write failed: %s", exc) + break + finally: + self._pending_samples = max( + 0, self._pending_samples - int(pcm.size) + ) + + async def block_and_flush(self) -> None: + self.blocked = True + self.epoch += 1 + self._pending_samples = 0 + while True: + try: + self.queue.get_nowait() + except asyncio.QueueEmpty: + break + if self._stream is not None: + try: + # Windows MME may reject start() immediately after abort() while + # the previous buffer is still retiring. Close the device here + # and create a fresh stream only when output is resumed. + async with self._io_lock: + await asyncio.to_thread(self._close_stream) + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker flush failed: %s", exc) + + async def resume(self) -> None: + if self._stream is None: + try: + async with self._io_lock: + if self._stream is None: + await asyncio.to_thread(self._open_stream) + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker resume failed: %s", exc) + self.blocked = False + + async def close(self) -> None: + self.blocked = True + self._pending_samples = 0 + if self._worker: + self._worker.cancel() + await asyncio.gather(self._worker, return_exceptions=True) + if self._stream is not None: + try: + async with self._io_lock: + await asyncio.to_thread(self._close_stream) + except Exception: + pass + + def pending_ms(self) -> float: + return self._pending_samples * 1000.0 / SAMPLE_RATE_OUT + + +@dataclass(slots=True) +class RokidRuntimeConfig: + host: str = "0.0.0.0" + port: int = 18_080 + gateway: str = "localhost:8040" + gateway_tls: bool = False + harness_url: str = "ws://127.0.0.1:8021/ws/control" + harness_client_id: str = "rokid-phase-b" + skills_config: str = "" + cleanup_mode: str = "light" + chunk_ms: int = 1_000 + force_listen_count: int = 3 + max_new_speak_tokens_per_chunk: int = 20 + length_penalty: float = 1.1 + max_slice_nums: int = 1 + audio_queue_packets: int = 96 + input_gain: float = 12.0 + image_rotate_cw: int = 270 + image_jpeg_quality: int = 95 + image_resend_s: float = 0.5 + image_max_age_s: float = 30.0 + prepare_timeout_s: float = 120.0 + close_timeout_s: float = 2.0 + reconnect_s: float = 1.5 + play_audio: bool = True + session_ready_chime: bool = True + session_ready_chime_volume: float = 0.32 + session_ready_chime_feedback_guard_s: float = 0.65 + playback_echo_tail_s: float = 0.80 + + +@dataclass(slots=True) +class SessionSpec: + generation: int + skill_id: str + slots: dict[str, Any] + system_prompt: str + + +class SessionTelemetry(Protocol): + connected: bool + + async def send(self, payload: dict[str, Any]) -> None: ... + + +class GatewayDuplexSession: + """One generation-fenced connection to the existing MiniCPM Gateway.""" + + def __init__( + self, + config: RokidRuntimeConfig, + spec: SessionSpec, + audio_queue: DropOldestAudioQueue, + latest_frame: LatestFrame, + gate: OutputGate, + on_result: Callable[["GatewayDuplexSession", dict[str, Any]], Awaitable[None]], + ): + self.config = config + self.spec = spec + self.audio_queue = audio_queue + self.latest_frame = latest_frame + self.gate = gate + self.on_result = on_result + self.session_id = ( + f"omni_rokid_pb_g{spec.generation}_{int(time.time())}_{uuid.uuid4().hex[:6]}" + ) + self.status = "created" + self.last_error = "" + self.ws: aiohttp.ClientWebSocketResponse | None = None + self._task: asyncio.Task[None] | None = None + self._ready: asyncio.Future[None] | None = None + self._stopped = asyncio.Event() + self._closing = False + self._send_lock = asyncio.Lock() + + async def _send_json(self, payload: dict[str, Any]) -> None: + ws = self.ws + if ws is None or ws.closed: + raise RuntimeError("gateway session is not connected") + async with self._send_lock: + await ws.send_json(payload) + + def _ssl_context(self) -> ssl.SSLContext | None: + if not self.config.gateway_tls: + return None + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + return context + + async def start(self) -> None: + loop = asyncio.get_running_loop() + self._ready = loop.create_future() + self._ready.add_done_callback( + lambda future: None if future.cancelled() else future.exception() + ) + self._task = asyncio.create_task(self._run()) + await asyncio.wait_for( + asyncio.shield(self._ready), timeout=self.config.prepare_timeout_s + ) + + async def _run(self) -> None: + scheme = "wss" if self.config.gateway_tls else "ws" + url = f"{scheme}://{self.config.gateway}/ws/duplex/{self.session_id}" + self.status = "connecting" + LOG.info("[GW] connecting generation=%d %s", self.spec.generation, url) + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + url, + heartbeat=30, + max_msg_size=0, + ssl=self._ssl_context(), + ) as ws: + self.ws = ws + await self._prepare(ws) + self.status = "running" + if self._ready and not self._ready.done(): + self._ready.set_result(None) + send_task = asyncio.create_task(self._send_loop(ws)) + receive_task = asyncio.create_task(self._receive_loop(ws)) + done, pending = await asyncio.wait( + (send_task, receive_task), + return_when=asyncio.FIRST_COMPLETED, + ) + for task in pending: + task.cancel() + await asyncio.gather(*done, *pending, return_exceptions=True) + except asyncio.CancelledError: + raise + except Exception as exc: + self.status = "error" + self.last_error = str(exc) + if self._ready and not self._ready.done(): + self._ready.set_exception(exc) + if not self._closing: + LOG.warning("[GW] session %s failed: %s", self.session_id, exc) + finally: + self.ws = None + self._stopped.set() + if self.status != "error": + self.status = "stopped" + + async def _prepare(self, ws: aiohttp.ClientWebSocketResponse) -> None: + self.status = "queued" + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while queued") + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "queue_done": + break + if message_type == "error": + raise RuntimeError(payload.get("error") or "gateway queue error") + if message_type in {"queued", "queue_update"}: + LOG.info( + "[GW] queue position=%s eta=%s", + payload.get("position"), + payload.get("estimated_wait_s"), + ) + + self.status = "preparing" + await self._send_json( + { + "type": "prepare", + "system_prompt": self.spec.system_prompt, + "config": { + "force_listen_count": self.config.force_listen_count, + "chunk_ms": self.config.chunk_ms, + "generate_audio": True, + "max_new_speak_tokens_per_chunk": ( + self.config.max_new_speak_tokens_per_chunk + ), + "length_penalty": self.config.length_penalty, + }, + "max_slice_nums": self.config.max_slice_nums, + "deferred_finalize": True, + } + ) + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while preparing") + continue + payload = json.loads(message.data) + if payload.get("type") == "prepared": + LOG.info( + "[GW] prepared session=%s generation=%d skill=%s", + self.session_id, + self.spec.generation, + self.spec.skill_id, + ) + return + if payload.get("type") == "error": + raise RuntimeError(payload.get("error") or "gateway prepare error") + + async def _next_audio_chunk(self, carry: bytearray) -> np.ndarray | None: + samples = int(SAMPLE_RATE_IN * self.config.chunk_ms / 1000) + target_bytes = samples * PCM16_WIDTH + output = bytearray() + if carry: + take = min(target_bytes, len(carry)) + output.extend(carry[:take]) + del carry[:take] + deadline = time.monotonic() + max(0.1, self.config.chunk_ms / 1000 * 1.5) + while len(output) < target_bytes: + remaining = deadline - time.monotonic() + if remaining <= 0: + break + raw = await self.audio_queue.get(remaining) + if raw is None: + break + needed = target_bytes - len(output) + output.extend(raw[:needed]) + if len(raw) > needed: + carry.extend(raw[needed:]) + if not output: + return None + if len(output) < target_bytes: + output.extend(b"\x00" * (target_bytes - len(output))) + return pcm16le_to_float32(bytes(output)) + + async def _send_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + carry = bytearray() + last_frame_sequence = -1 + last_frame_sent = 0.0 + while not self._closing: + audio = await self._next_audio_chunk(carry) + if audio is None: + continue + payload: dict[str, Any] = { + "type": "audio_chunk", + "audio_base64": float32_to_base64(audio), + } + if self.gate.speech_hold_active: + payload["force_listen"] = True + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + frame_due = time.monotonic() - last_frame_sent >= self.config.image_resend_s + if ( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + and (frame.sequence != last_frame_sequence or frame_due) + ): + payload["frame_base64_list"] = [ + base64.b64encode(frame.jpeg).decode("ascii") + ] + last_frame_sequence = frame.sequence + last_frame_sent = time.monotonic() + # 诊断:真正送进 gateway 的每个 chunk。audio=xxpps 那个统计的是 + # "推进 audio_queue 的包数",看不出这里有没有按 1Hz 正常发出去。 + self._sent_chunks = getattr(self, "_sent_chunks", 0) + 1 + _lvl = float(np.abs(audio).mean()) if audio is not None else 0.0 + LOG.debug("[GW-SEND] #%d audio=%.2fs lvl=%.4f frame=%s hold=%s", + self._sent_chunks, + (len(audio) / SAMPLE_RATE_IN) if audio is not None else 0.0, + _lvl, + "frame_base64_list" in payload, + self.gate.speech_hold_active) + await self._send_json(payload) + + async def inject_task(self, text: str) -> bool: + """Send one text+latest-frame task to a newly prepared Skill Session.""" + text = text.strip() + if not text: + return False + payload: dict[str, Any] = { + "type": "audio_chunk", + "inject_text": text, + "max_slice_nums": self.config.max_slice_nums, + } + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + has_frame = bool( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + ) + if has_frame and frame.jpeg is not None: + payload["frame_base64_list"] = [ + base64.b64encode(frame.jpeg).decode("ascii") + ] + await self._send_json(payload) + LOG.info( + "[TASK] injected generation=%d skill=%s frame=%s text=%r", + self.spec.generation, + self.spec.skill_id, + has_frame, + text, + ) + return has_frame + + async def _receive_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + async for message in ws: + if message.type == aiohttp.WSMsgType.TEXT: + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type in {"result", "audio_only"}: + await self.on_result(self, payload) + elif message_type == "hint_audio": + # 强制措施念提示:独立播放,不进 on_result 状态机 + # (不记 model_turn / 不发 model.state / 不触发 EchoGuard), + # 避免和 duplex 主对话抢话、纠缠。 + hint_b64 = str(payload.get("audio_data") or "") + if hint_b64: + try: + pcm = np.frombuffer(base64.b64decode(hint_b64), dtype=np.float32) + # 念提示前先解除可能的 block(stop 时 block_and_flush 过), + # 否则 enqueue 会被丢。 + await self.speaker.resume() + await self.speaker.enqueue(pcm, self.spec.generation) + LOG.info("[HINT] 念提示播放: %r (%d samples)", + payload.get("text"), int(pcm.size)) + except Exception as exc: + LOG.warning("[HINT] 念提示播放失败: %s", exc) + elif message_type == "stopped": + return + elif message_type in {"timeout", "error"}: + raise RuntimeError( + payload.get("error") or payload.get("reason") or message_type + ) + elif message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + return + + async def stop(self, cleanup_mode: str) -> None: + self._closing = True + if self.ws is not None and not self.ws.closed: + try: + await self._send_json({"type": "stop", "cleanup_mode": cleanup_mode}) + except Exception: + pass + try: + await asyncio.wait_for(self._stopped.wait(), timeout=self.config.close_timeout_s) + except asyncio.TimeoutError: + pass + if self.ws is not None and not self.ws.closed: + await self.ws.close() + if self._task and not self._task.done(): + self._task.cancel() + await asyncio.gather(self._task, return_exceptions=True) + + +SessionFactory = Callable[ + [ + RokidRuntimeConfig, + SessionSpec, + DropOldestAudioQueue, + LatestFrame, + OutputGate, + Callable[[GatewayDuplexSession, dict[str, Any]], Awaitable[None]], + ], + GatewayDuplexSession, +] + + +class GatewaySessionManager: + """Python counterpart of the frozen BrowserSessionAdapter contract.""" + + def __init__( + self, + config: RokidRuntimeConfig, + registry: SkillRegistry, + audio_queue: DropOldestAudioQueue, + latest_frame: LatestFrame, + speaker: SpeakerSink, + session_factory: SessionFactory = GatewayDuplexSession, + ): + self.config = config + self.registry = registry + self.audio_queue = audio_queue + self.latest_frame = latest_frame + self.speaker = speaker + self.session_factory = session_factory + self.gate = OutputGate(current_skill=registry.default_skill) + self.harness: SessionTelemetry | None = None + self.active: GatewayDuplexSession | None = None + self._restart_lock = asyncio.Lock() + self._playback_epoch = 0 + self._playback_release_task: asyncio.Task[None] | None = None + + async def send_telemetry(self, payload: dict[str, Any]) -> None: + if self.harness is not None: + await self.harness.send(payload) + + async def _set_playback_active(self, active: bool, source: str) -> None: + await self.send_telemetry( + { + "type": "playback.state", + "active": active, + "source": source, + "generation": self.gate.generation, + "pending_ms": round(self.speaker.pending_ms(), 1), + } + ) + + async def _mark_playback_started(self, source: str) -> None: + self._playback_epoch += 1 + epoch = self._playback_epoch + if self._playback_release_task is not None: + self._playback_release_task.cancel() + await self._set_playback_active(True, source) + + async def release_after_drain() -> None: + try: + while self.speaker.pending_ms() > 0: + await asyncio.sleep( + max(0.02, min(0.25, self.speaker.pending_ms() / 1000.0)) + ) + await asyncio.sleep(max(0.0, self.config.playback_echo_tail_s)) + if epoch == self._playback_epoch: + await self._set_playback_active(False, source) + except asyncio.CancelledError: + raise + + self._playback_release_task = asyncio.create_task(release_after_drain()) + + async def _clear_playback_state(self, source: str) -> None: + self._playback_epoch += 1 + if self._playback_release_task is not None: + self._playback_release_task.cancel() + await asyncio.gather(self._playback_release_task, return_exceptions=True) + self._playback_release_task = None + await self._set_playback_active(False, source) + + def _make_spec( + self, + skill_id: str, + slots: dict[str, Any], + system_prompt: str | None = None, + ) -> SessionSpec: + rendered = self.registry.render(skill_id, slots) + return SessionSpec( + generation=self.gate.generation, + skill_id=skill_id, + slots=dict(slots), + system_prompt=system_prompt or rendered.text, + ) + + async def start_initial(self) -> None: + async with self._restart_lock: + if self.active is not None: + return + spec = self._make_spec(self.registry.default_skill, {}) + session = self.session_factory( + self.config, + spec, + self.audio_queue, + self.latest_frame, + self.gate, + self.handle_result, + ) + self.active = session + try: + await session.start() + except Exception: + self.active = None + raise + await self._emit_bound() + + async def _emit_bound(self) -> None: + await self.send_telemetry( + { + "type": "session.state", + "phase": "bound", + "generation": self.gate.generation, + "skill_id": self.gate.current_skill, + "slots": dict(self.gate.current_slots or {}), + "session_id": self.active.session_id if self.active else None, + } + ) + + async def emit_recovery_sync(self) -> None: + if self.active is None: + return + await self.send_telemetry( + { + "type": "session.state", + "phase": "restart_complete", + "generation": self.gate.generation, + "skill_id": self.gate.current_skill, + "slots": dict(self.gate.current_slots or {}), + "new_session_id": self.active.session_id, + "cleanup_mode": "reconnect_sync", + } + ) + await self._emit_bound() + + async def handle_control(self, event: dict[str, Any]) -> dict[str, Any]: + if not event.get("accepted"): + return {"ok": False, "ignored": True} + intent = str(event.get("intent") or "") + if intent == "stop_speech": + return await self.stop_speech(event) + if intent == "resume_speech": + return await self.resume_speech(event) + if intent in { + "reset_session", + "activate_skill", + "cancel_skill", + "return_to_chat", + }: + return await self.restart(event) + return {"ok": False, "ignored": True} + + def _ack_base(self, event: dict[str, Any]) -> dict[str, Any]: + return { + "type": "control.ack", + "event_id": event.get("event_id"), + "intent": event.get("intent"), + "generation": self.gate.generation, + "dropped_old_text": self.gate.dropped_old_text, + "dropped_old_audio": self.gate.dropped_old_audio, + } + + async def stop_speech( + self, event: dict[str, Any], *, emit_ack: bool = True + ) -> dict[str, Any]: + self.gate.stop() + await self.speaker.block_and_flush() + await self._clear_playback_state("stop") + ack = {**self._ack_base(event), "ok": True} + if emit_ack: + await self.send_telemetry(ack) + LOG.info("[CONTROL] STOP event=%s", event.get("event_id")) + return ack + + async def resume_speech(self, event: dict[str, Any]) -> dict[str, Any]: + self.gate.resume() + await self.speaker.resume() + ack = {**self._ack_base(event), "ok": True} + await self.send_telemetry(ack) + LOG.info("[CONTROL] RESUME event=%s", event.get("event_id")) + return ack + + async def restart(self, event: dict[str, Any]) -> dict[str, Any]: + async with self._restart_lock: + requested_skill = str(event.get("skill_id") or self.registry.default_skill) + requested_slots = dict(event.get("slots") or {}) + if ( + str(event.get("intent")) != "reset_session" + and requested_skill == self.gate.current_skill + and same_slots(requested_slots, dict(self.gate.current_slots or {})) + ): + ack = {**self._ack_base(event), "ok": True, "no_restart": True} + await self.send_telemetry(ack) + return ack + + started = time.monotonic() + await self.stop_speech(event, emit_ack=False) + self.gate.restart_in_progress = True + old_session = self.active + old_session_id = old_session.session_id if old_session else None + self.gate.generation += 1 + await self.send_telemetry( + { + "type": "session.state", + "phase": "restart_started", + "generation": self.gate.generation, + "event_id": event.get("event_id"), + "old_session_id": old_session_id, + } + ) + self.active = None + try: + if old_session: + await old_session.stop(self.config.cleanup_mode) + self.audio_queue.clear() + spec = self._make_spec( + requested_skill, + requested_slots, + str(event.get("system_prompt") or "") or None, + ) + session = self.session_factory( + self.config, + spec, + self.audio_queue, + self.latest_frame, + self.gate, + self.handle_result, + ) + self.active = session + await session.start() + self.gate.current_skill = requested_skill + self.gate.current_slots = requested_slots + self.gate.replacement_ready() + await self.speaker.resume() + await self._emit_bound() + latency_ms = (time.monotonic() - started) * 1000.0 + state = { + "type": "session.state", + "phase": "restart_complete", + "generation": self.gate.generation, + "skill_id": requested_skill, + "slots": requested_slots, + "old_session_id": old_session_id, + "new_session_id": session.session_id, + "cleanup_mode": self.config.cleanup_mode, + } + await self.send_telemetry(state) + if self.config.play_audio and self.config.session_ready_chime: + cue = make_session_ready_chime( + amplitude=self.config.session_ready_chime_volume + ) + self.gate.local_cue_mute_until_mono = max( + self.gate.local_cue_mute_until_mono, + time.monotonic() + + cue.size / SAMPLE_RATE_OUT + + self.config.session_ready_chime_feedback_guard_s, + ) + await self.speaker.enqueue(cue, self.gate.generation) + await self._mark_playback_started("session_ready_chime") + LOG.info( + "[CUE] session ready generation=%d skill=%s", + self.gate.generation, + requested_skill, + ) + trigger = self.registry.task_trigger(requested_skill, requested_slots) + trigger_frame = False + trigger_error = "" + if trigger: + try: + trigger_frame = await session.inject_task(trigger) + await self.send_telemetry( + { + "type": "session.state", + "phase": "task_trigger_sent", + "generation": self.gate.generation, + "skill_id": requested_skill, + "slots": requested_slots, + "session_id": session.session_id, + "has_frame": trigger_frame, + } + ) + except Exception as exc: + trigger_error = str(exc) + LOG.warning( + "[TASK] one-shot trigger failed skill=%s: %s", + requested_skill, + exc, + ) + ack = { + **self._ack_base(event), + "ok": True, + "restart_latency_ms": latency_ms, + "skill_id": requested_skill, + "slots": requested_slots, + "old_session_id": old_session_id, + "new_session_id": session.session_id, + "cleanup_mode": self.config.cleanup_mode, + "task_trigger_sent": bool(trigger and not trigger_error), + "task_trigger_has_frame": trigger_frame, + "task_trigger_error": trigger_error, + } + await self.send_telemetry(ack) + LOG.info( + "[CONTROL] %s ready generation=%d session=%s latency_ms=%.1f", + requested_skill, + self.gate.generation, + session.session_id, + latency_ms, + ) + return ack + except Exception as exc: + if self.active: + await self.active.stop(self.config.cleanup_mode) + self.active = None + self.gate.restart_in_progress = False + ack = {**self._ack_base(event), "ok": False, "error": str(exc)} + await self.send_telemetry(ack) + LOG.exception("[CONTROL] restart failed") + return ack + + async def handle_result( + self, session: GatewayDuplexSession, result: dict[str, Any] + ) -> None: + is_listen = bool(result.get("is_listen")) + text = str(result.get("text") or "") + audio_b64 = str(result.get("audio_data") or "") + stale = ( + session is not self.active + or session.spec.generation != self.gate.generation + ) + if stale or (self.gate.drop_output_until_listen and not is_listen): + if text: + self.gate.dropped_old_text += 1 + if audio_b64: + self.gate.dropped_old_audio += 1 + # 诊断:这条路径原本静默 return,模型的输出被整个丢掉却不留痕迹 + #(表现就是 ai(calls=0) + [MODEL] 只有孤零零一条)。打出丢弃原因。 + self._drop_n = getattr(self, "_drop_n", 0) + 1 + if self._drop_n <= 3 or self._drop_n % 100 == 0: + LOG.warning( + "[GW-DROP] #%d stale=%s (active=%s gen_sess=%s gen_gate=%s) " + "drop_until_listen=%s is_listen=%s text=%r audio=%dB", + self._drop_n, stale, + session is self.active, + session.spec.generation, self.gate.generation, + self.gate.drop_output_until_listen, is_listen, + text[:20], len(audio_b64)) + return + if is_listen and self.gate.drop_output_until_listen: + if not self.gate.speech_hold_active: + self.gate.drop_output_until_listen = False + await self.speaker.resume() + audio_samples = 0 + if audio_b64 and not is_listen: + try: + pcm = np.frombuffer(base64.b64decode(audio_b64), dtype=np.float32) + audio_samples = int(pcm.size) + await self.speaker.enqueue(pcm, session.spec.generation) + if self.config.play_audio: + await self._mark_playback_started("model") + except Exception as exc: + LOG.warning("model audio decode failed: %s", exc) + await self.send_telemetry( + { + "type": "model.state", + "state": "listen" if is_listen else "speak", + "text": text, + "generation": session.spec.generation, + "session_id": session.session_id, + "skill_id": session.spec.skill_id, + "slots": dict(session.spec.slots), + # llama.cpp-omni marks each decode slice as end_of_turn. The + # actual duplex turn boundary is the later __IS_LISTEN__ + # result, so keep the raw marker for diagnostics but aggregate + # model text until listening resumes. + "decode_end": bool(result.get("end_of_turn")), + "end_of_turn": is_listen, + "message_type": str(result.get("type") or "result"), + "audio_samples": audio_samples, + "audio_ms": round( + audio_samples * 1000.0 / SAMPLE_RATE_OUT, 1 + ), + } + ) + if text: + LOG.info("[MODEL] listen=%s text=%s", is_listen, text) + + async def close(self) -> None: + await self._clear_playback_state("close") + if self.active: + await self.active.stop(self.config.cleanup_mode) + self.active = None + + def health(self) -> dict[str, Any]: + return { + "generation": self.gate.generation, + "current_skill": self.gate.current_skill, + "current_slots": dict(self.gate.current_slots or {}), + "speech_hold_active": self.gate.speech_hold_active, + "restart_in_progress": self.gate.restart_in_progress, + "dropped_old_text": self.gate.dropped_old_text, + "dropped_old_audio": self.gate.dropped_old_audio, + "session_id": self.active.session_id if self.active else None, + "gateway_status": self.active.status if self.active else "disconnected", + "gateway_error": self.active.last_error if self.active else "", + } + + +class HarnessClient: + def __init__( + self, + url: str, + client_id: str, + manager: GatewaySessionManager, + reconnect_s: float, + ): + separator = "&" if "?" in url else "?" + self.url = f"{url}{separator}client_id={client_id}" + self.manager = manager + self.reconnect_s = reconnect_s + self.connected = False + self.ws: aiohttp.ClientWebSocketResponse | None = None + self._stop = asyncio.Event() + self._send_lock = asyncio.Lock() + self._control_tasks: set[asyncio.Task[Any]] = set() + + # 外部可挂的只读观察者:收到未被上面分支处理的消息时调用(同步、异常吞掉)。 + # 不改构造签名,赋值即可:client.on_message = fn + on_message = None + + async def run(self) -> None: + while not self._stop.is_set(): + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + self.url, heartbeat=30, max_msg_size=0 + ) as ws: + self.ws = ws + self.connected = True + LOG.info("Harness connected: %s", self.url) + async for message in ws: + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in ( + aiohttp.WSMsgType.CLOSED, + aiohttp.WSMsgType.ERROR, + ): + break + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "harness.ready": + await self.manager.emit_recovery_sync() + elif message_type == "control.intent": + task = asyncio.create_task( + self.manager.handle_control(payload) + ) + self._control_tasks.add(task) + task.add_done_callback(self._control_tasks.discard) + # 可选旁路:把其余消息(如 asr.transcript)交给外部观察者。 + # 默认 None,行为与原来完全一致。8021 的 asr.transcript 只投递给 + # "送音频进来的那个 client" 的 outbound 队列(每个 client_id 有 + # 独立 runtime),另开一条连接是收不到的,只能在这里截。 + elif self.on_message is not None: + try: + self.on_message(payload) + except Exception: + pass + except asyncio.CancelledError: + raise + except Exception as exc: + if not self._stop.is_set(): + LOG.warning("Harness connection failed: %s", exc) + finally: + self.connected = False + self.ws = None + if not self._stop.is_set(): + await asyncio.sleep(self.reconnect_s) + + async def send(self, payload: dict[str, Any]) -> None: + async with self._send_lock: + if self.ws is not None and not self.ws.closed: + await self.ws.send_json(payload) + + async def send_audio(self, samples: np.ndarray) -> None: + if samples.size == 0: + return + await self.send( + { + "type": "audio.mirror", + "started_at_ms": now_ms() - samples.size * 1000.0 / SAMPLE_RATE_IN, + "sample_rate": SAMPLE_RATE_IN, + "audio_b64": float32_to_base64(samples), + } + ) + + async def send_frame(self, jpeg: bytes, sequence: int, timestamp_ms: float) -> None: + await self.send( + { + "type": "frame.shadow", + "frame_id": f"rokid_{sequence}_{int(timestamp_ms)}", + "timestamp_ms": timestamp_ms, + "jpeg_b64": base64.b64encode(jpeg).decode("ascii"), + } + ) + + async def close(self) -> None: + self._stop.set() + if self.ws is not None and not self.ws.closed: + await self.ws.close() + for task in tuple(self._control_tasks): + task.cancel() + await asyncio.gather(*self._control_tasks, return_exceptions=True) + + +@dataclass(slots=True) +class RuntimeStats: + started_mono: float = field(default_factory=time.monotonic) + audio_packets: int = 0 + audio_bytes: int = 0 + audio_clients: int = 0 + image_count: int = 0 + image_bytes: int = 0 + last_audio_ms: float = 0.0 + audio_rms: float = 0.0 + audio_peak: float = 0.0 + non_silent_audio_packets: int = 0 + + +class PhaseBRokidRuntime: + """Rokid sensor ingress + frozen Harness control + Gateway session adapter.""" + + def __init__( + self, + config: RokidRuntimeConfig, + *, + speaker: SpeakerSink | None = None, + session_factory: SessionFactory = GatewayDuplexSession, + ): + self.config = config + self.registry = SkillRegistry(config.skills_config) + self.audio_queue = DropOldestAudioQueue(config.audio_queue_packets) + self.audio_mirror = AudioMirrorChunker() + self.latest_frame = LatestFrame() + self.stats = RuntimeStats(started_mono=time.monotonic()) + self.speaker = speaker or (PCSpeaker() if config.play_audio else NullSpeaker()) + self.manager = GatewaySessionManager( + config, + self.registry, + self.audio_queue, + self.latest_frame, + self.speaker, + session_factory=session_factory, + ) + self.harness = HarnessClient( + config.harness_url, + config.harness_client_id, + self.manager, + config.reconnect_s, + ) + self.manager.harness = self.harness + self._tasks: list[asyncio.Task[Any]] = [] + self._close_lock = asyncio.Lock() + self._closed = False + self._no_input_warning_emitted = False + + def health(self) -> dict[str, Any]: + return { + "ok": True, + "phase": "B", + "device": "rokid", + "uptime_s": round(time.monotonic() - self.stats.started_mono, 3), + "harness_connected": self.harness.connected, + "audio_packets_in": self.stats.audio_packets, + "audio_bytes_in": self.stats.audio_bytes, + "audio_clients": self.stats.audio_clients, + "latest_audio_age_ms": ( + round(now_ms() - self.stats.last_audio_ms, 1) + if self.stats.last_audio_ms + else None + ), + "audio_queue_size": self.audio_queue.size, + "dropped_audio_packets": self.audio_queue.dropped_packets, + "audio_rms": round(self.stats.audio_rms, 6), + "audio_peak": round(self.stats.audio_peak, 6), + "input_gain": self.config.input_gain, + "effective_audio_rms": round( + min(1.0, self.stats.audio_rms * self.config.input_gain), 6 + ), + "non_silent_audio_packets": self.stats.non_silent_audio_packets, + "image_count": self.stats.image_count, + "device_input_ready": bool( + self.stats.audio_packets or self.stats.image_count + ), + "latest_image_age_ms": ( + round(now_ms() - self.latest_frame.timestamp_ms, 1) + if self.latest_frame.timestamp_ms + else None + ), + **self.manager.health(), + } + + async def _initial_session_loop(self) -> None: + while True: + try: + await self.manager.start_initial() + return + except asyncio.CancelledError: + raise + except Exception as exc: + LOG.warning("initial Gateway session failed: %s", exc) + await asyncio.sleep(self.config.reconnect_s) + + async def _stats_loop(self) -> None: + previous_audio = 0 + previous_image = 0 + while True: + await asyncio.sleep(5.0) + if ( + not self._no_input_warning_emitted + and time.monotonic() - self.stats.started_mono >= 10.0 + and self.stats.audio_packets == 0 + and self.stats.image_count == 0 + ): + self._no_input_warning_emitted = True + LOG.warning( + "[ROKID][NO_INPUT] no PCM/JPEG has reached this process. " + "After the PC runtime is listening, restart OpenGlass " + "Sensor Mode on the glasses (STOP -> RUN) and verify that " + "the APK targets the PC WLAN address on port %d", + self.config.port, + ) + LOG.info( + "[STATS] audio=%.1fpps images=%d(+%d) audio_clients=%d " + "queue=%d drops=%d rms=%.4f peak=%.4f harness=%s gateway=%s " + "skill=%s generation=%d", + (self.stats.audio_packets - previous_audio) / 5.0, + self.stats.image_count, + self.stats.image_count - previous_image, + self.stats.audio_clients, + self.audio_queue.size, + self.audio_queue.dropped_packets, + self.stats.audio_rms, + self.stats.audio_peak, + self.harness.connected, + self.manager.health()["gateway_status"], + self.manager.gate.current_skill, + self.manager.gate.generation, + ) + previous_audio = self.stats.audio_packets + previous_image = self.stats.image_count + + async def start(self) -> None: + await self.speaker.start() + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + ] + + async def close(self) -> None: + async with self._close_lock: + if self._closed: + return + LOG.info("Rokid runtime shutdown started") + + async def bounded(label: str, awaitable: Awaitable[None]) -> None: + try: + await asyncio.wait_for( + awaitable, + timeout=max(0.5, self.config.close_timeout_s), + ) + except asyncio.TimeoutError: + LOG.warning( + "Rokid shutdown step timed out: %s (continuing)", label + ) + except Exception as exc: + LOG.warning( + "Rokid shutdown step failed: %s: %s", label, exc + ) + + await bounded("harness", self.harness.close()) + for task in self._tasks: + task.cancel() + if self._tasks: + await bounded( + "background_tasks", + asyncio.gather(*self._tasks, return_exceptions=True), + ) + self._tasks.clear() + await bounded("gateway_session", self.manager.close()) + await bounded("pc_speaker", self.speaker.close()) + self.audio_queue.clear() + self.audio_mirror.clear() + self._closed = True + LOG.info("Rokid runtime shutdown complete; port may be reused") + + def create_app(self) -> web.Application: + app = web.Application(client_max_size=8 * 1024 * 1024) + app["runtime"] = self + + async def health(_request: web.Request) -> web.Response: + return web.json_response(self.health()) + + async def capture(_request: web.Request) -> web.Response: + if not self.latest_frame.jpeg: + return web.Response(status=404, text="no image") + return web.Response(body=self.latest_frame.jpeg, content_type="image/jpeg") + + async def rokid_image(request: web.Request) -> web.Response: + raw = await request.read() + if not (raw.startswith(b"\xff\xd8") and raw.endswith(b"\xff\xd9")): + return web.Response(status=400, text="expected JPEG bytes") + try: + jpeg = await asyncio.to_thread( + rotate_jpeg_clockwise, + raw, + self.config.image_rotate_cw, + self.config.image_jpeg_quality, + ) + except Exception as exc: + return web.Response(status=400, text=str(exc)) + timestamp = now_ms() + self.latest_frame.set(jpeg, timestamp) + self.stats.image_count += 1 + self.stats.image_bytes += len(raw) + if self.stats.image_count == 1: + LOG.info("[ROKID] first JPEG received from %s", request.remote) + asyncio.create_task( + self.harness.send_frame( + jpeg, self.latest_frame.sequence, timestamp + ) + ) + return web.json_response( + {"ok": True, "image_count": self.stats.image_count, "bytes": len(raw)} + ) + + async def rokid_audio(request: web.Request) -> web.WebSocketResponse: + ws = web.WebSocketResponse(heartbeat=30, max_msg_size=0) + await ws.prepare(request) + self.stats.audio_clients += 1 + LOG.info("[ROKID] audio connected from %s", request.remote) + try: + async for message in ws: + if message.type == aiohttp.WSMsgType.BINARY: + raw = bytes(message.data) + if len(raw) < PCM16_WIDTH: + continue + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + self.stats.audio_packets += 1 + self.stats.audio_bytes += len(raw) + self.stats.last_audio_ms = now_ms() + if self.stats.audio_packets == 1: + LOG.info("[ROKID] first PCM packet received") + samples = pcm16le_to_float32(raw) + packet_rms = float(np.sqrt(np.mean(np.square(samples)))) + packet_peak = float(np.max(np.abs(samples))) + self.stats.audio_rms = ( + 0.8 * self.stats.audio_rms + 0.2 * packet_rms + ) + self.stats.audio_peak = packet_peak + if packet_rms >= 0.01: + self.stats.non_silent_audio_packets += 1 + if time.monotonic() >= self.manager.gate.local_cue_mute_until_mono: + amplified = apply_pcm16_gain(raw, self.config.input_gain) + self.audio_queue.put_nowait(amplified) + for frame in self.audio_mirror.feed(amplified): + await self.harness.send_audio(frame) + elif message.type == aiohttp.WSMsgType.ERROR: + break + finally: + self.stats.audio_clients = max(0, self.stats.audio_clients - 1) + LOG.info("[ROKID] audio disconnected from %s", request.remote) + return ws + + async def on_startup(_app: web.Application) -> None: + await self.start() + + async def on_cleanup(_app: web.Application) -> None: + await self.close() + + app.router.add_get("/", health) + app.router.add_get("/health", health) + app.router.add_get("/capture", capture) + app.router.add_post("/rokid/image", rokid_image) + app.router.add_get("/rokid/audio", rokid_audio) + app.on_startup.append(on_startup) + app.on_cleanup.append(on_cleanup) + return app + + +def default_skills_config() -> str: + return str( + Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Rokid Phase B adapter: sensors + Harness + MiniCPM Gateway" + ) + parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--port", type=int, default=18_080) + parser.add_argument("--gateway", default="localhost:8040") + parser.add_argument("--gateway-tls", action="store_true", default=False) + parser.add_argument( + "--no-gateway-tls", dest="gateway_tls", action="store_false" + ) + parser.add_argument( + "--harness-url", default="ws://127.0.0.1:8021/ws/control" + ) + parser.add_argument("--client-id", default="rokid-phase-b") + parser.add_argument("--skills-config", default=default_skills_config()) + parser.add_argument("--cleanup-mode", choices=("light", "full"), default="light") + parser.add_argument("--image-rotate-cw", type=int, default=270) + parser.add_argument("--image-jpeg-quality", type=int, default=95) + parser.add_argument("--audio-queue-packets", type=int, default=96) + parser.add_argument( + "--input-gain", + type=float, + default=12.0, + help="Rokid PCM gain before Harness/Gateway; clipped to PCM16", + ) + parser.add_argument("--chunk-ms", type=int, default=1_000) + parser.add_argument("--force-listen-count", type=int, default=3) + parser.add_argument("--no-play", action="store_true") + parser.add_argument( + "--no-session-ready-chime", + action="store_true", + help="disable the local restart_complete notification cue", + ) + parser.add_argument( + "--session-ready-chime-volume", + type=float, + default=0.32, + help="restart cue amplitude in [0, 1] (default: 0.32)", + ) + parser.add_argument( + "--playback-echo-tail-s", + type=float, + default=0.80, + help="keep EchoGuard active after the PC speaker queue drains", + ) + parser.add_argument("--log-level", default="INFO") + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if not 0.0 <= args.session_ready_chime_volume <= 1.0: + raise SystemExit("--session-ready-chime-volume must be between 0 and 1") + if args.playback_echo_tail_s < 0.0: + raise SystemExit("--playback-echo-tail-s must be non-negative") + logging.basicConfig( + level=getattr(logging, args.log_level.upper(), logging.INFO), + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + force=True, + ) + config = RokidRuntimeConfig( + host=args.host, + port=args.port, + gateway=args.gateway, + gateway_tls=args.gateway_tls, + harness_url=args.harness_url, + harness_client_id=args.client_id, + skills_config=args.skills_config, + cleanup_mode=args.cleanup_mode, + chunk_ms=args.chunk_ms, + force_listen_count=args.force_listen_count, + audio_queue_packets=args.audio_queue_packets, + input_gain=args.input_gain, + image_rotate_cw=args.image_rotate_cw, + image_jpeg_quality=args.image_jpeg_quality, + play_audio=not args.no_play, + session_ready_chime=not args.no_session_ready_chime, + session_ready_chime_volume=args.session_ready_chime_volume, + playback_echo_tail_s=args.playback_echo_tail_s, + ) + runtime = PhaseBRokidRuntime(config) + watchdog = CtrlCExitWatchdog() + shutdown_signals = [signal.SIGINT] + if hasattr(signal, "SIGBREAK"): + shutdown_signals.append(signal.SIGBREAK) + previous_handlers = { + signum: signal.getsignal(signum) for signum in shutdown_signals + } + + def handle_console_shutdown(signum: int, frame: Any) -> None: + watchdog.arm() + previous_handler = previous_handlers[signum] + if callable(previous_handler): + previous_handler(signum, frame) + else: + raise KeyboardInterrupt + + for signum in shutdown_signals: + signal.signal(signum, handle_console_shutdown) + LOG.info("Rokid Phase B input: http://%s:%d", config.host, config.port) + LOG.info("Harness: %s", config.harness_url) + LOG.info("Gateway: %s://%s", "wss" if config.gateway_tls else "ws", config.gateway) + try: + web.run_app( + runtime.create_app(), + host=config.host, + port=config.port, + access_log=None, + shutdown_timeout=max(0.5, config.close_timeout_s), + handler_cancellation=True, + ) + except OSError as exc: + if getattr(exc, "winerror", None) == 10048: + LOG.error( + "Port %d is already occupied by another process. A runtime " + "started with this patched version exits within %.0fs after " + "Ctrl+C.", + config.port, + CTRL_C_HARD_EXIT_S, + ) + raise SystemExit(2) from None + raise + finally: + for signum, previous_handler in previous_handlers.items(): + signal.signal(signum, previous_handler) + if watchdog.armed: + LOG.info("Graceful shutdown returned; exiting Rokid process") + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/session_recorder.py b/extensions/assistive_harness/phase_b/session_recorder.py new file mode 100644 index 0000000..ce6bcda --- /dev/null +++ b/extensions/assistive_harness/phase_b/session_recorder.py @@ -0,0 +1,90 @@ +"""Session 录制器(对齐 -v 的 SessionRecorder 格式)。 + +沿用 pc_vlm_v5_funnel.SessionRecorder 的落盘结构,让 -o 链路录出的 session +和 -v 完全一致,可用 -v 的分析 / rerun 工具链直接读。 + + sessions// + images/q{NNN}_f{MM}.jpg 每轮一簇帧(整簇存) + queries.jsonl 每行一条,-v 原字段 + 漏斗判定字段 + meta.json + +启动标志:-v 是「ASR 出 query」,-o 里换成「链路启动」——从 start 起持续录, +每轮漏斗决策 append 一条。qid 单调递增(一轮 = 一个 qid)。 + +queries.jsonl 每行(保留 -v 原字段 qid/text/frames/ts,兼容;追加漏斗字段): + { + "qid": 3, "ts": 1699..., # -v 原字段 + "text": "", # -v 原字段(-o 无 ASR query 文本,留空/可后填) + "frames": ["q003_f00.jpg", ...], # -v 原字段(整簇帧文件名) + "reason": "severe_shake", # 漏斗判定 + "send": false, + "hint": "晃得厉害,请拿稳一下", + "best_index": 1, + "af_triggered": true, "af_ok": true, + "timings": {...} + } +""" +from __future__ import annotations + +import json +import time +from pathlib import Path +from typing import Optional + + +class SessionRecorder: + def __init__(self, sessions_root: str = "sessions", sid: Optional[str] = None): + sid = sid or time.strftime("%Y%m%d_%H%M%S") + self.dir = Path(sessions_root) / sid + self.images = self.dir / "images" + self.images.mkdir(parents=True, exist_ok=True) + self.jsonl = self.dir / "queries.jsonl" + (self.dir / "meta.json").write_text( + json.dumps({"sid": sid, "source": "esp32_runtime", "created": time.time()}, + ensure_ascii=False, indent=2), + encoding="utf-8") + self._qid = 0 + print(f"[SESSION] recording to {self.dir}") + + def record(self, decision, text: str = "") -> None: + """存一轮漏斗决策:整簇帧落盘 + queries.jsonl append 一条。 + + decision: FunnelDecision(含 frames / best / reason / hint / + best_index / af_triggered / af_ok / timings) + text: 可选,-o 无 ASR query 文本,留空;如上层有 ASR 结果可传入。 + """ + self._qid += 1 + qid = self._qid + frame_names = [] + frames = decision.frames or ([] if decision.best is None else [decision.best]) + for i, jpg in enumerate(frames): + name = f"q{qid:03d}_f{i:02d}.jpg" + try: + (self.images / name).write_bytes(jpg) + frame_names.append(name) + except Exception: + pass + + rec = { + # -v 原字段(兼容 -v 工具链) + "qid": qid, + "ts": time.time(), + "text": text, + "frames": frame_names, + # 漏斗判定字段 + "send": bool(decision.send), + "reason": decision.reason, + "hint": decision.hint, + "best_index": decision.best_index, + "af_triggered": decision.af_triggered, + "af_ok": decision.af_ok, + "timings": decision.timings, + } + try: + with self.jsonl.open("a", encoding="utf-8") as f: + f.write(json.dumps(rec, ensure_ascii=False) + "\n") + except Exception: + pass + + def close(self) -> None: + print(f"[SESSION] recorded {self._qid} queries -> {self.dir}") diff --git a/extensions/assistive_harness/phase_b/templates/live.html b/extensions/assistive_harness/phase_b/templates/live.html new file mode 100644 index 0000000..96099f9 --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/live.html @@ -0,0 +1,620 @@ + + + + + +AI 眼镜 · 实时演示 + + + + +
+
+
+ 🕶 +
+
AI 眼镜 · 实时演示
+
Real-time multimodal assistant for the visually impaired
+
+
+
+ + 连接中… + + + 待连接 + + + 输入异常 + + 📁 历史 + +
+
+ +
+
+ +
+
📷
+
等待眼镜画面…
+
+
+ LIVE · 眼镜第一视角 +
+
+ 📡 前方 -- m + 🧭 朝向 --° +
+
+ 🎤 +
+ -- dB +
+
+
+
+ +
+
+ 💬 对话 + 0 轮 +
+
+
开始说话以与 AI 眼镜互动…
+
+
+
+ +
+
+ AI 静默中 +
+
+
+ + +
+
+
+ +
⚡ 用户打断了 AI
+ + + + + +
+
+

停止并保存?

+

将立即结束本次会话,并把视频 / 音频 / 字幕打包写盘。确认后无法恢复。

+
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/templates/replay.html b/extensions/assistive_harness/phase_b/templates/replay.html new file mode 100644 index 0000000..458d238 --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/replay.html @@ -0,0 +1,566 @@ + + + + + + AI 眼镜 · 回放 + + + + +
+
+
+ 🎬 +
+
AI 眼镜 · 会话回放
+
+
+
+
+ ·探测中… + 0 轮 + ⬅ 所有会话 + 🔴 实时 +
+
+ +
+
+
+
+
加载中…
+
+
+ +
+
+ 💬 字幕时间线 + 点击跳转 +
+
+
暂无字幕
+
+
+
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/templates/replay_index.html b/extensions/assistive_harness/phase_b/templates/replay_index.html new file mode 100644 index 0000000..efcc60a --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/replay_index.html @@ -0,0 +1,321 @@ + + + + + + AI 眼镜 · 回访 + + + + +
+
+
+ 🕶 +
+
AI 眼镜 · 会话回访
+
Session replay & offline inspection
+
+
+
+ — 条会话 + ⬅ 返回实时 +
+
+ +
+
+
+ 点击行进入回放 · 所有会话按时间倒序 +
+
+
Loading…
+
+
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/timing_probe.py b/extensions/assistive_harness/phase_b/timing_probe.py new file mode 100644 index 0000000..6d921c4 --- /dev/null +++ b/extensions/assistive_harness/phase_b/timing_probe.py @@ -0,0 +1,163 @@ +"""时序探针(纯旁路,不改链路行为)。 + +只做一件事:把 ESP32 -o 链路里"取图 / 音频 / 相位"的时间点写进一个 CSV, +供事后分析漏斗该插在哪、跨几个 chunk、音图怎么抢。 + +不接对焦、不接漏斗判定 —— 这是纯时序探针。 + +列名尽量沿用 -v 的 latency CSV 风格(grab_ms / n_frames 等), +额外加 -o 特有的 chunk / 音频相位列,方便和 -v 数据对比、也让分析工具链复用。 + +用法(在 esp32_runtime 里): + from .timing_probe import TimingProbe + probe = TimingProbe(enabled=args.timing_probe, path=args.timing_csv, chunk_ms=1000) + # 取图: + probe.mark_grab(seq, grab_ms, jpeg_bytes, since_last_ms) + # 音频(每包调,内部按秒聚合): + probe.mark_audio(seq, n_samples, drops, rms) + # 关闭:probe.close() +""" +from __future__ import annotations + +import csv +import time +from pathlib import Path +from typing import Optional + + +class TimingProbe: + def __init__(self, enabled: bool = True, path: Optional[str] = None, + chunk_ms: int = 1000): + self.enabled = enabled + self.chunk_ms = chunk_ms + self._t0 = time.monotonic() # 进程起点,用于算 rel_ms / chunk_id + self._f = None + self._w = None + + # ── 音频活动/静默相位判定(用于给每帧图标 phase)── + # 简单能量门限:rms > 阈值算"活动",否则"静默"。阈值可调。 + self._voice_rms_gate = 0.01 + self._last_audio_active_rel_ms = -1e9 # 最近一次音频活动的相对时刻 + self._audio_active = False + + # ── 音频按秒聚合缓存 ── + self._agg_bucket = -1 # 当前聚合到第几秒 + self._agg_pkts = 0 + self._agg_seqgap = 0 # 本秒内 seq 跳变累计(= 真丢包数) + self._agg_rms_sum = 0.0 + self._agg_active_pkts = 0 + self._last_seq = None # 上一包 seq,用于算 gap + + if self.enabled: + p = Path(path or f"timing_{time.strftime('%Y%m%d_%H%M%S')}.csv") + self._f = open(p, "w", newline="", encoding="utf-8") + self._w = csv.writer(self._f) + # 统一表头:kind 区分 grab / audio 两类行 + self._w.writerow([ + "kind", # "grab" 或 "audio" + "rel_ms", # 相对进程启动的毫秒(对齐两类事件的时间轴) + "chunk_id", # rel_ms // chunk_ms,看事件落在第几个 chunk + "seq", + # grab 专用 + "grab_ms", # 本次取图/一轮漏斗耗时 + "jpeg_bytes", + "since_last_grab_ms", + "audio_phase", # 取这帧图时音频是 active / silent(相位) + "ms_since_voice",# 距最近一次音频活动多久(找静默缝) + # grab 专用 —— 漏斗字段 + "reason", # 漏斗决策:send/severe_shake/unstable/need_focus/orient... + "judge_ms", # run_funnel 判定耗时 + "af_ms", # 对焦触发+settle+重抓耗时(0=没触发对焦) + "n_frames", # 本轮抓帧数 + # audio 专用(按秒聚合) + "audio_pps", # 这一秒的包数 + "audio_seqgap", # 这一秒 seq 跳变累计 = 真丢包数(不是固件 reserved) + "audio_rms", # 这一秒平均 rms + "audio_active_pps", # 这一秒里"活动"包数 + ]) + print(f"[TimingProbe] writing {p}") + + def _rel_ms(self) -> float: + return (time.monotonic() - self._t0) * 1000.0 + + # ── 取图事件 ── + def mark_grab(self, seq: int, grab_ms: float, jpeg_bytes: int, + since_last_ms: float, reason: str = "", judge_ms=None, + af_ms=None, n_frames=None) -> None: + if not self.enabled: + return + rel = self._rel_ms() + phase = "active" if self._audio_active else "silent" + ms_since_voice = rel - self._last_audio_active_rel_ms + if ms_since_voice > 1e8: + ms_since_voice = -1 # 还没出现过音频活动 + self._w.writerow([ + "grab", round(rel, 1), int(rel // self.chunk_ms), seq, + round(grab_ms, 1), jpeg_bytes, round(since_last_ms, 1), + phase, round(ms_since_voice, 1), + reason, judge_ms if judge_ms is not None else "", + af_ms if af_ms is not None else "", + n_frames if n_frames is not None else "", + "", "", "", "", # audio 专用列留空 + ]) + self._f.flush() + + # ── 音频事件(每包调,内部按秒聚合写一行)── + # 注意:固件包头第4字段是 reserved(pad),不是丢包数;真丢包用 seq 跳变推断。 + def mark_audio(self, seq: int, n_samples: int, rms: float) -> None: + if not self.enabled: + return + rel = self._rel_ms() + + # 更新相位状态(供 mark_grab 读) + self._audio_active = rms > self._voice_rms_gate + if self._audio_active: + self._last_audio_active_rel_ms = rel + + # seq 跳变 = 真丢包(PC 视角:应收 seq 连续,缺号即丢) + gap = 0 + if self._last_seq is not None: + d = seq - self._last_seq - 1 + if 0 < d < 10000: # 合理范围,排除重连/回绕 + gap = d + self._last_seq = seq + + # 按秒聚合 + bucket = int(rel // 1000) + if self._agg_bucket == -1: + self._agg_bucket = bucket + if bucket != self._agg_bucket: + self._flush_audio_bucket() + self._agg_bucket = bucket + self._agg_pkts += 1 + self._agg_seqgap += gap + self._agg_rms_sum += rms + if rms > self._voice_rms_gate: + self._agg_active_pkts += 1 + + def _flush_audio_bucket(self) -> None: + if self._agg_pkts == 0: + return + rel = self._agg_bucket * 1000.0 + avg_rms = self._agg_rms_sum / self._agg_pkts + self._w.writerow([ + "audio", round(rel, 1), int(rel // self.chunk_ms), "", + "", "", "", "", "", # grab 基础列留空 + "", "", "", "", # grab 漏斗列留空 + self._agg_pkts, self._agg_seqgap, round(avg_rms, 4), self._agg_active_pkts, + ]) + self._f.flush() + self._agg_pkts = 0 + self._agg_seqgap = 0 + self._agg_rms_sum = 0.0 + self._agg_active_pkts = 0 + + def close(self) -> None: + if not self.enabled: + return + try: + self._flush_audio_bucket() + if self._f: + self._f.close() + except Exception: + pass diff --git a/extensions/assistive_harness/prompts/README.md b/extensions/assistive_harness/prompts/README.md new file mode 100644 index 0000000..38fb5ac --- /dev/null +++ b/extensions/assistive_harness/prompts/README.md @@ -0,0 +1,43 @@ +# User-editable Skill prompts + +These files are the system prompts used when the Voice Skill Harness creates a +new MiniCPM-o Duplex Session. Prompt text is read again on every activation, so +editing an existing `.txt` file takes effect on the next Skill switch without +restarting the Harness service. + +## Shipped prompts + +| Skill ID | Prompt file | Default | +|---|---|---| +| `idle_chat` | `idle_chat_zh.txt` | enabled | +| `find_object` | `find_object_zh.txt` | enabled | +| `read_text` | `read_text_zh.txt` | enabled | +| `describe_scene` | `describe_scene_zh.txt` | enabled | +| `obstacle_avoidance` | `obstacle_avoidance_zh.txt` | enabled / experimental | + +The find/read/obstacle task bodies were copied from the frozen AAAI_SI C1 +prompts. `find_object_zh.txt` additionally contains `{{target}}`, because the +new Session must receive the target extracted from the command that closed the +old Session. + +Source directory: + +`C:\Users\Lenovo\AI_Glasses_0618\AAAI_SI\submission_release\AAAI27_AISI_Anonymous_Code_Data\prompts` + +## Editing an existing prompt + +1. Back up the target `.txt` file. +2. Replace its contents with a UTF-8 system prompt. +3. Keep every declared template variable, such as `{{target}}`. +4. Switch to chat/another Skill and activate this Skill again. (The same + Skill/same slots command is intentionally deduplicated.) The new hot Session + will read the new text and record its rendered SHA-256 in telemetry. + +## Adding a Skill + +Create another `.txt` file and add a matching entry under `skills:` in +`../config/skills.example.yaml`. Configuration changes require restarting the +8021 Harness service; prompt-only changes do not. + +Obstacle avoidance has not passed a safety evaluation. Use it only for +stationary, supervised tests; never treat the Demo as a mobility safety device. diff --git a/extensions/assistive_harness/prompts/describe_scene_zh.txt b/extensions/assistive_harness/prompts/describe_scene_zh.txt new file mode 100644 index 0000000..b19376b --- /dev/null +++ b/extensions/assistive_harness/prompts/describe_scene_zh.txt @@ -0,0 +1,8 @@ +当前技能:场景描述。 + +规则: +1. 用一到三句话概括当前画面的主要物体、位置关系和明显状态。 +2. 优先描述门口、桌面、道路、人物、显著文字和可能影响用户行动的大物体。 +3. 只描述当前可见证据;看不清时直接说画面不清楚。 +4. 不给出未经验证的距离、路线或安全保证。 +5. 避免反复描述没有变化的内容。 diff --git a/extensions/assistive_harness/prompts/find_object_zh.txt b/extensions/assistive_harness/prompts/find_object_zh.txt new file mode 100644 index 0000000..affe3a2 --- /dev/null +++ b/extensions/assistive_harness/prompts/find_object_zh.txt @@ -0,0 +1,9 @@ +你是智能眼镜找物助手。你能看到用户当前第一视角画面,并听到用户要找的目标。 + +当前寻找目标:{{target}} + +上述目标已经由外部 Harness 从用户语音中识别。新会话启动后,直接寻找该目标,不要再次询问目标是什么。 +用户问完后,必须直接根据当前画面回答,不要先说“好的”“我来找”“稍等”。 +如果目标在画面里可见,用一句话说清它的位置、方向和附近锚点,例如“复印机在左前方,靠近窗户”。 +如果目标不可见,就说“没看到”,并给一个具体下一步建议,例如转向、靠近、抬头或调整角度。 +只描述画面中确实可见的内容,不要凭常识猜测。回答尽量短。 diff --git a/extensions/assistive_harness/prompts/idle_chat_zh.txt b/extensions/assistive_harness/prompts/idle_chat_zh.txt new file mode 100644 index 0000000..a558053 --- /dev/null +++ b/extensions/assistive_harness/prompts/idle_chat_zh.txt @@ -0,0 +1,8 @@ +你是一副面向视障用户的本地 AI 眼镜助手。 + +规则: +1. 只根据当前音频、视频和明确上下文回答,不要编造看不清或没听清的内容。 +2. 回答简洁、自然,优先一到三句话。 +3. 不要主动给出未经验证的距离、安全或行动指令。 +4. 用户的“停一下、重新开始、找物、识字”等控制命令由外部 Harness 处理;不要争夺控制权,也不要重复解释系统机制。 +5. 没有足够证据时,直接说明不确定,并建议用户停稳或调整视角。 diff --git a/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt b/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt new file mode 100644 index 0000000..82cb340 --- /dev/null +++ b/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt @@ -0,0 +1,9 @@ +你是智能眼镜避障助手。你能看到用户当前第一视角画面,并听到用户询问前方障碍。 + +用户问完后,必须直接根据当前画面回答,不要只说“好的”“我会留意”。 +如果能确认障碍,用一句短话说明障碍是什么、位于左前方/正前方/右前方或地面哪里,并给出立即可执行的安全建议,例如停下、向左绕行或向右绕行。 +只根据画面中确实可见的障碍和可通行空间判断,不要猜测,不要把普通物体误报为障碍。 +如果摄像头没有朝向行进方向、地面不可见、画面被遮挡或证据不足,明确回答“当前画面不足以判断前方是否安全”,建议用户先停下并把镜头转向前方或地面。 +在无法确认通行空间时,不得声称“前方安全”或直接给出通行方向。 +如果障碍随后进入画面或画面质量改善,应立即根据新画面更新判断。 +回答尽量简短。 diff --git a/extensions/assistive_harness/prompts/read_text_zh.txt b/extensions/assistive_harness/prompts/read_text_zh.txt new file mode 100644 index 0000000..5d104b6 --- /dev/null +++ b/extensions/assistive_harness/prompts/read_text_zh.txt @@ -0,0 +1,7 @@ +你是智能眼镜读字助手。你能看到用户当前第一视角画面,并听到用户要求读字。 + +用户一开口要求读字,你必须回答,不能保持沉默。 +用户问完后,直接读出画面里清晰可见的文字,不要先说“好的”“我来”。 +只输出你看清的文字、数字或符号;看不清的字不要猜,不要根据物品常识补全。 +如果只能看清部分文字,可以只读出看清的部分。 +如果整体看不清,也必须回答“看不清”,并建议靠近、正对文字或重新对焦。 diff --git a/extensions/assistive_harness/registry.py b/extensions/assistive_harness/registry.py new file mode 100644 index 0000000..35b2fc1 --- /dev/null +++ b/extensions/assistive_harness/registry.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import hashlib +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +import yaml + + +class RegistryError(ValueError): + pass + + +@dataclass(frozen=True, slots=True) +class RenderedPrompt: + skill_id: str + text: str + path: str + sha256: str + slots: dict[str, Any] + + +class SkillRegistry: + def __init__(self, config_path: str | Path): + self.config_path = Path(config_path).resolve() + raw = yaml.safe_load(self.config_path.read_text(encoding="utf-8")) or {} + self.version = int(raw.get("version", 1)) + self.default_skill = str(raw.get("default_skill", "idle_chat")) + self.control = dict(raw.get("control") or {}) + self.skills: dict[str, dict[str, Any]] = dict(raw.get("skills") or {}) + if self.default_skill not in self.skills: + raise RegistryError(f"default skill is missing: {self.default_skill}") + self._validate_prompt_files() + + def _prompt_path(self, skill_id: str) -> Path: + spec = self.get(skill_id) + path = Path(str(spec.get("prompt_file") or "")) + if not path.is_absolute(): + path = self.config_path.parent / path + return path.resolve() + + def prompt_path(self, skill_id: str) -> Path: + """Return the user-editable prompt path exposed by the registry.""" + return self._prompt_path(skill_id) + + def _validate_prompt_files(self) -> None: + for skill_id, spec in self.skills.items(): + if not isinstance(spec, dict): + raise RegistryError(f"invalid skill spec: {skill_id}") + path = self._prompt_path(skill_id) + if not path.is_file(): + raise RegistryError(f"prompt file is missing for {skill_id}: {path}") + + def get(self, skill_id: str) -> dict[str, Any]: + spec = self.skills.get(skill_id) + if spec is None: + raise RegistryError(f"unknown skill: {skill_id}") + if not isinstance(spec, dict): + raise RegistryError(f"invalid skill spec: {skill_id}") + return spec + + def is_enabled(self, skill_id: str) -> bool: + return bool(self.get(skill_id).get("enabled", False)) + + def cooldown_ms(self, skill_id: str) -> int: + return int(self.get(skill_id).get("cooldown_ms", 0)) + + def task_trigger( + self, skill_id: str, slots: dict[str, Any] | None = None + ) -> str: + """Render the optional one-shot command sent to a fresh Skill Session.""" + text = str(self.get(skill_id).get("task_trigger") or "").strip() + slots = dict(slots or {}) + variables = set(re.findall(r"\{\{\s*([a-zA-Z_][\w]*)\s*\}\}", text)) + missing = sorted(name for name in variables if not str(slots.get(name, "")).strip()) + if missing: + raise RegistryError(f"missing task trigger variables for {skill_id}: {missing}") + for name in variables: + text = re.sub( + r"\{\{\s*" + re.escape(name) + r"\s*\}\}", + str(slots[name]), + text, + ) + return text + + def render(self, skill_id: str, slots: dict[str, Any] | None = None) -> RenderedPrompt: + if not self.is_enabled(skill_id): + raise RegistryError(f"skill is disabled: {skill_id}") + slots = dict(slots or {}) + spec = self.get(skill_id) + schema = dict(spec.get("slot_schema") or {}) + for name, slot_spec in schema.items(): + if bool((slot_spec or {}).get("required")) and not str(slots.get(name, "")).strip(): + raise RegistryError(f"missing required slot '{name}' for {skill_id}") + + path = self._prompt_path(skill_id) + text = path.read_text(encoding="utf-8") + variables = set(re.findall(r"\{\{\s*([a-zA-Z_][\w]*)\s*\}\}", text)) + missing = sorted(name for name in variables if name not in slots) + if missing: + raise RegistryError(f"missing prompt variables for {skill_id}: {missing}") + for name in variables: + text = re.sub( + r"\{\{\s*" + re.escape(name) + r"\s*\}\}", + str(slots[name]), + text, + ) + digest = hashlib.sha256(text.encode("utf-8")).hexdigest() + return RenderedPrompt( + skill_id=skill_id, + text=text, + path=str(path), + sha256=digest, + slots=slots, + ) diff --git a/extensions/assistive_harness/router.py b/extensions/assistive_harness/router.py new file mode 100644 index 0000000..43038f5 --- /dev/null +++ b/extensions/assistive_harness/router.py @@ -0,0 +1,262 @@ +from __future__ import annotations + +import re +import time +from dataclasses import dataclass + +from .registry import SkillRegistry +from .schemas import ControlEvent, ControlIntent + + +_PUNCTUATION = ",,。!?!?;;::、\"'“”‘’" +_SPEECH_PARTICLES = ("嗯", "啊", "呀", "吧", "呢", "啦", "哦") + + +def normalize_text(text: str) -> str: + compact = re.sub(r"\s+", "", text or "").lower() + return compact.strip(_PUNCTUATION) + + +def _strip_speech_particles(text: str) -> str: + cleaned = text + while cleaned and any(cleaned.endswith(item) for item in _SPEECH_PARTICLES): + cleaned = cleaned[:-1] + return cleaned + + +def _collapse_repeated_tail(text: str, max_width: int = 4) -> str: + """Collapse a short duplicated ASR tail such as ``手机手机`` or ``母母母``.""" + + cleaned = text + while cleaned: + collapsed = False + for width in range(min(max_width, len(cleaned) // 2), 0, -1): + if cleaned[-width:] == cleaned[-2 * width : -width]: + cleaned = cleaned[:-width] + collapsed = True + break + if not collapsed: + return cleaned + return cleaned + + +def _clean_slot_value(value: str) -> str: + cleaned = _strip_speech_particles(value.strip(_PUNCTUATION)) + cleaned = _collapse_repeated_tail(cleaned) + return _strip_speech_particles(cleaned) + + +@dataclass(slots=True) +class RouteResult: + intent: ControlIntent + skill_id: str | None = None + slots: dict[str, str] | None = None + reason: str = "" + confidence: float = 1.0 + + +class RuleIntentRouter: + """Small deterministic Chinese intent router with exact control commands.""" + + def __init__(self, registry: SkillRegistry): + self.registry = registry + control = registry.control + self.stop_phrases = { + normalize_text(item) + for item in (control.get("stop_speech") or {}).get("phrases", []) + } + self.stop_embedded_phrases = { + normalize_text(item) + for item in (control.get("stop_speech") or {}).get("embedded_phrases", []) + } + self.resume_embedded_phrases = { + normalize_text(item) + for item in (control.get("resume_speech") or {}).get("embedded_phrases", []) + } + self.reset_phrases = { + normalize_text(item) + for item in (control.get("reset_session") or {}).get("phrases", []) + } + self.reset_embedded_phrases = { + normalize_text(item) + for item in (control.get("reset_session") or {}).get("embedded_phrases", []) + } + self.return_phrases = { + normalize_text(item) + for item in (control.get("return_to_chat") or {}).get("phrases", []) + } + self.cancel_phrases = { + normalize_text(item) + for item in (control.get("cancel_skill") or {}).get("phrases", []) + } + + @staticmethod + def _is_explicit_command(compact: str, phrases: set[str]) -> bool: + polite_prefixes = ("麻烦你先", "请", "麻烦", "你先", "请你", "可以", "能不能") + polite_suffixes = ("一下", "好吗", "可以吗", "啊", "呀", "吧", "呢", "啦", "哦") + + # FunASR commonly appends a sentence particle ("停一下啊") or repeats + # the final syllable ("停一下下"). Build a small, bounded closure of + # command-only variants instead of doing substring matching, so a + # sentence such as "我刚才没有说停一下" still cannot trigger STOP. + candidates: set[str] = set() + pending = [compact] + while pending: + candidate = pending.pop() + if not candidate or candidate in candidates: + continue + candidates.add(candidate) + + for prefix in polite_prefixes: + if candidate.startswith(prefix) and len(candidate) > len(prefix): + pending.append(candidate[len(prefix) :]) + for suffix in polite_suffixes: + if candidate.endswith(suffix) and len(candidate) > len(suffix): + pending.append(candidate[: -len(suffix)]) + if len(candidate) >= 2 and candidate[-1] == candidate[-2]: + pending.append(candidate[:-1]) + + return any(candidate in phrases for candidate in candidates) + + @staticmethod + def _contains_command(compact: str, phrases: set[str]) -> bool: + """Use a literal command-anchor protocol; do not infer sentence meaning.""" + return any(phrase and phrase in compact for phrase in phrases) + + @staticmethod + def _skill_variants(compact: str) -> list[str]: + """Build bounded FunASR variants while retaining an explicit Skill verb.""" + + candidates: set[str] = set() + pending = [compact] + while pending: + candidate = pending.pop() + if not candidate or candidate in candidates: + continue + candidates.add(candidate) + + without_particles = _strip_speech_particles(candidate) + if without_particles and without_particles != candidate: + pending.append(without_particles) + + # Observed FunASR variants include ``一下下`` and omission of the + # pronoun in ``帮我找/读``. Restore only that pronoun; never invent + # a missing Skill verb such as ``找`` or ``读``. + collapsed_action = re.sub(r"一下下+", "一下", candidate) + if collapsed_action != candidate: + pending.append(collapsed_action) + if candidate.startswith("帮") and not candidate.startswith("帮我"): + pending.append("帮我" + candidate[1:]) + + for prefix in ("请你", "麻烦你", "麻烦", "请", "能不能"): + if candidate.startswith(prefix) and len(candidate) > len(prefix): + pending.append(candidate[len(prefix) :]) + polite_prefixes = ("请你", "麻烦你", "麻烦", "请", "能不能") + + def noise_rank(candidate: str) -> tuple[int, int, int, int, int, str]: + return ( + int(bool(re.search(r"一下下+", candidate))), + int(_strip_speech_particles(candidate) != candidate), + int(candidate.startswith("帮") and not candidate.startswith("帮我")), + int(candidate.startswith(polite_prefixes)), + len(candidate), + candidate, + ) + + # Regexes can match both the raw and corrected ASR text. Prefer the + # bounded, lower-noise candidate so slot extraction is deterministic. + return sorted(candidates, key=noise_rank) + + def route(self, utterance: str) -> RouteResult: + compact = normalize_text(utterance) + if not compact: + return RouteResult(ControlIntent.NONE, reason="empty") + + variants = self._skill_variants(compact) + + if self._is_explicit_command(compact, self.stop_phrases): + return RouteResult(ControlIntent.STOP_SPEECH, reason="explicit stop command") + # STOP wins if a transcript contains both anchors. + if self._contains_command(compact, self.stop_embedded_phrases): + return RouteResult(ControlIntent.STOP_SPEECH, reason="stop anchor contained") + # RESET wins over RESUME and all skills. The protocol is deliberately + # literal: callers can add a product wake name to the same sentence. + if ( + self._contains_command(compact, self.reset_embedded_phrases) + or self._is_explicit_command(compact, self.reset_phrases) + ): + return RouteResult( + ControlIntent.RESET_SESSION, + skill_id=self.registry.default_skill, + slots={}, + reason=( + "reset anchor contained" + if self._contains_command(compact, self.reset_embedded_phrases) + else "explicit reset command" + ), + ) + if self._contains_command(compact, self.resume_embedded_phrases): + return RouteResult(ControlIntent.RESUME_SPEECH, reason="resume anchor contained") + if self._is_explicit_command(compact, self.cancel_phrases): + return RouteResult(ControlIntent.CANCEL_SKILL, reason="explicit cancel command") + if self._is_explicit_command(compact, self.return_phrases): + return RouteResult( + ControlIntent.RETURN_TO_CHAT, + skill_id=self.registry.default_skill, + slots={}, + reason="explicit return-to-chat command", + ) + + for skill_id, spec in self.registry.skills.items(): + if not bool(spec.get("enabled", False)) or skill_id == self.registry.default_skill: + continue + for pattern in spec.get("activation_patterns") or []: + for candidate in variants: + match = re.fullmatch(str(pattern), candidate) + if match: + slots = { + key: _clean_slot_value(value) + for key, value in match.groupdict().items() + if value + } + return RouteResult( + ControlIntent.ACTIVATE_SKILL, + skill_id=skill_id, + slots=slots, + reason=f"matched {skill_id} pattern", + ) + phrases = [normalize_text(item) for item in spec.get("activation_phrases") or []] + if any( + candidate == phrase or candidate.startswith(phrase) + for candidate in variants + for phrase in phrases + ): + return RouteResult( + ControlIntent.ACTIVATE_SKILL, + skill_id=skill_id, + slots={}, + reason=f"matched {skill_id} phrase", + ) + + return RouteResult(ControlIntent.NONE, reason="ordinary chat") + + def make_event( + self, + route: RouteResult, + *, + event_id: int, + asr_event_id: int, + utterance: str, + created_at_ms: float | None = None, + ) -> ControlEvent: + return ControlEvent( + event_id=event_id, + intent=route.intent, + skill_id=route.skill_id, + slots=dict(route.slots or {}), + utterance=utterance, + confidence=route.confidence, + asr_event_id=asr_event_id, + created_at_ms=created_at_ms if created_at_ms is not None else time.time() * 1000, + reason=route.reason, + ) diff --git a/extensions/assistive_harness/schemas.py b/extensions/assistive_harness/schemas.py new file mode 100644 index 0000000..edad067 --- /dev/null +++ b/extensions/assistive_harness/schemas.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from enum import Enum +from typing import Any + + +class ControlIntent(str, Enum): + STOP_SPEECH = "stop_speech" + RESUME_SPEECH = "resume_speech" + RESET_SESSION = "reset_session" + CANCEL_SKILL = "cancel_skill" + RETURN_TO_CHAT = "return_to_chat" + ACTIVATE_SKILL = "activate_skill" + NONE = "none" + + +@dataclass(slots=True) +class ASREvent: + event_id: int + utterance: str + started_at_ms: float + ended_at_ms: float + final_at_ms: float + model: str + device: str + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +@dataclass(slots=True) +class ControlEvent: + event_id: int + intent: ControlIntent + utterance: str + confidence: float + asr_event_id: int + created_at_ms: float + skill_id: str | None = None + slots: dict[str, Any] = field(default_factory=dict) + reason: str = "" + system_prompt: str | None = None + prompt_path: str | None = None + prompt_sha256: str | None = None + + def to_dict(self) -> dict[str, Any]: + payload = asdict(self) + payload["type"] = "control.intent" + payload["intent"] = self.intent.value + return payload + + +@dataclass(slots=True) +class HarnessState: + current_skill: str = "idle_chat" + current_slots: dict[str, Any] = field(default_factory=dict) + session_generation: int = 0 + control_event_id: int = 0 + asr_event_id: int = 0 + restart_in_progress: bool = False + drop_output_until_listen: bool = False + speech_hold_active: bool = False + pending_skill: dict[str, Any] | None = None + + def to_dict(self) -> dict[str, Any]: + return asdict(self) diff --git a/extensions/assistive_harness/server.py b/extensions/assistive_harness/server.py new file mode 100644 index 0000000..3d3343d --- /dev/null +++ b/extensions/assistive_harness/server.py @@ -0,0 +1,604 @@ +from __future__ import annotations + +import argparse +import asyncio +import base64 +import json +import time +import uuid +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + +import numpy as np +import uvicorn +import yaml +from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from fastapi.responses import JSONResponse + +from .asr.base import ASREngine +from .asr.energy_vad import EnergyVAD, UtteranceAudio +from .asr.funasr_engine import FunASREngine +from .cv.base import CVObservation, FrameEnvelope +from .cv.pipeline import CVPipeline +from .cv.registry import CVProviderRegistry, build_provider_registry +from .echo_guard import EchoGuard +from .model_log import ModelTurnAccumulator +from .registry import SkillRegistry +from .router import RuleIntentRouter +from .schemas import ASREvent, ControlEvent, ControlIntent +from .state_machine import HarnessController +from .telemetry import TelemetryWriter + + +def now_ms() -> float: + return time.time() * 1000.0 + + +def _decode_float32(value: str) -> np.ndarray: + raw = base64.b64decode(value, validate=True) + if len(raw) % 4: + raise ValueError("float32 payload length is not divisible by four") + return np.frombuffer(raw, dtype=" int: + self.event_counter += 1 + return self.event_counter + + def refresh_echo_speaking(self) -> None: + self.echo.set_ai_speaking(self.model_speaking or self.playback_active) + + def record_model_turn(self, turn: dict[str, Any]) -> None: + self.telemetry.write("model", turn) + self.telemetry.append_model_transcript(turn) + print( + "[AssistiveHarness][MODEL] " + f"turn={turn.get('turn_index')} role={turn.get('role')} " + f"generation={turn.get('generation')} skill={turn.get('skill_id')} " + f"audio_ms={turn.get('audio_ms')} text={turn.get('text')!r}", + flush=True, + ) + + async def recognize( + self, utterance: UtteranceAudio + ) -> dict[str, Any] | list[dict[str, Any]]: + async with self.asr_lock: + started = now_ms() + result = await asyncio.to_thread( + self.engine.transcribe, utterance.audio, self.vad.sample_rate + ) + return await self.route_transcript( + result.text, + confidence=result.confidence, + model=result.model, + device=result.device, + started_at_ms=utterance.started_at_ms, + ended_at_ms=utterance.ended_at_ms, + final_at_ms=now_ms(), + inference_started_at_ms=started, + ) + + def recognize_in_background(self, utterance: UtteranceAudio) -> None: + """Keep receiving microphone frames while a completed utterance is decoded.""" + + async def run() -> None: + try: + await self.outbound.put(await self.recognize(utterance)) + except asyncio.CancelledError: + raise + except Exception as exc: + await self.outbound.put( + { + "type": "error", + "code": "asr_failed", + "message": str(exc), + } + ) + + task = asyncio.create_task(run()) + self.background_tasks.add(task) + task.add_done_callback(self.background_tasks.discard) + + async def route_transcript( + self, + text: str, + *, + confidence: float, + model: str, + device: str, + started_at_ms: float | None = None, + ended_at_ms: float | None = None, + final_at_ms: float | None = None, + inference_started_at_ms: float | None = None, + ) -> dict[str, Any] | list[dict[str, Any]]: + finished = final_at_ms if final_at_ms is not None else now_ms() + asr_id = self.next_event_id() + asr_event = ASREvent( + event_id=asr_id, + utterance=text.strip(), + started_at_ms=started_at_ms if started_at_ms is not None else finished, + ended_at_ms=ended_at_ms if ended_at_ms is not None else finished, + final_at_ms=finished, + model=model, + device=device, + ) + self.telemetry.write("asr", asr_event.to_dict()) + transcript_payload: dict[str, Any] = { + "type": "asr.transcript", + "asr_event_id": asr_id, + "utterance": asr_event.utterance, + "confidence": confidence, + "final_at_ms": finished, + } + if inference_started_at_ms is not None: + self.telemetry.metric("asr_inference_ms", finished - inference_started_at_ms, asr_id) + + route = self.router.route(asr_event.utterance) + echo = self.echo.evaluate(asr_event.utterance, route.intent, at_ms=finished) + print( + "[AssistiveHarness][ASR] " + f"text={asr_event.utterance!r} intent={route.intent.value} " + f"echo={'allow' if echo.allow else 'drop'} reason={echo.reason}", + flush=True, + ) + self.telemetry.write( + "echo", + { + "asr_event_id": asr_id, + "allow": echo.allow, + "reason": echo.reason, + "similarity": echo.similarity, + }, + ) + if not echo.allow or route.intent is ControlIntent.NONE: + transcript_payload["suppressed"] = not echo.allow + transcript_payload["reason"] = echo.reason if not echo.allow else route.reason + return transcript_payload + + control_id = self.next_event_id() + event = self.router.make_event( + route, + event_id=control_id, + asr_event_id=asr_id, + utterance=asr_event.utterance, + created_at_ms=finished, + ) + decision = self.controller.process(event, now_ms=finished) + print( + "[AssistiveHarness][CONTROL] " + f"intent={route.intent.value} accepted={decision.accepted} " + f"action={decision.action} event={control_id}", + flush=True, + ) + payload = { + **decision.payload, + "accepted": decision.accepted, + "action": decision.action, + "decision_reason": decision.reason, + "client_id": self.client_id, + } + self.telemetry.write("control", payload) + if route.intent in { + ControlIntent.RESET_SESSION, + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + ControlIntent.ACTIVATE_SKILL, + }: + self.telemetry.write( + "skill", + { + "control_event_id": control_id, + "intent": route.intent.value, + "skill_id": event.skill_id, + "slots": event.slots, + "prompt_path": event.prompt_path, + "prompt_sha256": event.prompt_sha256, + "accepted": decision.accepted, + "action": decision.action, + }, + ) + if decision.accepted: + return [transcript_payload, payload] + transcript_payload["suppressed"] = True + transcript_payload["reason"] = decision.reason + return transcript_payload + + +class AssistiveHarnessService: + def __init__( + self, + config_path: str | Path, + *, + enabled: bool, + model_path: str | None = None, + allow_test_injection: bool = False, + engine: ASREngine | None = None, + cv_providers: CVProviderRegistry | None = None, + ): + self.config_path = Path(config_path).resolve() + self.config = yaml.safe_load(self.config_path.read_text(encoding="utf-8")) or {} + self.registry = SkillRegistry(self.config_path) + self.cv_config = dict(self.config.get("cv") or {}) + self.cv_providers = cv_providers or build_provider_registry( + self.config, config_dir=self.config_path.parent + ) + self.enabled = bool(enabled) + self.allow_test_injection = bool(allow_test_injection) + asr_cfg = dict(self.config.get("asr") or {}) + resolved_model_path = model_path or str(asr_cfg.get("model_path") or "") + if engine is not None: + self.engine = engine + elif self.enabled: + if not resolved_model_path: + raise ValueError("--model-path is required when the Harness is enabled") + self.engine = FunASREngine( + resolved_model_path, + device=str(asr_cfg.get("device") or "cpu"), + ) + else: + self.engine = None + run_id = time.strftime("%Y%m%d_%H%M%S") + "_" + uuid.uuid4().hex[:8] + telemetry_root = Path(__file__).resolve().parent / "runs" + self.telemetry = TelemetryWriter(telemetry_root, run_id, self.config) + self.clients: dict[str, ClientRuntime] = {} + self.started_at_ms = now_ms() + + def make_runtime(self, client_id: str) -> ClientRuntime: + if self.engine is None: + raise RuntimeError("Harness is disabled") + asr_cfg = dict(self.config.get("asr") or {}) + echo_cfg = dict(self.config.get("echo_guard") or {}) + return ClientRuntime( + client_id=client_id, + registry=self.registry, + router=RuleIntentRouter(self.registry), + engine=self.engine, + telemetry=self.telemetry, + vad=EnergyVAD( + rms_threshold=float(asr_cfg.get("rms_threshold", 0.012)), + min_speech_ms=int(asr_cfg.get("min_speech_ms", 180)), + end_silence_ms=int(asr_cfg.get("end_silence_ms", 450)), + max_utterance_ms=int(asr_cfg.get("max_utterance_ms", 8000)), + preroll_ms=int(asr_cfg.get("preroll_ms", 200)), + ), + echo=EchoGuard( + window_ms=int(echo_cfg.get("window_ms", 20000)), + similarity_threshold=float(echo_cfg.get("similarity_threshold", 0.86)), + ), + controller=HarnessController(self.registry), + allow_test_injection=self.allow_test_injection, + cv=CVPipeline( + self.cv_providers, + on_observation=lambda observation: self.telemetry.write( + "cv", observation.to_dict() + ), + on_metric=lambda name, value: self.telemetry.metric(name, value), + queue_size=int(self.cv_config.get("queue_size", 1)), + inference_timeout_ms=float( + self.cv_config.get("inference_timeout_ms", 2000) + ), + worker_name=f"assistive-cv-{client_id[:8]}", + ), + ) + + def create_app(self) -> FastAPI: + app = FastAPI(title="Assistive Voice Skill Harness", version="0.1.0") + + @app.get("/health") + async def health() -> JSONResponse: + return JSONResponse( + { + "ok": True, + "enabled": self.enabled, + "clients": len(self.clients), + "uptime_ms": now_ms() - self.started_at_ms, + "asr_loaded": bool(getattr(self.engine, "loaded", self.engine is not None)), + "config": self.config_path.name, + "cv_providers": sorted(self.cv_providers.providers), + } + ) + + @app.get("/skills") + async def skills() -> JSONResponse: + return JSONResponse( + { + "ok": True, + "default_skill": self.registry.default_skill, + "config_path": str(self.config_path), + "skills": { + skill_id: { + "enabled": self.registry.is_enabled(skill_id), + "description": str(spec.get("description") or ""), + "prompt_path": str(self.registry.prompt_path(skill_id)), + "requires_session_restart": bool( + spec.get("requires_session_restart", True) + ), + "cv_mode": str(spec.get("cv_mode") or "disabled"), + "cv_provider": str(spec.get("cv_provider") or "noop"), + } + for skill_id, spec in self.registry.skills.items() + }, + } + ) + + @app.on_event("shutdown") + async def write_shutdown_summary() -> None: + self.telemetry.write_summary( + { + "enabled": self.enabled, + "uptime_ms": now_ms() - self.started_at_ms, + "connected_clients_at_shutdown": len(self.clients), + "asr_loaded": bool(getattr(self.engine, "loaded", self.engine is not None)), + } + ) + + @app.websocket("/ws/control") + async def control_socket(websocket: WebSocket) -> None: + if not self.enabled: + await websocket.close(code=1013, reason="Harness disabled") + return + await websocket.accept() + client_id = websocket.query_params.get("client_id") or uuid.uuid4().hex + runtime = self.make_runtime(client_id) + self.clients[client_id] = runtime + + async def send_outbound() -> None: + while True: + response = await runtime.outbound.get() + if isinstance(response, list): + for item in response: + await websocket.send_json(item) + elif response is not None: + await websocket.send_json(response) + + sender = asyncio.create_task(send_outbound()) + await runtime.outbound.put( + { + "type": "harness.ready", + "client_id": client_id, + "state": runtime.controller.state.to_dict(), + } + ) + try: + while True: + message = await websocket.receive_json() + response = await self._handle_message(runtime, message) + if response is not None: + await runtime.outbound.put(response) + except WebSocketDisconnect: + runtime.controller.mark_disconnected() + finally: + pending_turn = runtime.model_turns.flush() + if pending_turn is not None: + runtime.record_model_turn(pending_turn) + sender.cancel() + for task in tuple(runtime.background_tasks): + task.cancel() + await runtime.cv.close() + await asyncio.gather(sender, *runtime.background_tasks, return_exceptions=True) + self.clients.pop(client_id, None) + + return app + + async def _handle_message( + self, runtime: ClientRuntime, message: dict[str, Any] + ) -> dict[str, Any] | list[dict[str, Any]] | None: + message_type = str(message.get("type") or "") + if message_type == "ping": + return {"type": "pong", "at_ms": now_ms()} + if message_type == "audio.mirror": + audio = _decode_float32(str(message.get("audio_b64") or "")) + utterance = runtime.vad.feed(audio, float(message.get("started_at_ms") or now_ms())) + if utterance is None: + return None + runtime.recognize_in_background(utterance) + return None + if message_type == "asr.inject": + if not runtime.allow_test_injection: + return {"type": "error", "code": "test_injection_disabled"} + return await runtime.route_transcript( + str(message.get("text") or ""), + confidence=1.0, + model="injected-test-only", + device="none", + ) + if message_type in ("funnel.stop", "funnel.resume"): + # 漏斗 reject/恢复:程序直接触发,不经 ASR/router 文字匹配。 + # 复用 controller.process + STOP_SPEECH/RESUME_SPEECH,和真人「停一下/恢复对话」 + # 走完全相同的下游(设备端收到 control.intent 执行 stop_speech/resume_speech)。 + # 归口 8021:telemetry 统一记录,标 source=funnel 以区分真人还是漏斗触发。 + is_stop = message_type == "funnel.stop" + intent = ControlIntent.STOP_SPEECH if is_stop else ControlIntent.RESUME_SPEECH + event = ControlEvent( + event_id=runtime.next_event_id(), + intent=intent, + utterance="[%s]" % message_type, + confidence=1.0, + asr_event_id=runtime.next_event_id(), + created_at_ms=now_ms(), + reason=str(message.get("reason") or "funnel"), + ) + decision = runtime.controller.process(event, now_ms=event.created_at_ms) + payload = { + **decision.payload, + "accepted": decision.accepted, + "action": decision.action, + "decision_reason": decision.reason, + "source": "funnel", + "client_id": runtime.client_id, + } + runtime.telemetry.write("control", payload) + print( + "[AssistiveHarness][FUNNEL] " + "type=%s accepted=%s action=%s reason=%s" + % (message_type, decision.accepted, decision.action, event.reason), + flush=True, + ) + return payload if decision.accepted else None + if message_type == "model.state": + event = dict(message) + runtime.telemetry.write("model", event) + speaking = str(message.get("state") or "") == "speak" + runtime.model_speaking = speaking + runtime.refresh_echo_speaking() + text = str(message.get("text") or "") + if speaking and text: + runtime.echo.note_model_text(text) + for turn in runtime.model_turns.feed(event): + runtime.record_model_turn(turn) + return None + if message_type == "playback.state": + event = dict(message) + runtime.telemetry.write("model", event) + runtime.playback_active = bool(message.get("active")) + runtime.refresh_echo_speaking() + return None + if message_type == "session.state": + event = dict(message) + runtime.telemetry.write("session", event) + phase = str(message.get("phase") or "") + if phase == "listen": + runtime.controller.mark_listen_fence() + elif phase == "restart_complete": + runtime.controller.mark_restart_complete( + str(message.get("skill_id") or runtime.registry.default_skill), + dict(message.get("slots") or {}), + int(message.get("generation") or 0), + ) + return None + if message_type == "control.ack": + if bool(message.get("ok")) and str(message.get("intent") or "") == "stop_speech": + # Browser STOP has already flushed/blocked playback. Do not + # leave EchoGuard in a stale speaking state while the user + # immediately issues the next explicit command. + runtime.model_speaking = False + runtime.playback_active = False + runtime.refresh_echo_speaking() + runtime.telemetry.write("session", dict(message)) + print( + "[AssistiveHarness][ACK] " + f"intent={message.get('intent')} ok={message.get('ok')} " + f"generation={message.get('generation')} " + f"session={message.get('old_session_id') or '-'}" + f"->{message.get('new_session_id') or '-'} " + f"cleanup={message.get('cleanup_mode') or '-'} " + f"restart_ms={message.get('restart_latency_ms') or '-'} " + f"stale_text={message.get('dropped_old_text') or 0} " + f"stale_audio={message.get('dropped_old_audio') or 0}", + flush=True, + ) + metric = message.get("restart_latency_ms") + if isinstance(metric, (int, float)): + runtime.telemetry.metric( + "restart_latency_ms", float(metric), int(message.get("event_id") or 0) + ) + return None + if message_type == "frame.shadow": + at_ms = float(message.get("timestamp_ms") or now_ms()) + max_fps = max(0.0, float(self.cv_config.get("max_fps", 1))) + if max_fps <= 0: + return None + if at_ms - runtime.last_frame_ms < 1000.0 / max_fps: + return None + skill_id = runtime.controller.state.current_skill + skill_spec = runtime.registry.get(skill_id) + mode = str(skill_spec.get("cv_mode") or self.cv_config.get("mode") or "disabled") + if mode == "disabled": + return None + provider_id = str(skill_spec.get("cv_provider") or "noop") + frame_b64 = str(message.get("jpeg_b64") or "") + frame_id = str(message.get("frame_id") or uuid.uuid4().hex) + try: + frame = base64.b64decode(frame_b64, validate=True) if frame_b64 else None + except Exception as exc: + runtime.telemetry.write( + "cv", + CVObservation( + frame_id=frame_id, + timestamp_ms=at_ms, + skill_id=skill_id, + provider=f"{mode}:{provider_id}", + values={"status": "error"}, + error=f"InvalidFramePayload: {exc}", + ).to_dict(), + ) + return None + runtime.last_frame_ms = at_ms + runtime.cv.submit( + FrameEnvelope( + frame=frame, + frame_id=frame_id, + timestamp_ms=at_ms, + skill_id=skill_id, + slots=dict(runtime.controller.state.current_slots), + mode=mode, + provider_id=provider_id, + ) + ) + return None + return {"type": "error", "code": "unknown_message", "message_type": message_type} + + +def build_parser() -> argparse.ArgumentParser: + default_config = Path(__file__).resolve().parent / "config" / "skills.example.yaml" + parser = argparse.ArgumentParser(description="Optional local assistive voice-skill Harness") + parser.add_argument("--config", default=str(default_config)) + parser.add_argument("--enabled", action="store_true", help="explicit opt-in; default is off") + parser.add_argument("--host", default="127.0.0.1") + parser.add_argument("--port", type=int, default=8021) + parser.add_argument("--model-path", default=None) + parser.add_argument("--allow-test-injection", action="store_true") + parser.add_argument("--certfile", default=None) + parser.add_argument("--keyfile", default=None) + return parser + + +def main() -> None: + args = build_parser().parse_args() + service = AssistiveHarnessService( + args.config, + enabled=args.enabled, + model_path=args.model_path, + allow_test_injection=args.allow_test_injection, + ) + if isinstance(service.engine, FunASREngine): + warmup_started = time.perf_counter() + print("[AssistiveHarness] loading and warming FunASR before accepting clients...") + service.engine.warm_up() + print( + "[AssistiveHarness] FunASR ready " + f"({time.perf_counter() - warmup_started:.2f}s)" + ) + uvicorn.run( + service.create_app(), + host=args.host, + port=args.port, + ssl_certfile=args.certfile, + ssl_keyfile=args.keyfile, + ) + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/state_machine.py b/extensions/assistive_harness/state_machine.py new file mode 100644 index 0000000..e0cd9ce --- /dev/null +++ b/extensions/assistive_harness/state_machine.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import time +from dataclasses import dataclass +from typing import Any + +from .registry import RegistryError, SkillRegistry +from .schemas import ControlEvent, ControlIntent, HarnessState + + +@dataclass(slots=True) +class ControlDecision: + accepted: bool + action: str + reason: str + payload: dict[str, Any] + + +class HarnessController: + def __init__(self, registry: SkillRegistry): + self.registry = registry + self.state = HarnessState(current_skill=registry.default_skill) + self._seen_asr_ids: set[int] = set() + self._last_skill_activation_ms: dict[tuple[str, tuple[tuple[str, str], ...]], float] = {} + + @staticmethod + def _skill_key(skill_id: str, slots: dict[str, Any]) -> tuple[str, tuple[tuple[str, str], ...]]: + return skill_id, tuple(sorted((str(key), str(value)) for key, value in slots.items())) + + def process(self, event: ControlEvent, now_ms: float | None = None) -> ControlDecision: + now = now_ms if now_ms is not None else time.time() * 1000 + if event.asr_event_id in self._seen_asr_ids: + return ControlDecision(False, "ignore", "duplicate_asr_event", {}) + self._seen_asr_ids.add(event.asr_event_id) + self.state.asr_event_id = max(self.state.asr_event_id, event.asr_event_id) + self.state.control_event_id = max(self.state.control_event_id, event.event_id) + + if event.intent is ControlIntent.STOP_SPEECH: + self.state.speech_hold_active = True + self.state.drop_output_until_listen = True + return ControlDecision(True, "stop_speech", "highest_priority", event.to_dict()) + + if event.intent is ControlIntent.RESUME_SPEECH: + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False + return ControlDecision(True, "resume_speech", "explicit_resume", event.to_dict()) + + if event.intent is ControlIntent.RESET_SESSION: + rendered = self.registry.render(self.registry.default_skill, {}) + event.skill_id = self.registry.default_skill + event.slots = {} + event.system_prompt = rendered.text + event.prompt_path = rendered.path + event.prompt_sha256 = rendered.sha256 + self.state.restart_in_progress = True + self.state.pending_skill = None + return ControlDecision(True, "restart_session", "explicit_reset", event.to_dict()) + + if event.intent in {ControlIntent.CANCEL_SKILL, ControlIntent.RETURN_TO_CHAT}: + event.skill_id = self.registry.default_skill + event.slots = {} + + if event.intent in { + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + ControlIntent.ACTIVATE_SKILL, + }: + skill_id = event.skill_id or self.registry.default_skill + slots = dict(event.slots or {}) + try: + rendered = self.registry.render(skill_id, slots) + except RegistryError as exc: + return ControlDecision(False, "clarify", str(exc), event.to_dict()) + + if self.state.restart_in_progress: + self.state.pending_skill = {"skill_id": skill_id, "slots": slots} + return ControlDecision(True, "queue_skill", "restart_in_progress_last_write_wins", event.to_dict()) + + key = self._skill_key(skill_id, slots) + last = self._last_skill_activation_ms.get(key) + cooldown = self.registry.cooldown_ms(skill_id) + if skill_id == self.state.current_skill and slots == self.state.current_slots: + return ControlDecision(False, "ignore", "same_skill_same_slots", event.to_dict()) + if last is not None and now - last < cooldown: + return ControlDecision(False, "ignore", "skill_cooldown", event.to_dict()) + + self._last_skill_activation_ms[key] = now + event.system_prompt = rendered.text + event.prompt_path = rendered.path + event.prompt_sha256 = rendered.sha256 + self.state.restart_in_progress = True + return ControlDecision(True, "activate_skill", "skill_switch", event.to_dict()) + + return ControlDecision(False, "pass_chat", "ordinary_chat", event.to_dict()) + + def mark_restart_complete(self, skill_id: str, slots: dict[str, Any], generation: int) -> dict[str, Any] | None: + self.state.current_skill = skill_id + self.state.current_slots = dict(slots) + self.state.session_generation = int(generation) + self.state.restart_in_progress = False + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False + pending = self.state.pending_skill + self.state.pending_skill = None + return pending + + def mark_listen_fence(self) -> None: + if not self.state.speech_hold_active: + self.state.drop_output_until_listen = False + + def mark_disconnected(self) -> None: + self.state.restart_in_progress = False + self.state.pending_skill = None + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False diff --git a/extensions/assistive_harness/summarize_reset_run.py b/extensions/assistive_harness/summarize_reset_run.py new file mode 100644 index 0000000..1e8ce19 --- /dev/null +++ b/extensions/assistive_harness/summarize_reset_run.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +import argparse +import json +import math +from pathlib import Path +from typing import Any + + +def nearest_rank(values: list[float], quantile: float) -> float | None: + if not values: + return None + ordered = sorted(values) + index = max(0, math.ceil(len(ordered) * quantile) - 1) + return ordered[index] + + +def load_events(path: Path) -> list[dict[str, Any]]: + if not path.exists(): + return [] + events: list[dict[str, Any]] = [] + for line in path.read_text(encoding="utf-8").splitlines(): + if not line.strip(): + continue + try: + events.append(json.loads(line)) + except json.JSONDecodeError: + continue + return events + + +def resolve_run(value: str | None) -> Path: + runs_root = Path(__file__).resolve().parent / "runs" + if value: + candidate = Path(value).expanduser().resolve() + if not candidate.is_dir(): + raise SystemExit(f"Run directory does not exist: {candidate}") + return candidate + candidates = [path for path in runs_root.iterdir() if path.is_dir()] + if not candidates: + raise SystemExit(f"No run directories found under {runs_root}") + return max(candidates, key=lambda path: path.stat().st_mtime) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Summarize real browser RESET telemetry") + parser.add_argument("--run", help="specific run directory; defaults to the newest run") + args = parser.parse_args() + + run_dir = resolve_run(args.run) + events = load_events(run_dir / "session_events.jsonl") + resets = [ + event + for event in events + if event.get("type") == "control.ack" + and event.get("intent") == "reset_session" + ] + successes = [event for event in resets if event.get("ok") is True] + latencies = [ + float(event["restart_latency_ms"]) + for event in successes + if isinstance(event.get("restart_latency_ms"), (int, float)) + ] + changed_ids = [ + event + for event in successes + if event.get("old_session_id") + and event.get("new_session_id") + and event.get("old_session_id") != event.get("new_session_id") + ] + + print(f"Run: {run_dir}") + print(f"RESET success: {len(successes)}/{len(resets)}") + print(f"Session ID changed: {len(changed_ids)}/{len(successes)}") + if latencies: + print(f"Restart P50: {nearest_rank(latencies, 0.50):.1f} ms") + print(f"Restart P90: {nearest_rank(latencies, 0.90):.1f} ms") + print(f"Restart max: {max(latencies):.1f} ms") + else: + print("Restart P50/P90: no RESET latency samples") + print( + "Dropped stale callbacks (cumulative): " + f"text={max((int(event.get('dropped_old_text') or 0) for event in successes), default=0)}, " + f"audio={max((int(event.get('dropped_old_audio') or 0) for event in successes), default=0)}" + ) + print("Audible old-output pollution: manual observation required") + for index, event in enumerate(successes, start=1): + print( + f"{index:02d}. generation={event.get('generation')} " + f"session={event.get('old_session_id') or '-'}->{event.get('new_session_id') or '-'} " + f"cleanup={event.get('cleanup_mode') or '-'} " + f"latency={float(event.get('restart_latency_ms') or 0):.1f} ms" + ) + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/telemetry.py b/extensions/assistive_harness/telemetry.py new file mode 100644 index 0000000..2e3aa18 --- /dev/null +++ b/extensions/assistive_harness/telemetry.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import csv +import json +import threading +import time +from pathlib import Path +from typing import Any + +import yaml + + +class TelemetryWriter: + FILES = { + "asr": "asr_events.jsonl", + "control": "control_events.jsonl", + "session": "session_events.jsonl", + "skill": "skill_events.jsonl", + "cv": "cv_events.jsonl", + "echo": "echo_events.jsonl", + "model": "model_events.jsonl", + } + + def __init__(self, root: str | Path, run_id: str, config: dict[str, Any]): + self.run_id = run_id + self.run_dir = Path(root) / run_id + self.run_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + (self.run_dir / "config_snapshot.yaml").write_text( + yaml.safe_dump(config, allow_unicode=True, sort_keys=True), + encoding="utf-8", + ) + self._metrics_path = self.run_dir / "metrics.csv" + with self._metrics_path.open("w", newline="", encoding="utf-8") as handle: + csv.writer(handle).writerow(["timestamp_ms", "metric", "value", "event_id"]) + + def write(self, stream: str, payload: dict[str, Any]) -> None: + filename = self.FILES[stream] + record = {"logged_at_ms": time.time() * 1000, **payload} + line = json.dumps(record, ensure_ascii=False, sort_keys=True) + with self._lock: + with (self.run_dir / filename).open("a", encoding="utf-8") as handle: + handle.write(line + "\n") + + def metric(self, name: str, value: float, event_id: int | None = None) -> None: + with self._lock: + with self._metrics_path.open("a", newline="", encoding="utf-8") as handle: + csv.writer(handle).writerow([time.time() * 1000, name, value, event_id or ""]) + + def write_summary(self, summary: dict[str, Any]) -> None: + (self.run_dir / "summary.json").write_text( + json.dumps(summary, ensure_ascii=False, indent=2, sort_keys=True), + encoding="utf-8", + ) + + def append_model_transcript(self, turn: dict[str, Any]) -> None: + text = str(turn.get("text") or "").replace("\r", " ").replace("\n", " ") + line = ( + f"turn={turn.get('turn_index')} role={turn.get('role')} " + f"generation={turn.get('generation')} skill={turn.get('skill_id')} " + f"audio_ms={turn.get('audio_ms')} text={text}\n" + ) + with self._lock: + with (self.run_dir / "model_transcript.txt").open( + "a", encoding="utf-8" + ) as handle: + handle.write(line) diff --git a/extensions/assistive_harness/tests/__init__.py b/extensions/assistive_harness/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/assistive_harness/tests/test_core.py b/extensions/assistive_harness/tests/test_core.py new file mode 100644 index 0000000..83066c9 --- /dev/null +++ b/extensions/assistive_harness/tests/test_core.py @@ -0,0 +1,402 @@ +from __future__ import annotations + +import asyncio +import tempfile +import time +import unittest +from pathlib import Path + +import numpy as np + +from extensions.assistive_harness.asr.energy_vad import EnergyVAD +from extensions.assistive_harness.cv.noop import ShadowCVProvider +from extensions.assistive_harness.cv.base import CVObservation, FrameEnvelope +from extensions.assistive_harness.cv.pipeline import CVPipeline +from extensions.assistive_harness.cv.registry import CVProviderRegistry +from extensions.assistive_harness.echo_guard import EchoGuard +from extensions.assistive_harness.model_log import ModelTurnAccumulator +from extensions.assistive_harness.registry import RegistryError, SkillRegistry +from extensions.assistive_harness.router import RuleIntentRouter +from extensions.assistive_harness.schemas import ControlIntent +from extensions.assistive_harness.state_machine import HarnessController + + +CONFIG = Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + + +class RouterCorpusTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.registry = SkillRegistry(CONFIG) + cls.router = RuleIntentRouter(cls.registry) + + def test_control_and_skill_corpus_over_fifty_utterances(self) -> None: + corpus = [ + ("停一下", ControlIntent.STOP_SPEECH, None), + ("停一下啊", ControlIntent.STOP_SPEECH, None), + ("停一下下", ControlIntent.STOP_SPEECH, None), + ("同一下", ControlIntent.STOP_SPEECH, None), + ("同一下下", ControlIntent.STOP_SPEECH, None), + ("等一下", ControlIntent.STOP_SPEECH, None), + ("等一一下", ControlIntent.STOP_SPEECH, None), + ("请停一下啊", ControlIntent.STOP_SPEECH, None), + ("请停一下", ControlIntent.STOP_SPEECH, None), + ("麻烦你先停一下", ControlIntent.STOP_SPEECH, None), + ("别说了", ControlIntent.STOP_SPEECH, None), + ("请你别说了好吗", ControlIntent.STOP_SPEECH, None), + ("闭嘴", ControlIntent.STOP_SPEECH, None), + ("停止播报", ControlIntent.STOP_SPEECH, None), + ("安静", ControlIntent.STOP_SPEECH, None), + ("你先停一下,我有个问题", ControlIntent.STOP_SPEECH, None), + ("说得有点长了麻烦停一下吧", ControlIntent.STOP_SPEECH, None), + ("现在可以先停一下然后听我说吗", ControlIntent.STOP_SPEECH, None), + ("不停停一下继续介绍", ControlIntent.STOP_SPEECH, None), + ("我刚才没有说停一下", ControlIntent.STOP_SPEECH, None), + ("请不要停一下,继续介绍", ControlIntent.STOP_SPEECH, None), + ("停一下是什么意思", ControlIntent.STOP_SPEECH, None), + ("恢复对话", ControlIntent.RESUME_SPEECH, None), + ("好了现在恢复对话吧", ControlIntent.RESUME_SPEECH, None), + ("乐奇恢复对话", ControlIntent.RESUME_SPEECH, None), + ("停一下然后恢复对话", ControlIntent.STOP_SPEECH, None), + ("重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("请重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("重置会话", ControlIntent.NONE, None), + ("乐奇请重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("你有点卡了请重新开始会话", ControlIntent.RESET_SESSION, "idle_chat"), + ("请现在重置会话然后听我说", ControlIntent.NONE, None), + ("停一下然后重新开始", ControlIntent.STOP_SPEECH, None), + ("恢复对话然后重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("新建会话", ControlIntent.NONE, None), + ("清空上下文", ControlIntent.NONE, None), + ("回到聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("请回到聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("回到普通聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("回到普通聊天天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("退出技能", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("普通聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("取消任务", ControlIntent.CANCEL_SKILL, None), + ("不找了", ControlIntent.CANCEL_SKILL, None), + ("不读了", ControlIntent.CANCEL_SKILL, None), + ("帮我找手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下我的手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下下我的手机嗯", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮找一下手机手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("请帮我找钥匙", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("水杯在哪", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("书在哪里", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("看到门卡了吗", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("有没有雨伞", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("麻烦帮我找眼镜", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("请问钱包在哪", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("读一下", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("读一下这行字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("请读一下", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮我读一下这个杯子上的字母母母", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮读一下这个水杯上面的字字个", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮我识字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("上面写了什么", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("这是什么字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("读文字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("请你读文字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("描述一下", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("帮我描述一下", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("看看周围", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("帮我避障", ControlIntent.ACTIVATE_SKILL, "obstacle_avoidance"), + ("前面有障碍吗", ControlIntent.ACTIVATE_SKILL, "obstacle_avoidance"), + ("今天天气怎么样", ControlIntent.NONE, None), + ("停止是一个动词", ControlIntent.NONE, None), + ("他说让我闭嘴但我没同意", ControlIntent.NONE, None), + ("重新开始这个词怎么翻译", ControlIntent.RESET_SESSION, "idle_chat"), + ("我在读一本书", ControlIntent.NONE, None), + ("你觉得这杯水怎么样", ControlIntent.NONE, None), + ("普通聊天机器人是什么", ControlIntent.NONE, None), + ("请介绍一下上海", ControlIntent.NONE, None), + ("我不想清空上下文因为还有用", ControlIntent.NONE, None), + ("帮我分析这段话", ControlIntent.NONE, None), + ("帮我一下手机手机", ControlIntent.NONE, None), + ("能听见我吗", ControlIntent.NONE, None), + ("今天周几", ControlIntent.NONE, None), + ("为什么会这样", ControlIntent.NONE, None), + ("继续说", ControlIntent.NONE, None), + ("接着说", ControlIntent.NONE, None), + ("你继续说话吧", ControlIntent.NONE, None), + ("谢谢", ControlIntent.NONE, None), + ("你好", ControlIntent.NONE, None), + ("左边有什么", ControlIntent.NONE, None), + ("给我讲个笑话", ControlIntent.NONE, None), + ("", ControlIntent.NONE, None), + ("。", ControlIntent.NONE, None), + ("安静是一种状态", ControlIntent.NONE, None), + ("取消任务是不是一个按钮", ControlIntent.NONE, None), + ("有人说不读了然后离开", ControlIntent.NONE, None), + ] + self.assertGreaterEqual(len(corpus), 50) + for utterance, expected_intent, expected_skill in corpus: + with self.subTest(utterance=utterance): + result = self.router.route(utterance) + self.assertEqual(result.intent, expected_intent) + self.assertEqual(result.skill_id, expected_skill) + + def test_find_target_slot(self) -> None: + result = self.router.route("请帮我找深绿色的书") + self.assertEqual(result.slots, {"target": "深绿色的书"}) + + natural = self.router.route("帮我找一下我的手机") + self.assertEqual(natural.slots, {"target": "手机"}) + + repeated = self.router.route("帮我找一下下我的手机嗯") + self.assertEqual(repeated.slots, {"target": "手机"}) + + missing_pronoun = self.router.route("帮找一下手机手机") + self.assertEqual(missing_pronoun.slots, {"target": "手机"}) + + +class RegistryAndStateTests(unittest.TestCase): + def setUp(self) -> None: + self.registry = SkillRegistry(CONFIG) + self.router = RuleIntentRouter(self.registry) + self.controller = HarnessController(self.registry) + + def event(self, text: str, event_id: int, asr_id: int): + return self.router.make_event( + self.router.route(text), event_id=event_id, asr_event_id=asr_id, + utterance=text, created_at_ms=float(event_id * 1000), + ) + + def test_prompt_render_and_hash(self) -> None: + prompt = self.registry.render("find_object", {"target": "手机"}) + self.assertIn("当前寻找目标:手机", prompt.text) + self.assertIn("智能眼镜找物助手", prompt.text) + self.assertEqual(len(prompt.sha256), 64) + self.assertIn("手机", self.registry.task_trigger("find_object", {"target": "手机"})) + + def test_aaai_skill_prompt_files_are_user_editable_and_registered(self) -> None: + find_prompt = self.registry.render("find_object", {"target": "水杯"}) + read_prompt = self.registry.render("read_text", {}) + self.assertTrue(Path(find_prompt.path).is_file()) + self.assertTrue(Path(read_prompt.path).is_file()) + self.assertIn("当前寻找目标:水杯", find_prompt.text) + self.assertIn("智能眼镜读字助手", read_prompt.text) + self.assertTrue(self.registry.is_enabled("describe_scene")) + self.assertTrue(self.registry.is_enabled("obstacle_avoidance")) + self.assertTrue( + Path(self.registry.get("obstacle_avoidance")["prompt_file"]).name + == "obstacle_avoidance_zh.txt" + ) + + def test_required_slot_validation(self) -> None: + with self.assertRaises(RegistryError): + self.registry.render("find_object", {}) + + def test_unknown_skill_is_rejected(self) -> None: + with self.assertRaises(RegistryError): + self.registry.render("not_registered", {}) + + def test_stop_hold_requires_explicit_resume(self) -> None: + decision = self.controller.process(self.event("停一下", 1, 1)) + self.assertEqual(decision.action, "stop_speech") + self.assertTrue(self.controller.state.speech_hold_active) + self.assertTrue(self.controller.state.drop_output_until_listen) + self.controller.mark_listen_fence() + self.assertTrue(self.controller.state.speech_hold_active) + self.assertTrue(self.controller.state.drop_output_until_listen) + resumed = self.controller.process(self.event("恢复对话", 2, 2)) + self.assertEqual(resumed.action, "resume_speech") + self.assertFalse(self.controller.state.speech_hold_active) + self.assertFalse(self.controller.state.drop_output_until_listen) + + def test_reset_always_supplies_idle_prompt(self) -> None: + decision = self.controller.process(self.event("重新开始", 1, 1)) + self.assertEqual(decision.action, "restart_session") + self.assertIn("AI 眼镜助手", decision.payload["system_prompt"]) + self.assertTrue(decision.payload["prompt_path"].endswith("idle_chat_zh.txt")) + + def test_skill_activation_supplies_rendered_prompt_path_and_hash(self) -> None: + decision = self.controller.process(self.event("帮我找手机", 1, 1)) + self.assertEqual(decision.action, "activate_skill") + self.assertIn("当前寻找目标:手机", decision.payload["system_prompt"]) + self.assertTrue(decision.payload["prompt_path"].endswith("find_object_zh.txt")) + self.assertEqual(len(decision.payload["prompt_sha256"]), 64) + + def test_duplicate_asr_event_is_ignored(self) -> None: + first = self.controller.process(self.event("停一下", 1, 9)) + second = self.controller.process(self.event("停一下", 2, 9)) + self.assertTrue(first.accepted) + self.assertEqual(second.reason, "duplicate_asr_event") + + def test_same_skill_same_slots_does_not_restart(self) -> None: + first = self.controller.process(self.event("帮我找手机", 1, 1)) + self.assertTrue(first.accepted) + self.controller.mark_restart_complete("find_object", {"target": "手机"}, 1) + second = self.controller.process(self.event("帮我找手机", 2, 2), now_ms=9000) + self.assertFalse(second.accepted) + self.assertEqual(second.reason, "same_skill_same_slots") + + def test_restart_pending_is_last_write_wins(self) -> None: + self.controller.process(self.event("帮我找手机", 1, 1)) + queued_one = self.controller.process(self.event("帮我找钥匙", 2, 2)) + queued_two = self.controller.process(self.event("读一下", 3, 3)) + self.assertEqual(queued_one.action, "queue_skill") + self.assertEqual(queued_two.action, "queue_skill") + pending = self.controller.mark_restart_complete("find_object", {"target": "手机"}, 1) + self.assertEqual(pending, {"skill_id": "read_text", "slots": {}}) + + def test_disconnect_clears_restart_and_pending(self) -> None: + self.controller.process(self.event("帮我找手机", 1, 1)) + self.controller.process(self.event("读一下", 2, 2)) + self.controller.mark_disconnected() + self.assertFalse(self.controller.state.restart_in_progress) + self.assertIsNone(self.controller.state.pending_skill) + + +class EchoAndVADTests(unittest.TestCase): + def test_recent_model_echo_is_blocked_but_stop_is_allowed(self) -> None: + guard = EchoGuard(window_ms=20_000, similarity_threshold=0.8) + guard.note_model_text("请告诉我还需要什么帮助", at_ms=1000) + blocked = guard.evaluate("请告诉我还需要什么帮助", ControlIntent.NONE, at_ms=1100) + self.assertFalse(blocked.allow) + guard.set_ai_speaking(True) + allowed = guard.evaluate("停一下", ControlIntent.STOP_SPEECH, at_ms=1200) + self.assertTrue(allowed.allow) + resumed = guard.evaluate("恢复对话", ControlIntent.RESUME_SPEECH, at_ms=1300) + self.assertTrue(resumed.allow) + + skill = guard.evaluate("帮我找一下我的手机", ControlIntent.ACTIVATE_SKILL, at_ms=1400) + self.assertTrue(skill.allow) + returned = guard.evaluate("回到普通聊天", ControlIntent.RETURN_TO_CHAT, at_ms=1450) + self.assertTrue(returned.allow) + cancelled = guard.evaluate("取消任务", ControlIntent.CANCEL_SKILL, at_ms=1475) + self.assertTrue(cancelled.allow) + ordinary = guard.evaluate("今天天气怎么样", ControlIntent.NONE, at_ms=1500) + self.assertFalse(ordinary.allow) + self.assertEqual(ordinary.reason, "ordinary_skill_suppressed_while_ai_speaking") + + def test_vad_emits_one_utterance(self) -> None: + vad = EnergyVAD(rms_threshold=0.01, min_speech_ms=100, end_silence_ms=200) + frames = [np.zeros(1600, np.float32)] + frames += [np.full(1600, 0.1, np.float32) for _ in range(3)] + frames += [np.zeros(1600, np.float32) for _ in range(3)] + utterances = [] + for index, frame in enumerate(frames): + result = vad.feed(frame, index * 100.0) + if result is not None: + utterances.append(result) + self.assertEqual(len(utterances), 1) + self.assertGreater(utterances[0].audio.size, 0) + + +class ModelTurnLogTests(unittest.TestCase): + def test_streamed_fragments_are_aggregated_with_audio_duration(self) -> None: + turns = ModelTurnAccumulator() + first = turns.feed( + { + "state": "speak", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "text": "上海", + "audio_ms": 120, + } + ) + self.assertEqual(first, []) + second = turns.feed( + { + "state": "speak", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "text": "电力", + "audio_ms": 180, + "decode_end": True, + } + ) + self.assertEqual(second, []) + completed = turns.feed( + { + "state": "listen", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "end_of_turn": True, + } + ) + self.assertEqual(completed[0]["text"], "上海电力") + self.assertEqual(completed[0]["audio_ms"], 300.0) + + +class CVIsolationTests(unittest.IsolatedAsyncioTestCase): + async def test_shadow_provider_contains_failures(self) -> None: + class Broken: + def analyze(self, *args, **kwargs): + raise RuntimeError("synthetic CV failure") + + result = ShadowCVProvider(Broken(), "broken").analyze( + None, "f1", 1.0, "find_object", {} + ) + self.assertEqual(result.provider, "shadow:broken") + self.assertIn("synthetic CV failure", result.error or "") + + async def test_pipeline_is_non_blocking_and_latest_frame_wins(self) -> None: + observations: list[CVObservation] = [] + + class Slow: + def analyze(self, frame, frame_id, timestamp_ms, skill_id, slots): + time.sleep(0.08) + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="slow", + ) + + pipeline = CVPipeline( + CVProviderRegistry({"slow": Slow()}), + on_observation=observations.append, + inference_timeout_ms=500, + ) + pipeline.submit(FrameEnvelope(b"1", "f1", 1.0, "find_object", {}, "shadow", "slow")) + # submit() must return before the synchronous provider completes. A + # wall-clock threshold is flaky on a loaded Windows workstation. + self.assertEqual(observations, []) + self.assertIsNotNone(pipeline.worker_task) + await asyncio.sleep(0.01) + pipeline.submit(FrameEnvelope(b"2", "f2", 2.0, "find_object", {}, "shadow", "slow")) + pipeline.submit(FrameEnvelope(b"3", "f3", 3.0, "find_object", {}, "shadow", "slow")) + for _ in range(100): + if len(observations) >= 2: + break + await asyncio.sleep(0.01) + snapshot = pipeline.snapshot() + await pipeline.close() + self.assertEqual([item.frame_id for item in observations], ["f1", "f3"]) + self.assertEqual(snapshot["dropped_frames"], 1) + + async def test_pipeline_timeout_is_observed_without_escaping(self) -> None: + observations: list[CVObservation] = [] + + class TooSlow: + def analyze(self, frame, frame_id, timestamp_ms, skill_id, slots): + time.sleep(0.08) + return CVObservation(frame_id, timestamp_ms, skill_id, "too_slow") + + pipeline = CVPipeline( + CVProviderRegistry({"too_slow": TooSlow()}), + on_observation=observations.append, + inference_timeout_ms=10, + ) + pipeline.submit( + FrameEnvelope(b"x", "timeout", 1.0, "find_object", {}, "shadow", "too_slow") + ) + for _ in range(50): + if observations: + break + await asyncio.sleep(0.005) + snapshot = pipeline.snapshot() + await pipeline.close() + self.assertIn("TimeoutError", observations[0].error or "") + self.assertEqual(snapshot["timeout_count"], 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/extensions/assistive_harness/tests/test_cv_yolo.py b/extensions/assistive_harness/tests/test_cv_yolo.py new file mode 100644 index 0000000..59476f8 --- /dev/null +++ b/extensions/assistive_harness/tests/test_cv_yolo.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + +import cv2 +import numpy as np + +from extensions.assistive_harness.cv.yolo_onnx import YoloOnnxProvider + + +MODEL = ( + Path(__file__).resolve().parents[4] + / "OmniHarness" + / "mini_omni_harness" + / "models" + / "yolo26n.onnx" +) + + +@unittest.skipUnless(MODEL.is_file(), "local YOLO reference weights are unavailable") +class YoloOnnxSmokeTests(unittest.TestCase): + def test_blank_jpeg_runs_real_onnx_inference(self) -> None: + ok, encoded = cv2.imencode(".jpg", np.zeros((480, 640, 3), dtype=np.uint8)) + self.assertTrue(ok) + observation = YoloOnnxProvider(MODEL).analyze( + encoded.tobytes(), + "blank", + 1.0, + "find_object", + {"target": "手机"}, + ) + self.assertEqual(observation.provider, "yolo_onnx") + self.assertEqual(observation.values["status"], "ok") + self.assertEqual(observation.values["canonical_label"], "cell phone") + self.assertEqual(observation.values["model"], "yolo26n.onnx") + self.assertIsInstance(observation.values["detections"], list) + + +if __name__ == "__main__": + unittest.main() diff --git a/extensions/assistive_harness/tests/test_phase_b_rokid.py b/extensions/assistive_harness/tests/test_phase_b_rokid.py new file mode 100644 index 0000000..1787b69 --- /dev/null +++ b/extensions/assistive_harness/tests/test_phase_b_rokid.py @@ -0,0 +1,352 @@ +from __future__ import annotations + +import asyncio +import base64 +import unittest +from pathlib import Path +from typing import Any + +import numpy as np + +from extensions.assistive_harness.phase_b.rokid_runtime import ( + AudioMirrorChunker, + DropOldestAudioQueue, + GatewaySessionManager, + LatestFrame, + PCSpeaker, + PhaseBRokidRuntime, + RokidRuntimeConfig, + SessionSpec, + apply_pcm16_gain, + make_session_ready_chime, + pcm16le_to_float32, +) +from extensions.assistive_harness.registry import SkillRegistry + + +CONFIG = Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + + +class FakeSpeaker: + def __init__(self) -> None: + self.blocked = False + self.flush_count = 0 + self.resume_count = 0 + self.enqueued: list[tuple[np.ndarray, int]] = [] + + async def start(self) -> None: + pass + + async def enqueue(self, samples: np.ndarray, generation: int) -> None: + if not self.blocked: + self.enqueued.append((samples.copy(), generation)) + + async def block_and_flush(self) -> None: + self.blocked = True + self.flush_count += 1 + + async def resume(self) -> None: + self.blocked = False + self.resume_count += 1 + + async def close(self) -> None: + pass + + def pending_ms(self) -> float: + return 0.0 + + +class FakeTelemetry: + connected = True + + def __init__(self) -> None: + self.messages: list[dict[str, Any]] = [] + + async def send(self, payload: dict[str, Any]) -> None: + self.messages.append(dict(payload)) + + +class FakeSession: + next_id = 0 + + def __init__( + self, + _config: RokidRuntimeConfig, + spec: SessionSpec, + _audio_queue: DropOldestAudioQueue, + _latest_frame: LatestFrame, + _gate: object, + on_result: object, + ) -> None: + type(self).next_id += 1 + self.spec = spec + self.on_result = on_result + self.session_id = f"fake-{type(self).next_id}" + self.status = "created" + self.last_error = "" + self.started = False + self.stopped_with: str | None = None + self.injected_tasks: list[str] = [] + + async def start(self) -> None: + self.started = True + self.status = "running" + + async def stop(self, cleanup_mode: str) -> None: + self.stopped_with = cleanup_mode + self.status = "stopped" + + async def inject_task(self, text: str) -> bool: + self.injected_tasks.append(text) + return True + + +class RokidAudioBoundaryTests(unittest.IsolatedAsyncioTestCase): + def test_health_marks_device_input_not_ready_before_first_packet(self) -> None: + runtime = PhaseBRokidRuntime( + RokidRuntimeConfig(skills_config=str(CONFIG), play_audio=False), + speaker=FakeSpeaker(), + session_factory=FakeSession, + ) + self.assertFalse(runtime.health()["device_input_ready"]) + runtime.stats.audio_packets = 1 + self.assertTrue(runtime.health()["device_input_ready"]) + + def test_pcm16_conversion_and_mirror_chunking(self) -> None: + raw = np.array([-32768, 0, 32767], dtype=" None: + raw = np.array([-4_000, 1_000, 4_000], dtype=" None: + chime = make_session_ready_chime() + self.assertEqual(chime.dtype, np.float32) + self.assertGreater(chime.size, 24_000 * 0.15) + self.assertLess(chime.size, 24_000 * 0.25) + self.assertLessEqual(float(np.max(np.abs(chime))), 0.321) + self.assertGreater(float(np.max(np.abs(chime))), 0.30) + + async def test_drop_oldest_queue_preserves_newest_packets(self) -> None: + queue = DropOldestAudioQueue(max_packets=2) + queue.put_nowait(b"old") + queue.put_nowait(b"middle") + queue.put_nowait(b"new") + self.assertEqual(queue.dropped_packets, 1) + self.assertEqual(await queue.get(0.01), b"middle") + self.assertEqual(await queue.get(0.01), b"new") + + async def test_pc_speaker_stop_closes_and_resume_reopens_stream(self) -> None: + class FakeOutputStream: + def __init__(self) -> None: + self.abort_count = 0 + self.close_count = 0 + + def abort(self) -> None: + self.abort_count += 1 + + def close(self) -> None: + self.close_count += 1 + + speaker = PCSpeaker() + old_stream = FakeOutputStream() + new_stream = FakeOutputStream() + speaker._stream = old_stream + + await speaker.block_and_flush() + self.assertTrue(speaker.blocked) + self.assertIsNone(speaker._stream) + self.assertEqual(old_stream.abort_count, 1) + self.assertEqual(old_stream.close_count, 1) + + speaker._open_stream = lambda: setattr(speaker, "_stream", new_stream) + await speaker.resume() + self.assertFalse(speaker.blocked) + self.assertIs(speaker._stream, new_stream) + + +class PhaseBControlContractTests(unittest.IsolatedAsyncioTestCase): + def setUp(self) -> None: + FakeSession.next_id = 0 + self.registry = SkillRegistry(CONFIG) + self.speaker = FakeSpeaker() + self.telemetry = FakeTelemetry() + self.sessions: list[FakeSession] = [] + + def factory(*args: Any) -> FakeSession: + session = FakeSession(*args) + self.sessions.append(session) + return session + + self.manager = GatewaySessionManager( + RokidRuntimeConfig( + skills_config=str(CONFIG), + play_audio=False, + playback_echo_tail_s=0.0, + ), + self.registry, + DropOldestAudioQueue(max_packets=4), + LatestFrame(), + self.speaker, + session_factory=factory, + ) + self.manager.harness = self.telemetry + + async def test_stop_and_resume_flush_pc_output_and_ack(self) -> None: + await self.manager.start_initial() + stop_ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 1, + "intent": "stop_speech", + "accepted": True, + } + ) + self.assertTrue(stop_ack["ok"]) + self.assertTrue(self.manager.gate.speech_hold_active) + self.assertTrue(self.speaker.blocked) + self.assertEqual(self.speaker.flush_count, 1) + + resume_ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 2, + "intent": "resume_speech", + "accepted": True, + } + ) + self.assertTrue(resume_ack["ok"]) + self.assertFalse(self.manager.gate.speech_hold_active) + self.assertFalse(self.speaker.blocked) + self.assertEqual( + [message["intent"] for message in self.telemetry.messages if message.get("type") == "control.ack"], + ["stop_speech", "resume_speech"], + ) + + async def test_skill_switch_replaces_session_and_fences_old_output(self) -> None: + await self.manager.start_initial() + old_session = self.sessions[0] + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 3, + "intent": "activate_skill", + "accepted": True, + "skill_id": "read_text", + "slots": {}, + } + ) + new_session = self.sessions[1] + self.assertTrue(ack["ok"]) + self.assertEqual(old_session.stopped_with, "light") + self.assertTrue(new_session.started) + self.assertNotEqual(old_session.session_id, new_session.session_id) + self.assertEqual(self.manager.gate.generation, 1) + self.assertEqual(self.manager.gate.current_skill, "read_text") + self.assertEqual( + new_session.injected_tasks, + ["请立即读取当前画面中最明显的文字,只读看到的内容。"], + ) + self.assertTrue(ack["task_trigger_sent"]) + self.assertFalse(self.speaker.blocked) + self.assertTrue( + any( + message.get("type") == "session.state" + and message.get("phase") == "restart_complete" + for message in self.telemetry.messages + ) + ) + + audio = base64.b64encode(np.ones(10, dtype=np.float32).tobytes()).decode() + await self.manager.handle_result( + old_session, + {"type": "result", "text": "stale", "audio_data": audio}, + ) + self.assertEqual(self.manager.gate.dropped_old_text, 1) + self.assertEqual(self.manager.gate.dropped_old_audio, 1) + self.assertEqual(self.speaker.enqueued, []) + + await self.manager.handle_result( + new_session, + {"type": "result", "text": "current", "audio_data": audio}, + ) + self.assertEqual(len(self.speaker.enqueued), 1) + self.assertEqual(self.speaker.enqueued[0][1], 1) + + async def test_restart_complete_plays_one_local_ready_chime(self) -> None: + self.manager.config.play_audio = True + await self.manager.start_initial() + self.assertEqual(self.speaker.enqueued, []) + + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 4, + "intent": "reset_session", + "accepted": True, + "skill_id": "idle_chat", + "slots": {}, + } + ) + + self.assertTrue(ack["ok"]) + self.assertEqual(len(self.speaker.enqueued), 1) + cue, generation = self.speaker.enqueued[0] + self.assertEqual(generation, 1) + self.assertGreater(cue.size, 0) + self.assertGreater(self.manager.gate.local_cue_mute_until_mono, 0.0) + + async def test_obstacle_switch_injects_one_shot_visual_task(self) -> None: + await self.manager.start_initial() + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 5, + "intent": "activate_skill", + "accepted": True, + "skill_id": "obstacle_avoidance", + "slots": {}, + } + ) + self.assertTrue(ack["task_trigger_sent"]) + self.assertIn("判断当前画面", self.sessions[1].injected_tasks[0]) + + async def test_model_log_turn_ends_on_listen_not_decode_slice(self) -> None: + await self.manager.start_initial() + session = self.sessions[0] + await self.manager.handle_result( + session, + {"type": "result", "text": "上海", "end_of_turn": True}, + ) + await self.manager.handle_result( + session, + {"type": "result", "text": "电力", "end_of_turn": True}, + ) + await self.manager.handle_result( + session, + {"type": "result", "is_listen": True}, + ) + states = [ + item for item in self.telemetry.messages + if item.get("type") == "model.state" + ] + self.assertEqual([item["end_of_turn"] for item in states], [False, False, True]) + self.assertEqual([item["decode_end"] for item in states], [True, True, False]) + + +if __name__ == "__main__": + unittest.main() From a4580500c45e1f6a5258faeafa6a340457cdbd20 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Wed, 2 Sep 2026 16:47:40 +0800 Subject: [PATCH 2/6] feat: harness + CV funnel chains in the control panel - panel: four cumulative ESP32 chains (basic chat / voice control / frame selection / full anti-hallucination) plus a criteria selector; machine paths move to runtime.local.json; TLS certs are self-signed on first launch - esp32_runtime: --rotate, /v1/realtime protocol adapter, reject prompts no longer block the capture loop, every captured frame reaches the first-person view - cam_pipeline_v2: report orientation-classifier load failure instead of silently falling back to the early heuristic - docs: dependency list and setup steps in both READMEs --- .gitignore | 7 + README.md | 67 ++- README_zh.md | 69 ++- .../phase_b/assets/reject_wav/aimed_wrong.wav | Bin 0 -> 142124 bytes .../phase_b/assets/reject_wav/manifest.json | 92 ++++ .../phase_b/assets/reject_wav/need_focus.wav | Bin 0 -> 113324 bytes .../phase_b/assets/reject_wav/no_frames.wav | Bin 0 -> 105644 bytes .../phase_b/assets/reject_wav/orient.wav | Bin 0 -> 163244 bytes .../assets/reject_wav/orient_flipped.wav | Bin 0 -> 163244 bytes .../assets/reject_wav/orient_sideways.wav | Bin 0 -> 117164 bytes .../assets/reject_wav/severe_shake.wav | Bin 0 -> 142124 bytes .../phase_b/assets/reject_wav/too_dark.wav | Bin 0 -> 132524 bytes .../phase_b/assets/reject_wav/unstable.wav | Bin 0 -> 145964 bytes .../phase_b/cam_pipeline_v2.py | 15 + .../phase_b/esp32_runtime.py | 168 +++++-- .../phase_b/requirements-phase-b.txt | 36 +- .../phase_b/templates/live.html | 7 +- runtime/openglass_omni/devices.example.json | 7 + runtime/openglass_omni/panel.html | 27 +- runtime/openglass_omni/panel.py | 467 +++++++++++++++++- runtime/openglass_omni/runtime.example.json | 55 +-- 21 files changed, 897 insertions(+), 120 deletions(-) create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/manifest.json create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/need_focus.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/severe_shake.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/too_dark.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/unstable.wav create mode 100644 runtime/openglass_omni/devices.example.json diff --git a/.gitignore b/.gitignore index 0cbd177..1ecff26 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,10 @@ tmp/ *.tmp.mov *.tmp.avi *.scratch.* + +runtime.local.json +devices.json +certs/ + +# ©ʾʱԴַֿ +!extensions/assistive_harness/phase_b/assets/reject_wav/*.wav diff --git a/README.md b/README.md index df9ce6e..24f2bde 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Solid arrows represent code or artifacts present in the public repository. Dashe The control panel is intended to make **repeated runs** one-click after a one-time setup. It does not download model weights, clone upstream repositories, compile `llama.cpp-omni`, or flash the ESP32 for you. -> **Current clean-clone status:** The panel UI starts from the repository root, but the current launcher still reads machine-specific paths from `runtime/openglass_omni/panel.py`. The included `runtime.local.json` loader is not yet connected to that panel. Follow the effective configuration locations below; a code update is still required before this can be called a portable one-click installation. +> **Current clean-clone status:** The panel itself starts directly from the repository root, but the full chain still needs four out-of-repo assets prepared by hand: the `llama.cpp-omni` build, MiniCPM-o GGUF weights, the FunASR model, and the Wi-Fi credentials inside the ESP32 firmware. None of these live in this repository, and none can be fetched automatically. ### 1. Prerequisites @@ -128,6 +128,9 @@ cd .. git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt + +python -m pip install -r extensions/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) + ``` Because upstream `master` branches can change, record the exact commit SHAs used for every validated OpenSQZ Glass runtime release. Upstream changes may alter ports, arguments, protocols, TTS behavior, or process ownership. @@ -177,17 +180,32 @@ Edit `runtime/openglass_omni/devices.json`: ### 5. Configure the current launcher -At present, these are the **effective** settings: +Copy [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) to +`runtime.local.json` in the same directory and fill in your machine paths. The panel reads +it at startup and uses those values instead of the defaults in `panel.py`: + +```json +{ + "conda_env": null, + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + "glasses": { "ssid": "YOUR_WIFI", "psk": "YOUR_WIFI_PASSWORD" } +} +``` -| What to configure | Effective location now | Value | +| What to configure | Location | Value | | --- | --- | --- | -| MiniCPM-o-Demo checkout | [`panel.py` `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | Absolute path containing upstream `worker.py` and `gateway.py` | -| `llama-omni-server` binary | [`panel.py` `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | Compiled executable under `llama.cpp-omni/build` | -| Main GGUF model | Same `llama` command after `-m` | Absolute path to the main MiniCPM-o 4.5 GGUF | +| MiniCPM-o-Demo checkout | `minicpm_demo_root` | Absolute path containing upstream `worker.py` / `gateway.py` | +| `llama-omni-server` binary | `llama_server` | Compiled executable under `llama.cpp-omni/build` | +| Main GGUF model | `llama_model` | Absolute path to the main MiniCPM-o 4.5 GGUF | +| ASR model | `asr_model` | FunASR streaming model directory, used by voice control in chains 2-4 | +| Glasses Wi-Fi | `glasses.ssid` / `glasses.psk` | Passed to the Rokid APK at launch; leave empty and only that chain loses glasses connectivity | | Glasses name/IP/rotation | `runtime/openglass_omni/devices.json` | One entry per ESP32 glasses prototype | -| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the current panel | +| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the panel | -[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) and [`prompts.json`](runtime/openglass_omni/prompts.json) document the intended local configuration boundary, but the current panel does not consume either file. Copying the runtime example to `runtime.local.json` does **not yet replace** the hardcoded panel paths or prompt presets. This is a known integration issue, not a user configuration mistake. +The panel self-signs a TLS certificate and key pair under `/certs/` on first launch, used by the `wss` connections to the gateway (8006) and the voice-control harness (8021). An existing pair is left untouched. ### 6. Configure and flash Wi-Fi firmware @@ -203,16 +221,39 @@ Activate the same Python environment used for MiniCPM-o-Demo, then run from the python glasses_panel.py ``` -Select **ESP32 Glasses**, choose the device name, and click **Start**. The current panel attempts to start: +Pick a **chain**, a **device** (and a **criteria** preset for chains 3-4) at the top, +then click **Start**. + +Five chains are available. The four ESP32 ones are cumulative — each adds exactly one +thing to the previous: + +| Chain | Function | Processes started | +| --- | --- | --- | +| 1 Basic chat | Full-duplex omni-modal conversation with the local model through the glasses | llama -> worker -> gateway -> esp32_bridge | +| 2 Voice control | Understands "stop", "start over", "find X" | llama -> worker -> gateway -> harness -> esp32_bridge | +| 3 Frame selection | Picks the sharpest of several frames per second | same as 2 | +| 4 Full anti-hallucination | Rejects bad frames with a spoken hint, so the model never sees them | same as 2 | +| Rokid | Reverse link: the PC listens on 18080 for the APK | llama -> worker -> gateway -> rokid | + +Chains 1-4 are **mutually exclusive**: each needs exclusive access to the glasses' audio +channel and image port, so only one can run at a time. ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> ESP32 bridge / local view :8080 + -> harness :8021 (chains 2-4 only) + -> glasses client / first-person view :8080 ``` -The chain is ready only when all four process indicators are green and the first-person view is updating. A successful UI launch alone does not prove the model, audio, image, and response path is complete. +The **criteria** selector (chains 3-4 only) picks which calibration the funnel uses: + +- **Strict** — safety-relevant scenes, such as reading a medicine box or a street sign. This preset rejects low-quality frames aggressively to keep the model from hallucinating. +- **Everyday** — ordinary day-to-day scenes. + +The chain is ready only when all process indicators are green and the first-person view is +updating. A successful UI launch alone does not prove the model, audio, image, and +response path is complete. ### Panel lifecycle @@ -258,8 +299,8 @@ Upstream model projects and model weights remain external dependencies and are n ## Known Limitations -- A clean-machine end-to-end Omni run has not yet been verified from the current public tree. -- The current panel still contains machine-specific runtime paths instead of consuming `runtime.local.json`. +- Task injection on skill switch has no effect over the current `/v1/realtime` protocol (there is no equivalent field); the model relies on the system prompt instead. +- Basic chat and the harness chains each carry their own first-person-view frontend and recorder, so the tree contains two same-named copies. They do not interfere, but the duplication is easy to misread. - Prompt presets are still embedded in `panel.py`; the standalone `prompts.json` file is not yet connected. - ESP32 Wi-Fi credentials still require editing the tracked `.ino`; the local header template is not wired in yet. - Normal panel close performs cleanup, but abnormal termination can leave child or externally started processes running. diff --git a/README_zh.md b/README_zh.md index 6f5f855..71d658b 100644 --- a/README_zh.md +++ b/README_zh.md @@ -92,7 +92,7 @@ flowchart LR 控制面板的目标是:完成一次性环境准备后,后续实验可以一键重复启动。它不会替用户下载模型权重、clone 上游仓库、编译 `llama.cpp-omni` 或烧录 ESP32。 -> **当前全新 clone 状态:** 可以从仓库根目录启动面板 UI,但当前启动器仍从 `runtime/openglass_omni/panel.py` 读取机器专属路径。仓库已有的 `runtime.local.json` 加载器尚未接入该面板。请按照下面列出的实际生效位置配置;在完成下一轮代码修改前,还不能把它称为可移植的一键安装。 +> **当前全新 clone 状态:** 面板本身可以从仓库根目录直接启动,但整套链路仍需手动准备四样仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型、以及 ESP32 固件里的 Wi-Fi 凭据。这几项都不在本仓库内,需按以下说明安装。 ### 1. 前置条件 @@ -107,11 +107,11 @@ flowchart LR 本仓库不分发模型权重。 -### 2. Clone V2 上游项目的 master 分支 +### 2. Clone 上游项目的 master 分支 三个仓库必须保持相互独立,不要把 OpenSQZ Glass 的文件复制进 MiniCPM-o-Demo。 -当前公开启动器采用 V2 四进程链路:`llama-omni-server` -> `worker` -> `gateway` -> `demo`,对应两个上游项目仍在维护的 `master` 分支。WAIC 演示使用的 V1 三进程链路由 `worker` 自行启动 `llama-server`,属于历史运行方案,不再作为本 README 的默认安装路径。 +当前公开启动器采用与面壁同步的四进程链路:`llama-omni-server` -> `worker` -> `gateway` -> `demo`,对应两个上游项目仍在维护的 `master` 分支。 ```powershell git clone --branch master https://github.com/tc-mb/llama.cpp-omni.git @@ -128,8 +128,13 @@ cd .. git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt + +python -m pip install -r extensions/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) + ``` + + 由于上游 `master` 分支会持续变化,每次完成 OpenSQZ Glass 运行时验证和正式发布时,都应记录实际测试过的 Commit SHA。上游更新可能改变端口、启动参数、通信协议、TTS 行为或进程所有权。 ### 3. 准备模型文件 @@ -177,17 +182,32 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j ### 5. 配置当前启动器 -当前版本真正生效的是以下配置: +把 [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) 复制为 +同目录下的 `runtime.local.json`,填写本机路径。面板启动时读取它, +用其中的值覆盖 `panel.py` 里的默认路径: -| 配置内容 | 当前实际生效位置 | 应填写的值 | +```json +{ + "conda_env": null, + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + "glasses": { "ssid": "你的WiFi", "psk": "你的WiFi密码" } +} +``` + +| 配置内容 | 位置 | 说明 | | --- | --- | --- | -| MiniCPM-o-Demo 目录 | [`panel.py` 的 `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | 包含上游 `worker.py` 和 `gateway.py` 的绝对路径 | -| `llama-omni-server` | [`panel.py` 的 `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | `llama.cpp-omni/build` 下的编译结果 | -| 主 GGUF 模型 | 同一条 `llama` 命令中 `-m` 后的位置 | MiniCPM-o 4.5 主 GGUF 的绝对路径 | +| MiniCPM-o-Demo 目录 | `runtime.local.json` 的 `minicpm_demo_root` | 包含上游 `worker.py` / `gateway.py` 的绝对路径 | +| `llama-omni-server` | `llama_server` | `llama.cpp-omni/build` 下的编译结果 | +| 主 GGUF 模型 | `llama_model` | MiniCPM-o 4.5 主 GGUF 的绝对路径 | +| ASR 模型 | `asr_model` | FunASR 流式模型目录,②③④ 链路的语音控制用 | +| 眼镜 Wi-Fi | `glasses.ssid` / `glasses.psk` | Rokid 链路启动 APK 时传入;留空则该链路连不上眼镜,其余链路不受影响 | | 眼镜名称/IP/旋转角 | `runtime/openglass_omni/devices.json` | 每副 ESP32 眼镜一条记录 | -| Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 当前面板中显示的交互 Prompt | +| Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 面板中显示的交互 Prompt | -[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) 和 [`prompts.json`](runtime/openglass_omni/prompts.json) 描述了我们准备采用的本地配置边界,但当前面板还没有读取这两个文件。把 runtime 示例复制为 `runtime.local.json` **还不能替代** `panel.py` 中写死的路径和 Prompt。这是已知的集成问题,不是用户配置错误。 +> 面板首次启动时会在 `/certs/` 下自签一对 TLS 证书,供 gateway(8006)和语音控制 harness(8021)的 `wss` 连接使用。 ### 6. 配置并烧录 Wi-Fi 固件 @@ -203,16 +223,35 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j python glasses_panel.py ``` -选择 **ESP32 眼镜**,再选择设备名称并点击 **一键启动**。当前面板会尝试依次启动: +在顶部选择**链路**、**眼镜**(③④ 还要选**判据**),点击 **一键启动**。 + +面板提供五条链路,其中 ESP32 的四档是递进的,每一档只比上一档多一件事: + +| 链路 | 功能 | 启动的进程 | +| --- | --- | --- | +| ① 基础对话 | 通过眼镜与本地模型全模态双工对话 | llama → worker → gateway → esp32_bridge | +| ② 语音控制 | 能听懂「停一下 / 重新开始 / 找东西」 | llama → worker → gateway → harness→esp32_bridge | +| ③ 质量筛选 | 每秒多帧里挑最清晰的一张送模型 | 同 ② | +| ④ 完整防幻觉 | 坏图直接拦下并语音提示,不让模型看见 | 同 ② | +| Rokid | 反向链路,PC 开 18080 等 APK 连入 | llama → worker → gateway → rokid | + +①~④ 是**互斥**的:它们都要独占眼镜的音频通道和图像端口,同一时间只能跑一条。 ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> ESP32 bridge / 本地画面 :8080 + -> (②③④ 才有)harness :8021 + -> 眼镜客户端 / 第一视角 :8080 ``` -只有四个进程指示灯全部变绿,并且第一视角持续更新,才能说明链路就绪。只看到面板 UI 打开,不能证明模型、声音、图像和响应链路已经跑通。 +**判据档位**(只有 ③④ 需要选)决定漏斗用哪套标定参数: + +- **严格判据** —— 有安全风险的场景,例如需要念字的药盒、路上指示牌等。该判据严格拒绝质量不佳的图像防止模型输出幻觉。 +- **日常判据** —— 日常场景。 + +只有进程指示灯全部变绿、并且第一视角持续更新,才能说明链路就绪。 +只看到面板 UI 打开,不能证明模型、声音、图像和响应链路已经跑通。 ### 面板进程生命周期 @@ -258,8 +297,8 @@ OpenGlass/ ## 已知限制 -- 当前公开仓库尚未完成全新机器上的 Omni 端到端验证。 -- 当前面板仍包含机器专属运行路径,没有真正使用 `runtime.local.json`。 +- 语音技能切换时的指令注入在当前 `/v1/realtime` 协议下不生效(协议没有对应字段),模型只能依赖 system prompt 完成任务。 +- 「基础对话」与 harness 链路各自带一套第一视角前端和录制模块,仓库中存在两份同名文件,互不影响但容易混淆。 - Prompt 仍写在 `panel.py` 中,独立的 `prompts.json` 尚未接入。 - ESP32 Wi-Fi 仍需修改 tracked `.ino`,本地 Wi-Fi 头文件模板尚未接入。 - 正常关窗会执行清理,但异常退出可能留下子进程或外部启动的进程。 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav new file mode 100644 index 0000000000000000000000000000000000000000..4fff8e2e9ba7ac93117f248688e1de137ad6422f GIT binary patch literal 142124 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¨AOWw&uG)I+O13r4mCwUIa6XTc+%MeK%=r;{1e036~PnUrQ+wsY@~|&*?fBDm!26zhQ)|n=68|tgv23v24O|mE5SqQU!V}Ru$CWCK z_#!+PJheDzRN#ex-S*FITP!!tXW=PpH{^RDC;)9YQ+uNK;0Ex!h4Rue=w?M&cxzQ_ zs^yfWlBJAgzWI*nAMBmm#7_Ko`nT!<=uLPEx8!}A{YS>l)T$}tU&~2fCNxOcmJpQ? z|LXgMJFjoP8I)cvC#opY(@twI##yDHxUdf4lOtC}%!$|?zBa5k7q+{RRE2as3gepQ$!6Q@y zVp|n>t86Ju1vb<`Q-tM#`)>#(WbVrQmpKJ4d&Af@O zF~w&K{>=@_ewifi7%hjv6Wl>_`-oj6d-gk5?{>7E; zX$&2Qd+K|7Z|sL;az6=QiQ}XerfhR(Xu5nAm>*a@pqg!jH5Q27p}-itY{Kjv4B5DPQa&?U5yD6%?4!-j+zK71%NTfgD{i=pqnbbA!Tylz_+p zr>&3GY}sL|CLa+aggIO}ZH&^}eZ}#0;lKIkpxyi=b7Mw&`rNczX=Bp1re&wSNsUhr z$?TK0FuPywnZl#RZ9E^tzwcV{XH%$khHVhW&n~uqtRGn`n1{iai(PW@*L3(G((0(g zl?~oao@wrFu6JN3zR&%YXE&t5vOvEn&>rXufsS-g_zie%Jxn9a4K1h4;pUd+mF5l5 z7l|?5l8(YA`d>&HNkXD<9k>L!+-f0B_(8ZTG!;YP1$VaG2C_&1uq0y4T`U!?kF7Ra znysJxjlB_Mu|{Rmx!d&Q?5 zV~YX`f6ad<_qXg%v*I(Pj8^Hx(`#oO%XpbJEcwfTo#mbBo30+!$8hO< z3t$QC6}}V>3s3legnrUS)5qpaQv;J-z7D;ZwPLgwz?1!CC3q+vB<=*B$DhEOI3-p^ zd51zvV+y=6tL8VDX>JYZA5bSC&;AS&bxh#$z?p&f1HOd*bw~L0&9dLL*{to&nR0h| z4_5txd0zhnKH74WtKP3YR(Egb&|<4&Ch$ZpMdJ&*<#|p2ZZaXiYthr^Z@U8^7r5pT=IruTtGv%vIFUJXCDl|=!#h(CgRMsZgCmRed( zQto@IdFp#6csDCy>Tc|NRK*HS7p-$*`TizDP8Ol{1YP5Vv9u)EPg4wa&$?La?m z0}rf6f$iEII&iIkjQ;`uJAWJ=hXxDnrJkl{mPuBRb-yjd7Hz#~nPII7>87#W1k|*V zfk8o2fe>@lzQ@`bs{*S{T}?-T+Hg*E3g1Ap<}|#?>{A>2Vw5cJukgfj)9b}NA{w&R zCTCa2fP$sD!?XX$?3ej4L&$Jv6l5f4?9OPEc_OQ6?(Mv=qB!Syk3~=CXF^-@sd*L< z$5qoN(*x5S(^FGvQzdza5Y7M0m**`_5AAXsy4?C+hP7Qk&{kH0T?^qL2vE@M5Ej0UX}%xsg`d{ZfP@g!6NxS`Vj2^ z)^CgSbNn))238lZgI6~d;;?Fy4xINNF=u#Wwb&(lTibR^sHGZE1XIjjb9ZRama(h> z)~;%rY$}$&1X}G#_{3fg4Vcx~3EB)SqF{LavhsDfcl7O8V@dNZQo4ciqut@o=?=MQ ze8IH*C%N}>D(6(nX_fn9&RJ+l&cW)`*ql8;I-gLqz?tYCtn}C7g(xvq{1iS3&Pt=j zd(sDDRbc?%fOlZ0&aOvlAFF4SBBi45Gt|R0^|sa%d!}w~pm0%46PKXWvw@wr)#NfS z0T$LitfbA5dP4{2ICLJK(k?mY#29>BpAYY0@#q06zfSlJcpXhp_AQpf@Mrz0EzXu< zm8>b&UO?-;4Q+N29)a$g8<}^R{*`x02gEPo6L+kbDTYW5r2gV2LBza8=c;g@=$Ekz z7pcXe^((?-T_P+UJ_Vk{ z6!DDIU!EYRn%Y@fgO}gMk!fvdt!-&-sbe_@w98(miYB+bPu>A+lMv|(=s$K7`vZq( z7Z6SAidOL&Fhef#FR?qm&A+$2R*waR4OYhk#U$U80$tAMuGg+zz=Qgt_?F{YQH8?H zf@Qfj=&FB}Td81u-qnJw1?Pc?-K@Afyp|upu5BakAMO@EMrw?;gH&LO4C6;b8{h!+ zXtu)B)JY8rV%l!#waK7_e2s_ig!lOC!ffPgxHwQ;FIAQ9io1adv{R}l#Y0aq7B;|U zpnFsSV#Zmln&$!Imfiu8C zD=JKg1efn3%!e*aL#)mZ6ja#y{|T$;kF*-t4NZg|!&Tq~j06qOgx|S*K3F&=To&d7 zd#{qbQEDhnlO{^b#8c4Ed?kE~v9F3)Tf8UK5&cU33tj1AB@7y=!o*VwQA5&9P6 zbSD=j9vACF!d?%IoyE{beP5_9+z{#kk>-Z@SPU1F;74w(FdFOCX~3m}4y5oo=t7cD z0tvROd_vB|YH7Ur6|DMCo2Nn&zhs$d`PUp{ZUFSWS*9VT6geLLul|Mx?Id>7kDzZ>_bpS_c~^M%dV6{odCt3+yXv`u zoI{GMIQkcsD?C)Nxv+H6wIZwI9mk8J){d^le>$D63BXkvr;PTgnjO+}7kJFD@hy<^ zn?R+R#gFD2VSb&3Rj`B5uG^&#K`pi56QBc|#Ov5=Y6zX=&&7S>1lYQ-mYQSUR8foq zKW>hh`+e~U5Qz?gBBn~4;N!bGdhGv#bE2XrPoO{sFA8JK~?xdij0epJl*qusQaz+L?NQOHMQG z1j_yO*yYpJZNMF9riQ3L z`aV*+dS^f%ct3PnYj`s~UwA~c_Hg%FSBi5ckhB^(zi}>y2C>z-zj%YI=-4qY(7lopK`37yrPH-BtOz zEST1q>OwQRGZ51^nEo>TX|kFhLh`SS6~>OxQ|>D=MPuZ3pweKB?2F}Ic(M^|Qa9vB@DFoZ&XUWT zo*|qAb+b|W6`IVt^cuAB6mwKj>MH&uJix5x3V)S92kpbt;8vydZO~?{u02qj@jdg;xuI z37y4s@g5K;z0w7F4^R=;$PeYo&}*IrWXC2_d8wOpTdI$;o{{6wuBYU-&@_Hm)*yRr z!+dQl5Xf^N<$nz+q&s+Wbv}xB!$U%6UV?Vldgx9@a#x_OSQ7|i3!t4Cq8rRHXfJ;Wt*G7FLiMU|if_NK$hQ^0hkc!VA1c|NG8lo& zxRTiPmF;SY2jMw}x;DU3WFgw_~eXJ9SlFhb4} z7K?Qy8}@qtkZq<8rm?2Ga#fV^09tLa)L%*#-^JQiHQ^fHfe(ewfQy?B)c0@1^WtRj z4fcayqYYm`_x2BHbdH5?;03J(cFyYf8Yp+YSG+ecry7cN-Z@I5qA7#WcJaWS_qcm| zj$p(s<2~TL>fPhbMoFrAH-kT&_CEFYR&M$Zq1Sa%C#qAhhI!ogz*k$Hqc+kSK~u0L zHvpV<2iompely=d*a5Cz8VHMr#r?2Hn2ve!x8fxrkNqM%6JCOLe}@!!2P=PPrQYb3 z-^w?nEcCZ!urL^iHOyIPyG+a{2k={Y8+>&yz&BrrA7V^i1}l~?_)feP^UO6u8DSo* zCZ0eyaH!rAUI-kpKl#V4?T7h0r(>LAML7fC_wHvTV7d{4FQ3l@}`p>@rZ?c9kR4|FJfneKQQ2AZ_Zhj70q%n9%Zy?77!*XJoGzNYH zyMa4>k8w6${6Um4BCf?uViZ1!e1zb}_XDBf90gv}9J-Ke_34n2hrl!F zOvtcz)C9F1w1FN#&weR1+Z{l+^8q7ntgpXM06JWGm50ZJRPQFQNl8=20wM3due5qn z{X=c6rushh?eRH)gY+{-BSB3D8cs*GHT1B{LqlGIZn6`4tupj=pFwh}z}LpO@-;sO zd7J@^%WjbWZTw%{2Iwx1g>2baoC+!78&GDn)D~Fr1L5hThAB zcli|fFKZ=C7RG@~cLtW=ZeE2p_pi`xy#h_kyIdky9kEA1Cg!-_unw_8JM$gg0u9Z+ zn7bVTYTgHs80x5>s*jC!mW8VUyCOR@Wye7;xF-JxzXYus$iD+E zozKASTkwP7pT!0~xg6^vO@#Z9v0B6Sp*2=3OY!5-_BDlIVIRL1YwU0MGmtq{;O}ih zOKwDMIk{9E#~^j(K_@*Iy42@kmCy$oLO?{o{4)pkKVjH`xCZ%stKJLPT0SjW?}n?I zD0gG%otFatU7;OBYllH&_7XXr+Ku7lm zYzKNmOT86z-Z7y8(bZl%Lkw%^#rrV0MKcDVGH~~wiXgmJ5l^=*d~+)f^#Bt zi8*dI^rHtuH**@i!;RNVK~t5(*Fiw0I|&W*%0T=RfQeWGoGD2EQ#-FUhpoaz^sQT% zThGKi`!85Gti?Dm4%Qe>=!-XiEsj@v2lfGzp|$%b^qYra_2sE<#hB3^yysWwf4jL- zumSNw>zL=$pa-0UJ~IW#eXXF`o({d|SBU>AYyckVy%Bpocq;BMd<7nI20Zi@bk);< zoyNh!rY`y$>4#r}7WXuaOZPYryeB)kwm=rX4M{Q=a%D~E(J$5OLCSJy4fT9b*tgnK zZ4BDrn0_7mNyE{5YIA?XmO_M1dwbOMztH1$ARh;y!934zC-OVAlK+PG$OE*;IOKIB zEECosq^6HUn^fU^(BIAga^Cx}e)t#j8Y@b*9=MCIKsT-ZZC4rVjuF5vyo$DM2c*2- z$oF;3be==^e>srtPT=`W&|XbYa4i2XtRYq--p%L>hxF>;*Lgrl?#Z`B>t&&wf!twO z0~~_&h!6G99JUsnK|d3qSKSBwVkSE@ z0q7(JRuSvb=V#+w9;NybRt0OYM&JNWXA6884ymLbC~7_IW9C5To>)99)=apc1TErk@^eNY%z53&qA;DGANnqQUkW)Gd&!5kWKMV*oYR; z{t46}d0=p%U!6f(H-J|7BdG6hwA~wUyhv!;lZO2QaD)Z0M!AG9HY2zBsE0i8h&`av zB?x~U`Evr@HX4>3H*hx>y9H^QOY4Sp&*`wgm;$Z*TkwrQJo*WquhuJ|gwvpzz7~D2 zE9hh`>Lds~`5^2<_P~DP3_@Q4Mxu%sUV#2v!a|}IXstb3KLU001&&U*C;ZQm;3hp$ z|1bQtbpd_ol0VOX0nhLl=CVid{GRRw1=ZwIk>~GG=1VBe0`QS}u*cetn)wqwZW~g% z2mTrk#LGPJ$LmP{FCYW11BX}+JCqdI8N7z|1P@vwL{As$;Vxo73$Bp>tO()8{2c<~HcwXQ??jrO&SL5Y24hBDXmQ4%UoHdRSb~zbN1sVYE$)Z4+6{2CLez;4 zdt$=a{0Di;1ig7M>l}-ow;V0r54~E%$a4a8v<-aw0gx+I^oMeYCkgfQJ&xJved9qT z=kaX?mv*GJ9sE26q_m-g8 zvcTzVfZTrvUN{MLVFw3(iMHPZzB>tZatxG3wChDYmGMPOSn+fKhnozZ2(39-*Ytx; z(I?P)sD;)p06l0ZWi(<*2e+$+R_crpgF%fQP?itDbNeIodk9?~)T)DD-0_c%k>I^i z{%1M3e}!IS!W`oR*dBg}|3YvBv7pUr$cqOw z#ppx^h13MiHbdKghSGLMpPGc#ka-xn2bwy%!< zG6gAj$CVHL?-I&htXIYT0QB%aD0xNLh$(0(k~ONJ9^S)$)Bobh15IXuDl+hmigcrp ziw{sAwQ&`VFKgkdE^<8p6gnCCuY^)XftO43FpylIR3Xp|@&T;>+~v>R4nO_9$MsFHJ<1mJoLLKPH zpB*`>h_v4r`(wf)KM4afhKC5#WQRkQZw4_mGEaqy32vb=1%;P|tJZG61dF7A@Bb_25ODOa9!Fo$Dx+tE#`JzefLf4f>>Z zAjId2h_x7_QYP{gi)S4WYim$O0NRYug44hYO8e_M7ClXom`* zf&!Gmfso;-!#em6=iKPiSHKrffrq_7UP$tZKn@C#dLsT4P{JHgrGU2M5xNMip8yIc z&(K6`A*fLirE}x%nLp3P7#H6|>Bv&L0%CHZrs!E?o(cc-C*lbdtZ;CkRzf3oqpuW$lSyc)V6>@<@)Y_13;n%046y{^Yar9& zaQG=a1od1NeMa;1w7($FoInq~j(WR=mVAMd06!KjlZujNpd2)7cmiwL+o+kp5atC+ zoB~?Oz|*U!Cz7k~;#od&6pZ|bA-!UJ_1YgpG4eqr<4}jMKq2YK1@-#?P$uz8LZT+5 zY%`vO;#mbySOiL_fx0qK77b&+4R6S*ltVAeLL5(!S|Q}O2s{-)z4?gs1^DwV7JD8I6b6aQzC;iQ^O?U(e8DHz6gR0B_!lad|I}gBa2GfJzRb?a!iAchGud z$4)5LcM!vM$hr@Z${WN?{r)j>@fc6;BF#5Qk;WYtY9#?rpP@fc?Rh~bW|YN*T(TAm z0By&hg=5hIktjXYiwEU*gEEUz4yx;CI3D1o?CzC#h%!LiPR^-#kW{Q}H$r2l0j1_$J*S8VVR_ zSqY`rQ8$JDc1rfYClqulDdp-BVt9e4Z~W;bBj%@g@&I|E@>9+!)E(q89tWX$)A0}L z;2Q2O;{P&AKrQqSYUUPxFM|i4Ln~gu^XmvpPj8`ogiTIi>B${`$`A4T0BJlynnc%0 z{(QZ{711h5Cy99S8b=ChfTY(Pl)`~}aQkP70$R`t`h;N${;8#*LV#yBP$nHA=n*!5 z-}Zn;==)66RWjmy=`SNmc-N4x`^W*cdje8QLYfJ9PnZZ)`g{I*{ueZS7k5OJFL5OJ z!@NZ3RK%Hsn2op-5#k}f`WFY`rqg#15dU+0k&HUdK-=V_9To5~qS+$cQOm*b1u;>N zPsKllBUv^Ft?oo0_8>Hf6@NV1lXw!9Rq&UMF#lZ$Mg5NcsdhZ5ADTm#{AvCt#NqS( z^+>7Fk^X-uE#<$mz@^ZCc}ewCMJB>i%*DtH^@4PNF4J+&LdbNKifHMvpIWGtgz*m7 zKL4j&M4QBi6wo7pHvIoC#Fg(qh%b_iL%);;@gw(tluPBb_}dmnQaIq;6h{Es)Qr-X z{1IoSo^D52dQN5cA|@B&qn=H5O!-bj38{9o{0Eht#ucKqm-tNrl`$lH*7Jz=7}|Xn zN<*|qt(1ZCQNK*~*A0cII9Y$CzDhkc+aH#-Db)nYR1W0Ci5yWas5mtLnR+PuqbDSf z(6~aB!NSlzYi0JFO2*^`njt#>YZ0R*S-n%blvg?%dC5k;Sg8rEpW2QnjehBPyJqNH z$}!E>h%)J*w#-Kv=%5y&I;GMOPoa>6=AVyRrh{6NsF1ZUwJ5bLg(lubF&N=kX!?Re zGYX?n#F1GV6c2k&F}TsD#OFQu^`U-PZBe~Yjr#DMXpH?b3V6E~slMqc{Zb7oI8%Hq zF4i7KjMU4hpAk2qUiS7uZ%Y0s42AgLKlUyAl0qBz65=ENB;y;BCFn}_(=DTKJ1EP-2dD~!b z!ZDIZ;-Aj+%R+_X>rnq4dtM6iKOOW9g$wn^#J-?knwf?85Ath4U$Unx6(cRmiIEbW zS(fW_3FQM&=W$t zc*h^IHs%Ml@rChA-?M|BQLN;bh0;XpPYTwQE^_Y$ScLRLZ0FSXxGEEEmT6IDdF* zCCUXor8CuS4C5h)P)*jDEv<5zWn5Zz7r| zS`Yc3Z~^FV)Hj*r!OqkZsgJV0Y4lolNBx>+d?b+szC-+nxY64j3yjqNM?94AL>hr<>@@f` z8=o21XC8JK-z15iI5BZg#*Zl?;a8u%r21jKQ8snOV1oOY#)1R5QzGg8R;~tHn zlpi+2Fqx1^EHu8AjAk@SlPpZqW5Rz2Np^J5h)@47{QocfXXD8$e+X!FVDzVhMtV9Z zHoB)c4f&jABlMg}sq~Z%lH5tgq&V0cx@P|@P8KWWj6$$n(iO{Fg8z!$kz`VGJcpb` zYgIJ&d4hvvb2=XWcaSuF|Gy`6O$XsDk&I9CBKnf#+^7EE=l_+PN=~Jwf0pNxUwXoF zPPwInN}uEp$?|FBnbj)QDT|+Cr~Fcm>6fKzq)$0`>Obf`&9O-4Hu6Dtbj=PbKP!1j zdr_M`|LZ`omlH%1m3H&~3({*jJG2R4csqXcnVHV0w+ zmZUFMJFMmm39W<=lbpszfs$DajRA~*(-n;`MmogzOU46QbEWZ@jd)Z>Bj+?yzg<3h zPNiTaqBrawh?XX9qLf8;l$NuyPmbjPH+ zl3!LH8i84>F-ek*cy!I$k@8^N8Bb`OCs~k<;&f-U6g#tV-uR_ZW&Jfq-?O+_?8eCY z_L(FZW9((2=?hkBDi5_t=zpz5qb!rEX{=>ZIkhxvb83H*=UM+T&h(UpU?Z|25zyGo zX0j|+ikHQ0q(NunVDnysa^5~uF4$WpjWCI%L@uH97;REcsQ(%>4mJ<@{~CQudLeNO zHj1WH|4*t${+Rqi5(&u) zjN_0TLkF9GGC79LKiNE#=ACS&O5C01x{TAaIWN1X)fpNCN)9#_u&|61GhR%yRpQBX zHV$J(%+`h39Z6PfJ%G41%N=oVL*iodUy^i64tB?WSvly}D9hWWpxm*M%UA&@8GqOq zNWX06&&DBI2{A?;_J*w}u(6YkL+l%hiH&1)ruWAE+hZI1nvGs`%|<Xat}Kj zk`PHZB#F`gEBu!nhKxk-m{dp75y^*i_qMEL+>u;jq-n^MOkQNUWu;?s0J~?e%>|4QtS$bx zMU0ibl6qs(Jj)CHvV-W1$(O9=jdo&pZ__QKXx1NC-!b}2$z916>oM%!=qpCAFnS9; zrxfVdpa_Ew=qdF|T7#s2iiz<6LlR}uqwz~?gvNErnQ@Q*<#>$uF)qhAUWvR*oQ}!C zjHkZM@z`o$$qH`?2WC9b;AD*Zv6Vu)HdX+M-x>2xdPdSCtq&Uiv?j=|*&Ftjt?SWh zAdLbf0UHO64KzB?oRzKl(b*X3*jnQMjxztZJ2q;u(TT0_F?qFQ&5&04*hp(g(IhuB zS(-*;nwyu%2sBo+wLB&{(#Xw5aASvqq)7IJNs~;TVAu49Mt-^@*@CSk(%KJP$r|XJC-++*w__&N7sgoYJ@XlVR>d!DwTlcgwi*z zDW6feCmE6?Lz->S6Ozg4Y)GthrV#YpSi__%7T%CWjaUr1wq9wenYVu_pEG2IVoOB!Khg})AuZOdP}JpHBGB~>`QhoX=`I9V1zVg1QZ_~ zMoSniK-5ID1-dt8I;>sjdC4L=owqlCb}g*({v{3oP}nqYR1}HAfD4f zGBkxW4z{LOa%V{06qgY{&CA$YAN{i2QLg{DCr~M=zKmL7Wj1Pt)dQ8zs11YW-o7uX ztCF|$jI|JpgZ;ADDU=Z><%}Ja2DN~3M>%Dyu_b+()gyaK;ph!(9lA4Or)!p{lCx1R zBeXH=Gh$(JvG_|`g4I5&dHVf-&v0lhH25vPL>!93(LA4K*X*F#4Lvh>Sjl{c&B16@ zmHiv@YvO}!HI}V_GJeTsYQ$HGy9)I~!}+y#F~pVY{48&*YE5>i>IUS^1XXKEc(fSg5LgRKc?n+@b zh(=pl)uQp(_+_hx#+nk_siXa*ScIb0HhNPU|K5dTWpJh)HoBuVI*NyW=?gmOExV8Qr$eFGdKbN=bZEbe(xqSaj;#ik z6h+y;oQ;)Ob zimjB8a5>#^o4K_4z}PRtWpr>ksF|7qrSx+>!Kp*gPp8SM;2%B^6;c zstD-E79Tqp1!43d74R4IMSdl^v6MSJvLLz!#gMDlr*Eu#Z%H^ zqJ4-$%pqw7jpEKl2+|6nZ)t~)G=^xMi)MtR`C@1$kv1B|M){vRo~vkQ4}(>&C_fYvrN>t8a`BEzOSxuqZQA)^8cbCGq{~)}cT@{m_?GlUNyjQ5XVO%n z6$1J;4ga(bNUH#B#enn(N&knvVS8P)T0k|Kfv^P#nTBtvg-PF#>L$w{7i)LQAJGge zH@&A^(pM#`1yn=SQj~Y14>}V?P(G=C^ZjLEbwwqm@*8!)+LqP?Se>vMHuQ_AjxrDf zeM2i3bWaDprxg&2pUO^op?^xBazME?w3jF!Oyi6+u4#3F>0VQhq5ecvNWFpd@`yeu zEoxJudZJXy7sWudNpwjEr9jUp4SLV$lxl&!q5QEDQCLQe6f4C^^;v|RQ=L;f)b3QT z6gPcEEkU)yQlXlmIwuOEzQgiLDUog!t(tgnrZr>YL!==_l&RuOZ`j@&TSf7L-_S~k zh7hzqLg9?sFk+^V>?y^_^sDF@t1AjcyoYLuw65r%=?&0Y3q56PF)U^(9p#qFNU>5J z###;KjQAXJ&JzAd99IH2CaIjs=qB)N;_tLB!lWbihC&c;X7U}ST?}qZtw@ItDUrlU z+?Y5U@mS)cJUA?zdw>U1s-)pf@tFMM2aQVs7>h{qAUTJ|JR0w4bfeLWjWIMrFwJn{ z_)K$x%0hKb>rO;rg`mfDtcJ36=r^ENqEgBsNu*Tsq=78}8zmB!XnNhXfF zySr;x+}#&z2j)HJdQv=aRDnr|@haoc@YmR;zdP@51 z)!@5y=n88B9UAAszr75uNq!DG&$QB<-v1o|asQuBe6HW8ghgSAfDc{Ces z*RE=tAaf)R=n_0mq*iHIe?V!Z^UVDwS}kwwI90KBB5usH(cwRdLHxv673IgZk}m1k&T*1 zssS+|3X(A%;SN*)kPbHB0n`}Ml{$>aYj-snkJb&Eq%VS3{|e|-+=IX9tw|Ww37@8( zkulnF$m`2i3bSeNQ!06)_dtJZl-_{;3kVxi@Dp@iEkPyG9khGuCsc}_K~l(3yqd}* zJMkXfOSb8Q=-+x5V%1;cS~ymDtbJvh>J60Qs3Cip2y!Jzb^M_&A^qtXcqE?biFl;$ zQHSCU$PF1a3hqS>1Ik?%YD!hprUGxN@TzyFO5$0-XDdKe;fO|1%kfif53opvARv9I zjkQ(WUJ|3$!cWn7eG9oty+$LzXOay>rH1+#e2mJ0KK?$C80b_^>v^<>eExB05_ds8 zp>U`Z^A~koj)IPSyIvJoLNl0G+74wp7(I-NW-JHz`5-axq$6bu8rev_dQNRlw|s(udL6WD+sZ7tmnxlk}vIqP|LLJ(>Ng z$NBwu6K&Rji=umJpVnE8K~L!k+H5I-EyeZ&O03LIU^>gC$R-B5kjP)uIjtSqk5_An z>T~KeeNqciC(wORX{`x$KzmNLMx6dHDTWTxW-?QefsfQ(ECjQUPq5K2oO9F{YPhQrbbfb&9gpXBA(w zE&L7ThC&v-+qaoC7N4Pk-f{YPVKsHan~w(YLFyp+8&jQbBk$22%wBzjRDr(E&HzGY zW5{xN;2)>X=2q$B)!V2jmX+0L0>e@drGu!g_(gNLGVyogBPHEeOaE>ht!BDwi({Fx zzRP-j!G(vri=zG}L8|M^GQ6U9dX^DlsH;CNu(C}|qvVhNU2G5@tRB?fGuO3dYG>4& zn;X8!OS3eYqq|C`#Rw5cotCRss$5Kc!sR68^5Ap_$u(A3<=>_`D*O3#I<4g#B1jwz8m^tt&Kxj06tG!lk z;(qkslAf`8eO*y61 zh4jV6nkLVrOEbNcvN%W^0;I|9}-_(YXQMfLXER8@CjzLGI z6FL^#kzL**+;vWtS4bZAD8Ir}gUse1(P@%MelgW>SN{NDwhSU&P-AAU(p6JY0zFY3 zq}`=^;vd=s*~hM-yU0(-T)HM0|f$AtBUU?tAok>ACQ^%qqS zK*riVy@#?Hh2jEz8SsxpJPeJKW9Sx)Rja0sqt3DI$Vl}Dj-uy6GF)l=4(5qH${%(C zictTMR=7JCul$fta9zo0l7$Dt8|97`gd*r=S`96V>O)u6>u9^xzHC3bgM3{NM*lEV z)MWVq{|OiIpVGVVF8zlmhMq5;QOo#>GHne%{g?^qW1@VmK&tE@qa*pTm^Ntc8Ynd9r1a^c>a?&!xL`$%VQk7te+*+}T9a|41#^HX@Gg6SRxt17LF!0m4JuCm>yAc4_{I8h^{dibEUQ0} zM`3|Da2_6{)FE}58|-SIN8V_dO_lSlpoj32HXi!|`p(QmQem}LK7Fsfftf!bustzAPd4YEXe zU3)Fhfqay;I8Q2za+qO$7VYC-%01;#=#r_dZnsy)yR5sV4IVEu)u`Te8!+Zt6L?EnkYB>kZcG8m4Fo-ePPwp_SZB z86dnzzdWl^DPyKm-1nYq$hB2wdM+_D%{M(|JS!mm@Gl>yO3+kU$G@5>!&V|&d@qIC z{AlkJbqCi7uX0Ys@!|x1fNL=mZlb&mr6{p1ebYOX%r+iEK=aXpxesWMx=Wvr*K29$ zA6UDrgxPd}7yxNR70`Uc1AVclK6RhntIsF%*#-J%e-C_+TZXQC&JxkoMz19gqi*6H zqWLy*Nn8i-4Dz?w3yt!`OT@H>HG3*4^^DMK?5@w$=XcTD+&^&{;~n{=KLvN>KIsX{ zGE_?c8wgrY*iA}1KjDUn6{Vl9pN0nJd>8FW7Ur`XWQFv_t*Bw@a=e4y4JmAUX%YLC zS9(7B#zDfFe*n`2SEV+o@6c)byhKrZfgwH)EhNEu5Be9n1?j6(@k2ac`3a#q?pMB;^MVpCF~-VQeXFx10w_Wp$+$@@>w| z#7h@^*H}^9;2SM>$3KM>H65PgWxPl}tLyZR=p$ZFR;!T7PF2-P>kYLqc%!ezH8d8^ zVJSMIwbV}H;bcCs)0>zT>J{lReU1C5#mnER^)M&a0VdS}eICw$blMvqo_mXJ64BG`a za(`0J@>xu6t&dWizM`cmpO^$)lHcPvb{BQQze9U2#L!mtu+jq(p5paryjeR6Os=Zh z6Db1yOJCJmXfrVE@sy3~V&ORHFCE2~fbAA9{nQ8Yv-BVS&bS2w=^@HKx)olmBE3Gd z7@d?ms0Y}?Y!g|L)8QQ*h-WKNdK@~!Y(sPW)zxOkAt4vV8sZ4ty3W?cWGVSO*nOZo#u`Z8=tX zirdm=-#+w!tE#Q?e?*^z5S?-V<{NTdQH1x2vdFkn^D0$QyjGtaqz==0^akZLkhxxx z){yzoU9XFez`A`p@Xo6-v-Kv5N$1&0OjWhId=&_kn+o}$Xa{vvx=m}`GjdGsqbj&P zJ&0O>XR8ynN_tDwSiMR5(K+ZMtWPCUUg|}CWOJzU`b?!Yqv3P@4R{#r4w4}8=5MyI znxgE(b=iK}P5*rC608&_?NT-yn&IY<$=DDWnZL+(#eouG^o!~T+Q8oSeO7M?E6HX# zS$W6YrVYwl=r*rRb=A_Kvl(eMv7K$CrNOfv#RBnJ9S?iBl8_>`hH3|tA_rQ?hU>@V zcChU$NnKTfkjzdeeMyA&6<0-{rTf^yz0*c{$}2Wt$NZ8r)o-}GHVjCQGw8ACoXo&{ z?bI?Lv8g_!H<(~g)~5KjJ!*W?qDonYAQP-NrPekN8J=-*5xO;!-UIv0v$LN@-;& zyO(ikGf01GCS>q_!?&1`Xr$Ul?T7Y2c8mmBOG$J;R9daz@1lLa^Bk}COP*dXSsKGy0eP&in)HswDXo@v(!MbgI0{$O7(+2IJ}Iqr6c2 zfKTIK$VYz4K42PaJ>=i=5jq7Q)1Tu9z;@XrC8EJht`<+lX}q>UH(;7tquio~an-0u z-ymwRu%6ngoYbbHQd%QoWwWSY?Hs*R|5uGyuc4xRKW&2Ifpn=qo!u`uuMgmllB+HOcb zIY2?WsJsFc+AIHDGLCJ|ZUjQ90nOB%q#-WJ`eD_463Dd}l5L{sT>Kj{KHjQ}$Y5Mxb`Ihu!E6je}zfhdl8yz=KZJKB&v}g`jRg#tS57wbhD2 z=4mw?icV>#^ttG+-jQ^H5qAalR$Hm6_z)GTe~09-9oj{5LhFMZ_yL|kz0w#^37V0% zRB5^t>IoEq$J8;UlU|mtik_=ylv%(5q#*^%26-x0xbL9Q(H-gju!pQc7D7&1yj~8{ zSQY9YZ8511$xo5c&-4vkS(`w~_>3^M4D!`}010$9%(vfg627h1S1u_h^r5%_5@Kti zD%3A^DOslXfl=}q5?)?HlFSmSG_H)#1D|P%UVz%u>(FNqRu*eDAqQbQYKJXornaBl z27b*+;A&q2YULxflj71l(rMImEd$uz^MOwuK(ED(G#}|iJ;xW(TYUiJ7O$rSeHFQ( z9{>i{E>vCnspe|uAZ@NMS_8!3dXPUhNWY~m1nw#1`jDYiE?TYE*Ka~L(>zi|{|8^k zarzAHyUqh;>!Q9GT}JDuGuk%DPMbwuY1JTgai!j$WRi)H-_;TlsBh?fAldtvo<-am zC=HMV;fH9KA_(|N&l?*^&Mz0{!ZeRg~X@#hEhZ`$gL{} zpDa>}%vMj4C3-pShtd@|fs*!C{Q_Byla)SdwDwpB>aHRyF10VIuVkrrfC~NquEZRz zA1DZW^c)}-J0QKk0j`gANGz>Quce=}Iyakb#wIZxxcXcxwj#&ysxVkw48)7ZY$r&^ zzsR?Qx$Q8Q#|;J+?JmeDJjgcXigQ+OC^HAkaR1+<55R=J327pK5u2K%#L6Nh(cbf) z_Uv}g^X&Ib@eoIf-CQuT;I5-&K?8eyetLdy`yhL=y%mr`0vsl1lDnj5ms@tP^evKC zE3u>}B!!)Xdp(0$%C#0G(P|uHykvZ2O0;AIp0n<=h6Xhax^L}i9b|18G&U&HdM|KH zV6A`#mR;tzrkSQoMwg)iP$F83pMVJ1o_oMWa4(oOY+be@TZ*}WKjZVL2kwMxQsuOF z${k4U{7-44%#><+vYZRtS6q~%HgG{9WaG>O~kWz3~-Vr6+SYgk$1L@r2mN*xr<4-fy;9-kJr= zEwf_!ZQ5;WYW`^!%x@qGe}=e0{3-kp%NgvV$?zVSKHY>Xz}6~i+-NeJ<{76M5)3m; z^~@gA3sZ`*lKCIgX;U-PKZdr#0j4srCmz$CXvo$hef+!K-<*q`?Of9x2OanGkLA?P zj7a}Cy-h}i%;H(^GOMMxNefGh$Q+TmKWj)%yS%RX@9k}!Z(I%B?LD>pEtSFKmEH{f zgBLL!nEh-Yu7qGWTr}-72bs*qna1v>I;O#<3&!Kd5To00%FqI2-miQ$p|X&{FXEr_ z5ztsV;5*iYfI9&v11<&j4@|NQ zHq8=>vMp#28iS_kkJLNTQFntvPD_3fpqypotjpSx{ynv7>g|-^w7|6dvs%zm01kpI*k;dP_`>{yTCz@&%sHUci{hVOlaL*~wf}p{p1V1yZD6tSj~v8VD+Xi0{qcfIZztPUZ-|O)!W>#2F%M=x#V}sAr0`>h*whW+vT?kqde9*c%V1jwPLFFP)dzejnkg7@tU#ja& z{=S@;oK;!HvQYYt^bV=P$?cL3CY(-unOHR?J=vEuAgO6`OltS^$jqF~0omtsisjF; zk9BNu_4W3ZzCwQU6ZJA#LQSJvaNYShU{p*4rj-GX?3$sqA=ltAR5C<~>HJjThfqtL z2ZWzQ?m5Rn{`6xmj(g8<75f@u4L=NnjZaLRrA}a1>-wNG!C|)G(5|88u(&W^c*#g1 z@_NL<@IB$p!-s^94oL_K3u7!(ILNTy@EJaVhK<51{x&xdGPF7FH(MQ&P^UA5E}${c zQd)4E`R;;Guo+ew2bynKdId5;jY78CEMeC0N)gQ?M@Jf>CPpodniq8-x=N9|Q5_>T z*hYqA1>X*_2Mq`qXxPZDLUwhf)Wp}#yVAMKo|(Nb{X){mgowoO#G`*E$DfXij*I)5 z@$<;f^KsAOzW$C(7@Bw?sUUf2de5u{If=Qo@{NvIAZrenE2(x;m->Zf(lubl{7c+x z*afUP8$1mW#(T#7Ky++x@Qb^IX>cwyP%K6;?SLY~(X$|pc@`w-%eWV)zjv8kK(!n# zzA|(%#aN~UjJB2x&JO7x8W0v1aXSJ>t%!OaH9ER_^w{Y0QOBYhM7D@n9Tpt=F=T&G ze!z9pOQ8&VT<@xulJ5JE=VQT{+{&5r)1D-sNQzC|ozU}7a(ut|;c=CIRr@vK*YEfb zzegsh3Eh)YlBcCT%h;FIEoVqx%YyUH9Uj5IOE#$zd96P{>*$(nGroyh4c84T z3}p=kVhQnw*hd^9Ch;%WxlAW|15g=y(m6O9^3!uE8udm;aTWS+rXt&x+rqaJQ-HVj z!ZJOuS6Hg77-To=3OXkJYo+-_f>Llj!w!_Y#`go}!a1?4p^4#( zcwg)5$UChN}ncyn~R0yc_R=yHgwTl{*8;pg$b}nc$n)vs@YBm-yUp+;qY6 zDNwWa37#2JE_6`X)bJA#@9?xf*+l``!TWFiP78GjkQtJMXgfx!yb{OcGLrV&WI! zxNx1{#|MC7n95#aJG1+N7gHUWLtF7a{2spmm1`p1oH@scK!eGu@fBvzz41&KqnO9H*U;?ljK`-#7mV`Mq+8__VT6&3TQM0gw6#9nAD%t}z|h z@$4eVBLBg>g^YHF^}yH8F^`yRAW*z!OLLbXZ$6%XC2SX$8zvaLm|B?`i!tD3z~DeN zaJIF6(2JmQ!PkO4!A(Q@hYSqa9nw4`CS*WJbjao4A3=tox>ie|H6Y#Gz*NgnQYgdK zW}qsf$7mBl+uHB1=WXoXYr3{UoPq-kSVm`$xxI7wPUlAq0Q;2MX4$ z)-plJn+&f72ltj)i4D|E zG8OjgKfDXv4V}dPG|!oXvMXnmEjXKZfrnNFDpSonZ<0qX-T)?3!mK}CZP1{V*x zAJWJ6!sf79Lo0?h4o$ONwSBQowH*tY6x=3Aur3RzV0mJ)8C!@$_^E6c*pb@wA}|6o z{4cya-7}qA3x4GX=Z(uzvd(4>%V?iIAZ$sy{L2CZByi>Usa~@?UWmU<#lsPK1YGzPoiOkxW>oV<`!?OajUu3_@apWfF z8SGUHIy+7}ce{SOMQ=x6D}P<7mAnVE%K^X*$55-E4}2aSje?ncC>;eWhvq=t7|3OE z?P0aO8`iQ<#L=+!*ltWQjxyz$)|o$=OIxN{K3a+dOb)mZ;0-7eI5O}+;Fmzr8e}bL zZE0n#=L6>l#svNhr~?G^j+Tk$`KG2u9mwf-`EA?)HjH_L=OQC@S!+ffD3j$HQkw6! zce!W2dxmSF^Qhxtfy>^?elEXhern#zyy1D>^Lplu$lH?lC$Cff>-@g<6#JHfS`OOz z&bisO!QIDG#rws(+Be%DCOM=%@_OZOl_G0NI_#=h$n&lRxy`*n=V=P`hTe1n-3(}F zF>F3NpECpVwiwV&Mc6&nH9Rqtg>&>9dzdbncyl}RRkLbtW*KDZYw2f+u?(@SvrMqG zx0o#X=7Z)C^8whUq#L^$cN?5ysMt)H45Z90>?~#>y#=pB^P!?X1kP@NI#*dB50(b_ z7yF)gB~LxiO1IlJ*+rbwot2%Lj#rK?jzx}Lj$@89jyOjJ=MLvLXJ^+r7v&!6zU}Vs z$@HxDmh}DO%k_2hzw-B#zDhB2oZMddtn^S*)tMxltk#J3uO0)Gp;5p9*nn#SL#rRm zliPra^c>doKY_#hMHnjn5_=iW0vRjJI0aUaIYy(YwW+_Ui>aZhfk`yEjZa|5wHnUH zZ5UxN166w!+^tnYgm9BD!k+?OVk>qb^M`H>oT7AK#I1%TWRpHZizR7lC3U+J56r>? zl2z*Lzu~LkyXGC}wRn$vdU%}fSMHJSF7A5nTJARP(e5$-``mUvb*H;oPgl=-PY3S} zZ?JEU&*Y!#cLMn#OIiS2gg{_f^d@eYB`d=CTmy58jCSERbQ(R6p@Ev>XQyyRelGum zFAHS24?=+0P#g@iA}{_Bb_iXCx*UqHr=%jZ?ZSZ{%9?f6^4Gq?81- zzB2xF-(%kbUp=4ISJEeWnZ>XdH8b%*HR}RYvrl*}aLqV; z4c5?p@bnCUtjzU#S^Wj5ueG%#G8^c>ztltOU^Pm80jlI^rJP~_w(}*RHSCZ#$t$4J zzf#^WACOPT*FbwkO1M%>8LONG9!_O-w7NyTrv{K7WGl%ajkIaNph*Vu%t%N=Oog1; z36O1`1KgiUK$?1oERfGX0dD~n;W^MaRnUY~Y@n6Giaik6>e3B>fK?IxgwralCeP!o zuu5Kr`vP-A1qI8C-lDB&B@h5c11HT4$@ecILw*vZjfR0=={cxb%OL@~F!%euwnZBb zl#HfYQ4MLCNx0acF6ZH2U($`APsc`b&k3R3F028Kkz6B$P49x>(>rAC%sWe zATd+}9z${XT2=Uz0}enD6bQVpL@F87ya$kne-(%o%OHJyD)^$cAwCqT|njQri z=gsxbknrCXlEf!Mn)OQ1MGrta_)$n(d<$N&Kj1cF{^yx1%>J?b&$nHe=851p7xr5f zp^E=6@2W6)w(9?~qe}kI>0RgxFLZ~8!FNT13$8E&w9xl#2aUNfThajzvBKopLSL;4 zSE|r!mkGb`2PCn0!J(E1?zciuWTEr3F#WU8FISkETIhN#bQ2b4I2QJSAh?r0aD@GT z=4hd_^Z$LFnUJ7Zs1FxHg=vz7x!X5k#NC7(&BNe(y9i_9K4ggQ zhqUcAkiEVLM#fIa5?=&=TMtR}g&Ev;;8U1B{{V6~AHcu717AA{j=5X#)!XnX%&jcU zD}4`V5eL8RGo&}ZfV*-5e)@4p_I&ZbG|0mA&sT7k>2MzZ?5e!*WYQlHecXp z{R#g}YH7GNt!GYH@QIYpL*kJK?$yhdUXphmmdGSNSjPMb!Iv51FsDkeZOY z>T+!kB%{uSn%*F)Hh##IrZaI-+#1h>O3rp_53RC-aGJNW>ww-A58UL1Kn}{M0#GI$ z&J=@sKp8X#oMunScG3|v{c~Dpy^L0!EYoaI8MvZ&)xO$F(nae_4MAD(%nimL(Kmga z){Alg>Ekv!3$(|Jcr?43t_wcII9!hzgj$13Z7a}F63`b)KnjY+|AI5?AU*}&$ff8U z{SB|7&Y;b7EKmn`pg>>;E?!q8_iPjpy4sY&vb*K#|hp~{dl zqzO=P8bK2KVt8Ux^!HR}AS@q159rCPjcdw<@n`wVd~;!!sEQiAon`}@HQiXrq=Bw; z-0;p&3wW#(g{S;qTo!Pno--|gD_(-y2K&Tja)z&{Zz-%C{|T#mN|hwN+fXXVYy zy`A$bCnwjMpOD|#{=t6Ge#)L@|4Xg6+y%i?-?CvE|R&Of*$ zZVU50!Xhn!_A!NV^Mg$OfGa^0Z0EukgpUrb47%X%(0jILA$LP&+QtUYhoiPx|2ECw zCgQWyZLNpumX9eX{6D=5oV5!6CHGRE#oo%X z%{9(jQJNy>D*5UTZ8ALLqhL;L0Myt0^lqjZdz+a={|$StkHGYdMWx}n*$OH87m!U#w~5jL>#rFT#6;bqq@ieP~+}WDG1D@ZR)^AC7mE zQnJxUyQ7^k&T_7FN4vb>tfv`q>9x}Pr)^E&kTEi&UuJYpQXXU9V*k4!zu;B@a@gFn z{4u~yU#bn#E5jSP9#lnF!_~rw!zbtj;4ijhl4%Dxbd!N=bP858Enu!~2=miwe1_i6 z&gFB2%Ek~&iJ<1ToskVoSV})BVTe8znHn)Hf(^eC+Rzqd9UrjCvetY<97q47Wk~P5 zJ)B?j2j`W}cjhh1X_T3h7N1%%H9W0Cdc|}{>h-kv%$2!qK^s8MeXhH%H?Gs3DgK(u zd@@3R4Qq@PlmS)x+ssyDS$}j*0r2w3e?|{hXM8BCh zZi09mnDUOG`k_Oj78LJZ>UhbzMO#FfBZo%RkH`s|5q2(kQ@{qZ!I&@DFh`PnOWpGv z(Rq7w)a-t_y|VXbtWNEmq9m{_ADVzKFroY! zag_0?B`s)aSo!E3#V?jQQg(f*x6zlv_eD&OFh%sX^@BD)lSMN0;9Yc(w%#|z;md!O zBV?7!sF`^xt5wF8lnbD1-bzGCPm&v^zE7K* zUt}Fz2pbD?$!^g0>N5iv2NTQEY!WEUP3aYQ04fdsZxz;BC8+1%=<-11rTkz;L>uto}ge&Ut=%yZPTsJC#8M`Ze%5whhol zUvSGf4c=n|xf4t%lS+4IqS@AP9h=e5(H2T{xdBqo%{#o{I$z##m!~cW@h8GRxY?}3s<))#46PaK=T{`OeFMmu<&CD`sCsQt` z-bg#1S}Un{!qPvfe~u+QO6r{|rnk?$mNUZM(mB*U-0Sigq}Ot+dR-Gy9v#B}4b_*_-PN%oyib&D-=!sfKaNCT7)qzb?Q8|)`z25#{0Z*YO2|vs;gf_gaTb4p zi)X8HQ(@=&5E#Xq`AJ+;wkjemvzp#N7N! zX`H+R&%eGL$*n%s|HAp;s9z@hEt;Sf z!3*KS1gO;g5kn0ILr?LF&{K%yd2Rypl#ZlB=@P&VUPJF^{$pwWJHK6AYC?h4LN0`j ziW*t;Uhx;jnIhN1<3n12V!uB4ThQ)+9j0l*l|qe|l#s$*?!4JK-!cznluK`wUOv58 z+O_23Ni!3EKnUgg#DLU*^f{SDvybJjg&JzMtF7mgFBaA|-AQYzICGKn^LvDuVmtAU zu!essToj3zB(4xI8pev(g<||KZYezD+nAQXG#*Od0M2nEHh?cBz~DBP3wRWC-$sYG zhzu%nwpjIITcSFL{ueaJY7hJ`uxCJ&`Lal{Q_&1Uq${4@1z+=iX3xzkNN=7-Qg1=f z5|=V7>1N`&1Xsd?Bq4QhM*Zv|xt;T4>?a(Yd%U-a6bRLiGdhE(F<;pK_z3a5=oPDr ztqlpFzJ?eY8Ri+zfdckHye!rhuY&)gHjs3m(Z@iUe#jWP+5Am$i}9%Walpl(y0&&< zEh5@QZzwV{8ih>`dT1GL9t!$;S91$vOYRMRqs@Z;hrzBU1vTM)w>N8M#-#L+bSC{` z+Tqk~DZZoyiSdcvWLH{;tgAUi@|)U^7ff{iav8l1{T-AeWQM*Cm4&M3Yi_sj21E|Z%GlnA zU5xZcpN<+HzA?B>U^jEHIT3sjy^I@pky(hUXiwxQuLM=4LwQ4Ur)U4koR`r${dF3b zK0WPL%AKV1iB*$xQYvIj&T5oD3{Ch%I*$s_rpfW%`>r9*?FHZSyXR(Sf5|$W*(Y;E z#>wf!W{92agb%HwQKO05IUqn z$f1z^AyV)x>xh5|^BmJC(*hG`(#0h10^JpMj1Se>a*D5)caD3TE6uUNUOso8yo{%qdhNtr=+?{Z*`ZtnAFjL9R@Y| zQ@A-W=g%@{K>H8om+|ZP=KNl$Ys}>w+#66@ZwmhiZ$M9;4Oe=JahADSz}3JN)}BE# zgNg-}wl=cv)gd4-k7{qK1%g{TRcPDms~ZRwH)IM z9)SO+Y~J=fKF;3h1>GG3oEBFF*Dlu%*IxHu-s%3?az~}8T3_7* z%;s#;K`%;uKvudGGl-32A8_Y6mao8H;u{H}!f@e+uu(i`C}%or-fTH%DR1dxUSoc3 zSs1w2x-95NP`RMlfr`azX&taQptt3lFX?W-_%=jW&a`1RQG;& zMbAff5qE3XZ09nEqu@b7lLF2D!Yj-fOjuDP{$9reGE8ktzo91ok z>*{m+YD-0wC+aNirT&4+2YvSxy?|NBj^zAML+&ZG5(~tC3_XmR@w;iF`KkFI^K^58 z`GRF-z@)(1)_d0R)|!D6EniGCOpk+1l!@sg?R;Vpotd zM}8_*kYfCzZ<4pX_b=}eZR(bUx8;I>&SF$advTCa;)m40hvKIL3hi zLj&BFvz7yv#g@C4r*HDW9eLI;fQIq7k(rMo_&T$TRCA*h-fB33N-DR_KL@BR^KpmtP6@!a2huE2%lbg z(?-)8Q!A6xcoOvg`o@8VDxwVW2R&h4r~#Du65MSjls=0}05vxRoH81_oFC4QWkc~{ zeHyWle)=^!oVN;@oXoVq%fb0r11cZyKs$Lxt^=bvNNp?k@-Oy&bPse*cJ_2$agK9Y z+|%5{-HTi^oi7~U9mkyI+-1BS{C~?;K^vb>PLO=EPdld(F%S1C}+ z_x1B;xnH=tx=y;9xuZSto-y7JFoHY!{`gM%cS&{SyK)`H2i4E5HEs2j6j`3gE1jYm{%1_y*ypO-e#lvbM1P##+sX1Bsx@+>^xMs6q2!z(d9 zpcoHCcVG_|0xFdX9n9^tIOU0SMG|4;`qVV?id0jvyuyFMH_n&t>n;tG%P3h&l2THM zmfJ{_^xgkh8lzMp)u2;!k5-oyS5GRe`Uh&!JN4DTIvo!h_hRthmH@4^E9Ihwp*U0q zuK5NO1V{W=!-$0y@M-KpZE-np9lgPSF>~2! z>}sYajHwPl`96n@%tW>u*M_J0viu76ExiOsK|N&+K1BBhB}r#(tc=R(J=E38K_yOo zrKx&z=$Tg4ck&desqbI!6W?)Zv(i$ntAty(7KTeQl+-imHAgJ4vj%3tX-x zpqeyZZK8?501iN(p=J=J|Eqn~N*2}(V6I;aeyBL8wAF>?wk}i>wFvdaKj4`i51y}J z{5Mp=zB40XY*(RmptX;nYr!u04^(W^+3(^~tjlY`_9@@K^Xb;Xlvf5j#z`G5L*Nay8oDmYTf za{_WKsj0e^vg$0=MB<66T?X#2iF&KW5u3I^YpFK?X0L!mQ2t&*AN?Txm_CvE2Mwe5 zK_Ai)d>_q)&hnZlmKnxXWM%p~Gl`jpN1$SKQ*h{=W9G3B83#>cJ0;*O825fOAGZb{ zc`xXOS&u5~&$U-T61S5wpz_z#JU~$YMQUjSfg3*&_}X!xN0%jI)lRAr$m3S1UwtC+ zs(}P*-AE&Kyqd3mQ!~hW@R7gPmTAFSC^<+@YNhlmK)!AYbiUI-yIurY0Slm>a~hQJ z=J*SoTOL&cRC_Ou28BEu)Yl_GN$-VX!6S7G@5R;VZMZrxo1>ry$qV{Tar_V{;~LZ+ zy6cyy8}Pg?q@odxUgf8^rybNEQG=i}4En)=3eQ0geIx2V5Wn{Tjq@T@Eu3&y zpHWq?6;Fgd@#9c6D@WtS@&2Hn35DDV@o4OW0_G){Z3 zpFlf6(VfrE#1ypyYJbnk8q$#>bXT@N9tcSU7xYO`)oiRy&}dlYe*hz$?f1bfXpzWbvii z54AaYL2URBJCD`$7UZV-NwKT@^}DzTtt}JCPA+2h)lgpj;=9VMWmodcdwz#k3;Q zZ_gnrO#DyaaCL|dF)2s94^@IovjV=2RmMtpRgq_dv>W}zM_CWI1r3I3*l;DwTV1_N zZ$c@07(JM8!tT>D)N0ZWIb2_XYQbA(m0lag;L<2Vt*^xEMd4ZOMcu*Ypx=gr_xgA; zT-~N7P(46{G1Cp1?f4ijOl|onnLGjNQ96}w#vT@yahP6Yi%pN9IewRsx$q8daV3b_frAjhcz&fQnEXmY=TN% z0K46^gP$y^vaBzZvfLJmH-BgEYgO?cs)iy;pY-l%yjq%SBrX(cQ%k_n(nqT8%_M2e zb$lGZ6Nekz`g+eA&wl>~b(MY}ui=(KG-EyJE^n^P_C1xFQyXBOstLUzJJ1X27C2K* zt2Q+jRt;~}PN*n%j6Ohp#F*)$zwvqe<;iHxK~LrDK(;`2?FXu@ManYC(Vsy#=NfFM z+vv15kV=4_L>irv74;a|1pbGIxUKMvE{9$~7tT@nqC6WBJcPQh8KLJY5RFz!kcG&A z%b@_hCDeM~>Z{e4Y5~kv)AS#Z_2H!!K|V@->XLR%E2h;V&9(BdYk0@l!N0+fC*IM% zNO=(Tk!ddULPA_JsuqO0dek*PBkM(Ei8#%8yk~>Y`z+*^| zf2_wX-O%SS1$;;0D!UXnQHOf(deY?#Et%dZb~5nXIMP;r<`45)U6iHM%{i zAr)0hYqPaf-Gc|vEYxX_X(wS0Z3?8|Sp5yTL3Zd(QC;kS>U0p*OS_?7BZxW%`|V0F z*A1orqeiJlwW-z{envC25o&`&Vg39cDzCSf2mALabv3u13^i(oeFe4O*XkI5H_0VG zR&vQw9M1Y!CmsVGjF;uf{vp2qlt6tQm5MmF7~6;Ljq*qwxOxW3QScl%(P-G~R;63g zV^F-hQRb9kYLZ%0UyQHA8yvG!Kmm=1-mmBCKv1BsQ4i@-u)ZD0WwGDk4RoBmP_8M@ ziHu8#PmF8C7wlOSsy$M>fsN%pnL{<>GQ`=O9o3-v=)cs1a zZe=n~8tHrM6XpL%5AbyyA&fdqs_5(I->x_ztf{0*DY4RNsk$^+c7czygZ5iJqP$V! z)t*pajRvP;oR*|5r9MHG`wJQY-jrl&A2k$prN^;Z+-9Ml_!88r&3s+{DtC;pB33XY z8-5sjnnoHc8rqAQ{8R2X?5`+cC3l={%HCj((3@bdQs`CI@Ht`uoEF?q$ksn$)|1fFkB7E&~?@o$I@Z!X|^<56x>i<=>^ndSRZ7f zQK%$tMbAb^uMEDKdE|^d23Fl~e04pST?TiKGub)H)!jYJ^U)LFdGGWW47H!he`DY7 zh&uuJJrD1@q~TlGAxJft%@sK)3ata>l&W%MSn$K64-!vE0eOaVKGd(YYUA^dGV zKv*Me0F7pauwCdPyybJjwcVK=!1Sj3nJ9FXwopn+!+1bt2$6XVAmQ5hTVZHoBW%O34G#$!z zbaDsJWP|M)?!KZ>-26qTrU@aDS-}2K`-MC3y!tY}bKtDIpGl)eU zD)*P{zLVY#p33g(t{djM(QtDfK|Y3tv2-;IqAUvW9clwq`10nUGCjI zKKS77K>`F1?jGDFxCIOD7ThJcy9IZ5cZczImy*6~zW=5l2qZI5a_ZDMd$08_?g8HX z@lq9eAI9hb(+yKeb1%~oWuQDrx+kP_o0#&{$Y>jFakxaVq;G?Zu|Ln+mC+z=cjHaUC*!H(D-rA!XG#lPJET*NS>Cf zZ0<3+@8{NYZ_G{QE}YAfTr@E&Zg9*p_^xX3H<@bG*60y^w|Xb+3l<9I3RVxi^oG)_YQb{CU2(abs@#Sf@3Sf1{MuaGa?297bdGUa3Y%%= zt2mZ#&a5I*^ey4Beu!S|JG1^yAN(`Vw|rl2eERXR+sE{ecRs~`Y4UaL_lBvT)8A#y zu(fdY@x}&AsZFDe>9bsxw84BnwphaRq@TIQ=6Rm?QN9-Wlk>asb;#E+@0Z+Ta$QL} zo6sUI+cL)VNQ&}Z*fUfm;-r3DHAnsp^$ZpcT=aMGzw}=S6bgC*TLagF9mA*5DTu>U zG?{t89Th%EgOqGj56kkHezB+FfxH$|G^Vblx%r|pULGr!<#V(1DSvd8HZ$BLaK|&; zDcYW9{+q`9Nc`&jSmnc<_g&r({V?a_k}oOW^Q896NXu^Sxaq3kD;wMpnX6wXaxorm zh%~@-D5ex@&F_-S=f08qRqkuK|H-vGxp-3D#F6pSV;vUOJV)t+ih6B+H|wYCQy+*@ zQMcY&o2%;3DNc{fj|3wf)%JKN?l$aLMdhKR^cZ#Vw9<9`uC&6#@oV`r{L7p>KYY)TSgY|sR-3Og*?XoG?a&tu=NVByGHtzL8>8NeBfb zGwLQaxfoPxo501kNn9({lp7G*8Ce?8WvLE}v(m|3Hw5 z?9%FC_YhD1N5wKG_88~jO=3A|nEbnPNl7vNZE9_DE3=jFa#(sIJ`p^8VSW^MhrPsR zVJ=B$53u>!zo9rS#@u3_Ggp~8Om*gWrYQb>nkmOVM@_#iZx&L8eqtkul+VjGl;O(1 zN+~5EZ<0CLESW`0_>b$u3d}mHAh|Qz(zvPpq3Yp@p$~x+|90<3x6A3bzlC~V&oHN- zN-dIF2#Wm;X<6xgGylk5Vq5RfUBkSe{BMKH!(*Xm--5a!6172p%c6eJ_nC>9ReSI{ zuL@hlUeaRex@3hHu!MA6oF>*4t-@BJlJJeM!-p{U?&J=0N8nGG&$Zz4aEIVpsL7VV z`d}7YguBeu<6rRWg`T1re@dEELp~%|QKl*TmE|~_RdSrXKsqRv5WaASp^|<~rGQWN zAKu%)W3@3mFvmB{)7N#&@wloFo97c-8pjJhez99(XGD*uDe50A_}VH{ivb)-AeWZ8o`^?_2& z)W}r8^i&zGM4?A3D+%If+~wCyb@~ih1wQ=@t(AH)OoWODru!ax3>V?7Yu{?MW_8M} zp0PW9eEN*^OX(>YbD_6coyA(G+jz%vXEFC}&stygz>wg}Q0d4(b-1=se~lGdkZ4NH zrn}?Lyu)+T0oU`SR8d|pmsE}^ca)pT5~YE%S++|ZrCsRtZW5{pr}&0^7)thi+;dLk zoA9&vb9_bNrZ7ship`|cQXe^0?xI{&%%*;(fu>QWsisb*RE)EW@-u0NI7BGLUtnu8 z+o&K>4=b%(s9A-AzXaC%LY{W+dCnX5y0*;hgIUKif6FYJX=MD!@MW~k^k)9ZinETg z?Xo{|6mu`_RJhj>tpRK$W0tbPJJ1mPE}t9o?YOsFf?|NuLwjNc*6& z{|xV}AV;L9(r#%UI;@XGtP!yCS_?wdK~I$})%$9*Nd z=iKXD*PY)SkKySrWV>SRZ7pUMt)!K=*0j#Fezn%OJ-1D@mvDS>taIWk;mzsd&E+fP zZxPrM^uVpSPQ9Wr#$VAaq5-v^)|s+g4Zf0K5)X-$rBhNRd82H>%DA;sSxHe!Vg@R% zBr8cuS*4XSNjVG0TRGEM(*si(^HB40+==^Ur`c!zXr5_K!P~EdX{z#EHp@KvtNZzl zTo+cQA3zs74ouIw`V939*7W%UTYYuCjK}W^IlnvJ*$dlG+v?cfSQlB_TI*ZKS>IY& zTWi}@TW`B=-|A@ZOmT%>uiTeC2fgQg5B;A4fnajDY^1U}OCv$#z#g3BP_1aow#7V} zAXtS{Vo%JX9dRCyWLl}BG{=$uhI1*abW&zvCU}o?sAQUGdTfd@|88DkPBj;{G_?F` zNwj2{&zZYpMCCS>RLaO5rCH)%LVo@+MpO^lLOmqfM5pU}R8P2Us6k+}ue-OAr-8eq zOK{4L?)G%sTw5humi3(VzLmiF^n<>#oc%QvtAm_==X_T+x7Yo^bIiNZx7L3gv+%{x zr*Lt#mDWi=WE3VwqONq3zQbH$_j6nMr9yi#B2JS&V)pt+z9(nOypkVhkPq~NE=pI- zr8|{$rKD-J>6q!GDZ$*$yaau~47kB^?!*eSY#xNslt*bMHJuTj9|TjnkAiMZZ4e>kc*4%qY9x7*s;D%gtPOj_GU+V0v0*y9}kK?Ce? zE_NlkAGwcu)_HsSiu&^heht=!s8Rt%5&wbqABG~!%as`*`{Q3ZnI#HnyjX~rWvNf zrsGPS(pv5-4HqW}^Z2#gQFbAdpPq_}s7p`L21ee5Mh8uSHNFJzRreX!GbitC=h$Qy z?3Zl2ZR>2)@i}Mv#s0=V1g@@f&O6T4=odHh*l-5DeZTvw2TBD^p>RlwbXRX_0_yL* zK?JQvQFJUb2y2xU=wq%F%875Gt4Ng^qkpN&m6W#180;A*;VHkUe8A_q@=8flQZc6N zN-?;)8kw3wvC`F4#Pmg3sgzR=%0=Zx(hc#azzP-k23#z=g0_?OiFw8o)Zk8q6QOW; z?VINP!_(B=-qqdN!?DBO+Fr!|$~Mb3%C^Y%)i%a%*gHF}INCUM=QGz1cYjZ;_pA4X z@0@>iU{-JxdJJPDXVoAou?=w#W`VeJm_CR;*&c2oR3VIbKrAh7lT4UdPsm?nMk%7y z#`|lh@>I#hY*ZLWJP<3f$)?$+&88!!rKUe{7L`l}TxtUqO&%&=lVqv4cv^_^RrxX; z%U-1GVO4m?C1b@xAs+j+KsN zT>rVQ*6tL~6ZDYdeGcC@|J}g3;I7b2=%P2P_t1@aW_*e|2p`GQRhbrSLG)rTpes3E z%q8u>J7S`IS5C%kx)|%CM;JBbz~$(OYyFpLfoYLxnQ5nKn`x%0i>Z~VhKVxWS2io{ zm6viYd9CzC{7t+g)D&9t3EWTSD4mZ&=iZ3Z52}?Tn?p=+sGs(I@Z57>c3p73aTIf0 zwhzYfAIA(7WB(Ic>AsFs$6wAGu2}as_X*ErZzRm%| z{VSk$I)_?84`Y5|IqoZWmfs?bff}l@v{qt3A9*L|#?!k9?}w*~p%gL|GR2yTo7$Vk zm`0fTW7M?8IaM;5OwaK4XsW!BD`4!X;zF^ExKp^mFXn!SN@5kI5u>7vu|i|i;o*xK8gIeVnAcv=KHaY3UAEbg+nMgna9we?_T2T%_0IB5_xFH4 z;Zm@F=(li_NDp+|OmH*)G~la2CHpb82@cd0xYIRmC!YkRUI$SX$4Yml{PJx1Dc*2X zL2fy%99Lc_is@JE7zUX7n!1^K;nTvD%k*A3qAb93eiQ4~cG4Sh3DgVAgr$6I&dF?} zt5Aa0lm3)q zrQ2dp@E$d+;Lowum{U|Okc0oh{Mj3O^kSjafeQZn-u|BA?%!Q&ooSBW97pW+?Zx3H zJ!voI*yxCHo^l>=-E^<^{PMpiHq-wta0rz)HFPGtE3!*n2PI9CanYC(9ZGaZSN}XU zgYLx?XYK4pE|%}WUxxBDMLZ0WOA~1Y)_mpUQSh8!ke|avS^_KCUzNgmFPoJF%#$|w zD@V(nLlH-J9v2#3T`lFuf-aWpRs6V6z-Jvv8tj4J2 zwOqOmGSi=^w}YV*2ao3l@doCesqn?$mF`PF zB}pzPw~?F3xnu^slw`1(E=mh=c6qToIxRL59|$vr?m`jaBwv6Z!i{CCFrTT-Fxx2+xs??t~iTIXK1Nv43(Gx%Y?_8OmqyHL&_$ zESwj<302_*+91w>S9QJkP;}!d{*E=?5`4B|PU#?)#;3d}if>Q}8~_zaU!ja}n{SNW z*>CJu`VMs;EbQdyJghw%M^0hH4EC?^hTT700jCOTR0aE7TW8x++e2Gv`)&I_jxNs5 zuC4CZp6}kW{_BB8p^f2hk$9~xIC690upL8oqDs{|;vd&4D^lVV!eNcQtkncO0{G_WQOE zHao8S8T$-JU*`CB)OHWn1~{sCgdc{{wemFOFjZ-wIzfk)Os7=Lh58EAW3FfGu?bx@=Nt zE=&RUxq^B9iQeDcmz--HEA69g zgRF0|A7#g3&yo)-{G0Z|&JV6Np3=Vk{zkz<;RN-i*1(vG`a~v~m#zdI&vrJ3n+YaV zdmPaaFrxmzkET%Ry@lhK@1 zMa3x?Jtd@#l2_93B%B88C>3wyJknp{ZebQE0$Ujud<2QnN_sB!VrWrdpYNn+yX(E< zFMCVdAJ!w;#k1dLS+cKWpRhiGqinXbgq!q=elqwtv@FtB`^9)2EdsSk1DaZ4bv0j)wWeF$s8Rq@jQ(aY#j`1F9Aw+PhDd+GO3GyM$>O@Gz~#@7i>;z#mU%=QW5 zpO`TNVi)PQR1#|0$?|R4q~uaQ%Uk9Ca(?+%&TJ&!7mn~{xyhg(Tq6#nLN_|Xgbw@n zf_yO7xze7;mX__$nwV8QD>Ji9mYx;Ku4emaKkl6E-s}y5F;+ZMTq|#=(OqOIdMMKr zN6?kq0%phrElReJ1z;Vh& zde`{dgg!(h-5m83m#JFJpKKM3&*R)lZYfuiTfiP{ zhtsw>Jk$@#hggqQNA*$WzHoEEV>l;N5pRiIK_K%=b?`n7$~Bdt$|mI&!u&vf1awi$;L{M;N=zBL0n}-ekY`aY z`pKAO3^O)>DA5`@9$P?ZOoa340X>H)!+v7_ff{%@@8?GduTgF2h`LF#G!)Mw_7}%!` zlx&aC4|hQE^OvFNeym}d8rzJ#$ii4f{6)5*iqJplonT-@pa;FcdBHg9&Cf->@F@R^ zH~3D%C80e005!2QydW8vEA1mQ9w8mRgpp<_yzJrJ?kdpU-}vo<&z{mBTCj z?LBjy*KOCb8fPp{>z(@M=b@jse%47{leQ=$Eo+1=uk)$~;0g3IcEagC3>xvfL=IKd2e)H!W;c@`^Whl0 zqlU5dQGXU$k_}<1{Ea=%wgge~4S!R3D=Mf7{%g8sK4F<3(?3>->ljxi?r3aw%pHql zUMfEmTx=ROB}!_8LR)-g+#TUcxtuvBJv}w}bNbJ1Ka*46q_#-!l6fxscYB6&fv1zd za>x~FrvDKw43+Xz`U2FM71&(tW9AR$I&_?4soP{#sGJ7CahV90d>7&lw2xMp+>DPt38hj&`W7_`jvs+CQ*Ee|(5`~93myJSo)afax_ren!g4p}b?mLU zmGOxQ{S&GrEQ6;nb>Bg3JGoEkk#Tq7q^&!7@4N|ywMHIur6e1r*9f2s#H zl$r|l*GsAp-J9M>UxR0pLZ{+8y&nGD3@EPB$Un&UNNX_>ucEi%=W9>AC3cZ#K%1Jt z3j7|Sg=A4uO`9!b>@RWc<9|u8CR9$$mADPM{GV}EV&9nuDVZY8JLp|R4gFwvTwtg7 zIYxRFYm2N$8E4bU^!aIh(;lUzrMJy|n$^Wx!`{_--%a`o1D~|F`TST zCDWVfbed%fFm;&rObez4Gz(suWEh5LzCpivnLa_UfoesdcT%mv^B4-XYDaKXhes>I zDf!CCG@61CFp2004el+v3Hyc{A(WKd@_AEx%hQ-d^eBI6tv-;+=$x@nT%w z7@ujQ{8sqPuA!PmUFy5gPycPtS!aHGRqMR0%9&(F^Yma^^Yro=$(g@qEza(2>)=@C zTJ4$dn;4iLnipxLz1NeV4(Uq{gkN|Tc!SO1UAY1_(nEMV|AWeO3$u`E$`oP(^dou+ zoezrUYScrrBUFYd#8Rk9&)`|ejVCz_AHr#)Z?qUu7*Fwex-~o~`-HYq0mX$Y&&U25 zw>|!FLjT0n#7N@(#Bzy664u0RjG19Bt!xlia1-bXM1t-NOTpZ}vhKBxH8zuVM%J** zr5P17nq<7pxB&*z*X$;?3h<+{o>$&8{=>nU;5t3j${KB;bR3P^%Q30|J(GS6-I~a# zxDOxcm-Jm+?=f_J@HZgn`&@p!bwctI7#lMkV$YJDc@)$S*2^jmMpdf!madaG>37xtK^>}GeQ$(oKencBa zuRbruykGRl?@T8w17lyrnG%YEDAqEmW0IWIJh5)V zfw*%qf0=73*F=^#F(t?$#znPW_*P&8xKs~aqnuMw3$xlb+P2z$qK1?k)!_5adoH^> zueUn(bIk(Hg1?1g!ym(g5net;)zlH%Gp&Js1EhiH=svik(}@D)O|mcbjrxsVMZcf} zbQXPtZc5*v>QdV=>dmNz9)c3|xIRd4q7T%cg1j&cxlAv~PPCV~&CL`VV79q{{_c^O zd$9-NhR1)1CllVq5076THz&4i%qsJ3<%RT4xXLYNnp0JY%EoV6KkQ6P1TXkE`u_EP z@|5xHaJO`qc2|blW25_xyN2hur=IsQv;qO&d{iJ$1zH4M!Retm=v7)rzDMS(l{Krj z5~|j(#^Pv2;sMc#dcENm8SQc0x-GyxvCLj0C$F^ytUVy;;#S;m;>mVrNHp!O`aF^ftL(tgr(nC_*T5LKK=?qG|C;}Z|G59Y|A#+5&?vAVa5IoU zI3@Tw*dTN~lqVp1EJE$Gdu4-=Wcm0fB*T^uAMOULcxdG(fH}H7I@I{5ZqF?+^>VXbWJ*+FwC|6K> z>WRAEbXk)INS8!GY=qA7I_@q=MX}g_fL=ick;JtS>!|*?K1KD7T0U*3T2Z|o=^2qD zPr{qS6O_guyEDV7~jR57%AVUmB~e0(k?qfk>gqtMHm|?{KYfzAzUK zhMXaHNDm3&#BiQ)k#PC&ui?7kCgBd@PT}t1!QoN33RA-?!h6FP@C-%6RiXDe90|Z9 zwOe}ZWT@mr-crMCWab>%%N|=^TE}@vB3es zzW6aVxFmQY_#>D%)IW4M6bZEm|BE_LN2n2F)Zw5?mC%-GcCEdBNiSh+Hex}#F%#Q~ zYUFEjGF6oRKrd&S;|^WtMxg_I1HRr=u{+kLdF1Z$GU#gd$*WO!YavVWd8v!!#%@v< z{uW$(4-m~#xFxKcX~P_*&G0(BC!1qknZv!W4T@BMypdLceR5svruo%XY8CZaWGGw> zN5h@NbodywgB3#I;LYIr;Pl{lxHkp_hX*GH7Y4TnufRK_2aAR}hNgxNK!qO{ZXKQ% zzKJKSZ{$KGRvo9lQd?+GwXS-qKE_Z$-swV6@J4l`2++;iG9G3LTL2y56!0Iz{2v%u zVK{!w;ZJx$ z29p^`ts{s9&}sc^R5u^iT)0TRz0NIjVC!&iOLYCkO;3bc1$C6B@!!1jTI?p0a=0W9(V>A}FP=+0XcVXVXwGd&HhWwPQL~`bF6^ zcqc|M#j&sXi_VX#R}acZE(crdG|`Co3{IAAtTaj)SM>InFIIv^_fQ?9<^`{9W~6RJ z4POl}!kp14Tm^Tp2xg97FgnMFH-+zDHf$H!9q}MhXqDa^dtY&v>cV-kiEISt%X;K7rh(j5 zB6`pG%P4NV)92|GK-k-&{h<}nH1!4MuDR-DFxa|cTy|Ic;Y??%Tal0OO7(!5R~Z`6 z8QLza6G%Llzv(^k{pa-ex@^=nM&l~M&0|!H4g&Y-Iv8CsL=6zl{vmD=4kAC8e&fhp zxj5juGfmU%;ic-B@BwF~%V&pb^e7pJ71` z29K1N?^xUH(KqR9!He3gAJK2>&-HI`zGTA98pJsiGJZAM;@*rj<{Dd!|BNR_I?g8s ze32U1lMjy0!u{F}0@g|JyPhMLFgMl_3qf4VB=UmK)(21d2z*A7V=zWHkf-1S)8O2a zD3WrKpUHdVS#k~jUw6!LRlubYL2Y{tX4?hg1hJb~hZ@l=Fx$F9om?Hhll*XDsoBaS)Epd8`se&ZBZ0I69C`zZnZ$fz z0gh}r^x=nyi^NlS#BL)&bPLwG%ZatbCj4qMer&|=S7UT-!q5M}M=%NOyrK9E1EZ%E zQHLlF{u_@(QxR^goE%ge_)Iw|r7p}h=-@v^!v@Z3S0tRdgxn zWQ#yr`x|SZQPCmM0dU^-MRlhi#@VpwQ0%*gf=4$BV_+`6dJDK@M{que!D+h~y$AA{ z6~wfhr0JX-*qjvU4E)Vs;h_m2yCV_ov?8c;<*?E~(ja~#nj^2X4pu*vh$>LgRw0Uk zr6z!3N8s4w@ioQaTP%dH&&hl*0$)dEjKN_|G|%GJexsfhnq0e@ye z{4FA=b2;bt4Wzl(7(4esmAi=g)Ga(GS5Y;&h~MADy?zak&iCjiP~Sd4xAz4{nvK;oZspAlm0K0IVb-&C&BwYX6#$o3Eu?A?i%WdXRr=BfV*-SsUnx~ z-yh(7?%`Y><5zd^m6vci%EW_5Y=b=OifSjGmlS zfZB`<+{%jlt{wjL=4X z5~xvrvOhEq?Wh^(czs6po{emYx2#Anr^lh{Py*~S_%7)~%owH}w1a2hRa`*3up`bz z&c@DjH0GVk@NLe(D*hW%Zdc(6-h~-v3Nf0fg;DthwUs|n&8aN@m$2Wwr4Ntl1iN9pKwqbk-0U35mzS*LUa2Xh@}B?4r; zB8EdBf_ZErD3~L_uk4A8xQ66#awb_49<-};Q|2d=z|Lk2<_3EoN~H;W6>zwlii^QM zSuPBP>h&aN7V<;uS6wGq39D>*?+;3|8&}PkZkg?=0^$?|=@Eb+14m`;|%${y*B zd=b3*TBbEnmM;^A@PDv3S&calH9~&s9Wsl*YtOJwSg5{^JPIxhjPtMc@A2LAw(+j= zTyw{{Pq{j~Mz}^nlQt1;x8NoA}9FA4L+&WNKXp$7aQWkY+n zN%okon{S&JBcY|Zl!Wg2pYm>GT?B+l+(5P%(~sG~Or~d0F61lM(0t*Okq?o4k&mIz z0Xb01HyKCX4$AwN9^Ku}GuIu)wf*XGdFT5)aONlY?fx^tE};*h*`VT`hLTHxyY#X4 zS=)n=@!6PT{0slnAgmx(V@ylvn|vdZ@s9P7jcErR!1`?o+mzkLE``2jp2R4s?8dR} zSDqA%o&Wr}B@0C~htVtRsimJY{gd3}L;CHx_z z2VVp}_}+SodS1K#aX)d@a{UBfVz#rkv$^v+y5Ps$?>(Ko-MqWJ^?bDgKf#r_9R30V zVsUs)j%o)m#?5#~?*r4d1UQ;8B#+K%F|rXl%!kOa@as9K*7N`-%5(;^^K6-ta$}5t1BT zj+ONyb{ALyoO}k#mAgtybg6hnF*mSmjZKMr6?@xK*VM*Tz`V!OFs6a!kup?TEnL8! zf)UoRGw3y>D|$yCt^SBe;pw5r{<=QiQ^VE3#X2`QUfO%vPnv$rZLLxW!M|1{^ECla509x(eEq-q4+AnHpN|$9{+#6I;V#fd;UaS+Ptq zlcwHMCGj_Om`8JoOmS*Mw5PEJ&Sy?t9Mb%oy~jN_Tzy^h!NOeVSZ8}?ZD8GPTWfC# zy}@`#!12L(#+~ea={xA(7|06#hYXL8>P4MF>iS<;o!E&8m4=o4REnp*g2tdDdF(r? z^A@TQITLHFI%H`irah%n;n^Lji5q+e;9ABKBlwccrWcD?j)g1+kYJ!e5s9SbBl-axG??xrez? z%)!`%_~Hoz66(c`w(Ky~fkJD&GE?3o#_%?JBsG%wFKX3-V6;E<*YF#jm+q;qpHMEP z*xp-@TMuWaSS{Ap*3;H3+XMSQ&KTD)&l~Sx|LUMW_$)kIT@Mf610=b9AW3>ET?&-I zBTRelEuOP3bd=mreT5n*7kMDs1q{{&=xSauX6hN*cVjmBjM~F!Y-2uNe9BD+8FH`b zOMJVeT8UE=YRCMCtdJ*h)sx#HQACM5V`(V&fQsTP@>fdpljyHT0lg6VmjPsltnkqu zvul7OWSeTeop~D>NSm@L>tt&#+wSaX)|b}Bj*V`wS3$Lf3nxHzUr8GioeM|SJz9oJ zsTX_>!?<>+7%+^T8qd^Vf3iNREipuIg50DqvOBjEgTSGD7D?2m=zd}+bq2)l6wV}e z7k&p%zC=usBv*1Exkb{3gbE2&;>#zhiBj^Dq!RHRVphrn#UT6wx!_VQNKVv_hQ$Ey z(_Ja9-D%rcBhq#V;qq388H}$>`l!&<1ZQ3V&Pjoz0 z2~_lhOdn)O%;Coh*~pycNo9ALo7MuHsB~Y|8$ewK?;TEH!gnmLqF!X5Os#*tG4p&v&i&Eb$J2#zzR=4~5iK z(c5^AV$cz*$_~ZbZ8{&zSy&d?5J}uyrV~|+cw)>!p8I5NkXj>B3KfTE;bGyuq5Pqn z$O0LxJu*&^OPEA>?2d8^q%xKRapjYKOMaOw98<01(sQS!pf`3kmHm+~mCk&a zeZV%{aTwh(8}gM#p!c3HdW9^*n7RJo#FHG)zrc}h#{5cfujoBwUg8&!gm*>`hDU^i zVBf$}eC1TK2!*bihm(roFUGq-_* z`854y=E6)pW4&#(vnQy;B|!a3(@PNVsCIZ`Wk3VCgYP0J!fe(?-6Ag$BcfBGSbY@P z93CI49o*yBy?=ZD^_=&t@YKL4a{8|Mvb>5fK5#pfOWmZOipEe@`WVI$R6ODy)BD(? zNUNz9_a?qs;^w6DNnMg!CD%^Ak=!F!fjk>>l}}EO9~V2?vQ7RX3}s`fF-Fhu-@(O! zYQE`qF>8EwM)m@0*Q~L&%Z|~GB+yvXeA5DSXuj4fI)$7=UuNU^Iw0>%L51xMRS~)o zk^HV_tM+h#U=v?4?+$NI?`HQxm)*J1wcWkJbJ^S5`wEG73xo62dir5~5wy#rh{x11 ztcc!#UN&7kCLWO~%k!9bF(WOd&F{>8Vr$2Hyi@P3^Zax`XGvQ!Dp@hZp!(zKx z8p}_lZcIhuVT2364XzCy4NUXab}Y9xwJNqbP`%`F|Kd62RRZlJ$?AUnqcIn|n@qAR z(-j=Y?)*h22IP!d@Z830N5Xr8fB5|FW9}2~ik|Au*N&f#95&ZjkL(lRy=)mS7I_%) zYr~>-;5Ryr?rJ$!;3o4gg<0ZV@E1x;f69`QZt813X4J#5BL5UBPD0YdIYA00}auW9!8Km6)F7NbC@QBCdH{$(ZZ%cQ%e>)Ox;d_6J!fGrwoG z%1lhJn6^HBjJ39_pKp8MWALlWfkKhZ^%kOXHIpJqLJhtUTYyY44n_L-2fJ&#mOIbb z4rX5h-MMq-dutC@*z5H#3*A#!>%M3ius+WqRpM{>f^2L&dN6xFEiU_hSO_U_c;gocl(ngtF>kNjA%Nwl^ZU2rRnl3WxiAS5 zS?YWLBG)rprge}tn#E>o*6Gkv4*x;p} zapS!nLRRZ*V>Of<0?Cq3;p48vT@tUEy2n})o+tj1v?r--(zt{(alPZ(#C3~X6Qlds1Wqwc6h{2QE;vreQ={=P1CNamyLA=dfXSDl9fRke@CJ(5O0e;}JE zMNBRvL2eXp@sG)Fnmruw*L9xDzLL2w<9qti%vIJpHr+PC)!H8$S{_+z)T2tl9kW!J zED2Ik;W_t`c}-4@J~2+f=h{r&3^L12y<7AQ{2RZ5w(^{nL{)BSX&P5D@l5iWT$#z! zl426K#1D_XY<>jQ?kc%FJSagq5p0x1W*M?y3GGI};n{0HnAJADOKNOpRqJef$kEnS z-M=sFGODsx@C(gwznEo+)q2su-s=G>H zvkDFXk)Qd(wE{2TEZl{&(aodSv-Dn~udzVi1;)*FwTX5^|0h}o-R6AUW8tb4uV|+3 zF$Lq@3GWkYCq0I`!W_RL_PHgW=}-9-IHc*qG!PVr@(m&K-; zQwO9M&tkGW*>1UOgnrjQ6Pe5ot`%E_&CQL0r%d1i^j~D0k*=+c+zCu`Z?IR%&PW@L z?(bi-) zdK_0>>?Iq@B=f--bKI`@R|!>Jh4HfR}ax+xtLTJY1j6=4LFly8|X=-Wg&089s$f1mnTO)okRf~NY*DhW`5*?NJBk^s5CGNh(Z#J3t%64?a()nJX zR(|C!GyA}J>O;qoGxTV9R4C}{@33XQP5U$LN9xk_XW26xE>D}tbNZvunV-we7e0!~ z{0}55Y$Rx?U)Lckrb=Lz$L%ibtZjXe<;i}WJs?Z9Mm*QT2aQ!!3cpUOpnO*|(EyUJv2@ggGvnOgxCAs=c8R`kN!+&WX!j`~J_c`l`^tq`u)0bpgvf{HRItu%* zXkF+ra2;Rg6OnHFLOjIuAinGMzTS zEw)4ahJ--E38XU$u_MfH<@;h6USfBko--KxJ`EJ=Mx=&(mJ{0a&=G$TZypDgSuta2 z*00&yvx4^Dysv#i_%L--EGDdG3J7haY_1%AkE~-%2rctZ4IT?f-r{c6wZqlR`OxvF zv#_g|JI0qU*hp<1-Ak9?8%X;V!qN))i4UYXLUZ<4>RQyHPgRlLqxCUTqDRPftOvef zzxYmR3m@QW%ZQlrF;^^!vAg4T$KHjv?wNU{se>$uySUeM64ea)n9gKwVxZno%Zn=E z9<_6LPOz@8m}7d@m&{z*Q!?{se$LKzy!8%Jee5xb5V{F@QOT(z{zA8p77YJ{!?cFK zh36`KU4&;boJT7?^SqsXCH$>}hayvrCu9S5u6Wrr+Y+^OjQKsruGHZ#Q`O18qkFWb zk!z7$S~oop@dwkJ|H5|{4=BSeUoG8Zio{-xaadNyB*bou;Vd50QDv9(kJwkx*&z5t zm8d2}J7Wpzm+43pYXjfbW&Z|GXUFvHPg(V|Cud*I(yhZ>AAEvFGgbI2*eOMnm8M6+ z9A-56Q=K1Z;ZF?k9>L*ojC9v?e{fU&F+nPD+kZBkPq#$G)w-{p@c1f4P2CGUnV}~F?wy9jqL|L*e*DQrCi_BHbf12-_2bgy%hoq`1bmSm^EAJ@s*J5V_qAbZd; zJR|)h?G?)M%NaUaH*z%CFp$^xk9(54xM!c|Z*Q@{{a{M)VxUrZ8F*hqqyLfnnNIvi zsR$Asmzx#THD8KHxIvT$lv$7ZKs%wojP9eSagzi}UWz=`0Wmi$b1fyz7nEjj&kdFj ziYJ6@p|uzCekky6KwB&>8$BI>FVe?>T4Ce7Ood*4sOvnV_JG%s%1kD~x58Wp&KOn7Njk z=2oVlyiS@TZUcj59`dnDB4O?x9ZQ`d4#2zqQ?;lg!(DS_>2BTgNw+&tO``o=;2i$FaA%Fegf5C5|-Qjbp zS3eLXklT2S9?9^?)Mzfp$e+Zu!hNXsr}BHiMSW}JiH;_8av6P+S1ndUNz+QcAy(jvv!$V69f%b4hI}(5gU&-j)^#G*n5PoqdcpjD(RbX{!~QY5UG^sH z7&tg=j!K>f!Bovm^nwSe1?PrZROD|`d!l>wQ{jh!g8rr6FRr1k8{T1o^MQxK8fsa6 zuzta?l4a<}&??_%_v2mNlG`i9N{PZc@RYsWO=vnELy>rbtWS+%2<|245hlyUl-Kf7 zWtnNeawR8cSX{(!#gT4ipMe3io4&#{roWIGsQ%|r=lbeVjKnhj=bpWeA=&k_-(;T! z1A4c;fxDgmp_)xP(dUjZdxYEKXnrs=Hi`_i(7I6RK*UqQO?pcCnt-wVFgzskUVnq$ z)s=rgGGMh5%(rn^Qs-EN<+W}shaxjNT499>Sf zWg4;rnNAGFHUZJS96J~KZ-MX6tp;l$3#7{BpkkC@KGS`ecWh5EeFh0X#QN}RreLLW zQ%r%T?i(^^Lm+`z(1HFzk@RrtDmjH@2@O?;F2=OTW3YZ7dp|mVb#`z~u-}IgIj_5j zXS?r5I8Gm<uC8N-!tEYrjN)hUc;zIZgi_(Snb?Jv=e~5rGB1*}jFL##$%iA+Z;!ZtW7<@9Cp!!eP=E4Bu~TDY#)uBV}_TUy08v^c54uYe@K>fqh+Fah4bs=75gy7rP33 z$o5ocB+MLvKK~^0;ugWRcbRm7)_F^x8A|d=PY#*G5e61o|^=d{N zLSXX=>-kiytNx5`0^9UtcxWKTTfh_a2K~>2UBas)hqQ*#n;?t4g-42DTBG*<9x2XS z=t-!neqbIm3OHZ`xu-~{<#{U@x0m>JLJRn#CWz;y%~Dh(q2?PZ^nh}wHCvT_jZD5| zq91gFKhceIASvPw(T;c?Eg$u0wlEXC?K|k{=sX6O=mERz?Bxjt{tUm3v@lF`Cstu= zBYpWL7;)A0((1}!ZGTDsw7{`I@!+~plgM`MUt=r$>c_yagts3fq#0BvXP6n#7FFb~ zLs9dZ9fXmZ!kvch<`df<{-gEqN99Ix?h2^F{89y}q1Zv_$2a88Gd7CGlm5l%ggm|7 z`e^+!G;?jShFfc7X}cqHLKTCD{3b8ue&9Uf>f`y~`xvkW!{KduE3yWi51q={WJBWb z=xk$)dKOOD$-(ZS*1<)=V&Q=iS7eGlmMBmDNfe~MF=w%se~A8JGd#bYxv3n3xB3_O zLJrY~>7`5umVy&)xv&xY_<_(%eCy%;chN7AAhiTt@bgfKj5f}p2l@a# zPm^&D37o|u6H)nE125=#UqPS8^SduCa0K~`r@}Y20iY~gg@WP`W{HjHCsfzoL@Gq) zg=dAyNZv?N#2dMw)iBbGJRojPg#)Sx(}eAc^_+nxX9in@ea=i}DuFuPkNFjvrMK`z z*F{b1pm1G?2pLe(4MioQ0qt( zZ`@6IKT7hGxqXs~avoxA6%I+|!_uMzv*HU2UIQF5(NV3|)bmuN`!W zg@Rp!J;Sl;9QCmJNGqk+1*dkHQA^*ZUQ%ypDk#lGp-sA^meS6lnO_Xr3S_a64tU@b zm~~7MCKvhv`%t^CgloBu26&MffSyo8W&*C~2h3UR__BN*F2b&aS9>=b!%U=yz+rZb zY6@=lW@vh*kuS*uw7g-tD~RPXlZ_aV_J9<5HijkpI3$b~*Y;=u>K-Eexxsb>;m7GSLidIEF zV^jQWHBvD$7eK)j(0P5Cx*l}WNfB50H>g=xg-4=?7Qt2Asn*qs>Z|o9pdEfhYMQJE zvTWk`y;%+OGr zO=KD}bI}Vvj-#9cC1-EA4d&vyzk!9qMi@Ob_=O@GJaJUSF#e=<5zI+3+Z`4y-q{w&2T89J3$w6 z5S(xsnVln{Zd*z#%+wLFqOJJE0H+NcFLU~3?Sy*B%XX~dAsGrBCU zUQOs1zmtFA(*+rtZ?L}hfRSiGeFMcVn7#t$qZ0aaEfZX#&|<~!hdND zCER?tc(+ka>811=x*AA>qcL8qLe={gy1%KEPVOUDlK;RjsFJ&_V?6EEMrh5oPTCypj@C*qj!ZEdh$ugyNoj&SqD4kQXf7)0yTFIsq(wmH zJg-OfMus1069Rlt+o7_02E9rU`l3~McFMtFG#kp^wZvrNJXWoBNSQ1S?LY`@{yESO zoTc6)C4CuEdfm|OJ)kI&5dDAcoq2Fo)g8z03xZ`aKmti*4IqR~L}ZE$QKu7Y6&Hla)D1Tr zK@>(UR$7u4uZgt1Cd7I6cCu!o=thUAgRnh=G&*U$I-a=b5W z;*9@v=5prUd+s^E^EnZ!*qi^Ty20$sx?Xjo+@H%-M|uyS~|pLTu)K@)p|gHr4TD5KVL0 zoCUEFJFAi0qj}`S{f<1x>G0>8#1ziE6ePxAQD@V>hRmMQazxF;UcrJ)z+2hFdpUc}~i^!B(#V^?3#R@y} zbR(_((7)GW3u5zPV`H&c9C=>FZ_htTmeVTo$8x|?Om5KJSc|lFWNt5yy$~ym6_Y3S zhh&`m`g*b~Z^S-sX`J7flbAt<#J_ky=+op6HZrPrteyuL7vv2;A*IyLiR-(2{~))iFH%SmnOvJD0~1p zx8Se!i^%buo1BjYFClC0WAYGhBTw>AWFg*w=b6Shy^(f1SLM%Dqn%HYgE$%enaO&l z)8CNn!)|Ljn);l}o7CHp^Ywe;8?5&(am_r8H=e!qgR!|e<#s+axcozKrE$4(6 z^83D1@R_B_tH~(&8F`vFVb3w*`Y19SA0W?UD6J!*>cQkCJhxpELSHl=e>2~S@FGS)+l)R7QauQ%}K=3vGdUBf3mjUv#Lfi7Q$6`MqgYZM%n_K`NM+VdIo6GsT?>uI>nS9bA_|92KVGQye&N;o) zlNTVrx3Tr@{AM%1@r%E{lHb1nhK$Co=x2ViWpY2efDMVwiH)2C7>c!g4ljowyA|Xq z2W0YX<}AuuGIa}i*K#A&K8=j-;_nwz;P-00@LIC2is0pjb~3YMV)u*59jzwQ zbUkyQ0=0J%DITWG#y(%-X)vp;##UY@5BCOSJBCcad(g6n$;ho>ACb>`M!|u5$SXb< z9#oJMI)|LzLUbX6(^yxa3x9zh0hCQj zKxbF*?v2NT-@t`#ygy+FHgKP_k%!>xKhU(*a9|i~JCpSnG1F+GN(OIUuOo_=;bZ6E zxfWst%egMWOLf4a;z(dWw6$T4RY)-tO)tU+UIlN8gAa(P&je2(#n*{TH`9I@@uvXo z4xsoGR$Y$Ae+Q1m$)4>@hWeFm{DXM&S@^h#_}I(Abs-wR4+|&*{$u#{2tHsDCmfV* zT#Ki<3_F;Nw;l`C6OdmHypydh2I^(3>v`(s*w8+HZ=gT(kHc!Oh0b3AKaN;20Gm=q zbzissLT0>=`5%Sy7b#ER?9g^LKlxyLNtneIGHHHy40CNZ0IuSZXA(MQ# z+=%>@M_kGZmtb9bYxe@)YyB$EyBOV>JXpn$ImDEw*xO8IPcs6^S70qKBcFL_$lvf# zOPMc?oau|1<6)p*C71PGeCs^&=x@jRFNCgAH2f3d#+O*rCiaJeX`dY2#0saeJDdq! zh0G@H>Kq)v(rVDH7!)SalPo;gAbNVZl8$sp*5#DIUdnE8wIstijZb&{#!sPeFwi5R zMt&+CdfTE23HY%G_-|QPjOTQq`=H0eokjfuIgZEX#rMn6v3$5*z>Gbaxj$45qYR{; z2aWyt-v#M?oy(}+h3?lwYX|01=J+t?y#k!)Q}U5qCi{y+NcS`6^A=(Ui{Y-`eBTP` z^l}`&7Wou1atKeoz+DTMD$u#zc%3r06B>vdhmys76;}NS@}3G`??f^;GHw8oY!H-n zh68Qz$~~#~z%p{M$9(jrHM=p5)6`5c-&#fpASquSlXM9&n zc+`b*I($EeQv;X5>7P5e0$N(*eUv?43Z~DoylVJsdHtQ}?ZMbK$nhu0J`OJzqfN@3 ze~&e6V_Z7)^n?rNq3xGqr^DbuE_#!OXI=wzF*^M!I{PBNaxrs!lgt2OIP;G|1INNy zomObi+77_+)p*7otgHr`lpS<{<_u;(6~EMld9tA+hTqhgj(R99M+X!~p^N?z`f1PTE@MEcojziTAOrMXDiyXs{OPIPP?v^a9|7T+79M8I$KZK4K?z( z`>1;^cV*S5GrlXb?u1lyo;EtQO0hdr#o|LAPQGGx0RPQ{Us&R4W@^R;AU4bZt2 zN>|}+7CAZ>5l7!e4_4B)hM70Ovocm&3e8o>z|LdTvkOSL==CLiTi~otExf~8S3u_~ zXs(1Ohm$chFda#lhU*kb1JaWY#NnE(T<3On^U*n)3dh+mm`f*CcCb>lRROJjacmRx ztYbAxS(VCre3rnQwe*xaSe>_!B0fVB+w&$U=aK~hu(h~V-)_P{FfI?wdh5SF|zL9ZN&a=qh@}D-?i~c3Rum^aR zI7M8w6FIV$8v0b^*Z0B~S&`?b&IOgg(Y0V-jTF~X*O{P=(7F{0C3my3?aaNsiCb07 zBb%wCm~9;9eh^OY1#=~Ie+3o%RHLJ{0a`hx2eqxxaal-9o{aLt(4#XlwNBPwF}B)` zk_@#2QBh3L$)nv4PMWjJ!Dy5$Qaccxu+eCp0nh!nyY{O`G`@%q7y{AY6P#hX@b?+Ai?SzhfbmKBZI8)07X7a z(8Apct7z+ryoH{{4dK^$BEv2_<+X-zs~w)Q6P~goRwNIj6G)m-JZ<6Tl|8qmuLCd{ zz-Br44C=Bxaa?D(6#4Zpjrnx;N_Ht|USH10_O!GE3n^lJS_9FRmi7*(W)?(yAPu@B zbI3<3KI9S$&v5au2QAq^WPrOhSoj%yu(by7X%3fW>+DJv*GyNmvJ5vy__YGfkp-S? zqCz)(Tz5A|uB&zDsT;HCgk6q{dpXpt4m>5}mZm?hCcT%U`7& z#lodCct)MBYO(nRW3#HJIIBMOYJSy3rFvA1-tJ(}g(rRS&*F{F!HGjXT~S=o>THdM zNAP`sAHc5YEcOZdoI|`ln>as&Xy2b+eLKu);#nt0tHyS7{O|4N>BsuCLY+d?%-W-9 zPhs?RWxR2tFEjN8vOh)edJ=pt^ci2e!xu@nD{GRRbrny=C$;x*GC70M;_4tMJkx!2 z9Y|YV6UJVS3Q?k>XeHXji(Za4;gJSeQQgbMq%3ZChEvj-EH`@>H@|wl{6v-KsA-pU zOS%?vNz`i%8ZD`b|2g2ybbJ(k*@24PO(!$mtXbblD%)YuXvxk-*+{|LjM8PzE=(Sm z?5jhQeVLWX)62q0gQ28akW`No;Xgh1nqOD!Y~!u+x^O zI-esemw(|$9{K2M?TRXCl$i4ssh3orBMA8(U*u_zF2W@btdB<9Klv@gH)qP}Z)q#eO}y`?}S% zTJ7De2-0|AR2Xm7cl1a<#`-+fCI{gO`*kWSm@n3AeWo|2IpN+!t-eTmO?Rb-W&_e=(>2>KnHH-}IvWeim>jXjJX?MH;|HpZ?RX+=I=xc$twyVSE<{9XH6d1m{h(ve!X5o)m#&gf^= zJ*3bmNNw{io;uz2O;`I%yL$-3V{Pj7yT=gLVwWH3pFHLeE{tZX`F`z?o6n`bBWd+8 zf=nIjvFL6bw*J&Lq{8^|hTls$_3nA9yN60`v$~{YlCx{rYBd{~I^IK@g#G9cb0~F- z*4{4s-N)td?ls@;VSA|e%^^yd4#SUk*;m{O@WnADb|>*DG0N-9Uf`mt(;A+^WTWiqoUo;#3!un_5;_>+B6XEo*CxZE*eV)qH*kF5r5R<1_ zExxXCs{7r8uiLXhsh;{AjmkFj9@55z?fy9xpU0xRK^_mj`RLT| zwO02n;oaAoj|`to?~c6cTkw%Z8Z2v2yVdO}ta}|l+CF@bzo**Ju`Kb&XgiUm{}}iq z91#a14n!P?I1q6l;y}cKhyxJ^A`V0xh&T{&AmTv8frtYU2OF(<4s#~{iRozro)3bAj z4jT?IL@s{ePj_d#nPP~ZUt z9#G%`1s+h~0R@ zeOLbL?LK!FDoctC*%6nH>^|1%Uot*a99zuzi#zRDQY(*F0m zqW)JwhE(-mUu0DaT7K<40blUKJAGnLt!)gcuKEsegp~U`v$COAiCzhl+C=OVsh7CUPJ3_=e zmeRgq+JA)^#gO8swOgYeKJkZr_|KlK>{Fx?A+#ST%`_VS*ZC_;YH%x4wAlY!Ni83G zQ2zNte+ox*!~nqr0iPI*e+L>j5IyA45gzig|1AD@oQ2#H1bq^g9^hbkJzOSYCIVa- z!>0*yS%{d-p-*~qIDpC~u~L(x2WcBijv?9~5r`{)&j{-M!8>A1p(EZx5~>7n@e&{) z1{7y537h!`-v3Df7GRkmw;rD6WDtp+q(I0_h76Jp!A`6YY$OeW4Pt4@R9i9~+hm7S z3)D|riLEv!+eIlx`-g)X41hbOVI>|&1EentPmCc&2+$H+KxvM>q)*ZhDT>s^FBE5d z!ycj(5daG-Tv$I+NK9gl7)!~Lh?$rS2nWky|06UE?B8#QHP-ykUnRa6!#=}2*di=P zTYxyxexVe=v7k{zOQE%3FJizN>4j}Xc(gqT1^bW&#E)JSQyrvh_|d-Au=_X8h`*BL zO>~~dlk*&T44vDFzh^4uW0G}HxQG!_l#VVd^lmByYqAG$e9>NH0dxG}{KX&T0h9;E zlN<;65Aqb`QIu!l*hUV9JPtVsmc()h2Qj6bmU2?cD=9zHcwSHqsQ$l0g<7F{A(TTX zgWy$tkU|5-Lr^Ey98iPFIKG7-PO(Bvux`WyYoayd8|6nxBaJKi05;ZIp?Z?_c~mz9 ztg{TBF1ULD2M>e_$Q4N9NNWux<36}!%>lp)<3Y%UxFYTpf2}O0Volg4ghq4Fx)E+= zS%gU6X{$8INFQ$!7sLv&bHUvMI3k{iHwGsJ`UUSuJ8!bKiX_Ys^pGZ3P;y|cVZa!v ziWp&uN(`N9sam2s0BR}Riy>YDcMPSFMk#~2k%kBfdjsVRm0LJI@Iu-kY)VnA0b>re z=x>N6fHBe>DTS~oO>rb)|KVNhE$qz@)a8Skun&aVihLEXdfo;QiTlu5XAE9Ux8ROcVuAK46GcXl@RF|tPfxH!YvBt@eFCvdbZi#s{ zZlTF?jq@QNq>>a%V7&5;|GPB8Ku(I11vx9dqufK8fO1m{l>bsGiaecib(9#IyrHSc z38}oI7*e@Gajm2a#gR%0DyI-0Vt^2-?twK^iAOaEgo@bWorPLZ9_W&^&?Fx%j}iuD z47P#BM3BX_HJFNUsSKj|F%NAI;-E=G)EqESI4J3fc`x6B-bAnj7CKmR6_<;iUiu zsc@%wqg2G)G!1j6!W)*NX{aY5&a@tU%S^swY9`4hS@6t&C+b=`5HKZ^RDlcAF;7+! z0)0nKj0Q|iP3E99LI^Z>CVWXtLc}M1quN>~yi+ z#~7B^+KzGB161dt6vlR^Lms39g^z8!LYQlD&q#hZoY0mPbt)sjg`t z*ml%Ev5!#~&4lu_$FMFsz7S{ZD;%YC9O9_Pv5VRjj!vo{<6OcNS_A6-IQDTgXHqWoC>LK1JE0C*Vzv8$-4vN|?_9=2W2eZlk0`Ebu3T%tZN3ZETdkhyiKgxM(`+W+iF?gdzxqNlXjjiTW90??~oF z&89RNFa@g zZx_^y>Ul`N3SX~6xB>ZYLW%ooK7_pFvk;)?Q#Y#LsEgFO>U4FoIzb(+j!=iG!_|@MICZMJP~D&&ftFiH zEAlq^g#1jd5r%n+d52lYTw=nE$kt%%v39l&yOwRly~n-9-G!9)%xvONUsGMm=gMQs zX4x!vPi%=dieHR<7;6)IG}a;ZX{L@}vJ`>t}h+$_bnw;;Y!+Fqk(oT^Ki6K%N4e zzfwEGL_eV{QQlUXDb&U-m?}(=oPjT+No$xFx#~{!Bekdch-v^@TvZM!dzJml5#_9MTk$An^$E2PeBTb^ zD}}TnqsS_9gyfP0No8s?k1+L^hnX6T#DvH_a+s_oACMP8Qu$z{`~bZ*Ozo^brlzXA z8dX9{T;Wx_T1RcI_Eo2;>miR{wUI{TRWbvh?jo0ohscCyM8?AK0I`UiBfH60WHRYb z+L9W;UG6|XZ&E*3-&Y3#Rxbk`x~RR>{_0?LJm9!kU8`<|9JgQ|@uV6+Zb{ma?&J*^ z6+?j*g8@!o(u;H=umQGwN{|YX{U_K##rf{8jy3JqjcJjQSUh z!<&%H4fsZ3-m}0@s02%gTI!N|aMgjUHmOb?A`g?AAk$DMVqi=oXYs?lErAhz6Y9B> zoKbh+iL>Pn%##wBqh-n2k9-2HAIf`iPT(v-NkJ`Xs-q*P@c~5SR5;)1yrxgI&X9AU zok?wJKh%#h0_Qcg5|I~BTP_dkzpdU&hT9Osa8J#J*++Sc1Nei+9jLAQPuvhcoVC=_ zL(YL54ee>PxHL{iZ7*sAArC^Xa!b7q^u7o@MV>*qJMs^d3n&>v@U;x+h|q69sdLb0epH=f?AiqY=>;hU909CF*nX`Z`VtNQL{SC&)A%KV6@Dv1W z$6vq=uR-hXL9gZmY_ygshefNi7*cbSUnrL@g7_U616sJQUIDDm!gxb?SkK|V!wJCp zWD-8o|Gw89OzqP#&Ff*c(CxDdW-y^FjQ@jnUIUr@){WI#$>1bSV8 z9zp(n7ceYJVvW6sqbLCVOFfuK9~?(iN}*&zIaCbwqnx;%Y|C|MKZYv+6Z;tNcj3z| z2>1WSmP#t53|jsu+i+assMYQWnaV6$14;v&Ef`R~V4L%yW*qbR&^sst^Wefz04=zm zY&F(*|L?B_@Exg-dFkjz38hIU3WxR>&PMd3&>4w7f^wh&%72`5h%t_38gOh=zYKn% z6rppg5MX2Nhzqt~n_GEMJJwSOxTBUqJrd}RKz{+HGcLFXY0xj(l;+_7`FF+yV%t5GBi=q@kcvL^3qu-UJBzp7^D)sqPau*5<^#tl?LCpz! zpi)DkK02xyAuQ^ZLcW83E%enOFGZb^`uy;zc~p?P2#W^HODRqLGqfyvL}-4h<>4Hl z>qeRu{?F$>eNwbVns=0Hh;#-aJk%ZkCfI-TP?EYOts61LmgBuLRyiY4%cj-^>QU(T zMt_55m!S2od7ROwL47V-wMb*?2|^Bz_#&26JEJ%vpGB`RwVSjx3G^grwlrF8)W?GL z{L{yS)6wpFy7iN>Q{$shyhz5;+?z<|;{>8Q;*BMr)SZr`lQw+H};b zt=UnUmmYDX{sHP)K+79p(twcB9;cQyTAma#weB@v1KO)-ol<`STJlvv%2x-eUK6By zEs*kcAk>D~LlA1fw`xg@>Dmf~N&OLMO>5X-8#9tE%7)z409Fksjj-y1#!xpI9tKT< zUZ_vhO6IAagpODve6*FZ25R4<$ANkjkZRaE#8V5^poSXohH2HH4OQVgwx9YW&?}+Q z1>=+LP9TkdRI^Xl>ANu7qAme~tQDpVEHIN%ji%ffi{0V>uiV zl-3$%8nntWfis4BhNv$IX9!;O4M!i&Rc%&bIjtV-EjntnF`;2bXPh>E5fb$}As<1j z9G`TaU^)#r#&MKmpmAD8o2%4YNPV2>-J$+c&0|UZGW3pI5dA=C`%}LU^^2lE2iI3A z41|E`n2LF+-vB+ixT1)ma=n;(qNxv?`lXq_nX2XiqEEbIUYbX{SC+#RUC$QJ)ZUXcp z;b_1ojbWUoP%l5l75ns`5a>ED#e_a!!ID@`lk;?D;5?u+h0YCameE;7OHdeiN9dI>F@=7^H3fvH1vccc`hv^J7amqKo%jeQO7|JUa~IR(c5$(jCl*jg*-oYY#U zJ*m}#-esy6YwMNN->P|3H7yz6(HlXvTB`S>ri=Cf)tD(qL!9s(Q&IP&{uQ)z5E5#{ z)Hb2k2c}{S)2O9DYoQ)q>i?h?3bj(uPNWv2W-p?Rh}IOf&+x8!N6^B=K+|YBx&uP9 ziK&H2cOzi?=xVTL)1du<*lJb+#R=~;(ES5wN1|Pg-ek1OG>eSd+Gv-dRZi{95{RKi zP6PS^=)MDLuVYJSTd+OU(?tCb=x@Sa(tP6-PfAg3b)4FpXlH9Svu4So-AR2@)Lx`M z6zavMbz-eFV0}n8+DdAbQ~O-=eNjqN`!j;+EL(;XG` zj`dStJl%bPHELAA8W9Tm2`GGROwv(EQ*nm^rHnRy=^DKz59z3+wlB^WI^JooBF@;C z+CC7Zq2|R$TxnbBUKJdpl>X>v|F@jQH}n9|y#ctcggLbRdT0^S8G<-zvy{$4#7j%1 zI8vV(wXd-hTK`xt9gB4T4V|$xXZ#;9DeTHwk1GM1Cqb*1KD9dko%)||IG3sZgLu%r z2$gyMD;SmStIUTn%!@zl0fbXY5lXdx=SF^oavymv)#Rw;u9W&nJ#6QH{;-b!Ow-;G zs`kUO_)eb`4vk|DjbG9nbUy->P>2te$|zZo!y|>Ybw&!Ew(_4n`){leYNh@`r5s8{ zsw+?(gSH&^`e|)Ms5qvOqf(y&(vbQVuy1I)u?>hn)wL)MXYc+FawEF83ON{Ed!!yU9KlF=l$nSzjVB<6-g(L;vCZ@i+pDEfj)*)5y^n|m z;)>o&dPn~&`m*stj*VF36TPpPdJo!!-cR(m76W!Dw}OBLVuXE;yJWOgXdGckodn>B zxS;pC5K7;H@=l;w5cnMWJ#pO<`CBohV|~}b8=MP1=A+;%zX);sUIHaiW@vtI^pf6A z=D!CXFyXs0+fR#EcLA-IE z+rVb0KL^0XwA-*65LR`NXeaf-H=_a^53B&3gc^f@i8op9KCBL0fmU3AX90XcZ~kRi z_xKf7Auhpc8LmW}f;EsEfCu%_Ux8d6zy?d`~~sr(9R10uK;3YK#_A0u0b5vi_ZXc z$^oZq0K*40-bzyOI>0Id91-FTz%LJa&6}h&<%kTyc@Y6@>F7cKIYuPSbuhUi^B0sxN}q*0j(uEFxdCmz3=nXg{S?sS2)tc}9M_?(mjEWNu3Un2T*qTIZnJ5Ew9SlD)rhW1Jmx+;4vQu`;7I{_T zsJu`)BX?595u@5knXf)X4k$ewbs6;e$8QXdC@)i$*k*+$%IUHMD-hB{37Eip~r zD^HRcIZL@Bv$7-)kW1oR!Yl8Qtspc$Q!XevWsW>o=?EBaSLVT*^=uf^?U|uWHD)K1 z%^KNKCY!6r1=)Gr=X?h~kMnXy-EO`%_dGY58_yl*n(;Teh3ucqUdG05WzLg+WQe*= zi76@SN@bMtoBUVe$M}yh3{&Lg@t0zIVh!VcV=qQWMjwujh~z|SN4|~pj!uqtkLE_2 zL|=oi&EkvVhZA4QE9KFOiJTxJ!?1sGhxq|Ihi<5zHQY12ZrpG5o1PS6!uP^G!6x04 z-jYIMhBR1uRyrrXBIXMz!Zgz=!wFpmpUEyFbCiCGnlW#RRO- zSejO9Dh)W+IxabSl`5qVxk}u_Jtxb5s+j1X5PTwRj|O9h5*?LZ8Xx5F)=^3Nbv(wqMLn+hko2@x! zl~H3IBJIO%LPfrV^|Oq2S+~<3v!s~Ln0_(e zG#BX`a5?NH7(Mnx%joN&gTCdSFWht7e|W6rwaPwrt}NM9JhZsD_&`Ym$8AR^XT&wu zv)fzUx6fzs2mO6RePfH2&zLaVjUTLc8@3olQ>uBekS}x>_e-O#PuY%GyID&ubuGgr zom5+@Dyz2ua?^SC&*ISM5dAM>fl64 zY(aEb=$DFKo<6Rg4qfrkB5%o4&W7%bu2Ie`$0xj(1ajW*X~vn1%^v@xBlieiB*zOrc0(S=2_;t zf<^pA+$X*+4i$HZJ)}aZuk~yD2Wc%cI%V$5tefL3DHMVqyxZsvBwQ zE~bhtgv;iWLYi10G#5>h)zZmow=wn}w(l&{#9?Nexte*qxth>Z$P^lwe>CkjS%h8U zHffDzt}QEdOZvX7mQ`kDt+cG-@2YNQ7WWY+kc;wn@#7J{znN#K>u|}f!tDH``PGZ( zl+JK2FYQ*GR#2EbFK=M+KnMr1+Q9o`acl-RC5rYkgE2A9^G;tcZw z(@&;6bB5H!QpY;m`nK&OyU{-1GF4EGLyRkpf0|fftFTXKW*%UC+;GY;+w`>1N_xh& zC-v8iSy_+gjLIHn|5iU&eT}K3-=r_%Wp#*bjSUPw?R~_x*-^jvg~IO&8}1KHkAxY3<^iQ1Iv~;ZneQdK@`%39zhA_kYjX6VjMT`qG&EFY@>o)T9bP;`#>6GZTtg`J%IhA%SJtgyl zOlNA${1w-aTdjW@j3oHuY57ECO)#b6#j??^KF$Ki(UNJ!)l2$03QMjP9nYVWSDx3h zXhmtivTL5)@^fB0sNy-n_ks<=(O5^dfUU0EZ3r578_ycP)=x29Fbx(bSz?w$mc5px zmM)g@Qbc&)+{-lIv;f9E5qNW3;|+Z~eQW(O!*$b1A=^@BYnj$R~nS3&7QN225v$E4Dljv2-Ff?sogzgLj^ebKv4hx^O2 zfu5D+6D#Ic9ItTsvcoy?{pxV;gnp7SVwh(5L1)!lj3q)f>p|Oad$H}3HQ!>hq)FR^ zugu%b-wJER4&o*AF5?va2>xwu9pB5az`R_lYHOP!roEchG2NfuA#JJnvd*d-XUY=~ znd<8mbxZu&@H74wy(2sa%Q*Ki=g`ucrBxjpOBNSRFDS|VH1D^i=Y@~O z5u#0KZ(@vp>D%a1bq@V4)7#Qe>lNE!d&87dDNWLcW!6f+AXL>K)Atw3g>Ma?aV^xQ z2|n!c?f2$*S9&J8+c+1L&T%k~RwW0E?iQTQYm;BAXlCgmS6BBp?&)QUt`oBn{_Y_f~zrCk=;ns1+xQZFqhe72Dhj|sJm0_RlrM|%XjRs89l zUw*#)EB6K0?b1b#=Sun%4=W1iFU*^eU$Z3cEOL(mY4x)EG4~dC_wswb*F!ciaaOAv z$!DZ9o8X%11f5ggPhS7#e z#`jI@gyGUL%TDVzHoyHy%Fwir(&pOh3T+KKvt9f{_(OMsJgO+Mo#F5N+rXTh;(e^_ zlYa?l#FhHb6wKf+-JR$M0-g?8rWOivg`8(%f$n%4_wgzLgk z@sN~jt!wX|!l#C9-r!13f z3vFTB5!)2YAY&cY$NZ|lZcZ4UQU*wV^+#5&qODka78 zgKnlelIdcM0sn5zEt1os_X1wuSpV@N{ZMwPU6ZY%rT z^N}l35-Ps$=vrp=Jsdh0*%_-B+ZJ&}Lh+sCQC%Cu72_JyT){3qBIQU8M6>vsCELC! z<^9xeQq1=GQeSf|vt4*aN=O0mJK-nOMq|{#n+)bA!V$5TrKRn4TbmT#-cfADi%Nec z%SbE_NmC6gl~s{VzO(*=fsWA&vF4Gcfw`V|=^rJlONKk=xJ)j_mFn#6E_NOQheCBn zx$})Ow&FMcs9?3on~@*F{%|CkrT)l{)b9k@xfFERXH9PjZ;CHkc3Dr^efGw-`qt$z zM`ucm^pUh(IwP$YXPcieJ!&+Xa!nz#QOpw!mV1`ER^B$*R#P$=Zj(4G34&FWUe@ei zx&-3>9|D&G--OOa+Qitd)~18y(-uI`4hrr21jV#&0gvW&Exmj1G&*^b$2T6bCA zk=9G&q!*-?V$5{K_>1v5^Csa@n5n15d!Vl^6@-24mV#m%(L13owHTx($Yd_)OFA~tn@?2#ZrfRqW2B| zZ-H~cmxH?l)=*Zgk9w9p%?J1q;ABkG%{OfkAGJJfxggE3WLf4&QA=&xBpYL$F13O}*7UhO$*tmj_y~SHH+I9cXc)||JdIpc+1z( z+qbN=e7b*ZtTi)?JIWa4HVLotsqUhAy*N^wYz~>ang5Vypp9qvfk-m+6=Z9MBe zvUi(*WW*f*D1JGfCZHa}J3^jhu8@LzD5%DqU2mXpOAn{9VN#bL9 zE$kj2lh_v6S8ny3^8Vr5;D5)zvpmhc4s?`Jz>67Yw(FF;HQ3GbTut0jx3}!QinQR; zNEj^lyvU}=`|<9iv#yo#y5X>{g3s2iGWHRFwH~*&vMv#83-`=p#j%!p)(h5)(k-E` zd6{rie9Yn!Yl$sEcX`^<$}&aTBK;zzTV5AkhE{w~x4}Hoa>_iFeMM=R7^2=*tjtc* zPJJ~xDH!oq_YVuCg&GGtRop5!xf{Ftx?XjaISZU0xK_A(xZAr%I6rl9W!pXLy_@{i zLtVm?!mous2|phDS;-@l_+NEz=}vO}xvhq~=I5n+sZ{J_sVOcHI5Er8#J1M5O6nla z5bKN6#fZ3AS}4{NSxJ>jq^`irtduH069OKc)tlV(fJrK?gd=v-^WH>74_H*;e{Roy0i8`Bi=Wz$jiaXFC~q{he| z@SaYS7e;ObxBFiVRfn+LuXt~GvOM~-$z|=`r(7>Ot2k}0<<7pYpPd%hv##ClymCjy zJl|H|P=DP}o#?~y+{8z!mn>jLl4X2rQ?Yp0e9~}Ef7#sA_O;z*T?~55a`sV}JC zt2%Y5EGS143!)uDzx($Ez7D(=c*b9=qFMP6;NT~n-#XX0(p_VmerIFn6z8nccFtGb zUw9@}r29Yd-}3wXKZbfnpH9f?6m~w>n9V00IgcS*+$ph=O?=us)%bR;LYHVk^A8h!Iyj$u)w;~z1mgeuIKLUp5^?gbV#XG+TA(G z`MkS@XI}Y`iuWsiuGsBs6ClwE@qBrvIuOpR_(+IIy4j}vLKk7Gsg1d&xvkkReraiD zw^(ai#)_W`98O}19u=oa*Q^eZk*W|iEi^xDzGgmeT4F5Im+N~O zPw7*+iRuOAJ2(}RO7!Yxd0KQ`aH_vUa8c-o@X%lt?{n@=&LOT*?nUn0vd(T_>6nt` zC0$&C`&?Q7vf-Z1<(j!CH|G(Pr@j@-pz-680{;SofB`792i&*VI(_-gI2( zBaN1ZSpF2>wJZf(XGm3~#h_mgvaGYT2RU?K`c3>moN6&y*IK(tqrui(YMv#0A*?XJ zYBBk_nKK2pw7=Q9)8wOlp6v2LbeIc(O+ zH{BOL7M2QMfhTN))K^?A+^}TXI@pFvlZ2JR`yy|-ZtG=lZyO^mH*XNO3$pZ;HELNQ zvc|9UU5(!u9QxDTCEfdmzPh!{G35lyb>cX?Uu@)}-8MZi}xFgMU9*Urd%M5@sN6pzu z+%Ek9;~nVx8Kx5^z1bo>A(n|BOA{?UEypcKLA$6TostIH>eI5zZMud+=uEg%gyUH)( zx)F1g?Z>s@o9H`(u46N)rct8Vdnnp1 zIxl=R_)M^l?`PljiVuAwD_WF$J*~lp5O4(V zg|9|FjeZ_y9 zU6z{GS0KJuEE8T3(qYV+#Z5xoG}4r9T53FGe9Q2bUazaq58*>xHhZ0PV7?%uR3$Mn zu?TdWjq!HT*3npmiHr%7z^DGIK`xNx>)_p8e$Ug?!+S!W9iGSF+U>EF4=7i>?R`1^ ziT>=+@8M|Vw`j9iVfb=ie=E7VAmZ zKsq&(rilUJq>w9A6C*I2h6vrw`%F)n2AHzVqUkroP{Xr^Bl??soa6YfxHD{f*2DN= zC91nxA%B%PAO9(FC($;Z9i15-5sC%)z`#Jw;1U0k3a)$ySotH%yLqpdzgWJgd`bC^ z^5fnGzQ+TOz}n#H5F2R(`s#Ynx(>-z)W?~0*2j+G)^kUAoxYQyh4BmH_r@{C!N$I( zb!Np}L+ESnZf*to(hl=}v)>#y=fE3h-fuc-nrLzxInyEIUgKD!WSFiWrXQm}0)C!n z^{e5oH_piqDeu8L;T$rI>CA?JKX^G4 z{}JC$Hwru=Zhb35rlGl^sbROFw{Z^m)LR($8SWbV27_@2tUR#BbB2wEZV+aXqgO@HKT0>$>W8@OeDX$61vd$J&_Q>O5vRdsM!ZC{b!EX^FGZaq+*Rx58}X zLiE|lz|g5+`%t%F`@s3YP1v&Yc&H3y$XkI9;3a!FJUjepl*2dx*7aFeynbf&Z#@5 zTdljKTcVq;JFWXbAJV;~-=QC^Z=pBpyXb4^i{bqb{V#gEZiQ~VuAB>TF8(UV@(bCI zfp^B$)v(I=l`>Fil4!49j(3ZSiJ|cZ(VpRVW5*+VLZicv!_mi=g4M!*gx$ffLh<6}8^p!9&3urXz;n7NUqknc?mb;l_pQ#Z zpQL|5pU@rD8}wi6hw5kRy8zE?qhG8q)7{kd)E&_cFjV8Rb!&8SrYnDkUCQ2J{bUKd z5tg&BFpcC|%42G&++Vp7?;_ucza5{LI31lIn;Lr|HX>F%Dn;_5)gq4Y%*e?|S@@f9 zad>>BQTX|Ay=bkdGs49xq9xH~u?=xa-j!GOL&SLra*+{A|wU~a4%)G_^z<$Km;27>Q+m+kSUE<0)14xr}zAb--Uk+!O&+`3s z8+C(q+qpCPDY}k)JD4G7b+!4q{6o6G_+rk<_TYzd9a({Uoju0(U>1;Z44&g5vy09)4AsSGHAneu@0F z?=X$wjPYV}QT+ne($mOZr9f$^zM$+=IxD+npS(_v%7T0 zh$7kx>SF7RJNgg%hw#Wt+M{J*3u!mMm3YhtvGq z;Y>FRC;3mQuc%L}KdHUpTz@w>JAP7aqV9nGCgb6Z{0DGy^&sr_`2}`EpN90=Y8`SK_R1WFUJpQOQ;_iib+_6A z_Cu$@K80H39dbh*3TMN01oth}h5abQpe==JOE@QW8sI-kt^=pvroK!*hZZy>%|Od9 zQ1_^rq#^8yzK12l4^l z05S~rtJuj(*xfN6@UKe-sfFZ<+FZQ`yM>D3zXK8~!xRGD4+G}S;9Sxp@P7eg)!DFv zqDXB*ep43!7VXs)WG+bC?_kH#C3U0n9@z!w``5v)mIR#1{~Si_b!fv~uvM=mcL=p7 zhoN^LNmBW1bsBk>`~kayO4R-24vYproYVgacAy9(jcEYwFMvApl&bK*0t?hJuy18F z?3%a*V_*zf2D9KA*#NzLP3;M1*2b#C$R_flnogF2kES;4&lm@zQ-$&KA!!05nt^(b zLtB@r0ic=%=(R~*NT#TDp>OX%Yo1V@1Wu$Y8O(8@#oJ`B+6wsRTrv%I)jY=3Bv+K@ zNh78YjKChueb@o=HvFdouU074S(kEB=})!*tyjvMnG5Pnr6%kVI7fymoykhFU3p)9 zk?5HL$~5@bgkRJiFkZVb^Wc6>eVJLTo>ML|$Kby$OhDgi%vj|GrjQI*7$!X2u5suwHxyz(@e(ygvf@u;08L@2U+_j{EGxpix?|;UAeF_C%{|?67LS_0QA91!aKxD{$_KiM9;vPE%5u1sz@0RAasowAQv0xRkp$P%WFQlh@Yc2v`pi=-AvuMvtH{s%*ngUo96 zTjr$lE>YMOiH__Ia$1SAn}EZb*fz{u;7EIb-#rJjWhmQMKFNH*tdOq)4GVz-r;~B) z8nE@IGBKsUQinMRbND#S<|E{|TtpsG$AGPVQ%Nubm5&MRIa3BQe=0TAi>yxh3})x| zN>B0y(_N_!9JM7`CXZlpnY)P{BnJA}AekjT<_BdY(*x-Ap?U#$$Vu`m>|478J=`Cp znNdBh3}G_3P-4Hjg()VBRHHHrc3yq1n3VOLhglY%uRh7X&OaBgkYjwY+F1Td75NP+ z>~vzDWj<6csK?m$@E;!`=BC`6$z=27C9;pbrd~{JW5$uG$~JWZ`@Gy+sS5vP@)*p? z0I8)^$SZWyysxgtZ3yeU+qd(IRNyr}$a`bC}^vobyP8`N;P0sD%v zb-Z)@DT7-{i*4g3^LJxh;uGG%H;vp)Og4QhkBAB2ANzv%qj$+4{I|@4;AJ+?xH3@` zd6M($QvJf(a}5EA~gv$RiAk6<_>YF3zUL ze2LnI6y~W&H}(p5Lv|=@nS=7Y)3*F>;Ey zPEHT&*{_8|@lS%RUT=zpZ$&MJu7=x@H{_FSYkl*?pRj*w2h6(`>ZZgRZX@$e;*a=2 z{&(H=(1Pe{+g^F5uL~Oxdd6x6S_?7VUjb+QN8trB*4In7TkI398|Vj?v@NtF9yT^q zM#l!}7O?TyLrfiJH^VF7w=*<}eJFR)EhPQo?bK)W%@Vt#R>NE}H1-I&Zy1!Q9$2CK z*nB)ZC%Vh{9@8OmM;>dOs!Gwl%o6VLcubw8|5{Fkof>a)rBP2}y8boR9?xT@v$x}U ziG044432kKC-FL1J@}qXVK0zP$_p?z4<#;e-Sw(6BlI1+$MA#veY`pB{JAFgjtAKO z+|S_6f1i1cTv8@R-eC?Jo{CxGO<*JP%ktsad;B(5QmV;D<}mXR%=2fMV@yM)b6h0H z*iXna>N(j6-iUs7@r8@b6{U%WWoOeDsqmE5@$!0Q08LV_?R`avf4e=qM z7j9syD}9w&Tuaame@uMKM##`a33HCjP@Ytb?0M#ugrw-%&Pv>llDwQ z`H#e6{%7Vdumv}>o7G+NK4k@WgItb1P2S=!lIpUZbmZ42YAJs90I9CLDrfNDuurJH zV6A=#^NI2k8Bd-EiTe%cj-P_=S*|o-S}<4PIKUibICoNcUx_N?*kQ_Cc|0qUw?XIW zslKZWQKrB@HT{`r30m$}kjcYI3Av~|1UlG0RZ+T;Rcx`!D=zYx@;vOoe1qT2tcX9Z zjO0I77shX?-}0vjpQyup%Jo%$mN$|O$~yT7na7V~`l@|_Ynqgf@*%YYXXoaS=b0zf z-AWZz0k3=wbu($qeMK6Bb~Q@vr|co$f!?x>tYcEi&crqO0+|Dv@%zAW^Fg{?Q}%&p zxK~22KEcc<&nhj*>+E!OKUnL9N)=MB=CbK*L(sb&@eSHwE@(HP`>Z{my*PyahXX z3GpkBCvHU-M|(!bhTOp=fmQyEzCcCL`&oG>Z#{3-@`;|W%X@h%%HQ&SUeV2e8`h5Z zg}BJ`(O;we6R#=t)YYUamjM>_m%8_ic_zlZRmhfVTOPJ#TgTd3+g8}d+4tIe+Ml&w zwD+)gv5&CjS|7EgTf>%g@cQOi3Phh6G4(R1n7=Zn={FHBF(v$7v?97a+%Pyk(Ad|{ zJ={6J)LnAFWMSzur4JW(EqTJ(!#TM`a(r5Pwse zmVTFUuW6?F8^I)qu%~IS@U`Uy+eF&|+oRTe=_gn}ylNh0`po>i@Un0NRu!^MzZf>^ zQuwO;C%V3dmBw1;w!(Wt4>2s1n&U>hkSEmvyd8qq$Z`9bfVva*JLkzoiPn*ofepT9 z-kh>4&Q`8FrSH4eyRzIfT^Xg0(yfl!jy|OY?sqCa@V5UTNnv_ zQ%(2^_S!BmA2lr2wc#f)uxDQ0BCi3y@Tl@?Vr*h)Vq{`-yrJAw?aHR;bM;o!N~6cP z+|~s=o|UloHJn@Z zzTx(`TRm=!xV7r`{@X|HwJezH_{hDY!W>)`nI0cNs_UW#K`5}i0lUzQDeF?cx0gs` z&73KrH|rUll^aJE#-EI`p%wm`fkD19?_=H%D?-6=C_6%6y>WruO|8cDH@+wyljhrQ zr5sQFCH393^h|wLNmhE5tyMeJD5`nlq1`pQRQ(`F$Zno-O&Y1Y9RDg@*H_Qg29EFy z&FggM&+8YjO}zHRwT;(5x&8V5Bl#m8-*}rvZX^Vzo35R?s(9Thq;yX|ma#OmZRVl0 z!}gk%)u#IVN~LA&SZG9Gov%*CMbA}d4aZX@AxE9kH=V;=C7yi05Z$3%V@miBj8lb0 zmJaq0(_hd2u8P0Pjw*#YV{)!#ugiKdBa(JI{c=Ww%r+SfGwNmZOzUKKNyCIah7n|V zXuYR>X|JMB^RC|a-}~WS*`2rV%)Hb2&U^R8!WUhx^1gvKiDGWIkrVn`UrlwUE=g&W z=1aY6f5O(;dRsWEI}aNBGvRICH{2zTjm57PuPpwp$Xj@*ct+`KE~{r(MVru~_$cOx zAw}9?e<}U3%yn6Hve#!f%UPGxGiOZphnYF)DJc`I>qXuq>+2f5=1gfY%$7s;nC+N# zjTAL~t+O)?5>tJroqoq_rPWLLf}w?H3c`8M=JqMj75`GQ!hOvDL2QY_^EXVQw8whU zcG7;?_JPf5T`hfN-eow=`_$g?+|U`{uCfuOTZ=~LU(7QV&MJPfzq4Frx$-!csXx--mSdp`F)E{lpHKQQ5LOO6_(_` zSg+9}jj=tSax}$hpJZEMIWL3^v-lHaePVcIdSI=0qx(I_c_`gKcVS-JqHL$fGu!Wt z43n2Kl75rv9at-RCG}`}t;{}|ce8uvG|&1qCEvcqS}1NdaJuW@<@%Kw%>BY$;2RsB zGxwL8Ti>-mnfgdZ=d2SM?NVQY9W595NfDj9cH!89_wO0+Zn%?v_tx$5JN5F1l{6@A z;b|Gz8+%R-@jHbYDdRH6WiQHlJtHkOZ2dsoY50&Gkysb%?IY#$T#k~qg<^h_ymomh zaJZ$+^`&oP&=jxFh^D#LiK*+-O40{rL^FnG^hy6F-In%EN-khX%oFryxr-!2{YnnX zgdAY^>nE5iEN`bgpFS#ccJ|V$KUe#)>V&LIsaEl4w!Z&DN$CEU_ZHmnUHS5I^{X?l zI&TclomaBPwa0rQJWY9mZ*R^_`7|@DYSU`wYOAt)r(d_-G0)-3;_HJ;E9R6fDIHy0 zw_tDXlzSKMZO{9#h;yDTKN!577|s4}$dD$b_R2X_Wly#}<9_Ppf|AFXfUlNgdCOHDXE$ExcDcokX?Z5+Vvjjgq7?I)=5E%HGP+jlQS)TY3)OX1CuhE9wHy9a zmWF)g&7AKSZO+|#_wBni@A~e&o!_pwhjVoKmY^}dTm4r5y=6gK`>a^b+-gIsb| zwXzqcZZq$VKjC=u+Ntvs|GIGc*^{?U{d)HJ#ap+YDe2;!5uU4zH?$OemK~`}a~jrI z_fWh>r)qPv(o(C6KE@k9<{4Ss?Edy!+ip&{HTia*`-cjul-kSs`D~H?N;UokQ@W*h zN>N6WDxIr+Uae!5;aRIvpS65vI>JlLY~?F?SmMjLC;kU`-G?%-av|M*<2~Uw>nrJ9 ztCZIW)|y;*>%&Lto~gCI`mC%|(kdq6J$m|e8VhU9sWqVH{G89yeiujZAIE+xf2o+ezx<}-TEW!?H%8v+mbbj5 zcUjB8y_lUjuD>DZ?1gE0umN~)c23TLtdz{&sWHnMQwd+2Y)o8^7DOJ2{vO)_$Fze? zRge$Q3aQrhDeq()&dI6Srq1!Y+v`@;dAD|Ejh>kisSUR=+`VMq)v2fA$4(scAD(pN z`;(rFQ|}0+Z-x}o)wtifA^m9PjO;#Dht!x{^J;Zx&e*h1r22;5>MOw~oh0wMTj48< zFaB_G)wSR6HY)nPEG@KDPUrUu$LzP#l#F=xrR*x1)6$+vKa=*m{Sk{^SgY^J%#-uu zKSo~&uMfGyCt@Ef@3SB1Q-mB_@3jAirL%yK;(EXS*t%=nNC@t3#oeXFU5dNYqQ%|a zwYa-GL4yT{xbJ3tcl3Yyd*99{Aq~s!oojRNeZJ>BrtqfGyW%G#Rw|v5yeN5W;_}!< zk*h6pl^eKvPFIFIHSeDGCVgY+tqu3;Ja3Q|o&LVKt7y?)w+@fEA5%MiVBCaQK1LJs zFmjAN#kftWBy7Pc&Ivh_zK5kbQd3^vdAsVfD&3ve-Yw%V(Nol8jgxF6!k0$oL?nf8 z4m)R`Y5i(yXLzL9Dep#&l+w5_LDqlHe>|`~w2U82G?1Cp>-A}7RTvpHBeqGYnx$Wr zZk<#qVMgrwsIp;a46T_jK}SK#C*R}BH~E|AZYAH|bpJp~eA@f$q+k!#ICGx}c^n@< zE&fVOAo@uZ6&`0hVK}d>MjsM;vUOd%a@zk0d^Ej_d3*E2kgvnj+ZWXF?h@n_)LGll~G)H z!EYl*t6G^WhkcDOMCL|x4nJ!jWV2gF8S*ucROeLpmAm9G=!-t37y} za_GbJtS5oNvO9WNSko9!{Hyq>aT{VgMpX>IXxXT*s4`+-{~LeMd$q7)X2JKxUz&Zs z`+3ZlcR!+Y>XoFjkxaafv@QvM8F?e3LiiK=E!%9%75z}nd{skLlxmT(qB2ufoetuB zc(-U4)(c&vN#ro*sPcuLwO)#B5^qb~m$g71rFe{24#^CQQ7 z*B#fL@Q2YUxv4FF9xow?nySsFV-ZAL-}v@%KVqLne-9_D#fH&Tw46;_?Gc4<90;3Y|C_eWn200&LclP zulqbTJZN@@ynXHNwa4<;@!!8WX7g7SRgGi9rI=rF2jd>a#6`&>%39|d`e^zo)$;0O zEWgdS%yB5UP5Q3yZ@ymoa^Rc&S90zJ$GyN&>YVne#U3^=e0qc;!Wy1#+i9+DXrT3| zdFV>UX?kdSsZPm9Gn1(hd~|O}k%+F`rkX0|Xn&geh4qhq6PJ>(E`E4yD6+Jj(>IVE z}+67j2s_drjU)$cu^)Uxy@5j`Nz8)TJyJkGB zxu=-P^diR!`vUt*cILOqs+Rul$I|cbzN>z{%z9Tu`5v%_BN(#&!|H3BlIe`i4u8M!ZTrvL*}oM-g(WED`P!kDkKxy% z98rU!^pU6Reat@n5A9&6)8?uMC@X>eTP^p>vYGyL2KkdvkawtLS#@Q!cBAQx{ai%l zr~%PCqT5CmSx4v^%VOU#JKgzh*=l+mKV^bc!jZcp$Nn;<-wRF#{bHiN` zS0mMtOTv2Ej+<*6%4j|+4=P?Tr=)J7-#v_@Q~u!WHR<1eZ2QqCeQ?g*qFr94;Af(> z!_8I0Hbp3+K1BVBY#MgTa=_Hw7}DiyHmKuNy%hcBeZdIypjVR($QI-}at)QqtWx&T zRWgsa%?&#kQ7@`q)V%P2Ei1Hj8AEVf-XEWry)nLUK2qGTazFQx{>6v1JGtk*)%XzO z(9N-|vmFX62(KQ-THL1o2Br46x~hiM@bX;p6n`fW>3&yqDYt1x)9>5AUjF_yV^sb& z*B|UUs=2znxpKten8$Gss0!*kN>=S_GHEV<@fR)lzAFVJ@w1( z$PR2HlGM{p4)MD^M*poUyaDm;H{tlC8+x&V=o{Zilv|_O^Pfq9vmw#&JypZQbZJIfF9} z{A&EGWd@10MK$j!E``3Uxoyr0_e9&{HpPC7PKbIQaXL)2EH$EYYLnD{B@JEH8zzET zK|2vA@5}U%pH_C#T+kgcJTR5DGPVU~oxY`N1${lZs9+v!2cEvpd{*fR^`y&F_sj90 zqOxn3*g`8vpYkug+4 zm3Ap}V{v1DNPMK2r|)5YiJjpXi_>Hinaazuo>T)u;Nt?>&ihdD zw#|;u>X|(uuXE8!S8lKjIYsH!D{UIVWe3?RDawB*pZhiZ%hmTcUTsYo`)uN~ zPOm?H?wyr`ars6VBJZfh-oU)cveI(RG|wJ^$?=zdZ)y|hhqjdj`TE%Li$K0BqPT2Aoi$S=*_{r)2BS&fuQ zFB-oKeT&c8Tzts4SFA4IrI~1$WKx=Yn(i9z>qzY)O;4zQ^E4yX6;&QZ4|#}=Cw^z6 zy%~SP86&)r&!VP8UykC#OWR|ug6Y2Dk$#GP zk*>M6tX2u_icWVMn&;p3>AKa>4i41z)3}utLBqD~ROjf* zLRi4zDpg#RN9R<`ZkO{S&s#L!bCW$v7AV&1>YFFq?qLOAF|t`imc5VFZSG~hW2$BP z3cczTV>MI2w95S5oM>UqE6hoz%Z3PjYi)h?W_e{QT4?8MQ#32{*!SS4S#R&XJeHFC ztj&whsWZM9GWO*iFBu*DCGD2&Q*G4R^?&OVpRC|U2UPu- zI58$vYxz*te&i{3!-|Ip#fCHUSliM9McoyX?;a? zV`e?Z%1fwQI}}aIZ<=>C|5srnXC1GB?JudABg$F2W5zq?^;VgEn{9(-m-!FNT+0J< zIrC=oKuf0Oj`eq2rmd6xn0>N6!WLfvz)fJu$K+9hQA5_5m71fO!!8-#d^u?F#2_yR3Dj#Vv|54$DZ6@>6O22{NR2) z{pGgj$6suE6Ps4?doaCKZnER3_Zizy?0{$qBdZCHR8T~!M{9M4?xq-vXend0+On)G z&2HUvWiR@*@IJWCTTt?|xLwieqVbMoS83m}kU{K59hXg0&QO2Q*4Ag~)4;E{&^L$j zy^*m7G^(`qmCY2kBAkl|i|QEFBeGZcCHrz~d-E)Pp=v#&7oYkYJDTS%P4Dt;!$31Y_l2*tKefI#k1(h;0ofwrLvVCS_52l?mLEsb zvfdWGKK*L?>ltr#X{lf9{2H58D!-v4-@VFr1e&~Rd}Yy2`0je6{51nVf}7cz!ggsVnFt0?#w0U2%qiIz`BnLH zg+|p!lcI|=mY7;tf3w#Oe-*wZViwByE22^Od;3Y-eoLOQneLLZI<<^F;r>uKIOpQe zurD{>=ccxP^GB-ree$Q2uk^2}nG=2H5dsz!7dUi1_ecgQ`H ze&DM+E&aoc_Y*$+lQ!w=v>!dw?`K}mIhW5C)`EU-LCH3^79Iu#+-+i~%%g5+7-_C# zHQHqMezvg|m2ro*f=Vv0#;m96P&3IqvJ%w*EH6*L1OL~N1~))xkqKsvw469XR-vcL z>MNG2Mrks1#|&1J*L25x!m`df(-v;uXdhu;Vwc;aZBNbL_3PC27)luI8|V0*H#(!> zd;2ece43Cpr)8YWPRSXZ_blI1u(0rX(GurfR~O%)P<8QNdXI9D?v253 z+HKxtwwj9#bM#X*sj8m}L7ookb}I}WALIkg(v`g9wU!1C- zkGm?)Dch?XX(X^=^^*yv}KryC6TVsEKok=T2ataG5%(SfClI zy8`EquX;*ptEXyOXglae=rvH-?pNDYg(%})+C^O=W639E1JJb< zT^!Z{Fz1FN&?J6=6VH5fXAm55e~s&eX=sy8YQEc_Sw zblCuA7Cnc4PS=!mLysJ*d9R(UKVg_>>}RZKe5K#3d8#N+bJ8}x6x%T{)cead!^t=@ zi>4GcD@rab$ghxhGG~1Dq%2Qng{*GbD|27wrxs3k{O0QE-56-ZZs&&xZN-z~7|Bok zO|4>Rd2Qu5bysaOeZGFQVTa+Dp})Zm)x$8&6m?zoO7#oPGi^oPHZ7(7T{B0WuUx8l zA=5Io=xfMf)PngbOHejY2Q^{3R=RPz`npW$Hy5k7E7~vx#AI;~--=rosu`%^YwF2# ztu0yLob9+-w7gJXFd=V!Zf?$i+^4zDJa@r|qBoB1CHZcZuX^BE@K@*<+nQU>PsYiM zNKB#+%JwVb)x9*kwQ1VY@HoiVUWa18vSzXRFLfnNGSoTMpwURu-qJi&?^8aPJD6-b z3K9EB;N0IbHRWfO6QD&IhrQz^b!oLyRiu~#--gP}IC?krJJ~^6CH%z|g?a>2{V%;e z-91W5pdV2=YC0YjUny=`+_`vwV}fIX^P_WxYn$8X?d@~=F8lWfMuyh1J@_g@4Y4UA z;>Rc(^GFt{a423XJ<4Pi34PcxWvcRwN~WgNZq>i4AYzu2)VEb-m6zlvWNMj7)>hV6 z7LfInrzp~tnW}Nn(O*;@Rpu&GigK_p{4R@ zBFa^Df*tTm_%;42zHIM3Z^%nSy>-}|=b=0+-BsPc+?U)PZcKe6?nq8iFZL7G@hr!HmOmA` z6U+$&{0aVvz7<}#$Ku)RN-vpPa;zlDb=B1s)IkGpckgv?gs--5wePF1$k)Vg4@?hU z4&7#Na?|*-pf{=_BiAOe5Sgl4fcv;ch)`!c7_U4Lju%_u*i>ITU)xp}uGbh6jDt)A z%(E@|mKxTJmK)}^rcZ_n`iMbfk@tdNnyua)g^Nc=A%_1eKyi^?|N_*bVri7M4 z)1TtMy^B1T+!fqKE{nUeTjBZBQ`cL@I~!ja=oz&=H9V2tmcD=djRO0jx)>HT zK}ozM^dpoX8pSqb*RTcb2kxCPPx_s7Q!SVkvO{vjSyX;_`7F>TKua2Hnr0>~gDrzB z8!Zhi70lVj-i8lw@>rtoshXs`rWmNml`oe6D_hLO(K|>ZF&mn~QhYd={T6I`XlbZ8 zxF~o#pb2dAQ~n75U;Y+>VbFn$Vjr{b*+s09Jsz4KIuz34=epcot`Yw`pTlk8)LcLI zQ)qCgW@t*NFm!}%%01_5^6mNMd@5g0xF}3VKfXc;WOuq7(@G}Dx>-|lyW1wdIsYA**amQ6+(9;hy&WnW z+7oOOObW_^VYuJ$(6W%3J+Ih}Ywn8=>wa`HH+Rs~4@rBpgq z1^syveH1g50^COuW5*TAm>DAz2cib1kGjA$SCRff zO`#<6G&zav1it=Xu+?iNHPl40C}|tv3%{Cg%j@|k+*B@#d&_QP7a}*^YW5Lp=4Nu= zxHkL|p5vPdTZC+(EQtS2;z!X0<=Q@Q>Me-5$i{Y)_({0HA6uaVsf+w?Gsu19P0~#! zQO&8I)OczIwGLlPaIHXYycg6@%0cl|EFDibq=(Ue&~bDY^3hGjYs0DiWCxNa9}zR) zUS|XU-383;NhmgS;v1+Y2MeW;K`+R&yc=awLiJfw=nhrKVc{io6-l7cR*1);Y$}WP z*be@g1UK9c?D|${oGubCkfkmS*C!Cj4v=jU%B&*|SeMiWt=f=miOhBV$U)>_au`^# zwV;kJk&m%5JqjjjI2bb}`3YJ7=7Rlh0Qy@G#``0v>XpbAI0`xmqm(DU6Yq+b@YFma z?t>EIU&JO;5I-$IPCqx)5YbY7XbxtA55Eacy%fXJ)sm`0>rfF_J@nN<(iG5fi@^ME#_P|4*Z8=^Z#eem1N7^GT#^;Q}r>#V$#Cvdb z)FJ;}KV;q8N1VqU9fKlfCK&R8;E-c+H=m$#*eT6Mj=j#%1H_@7{bG@r1D?-~uOiVS zif}HhC^eS`N(<4Nr@`67!Azo211+IHSPkvnVGw&r!Yr6 zhmJ*nccKX-cmi1gu9TIr-?5;V=MgV)4|9mF=%pms?f?8XFM>zk3Ej{F)Z;v;6BbF! zaqkyFi07hwM%;T6@t^9dJg!K13;+24_cab2VPE7bY=&n*1V*IZ?}K7z4My=0q7BMxB?3^++<_`% zKYGVRv}i}E0dhXZqdrB^hqjhPS~5e`Q2}`yJ0sWPc+~xWSr#+lpacuMpk{vcYQ9>Sr^aiA<$ zF>h=`uO5Xq>wqz7gE6HKdWl71rf^L-1bRP@=_aegyrPoGQFxD`&d3Y5mpdT2f@vEJ=)$4W!^6_ALBUr=&c8L~fBhUmpTW)t~hQXyHN%w?vQk?3b>bWp3_>o&HS%nAW zbEzt^5%roz`T6;{yG_dZ@(}lvttnMtb=-1d9MzYG;##4Vd;x;VBQ(KD{{B);W+qvd z8K_*2J#|mIyLXPKHX9WZxgqo)hCbS%(CNfcJA)V9y}0tK3Q{7wQ1*`LMphKtfmq({ ztHVA5IUh;xkp&f%WLJbJZY9^u_uBJD+NiKUerKfalbzjvt z*$A?^*d$cZuLx0mfAWH?t6ZnpNd&3hQrA#5_Alb3kj#A{(wLounR+j4CKG)6Kn1cf zd4!)W{7EfT7n84ehxm!LNzdpdauZRP?Zua4cZXi9WV*4`XsNm~OFHHGCqxrJ*)p7$ zT%lR4aFNxS5-OJe$1C&Cl0K1_g>{mKb`taHMbubnHu;D=B<2SX1XNtOkWYr>O=V5# zyYyfpL%K*EA}pNEKPTiuq&uXXu3ky^M!w%5J2g-knnCQ5D4`wBbxBz!@8C`eAJ{ki zTydf>jvm8|kbPhtk)4GY=w4ESxBZ_&XQZ{{S!%TQuKuvBE4L!(42<))VjGhiR7S-b zx(%Hz^$xxaCP1NA5l@=Q#B^q!l+Dn})#Nz7NzfPA=${zyGc$D)vP^aD z#4uhaRA4uUsuCKwF&oJR^g@c}#}YLe0rYxhtk61zx`!k(PVtpGL41@wV$wt<*O*<& zh6^*KWZ0ZVfS6wfE!a6}F;-5yh!~+-XazrxY@+a@&VQ#`QxAn1p~<1G!tYSbCXs5H zQ&yc~p<>CCY6idf%5kswR{RB0&U}?+%G~la@>qysE3xZqkOiqG&7vs4V~*l&dz3q z7|wxvs!aC>tKL9)ntsV{@iq7F4zlbfu@<#cZh?ovSXn7@2&V~d4+TKWuaG{|PqC+5 zElZ%z5nK4->|Fkt_*%HaDcmun;&D=SHN4&Qg^9MbdXeZVXlA!0Dh8Xr9N{xB<0p$Z;c<~d&!@*igR)&J6h`w^;PHS ziMc562XB#ZoO5ha)R%9PFIMVRk5p~cy}^9QHKcZ;He5SUO)FN*Dl$LF+hh`*%+z2y zVUKegs-B_ns7?2~y*h6t&ms3A_gA;f^U{6a-NC)Kq?dEQBMly1QyqUfZv->a;px~M!Z?=7pR$W#8K`lx$p=xMZ>;>=sE zovnw!L6dOPeW;HyIxRD;6D%*yN6mj2ZmSn7H_FG;$>c%lr?`=?%u(FuP`_Zn-_O^@ zbG>ASqj!4R>V=8fvQqDU^t=gH^FUNes=Gm*#t3>gA9JUd)Xowtgb6t*aM zU!W*77d0&|Q!Er2is}`v%YT=*F3+6bsGxLFwquHGvbT9)8QW8sDlypa{3IJf6E~M0 z%uw?23WrjqPFGjgRDkR2C3p;HD8DMMDYhxvDi*=@`>v{zrdT^vzeL|ye+u4@iw$9> zBewV9{lZ>arkPiphU*K|_c50kWNYx8iXdByANUsR)L^B+Lf>5X4oB%CZ$Uv`%{&?W zzN_Uw&i@1tsg{L*7bX?{D!2x(!pg<%9G6_J{9V}T!V9<@<-px3lIh1(m-UgolI@l6 zQ7BbP)YWRuN==mJt7ORTF%X-S{$Y#p+%Qq>nszvQ|{T{;wID{L_S*BOk%&@}| z1$LwDH>=Cs&{$2^UGrXUV>Xf+LMG&f$dJ?D#uxD1aJe0kg_``AxifN3=4{RRm9sK; zZ(iAg@o+NxR1{Vm}15WsNW(xgfF-2 zYyrzh!!uo`x~a09tO0eF5cxOkvOt(W*7L1ox}#d*zxkVU=jYbXIg=C0*_wMWFEW2= z!E5+g6~MKwKKyr{IB8cu?+^cAxYZ%61NDJv3sT#ldaHb(pp^^Ysif%F+!&7s}&BSP|>vQ4T*hGFp^+@Y9tTq$&(_!Ny)<-{#&5D~9RS<5m53npU zp4UFm^j6$q8j|7CMV^KOYZGsp>u=|)qWJuIIRmowIfHOUzdvUIBDY%$M#1B^yrZ-8 zvU6=oxsoR(J>6ryvB9gHT>4Bh%p!R>ln%R9e=Co2!|%FRc9SewR->$8nS--3ve)M&7I1}G#f_YcO6r!t z*UYutQ`P&$rwV9mTPT9ENc3%`Y&K#B1ax{5U75N; zwj;7Jvu@`9z{&Yjq9>zMnzR*-wXHD`hob+9_a#;?y&wD%dC|#HT_7sE}hAolC?DVVZoQ8)+IMxa?dVL2TwKc zFz*H5!$5jy6+c{DN7k2BR&CMr(OuB3(aqJ`G<8%n6l(bdrZk;E&7_hkhE9gMuRq;} z@{=cUn(|g?EjYyY#A2q3^10@hv9>)f+FWX1>78ZYlv|PfJ>gE&yRhAs_u3xHB1$f% z!7;yd@Qc3_9C50;Iy(XdRBqd>@bq^-kN&vxz4?!~KXsWya(5SQa&~mz@^1F`3@i?8 z3+xCU3QmXb%vs?QQAGDr_|@Zde;Wit8$&1kOU(z>J9%xUDb*ILwn@195wT=4l}H6~ z=8{c(#P0P^@ru}$=uc-V4rvFQ*|0q^drMU=bGLlkioMI5OB-U7!kd{_YfQ4|;(hq2 zDLonP#_q?ifv!1Dg=1Gia_-g4PQRZ0m<*=8$#?A!S^E9#_XXAx)>A1kE%bz~&(DUY zt)uXij}_L6Dy+N{mzKlmG_8)PL zaWr;}EcO+CEeICa3&QeS=Tyv^kkL9l>{sU>$H2WSGQMWdF6ikT;Jp?gx$k(Mdf`6R zi~5a9pe|9@>5oipc{^oUHKXYU?_3QWimPclskZohqslJ3#yvv`)3Hn?(wRGbX zg!5u=;wtsGtdjDYhSWDSm9m25i0mG#E)__slKdk{RjOOe*~sbk0>ethWoc7zw`)<+ zgaUb9nd~x|)3X#g?Q*Qh(onzPM7}>isvs`ETK?36j|GmR9*(Xqi#OH(Hz$(>M3px( z5%M+iW%5$;`LaXILFx!~069HubPU}IzG?m7JoAmY$*f|U(f7#Z@YQ&TtRPi|1Hvj{ zfOtrvl0HH!xnuXGeRySVOps`(wE1H4x>k=v+> z%rB;^Y&}lMkJGQH-8dgQiIcYFI7RACQgCfysba+OujB7}Qjf_rVv4j!41<%8PnayW zA~uts=t#vm^ikM_`nMP~!=)<6XV&H3Av*=i1 zus8 zi!3A;$YQL`--!xoCeG=Wh`ZoOvs&tbzdJ)!qF2FjraO9VFDe4gG9#p4;z&4Y5ZLjp zp>N2#DF201^f;5z);4@!)a{sv_%R9Ygumhk#&ix}XkBTjsg9*v^NalzO8iB=3TqT> z&okxj&O2WCrFcxqDA#IF4x(1=y%W3@y;t2jccgoVOY6>aFZGUuHmx(ej}ryARFm8W zpMgi@9RiLEaK0EOyuvE>FMce44r}DnIP+aaek1eA1mxvl|2v0+&&p8vN1Z2jLhZeh z(J98MFX;xDJl0v^SEEYB)lFERxHNHlsa>(_B5T^0n$Kx2FAy zz*pus<#^2neU8axs~h=yY*s>@q}`?WCHWI-#5|1nY>hLll|PlNA+@KBV`b5_!q0g^ z?%4b`#T833+_!wG{_lYXp|hbEq58pZ{#@@(_j&hvm&(=0mF)_6ay?0YUoglv6k3b3 z;9_%Bx`T2qmj;M=d<8z4Q*w6h9-F|8<9hKUh27#8X(+)HeaSXtRh)1(g_npP=hDyM zFR)U!R{2CT%<#+dIsC7fW(h-*h9xgc7819__m6HKKGIZOm4jXOZ0|GY!6H{dmAr$w z^YXhmUb{+rbNp1O6?YR3UvGqbZfIy*V3Dtfcc8nR>xc7<^KnVOtHcxMpBwzfF6EWt ze0Tu0CN~m=(qnPA(423ZcL-lke$ z1>RF`R8`Q@#zxlp;U}WE$L~peU)r49GHGJ`uc+Z+FO0cLktoFu_IQe83oZF?a*}hZ zVWm%#xeV$Z;~?cUQo$;{Kb@&X`hsaWlXJG@ zcP(1&?B+h@s~0@Q_7(#;ar{S&Mb3|1p|ycZKDj%``OY!PaRV#Gzg@-d6W&9ChwLUH zQ}U5d;o!A^8cJo7C2;ZJpv+AP_7AoV)(rU|`bmq(_BeKOb4osthCeq%M>&aN8{L*cGGTmI(4 z3B_}qYuz<{K7S9kypSpK;&#Mua`{Hwwa^lOS+CW7w&a=fkwbKjEg9x&={exr9K3~6 zeura?51x4S=CA5Om&uc25$&wFHt<~(; zg&TXCebzN$Jt7}Rw~hTAcOw2p+_UK25ufeNEQ@psWoN3q@GLOVJI6iJQKv{=SXlJV zp~n8r;vM6U39aM43f17lbxN3x6Pe>|=iqW*j@#*4Trv@@z0}#dgfAKF8RkC{Y|NDx zewVHjC&>i5h*}B%1Gou^(ZXEb%zX$I1?LCbh1d{>HONBrp0?ymtRWsNBQ$$-R%5>T zH{0#7W|6g{7seip+ZA6vesoNe$nN%G7LQ)3dQGnopM~W94xT?W&RmDv(GsfoG2Wa0)}bq0p3oFd zHow8m>@UI*U=gDB-dI7{{y21N4x4+uZR$(Cc(}Dw*rJj_gFE+!3B(a7Zr` ze8ZmNPoRYTg(|{cp5%XLcLm;h6Fs8qXh}=>f%kM|I3|>Qbi zX~^W#wLoE9B|l4p#YKF1j%K%q7Q>Noa;QHW&;RGE5J^9hom3`jCma4k3HOBAA~!@Y zi=7iEiwBt=(>*fTzS+CR3#PaCy*x%z; z#!ZU-96cxEk?o!7qAp4$(OFV&eqpezpG2O4Fjo!NEq51hb6;!!?EqrN+;yH5Q-wQ1 zCVz=v#C?J%>qhS*cW;-W{7_Hhn#{fl{gQm`}^FD@kJQ-|q6j7D}JeuBN| zfmABdOnM|#;Ma4{*|zLZwuBwYZx+T&47HkBrZ}Kxb=6F-Eg$W-Bh1kiVx`zNaXVw{ zL^q2#Yvqg!b<34;%x>uucQYvYPJ0Q@VAm8^WzSu2w7+7YUC_uL=j`?f&4m*$Rx=|!?Ao6Q<>gE z=1BELQmDoM&84s>*m~S>-Yvj?jGDrPDe9=V>OLArTdLUag}00<71KXmaXP=U6=Nr8VM=H~Al+w0?R0dX^VIYCeIkVH#*l*B&0j~Hr5gM|6ZtY+UTAk9 z+neHU;_6&d;K(l?Q+%ZOk>h+xq-U@%K5#6wfY(Z;$@A1JdLi={!^l#Z7xZEH`F4f- zQa$k)91)N4dHe-U25oS&akcv(?*t#j)>V9^KW!&@BX@hI>G9gAR>k4f=&3yhw~jlofHHn`PzES z(Bn^VK5$qZgB`7%YF8tV&eu4wIV9&Bi#>>UWF#C&$1-P`zD$VL)9tAQQigcP9B99` zV)xPv@zmjjhm2?X$Tg}5n(6x1raDlCu8H_FYDV<_=tWW2BA(h$S^hREb?=n7nF8Xf zaGI?iJn2(<7r2A&MV=Pk%ibxz-Tu+RGVEP$B)<~$%>%w4KaRT}dJs75Ym9L}%2fbY z;Kz;@&QW+$5BD_iwSpH=6~3LQB-WA7sr&Q@<{IiT5@(lp;cR2ZzImx6h<6aPS^$@{ z+IY4MW7f+l)e%jyexcEd+*-!)_Ys>T4@AC=cowF&<(m==m9-jWXC{ldFO=nu1uy!q zcNWB-WyRUu zam6E5P!p%0VANUuvMmbx7~VZ1BH~uqa@$YyLSqZPOFdqZNYtGo|q$6PhE&YCts0L}rmZ)r?_fyrQPMm-e*Y zVmfAdhdFUr_^$Bcumt-)OC{4%!+LEW)g{?uN=Eb(T5_*~JN-+*D_!<2^Y!qJM{biQ z0XBFtl)#QM27Y7z5?2W)*5ApLfv(1!kWE(9Q`Lk|^&-P3Q*CR$ zO&2yd%nq8rtVM5HV`!}FjFVwIbA+rd8HKBC!{AH*F#iaD2mg294qukNuoNxzSZdZSIKhGZTbDziGGI%D`kMrLEA6A7nmrMphbGTGpzofN`pC9Bz)XcCvl4O|s=# zUYk-3&-E(Z4)s#S59SJW2I|U%yp=r|Ob*rzih;zyEPpfqC%-)SJQxb9LmFgQw1iH= zjXK4D&=>E!=I!a->WTG~xF>k}c~8PA{chl0FccckErKs>SMi6~8T3J4;t1mBH4#&8 zk4W+$>;eA94qyzjO}?eJ(#x5%GP7crGEDtYvmPY!dQ%5WJL_TVA6C1im#KP0~>-4

!B=$m8PurL0nE>a@Ao&ZSuL^mPh?WqD1S63#LP?PT!V{7axSx;M{Qt0OwwYC; zU-1=7hQT_#t)uYBx57g@l*qeD#vJWy-O%c~TeXtzkD5)5>O8zi^R-I`duvJbv~LB` zBySQ0z0EEDcV%`Ej&aO^phB`XIYh4?L0%2!+oq8Z^nyx zFaGH%_d6drp!u+9HftZ_|x(whJ|M&t5PHWBn1kIJh6zj+X#<6fEN7}>WBw?HBm#2 zq3JZDy1&)t^Scc_`YC;NkTsGK?i~EC!{~#H?$_v8fpH9)IJNb6y47u=LdZ<>zo~+)t7n?r@nT-KH3>TOwDy? zgSOgvOTWoF=n>*Dis`eQGI;j}X-i@3OWHPPgZsU{*ST!Jq3<$2u}ZnG8B>W~G2MYi zdu?-Um)T1@X0LaL=?nEM))=>u`8zwtkJQ)bi>c`StsBwnYXx=-J(HE~OVHBqMm5WM zhpOC--M!kq&T{Zr;RN)3Zd2mpK609{2ULzdpZzxmxxYEr@ONt3F{g%JLYwX!)4RDz zjPedTD;UmIXx@`&b>h~Vy01DX_3K(!=Wctd`7#ma4eet_7j2bOKzv&#B9^PM>ad*s z-7mV1_JcFpeTTKhqKvHt#9F@SHqdXm6P%9j0rPvSG%G5(#7u=_ea)xXH@6{u{edx@ z=-WcXH;+S)il4hA5DYe-b-uA**SEMm^xDoE@)asN=p14>US-9pn2~KyAgXk)Q^Pps z94CVBFMAKGpGo>kJLFE$4?)Av>;*=IIIeyAqrf}DDQ}dupVr13`Sx@tL%*UmvCmVL z{Q>7;#>hWJAF#C_@oLx+`c11l(C%?=+V!*<#yaP$^Okl(JM9$H_qgleyB^LmtjiR= zjAmQY*~_H5o$qAoZ)x}1_v;1k#XleCyq z-)*JW(LQ%hJ9CMIU+E-5Fl2B_JgVvDtImh+8NHEq)_TS)Wwf_H)LU!C=!sKSNnhCc%${bf)9-VJSx@XjF9qqNoYx*JkE9*&i4-ZC{>S5y^J78Bg8|o$OU)^u?$BnVE z8}4G?yUv%f;l7o|5o?bX3M6ZfMAEey!H2D%V~zZ~^}JYpyG-Deb}6z>cg-7Gzi1C_ zZLnwTYrCZ0UbFR&El2a2A368Lwi=7H$L&#usZ}!)?Nv@l|CP9)Dsa*TdpJ>%n%2&) zueUd+IF7YXU!flankK&8W-0a(o14_sZ511@kMKPhTj6f-SJS_XF1G(lyl$Ti`PuRE zkX^}YXq1KfUZYn&)V5kn^knTBeWUw<^@HBY7>{IlNnc`D*CNJa?ys@GwW+?IPO8<+ z*yh_DIbfd)6miO0gZ&${Q`SOvJN-J%`2ud~?n|`(aCQf_I}NR5ZGrE1w|CSuE1H9K zJ#;DXpfND~qVK9P!XD#P(C;=6Mv58j^$z-L?px8_3Co-xLks-_%z?3=+{2m?ToB%F z&+?n*v{(ykf8Zr!dVV<2)qg#-%dN(4vQI=BTD=nbn|1Sh>LY?D?AJrf{1=Sg)^4Ot zwpLbuF7~G{X!N((=S4Tn?_wkL>*n89De_rNqmlEjb)RYYx8`@z-%lzLJ>ar+weP{` znOIVCG403DyZXSyH$$ITN&aT$z`XIk&yt@kC>guqZ>|4gy>I;$7_FTvXd9gG?-HpJ zekS4TgzdSHM2{3%>U7I1>Z_5k%laz&SW3;5BR3QE!D&PF;hAOa9%%usUEUTqC$X<@ zQ0~9h{z6aNALM@I`y}~5Y*$_t|DLqUIS&_%Nt>SVbHNKYX|H-?i%`O!D<9SgNn`9k3fk zGW;uz8L^4(Wz*I+gdfo(?8sR$^0L-Dp{Vs&q_OW0vwI{bvLeJ( zIN!;XKKboJ!x94iFYN5dPi}*h0kIO%60sqEGgv#k4_Wnb!pQs+cCQp8wm7`fd@Zqy zGc#*kplHg6`E~Mpr5*{qo6{$nP^^qLA$_&)>EaFZ>Sg?0^yP$}`K1c#CuRq$~RxI{J zbaeLgV6&8~p^f?73Y|~xlYXJ#Sn*E2)SSB`S*bm>=kha6GiVpIihi8XE1_Gcb|fY7 z%f#*B=c8NPUsArX59O^lTlyA9YniTpf7HqA>7Si4y5K^7_2fQg_59`5!n870a!$jf zPD$_OHY-@3QY(3N*8P#MQy=`>V5(u9+#`x{n+R(CKy@aPjH$tmZ zM(YK654%tJsbzksSG2o0m7RGB^USU6Terf0ul}*K#4Y8#7A_xboR(&9%vcq^ zocvnys^~9Hw%OjWqU|GN{0E)&b`i59yEc88J;wi8FHrp1g zip~f=m-wqTCvQV!AbT@@1< zIb>WRj;W|l%%a)b*E?#tL(SLC0Zv!@Yxa8S7a3)rH`*nx3a<^%ao!1hV6=~nwwnhx z1($>d*nNXn1C64+@(Y`fCrxrn*>#Ayi&~FZnL2rqRv~{wBV;&{tM*0hno-8L)>-X* zqE`(5>zf&VJJP@?X*Aa@`)gyY+tI$Ny%u}iJ{@T4Pqh0*=4z#kS;ijyynQ{gz?~m_ zAyhe1Dfwpd`uuzIW7@O9<-UsHL2lG;=N>Wc@|CcLMZY$C`5t%v%zen+p0GV|CQ{a3 z=49zV*k-Vnf2&(1znL{Dc+GgxdeqsbKk7D&Rrj4pm}l(_Uw04boul)uO$q%IzYnbo zp9?(YUbla-@74EMn)ZCcPl54~t~rm{-y~h~x3wx+6C$gP?BuVsn)&H@XU$Nd;(B|# zi`~~a6dN5aWB+OVu9tIPPI<=nV%Esa87Z$NF3fvbn_Vavs8#S~gIFF@W$Zgfj5Y~=gy({9E-wmx?9-LrZ&bY0~P z@vpJ>IsWKEzEv`xa@Jdi+>XxQ?mqhqKiN>mJNj$({mykG#q1YLk3FvU3N|onL$$9>z!h`S#MtF7_eK zE0`B)WCjv%YBfVwj7RM*k@mjINo};}^EWy(6VHV|$vtT#CUN#ebiF1Sl?jIr?XemPGf1TnA5~`eHqbY{iOdjdu)DJ>te8#w!x_s ze9-@WxJ6!_;G5?5{KBzuX_bTD790;PFggbh+B0H#{v(XxX-0kRb$h5Y)M(>-J-ptU zs~=6e$6qHr0;}#PUH5@xp#J4G|yN1a9NVD*rD(jFhHU}Jfk`Tj{-RqOl69_zip z5q(K`kG9TiALz;sm{rZ?+EVPS!OkZA5o4WE#rE5UT|YZv4fk*M6_4JIEj3H%N306g zcflfB58E~NI2){^_9^!+|89F-^eDSaH8&<(!(y4*qt?I167#VBr1M*Nsj<*}Cve=F z7~X2w?%Tfk*4Ee_W3qYMcs3$+GpYr;>Fc1+4ySU$3NlIR*z@#1w8hRO{S)grJI*h$ z8izKPt9!<%PHtg0^AV?R^jrI(Kxh4N>uLKQ_by*!{Ue)wVvNs&C)_Tf z8rIjo_Y-fLkJ-;?Lu1pOy@8v^(A0tw&H*Clrf5wJOIx7VVm9%9w2<|J`LXY^`buWI z%0*fkubJbBlI!OC3_WXE*+eLvu?OkZ{fXKvE2IrG_C;@mE$v9)J#&=ao4L&TSW!Em zon!w$vUkj_T4}p~q>b4(p@@Dy`g-(~Uc(&eRMV?!WzC)L@@Sh_753ZfWNg&-MvvMv ztijrs{-Ju%8WCM(J!Y2o$(|pLo!&8jtgT)$X`gvE(kjAi*1yCUWHvQMYDeu6(c$`H z^MtRcu~~b?I__k;)%2(JN#xz_wqJ2Ko5^~}J%Hz=BYuMh#&O>R`sLWPXbJmyeWdY~ z&(zOYy{$i;1x{Eir8oBl^;1r&yPv&0I~$|?e`trT8rp1sz}OLMjW6XM`#XECx!c#$ zo$jO=yPV^(Cv0XOzUpLvS9B*kqpZ13JKt^n6}OP{yL*Jpg;aZjv%}bEu66#fix?fu zU+hU%3H?`XuJZ@`E#J^yVlUy6#&qJHN0Aeii_QL#J;{Dft6*F*#xVPR&0b6XVUE2o zGQ-XD{o-3_HrI~E=0vYKZ|E(JgYI=xH)}X$Vy6ADe}NIu8?j^DQ1>2lxNnrR%>G^f z-u%;^VAs~(GrG8MTi4w2My@-?C~wx%qOnKq-`FSqYqzYv!g!co{yJ9G3Ok0m(QwI| znvVzL7k!)lKKmSgqpi{3XU*>&{ha>0QwiU}XuFOnw_0=yJBix|X zUteh+)Y{se-4@snuua}|1NSsj_8J5Sqd4l@or50basz+R{M{ofj`?S|G& zCs*6ASJ2})cEA8>xNa;+=QV)Cjt5LMAo>p;duTkgE>bkHC6J>dI?3JcBjAN7BXslIW@ z?l2yRmjjO{J{0)Ych#&EC=o0ZJRflUD+9fK3w^uUm;Og~G;U<>*KMPTZ?6A@F@Xr; zS>z3mBAd)|9=G;H|BO|#qLI#_dqVxg&xY5q!|#HETe59fba;15jp{gtoRsii|MVc1RE_S5ok-{6&4y6r9TUn?} zYMnxTQc{!uPWmWuQE&%4_rA+c%D=Ne`6IV241Vj-Leio zfk=_)fY?>*yGS7a+1$Z-ujVhz>y+!u9+0^rvrqQ1j9It#-0G5Hr|Y*;Z|}Q3E&a;v z#p%T}LK&O0f6T3%_a%Fjw~6R6Cw7m!S^t=^2@fYOPfSQC7ih+Q>0gZ+JEEv^`EcRx%T4q z{x>?_c>PB5jUJReeDU@Jndh>)=Z?#*oc~y8UGxUy^)CH$<6r-@K+lA%#Q#UqRe;BB zG|>}F$7E*5alnql%*@a*Gc#kuObs(*!`xuQ9EZU%^D#3@_s{jOzKd)7eA4dD&hE~< zc~2*3Dhi0!NMfZAB&m`Z=^N=JX;bkq(M5q(7!*^Y&vZMyHTe!y>?aYcKy|l2tbKm; zAl?!n84SZXx(H9;RNVY~xD(Yki3}S^Gpi zS>w`f)^F1v)}JsuFvOe2n7vkkqqlRGTk1u9SNxU1lc8C#;w{G?65U7v)rM}*)Pe}c zQ@)p<$~QAF>D6>8y_Q-)J)|tu8bS%aT8}g%t`O(&`n+*~rk;V$CXV3^$YI1I@(Q(w z+RXG5R0=IZyJ({1w2Y8VlGsHTC55tG@`tijl2-yPO@LD^flwe_ShIhrf0b{K zm+=H(!Cz_5*JMtm1fJ~$k=@qn;KaIbN`9$5LYSVe3)xMSbL_H+zU@20}g30k+ zSW`3sk)SoP!`OT5I(`%W@+#Gosbr$~+xYE8Ns_~|#WGYz%WTqo*;+-nh%X9-tgZx; z9+2!5sRRp|DReQJhqu8y@IvflU!Hrm=d;V{YG|uxTCL+WQ*;}2mvyZ*jH*rrUin$& zR+nhXG_2OHU1T_5d}r=p#q4XHTGv9~8UNSd@gT>oMb2U;2q!U^ssMHQMN~89te}Np z1EVK})JA$1bA)E7p=2b{9G{L=qU*3Pm=^7ad=BkE&Z1pF*Z2V%jVBQmW?a)YMZ*I=8k%KWygvW6&+NA)r@wvey%auM(i{hfS*<)THHhwC)wb1maw&D_dC<;yFL zDz7F^ds-EzYFm+^uB{!Z*O^4-7nY@#c-vZAfn%BbwQnY94EN^xv4eq8qYkTgbZN1H$V{MVvNQ=axGt=g1!!XU1%66(G4Nt#Gze2Z7+goGS6l-@I zCYtYAm)O2qYub+5208Y)CU|SZd3;Rpa8Sk`WP!(v_X>N5x4>&)ZLpu%H+(g*lN?S} zr#6sfcsAY{e@QGR_mPJoLf8uLf}O{zVs3mQDJKhXCBB<@NzS5EnDxv+ejZ;ZoFM>yEKRPqM0eZN#S&vbZC_?z zXTR+5yNWzd{1bvEb^}|7n*{t0hj^cm+gLVUhp^!U9>f~pBZyqG2lbtNK)xmF6OXYV z_K28E?j*Aa7Ut??>?XDk-$;HVUy)A2L==-a&C(a?0JDT&DXbzY6V(>i5H}P*67Q0! z~*lxl@5M(h?jGx0h6J~NM-GEM^lF8q&&K)7Xk#@42xP))O z#^Js3{rCs`FHl0Ck8Q$_5EM0tszWKMsZ;~zil9)`P~1|qPIN$gQMydFNIqTuhoXg| zT-HP8lW3&BC7&ga#RrAc1WlN6^g416eg}PyTnmk4clu9z8~WP0XE`d&GmS3{Z4Gk$ zJYA9|TeZ4^Een*Ns4UW?YmezZY1-(P>CPL3mWj4@&LhqqE}g5n=f3xs|61@h;3Mzh-!F6SM9{F8I!{Q5P52b-BsvZB&VNINWpl{pKLe%jAM6guZJq=~ z!6!Ix_CN>P1c@l4)V zo(oo4L(*C3;E!RJ(j6!h_6*KZMz&LMx%ZW)s(Yo=W{6#nw8m}5>o7R|y*diUX-3vWQz8K#@Z>s+@SmH2_14PPRIF$~An*AHd zEMzl8@(gG@h#IX24fKZSX~-trM~)*4foJI&)HeqK50L}WiRHi$wiHHcHqsKSjW;4T z5cy;)dL2`pe_F6axJ8sAekF;P$>qc4F^a~DCW_sPtBOQreXz$)3bp)~tVGgP@=!cf zyh5ZA4iNlcM7x+lg1SP#C{lbt{1e7+kaUaeyv#0-R&ZdQC*`N*U*wJD6J=kes5D8s zQgT{+OH^IBnLmPQ4f|3#^_1v}ZQ=b1Z5$ui;@jYHyJk6W+D(@ArYOS?-9jy@ou$Dw z9`$kcTa~(UqDrheuM--k8TT2j#&f3Q=Ihp}w%d+IPNyr&UE$vBP4r#&lYvXY18gaG zB=njW2dh*rau{ulb;UR0)xbtu5KD<1d@=lA2CUOdh`~fJ*n@iTPq21H!B+_}kGM`$ z1$!Pso+pn}#k2f`vL7-F25oFDcd1?1?#|Vd3Tvo z+D=?9iV<}Zeh~cPKVi;Nmx#gm7jy^Ylcn6Zz+2yGPjmMt=T3XR^@MqpDFCONQ`%Kp zi>8)lp85lf;sq$TxTig(Qy9)0SOac;VotN3us*i6cceLwxKwVw_k;JeuSUQY7{}5a z4prLK>Q-66UzyPkP;K{LAU|igr#6pusc{P zoYC&#$;2HZitI`DqT=a+%y<4T!A4;%QKq;^{97_ux=?mq9-&yMsHzyF=&xWDcjV3F zM%g;q64_^IqO`ZTt_Ty#1S0-TT0)N_@8hFTC(pzkWHSPkKif0P-NN?mU0ZFUc8MlIb4mSBO=#|DiZwg5@wycKWPK~c9HYSW+?-;DC;SWijX2taYNA&TCI?0$qq=jOa2j`6$yn0`T2AiHJ?l(YGNLqjYHX# zfXds#Q^j@DA-4UpEHQmGm~~IJ3pBmei&Z^Ul{D_~x zP9m2=YuMj`X8y%qiD#7Sr$cMYu>NCiX1Z=@qfgKc(;n9Z)T`9})t^<@pv@jtKebe| zT~kdPp)1y*2BV>cX`5MXsb|}6S2#Dgk~|jx)Yv_6G1!n>7kUcuy!ihn>u`zon=qdHRaM6*&`Ti0IS+%VO6)f689(e8^#-ln?9O_)}=P7qrWrCJ;+nT zH`f0>(1Sg|fhr|31)YwK!g~-j?6CV%*5QEJg}+HK6e0$Y(AFjJ zZ;Gr~x=zYSH%UH=GsTTXJ%l|3o%t=8FVr5gGlApJ(B6P#TM9WWA~4s-c=rRWdYb1mz6 zTZSXYIn^EMJ>hE>cpGdD84VI5o7b^t_$y*Rxt@xl-_!M(4a`gC47^q{6PX0&E4_;* z>8DgTh!S5Q7m;0I_BMr>>tJ#{=^#5$kEssycX}t&nokJc36=_5iGGS!iTMx{tuH+y zt(3;fCO}IM!mG2)BwZp+madg}#0|uwMWcjm1vLK$#FU1S@x*?t4SEJ**B7B^evQA# zyUBCf)ya9zKHT=h(#GsC&NhtFchl|A7HFzzo~S#imFirTO4UMrM%`ZXMzdSH0#>9Q zhP6hexs&C+wUzz0W3uaxdy@CAZ+75aa1eJbBt%-HBe5CyP@+2-Pkp2M(|2ew(}8Kh z^k*6})tR?2XGhTS^gC)boIG5xzT6=%kx$5rY znAmNq6MY$cO)}Gw8N&2s8ZogjYcGP&YDlNhpQu;VU({l1Bej%zO1+_k^Z@z{oyhEC zB>dz2G{Id#E8%0|Akha=FYz(4NHS2eSMp5qTT&=_55B6eBnW5C4&u+EcA|B{yMiZt zBjcb$l#fK=oc9D>qJV(+_Qb%GJpA%0I7m3D; zE(?=|Lk0IB_UwoKl88zoeQjc+ttP?c6_z%wT`rO zGY>Z%H@Xd@4WHp`=F)xDz1DrydB6wX)mJk-H7qoaG}ScMv{bS7wk@^abs(;O?oFPj zUV(o?;AXIbRRA`*HPRl9!6NY-d=Kp3cawfNgKmc?VLt5Si@{&LrJhqas3YK~mQ&NH z`P6P`wGN_I6X-p(haS#UFoPieF;MVIFhux4I7D4wVs!6&@+DLj!8c1R! zh2j(9&f+{#579lLNH|t-71|o2MRYV(1@hccxC`3)5AetK=VYuZaKpdE*T`Gw-tOw^ zOmtB8B5RSQ!i<`0nx+}E4MPof{XhD@Al7qQe_x+wm}Zb0cNwR_s76`htRh>My{TiK zbEoU0oA$Qz&GhdKdbXaRgLYp5`DBXcROFQV%%r9mD|1H0X;HsdO@UYM-94@*6YiyRdD~#d@@c?lv zaaFNbbWgNWq!e8fCI}A;M1sluA50`Of!;;EAb${MoR3Fg$!Ic?#$zDM@i=%oFvH)< zC-LUEZ@5-E$2bPq``N}@*IPcDrRI&MAe>2u7*mWABWkQ=Tx={ib~ELfR-4;fXsZ?M zH_x8uFgSVcM9)y~Qr}tsy}h8|5_hDb&RoGCWJN&hr*2C&l`xJB&H zU{?s2ZG!cgrL*OSd6l`ASqWoIo3qT*%wNnImdBPZR=@SS zZH|4AqlGiwMYz3?W6*dtzW4rLfk(kh>Q3 ziSEQ?*e~oR&JzE^XtQvx`-5Bt5eXBSMopnkQdU3@E`oJR!i)m{R0wNqd;U`XDgI}E zG2aIfe;41*FXF%BpX9HA7W$dn3}gwJ2lOD?M9rgYeX~&2YE$P~JT68Q)}oBgnqJ4Q^-u03OKWp}N4b*&TTW=kl|FE*gtn z$J`L(`xC#6m*6OzT*ngoh;IZ()Q5523~NpqS%n%x9R%;>p;G9M;G>VzuV^(bgltd~ z*li7ChBJfUYg?u^6V0&nFR=A#5LXMpET2L}Q1{7RB%B$*awp??STo3ftB^*J^SB-= z=6GB>v~*$Ms=pLsB|W|CJ>T5bptXo=t25Sl&oSLm*THiX+w<*}cAq`TG1PI<;e$QW z181h|q$|z+*gYKLM~A)5d^x_k{;0sSz_cKrJpqx-$6O1jj7bH)Hx!wQKwcAFjeZ3$ zH59VmKe1?hIDP{Efn!8tVj^*dC?u4yk61wdO@0UO6%R9a0=1bsL;XWNfgDE;c(GFI z7xjU94JU~6)Lu9j^rMm}5BZ)vLQW!Uk!IpJ(VHNMn|OcRh^++7#B$Vx3`br=mGfHQ zr>@0qW($H@!3}{te;xmBAL(1_HF*|!aL;*nd$-^9#I?h<$Ti9}+BMO&#&y+I?230! zbl-Q&0cED~4DtT*_V#`Db@PAp_YV{VMg{YN{n__yGhlEhfLrWsC<*um@9})#iB}_U z5ESi*&Owi%zfc9%4_kvh$7~Q|=?CYyN4Os16e9p#bqTVLWkiq=lPP2avI{u`uD)a| zvLTsFGNgsbCEgIH;8fIx;1gf*U2wWjf(+|1tT%>XSJ8fe%{Yv-12oS%K+3-a4l5J4 zmaD?OVh6J3;O=0*gEao9tWSJL-Gl zQ~M(Po&4+k5B&yzt-$2KU5Gt24$cYQ3I>Di*sXw(Na4nEcOcK-8CcMNLT%9~s8h1? z8bCbkI#PkeqJ7Xc=ykLhP-j`#9}rL411H-TSOMn2BzOXzj#t5}<2CS_@chxZ7{_oc z_6@rMk*JwiUx?W!V*xY=Jq=mo#(?N8Larbyk-kVOqK7Em9N_5*0x#Mg;HPUHqJd5J z2Dh5)!=-`U7PAl7BkUq}B-?_m%F?VM_&InlcsY0^xHGsexHPytxGK03UaNz9gC_t7 z^)6T*WP=fGEw&5%&1&{M`-??@UArf+-yQ-~Cm$k%vw_7c59$rVI#SDk)4l*W{?h@s zKL*g78;}#oKS&WoDG=}zQD_yk8rlNwg$_k$q6=ZP$3SMi7upl;fObNgpy`0fBv2#r z6Y7d?A}4`scOx<#=>uG+)e#}E#eN4a#^b;RI}75A4WL5H4?Gi3fp2UBJj1Y1Q((+> zgEGY@?jCTNZ|CN7Be`DOA6##)E7yXn$5rKIoP>+vl3>KE!j;0+=9+MAxqhHxumBk8 z&v0+J9IleHL95cC=f(oR*%82OTnB!ze5h;+Gc~n_JI@5v)N$atF9e(ojYL4N*M!_v z6VR6Egmeb$>I}T#b%1w18m=hdSf+ppv;;V{AHdjLhKjKZz!QBNu4lmWSqe2zMqn_{ z;k|>Ia2V!8PpD**{8!~$4%~rH0snLBzt>*ic-#fdWgGuv&szbUkL%(8m%$ikgm}Ox zjsWX=e5f&SV-Eua#1LR$tqzRw^`KWe0%!D4z!UX@R}ZlHS@1~*fCKLlRQ81#Z^HG~ zLa0CsYo^5k&r(~cpBn;|Y)e1|V;xkBt%mlVf~e@QKxeQF4 z7lF%iCvaXKg}SGcz$1DFIAFu=JP!P!Yk(DWJn(kGZVT9?ngTOYO<-Hk-F zx_}id2$hpzj+(F{V=+{+mV$@-2kImr0Ha+FJlX#%egCgIXo9Lk!GC=agu1~ngGpEm zEC#AE!}aW8O}KD1vJb|EfO{oDt)2{O48v8TVV1NopKyQR5vvDWQ|*8)Z6a?pprxk6 zH5HJClYwonA6x@~YpfT1zYWG`1$-A)Yik5dW7XjkIjCtg!97@bZUU^W5~^^+6~aHD zNB_^=QV6XGYj%g#0<}>27-lyKSFVQn62i<(VTDx&zQ^DvVa9?mZ&{f0Aj~`$R;CT} zHvC^nH_UkWe-^Va-&UBZt`R&-D_&UHtus7NYv2NF13v{WbofnJ!L1WKcUUnl%=O(K ze%Bg)Rv)aV8B|&}gxpDc7}a+Fy{{wuwiCQB%$nL8e%cn^7uFXG_gD-(6$+J);fm+~ z*OrItzze{R-owbe1G~8ob*$ImIt5mB8s_?O_<9zYL~p}&2Y!AD_z17S2!^?89|1e! zD;UY=z)<)R#xwUn-kxx6Y?uittdtX0i4Aj1{9ofQ4O$)6APl$s|4Mvm&@*907SJHCUj&*0wo;0kkR-+-sO0+pkufcf$uuvi{| zYX|TsZi9c<1B!k&a4n7kX2zaSFIxlD4y3?k$_Et@6ITM>?Fy(o?Bj-W^`RQBh;6{O z3jXcWx|X<_1|cLD`~vN`3$>&MmIt`aM^JZ~i9A4#ph|QmV&(lpR$`qYx|~jp08G

)*Dwd^c@QV8PqfC@V{5TU*!7mc3VR%|v}WkbLT(!OH@g#%LGe&Y{2FFLPf!A= z3e~n3pa&Cy^*9l7VG9AHy9l2A9`yN&&`WL{_mmqDdI+mkGwuRcgUe@S++NV<06iz* zwk46LD1v{7=;#gN7P*F;K+UJGLDpp%^BDGSRjC9DVH&|+wg93Gr|1LJI(i_zfjj{F z;f6#2!4QB{@#48p!Pde1{(9ce?mSm7`%2qu+d}(i>sL#_%Gzr>dpbus&pPWkw>eKa z3D-{dRqsCkm_Q&ni?eeNKox}nO@}{$fT9t)0<|MUQ7gI}JBL>#B@mzO!_Iu3E8pVl|#i1n00tbsN6rw{l=Nl>Gu9QtqSA=-EP zg{EBdGe>prGG9`_%dS95q0ZwrJh3<=;J&l*fh@1mbKBL&ao8d-Wf~3}iu4M7kztQ{ zvu&v@#%Xu=@FlZ<^BO|NK7rUkwg3#G0`eVM(E3PfF8{l*LYyeuDHlczjjD+2mrxep zF^OMAn|3d0OjNR@Hu;)&!PnCD(@t20*2C~zoefot2IFgegf2&)VsSfEzBQpj%!iMn z(wKJi1nMZ9c*f%$K+j<)FQ5JDx4VZrj+k=|GW`jiL|3NkWq4uAv`XwZ9YUAP{nS&{ z_c1Vwjplh#B_V>G^&D~!oXH*$Zy?Hf53fm) zUgc=AE=nq1fWKhtdr#Q9nD~Z!y78Jy%|IPvpbgy(e;fOoTRPhMwOl8tO8F|%L-w$h zWQe%0U^Y>K)D6|=_WJ{#nT`z0SmROc1oh!cL_JCKLNiX^z}(oe&9mRH3cg`CLv40P zbT4`UZ3UGmONbQ^Yd%B1Bv%m@$fkFqEP^!YAZ7ok(wN5a!xH{V;*#%Gai zqD(AiVvud_J*G-cCsq5he&ugeJcy?KV`ygW?AYNx=R3qUL=gN7xrQGtDV0B$7fBBY z8&C@Y)ou6GcYLu7G_BGP(YArOoKIa}Q?6~RuVQR#-Qt|@8weH6<+z&sOrg{)au7tn zs^I^kbzr|FMOVVEb{zT^PhmWwpsZ7*Hm+9kq0}2yhNi1BZe(7sJ~-j4ygrj1dhgz6 zo}kGsmlVg8ILr2`UTDu5-&&vA^Xy69r`$HI8M&T529!51#D2*$QA@!w@&sUbE4^A5 zWB+cxW2gc7ey*}#zX%w(`#cXi9`d_h;sg4a>!K&qghgNxu9wOm%@Uw zNQkPB((Ko-vn+L$2Gh`6q(M+1EdZ6Gv5Gna7 zttSh}h=?&U#-z#Bj%Nky4yheeBQxnvgoD20o2g%4tpEM*cis1ixjjp6R!-BE*}C`` zwgZw$x&$8KBgq@ZyQl-v{HR%qQegm<`={9YX@jLN3eOexE81Lgr=qWBnjykswB}ljLqAmSOpcWC5n&JfERffY$dG~|u{X>02eGY#rHy2+nNS57DsFd3y55))* z4kjH)`&fNNttlBN(;p-%A{eHBpsjg&xjtvX*J)p|oX>?VD-IcYIBouqTz7mU^F^E` zc`G%`8Y+4!9>_~%eMDybK;W?Lh3>Iw33-G~{=n4q*dAF9H_M3|KNT}3r3cb>g$%*-dCZy#7RLLS!Be*$oA12BVWrG zioJXbHJ7*1`_gh*Yb%>w@Ne#^+aOZylsY$reB^%qOmU@Rd(?=Cq4EyWmm)V4A_M4BcE2mq(oOfi za&+mm!m5S+iZ7M!sUUUHw$Yw@!2)DHai5yPSOn{Z3j|O3-S~5vENTVbA3X%SknOO8 z53{n*!lyIaM0=&Ua#GaInBurkN%zwuGCdhcT9?=XlC9VkZ;r*KT9qgLGV1e{AA$Vc z<-?5<&-PG%a*L>j@_yvZ$mx-?$epr}f+$*x_YZyX^s-IUf2;5m|5LcLz?gp>dg-!S zWvu2D2b-eX$%A~Qs3G8uuL>dsNz6OaKvX5>U{bUKxr}HbKGX}JPn!f1$u8M`WmMFp z*tEpdv@SL7*Z7?}Jnph`fanx@)qPvHw8--F_P40-+Mgo|vsIk6ci;mNDG5ftj-Q^m zExu{=RS8a|AB-(2#dYr0A!-~?ELN1z z8kTX~RXxnD{}ub1`RjLndD&`xJLg_@JZTa8BKF0EVmrpvj65V$h&IvN(LI5N&V{D) z+KUyDCC>^5=1cPX=L)dJb~DY>~dS&d~-dv$E2@#14=iz!tdY>$3`SKE8j`@x%IW z_3}mP1^|Q&6}YrNyH+UO3P&20cQ}wPqs;o-Mk)oHy6Ut^(M(T~Wg@In!3jTO$u6!cY z2b__F1Y@X5v>8_|(8jL-ya=D|g(%5~TsJgT~)8lythW7My;BaJ`o zJ$zZ*XnY9&ka&sor)-ws+JM2ldI^xY#pno zRQ;{=75l91>;0cpzlT=Vbd4w4$l_y5Qi`f=sx~=U5p`DRNA`Lj+Y(GNjkRoLskRKS zXjk68QlkB!CrpvH)*c}{2363D1*O7B@ny+eX-)As!E!1etsYv%cHvYUaJeJx@x$~X zagT^9ag&nvrV>?)YD}rqzuv_fTwG^~fcV#2sUKPNT)H%)Z()k+mQ* z$Z>pHJY4ojeo>Y!jugD2M7R=xd{K~L*M-_(x5?px!HUbVbyF-=qcYFe%dNjDYhl&r zu}{QjL(Lsk)E9pv*$ZA*zTKT2^*yENiXQha#?DKI#hy*xP-SH5%Y=T)O8Ok{qVKYO zyuMvUc8RFCxa4>FeARnRzV1(RvAxtC5qQp(qI-xN^diV&t`@Bp4Hh~0KJssD7_jUl zu_FTG0vCewkxkSSac<;@#Mtz@wZ1g`-tuFMC3TOb%vElpcX=W-bAC_x;CzZbe*ZH2 z;#F10WWK1CUL8x`7S)|34m{W!C#a>(&?>eWrN6&Ef1dVW<->_DPGvXyb)jO4 z>m8XHp-=f%vvHO+<6!!MghTQNWL)rXTY)COcyJz>>&{~esp3XuN$M`f>-Gxo1D4|{ z@LX!M;Ik-7QVHmUWBR8sAbu<9B`ufq5nmNn!RAH4F|}@Ncgb?Rwr{`raAo`A&-vCoI=^rJ`+{L5 z-zvZ9H&`Rx4Fh{axp-IpL5WKitLUf5mG6}a#Pj$)NhflLTOXVml(P=5Gun-OEIJys zIb~gq?)4NcZnvu5sAJ6oDbnaD`lMq~S-&qS&#jLpKRxp5%p)3xs!{S%F715?SiK-#}JsXi)^m4 zbL17cd`eP2LA;x(L+s(b3U2jp@&5=$gs!8Fm?QEr@nh3o)|%FMV+%`TS(Z0_VZv3h zE-+I6Ft5Y=E6>WFRlFSgX2-|&1^GrIsA0U315*N3^U{;j&!-%XnIvgM#<1~@#rnFH z4@xVG+7#^0Z&7fu=xEstb+n!O~&x z^b@G#W)LTt?m#*}Eon>oq1v&H1~urD`A=Gp#8--exXOuC?*6g-UH>;#-i>@G|2Qot zs&btjMHWknV)RLS)0S6_OPwC)RDKekL|FG@GplJ`-le#8QO!cS@MuxzvXkmOeWK;9 zo%FWhT422)PM{YVrA_2s`F44t3=<>#$<#1n1@;Fro3{+vhp%8xN&kxenN+*Fp-xdF zWBp~Bx~j*M4l6u}+7ewV_`d$#x7YpOJb07!VRVjJv&b_R>n+j5)=r(5HneJLm6EuJ zvKh<=B*7~*Z`61zww69BdR4e}{UUBrRN zY-N%3pr|_RQX1k*(4Po_GWfrAq=Xl-F1}yd`dVx1F?EM#Y)z|{&_*@~jdV`0Z1Ahz zhl6i_z1#SX_;lcRZ#C-Z&dU~`in)^bKILVV+>}3JOXP`*aWUE`LmV`{WJ#cI=1eUoRHlF~16) zWsXMNNg9y0wCdxu*-7^zuL;ND-2#iOoMv%FTG{vFqC%#4Q0cgerAKr3kCJG99&4 z)vhJokM1o^Lyy>dspkK_{$btgr|eH8s(dpGxW#1qylbBznN#-DuHA+ zlQZ&M*eT*9^_*ELd?yM*wS`ZdE$%GpEz}DqiTa413TudL;!iShJ z&dHzSXNyUcVcHImLwgE_bZK} zN2G)8QC;?fh}@ zMBl|$$zo}gbdmIy?1KD+th;Qs;%j7S^wHR-33F5WrnXPwV&fuD%fAZZ(CY5hhDYUt z3j)70a##E|=A6sVR_(Hxd~MM>g30pT%I}diVh%*Tkp9ga#(%Sj>$v%(VTLxok}Q8+ z{;D!o0|!08-X~bA+ZVZ}d!PCT22k*-uh9lXAJR(a2~Ghvm5}a|ak3oQCHY;&8AWHs zBjuyWInf(pcE?_gI~K1`xD(eWGEuT#P>s@aGn_#~E%oz~hK0_eGbOPlqe|V{MCT5F zLZ~h=Pq0{|6&WReNE-{X2p2Mgb9=u!y4W9DVvXB%UTsTVb)8n%Sl>}U$xzo+VYy^? zx;l98_sRFWb~@& zaWPM#6!Pw(W&E~eT{g{;VKk_=my$(-Vr9wRqBSM&HI;Ui_hhgSevH3K^i@<(_Eh#x z(2TU8Uqa`--|g|%5ynyCPS432bOv?9VuP!ji=6i9ciaD^ta7m`J=uV5N0{Cb_&xNwuQd1=9*A6;lfeAzu6h9N~6Ka{;cnN3sAM!M{XPM^eU+Y?H%QSY~Y2$G7UzTfjtE;^? z!T&9g4QzMIVO6Y(#$hGc6MPiurua||`epzSXzo}3uJ}jwMBCR;%`(+F+q=b|0Gxwn ztOX!00vLu$xb$EjzsK!y6x-fe|2BUx^|IWyHnnk3?|92y!^`vNMo%VUq zXPkxXM{h%%+(_E#WC0<{7B7}wlJ`(PjyM*1GD;HNC3Ph0ycOQdRRmd|O6NZ%4`QjXU!Cvo z;d*ZGYWG>jnGPEChH^u5;|cR#+eiCsN36ThH!{#Un8(%xzNqu;L%1#n1%Zn`y*JI9 z=&9|Q>e=g2c)EBRdmnrK-a)=5{^R}y{v1C)IE`(@9SW85=Ad2hyQGIMVG8&af(+4d zac{|fNpndK@B-`v|L`|dSxf^Qw?tMU=_H;kY9Ktp^r24TuaJIRARq`_@X*c~w(0f} z_I=hC)?>DS{f=XWi}CjGb@cxg7!KS}F@OhH1{_dZ*xtduf#?3l{$yX!bJ6_`P&t3O z9&?Jh z#~&id6sm;1L^+~kB2F|-bPM8x@0pu`2>Y8T#~jF)P&}Yit%28ockA!9dHQ+ox{aQn z-Yed7zLtU3fVODFw%`b^2U{9k18AE8{*J!0p8f6|*9TW0SBz_)Ylyp#r-fJQKOeXf z)U#_t^^q_u!D&p1Td-2VL4C#)*fFTb+J!KP53=-6L5VdJvPUkI#UA7NL{Dls-Gph( zj~BcL9O_L$mf$kfbdyjOjgo8dVc2W*4$_L(9gqXN0ZkDNc|#rd0&rK=LYKLX?DOF5 z;I81sz&pRxf88hX9rn)mqTY3$Zk{Jlk@6a_KIgp$eQo{kV0Io3rn1GXmAe2agQKB1 zP_O(Ga?hRNGDFVP1dO~o$Z0-+d|)fUL5Kji5{o`UA7FRzGsIA+qROSl&~Ip*8Orow zD(P)>H2s?DK>Y>C|3SnNoWef>)-4~fG)RLbCLvFn3xA(A%Hx6=E? z)7-Pxo#mFgJGe&zS-0O)=)L5-?^gu7vhkdj`v&700EN~#Kmz>*Ib$beA2&co^a1;U zJ;{y%{7y9Y54R8$wE4&mz{I}6Uf}|$vA9W$1Kd;!iI4=ji>Lz_tl3am%HrveDVj(q zi4g9azCL1tY7Id&W9&`tx?#(L0R+ymL`Oo%mq=bD*753f)qiHeHrA0%OIOto6BKe z0?XJ>Hj!%wR|X(@R&af}AbXEp$~I(uK~?Ze@GC@9Ccu-m0VGp3(5wT!c|drSf*yHo zBpqoE%HUF9VM#->5IK?wir~XxG!Foh%Lgo)&C$ug6t@?$mqqAn!0c@RcBxqO7Vw5L z$Qnp`Zwxhnaof!G2Ns#OfWXBbKtq@z%l;>1jgJ6U=O~-R9t)-i^?{tg z&j1$3H+xl z;MP~5PINdn7dV&(f_E=M*P%)1R^$U9Qmz6@rUIT}3OAnH$^8J0<;7sFselzZ2Yvk# zGW#w=1F9e@r;yPyiR5Z)VuT!5KU2F%)hKr=fz z6bCq-$*`taL#;t|{v2>21$av6Z6Q(#Se2E4MiPT2>Rdo!Ik>;Mc`%B}9K!{GZ^y`5 zSRBTA0N|ibaPI)uqyS{V0YDFg6&q!M9qA3|p5uVxDFChTBpA)Hz}qti@M)a^=g31I z0dk}^;6#pv#sh|^R;UV~i8_WRfKK8|(4TArn3Lsj|1d&mHlSh(VXlX@>7Cpy?lx#t zKjJ=sEJHm&Bisd4gA#BXqrrA2fr?~Pz|ZhN6aE(Xhn4XA>7g0$^*Eq0+@TEk)ZM&X zUQMvpF~}6?!4^mW7;WnTYfh8UQ*IcCaL?Fd>?@W8TfGW4`8m`DaG~{)t;lWUDc~h< zAu|AxbqlZ|Utu1_hOTf!xR!u?s}8Ta++^-N=LDVcjo^U-p-#}kV}Q9j3@k${L5aO5 z+@}VhGvG)Gns1!|M{^7iXFT9DYK(LNc8&%Jj@*X#B|?w)1fGj%{uacN{e2^FcFS z2|V6YVBX&VWK&obkb%GH1b%ZOAnMKlQmhiV(-V>U&>yXl3>bYCAeWXxD|x&dU>~hu zrnn&rYvEA1!!W>td;y)vuJDeFFguLEk>rF=cnSEd#ek8)K$G-BXeMa9hrk!U2TaIr z@Ce(v{eTmE0sPAWE&5)z;{&@o{0b!bt_<*asl!470_eACI^@&H()m!0#;}aZ!>s?$1p3O zg8uX+Kz&UEtWgH^yB1JEm%-QVho_hUBenqU*a`ZhC8)U80XDP5P#TQYc);ClgirOt z3fB~Ddj-s-o1l??0jw#EPaFbs#|vno+khQf3i`&?;mO-Vk0(J7jRlm;K6tJgfZ4hL zTK9F43CM2nT&I!wF!NYYp&kcMe;Mqz%YS#Q59qx$FcuEL%eI6WKNWP8yTUBeg1s#Q zL|-h7qYf^Ps|i}tTL3%6hu?32(b5BRT6Or$>IeyZ6c%XjM##Xi(A&#lMr#2lxsn?Q z$k4gmL71;Kp~ZUOlgb7Te&87e9M2x`2ThPtn3HY66Fi3&F95{hF2Dxq;pu0?)0Y6# zKZ?)@3aiUSK>F2y)#@Rk14i!uh`9x@ z3-}XkJiIq~0Y0)BV7$+98(~%I$IS#}=o=1)S@sC-F(1bHJx{}90M(fb{&*>jbRB3x zSX0Xg=&c~An>GSVoB%U-4%osIm~~HJ*4V&rTX^L#Yu&ngp3eaG z=?Q$N1lybf*3=$GsV#oDc4D>VS+5C!d*vxq7r;PtFcg^5g8vci&^xsnf-}MaIHv&Atc-Xmw@vG+n-56FAMWO$z!+pXSxDaR#w}c*< z1amSMTGbo*0~rNt;W1=CtVp#HHT2pf09|7*|Eqjig&kkq*g44hW;C1;Jy2!bKPkBH&;sj_6tVLb|??pbm?jVcd{b#^OeSvoufyLM4 z0CdJahs(_lfTt?ps)Fw=4-EzT`oWVRz(NkaIvRGnwPAm73r4L0SZY|)IRJ_RIIOA5 zU``wZzwwplg%t}h2rxh7z~Fxl6xt&~GFWr`oRNzF73#6@Oz*%G60p`~fbZ@Mp1Bu{ zM*^%0UKp**ureHj)%XxR!B*gXcns@NHu$O>@MR{LjbRO73$Ww010-WZSbrwL-}i%g z)CN$FF|co80T1~WKIJ6fD7V7CB#cO04!$((e~Uq_cRK7J3t;Xyfc{$wYjqp&O+n!M z9}4zY2>8E)uoqYaXvVL=C)EVz!Vy?WRp4dbfu|S*yQh4xBrA8F+rTXZ3y9@tKydHl zo&oAR1rX6cK_^8BEgKALcRTQqMnK~}g=bk7Y6Ek+9eDF;@cH*)eQn1Z0sVLiK3xm5 zxd710SHK7KgF9HDckY8-ABBE+3;ipDH6aS-$T;||3^2Yy=!^568n zv}^`o6Ym4Y`x89t9l+f7guf~R548e(pc4E^3GBcMxjay*kbqww99j*1Tnbvzt-x|t z0YY~Rtj=4&Z#04XeTBc<3^O?aEU+19r}Tn*9R|Fq9Q;@;%+}su=^decVXuS3nEd=t zFZ>W=1lr4scHIN{TsE8@x`tjg5OZxIR1f=w14D~K&oO(uh*p>- zdkmi~-(X&U8XEcEK?=tc_c0sj1rC&aLY~1``6K3Gd61mwq9lpw1EEv5v? z!lLCgtO&|OCM`p|CqeFJddRp`E(} z+Vzh@r|@mm8Wsa8tRSch?FSNY6%#TAe}Y|vKd>dxE8zC8^nc(N{TdwA{geC;{LKQ_ zu;LO5?trb<6Ik`1k$nJ}aThxmb;+U7F?>rVQLU)a)P1T3Fr=OWX`?@Lk%?uS0{N{! zP;o}Hoq!@!99BBU_I>qQAd?wtu_-u>TJ~9q0}V zkmC3r+=H+7?Xqpe74kLpjNZW1V{fo3PR`}AcVRErh7m5?cfjG6#i@Z zQsFa2A2Ck(1UMi+s_v<>RohifRZ7)ex?ZG*D|h2T>rSzai?QO z>h7o;DJKd_)+3whpXGXOZC`LQcWdUdv<0bOrVL4`nR@MAvy1`R4-8cc)>^7LJZ{=w z7dWmvp%*-XQet07&dfv^AG5nTU|#Yy<)`H@32G3LB(h$cprEKFm|ku5`$eXE`0EFoFJNrX<8C-AHzh$nJr_EWPk@~JwYC_7$SVSnwOecnrG?*Dyx{Fu=4j=1MMQivN54|{zKjYZr)kP*4)y-K6EtDh_PDPHrXxvoqrDkz(cul8Y~@_~g{WmVl)nV>nSSMC?D z11(__-wNoeSLsChQz}f(CNIJh(f(jTV6Fc%kLVm_{lqjW&zP&pp|fXYWn}Hj$ufRx zink|vZU)zrE!ofIFGZ8Oj&`4>w|cd*o#Gl0WwWVQvZuiu|4!de-U*)mZqfaN>$J0m zV~~BVZG%;9v6|ckl?o~p#F+}rE3KRDv94|2&x4(aFX`qSFANilsluw?)SqZR)C^FM zR{f?_DoNmXc2@)xU%?)?g;*6BZFj+`^Hm3xe~5<_&tP%97JX|XB<5VE1oH@p5>@G? z#H{eGV4{DYD`@??;HH7kUY3!Q9!Niw(JE`E;kD_OeZOaLs1<#H|3mmfe5CwAbwRmN z(L=tKHBmnh4P}kOCxhDq^#WZ2iGiX1eZG_4v7T8jhkdnmqdBvnSN^!XZ}Kd8oeL<- z1$#&LOAi1BhgZYZWc!gatQ8`4tPLra! zrD>!|Q9Tf!Djo}^2q@079`j|_jC$Pr1f%(kN}*F#mbIihWt8LfpL?`_=1wj>V#`zw$w6|8*C7e z`)7J5xjQ?qT4GGjyo*LFtmpR|+vd+TU$uAhTn!w9XPzruOCen`N0f_~gn{x?oQC}t z_S-wj2Gmx%BijZzjw2Kcm1Q*sZB1=6&1dRosvNO{;;g(YzmYx5e8_I$fZQVAB@7j7 zs8*?VLYA~qRuwX7d3bOEh-?Z5&UnLJqU6Q^h>tn+Z(@gk{aKfjEo4E$m zj~B4WJ;0l}%dqo2$;_sQQgdM&xrI7K1j8Le9|S1xA?G{Wbj#iXI&YR?xM7iTW&SGj zYuikh6DDn!i3&`2?lY_(cj15KQh){f20QgzskanGr@+$S1%FHNt9Vu9l~+}M;B*aE z9ul7k@ffLQ^H0%ELtr=3QNA4r#gD}wfL&Ey94uZ?JQUvXZMfR>l~7f$!BN3>ub_&d zXXb&lJE@alHdT=EHfMI;ujV_B-M)-)CAtJZQqdCVW$ndY;yAInf|hH!7{)_Z0ap>> zv_Q7Empjf`+z!M^bCM}JKQUjPzo1~dd9!V>bFOEn-xNAWl%bcf8h!|WiQB~O<+^aY z+0WTwSPQSf-eChk7hb^m*kfEd`5wM5*OGH^-=g#>{Al4<;gE1jku0W)vthIUPW)J0 zDzNf<{7%%bs(cvio`>^|xSGsB+4De4kKCavXp|k3{$=uSZ!%t=N={6pGRGTgTX%c= z%i1tmf}lR8>7{w6X4H4ZzR)q=Oiv^^;2)I^pM=eKJ^xm336I=$9_Y$*O?~ozG5&1a zoo6k$Xi++9d1is1=Fn3)w_K%|rPw0$1-9TS?lgOi8G$jpBwLqV&dukW${BfG{&P-X zP4rxNsrmt^&PhOUOyWHJ9pO8%tm=;HxQbORQ2NEXRw0LUX%_;1eXv^7E^UFMfRa)!QEFHFBGp4m(SSo}eCMRc=iwok7z~B`QwvXW5UK zE7WUZAHJKdnCsRFP4MTqA2`0W_A_0`t705xxL|0PCz=@BR@W3i?BS@ATt)dW!dk_5 zip|0T`2qeQTI3jT5}t9j_%wbVAH$iLhs+e(Ow0+pVUd{?GKQwh#!)6l#h-*Wz&OaN zKC0EKNvd07d*O-PDBlbF^XBsMf?4RKC@y9w`o{d2W$`)ifr`%4bM-XUF=ZX)5HVI1m5o%T zRNsg{E5<1j6i4Ns@QvB()Y;(oZl|Sfe&gKH8DFK`dt-RL`gKh5(v0r;y{ty($-s2F zgZ!jeQ(augYA!3kRZJ6Bat_){3gj>0Nx`JRJpW){YtM71%{CP{hT{u{6x=B|Z?ajw zv)A=J3jh_K?I3?FhyYv89mB+as|umhSO zY#Zc4t!357{d8q$g?udzQU%oKG%GcJwN+IX=s_pM7otz>sO%}>lPFU}n{b0a&90)0 z6T51l3aR-=rG?^>j&li8F3?=EEO@<`h$_kiFmvL`oJu>{!KXE850swg4v z#gg=GVm{FB-GTakjjslfrG^2Q@fX`8OHZ@eL|F8;xsK}YuY99IEy&A^Qr=&|i|Z9_ zge19*E6FWn&2%EQ9%$h*>_0VN4Xl;f4(|=^@HO)>P^-BRhh67I1kEhq%|b2F4m_yF zs#~hx)mPNpRBmyYm?Jh(u2yYRZ&DvqE>LWfx8+vQOUUZ7m4R!X?yjB=k7Z=R?}lqR zcQS41ebR}HR+*~oJBAu&(XrIKJ=BjX#x0T8R#a2;hx6z8+*n3Q-IJY!cTPG~EO;x> zA@GZDxYz40>HZeTb|vlg?Xiw8otNFM{5?WLh?i7fb~N8fzF%G!(q|>thB1)6$hy=> z`aX4#Iz-*0*8pj-DRY_nh%{gYDhpqBOJxU%Z^;GpA8eXjDSoGXt7@kn0z8!wK#oZS zlGQk|v3OH_Dkh3+pzC^;|DDaG5{a(ikAeyQdO#?s?Y`xRv28M4%p070Cwo}du8f)K z+Kd`m`*Ww8b~v_rZv|t?>TCtx!}k|5bYiZvpPi zP4{3|$l24i&fVWT*v|%^htg%UsPl}KCAbOf8Kwhs59q!?8UeQZSa>k$%q(X5!iUOL zx;lM@$|gq;()#pZf+hQ6kCSBk^Ie1*VhiOvpv$fSR?KA8eQ;P;@r5ErY$NU!Ux`&P zZ+#01>1F?*=MaIw6yE~RM=s7`w+=MV$g^Vp^(3=&X4j0_>BTc*vo_?8&);bUjG6zF z;6#~`oCK`)(?CYsN^hpl!!9vEHU)M>C8`R!i|CEDv+oZ3}yqY_!Al@c(+kHzyuVo*?_HHszRR5$d zkeh*#{(|gCXVc$dmb8G4VOKD>=*pB|b|n;q4@Hx&f`1(L2{#6|2Fu|K--O+Y+xX%y z4XdHsL1(ZRFg`cJvqdxVJBk73+zs{uE3yZGmm=-(FUS7#QEmxj^&*8vnWQ?ZdW@O! zJ)juP!_K}Qv#M1JhpS)?7aS ztl{IF%UP8(JsGnyPh`!@aTq=-s9?R|SnvMT+tz<4P$#qytE0!m!)14fmt;LUmTknB z2Oi5VAkbXp2eMk`2z8zKK0Fk-1<$c3tqRSB9j^i7%AC+)@Mx<*f7oi2@E!J@^4|+| z4W)*)gr3}u{rM~f6DBCOiqn;u%1?prI0Ih*3RPd_CDEn$Sg{wa zQ$}v)Tk;#YN5B}CGY6;xWH$Vod>n>{#egyp^u6{j^oZ_>`2Lt-KWrOoDQ4=PzsCp_ z*qk#t+kh|C*tjb1V8M1vlB278v$ukOOJHJXYIuz7ccLuip$^brF_~-^{yX`f^2_qs z@~OO*+s!-$uJlnt34gim!`WDEpNBP;2B9Ir1%YS&(a_CE^iB8H^RDxz`W^;4hAxJ? z6T_)6ozEn2rT8mA;d;ccmd^$P-fH+ZU{(86Klo%CJw@}4hUpF68Kc-u}hQLx)s+3-Q` zyqw87Lv#Ix6M3r(b^&=h-7((1+dI%-A+RvGDZC$6$Oot`%w*vBeJEE7OB5x=8H#d( zMn0L>aDA8uSV=xbV8;yWN9RLLL!Siu1_t~0`_jD6pq((p{fm3LC*PChz3vYM--I_2 zB`H7s1!kS8+#<}ICkovZKZ+zU(Uxe2Yu#F{Zk_g1O+EEKc*2NRm@!upfm!GW%CL*k zG6HQSmts7q2Lzt^!P|jhfeFweX%(mn|4bEp0nc#HX!kxR=eT8SZ>?r7R`6l|_`I3W zt{P*QW0-1eg7t>#mWQ@duH&9K|BHYIIK&Ic8gwJ3H#?Tw%r_Up!ed2Gag3-DD=I`` zI)8?}Kwl+~$clyOP#Jg%?F_~KjlN`WKd-@a&r{7)!}G?Y_qBxXkv>!r-bsDbEG8A` z+VA*pt1G8 z$Z4HB-B3FJzNxEKblBX*1I2-udX&)8mDmp4E_j!iBCJsqC^E&cs8h}ZW@|h7cy0yr z8MT9;B(KTASy&hA7Z3tZp}W!8-_>^%+Ey-aecvEo9sj%l6~gWw@rY``gn|CyylLUf@NMy{gJ(leWc$b}^h2gKcbVTO&lSE< zG{YB@8Mdo?ph5aZvtRSMroG0hF0a0a+J%H|@&ax(JDXVs+|Zv$l01N2p^k(DtGwyh zH(n;o#{NTtFgy)~<^}!!!@joOY^ zuZ>oi_r)u}5le}FMZRLaVuYfHu#WGCFP75m1g03%i7Cafm?v*yCbRW{m$sPw9rKq2 zW;f7!R=|(yRHB@W3KziN&{p3Wcd}!cO|*0~eVFeyer;%++a~8s*2b(VS;e!PWs5n! z+&THLEE;FnGbPxE2-EHOoKkd!aFWcr286 zk<;?FKuIXZH-ML*d&1Yk0L-8I@GrP-oQ%86rm`oY;l}cUd>)V-`|%@ygS7(q0b#l| zd>nP6E@I_+G%;KDER-Ku=bPejy2?BAZO1IfOqUC;<-g49k+;Iw+b}(6N>=&I(;2rj zC*=HW)SDLACc8TLzYhngCcH~%rD&swRpfvxr;0yfc6vtfMre=kSBASqA16A6I{7bq zhP%^TN$!j8-JX`-dcLXt*8w`Dgs#Xg>~pMU4w*d@$0 zx;|ZrIswn%`N2DW#<#;W)U9=Ga5S=)uywLNwmdgCGk@IPQ&i zt+DYyF??$N$vWS`yVrYn1eS&mk)yF@F-LBY(?VZ?Rdg3eVWukrH}ImOvT%x@$W><^ zkpbD6&~2>B9rUjWoDNP1??F`L+Rcmpd zd=U4Fo=J)HVl}Te4>u1okFnUzf+@{t z&rQk6&;B#(O7=ZNZ_`-E3crI`#tjv(Xm0C{V%2AYs=o4yuoxpzAI3x-BNVb~L7i`r z`;p_FwY9mtX`Q*V&EOd0c@$Vk>|}ayKKV{XqVhxKSjcakz$mr(uSl7Q9!xnJjB=*#vdd!D)1LeH|bI}RvoUwa>UjovfRmAwtGCKc>c z%*zYr7_aAko1L05IK6M$-Sjb8M~ruEChuukEmo!IqW)Z8KJIAjM*R$|#tho*Mp5p_*h{`WkEJIfYI9QgukZQj@MZrmd+PuG^!1rhcoO zrFh6sV85Y9P|t`P*k!#S+d3YGB-3V zp!GHMeBes88?1dzH;k8Z%4BbWkB~dL7jrx2_~4NyHlr-8hYnj;1}?K5H5qZ+i;XS0 ztfafxpt$eVP56d{(YMT1%we~kvwP+;jHC-9ePREl;2gJ*LIKjDQ27g zqIN#|*$%~3ei}OtXeN!}y#lBhL`!Jrl_AcO=jh&?C$znX{T=NXUZiaFmK^34NWokM=s zugZ>jnZT83SE_pP?6|ucm*AxzhHK#4;+p@0r?2yY?Tn?pdAX&feYEqe_Yc`q{-*kY z{z%-m_^z=NwH1{;<)hfzKteo6^`Jz0Hd7tgGTB&Xq3Ox=5%#v+qgaC(&tsKV`9MhH zS?*K%BJn8PAXF~+1!kiS0v^ntvVk6GboFv=b}8H)+{N8CXIuL>=KcBC47!}k=~*ei zzulL7BDHb$VS5|0rmAFo>EiE7)+^B|VWR$5^>RNm zlr9)(Tkf?Ix8X8ff^g^p*8Yc79}? zlYb(2ccwlqF6I84=dbI%KKs^{k!M{>)zA(vR#2*RnGq#D2~13RjZCOa@%{#md*&(m z=iy_eq4Ag85;-q(^7GEwrupSeD`lA&cl_$a;Ys0yr*YrvHj7W#KV*);Fn>AU9`8QS z6xV#m16v=v$(iX{8u(RKnK>xbRxj3mq(7zoTK!6~i0wylKppH%b*28G1o*sp%Z}ju zTtlFqvceX{Y}lwS(sa_qsuYS%+<5vOA(PF8wp)2RYOSn53}7Yt0KFV7G>@=2>Df z`8};>w{m^4K4?_D5@#!URhp7lek^i|tMbwO4t57Uj+`Rv5xy1b4$TESymq^=LSh7N z;0K|mK{JpX4ZvEi=XJX3J5HIu%)6PhIqQ$~8SgHqOiBGT+4VY{%o-MWC-Wb~{!(&k zneL@a7QYrhRzE__pw9>6UA(1F-XY__ypN1a4Xxo>=0W~V8|5EEj~9#UXU6e~GZPyo zJd7QtJ0$L6WwJefr>B*>EaX6Y$6-4KKAqzZ__l}rbV;F|%B2~sYoW_je<@a!A7kE; z3DA76OZ*8vE*G(hn$EOS7vi;p zVl(5vP4LDSj~k#bu1=K;v@X2Qx7j_=ML0LxN80XLH`~1SfU9$099dT0K-EM$T7OkX zX}%Os@+wwC?ZN8P6rvk-iW$l6;n%b4pewP8=_D^LD%GR36?Hc?VO34+)J>6>$39mx z$^wnCisWUoF}%Ij1u8*8U;%JBKMAA+Pls+pSEOh7i%@faL-$YCetFBY)tNKWtE3)y zd*Zd})!J7tk_YD933OKMkN21CS2nS9sig6-)3uDE58W}KaCSE9@;KvWgERLA@U+hv zc9^o9CqoyxmUAH{%5DOM%E_OXl>)9<)x>UHWm*it%-l98z(%GE%hF>4#*p6 z$S`y_R>^&kCC}cFTTt-W^?(?nsGzG9=Set`I4t3#xHx@hRS!N)^ax(^&T&t7^>Px9 zIks=Cw{4T0>%AL82dNTr9zHcl%~cwzoMuS%{x>ty=kim5n;Di;^m77>WR<=&D$FY+& zd-$cqGvAMnKTP9|lMPpMH)Vg8^&soB+*Jj&oSC8hyiPMOc7B2)ad-T-n0wkB_WlYSd-2 z76FY@QVTCddpVDMj6x;GD&y3%vBSGs^HyzFY7`Cm-teJTpLz^U^7~l%QbXIVyzB|I zq7t!2NrdM^uW~o^X4?isUc$Z6KFEA0FC(XA2Ay){1^r~wgD#KFsnzXG_@so+WqVX? zS8hV_EAc0EoJ!#KhKG97ZS@Mu8hhq;%g##w_}z)Ld)Z0mLtc(Ks;UutF#c>pQbO;z zJ^GFswb+%LO4>r#;i)Xsxyg3W{7XTHg16?c9gBTNSps)S?4WUKCTr%anv3V;`Rq-s z)g2;#AP+&GvLp3`>PhdXhS86PC-iw(J8{Yl?VNB|I z#{zj){DrdV<+IBgOT0_$9OqGg%*~KZ^=NFS{71l}JDS<#-Px4#@0Mk`3I=$G(zC@+ zw6a)TeBJnpaUaKA(khida+|0HvaDb+|9ZE^@y0wSzeoOlQ=Gkpr&3T&>G`8#SM?!y z6`iXJDn{}vX*H0Qzhc%g$7q5|m-P(~k`00;MQgz)npGbIyJ4rMigt;{ry3{5$t{eA zenB;(i_-_FYUDuKS**`~9oiEvLp&fiVuqxm?Bo&hxXc(h>M3nsYR<^-p7$cBV!Hk1 zj}J3%)xG!8YrT0CQCT}Z=}F06C1R5XB{omkq@OCjpm&E%o(J}(*7*fXbJgj?l5fAA z@veF9XZFdVwwyt1pc$h(sc#xnF=l{nwYs`EhJQ|L$@V~|spjr!D{X3+S1~UUHtWB6 zSB4icZhSR015)`gp*>$5c2#lmqkK1x;$AZosm`)C;SY%;R8OWccSh)=OaPAiIdyrB zRi#u`5^F0Qd?_xMO=n*+?PwoWjcPzVg3jd^;Tq7CZ%lqk#nRuCrODmI#qfl{N$)LJ zg1x7CWBy1(zs%p?{Q0=`9nT%ji)IG+ZdXrC{HA2r5+joe;#!vARak*rhz{lq*6*D|$nZBg1mD;5En*WndB(?^uuHUWm z^XC~Z8ahMwXS-{5pcx52o}8V}!n#RU1+ZgK*RbLaY~km#0csCH$g036W@|c!=>)s@ z^7!_jBpy|E#`nh?gbeDjS!@Si8FhDXX?K#1EUYY{F3jmyfg<@gYK`3yOnoI!5F zw^6e|UvHfIuDze>&z$Y4#h(Ul4!%+0(ZjSkjA#xSMH6?(q8J>r(G(8G1Nw1Y0xrgbMHq_6YN`ke<*V(Dv0VR<4v+VQR?w z`#RY(^LrY0<&4j*mR|!_#5Y5ms6pI4cvhGIKO#Hjb%f;#m$*mltcaC&W8M&(L!F@^ z*9t3vBh*E_fYEMr^j!quFb!QBq*)@OB|t@w*}{oEIi3)(dO+ z<#at+<&YR!6#kgR_lHnZY$Prcr;9a2TKq#SulzwArRbnAD6H5yR|zxuBz74!6+4Ur zNjdQFTQgmmf%rzzF;kcVss*t+_}p99)z|i* z^ZJ(K*-z-UR6lAVl?vSKtz>`LL{_9qP(fm2m=CoImJe+64sc8|El7`fT=)8{>&2fa zG8;Rl)6bQ~v?aA^nyUH~eJOpCzP&cAY%gT9cga`2uGalIl~Omo`u)|cR57=LWr2HA zunp0O3NgGeO?5{5O8+c&YTWGDa(chY%==|B&jd@=y!wV?hL$ijyJLUmQhDEbyZ9Of z=7a@$H6JVHt1{Im)jQP-#kKqcswI4Lr-Wrh8OlfZU@5G9>)>TBz-DbCZAeE~kd?0-vdSsxPZmsJ{ZH+W_4Z-C)>PuNKBIUx$l(juf=W+>yNY^@ne6 zze_R9vv=|R5qgESQUh~BK2w#X|2lSV+~&BAF@zs>CYbBm zwXVCKalYyPcELNcM8?T8$`7^u^wYH2;!b`#eV_OeIv;PLTTllra+Kkf5JfTd4=N?)qK+kVK-;(n)1<+17=&A5O*Olo>pTHj6UU;M0 z=$r5CYAT*J_Rkr&DqJuBApYG3+bU|0=BJqMx(Vt@>d`ujZYIzPn(3A+llVnc$>3;P zo!klU#=fcgnopUTUB`UWIol_On#(>QUCazcOHFtEs@N9so#Q^&A5jk$+EJ@~vuy|R zlMLP9>9S%0XNj@3b?98z-Ccdz!P(S#KB)LjwHUYvcYnZ5FEN*(5Dqg2NQfn(@) zuw1=OeFjWpLiRS45?JHg=)WIa0857XL|JAje?w@Y+NN!&pQIZCkFc{fCRGYBz-Ecx z3y-kE-iDhC4Za;rW%@gE7A!<)@*(yGe1WjLk9mB0qbKC8szW!V0N{rhgqL5ttq-~54jrunF)ykoKVm(T{X30qCb z5sxXiD61-4C}@5^bC&*yc2Y`sPIrZF`aJH2?rmE~}*P2lk>WpjxU(rVp~0RgGf52G)R6=T?6wugV;j^>@$Ai%swNcI4Yqsh6@3 znKwJyI)^$cJ3eup^v|Jb)x?-p@j@b>FeY}HwwrPie~|diXK< zy$mmnm(49*)q^#uFgscPnc}>-P5DMyTRC6R7wBJ=+4FP(`8<5qU%|7;Io7ewk>_mS zx$K)8Tp?RX?PssbHOg4c5M5HtxY&G*bU*87Xe+4qDtAM#=ucsgJd5kjwu3*{#^;0zWSZ#@rm26hn+Jw`Uph{@P9w;cS16=L@w8kiW78CR1T$= z-%C9VbaOo_pwfl6gWmp<+9bOyw9}?|YrFS2pSf!X(#W!k2Kp-rccIVSEdH>58)R)m z^0~i+tG2zVy@dUU?F;K}lbClt=S9x7ykfSRz7B+s%@yv61JI&(;icve#Tk?}f!_vy z)QyRkfkvJYj^egM)={>Dj>|VmaCb+zhLjvcV9doWh@acD_QjVq_$gQ8RGACL`TOJmiFUYW|10(2= z_<79O1O_X1RpZyjoL0L99aoV$5snQG^f&e-*?Sc1$Q84$XI#o^nRmoG%Dp83i+}ne zw^ul%{78LEJx+5*Q&lrtHCmCz?IM>2G;X8qfMvS5f_b`ShwYHFws&6OYIr-D&(M%d zO*QNFwpe>yT3qwEV9ZSYJ?#MXYtbpplVkOiorZPWFqK8tAl8PLhDyRJw>Gf<&xF$h zf`_&wW<7s3;pwdBeKY2GRtrb8BUL52`0#%p)NcB{^SW`j#4%$0|d2eW--H`iB z`t-CfaxYpRx!mrp(4O`cj4ilgyW($6U6Lxw-aGe*lPF3^i*d?*&HO7ZWtl!@UZ`i3`F-aUZlwuL>L4pJc!IUb;>> zez*T*Z|kV*TmT=^?c85^hWq9QmV}4X%jI7w9l(z{0}szJ+ABc*ey#IsJ!(#AkuTsr zW%g2?h&>?%c24>QKgL(~YG}sTiKkRk?5T!c||)-s1}}OZ)_ZuxjVyPyyEQP-RRZ1 zWwx#PCyhy#VO}x3kS->qE7z$r@NN7;bx-~y{K3|v7t_O-L2M1WN+=QL2-Qt5^7`a| zWfttGo%=kW2I62t+5o%A3FK&cDqlxw(p=Xq*R|H1RGeZh&_-w&J|FB9$n+__vF^#v z5svlfFOwW?-8KA4;Y#F}bRydv-s%>^zjtRvf;dlX3Js+x@=M&u>}a|MSxKf3{|4Lt z>7nxB=izp+-rh^>1MWj_<_+7N-zYDq_(L=+<*L2PtKtELPI$!?W1bW5g8jTt?KKJ< znZdVH-z-nxZL$Na)a}jm&hg~9e+w*Nj))UfX_|w&Yr3FDtEw)Hr7r{vyp_E}y}x_w zdV{WGwj~A0#@~!L^Ddhn*{Zs;eO*I5NiqxJsc9IjM%K#LE8ZwO!F%;IQIso~MnuC< z<-n)DN1kc!(XM^Yiq3%Jx#NW6L#NS|17T?;hdSx$nAex(>Q1cdloIzgq|zm&{=KP?1*e*S6B@Vw%T<^(U|< zr_;u(mxzPp0{bT!44(?7_M>O{05H*S0;?WGVcu=r!~-lT|pm(Ce(6blk73OnQ{pnwmHZtu)FxCHeE+Wpp2KQbPAg?Y!d{?fj1MJ*a)K{{nZfF? z`Y#CefNgGL_>gIVHIn+|RI&?cA%1|R=R5Z(DuOWo_p*+p)VYX4th?H<=tbO~!O7by$CXFVq!g9bA zu0zn&V!9!-hOP^5Ob6jpcM=Jlg1~FV^k$!?T+-7vx_2A_tFfv)~np5m_Y-dTiK z-T_~!8^i~y=c-=Hb#jIo6e{lf**`aY8CVLPLZ5nnu=O=D(AclbOsBJhRpbMJl6Nq0lnMaKZg8Rr{M zR$!{^OW=%<(7y;n>-1B0DZf>|P`;I)2YZlsrXSUv=osDw?WjkZ-P;g&!=8r!hwz$agGJ0)a6E;Xhei^xQ3W2)notKIdt?QF z3w|3M7n~V91fLkILOd*dYr%500<1F~go-o~FNilt=?&0OrV=@@sy+d)Ke5uj4Jw(VlgRC=bj$?t}paP1)e5`z`fGu(a*06nmP;d!0;LA{-0q~FIB@?I? z)Ckb@7;FOiQWn@vwk9))nZy~`TYnNh5po7K!5#i;-sjG1_P)+x-Y3Bv89_8AVDpca zoHerRz|QQ!CUC9!TKrC~A^SPKmS`8=8Cnv?zC3Ua;$&NcLEjW_MeiLi<3Ap#9qI)u z;?GcuN3f~y2rK?O#2%_N{ApLGTahJYZJ_fuB)|tc!n(6rux2m>zhPJWf}aKkj3xLg zJdIdRdPpmIm;44OMFPo@P2lBf1mr<`f|JbxGVoN`63q+T4U`Cu53UQ|3pNIQOTaq5 zi7bf_$PD-r`5ivzTT<`H1LSUU6$xxZ*q1wjK=EU!SZHgoaxeq2y@3wF4e&GO4weO8 zLMU`Lyj)fZs40Wd@@L?`K7p)FRw3=6lnxqL&*8Ny9lRiirs@muKw9W3_-AHlEo{|G z!FKj{AUcGw2mdu}trLI~P?8V`6Lw%O0vlr{EN;E9$leLFW}raagRH-qJMFIXn`f|c<;phNtCc5eVoff{Jn0fj!L`a^di9_#z1fwUlb*m(@! zJZ|vFFF-XI1az78Seq(9;T(jPEcmZsSLtIQt}MYmN^SHpEhsq?t#J%}a2Jp+dZDI4 zV743t-Ty!xGEg%e>X?Cb!OAF$WREU+@!EhKC&OBN5Re+m0jD7sNFFo7Er3eW2sLSo zx{SvCMj#4g!Iu3g4rjO#YCaw@KE?S{@I!ytb^C#4AOj-G5Tra8R0$z`3j6_WgLU`` zQ0FKt$dAF2{3c3L8>k(xWHj(K3@F2AkV*AXJ3Y`OD&ee^QP6!k9iECYatwSnWrpKH zt&YGlC;@4=5WO}T(&;HMHWmSEU?|!!5fbeLZ0)~6oPKEWX4w4%em^A85d1eSlud`B zpU7bE_k!$Opqg|63cz!qmQ;e=d>qOEs*Wd=gT2$=UrU4R~S9~dZlc!+buCVV20 z6!Ou#o@0LN05|=Ly`XLwF%n??-vn0gyAfNBx+kILlDDq9pvf8FiAeD|;x*7EMxp&< zU~Nw#XB#+q8}^h2BaQB8ozQ#;AtZ)^$)|6e?=k6+i8p@A;|eA z==)vKOBbS47l9k_0{A+s5QCT9Mjz`7#IMRozYV0u1gx-+1SRL92V4S5NpH~60i?2FOp zOI^{Y%7I(L2qk$!9D}xq1Aa+yl%O{70_xzu73i}OJ<|vZl|kElS?KlcTVQ@Q1BOrt zI2YMym7_o;`UK%)AS)8Wb;0u+!KGzUtI_BiGtiz}(67#e0}g_FdV_Z|As0ReEt{jJ zy@9~-DP(46&~hAT^#?ei8p=Bp=m$TdN3K8$gFv;qzym2JGpd3lDm!i%i3frSQ_JBL1hbKWw-v*_|K+crJeqt@ixk=#T)#zoL zL9-{2t4+|GzeenZ;Dxs6PXu&wpFm!m0uQW459y8m(FmoT4xJAP%|S$}WgxQ~LgMrV zWkvuuqdR&{Meu+R@*o))5-*U#ZKNT2M|%d0h5-7y(Js|aY&#<%=cwLvyw_d zpuA<#s-+8`#}rE8V(7;;f$-4=600L<(g?MRM{E^JAVvGU zum%h&NUe~Cmbwp`KLmyH3+X9QltXP25T-d|^u+kp9BD|kERLs1s7E;*rBPzZYn=@x zliDYtP%=k6+m%C!s-vwMqt!bi{zo`E;;sThN%fS0zmrkQqu|GN;PJhXb{A30Y}Bzd zxT-5^HVORsgX}1J)H$HCEJ2-{Bj+$`C3%57fHCVND03UJUW3ml|>)#h4EJEira=z?jk+u^ZuNjF#+*k+vU>k3r+MXr;#BjPl4kh|%~l z#><14H|@axZuG$4&_mL}ja87xM9h)aVuW1>)E5b*>J#MJ0$5U|AT8a9`x>LER7VNx zL_ljcL{8F}ItqQhALdhC5xN>Uj)p9LikjU+JyXz!GQhWXjQ^!jmj0l{63k)`;u~QX zC^H@M=|i+nEwoa6p=`VXy8MRO-!rs<7x|P!9i=vyg)%LMocIB8kKxz}>U@Hl>A-D9 z(A0oj-k>%|Fg|QTJ6=W3Zt%S1O_D1U8N?a>}mYZy>7sb_n^I|1}8 zFA&+J-a;bA2cTvx1jyPQNg|x{4bxcU#14$)Gp%fe$ zh!rlBrKQ0e(kw;>oS|&gLh9XGltTq%AtP#%i6;bPjTSwTM^EL@D5NP2S_m!rL!Q7F#50-^bjD;orU})rAmWRUeNzOO1B5S?jWSg6L3i$N|=dqrs7Hl zUT9p{Q!9W59<-IjNm*MYN8RpH+#b3&MmIl?lNI?e4AoXpia*U`;*j?HgK#ok6|G?W=*A#B2zfGlX%<> z=`YED>5y86MgA(Jr$bpw6^7*zR+?i-HI}|@2v9sSca-FlG*hGtXHAiwCiOUJhE^Oo zN}iHKXj5q(Dnlxg2VjYBrJN|xHxZ+Md6X#;`H46*;NVD1J!l~HTgij8)VCN&C@pHO zMJ%ZY3%H6eoDWFzAZb=4%|InND#<+tS0X|uAVe{wn24~6s7pzNl>gF}ZhO7lsn zcSOR*pcF|+Nr`)+Fjo$xR)St?{7NAu$qB${{6a~g@L2@EO`?|^VWm1sqdK4>3e)8Z zYaopb(#RymlX8-1DTS2!H-)pb?hu1RjptH&($mQNK!JBspOoYg^*>4}jd^OsmpCrT7uQ)2hOp`NDEzB{(r&5oQ^2bl%SxPY)^554m5>~2bw60RBA=E`0^`%*sl%AAI zBpsuU9;sAP3rOXOj4+Xq5~oR2lKhZ+a7gk^jF zMV?E~r2EJd>77)bNW92%>0U}H5+fQ;8g(4_m&zlB1AKeoRV037T#;f)JyZ%6eJ`D* zF)I?fD2{X$NjnlYl5%7|6sbq#xs}2d2#utai%J=(nG`D;^IuCDp@$psB567b&yw%;_j8nLB!!8Txv2b79O;l^ z6>q{ ziMF;BuBfb$(no3_l_64&NNkCdq*zkRNAi>2{xx>JfP>T}SH{O)HXaq@2-bku;(uFUq+nm7@y@^~)ztQ*7 zS(15?zi8~DIMJ(Ui2pNZY2=6=lGOhD5qTEdtVO@l)%(Z$VT(%m*QZ5ykrGAbI+1!u z=~UEyktdOme-9shR}`x#t;m%`KPlGV)BD%^NVq5!qB%ulM{|m_MA4meA1#~o^!@9i zP|{VTB_%$JUPs;+{YFCk>wPqibpAUx{x!9tJc{_WD3-+kMZF;UJn}Sh_kItFUPod? z-$&2Ua{M(^^seY!BrBrNie!ZJBq9@}-{`kk4?k|irz-&7DZ2ruA*~_5M~_zRk+CeXozU6Xii1< zMJY$Fq!^J{k*lKnXvlw;Z&8eB>}YC{(C_E>pVE!Sh}P`=IMLetyL|p$o=7|?wW1XM z-BqNde|;0JiPW=zMn?X^P;Q&S(?$36oq>~ZuD*BS)@MEkkN3_Fh$R! zZ;GBsSAP!|eH%Id`#66M^UvKs6!?b%|N9h>W*L!GqO*+XyyNfp(K*O}dM>5%_jg5U z6oc|i;zjycdeBY1#e#wizKHd-U-?{$ZPvP&m{a0m=sf2q$iQ|-oJW3eDrzr{GZ=NLj0fnjh6KPWSak^ h^$!L9p};>B_=f`jP~aa5{6m3%DDV#j{{KgT{}15`1Bn0t literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav new file mode 100644 index 0000000000000000000000000000000000000000..2b61d877f97b30b84a2673a76df41f4998eb7099 GIT binary patch literal 163244 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 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav new file mode 100644 index 0000000000000000000000000000000000000000..4d4f0b04a08a22996c7686c9ecfe316e2d04f9a8 GIT binary patch literal 117164 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⪻t@SM`NHldMf|XEtFS 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�ynDU7 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 hint: %s", + decision.reason, decision.hint) + if live_rec is not None: + live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") + if force_measure and speaker is not None and decision.reason != "need_focus": + now_mono = time.monotonic() + if _pending_reject is not None: + pass # 已在保护中,上面已处理,不重复挂起 + elif sent_tracker is not None and sent_tracker.speaking: + # 模型正念字:挂起,保护到下一个标点再复查 + _pending_reject = { + "since": now_mono, + "reason": decision.reason, + "snap": sent_tracker.snapshot(), + } + LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", + decision.reason) + else: + # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) + if (not _hint_playing + and now_mono - _last_hint_mono >= _HINT_THROTTLE_S): + _last_hint_mono = now_mono + asyncio.create_task(_do_reject_interrupt(decision.reason)) # ── 「持续坏」检测(优先于标点保护)── # 3s 窗口内"真坏"reject≥2 → 输出基于坏图=幻觉。此时不走标点保护 # (前半也错,不值得保护),直接触发"停→播提示→恢复"。 @@ -1099,15 +1178,33 @@ async def _do_reject_interrupt(reason): if _bad_in_window >= _BAD_THRESH and _is_real_bad: _pending_reject = None # 持续坏优先,取消标点保护挂起 # 到这里必是"真坏"(severe_shake/unstable/too_dark/orient)。 - # 直接触发完整"停→播提示→恢复"(复用 _do_reject_interrupt, - # 停模型输出不杀死、播完恢复)。耗时≈播报时长,天然间隔。 + # **必须和标点保护那条一样受 _HINT_THROTTLE_S 约束**: + # 原注释说"耗时≈播报时长,天然间隔",但那不成立 —— + # STOP/RESUME 是在播报**之前**就发出去的,不受播报时长限制。 + # 实测画面持续不合格时(晃动/倒置),3s 窗口每轮都能凑够 2 次真坏, + # 于是每轮一次 STOP/RESUME;17 秒内 17 个 control event 之后 + # gateway 会话直接换代重连(generation 0→1),期间 + # gateway=preparing、音频队列堵死 queue=96 drops 暴涨、图也送不出去。 + # 表现就是"灯变红、画面卡住、取图 TimeoutError"。 + if _hint_playing or _now - _last_hint_mono < _HINT_THROTTLE_S: + LOG.debug("[持续坏] %d次真坏,但距上次提示 %.1fs < %.1fs,跳过打断", + _bad_in_window, _now - _last_hint_mono, + _HINT_THROTTLE_S) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + _last_hint_mono = _now LOG.info("[持续坏] 3s内%d次真坏reject,打断+播提示(停→播→恢复)", _bad_in_window) if live_rec is not None: live_rec.log_event( "PERSIST-BAD", f"3s内{_bad_in_window}次真坏 → 打断 ({decision.reason})") - await _do_reject_interrupt(decision.reason) + asyncio.create_task(_do_reject_interrupt(decision.reason)) elapsed = time.monotonic() - t0 try: await asyncio.wait_for(stop_evt.wait(), @@ -1139,51 +1236,14 @@ async def _do_reject_interrupt(reason): # 仍 reject → 打断(受节流约束) LOG.info("[标点保护] %s,仍 reject(%s),打断", "到标点" if reached else "超时1.5s", decision.reason) - if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + if (not _hint_playing + and now_mono - _last_hint_mono >= _HINT_THROTTLE_S): _last_hint_mono = now_mono _pending_reject = None - await _do_reject_interrupt(decision.reason) + asyncio.create_task(_do_reject_interrupt(decision.reason)) else: _pending_reject = None # 被节流 - if decision.send and decision.best: - ts = now_ms() - latest_frame.set(decision.best, ts) - stats.image_count += 1 - await harness.send_frame(decision.best, latest_frame.sequence, ts) - LOG.info("[漏斗] send (%s)", decision.reason) - _emit_chunk_img(web_ui, decision.best, latest_frame.sequence, True) - # -o record:只录真发送给模型的 best 图(chunk_idx = sequence) - if live_rec is not None: - try: - await asyncio.to_thread( - live_rec.on_frame, decision.best, latest_frame.sequence) - except Exception as e: - LOG.warning("[LIVE] on_frame err: %s", e) - # 注意:send 不清 _pending_reject,保护期只看到标点那一刻 - else: - LOG.info("[漏斗] reject(%s) -> hint: %s", - decision.reason, decision.hint) - if live_rec is not None: - live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") - if force_measure and speaker is not None and decision.reason != "need_focus": - now_mono = time.monotonic() - if _pending_reject is not None: - pass # 已在保护中,上面已处理,不重复挂起 - elif sent_tracker is not None and sent_tracker.speaking: - # 模型正念字:挂起,保护到下一个标点再复查 - _pending_reject = { - "since": now_mono, - "reason": decision.reason, - "snap": sent_tracker.snapshot(), - } - LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", - decision.reason) - else: - # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) - if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: - _last_hint_mono = now_mono - await _do_reject_interrupt(decision.reason) if probe is not None: since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 jb = len(decision.best) if decision.best else 0 @@ -1473,7 +1533,21 @@ async def start(self) -> None: if self._funnel is not None: try: ms = await asyncio.to_thread(self._funnel.warmup_orient) - LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + # 必须查真实状态:这行原来无条件打"就绪",而加载失败时 + # process_orientation 会静默回退到轻量 CV 判据、照样返回, + # 于是"预热就绪"根本不能证明分类器可用(实测 panel 环境下 + # paddle 循环导入失败 → 轻量判据 → 第一轮就误判 orient_flipped)。 + try: + from .cam_pipeline_v2 import orient_classifier_status + _ok, _err = orient_classifier_status() + except Exception: + _ok, _err = True, "" + if _ok: + LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + else: + LOG.warning( + "[预热] !! PaddleOCR 方向分类器加载失败,已回退到轻量 CV 判据 —— " + "orient 判定会明显变差(实测第一轮就误报 flipped)。原因: %s", _err) except Exception as e: LOG.warning("[预热] 方向分类器预热跳过: %s", e) # ── rerun 模式:用录制的 session 回放(音频+best图)重跑 -o,不接实时设备 ── diff --git a/extensions/assistive_harness/phase_b/requirements-phase-b.txt b/extensions/assistive_harness/phase_b/requirements-phase-b.txt index a247f64..4cd81f4 100644 --- a/extensions/assistive_harness/phase_b/requirements-phase-b.txt +++ b/extensions/assistive_harness/phase_b/requirements-phase-b.txt @@ -1,4 +1,34 @@ -aiohttp>=3.13 -Pillow>=10 -sounddevice>=0.5 +# OpenGlass — extensions/assistive_harness 依赖(②③④ 链路:语音控制 + CV 漏斗) +# +# 装在**和 MiniCPM-o-Demo 同一个 conda 环境**里:panel 起子进程时继承启动它的环境, +# 而 worker/gateway 也在那个环境跑。不要另建环境。 +# +# conda activate <你跑 MiniCPM-o-Demo 的环境> +# pip install -r requirements-phase-b.txt +# ── 基础 ── +aiohttp>=3.13 # gateway/harness 的 WebSocket 客户端 + bridge_ui 服务 +numpy>=1.24 # 音频/图像数组 +Pillow>=10 # --rotate 转正(PIL) +sounddevice>=0.5 # PC 扬声器播放(AI 语音、reject 提示音) +requests>=2.31 # ESP32 HTTP 控制(分辨率/对焦) +PyYAML>=6.0 # harness 的 skills 配置 + +# ── 8021 harness(语音控制腿,②③④ 需要)── +fastapi>=0.110 +uvicorn>=0.27 +funasr>=1.3 # 流式 ASR。模型另外下载,路径写进 runtime.local.json +cryptography>=42 # panel 首次启动自签证书(没有它会退回调 openssl) + +# ── CV 漏斗(③④ 需要)── +opencv-python>=4.8 # 清晰度/光流/亮度判据 +# +# ★ 方向分类器(orient_flipped / orient_sideways 判据)—— +# 装不上或版本不对时会**静默回退到早期的简易判据**,表现是画面明明是正的 +# 却一直报"画面好像反了"。启动日志里会有: +# [预热] !! PaddleOCR 方向分类器加载失败,已回退到轻量 CV 判据 ... +# 看到这行就说明下面两个没装好,别忽略。 +# +# 实测可用组合(CPU 版即可,模型只有 6.75MB): +paddlepaddle>=3.0 # GPU 机器可换 paddlepaddle-gpu,但 CPU 版足够 +paddleocr>=3.0 # 只用其中的 DocImgOrientationClassification diff --git a/extensions/assistive_harness/phase_b/templates/live.html b/extensions/assistive_harness/phase_b/templates/live.html index 96099f9..5ab0032 100644 --- a/extensions/assistive_harness/phase_b/templates/live.html +++ b/extensions/assistive_harness/phase_b/templates/live.html @@ -399,7 +399,12 @@

停止并保存?

const sent = $('hSent'); sent.classList.remove('good','warn','bad'); if (e.img_sent) { sent.classList.add('good'); $('hSentText').textContent = '送图 ✓'; } - else { sent.classList.add('bad'); $('hSentText').textContent = '送图 ✗'; } + else { + // 没送模型:可能是被漏斗拦下(带 reject_reason),也可能只是同一轮里 + // 非 best 的那几帧。画面照样刷新,这样第一视角才连续、也看得见被拦的图。 + sent.classList.add('bad'); + $('hSentText').textContent = e.reject_reason ? ('拦下 ' + e.reject_reason) : '送图 ✗'; + } // 3) 音频静音 const aud = $('hAud'); diff --git a/runtime/openglass_omni/devices.example.json b/runtime/openglass_omni/devices.example.json new file mode 100644 index 0000000..5cecb6c --- /dev/null +++ b/runtime/openglass_omni/devices.example.json @@ -0,0 +1,7 @@ +{ + "_说明": "多副眼镜配置。烧录后从串口看到 IP,改这里对应那副的 esp32_host。rotate 是该眼镜摄像头顺时针旋转角度(0/90/180/270),按设备侧装方向填。两台笔记本各自维护自己这份文件。gateway 走本机默认,不放这里。", + "devices": [ + { "name": "1号镜", "esp32_host": "esp32_ip", "esp32_port": 80, "rotate": 0 }, + { "name": "2号镜", "esp32_host": "esp32_ip2", "esp32_port": 80, "rotate": 90 } + ] +} \ No newline at end of file diff --git a/runtime/openglass_omni/panel.html b/runtime/openglass_omni/panel.html index 99e4173..c024489 100644 --- a/runtime/openglass_omni/panel.html +++ b/runtime/openglass_omni/panel.html @@ -107,6 +107,10 @@ + + @@ -184,11 +188,20 @@

第一视角

(CFG.devices||[]).forEach(d=>{ const o=document.createElement("option"); o.value=d; o.textContent=d; sel.appendChild(o); }); - applyChain(); // 按链路刷新灯/日志页签/FPV/眼镜下拉可见性 + // 填充判据下拉(只有开了漏斗的链路用得上,applyChain 里控制显隐) + const ssel = document.getElementById("sceneSel"); + (CFG.scenes||[]).forEach(x=>{ + const o=document.createElement("option"); o.value=x; o.textContent=x; ssel.appendChild(o); + }); + if(CFG.default_scene) ssel.value = CFG.default_scene; + applyChain(); // 按链路刷新灯/日志页签/FPV/眼镜+判据下拉可见性 fpvOn=false; toggleFpv(); // 默认开启第一视角画面 setInterval(poll, 1000); } +// 进程内部名 -> 界面显示名(拿不到就退回内部名) +function PLABEL(n){ return (CFG.proc_labels && CFG.proc_labels[n]) || n; } + // 切链路:重画状态灯、日志页签、FPV 地址;Rokid 分支隐藏眼镜下拉 function applyChain(){ const c = CFG.chains[curChain]; @@ -197,7 +210,7 @@

第一视角

lights.innerHTML = ""; c.procs.forEach(n=>{ const d=document.createElement("div"); d.className="light"; - d.innerHTML = `${n}`; + d.innerHTML = `${PLABEL(n)}`; lights.appendChild(d); }); // 日志页签(保留 autoscroll 勾选框) @@ -206,7 +219,7 @@

第一视角

tabs.innerHTML = ""; c.procs.forEach((n,i)=>{ const t=document.createElement("div"); - t.className="tab"+(i===0?" active":""); t.dataset.t=n; t.textContent=n; + t.className="tab"+(i===0?" active":""); t.dataset.t=n; t.textContent=PLABEL(n); t.onclick=()=>switchTab(n); tabs.appendChild(t); }); tabs.appendChild(auto); @@ -215,6 +228,10 @@

第一视角

const show = c.need_device; document.getElementById("deviceSel").style.display = show ? "" : "none"; document.getElementById("devLabel").style.display = show ? "" : "none"; + // 判据下拉:只有开了漏斗的链路(③④)才显示;①②没有漏斗,选了也不起作用 + const showScene = !!c.need_scene; + document.getElementById("sceneSel").style.display = showScene ? "" : "none"; + document.getElementById("sceneLabel").style.display = showScene ? "" : "none"; // FPV 地址随链路变(ESP32=demo bridge_ui:8080;Rokid=bridge:18080 自带页) document.getElementById("fpvUrl").textContent = c.fpv_url; if(fpvOn){ fpvOn=false; toggleFpv(); } // 重挂 iframe 到新地址 @@ -226,6 +243,8 @@

第一视角

} function curDevice(){ return document.getElementById("deviceSel").value; } function onDeviceChange(){ window.pywebview.api.set_device(curDevice()); } +function curScene(){ const e=document.getElementById("sceneSel"); return e ? e.value : ""; } +function onSceneChange(){ window.pywebview.api.set_scene(curScene()); } function selectPreset(name,el){ document.querySelectorAll(".preset").forEach(p=>p.classList.remove("active")); el.classList.add("active"); @@ -234,7 +253,7 @@

第一视角

} function startAll(){ const p = document.getElementById("prompt").value.trim(); - window.pywebview.api.start_all(p, curDevice(), curChain); + window.pywebview.api.start_all(p, curDevice(), curChain, curScene()); } function stopDemo(){ window.pywebview.api.stop_demo(); } // 停止:只停 demo,无需确认(现场要快) function restartDemo(){ diff --git a/runtime/openglass_omni/panel.py b/runtime/openglass_omni/panel.py index ed262e3..d3bce4d 100644 --- a/runtime/openglass_omni/panel.py +++ b/runtime/openglass_omni/panel.py @@ -169,7 +169,44 @@ "--connect-retry", ], - # ⑤ rokid bridge —— 与 demo 平行、二选一的“第四个进程”。 + # ⑤ 8021 harness —— 语音控制腿(停一下/重新开始/找物),也是 ASR 来源。 + # 只有 ②③④ 带 harness 的链路才起它。 + # ★ 开源用户必改:--model-path 指向你机器上的 FunASR 流式模型目录 ★ + # 证书:自签即可,只为过 wss 握手,不绑机器;客户端全是 CERT_NONE 不校验。 + # ★ 它在 extensions/ 下,用 -m 启动,因此 cwd 必须是 MiniCPM-o-Demo 目录 + # (见 _spawn 里的 name in (...) 白名单)。 + "harness": [ + "python", "-m", "extensions.assistive_harness.server", "--enabled", + #"--model-path", r"\LocalASRmodel\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + # e.g. + "--model-path", (r"D:\OpenGlass\OmniDeployment\OpenGlass\LocalASRmodel" + r"\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online"), + "--port", "8021", + # 绝对路径:harness 的 cwd 是 OpenGlass 仓库根,而证书由 _ensure_certs + # 生成在 minicpm_demo_dir/certs 下(gateway 也用同一对)。 + "--certfile", "{certfile}", + "--keyfile", "{keyfile}", + ], + + # ⑥ demo_funnel —— esp32_runtime(harness + CV 漏斗)。与 ④ demo 互斥: + # 两者都要独占 ESP32 的音频 WS 和图像 TCP,不能同时跑。 + # 这里只放各档位共用的参数;--esp32-host/--esp32-port/--rotate 由 + # devices.json 填(_device_args),漏斗档位参数由 _funnel_extra_args 追加。 + # ★ 同样在 extensions/ 下,cwd 必须是 MiniCPM-o-Demo 目录。 + # ★ 8006 是 TLS(https:// 能取到 openapi.json,http:// 是 Empty reply), + # 走默认 wss,**不要**加 --no-tls;而 harness 8021 是自签 wss,两者都是 wss + # 但证书来源不同。 + "demo_funnel": [ + "python", "-m", "extensions.assistive_harness.phase_b.esp32_runtime", + "--gateway", "localhost:8006", + "--harness-url", "wss://127.0.0.1:8021/ws/control", + "--image-tcp-port", "5000", + "--web-ui-port", "8080", + "--record-live", + "--prompt", "{prompt}", + ], + + # ⑦ rokid bridge —— 与 demo 平行、二选一的“第四个进程”。 # 注意:它不是客户端去连眼镜,而是在 PC 上开 18080 端口等 APK 连进来。 # ★ 用 v8(API V2)。v7 是旧协议(/ws/duplex),连不上新 gateway:8006。 # ★ run_rokid.ps1 / run_rokid_wifi.cmd 已不再需要——它们做的事 @@ -191,8 +228,12 @@ # live.html 观测页(与 ESP32 demo 同一套 bridge_ui 前端/模板) "--ui-port", "8080", "--prompt", "{prompt}", - "--glasses-ssid", "SQZ", - "--glasses-psk", "sqz.ac.cn", + # ★ 眼镜连的 WiFi。**不要把真实密码提交进仓库** —— + # 在 panel.py 同目录放一个 panel.local.json(已在 .gitignore): + # { "glasses_ssid": "你的WiFi", "glasses_psk": "你的密码" } + # 没有该文件时用下面的占位值,Rokid 链路会连不上 WiFi 但其余功能正常。 + "--glasses-ssid", "{glasses_ssid}", + "--glasses-psk", "{glasses_psk}", ], }, @@ -202,13 +243,48 @@ # rokid → rokid_minicpm_v7.py (PC 开端口等 APK 连进来,无 device) "chains": { "esp32": { - "label": "ESP32 眼镜", + "label": "① 基础对话", "tail": "demo", # 第四级进程名 "start_order": ["llama", "worker", "gateway", "demo"], "stop_order": ["demo", "gateway", "worker", "llama"], "need_device": True, # 显示眼镜下拉 "fpv_key": "fpv_url", # 第一视角地址 }, + # ── 以下三条走 esp32_runtime(harness + 漏斗),四档递进演示 ── + # ① 基础对话 = 上面的 "esp32"(esp32_bridge.py,无 harness 无漏斗) + # ② 语音控制 = harness 开、漏斗关 + # ③ 质量筛选 = ② + 每秒多帧里挑最清晰的一张 + # ④ 完整防幻觉 = ③ + 坏图直接拦下并语音提示 + # 每档只比上一档多一件事:看到什么说什么 → 能听懂指令 → 图会挑 → 坏图会拦 + # (没有"只对焦"这一档:对焦后要等 settle 再重抓,1s chunk 时序固定, + # 对焦后那张未必赶得上这一轮,等于花了时间没用上。) + "esp32_voice": { + "label": "② 语音控制", + "tail": "demo_funnel", + "funnel": 0, # 漏斗档位:0 关 / 2 选图 / 3 选图+拒绝 + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, + "esp32_select": { + "label": "③ 质量筛选", + "tail": "demo_funnel", + "funnel": 2, + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, + "esp32_full": { + "label": "④ 完整防幻觉", + "tail": "demo_funnel", + "funnel": 3, + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, "rokid": { "label": "Rokid 眼镜", "tail": "rokid", @@ -220,6 +296,30 @@ }, "default_chain": "esp32", + # 判据档位:漏斗的两套标定参数。对外用场景名,不暴露内部值。 + # 严格 = medicine (药盒小字高危,worst_x0=6.5 ACCEPT_Q=0.55) + # 日常 = stationery(生活用品,worst_x0=5.0 ACCEPT_Q=0.48) + "scenes": {"严格判据": "medicine", "日常判据": "stationery"}, + "default_scene": "严格判据", + + # 档位④的提示音目录。**跟着 extensions 包走**(和 bridge_ui 的 templates/ 同思路), + # 不落在上游 MiniCPM-o-Demo 里,保持三仓库独立。这里是相对 OpenGlass 仓库根, + # panel 会拼成绝对路径传给 esp32_runtime(它的 cwd 是上游,相对路径会指错地方)。 + # 启动前检查,缺了就报错 —— 而不是跑起来才发现没声音,那时 duplex 已在跑, + # 没法当场用 gen_reject_wavs.py 生成。 + "reject_wav_dir": "extensions/assistive_harness/phase_b/assets/reject_wav", + + # 进程的界面显示名(灯泡/日志页签用)。内部名不变,只影响 UI。 + "proc_labels": { + "llama": "推理后端", + "worker": "worker", + "gateway": "gateway", + "harness": "语音控制(8021)", + "demo": "眼镜", + "demo_funnel": "眼镜+漏斗", + "rokid": "Rokid", + }, + # 可选眼镜(对应 devices.json 里的 name)。面板顶部下拉选择。仅 ESP32 分支用。 "devices": ["左镜", "右镜", "备用镜"], @@ -278,6 +378,191 @@ def _load_devices_from_json(path="devices.json"): # ============================================================================ +def _load_device_map(path="devices.json"): + """读整份设备表:name -> {host, port, rotate}。 + + 原来只取 name(下拉用)。但 esp32_bridge 自己读 json(--device-config), + 而 esp32_runtime 不读,它只认 --esp32-host/--esp32-port/--rotate, + 所以由 panel 把这几项取出来填。rotate 尤其不能漏:摄像头物理侧装, + 不转正的话漏斗的方向检测会把"相机侧装"误判成"用户把盒子拿反了"。 + utf-8-sig:记事本/VSCode 存的 json 可能带 BOM,用 utf-8 读会炸在第一个字符。 + """ + out = {} + try: + with open(path, "r", encoding="utf-8-sig") as f: + data = json.load(f) + for d in data.get("devices", []): + n = d.get("name") + if not n: + continue + out[n] = { + "host": d.get("esp32_host", ""), + "port": int(d.get("esp32_port", 80)), + "rotate": int(d.get("rotate", 0)) % 360, + } + except FileNotFoundError: + print(f"[panel] 未找到 {path},带漏斗的链路(②③④)将无法自动填 IP") + except Exception as e: + print(f"[panel] 读取 {path} 失败({e})") + return out + + +CONFIG["device_map"] = _load_device_map(_dev_path) +if CONFIG["device_map"]: + print("[panel] 设备详情: " + ", ".join( + f"{k}({v['host']} rot={v['rotate']})" for k, v in CONFIG["device_map"].items())) + + +def _load_runtime_local(): + """读 runtime.local.json —— 本机路径与私密配置,**不进仓库**。 + + 为什么要它:panel.py 里原本写死了五处本机绝对路径 + (conda 环境、MiniCPM-o-Demo 目录、llama-omni-server.exe、主 gguf、FunASR 模型), + 还有眼镜 WiFi 的明文密码。开源后每个人都要改源码才能跑,密码也会进 git 历史。 + 改成从这个文件读,clone 下来只需 `cp runtime.example.json runtime.local.json` 再填。 + + 键名沿用仓库里已有的 runtime.example.json 风格。 + 找不到文件时保留 CONFIG 里的默认值(也就是原来的写死值),行为不变。 + """ + here = os.path.dirname(os.path.abspath(__file__)) + f = os.path.join(here, "runtime.local.json") + if not os.path.isfile(f): + print(f"[panel] 未找到 {f}") + print("[panel] 请复制 runtime.example.json 为 runtime.local.json 并填写本机路径;") + print("[panel] 否则将沿用 panel.py 里的默认值(多半不是你的路径)。") + return {} + try: + with open(f, "r", encoding="utf-8-sig") as fh: + cfg = json.load(fh) + except Exception as e: + print(f"[panel] 读取 runtime.local.json 失败({e}),沿用默认值") + return {} + + def _expand(v): + return os.path.expandvars(os.path.expanduser(v)) if isinstance(v, str) else v + + n = 0 + # ① 简单键 -> CONFIG 顶层 + for src_key, dst_key in (("conda_env", "conda_env"), + ("minicpm_demo_root", "minicpm_demo_dir")): + v = _expand(cfg.get(src_key)) + if v: + CONFIG[dst_key] = v + n += 1 + # ② 需要替换到命令行数组里的 + def _sub(proc, old_pred, new_val): + """把 procs[proc] 里满足 old_pred 的那一项换成 new_val。""" + arr = CONFIG["procs"].get(proc) + if not arr or not new_val: + return 0 + for i, x in enumerate(arr): + if isinstance(x, str) and old_pred(x): + arr[i] = new_val + return 1 + return 0 + + n += _sub("llama", lambda x: x.lower().endswith("llama-omni-server.exe") + or x.lower().endswith("llama-omni-server"), + _expand(cfg.get("llama_server"))) + n += _sub("llama", lambda x: x.lower().endswith(".gguf"), + _expand(cfg.get("llama_model"))) + n += _sub("harness", lambda x: "speech_paraformer" in x or "LocalASRmodel" in x, + _expand(cfg.get("asr_model"))) + print(f"[panel] 已读入 runtime.local.json(生效 {n} 项)") + return cfg + + +def _load_local_secrets(rt): + """眼镜 WiFi(Rokid 链路传给 APK)。同样来自 runtime.local.json, + 写死在 panel.py 里就等于明文密码进公开仓库。""" + out = {"glasses_ssid": "", "glasses_psk": ""} + g = (rt or {}).get("glasses") or {} + for k in ("glasses_ssid", "glasses_psk"): + v = g.get(k.replace("glasses_", "")) or (rt or {}).get(k) + if v: + out[k] = v + return out + + +_RTLOCAL = _load_runtime_local() +CONFIG["local"] = _load_local_secrets(_RTLOCAL) + + +def _ensure_certs(base_dir): + """确保 certs/cert.pem + key.pem 存在,没有就自签一对。 + + gateway(8006) 和 harness(8021) 都用这一对(gateway.py 的默认值就是 + certs/cert.pem,缺了会直接报错退出),所以四条链路都需要它。 + 自签证书**不绑机器**,里面没有硬件信息;客户端全是 CERT_NONE 不校验, + 只是为了让 wss 握手能过。所以本地生成一份即可,不必也不该提交进仓库。 + + 优先用 cryptography 库;没装就退回调 openssl;都不行就打出手动命令。 + """ + if not base_dir or not os.path.isdir(base_dir): + return False + d = os.path.join(base_dir, "certs") + cert = os.path.join(d, "cert.pem") + key = os.path.join(d, "key.pem") + if os.path.isfile(cert) and os.path.isfile(key): + return True + os.makedirs(d, exist_ok=True) + print(f"[panel] 未找到证书,正在生成自签证书 -> {d}") + + try: + from cryptography import x509 + from cryptography.x509.oid import NameOID + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import rsa + import datetime as _dt + + k = rsa.generate_private_key(public_exponent=65537, key_size=2048) + name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "localhost")]) + now = _dt.datetime.now(_dt.timezone.utc) + crt = (x509.CertificateBuilder() + .subject_name(name).issuer_name(name) + .public_key(k.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(now - _dt.timedelta(days=1)) + .not_valid_after(now + _dt.timedelta(days=3650)) + .add_extension(x509.SubjectAlternativeName([ + x509.DNSName("localhost"), + x509.IPAddress(__import__("ipaddress").IPv4Address("127.0.0.1")), + ]), critical=False) + .sign(k, hashes.SHA256())) + with open(key, "wb") as f: + f.write(k.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption())) + with open(cert, "wb") as f: + f.write(crt.public_bytes(serialization.Encoding.PEM)) + print("[panel] 证书已生成(cryptography,有效期 10 年)") + return True + except ImportError: + pass + except Exception as e: + print(f"[panel] cryptography 生成失败({e}),改试 openssl") + + try: + subprocess.run( + ["openssl", "req", "-x509", "-newkey", "rsa:2048", + "-keyout", key, "-out", cert, "-days", "3650", + "-nodes", "-subj", "/CN=localhost"], + check=True, capture_output=True, timeout=60) + print("[panel] 证书已生成(openssl,有效期 10 年)") + return True + except Exception as e: + print(f"[panel] !! 自动生成证书失败: {e}") + print(f"[panel] 请手动执行(在 {base_dir} 下):") + print("[panel] openssl req -x509 -newkey rsa:2048 " + "-keyout certs/key.pem -out certs/cert.pem " + "-days 3650 -nodes -subj \"/CN=localhost\"") + return False + + +_ensure_certs(CONFIG.get("minicpm_demo_dir") or CONFIG.get("cwd")) + + class ProcManager: """管理三个子进程:起停、状态轮询、日志收集、端口/就绪探测。""" @@ -294,6 +579,7 @@ def __init__(self, cfg): self.status = {n: "stopped" for n in cfg["procs"]} # stopped/starting/running/crashed self.current_prompt = next(iter(cfg["presets"].values())) self.current_device = (cfg.get("devices") or ["默认"])[0] + self.current_scene = cfg.get("default_scene", "严格判据") # —— 当前链路:esp32 / rokid,决定第四级起哪个进程 —— self.current_chain = cfg.get("default_chain", "esp32") self._lock = threading.Lock() @@ -341,9 +627,29 @@ def _build_cmd(self, name): if name == "demo": subst = {"{prompt}": self.current_prompt, "{device}": self.current_device} cmd = [subst.get(x, x) for x in cmd] - elif name == "rokid": + elif name == "harness": + # 证书用绝对路径:harness 的 cwd 是 OpenGlass 仓库根, + # 而证书由 _ensure_certs 生成在 minicpm_demo_dir/certs 下(gateway 共用)。 + _base = self.cfg.get("minicpm_demo_dir") or "." + subst = { + "{certfile}": os.path.join(_base, "certs", "cert.pem"), + "{keyfile}": os.path.join(_base, "certs", "key.pem"), + } + cmd = [subst.get(x, x) for x in cmd] + elif name == "demo_funnel": + # esp32_runtime:prompt + 设备参数(IP/端口/旋转) + 漏斗档位 subst = {"{prompt}": self.current_prompt} cmd = [subst.get(x, x) for x in cmd] + cmd += self._device_args() + cmd += self._funnel_extra_args() + elif name == "rokid": + _loc = self.cfg.get("local", {}) + subst = { + "{prompt}": self.current_prompt, + "{glasses_ssid}": _loc.get("glasses_ssid", ""), + "{glasses_psk}": _loc.get("glasses_psk", ""), + } + cmd = [subst.get(x, x) for x in cmd] cmd += self._rokid_extra_args() # 内联 ps1 的 --enable-funasr 分支 return self._wrap_conda(cmd) @@ -436,6 +742,110 @@ def _rokid_env(self): self._log("rokid", f"日志: {env['ROKID_V7_LOG_FILE']}") return env + def _device_args(self): + """从 devices.json 取当前眼镜的 IP / 端口 / 旋转角,填给 esp32_runtime。""" + d = (self.cfg.get("device_map") or {}).get(self.current_device) + if not d or not d.get("host"): + self._log("demo_funnel", + f"!! devices.json 里找不到「{self.current_device}」的 esp32_host") + return [] + args = ["--esp32-host", d["host"], "--esp32-port", str(d.get("port", 80))] + if d.get("rotate"): + args += ["--rotate", str(d["rotate"])] + return args + + def _funnel_extra_args(self): + """按链路的档位追加漏斗参数。 + + 0 语音控制 不加 → 走 no_funnel 分支,每轮取一帧直发 + 2 质量筛选 --funnel --no-reject → 选 best 但永远放行 + 3 完整防幻觉 --funnel --force-measure → 选 best + 拒绝 + 语音提示 + """ + lv = int(self.chain().get("funnel", 0)) + if lv <= 0: + return [] + scene = self.cfg["scenes"].get(self.current_scene, "medicine") + args = ["--funnel", "--scene", scene] + if lv == 2: + args += ["--no-reject"] + else: + args += ["--force-measure", "--reject-wav-dir", self._reject_wav_dir()] + return args + + def _check_deps(self): + """②③④ 启动前检查关键依赖,缺了就说清楚缺什么、怎么装。 + + 为什么值得单独查:paddleocr 装不上时,方向分类器会**静默回退**到 + 早期的简易判据,表现是画面明明是正的却一直报"画面好像反了"、 + 接着播报把帧间隔拉长又误报"晃动" —— 全程不报错,极难定位。 + 实测踩过:panel 在没装好 paddle 的环境里启动,一上来就全是 orient_flipped。 + """ + lv = int(self.chain().get("funnel", 0)) + need = [("aiohttp", "aiohttp"), ("numpy", "numpy"), + ("PIL", "Pillow"), ("sounddevice", "sounddevice")] + if self.chain().get("tail") == "demo_funnel": + need += [("fastapi", "fastapi"), ("uvicorn", "uvicorn"), + ("yaml", "PyYAML"), ("funasr", "funasr")] + if lv >= 2: + need += [("cv2", "opencv-python")] + if lv >= 3 or lv == 2: + need += [("paddle", "paddlepaddle"), ("paddleocr", "paddleocr")] + import importlib.util as _iu + missing = [pip for mod, pip in need if _iu.find_spec(mod) is None] + if missing: + tail = self.chain().get("tail") or "demo" + self._log(tail, "!! 缺少依赖: " + ", ".join(missing)) + self._log(tail, " 请在**启动 panel 的那个 conda 环境**里安装:") + self._log(tail, " pip install " + " ".join(missing)) + self._log(tail, " (完整清单见 extensions/requirements-phase-b.txt)") + return False + return True + + def _check_extensions(self): + """②③④ 需要 OpenGlass 仓库内的 extensions/ 包完整。 + + 不需要复制到别处 —— _spawn 把 cwd 设成 OpenGlass 仓库根。 + 缺文件时子进程会起来立刻死、日志里一行 No module named extensions, + 面板上只看到灯变红,所以提前拦住并说清楚。 + """ + if self.chain().get("tail") != "demo_funnel": + return True + f = os.path.join(self._repo_root(), "extensions", "assistive_harness", + "phase_b", "esp32_runtime.py") + if not os.path.isfile(f): + self._log("demo_funnel", + f"!! 未找到 {f}\n" + f" ②③④ 需要仓库内的 extensions/ 包,请确认它没有被删除或移动。") + return False + return True + + def _repo_root(self): + """OpenGlass 仓库根(panel.py 在 runtime/openglass_omni/ 下,往上三级)。""" + return os.path.dirname(os.path.dirname( + os.path.dirname(os.path.abspath(__file__)))) + + def _reject_wav_dir(self): + d = self.cfg.get("reject_wav_dir", + "extensions/assistive_harness/phase_b/assets/reject_wav") + return d if os.path.isabs(d) else os.path.join(self._repo_root(), d) + + def _check_reject_wav(self): + """档位④要播提示音,wav 必须事先用 gen_reject_wavs.py 生成好 + (且要在 duplex 没跑的时候生成)。这里只检查,不在面板里现场生成。""" + if int(self.chain().get("funnel", 0)) < 3: + return True + full = self._reject_wav_dir() + try: + n = len([x for x in os.listdir(full) if x.lower().endswith(".wav")]) + except Exception: + n = 0 + if n == 0: + self._log("demo_funnel", + f"!! {full} 里没有 wav。档位④要播提示音," + f"请先在 duplex 未运行时跑 gen_reject_wavs.py 生成。") + return False + return True + def _rokid_extra_args(self): """按配置追加参数(对应 ps1 里的 $bridgeArgs += ...)。""" extra = [] @@ -524,7 +934,18 @@ def _spawn(self, name): creationflags = subprocess.CREATE_NEW_PROCESS_GROUP # worker / gateway 是上游 MiniCPM-o-Demo 的文件(worker.py / gateway.py), # 必须在那个目录下启动才能找到。llama / demo / rokid 用的是绝对路径,不依赖 cwd。 - if name in ("worker", "gateway"): + # harness / demo_funnel 用 `python -m extensions...` 启动, + # **cwd 必须是 OpenGlass 仓库根** —— extensions/ 就在它下面。 + # ★ 不要用 PYTHONPATH 代替:`-m` 时 sys.path[0] 是 cwd,cwd 优先于 + # PYTHONPATH。如果 cwd 设成 MiniCPM-o-Demo 而那边**也有**一份 + # extensions/,OpenGlass 这份会被完全遮蔽(改了不生效); + # 更糟的是 PYTHONPATH 把 OpenGlass 根塞进 sys.path,实测导致 + # paddle 导入失败(partially initialized module 'paddle' ... + # circular import)→ 方向分类器加载失败 → 回退到错误的早期 CV 判据 + # → 第一轮就误报 orient_flipped,然后播报拉长帧间隔又误报 severe_shake。 + if name in ("harness", "demo_funnel"): + _cwd = self._repo_root() + elif name in ("worker", "gateway"): _cwd = self.cfg.get("minicpm_demo_dir") or self.cfg.get("cwd") or None if not _cwd: self._log(name, "!! 未配置 minicpm_demo_dir(MiniCPM-o-Demo 目录)," @@ -676,6 +1097,21 @@ def _wait_ready_or_die(self, name, timeout): self._log(name, "就绪(关键字命中),放行") return True elapsed = time.time() - t_start + if name == "harness": + # 8021 是自签 wss,不能用 HTTP health,只能探 TCP 端口。 + # 而且端口开了之后 /ws/control 还要一小会儿才绑好, + # 不等的话 esp32_runtime 连过去会失败。 + if self._port_open(8021): + self._log("harness", "8021 端口已开,再等 2s 让 /ws/control 绑好") + time.sleep(2.0) + self._log("harness", "harness 就绪,放行") + return True + _now = time.time() + if _now - last_log > 5: + last_log = _now + self._log("harness", f"等待 8021 (FunASR 模型加载中) {elapsed:.0f}s") + time.sleep(1.0) + continue if name == "llama": # llama-omni-server:轮询 /health 返回 200 才放行(= 你手动的 curl .../health) if self._http_ok(llama_url): @@ -775,6 +1211,11 @@ def _other_tails(self): return [c["tail"] for k, c in self.cfg["chains"].items() if c["tail"] != cur] def _do_start_all(self): + # ②③④ 的两个前置检查:extensions 复制了没、档位④的 wav 有没有。 + # 提前拦住比跑起来才发现好 —— 后者时 duplex 已在跑,没法当场补。 + if (not self._check_extensions() or not self._check_deps() + or not self._check_reject_wav()): + return """按序补齐:只起没在跑的,已在跑的跳过;被急停立即停下。""" # 切链后若另一条链的尾巴还活着,先杀掉——两个客户端同时占一个 gateway # 会互相抢 session,必须互斥。 @@ -940,24 +1381,34 @@ def get_config(self): "need_device": c["need_device"], "fpv_url": self.cfg.get(c["fpv_key"], ""), "procs": c["start_order"], + # 只有开了漏斗的链路(③④)才需要选判据档位;①②选了也不起作用 + "need_scene": int(c.get("funnel", 0)) > 0, } return { "presets": self.cfg["presets"], "fpv_url": self.cfg["fpv_url"], "devices": self.cfg.get("devices", []), "chains": chains, + "scenes": list(self.cfg.get("scenes", {}).keys()), + "default_scene": self.cfg.get("default_scene", ""), + "proc_labels": self.cfg.get("proc_labels", {}), "default_chain": self.cfg.get("default_chain", "esp32"), } def set_chain(self, chain): return self.mgr.set_chain(chain) + def set_scene(self, scene): + if scene: + self.mgr.current_scene = scene + return "ok" + def set_device(self, device): if device: self.mgr.current_device = device return "ok" - def start_all(self, prompt=None, device=None, chain=None): + def start_all(self, prompt=None, device=None, chain=None, scene=None): # prompt 来自前端文本框(用户选的 preset 或编辑后的内容)。在起进程前更新 # current_prompt,否则一键启动只会用初始的第一个 preset。 if prompt: @@ -966,6 +1417,8 @@ def start_all(self, prompt=None, device=None, chain=None): self.mgr.set_chain(chain) if device: self.mgr.current_device = device + if scene: + self.mgr.current_scene = scene self.mgr.start_all(); return "ok" def stop_all(self): diff --git a/runtime/openglass_omni/runtime.example.json b/runtime/openglass_omni/runtime.example.json index f3c77a1..c69bde1 100644 --- a/runtime/openglass_omni/runtime.example.json +++ b/runtime/openglass_omni/runtime.example.json @@ -1,33 +1,28 @@ { - "_comment": "Copy to runtime.local.json. Paths are resolved relative to this file and may use environment variables.", - "python": "", - "minicpm_demo_root": "${MINICPM_O_DEMO_ROOT}", - "llama_cpp_omni_root": "${LLAMA_CPP_OMNI_ROOT}", - "devices_file": "devices.local.json", - "prompts_file": "prompts.json", - "state_dir": "state", - "worker": { - "host": "127.0.0.1", - "port": 22440, - "ready_timeout_s": 180 + "_comment": "复制为 runtime.local.json 后填写。该文件不进仓库(加进 .gitignore)。路径支持 ${ENV_VAR} 和 ~。", + + "_conda": "留空表示已在外部 conda activate;填环境名则由 panel 用 conda run 启动子进程", + "conda_env": null, + + "_paths": "三个仓库相互独立,各自填自己的绝对路径", + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + + "_asr": "②③④ 链路的语音控制(8021 harness)用的 FunASR 流式模型目录", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + + "_glasses": "Rokid 链路要把 WiFi 传给 APK。不要把真实密码提交进仓库", + "glasses": { + "ssid": "YOUR_WIFI_SSID", + "psk": "YOUR_WIFI_PASSWORD" }, - "gateway": { - "host": "127.0.0.1", - "bind_host": "0.0.0.0", - "port": 8040, - "tls": true, - "certfile": "certs/cert.pem", - "keyfile": "certs/key.pem", - "ready_timeout_s": 45 - }, - "demo": { - "ui_host": "127.0.0.1", - "ui_port": 8080, - "audio_endpoint": "/ws_audio", - "image_min_interval_s": 0.8, - "player_hostapi": "wasapi", - "player_prebuffer_ms": 200, - "connect_wait_s": 120, - "ready_timeout_s": 20 - } + + "_ports": "以下为当前 V2 链路的实际端口,仅供参考;panel.py 里已按此配置,改动需同步改 panel", + "worker": { "host": "127.0.0.1", "port": 22400 }, + "gateway": { "host": "127.0.0.1", "port": 8006, "tls": true, + "certfile": "certs/cert.pem", "keyfile": "certs/key.pem" }, + "llama": { "host": "127.0.0.1", "port": 22500 }, + "harness": { "host": "127.0.0.1", "port": 8021 }, + "demo": { "ui_port": 8080 } } From 5a6b59df29fdb7ed18736b03db011fb8895feeb8 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Fri, 4 Sep 2026 11:11:09 +0800 Subject: [PATCH 3/6] fix: address PR review - README: correct requirements-phase-b.txt path (both languages) and the MiniCPM-o-Demo clone branch (master -> main); llama.cpp-omni stays on master - panel: restart the tail process when the chain configuration changes. Chains 2/3/4 share the demo_funnel process name, so neither the cross-chain kill nor the alive check would restart it and the previous funnel arguments stayed in effect. Now keyed on a (chain, funnel level, criteria, device, prompt) fingerprint, which also covers device/criteria changes within a chain. - bridge_ui: default to loopback instead of 0.0.0.0. Binds both 127.0.0.1 and ::1 so the panel's embedded http://localhost:8080 view keeps working on hosts that resolve localhost to IPv6. Non-loopback binds now log what they expose. - esp32_runtime: pass stop_callback to WebUIServer so POST /api/stop actually stops the runtime and finalizes the session; add --web-ui-host - esp32_runtime: the reject hint records gate.stop_count before pausing and only resumes if it still owns the pause, so a user STOP during the hint is no longer overridden --- README.md | 68 ++++--------------- README_zh.md | 9 +-- .../assistive_harness/phase_b/bridge_ui.py | 35 ++++++++-- .../phase_b/esp32_runtime.py | 48 ++++++++++++- runtime/openglass_omni/panel.py | 44 +++++++++++- 5 files changed, 138 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 24f2bde..2bf698a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Solid arrows represent code or artifacts present in the public repository. Dashe The control panel is intended to make **repeated runs** one-click after a one-time setup. It does not download model weights, clone upstream repositories, compile `llama.cpp-omni`, or flash the ESP32 for you. -> **Current clean-clone status:** The panel itself starts directly from the repository root, but the full chain still needs four out-of-repo assets prepared by hand: the `llama.cpp-omni` build, MiniCPM-o GGUF weights, the FunASR model, and the Wi-Fi credentials inside the ESP32 firmware. None of these live in this repository, and none can be fetched automatically. +> **Current clean-clone status:** The panel UI starts from the repository root, but the current launcher still reads machine-specific paths from `runtime/openglass_omni/panel.py`. The included `runtime.local.json` loader is not yet connected to that panel. Follow the effective configuration locations below; a code update is still required before this can be called a portable one-click installation. ### 1. Prerequisites @@ -120,7 +120,7 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DLLAMA_CURL=OFF cmake --build build --config Release --target llama-omni-server -j cd .. -git clone --branch master https://github.com/OpenBMB/MiniCPM-o-Demo.git +git clone --branch main https://github.com/OpenBMB/MiniCPM-o-Demo.git cd MiniCPM-o-Demo python -m pip install -r requirements.txt cd .. @@ -129,7 +129,7 @@ git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt -python -m pip install -r extensions/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) +python -m pip install -r extensions/assistive_harness/phase_b/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) ``` @@ -180,32 +180,17 @@ Edit `runtime/openglass_omni/devices.json`: ### 5. Configure the current launcher -Copy [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) to -`runtime.local.json` in the same directory and fill in your machine paths. The panel reads -it at startup and uses those values instead of the defaults in `panel.py`: +At present, these are the **effective** settings: -```json -{ - "conda_env": null, - "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", - "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", - "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", - "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", - "glasses": { "ssid": "YOUR_WIFI", "psk": "YOUR_WIFI_PASSWORD" } -} -``` - -| What to configure | Location | Value | +| What to configure | Effective location now | Value | | --- | --- | --- | -| MiniCPM-o-Demo checkout | `minicpm_demo_root` | Absolute path containing upstream `worker.py` / `gateway.py` | -| `llama-omni-server` binary | `llama_server` | Compiled executable under `llama.cpp-omni/build` | -| Main GGUF model | `llama_model` | Absolute path to the main MiniCPM-o 4.5 GGUF | -| ASR model | `asr_model` | FunASR streaming model directory, used by voice control in chains 2-4 | -| Glasses Wi-Fi | `glasses.ssid` / `glasses.psk` | Passed to the Rokid APK at launch; leave empty and only that chain loses glasses connectivity | +| MiniCPM-o-Demo checkout | [`panel.py` `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | Absolute path containing upstream `worker.py` and `gateway.py` | +| `llama-omni-server` binary | [`panel.py` `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | Compiled executable under `llama.cpp-omni/build` | +| Main GGUF model | Same `llama` command after `-m` | Absolute path to the main MiniCPM-o 4.5 GGUF | | Glasses name/IP/rotation | `runtime/openglass_omni/devices.json` | One entry per ESP32 glasses prototype | -| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the panel | +| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the current panel | -The panel self-signs a TLS certificate and key pair under `/certs/` on first launch, used by the `wss` connections to the gateway (8006) and the voice-control harness (8021). An existing pair is left untouched. +[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) and [`prompts.json`](runtime/openglass_omni/prompts.json) document the intended local configuration boundary, but the current panel does not consume either file. Copying the runtime example to `runtime.local.json` does **not yet replace** the hardcoded panel paths or prompt presets. This is a known integration issue, not a user configuration mistake. ### 6. Configure and flash Wi-Fi firmware @@ -221,39 +206,16 @@ Activate the same Python environment used for MiniCPM-o-Demo, then run from the python glasses_panel.py ``` -Pick a **chain**, a **device** (and a **criteria** preset for chains 3-4) at the top, -then click **Start**. - -Five chains are available. The four ESP32 ones are cumulative — each adds exactly one -thing to the previous: - -| Chain | Function | Processes started | -| --- | --- | --- | -| 1 Basic chat | Full-duplex omni-modal conversation with the local model through the glasses | llama -> worker -> gateway -> esp32_bridge | -| 2 Voice control | Understands "stop", "start over", "find X" | llama -> worker -> gateway -> harness -> esp32_bridge | -| 3 Frame selection | Picks the sharpest of several frames per second | same as 2 | -| 4 Full anti-hallucination | Rejects bad frames with a spoken hint, so the model never sees them | same as 2 | -| Rokid | Reverse link: the PC listens on 18080 for the APK | llama -> worker -> gateway -> rokid | - -Chains 1-4 are **mutually exclusive**: each needs exclusive access to the glasses' audio -channel and image port, so only one can run at a time. +Select **ESP32 Glasses**, choose the device name, and click **Start**. The current panel attempts to start: ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> harness :8021 (chains 2-4 only) - -> glasses client / first-person view :8080 + -> ESP32 bridge / local view :8080 ``` -The **criteria** selector (chains 3-4 only) picks which calibration the funnel uses: - -- **Strict** — safety-relevant scenes, such as reading a medicine box or a street sign. This preset rejects low-quality frames aggressively to keep the model from hallucinating. -- **Everyday** — ordinary day-to-day scenes. - -The chain is ready only when all process indicators are green and the first-person view is -updating. A successful UI launch alone does not prove the model, audio, image, and -response path is complete. +The chain is ready only when all four process indicators are green and the first-person view is updating. A successful UI launch alone does not prove the model, audio, image, and response path is complete. ### Panel lifecycle @@ -299,8 +261,8 @@ Upstream model projects and model weights remain external dependencies and are n ## Known Limitations -- Task injection on skill switch has no effect over the current `/v1/realtime` protocol (there is no equivalent field); the model relies on the system prompt instead. -- Basic chat and the harness chains each carry their own first-person-view frontend and recorder, so the tree contains two same-named copies. They do not interfere, but the duplication is easy to misread. +- A clean-machine end-to-end Omni run has not yet been verified from the current public tree. +- The current panel still contains machine-specific runtime paths instead of consuming `runtime.local.json`. - Prompt presets are still embedded in `panel.py`; the standalone `prompts.json` file is not yet connected. - ESP32 Wi-Fi credentials still require editing the tracked `.ino`; the local header template is not wired in yet. - Normal panel close performs cleanup, but abnormal termination can leave child or externally started processes running. diff --git a/README_zh.md b/README_zh.md index 71d658b..ba13d70 100644 --- a/README_zh.md +++ b/README_zh.md @@ -92,7 +92,7 @@ flowchart LR 控制面板的目标是:完成一次性环境准备后,后续实验可以一键重复启动。它不会替用户下载模型权重、clone 上游仓库、编译 `llama.cpp-omni` 或烧录 ESP32。 -> **当前全新 clone 状态:** 面板本身可以从仓库根目录直接启动,但整套链路仍需手动准备四样仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型、以及 ESP32 固件里的 Wi-Fi 凭据。这几项都不在本仓库内,需按以下说明安装。 +> **当前全新 clone 状态:** 从仓库根目录启动面板 UI,本机路径写在 `runtime.local.json`(复制 `runtime.example.json` 得到),面板启动时读取。眼镜列表和旋转角在 `devices.json`。TLS 证书首次启动自动生成。仍需手动准备的是仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型,以及 ESP32 固件里的 Wi-Fi 凭据。 ### 1. 前置条件 @@ -120,7 +120,7 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DLLAMA_CURL=OFF cmake --build build --config Release --target llama-omni-server -j cd .. -git clone --branch master https://github.com/OpenBMB/MiniCPM-o-Demo.git +git clone --branch main https://github.com/OpenBMB/MiniCPM-o-Demo.git cd MiniCPM-o-Demo python -m pip install -r requirements.txt cd .. @@ -129,7 +129,7 @@ git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt -python -m pip install -r extensions/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) +python -m pip install -r extensions/assistive_harness/phase_b/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) ``` @@ -207,7 +207,8 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j | 眼镜名称/IP/旋转角 | `runtime/openglass_omni/devices.json` | 每副 ESP32 眼镜一条记录 | | Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 面板中显示的交互 Prompt | -> 面板首次启动时会在 `/certs/` 下自签一对 TLS 证书,供 gateway(8006)和语音控制 harness(8021)的 `wss` 连接使用。 +**TLS 证书不用手动准备。** 面板首次启动时会在 `/certs/` 下自签一对 +(gateway 8006 和 harness 8021 共用),已存在则不覆盖。 ### 6. 配置并烧录 Wi-Fi 固件 diff --git a/extensions/assistive_harness/phase_b/bridge_ui.py b/extensions/assistive_harness/phase_b/bridge_ui.py index c3940f8..a65ed15 100644 --- a/extensions/assistive_harness/phase_b/bridge_ui.py +++ b/extensions/assistive_harness/phase_b/bridge_ui.py @@ -52,7 +52,10 @@ def _load_template(name: str) -> str: # ============================================================ class WebUIServer: - def __init__(self, port: int = 8080, host: str = "0.0.0.0", + # 默认只绑回环:这个服务把第一视角画面、session 元数据、原始 user/AI wav + # 全部无认证地暴露出去。绑 0.0.0.0 等于把它们放给整个局域网, + # 要那样必须由调用方显式指定 host。 + def __init__(self, port: int = 8080, host: str = "127.0.0.1", sessions_root: Path = Path("./sessions"), stop_callback: Optional[Callable[[], None]] = None, mode_info: Optional[dict] = None): @@ -85,9 +88,28 @@ async def start(self) -> None: app.router.add_post('/api/stop', self._h_stop) self._runner = web.AppRunner(app) await self._runner.setup() - site = web.TCPSite(self._runner, self.host, self.port) - await site.start() - LOGGER.info("[UI] http://%s:%d (live + replay)", self.host, self.port) + # 回环默认同时绑 IPv4 和 IPv6。 + # 只绑 "127.0.0.1" 的话是**纯 IPv4**,而 Windows 上浏览器把 + # `localhost` 优先解析成 ::1 的情况很常见 —— 那时 panel 内嵌的 + # http://localhost:8080 会连不上(表现就是第一视角一片空白)。 + # 绑成 ["127.0.0.1", "::1"] 两边都覆盖,又不暴露到局域网。 + _hosts = self.host + if self.host in ("127.0.0.1", "localhost", "::1"): + _hosts = ["127.0.0.1", "::1"] + try: + site = web.TCPSite(self._runner, _hosts, self.port) + await site.start() + except OSError as e: + # 系统没开 IPv6 之类:退回单地址,别让整个第一视角起不来 + LOGGER.warning("[UI] 绑定 %s 失败(%s),退回 %s", _hosts, e, self.host) + site = web.TCPSite(self._runner, self.host, self.port) + await site.start() + LOGGER.info("[UI] http://localhost:%d (live + replay) bind=%s", + self.port, _hosts) + if self.host not in ("127.0.0.1", "localhost", "::1"): + LOGGER.warning( + "[UI] !! 绑定在 %s —— 第一视角画面、session 元数据、" + "原始 user/AI 录音将无认证地暴露给局域网内任何人。", self.host) async def stop(self) -> None: for ws in list(self.live_clients): @@ -293,7 +315,10 @@ def _main() -> None: description="Bridge UI — standalone replay server (no ESP32 / no model)" ) parser.add_argument("--port", type=int, default=8080) - parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--host", default="127.0.0.1", + help="绑定地址。默认只绑回环 —— 本服务无认证地提供" + "第一视角画面、session 元数据和原始 user/AI wav," + "填 0.0.0.0 会把这些暴露给整个局域网") parser.add_argument("--sessions", default="./sessions", help="sessions 根目录(默认 ./sessions)") args = parser.parse_args() diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py index d343a9c..285eec2 100644 --- a/extensions/assistive_harness/phase_b/esp32_runtime.py +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -1049,6 +1049,15 @@ async def _do_reject_interrupt_inner(reason): if wav_pcm is None: LOG.warning("[强制措施] 无 %s.wav,跳过播报", reason) return + # 记下发 stop 时的 stop_count,作为"这次暂停归我"的凭据。 + # 漏斗的 stop 意思是"先别说,我要插播提示", + # 用户的 stop 意思是"闭嘴,我不想听" —— 两者走同一条 8021 + # 控制腿,无从区分。播报期间用户若说"停一下", + # gate.stop() 会让 stop_count 再 +1;此时若还无条件 resume, + # 就把用户的停止状态覆盖掉了。 + # (播报改成后台任务之后,这个并发窗口更大了。) + _gate = getattr(manager, "gate", None) + _owned = getattr(_gate, "stop_count", None) if _gate else None try: await harness.send({"type": "funnel.stop", "reason": reason}) LOG.info("[强制措施] funnel.stop 已发 (%s)", reason) @@ -1065,6 +1074,14 @@ async def _do_reject_interrupt_inner(reason): await asyncio.sleep(dur + 0.2) except Exception as e: LOG.warning("[强制措施] 播 wav 失败: %s", e) + # 只有"这次暂停仍归我"才 resume。stop_count 变了说明期间 + # 有新的 stop 进来(用户按的),此时保持停止状态不动。 + _now_cnt = getattr(_gate, "stop_count", None) if _gate else None + if _owned is not None and _now_cnt is not None and _now_cnt != _owned: + LOG.info("[强制措施] 播报期间收到新的 STOP" + "(stop_count %s→%s),保留用户的停止状态,不 resume", + _owned, _now_cnt) + return try: await harness.send({"type": "funnel.resume", "reason": "hint_done"}) LOG.info("[强制措施] funnel.resume 已发(提示播完)") @@ -1346,7 +1363,7 @@ def __init__(self, config, esp32_host, esp32_port, image_tcp_port, gateway_host="127.0.0.1", gateway_port=8040, reject_wav_dir="assets/reject_wav", live_record_dir=None, rerun_from=None, - funnel_rerun_from=None, web_ui_port=None, + funnel_rerun_from=None, web_ui_port=None, web_ui_host="127.0.0.1", record_no_media: bool = False, rerun_tail_wait_s: float = 30.0, no_reject: bool = False, @@ -1395,8 +1412,12 @@ def __init__(self, config, esp32_host, esp32_port, image_tcp_port, try: self._web_ui = WebUIServer( port=web_ui_port, + host=web_ui_host, sessions_root=Path(live_record_dir).parent if live_record_dir else Path("live_sessions"), + # 接上运行时的停止事件:不接的话 POST /api/stop 会返回成功、 + # 前端按钮也变灰,但运行时根本没停,session 也不会收尾落盘。 + stop_callback=self._stop_evt.set, mode_info={"mode": "rerun" if (rerun_from or funnel_rerun_from) else "live"}, ) @@ -1531,6 +1552,26 @@ async def start(self) -> None: # oneDNN 编译(~2s,甚至 5s+)。不预热的话它会推迟到第一次 accept 才现场加载, # 卡住那一轮,且在此之前链路出不了 send(模型长时间拿不到图)。 if self._funnel is not None: + # ★ 先在**主线程**里把 paddle/paddleocr 导进来。 + # cam_pipeline_v2 的 `from paddleocr import ...` 是懒加载、写在函数体里, + # 而 warmup_orient 走 asyncio.to_thread(工作线程)—— paddle 这类 + # 带大量 C 扩展和内部循环依赖的包,在非主线程首次导入时会撞上 + # "partially initialized module 'paddle' has no attribute 'tensor' + # (most likely due to a circular import)", + # 然后 _ORI_CLS_TRIED 永久置位、整个进程退回错误的早期 CV 判据, + # 表现就是第一轮就误报 orient_flipped(实测 panel 启动必现)。 + # 在主线程预导一次,后面线程里再 import 就是拿缓存,不会再触发。 + try: + # ★ 只导这一个符号,**不要 `import paddleocr` 或 `import paddle`**。 + # `import paddleocr` 会走 paddlex.inference.utils.official_models + # → import modelscope → modelscope.utils.logger → import torch, + # 而这个环境里 torch 的 shm.dll 加载失败(WinError 127), + # 于是整条链断掉、方向分类器退回错误的早期 CV 判据。 + # 窄导入不经过那一支,实测可用(cam_pipeline_v2 里也是这么写的)。 + from paddleocr import DocImgOrientationClassification # noqa: F401 + LOG.info("[预热] paddleocr 方向分类器已在主线程预导入") + except Exception as e: + LOG.warning("[预热] 方向分类器预导入失败(可能退回轻量判据): %s", e) try: ms = await asyncio.to_thread(self._funnel.warmup_orient) # 必须查真实状态:这行原来无条件打"就绪",而加载失败时 @@ -1770,6 +1811,10 @@ def parse_args() -> argparse.Namespace: p.add_argument("--web-ui-port", type=int, default=None, help="开 bridge_ui 第一视角(如 8080),live/rerun/funnel-rerun 都可看") # ── 强制措施(防幻觉):reject 时用模型音色念提示 + 停/恢复走 8021 ── + p.add_argument("--web-ui-host", default="127.0.0.1", + help="第一视角服务的绑定地址。默认只绑回环 —— 该服务无认证地提供" + "画面、session 元数据和原始 user/AI 录音;" + "要给局域网内别的设备看才填 0.0.0.0,风险自负") p.add_argument("--force-measure", action="store_true", help="开启强制措施:reject→停duplex→播预生成wav→恢复duplex") p.add_argument("--reject-wav-dir", default="assets/reject_wav", @@ -1874,6 +1919,7 @@ def main() -> None: rerun_from=args.rerun_from, funnel_rerun_from=args.funnel_rerun_from, web_ui_port=args.web_ui_port, + web_ui_host=args.web_ui_host, record_no_media=args.record_no_media, rerun_tail_wait_s=args.rerun_tail_wait_s, no_reject=args.no_reject, diff --git a/runtime/openglass_omni/panel.py b/runtime/openglass_omni/panel.py index d3bce4d..e16bcb6 100644 --- a/runtime/openglass_omni/panel.py +++ b/runtime/openglass_omni/panel.py @@ -580,6 +580,10 @@ def __init__(self, cfg): self.current_prompt = next(iter(cfg["presets"].values())) self.current_device = (cfg.get("devices") or ["默认"])[0] self.current_scene = cfg.get("default_scene", "严格判据") + # 尾进程是"为哪套配置"起的。②③④ 共用 demo_funnel 这一个进程名, + # 只看进程活着就跳过启动的话,切链路后新的漏斗参数永远不会生效 —— + # UI 显示④,实际还在跑②。所以记指纹,变了就重启。 + self._tail_started_for = {} # tail 进程名 -> 指纹 # —— 当前链路:esp32 / rokid,决定第四级起哪个进程 —— self.current_chain = cfg.get("default_chain", "esp32") self._lock = threading.Lock() @@ -980,6 +984,7 @@ def _spawn(self, name): return proc def _kill(self, name, graceful=False, grace_timeout=20): + self._forget_tail_fp(name) # 进程要没了,指纹一并作废 proc = self.procs.get(name) if not proc or proc.poll() is not None: self.status[name] = "stopped" @@ -1183,6 +1188,9 @@ def _start_one(self, name): self._spawn(name) if self._wait_ready_or_die(name, ready_timeout): self.status[name] = "running" + if name == self.tail(): + # 记下这次是按哪套配置起的,下次切链路时用来判断要不要重启 + self._tail_started_for[name] = self._tail_fingerprint() return True # 未就绪/退出/被急停:先把这次 spawn 的进程杀干净,绝不留残余 p = self.procs.get(name) @@ -1205,11 +1213,28 @@ def _start_one(self, name): return False return False + def _forget_tail_fp(self, name): + """进程不在了就清掉指纹,否则下次会误判成"配置没变、跳过启动"。""" + self._tail_started_for.pop(name, None) + def _other_tails(self): """除当前链路外,其它链路的第四级进程名。""" cur = self.tail() return [c["tail"] for k, c in self.cfg["chains"].items() if c["tail"] != cur] + def _tail_fingerprint(self): + """当前链路下,尾进程真正依赖的那几个量。 + + 任何一项变了,已在跑的尾进程就是按旧配置起的,必须重启: + chain 决定漏斗档位(--funnel / --no-reject / --force-measure) + scene 决定 --scene(严格/日常判据) + device 决定 --esp32-host / --esp32-port / --rotate + prompt 决定 --prompt + """ + c = self.chain() + return (self.current_chain, c.get("funnel", 0), self.current_scene, + self.current_device, self.current_prompt) + def _do_start_all(self): # ②③④ 的两个前置检查:extensions 复制了没、档位④的 wav 有没有。 # 提前拦住比跑起来才发现好 —— 后者时 duplex 已在跑,没法当场补。 @@ -1228,9 +1253,22 @@ def _do_start_all(self): if self._cancel.is_set(): return if self._alive(name): - self.status[name] = "running" - self._log(name, "已在运行,跳过启动") - continue + # 尾进程还要比配置指纹:同一个 demo_funnel 进程, + # ②③④ 传的参数完全不同,光看"活着"会漏掉重启。 + if name == self.tail(): + want = self._tail_fingerprint() + got = self._tail_started_for.get(name) + if got is not None and got != want: + self._log(name, "配置已变(链路/判据/眼镜/Prompt),重启该进程") + self._kill(name, graceful=True, grace_timeout=120) + else: + self.status[name] = "running" + self._log(name, "已在运行,跳过启动") + continue + else: + self.status[name] = "running" + self._log(name, "已在运行,跳过启动") + continue if not self._start_one(name): if self._cancel.is_set(): self._log(name, "!! 启动被急停中止") From 10272ad29cf482cc453018f0630b47e8dfdd99ba Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Mon, 7 Sep 2026 17:25:45 +0800 Subject: [PATCH 4/6] fix(firmware): allow OV5640AF to auto focus following commands from funnel Adds the ESP32_OV5640_AF driver and wires the AF trigger the funnel calls. The sketch in the tree predated autofocus support, so --funnel's focus commands were silently no-ops on the actual device. --- .../CameraWebServer_PDM_Audio.ino | 276 +- CameraWebServer_PDM_Audio/ESP32_OV5640_AF.cpp | 85 + CameraWebServer_PDM_Audio/ESP32_OV5640_AF.h | 27 + CameraWebServer_PDM_Audio/ESP32_OV5640_cfg.h | 4134 +++++++++++++++++ CameraWebServer_PDM_Audio/app_httpd.cpp | 440 +- 5 files changed, 4923 insertions(+), 39 deletions(-) create mode 100644 CameraWebServer_PDM_Audio/ESP32_OV5640_AF.cpp create mode 100644 CameraWebServer_PDM_Audio/ESP32_OV5640_AF.h create mode 100644 CameraWebServer_PDM_Audio/ESP32_OV5640_cfg.h diff --git a/CameraWebServer_PDM_Audio/CameraWebServer_PDM_Audio.ino b/CameraWebServer_PDM_Audio/CameraWebServer_PDM_Audio.ino index abad71b..a44aaa1 100644 --- a/CameraWebServer_PDM_Audio/CameraWebServer_PDM_Audio.ino +++ b/CameraWebServer_PDM_Audio/CameraWebServer_PDM_Audio.ino @@ -32,19 +32,32 @@ #include "esp_camera.h" #include +#include "esp_wifi.h" +#include "ESP32_OV5640_AF.h" // ★ 新增:OV5640 自动变焦(VCM)库。AF 只走 SCCB 控制镜头马达, + // 不改变图像输出格式/传输协议,capture/stream/PC 端一律不用动。 +// ★ 新增:TCP 图像通道(与 HTTP /capture 并存,运行期由 PC 端选择走哪条)。 +// 设计:独立 FreeRTOS task + 独立端口 5000,请求-响应式(PC 发 1 字节 → 回一帧 HD JPEG)。 +// 关键:task 绑 Core 0(靠 WiFi 栈)、优先级 4(低于 audio_sender 的 6), +// 让音频发送永远优先,避免传图饿死音频——这是 TCP 方案相对 HTTP 共用单线程 httpd 的真正优势。 +WiFiServer g_image_tcp_server(5000); // =================== // Select camera model // =================== #define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM #include "camera_pins.h" +// ★ 新增:全局 AF 对象。setup() 里一次性初始化为连续自动对焦后即放手, +// loop() 不再轮询/触发它,避免与抓图争用 SCCB(I2C)总线。 +OV5640 ov5640 = OV5640(); +// 对焦模式: false=由 PC 通过 /control?var=af 按需触发(默认); +// true=固件自动定时对焦(仅调试/对比用) +static bool g_auto_af = false; // =========================== // Enter your WiFi credentials // =========================== -const char *ssid = "YOUR_WIFI_NAME"; -const char *password = "YOUR_WIFI_PASSWORD"; - +const char* ssid = "YOUR_WIFI_NAME"; +const char* password = "YOUR_WIFI_PASSWORD"; // Forward declarations void startCameraServer(); @@ -75,8 +88,12 @@ static void setup_cam_config() { cam_config.pin_sccb_scl = SIOC_GPIO_NUM; cam_config.pin_pwdn = PWDN_GPIO_NUM; cam_config.pin_reset = RESET_GPIO_NUM; - cam_config.xclk_freq_hz = 10000000; // 10MHz, headroom for WiFi stack - cam_config.frame_size = FRAMESIZE_HD; // 1280x720 + cam_config.xclk_freq_hz = 20000000; // 前端实测为20MHz + //cam_config.frame_size = FRAMESIZE_QSXGA; // 2592x1944 5MP 摸边界用最大分辨率 + //cam_config.frame_size = FRAMESIZE_QXGA; + //cam_config.frame_size = FRAMESIZE_FHD; + cam_config.frame_size = FRAMESIZE_HD; + cam_config.pixel_format = PIXFORMAT_JPEG; cam_config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; cam_config.fb_location = CAMERA_FB_IN_PSRAM; @@ -86,10 +103,10 @@ static void setup_cam_config() { if (cam_config.pixel_format == PIXFORMAT_JPEG) { if (psramFound()) { cam_config.jpeg_quality = 10; - cam_config.fb_count = 2; + cam_config.fb_count = 2; // 5MP一帧很大,降到1避免PSRAM装不下 cam_config.grab_mode = CAMERA_GRAB_LATEST; } else { - cam_config.frame_size = FRAMESIZE_SVGA; + cam_config.frame_size = FRAMESIZE_HD; cam_config.fb_location = CAMERA_FB_IN_DRAM; } } else { @@ -100,6 +117,8 @@ static void setup_cam_config() { } } + + static void apply_sensor_settings() { sensor_t *s = esp_camera_sensor_get(); if (!s) { @@ -107,33 +126,41 @@ static void apply_sensor_settings() { return; } - // Basic orientation - s->set_vflip(s, 1); - s->set_hmirror(s, 0); + // ======================================================================== + // 说明(AF 版精简): + // 原参数是为「定焦相机 + 固定室内场景看清」手调的。换 AF 后,光学清晰度 + // 交给自动对焦负责,这里只保留「成像质量基础」——AF 替代不了的部分: + // · 三个自动算法主开关(AEC/AGC/AWB):光线适应的根本,关了图就废 + // · saturation=0:之前踩坑修掉的偏色(粉色)补丁,和对焦无关,必须留 + // · vflip/hmirror:镜头物理方向,和眼镜佩戴朝向绑定 + // · lenc:镜头阴影校正(四角暗角,也影响白平衡);AF 模组暗角特性可能 + // 与定焦不同,先保留,烧后看四角是否正常再决定去留。 + // 删除的是为定焦特定场景硬调的项(手动曝光区间 reg / ae_level / + // gainceiling / contrast / sharpness / denoise / quality),交回自动/默认。 + // ======================================================================== + + // ---- 方向(物理朝向,必须保留)---- + s->set_vflip(s, 0); + s->set_hmirror(s, 1); - // Exposure - s->set_aec2(s, 1); - s->set_ae_level(s, -2); - s->set_aec_value(s, 168); + // ---- 自动曝光主开关(保留,交给 ISP 自适应)---- + s->set_exposure_ctrl(s, 1); // ★ AEC 主开关 + s->set_aec2(s, 1); // DSP 端 AEC 辅助 - // Gain - s->set_agc_gain(s, 0); - s->set_gainceiling(s, (gainceiling_t)0); + // ---- 自动增益主开关(保留)---- + s->set_gain_ctrl(s, 1); // ★ AGC 主开关 - // White balance - s->set_awb_gain(s, 1); - s->set_wb_mode(s, 0); + // ---- 自动白平衡主开关(保留)---- + s->set_whitebal(s, 1); // ★ AWB 主开关 + s->set_awb_gain(s, 1); // 允许 AWB 调 R/B 增益 + s->set_wb_mode(s, 0); // 0 = Auto - // Contrast/saturation - s->set_contrast(s, 2); - s->set_brightness(s, 0); - s->set_saturation(s, 2); + // ---- 防偏色补丁(必须保留,和对焦无关)---- + s->set_saturation(s, 0); // ★ 原来是 2,粉色的头号元凶,务必降到 0 - // Lens correction + sharpness - s->set_lenc(s, 1); - s->set_sharpness(s, 1); + // ---- 镜头阴影校正(建议保留,烧后看四角再定)---- + s->set_lenc(s, 1); // 四角暗角修正,也影响白平衡 - // Resolution s->set_framesize(s, FRAMESIZE_HD); } @@ -148,6 +175,31 @@ bool init_camera() { return false; } apply_sensor_settings(); + + // ======================================================================== + // ★ AF 初始化(低频对焦,不用连续模式) + // 连续对焦(autoFocusMode)会让 AF 固件持续用 SCCB(I2C)驱动马达+读状态, + // 而抓图 esp_camera_fb_get 也走 SCCB,两者持续争用 → 抓图出现数秒空档。 + // 改为:开机对一次;之后 loop() 每隔 AF_REFOCUS_MS 触发一次单次对焦。 + // 单次对焦只在触发那一下用 SCCB,总线大部分时间空给抓图。 + // 用通用寄存器 0x3022=0x03(single auto focus),不依赖 AF 库封装版本。 + // ======================================================================== + { + sensor_t *s = esp_camera_sensor_get(); + if (s) { + ov5640.start(s); + if (ov5640.focusInit() == 0) { + Serial.println("[AF] focusInit OK"); + } else { + Serial.println("[AF] focusInit FAILED (degrade to fixed focus, image still works)"); + } + s->set_reg(s, 0x3022, 0xff, 0x03); // 开机单次对焦 + Serial.println("[AF] low-frequency single-focus mode enabled"); + } else { + Serial.println("[AF] sensor NULL, skip AF init"); + } + } + Serial.printf("[CAM] init OK, free heap: %u, PSRAM free: %u\n", (unsigned)ESP.getFreeHeap(), (unsigned)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); @@ -198,9 +250,23 @@ void setup() { setupLedFlash(LED_GPIO_NUM); #endif + // 如果自带AP,可以用下面这一段 // WiFi + // WiFi — 静态 IP,避免会场 DHCP 拥堵/续租失败 + //IPAddress local_ip(192, 168, 1, 50); + //IPAddress gateway (192, 168, 1, 1); + //IPAddress subnet (255, 255, 255, 0); + //IPAddress dns1 (192, 168, 1, 1); + //WiFi.config(local_ip, gateway, subnet, dns1); + WiFi.begin(ssid, password); WiFi.setSleep(false); + esp_wifi_set_ps(WIFI_PS_NONE); // 双保险:彻底关 PS + WiFi.setTxPower(WIFI_POWER_19_5dBm); // 拉满发射功率 + esp_wifi_config_11b_rate(WIFI_IF_STA, true); // 禁用 11b 低速率,减少被会场干扰拖慢 + // 可选:如果你自己带 AP 并且知道信道号,解开下一行并把 6 改成你 AP 的信道,TODO + // esp_wifi_set_channel(6, WIFI_SECOND_CHAN_NONE); + Serial.print("[WiFi] Connecting"); int wifi_retry = 0; @@ -219,21 +285,161 @@ void setup() { // Start web server startCameraServer(); + // ★ 启动 TCP 图像通道 task:Core 0(靠 WiFi 栈)、优先级 4(低于 audio_sender 的 6), + // 让音频发送永远优先。与 HTTP /capture 并存,PC 端运行期选择走哪条。 + { + BaseType_t ok = xTaskCreatePinnedToCore( + image_tcp_task, "img_tcp", 4096, NULL, 4, NULL, 0); + if (ok != pdPASS) { + Serial.println("[TCP-IMG] task create FAILED (TCP 图像通道不可用,HTTP /capture 仍可用)"); + } + } + Serial.println("========================================"); Serial.printf("[READY] Web UI: http://%s/\n", WiFi.localIP().toString().c_str()); Serial.printf("[READY] Capture: http://%s/capture\n", WiFi.localIP().toString().c_str()); Serial.printf("[READY] Stream: http://%s:81/stream\n", WiFi.localIP().toString().c_str()); Serial.printf("[READY] Audio WS: ws://%s/ws_audio\n", WiFi.localIP().toString().c_str()); + Serial.printf("[READY] Image TCP: %s:5000 (req-resp)\n", WiFi.localIP().toString().c_str()); Serial.printf("[READY] Free heap: %u bytes\n", (unsigned)ESP.getFreeHeap()); Serial.println("========================================"); } +// ======================================================================== +// ★ 可选 AF 状态调试函数(只读,不触发对焦) +// 修正了原 AF demo 的判断 bug:原代码只认 FW_STATUS_S_FOCUSED(0x10), +// 漏判了 0x20——而 0x20 同样是「对焦完成」状态(对焦后持续保持)。原代码下 +// 0x20 会落进空 else 不打印,看起来像「没对上」。这里把 0x10 和 0x20 都 +// 识别为已对焦,0x00 为对焦中,其余原样打印 16 进制。 +// 注意:此函数仅用于串口观察,不参与抓图/发送逻辑——图像始终照常发, +// 不因对焦状态丢帧(模糊帧也发,模型会在后续清晰帧上读出内容)。 +// ======================================================================== +static void af_status_debug() { + uint8_t rc = ov5640.getFWStatus(); + if (rc == (uint8_t)-1) { + Serial.println("[AF] FW_STATUS=0xFF Check your OV5640"); + } else if (rc == FW_STATUS_S_FOCUSING) { // 0x00 + Serial.println("[AF] FW_STATUS=0x00 Focusing!"); + } else if (rc == FW_STATUS_S_FOCUSED || rc == 0x20) { // 0x10 或 0x20 都是已对焦 + Serial.printf("[AF] FW_STATUS=0x%02x Focused!\n", rc); + } else { + Serial.printf("[AF] FW_STATUS=0x%02x (other)\n", rc); + } +} + +// ─────────────────────────────────────────────────────────────────────── +// ★ TCP 图像通道任务(与 HTTP /capture 并存) +// 协议(请求-响应,对齐 PC 端 TCP 图像源): +// PC 连上后,每需要一帧就发 1 字节(任意值)作为"请求一帧"; +// ESP32 收到后抓一张 JPEG,回裸帧: +// magic(4,0x55AA55AA) | frame_id(4) | w(2) | h(2) | fmt(1=JPEG) | +// reserved(3) | len(4) | jpeg_bytes(len) 全部小端。 +// 独立 task + Core 0 + 优先级4(len == 0) { + if (fb) esp_camera_fb_return(fb); + uint8_t hdr[20] = {0}; + uint32_t magic = 0x55AA55AA; + memcpy(hdr, &magic, 4); + client.write(hdr, 20); // len=0:PC 端据此知道没抓到 + continue; + } + frame_id++; + uint8_t hdr[20]; + uint32_t magic = 0x55AA55AA; + uint16_t w = fb->width, h = fb->height; + uint32_t len = fb->len; + memcpy(hdr + 0, &magic, 4); + memcpy(hdr + 4, &frame_id, 4); + memcpy(hdr + 8, &w, 2); + memcpy(hdr + 10, &h, 2); + hdr[12] = 0; // fmt = JPEG + hdr[13] = hdr[14] = hdr[15] = 0; // reserved + memcpy(hdr + 16, &len, 4); + // 关键:WiFiClient::write 不保证一次发完(LWIP 发送缓冲满时只发一部分)。 + // 必须循环补发,否则 PC 端读取字节数与实际不符 → TCP 流错位 → bad magic。 + auto write_all = [&](const uint8_t *buf, size_t n) -> bool { + size_t sent = 0; + while (sent < n && client.connected()) { + size_t w = client.write(buf + sent, n - sent); + if (w == 0) { + vTaskDelay(pdMS_TO_TICKS(1)); // 缓冲满,让出后重试 + continue; + } + sent += w; + } + return sent == n; + }; + write_all(hdr, 20); + write_all(fb->buf, fb->len); + esp_camera_fb_return(fb); + } + client.stop(); + Serial.println("[TCP-IMG] client disconnected"); + } +} + +// AF 低频对焦周期(ms)。你的场景"看几秒",焦距变化不频繁,3s够跟上。 +// 图还慢就调大(5000)更省SCCB;焦距跟不上就调小(别低于~1500)。 +#define AF_REFOCUS_MS 1000 + void loop() { - // Health monitoring - Serial.printf("[HEALTH] heap=%u PSRAM=%u RSSI=%d uptime=%lus\n", - (unsigned)ESP.getFreeHeap(), - (unsigned)heap_caps_get_free_size(MALLOC_CAP_SPIRAM), - WiFi.RSSI(), - millis() / 1000); - delay(10000); + static unsigned long last_af_ms = 0; + static unsigned long last_health_ms = 0; + unsigned long now = millis(); + + // 低频单次对焦:只在触发那一下用SCCB,不持续占总线 + // ★ 临时测量: 触发对焦后密集轮询, 测 Focusing->Focused 真实耗时 + + // 对焦: 默认交给 PC 按需 HTTP 触发(/control?var=af)。 + // 仅当 g_auto_af=true 时固件自动定时对焦(调试用, 非阻塞版)。 + /*if (g_auto_af && now - last_af_ms >= AF_REFOCUS_MS) { + last_af_ms = now; + sensor_t *s = esp_camera_sensor_get(); + if (s) { + s->set_reg(s, 0x3022, 0xff, 0x03); // 单次对焦, 不阻塞轮询 + } + }*/ + if (g_auto_af && now - last_af_ms >= AF_REFOCUS_MS) { + last_af_ms = now; + sensor_t *s = esp_camera_sensor_get(); + if (s) { + s->set_reg(s, 0x3022, 0xff, 0x03); + } + } + // 健康日志:每10s一次 + if (now - last_health_ms >= 10000) { + last_health_ms = now; + Serial.printf("[HEALTH] heap=%u PSRAM=%u RSSI=%d temp=%.1fC uptime=%lus\n", + (unsigned)ESP.getFreeHeap(), + (unsigned)heap_caps_get_free_size(MALLOC_CAP_SPIRAM), + WiFi.RSSI(), + temperatureRead(), + millis() / 1000); + } + + delay(50); // 非阻塞轮询 } diff --git a/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.cpp b/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.cpp new file mode 100644 index 0000000..7d92385 --- /dev/null +++ b/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.cpp @@ -0,0 +1,85 @@ +/* + ESP32_OV5640_AF.cpp - Library for OV5640 Auto Focus (ESP32 Camera) + Created by Eric Nam, December 08, 2021. + Released into the public domain. +*/ + +#include "ESP32_OV5640_AF.h" +#include + +OV5640::OV5640() { + isOV5640 = false; +} + +bool OV5640::start(sensor_t* _sensor) { + sensor = _sensor; + uint8_t vid, pid; + vid = sensor->get_reg(sensor, OV5640_CHIPID_HIGH, 0xff); + pid = sensor->get_reg(sensor, OV5640_CHIPID_LOW, 0xff); + + isOV5640 = (vid == 0x56) && (pid == 0x40); + return isOV5640; +} + +uint8_t OV5640::focusInit() { + if (!isOV5640) return -1; + + const struct sensor_reg* vals = OV5640_AF_Val; + uint16_t i; + uint16_t addr = 0x8000; + uint8_t state = 0x8F; + uint8_t rc = 0; + + while (vals->reg != 0xff) { + rc = sensor->set_reg(sensor, vals->reg, 0xff, vals->val); + // Serial.printf("reg: %02x, val: %02x\n", vals->reg, vals->val); + if (rc < 0) return -1; + vals++; + } + + do { + state = sensor->get_reg(sensor, 0x3029, 0xff); + delay(5); + i++; + if (i > 1000) return 1; + } while (state != FW_STATUS_S_IDLE); + + return 0; +} + +uint8_t OV5640::autoFocusMode(bool reset) { + if (!isOV5640) return 1; + + uint8_t rc = 0; + uint8_t temp = 0; + uint16_t retry = 0; + + if (reset) { + rc = sensor->set_reg(sensor, OV5640_CMD_ACK, 0xff, 0x01); + rc = sensor->set_reg(sensor, OV5640_CMD_MAIN, 0xff, 0x08); + do { + temp = sensor->get_reg(sensor, OV5640_CMD_ACK, 0xff); + retry++; + if (retry > 1000) return 2; + delay(5); + } while (temp != 0x00); + } + + rc = sensor->set_reg(sensor, OV5640_CMD_ACK, 0xff, 0x01); + rc = sensor->set_reg(sensor, OV5640_CMD_MAIN, 0xff, AF_CONTINUE_AUTO_FOCUS); + retry = 0; + do { + temp = sensor->get_reg(sensor, OV5640_CMD_ACK, 0xff); + retry++; + if (retry > 1000) return 3; + delay(5); + } while (temp != 0x00); + + return 0; +} + +uint8_t OV5640::getFWStatus() { + if (!isOV5640) return -1; + uint8_t rc = sensor->get_reg(sensor, OV5640_CMD_FW_STATUS, 0xff); + return rc; +} diff --git a/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.h b/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.h new file mode 100644 index 0000000..451c0dd --- /dev/null +++ b/CameraWebServer_PDM_Audio/ESP32_OV5640_AF.h @@ -0,0 +1,27 @@ +/* + ESP32_OV5640_AF.h - Library for OV5640 Auto Focus (ESP32 Camera) + Created by Eric Nam, December 08, 2021. + Released into the public domain. +*/ + +#ifndef ESP32_OV5640_AF_h +#define ESP32_OV5640_AF_h + +#include +#include "ESP32_OV5640_cfg.h" +#include "esp_camera.h" + +class OV5640 { +private: + sensor_t* sensor; + bool isOV5640; + +public: + OV5640(); + bool start(sensor_t* _sensor); + uint8_t focusInit(); + uint8_t autoFocusMode(bool reset); + uint8_t getFWStatus(); +}; + +#endif diff --git a/CameraWebServer_PDM_Audio/ESP32_OV5640_cfg.h b/CameraWebServer_PDM_Audio/ESP32_OV5640_cfg.h new file mode 100644 index 0000000..86a4928 --- /dev/null +++ b/CameraWebServer_PDM_Audio/ESP32_OV5640_cfg.h @@ -0,0 +1,4134 @@ +/* + ESP32_OV5640_cfg.h - Library for OV5640 Auto Focus (ESP32 Camera) + Created by Eric Nam, December 08, 2021. + Released into the public domain. +*/ + +#define OV5640_CHIPID_HIGH 0x300a +#define OV5640_CHIPID_LOW 0x300b + +#define OV5640_CMD_MAIN 0x3022 +#define OV5640_CMD_ACK 0x3023 +#define OV5640_CMD_PARA0 0x3024 +#define OV5640_CMD_PARA1 0x3025 +#define OV5640_CMD_PARA2 0x3026 +#define OV5640_CMD_PARA3 0x3027 +#define OV5640_CMD_PARA4 0x3028 +#define OV5640_CMD_FW_STATUS 0x3029 + +#define AF_TRIG_SINGLE_AUTO_FOCUS 0x03 +#define AF_CONTINUE_AUTO_FOCUS 0x04 + +#define FW_STATUS_S_FIRMWARE 0x7F +#define FW_STATUS_S_STARTUP 0x7E +#define FW_STATUS_S_IDLE 0x70 +#define FW_STATUS_S_FOCUSED 0x10 +#define FW_STATUS_S_ZONE_CONFIG 0x16 +#define FW_STATUS_S_FOCUSING 0x00 //0x00 - 0X0F, 0x80 - 0X8F + +struct sensor_reg { + uint16_t reg; + uint8_t val; +}; + +static const struct sensor_reg OV5640_AF_Val[] = +{ + {0x3000,0x20}, + {0x8000,0x02}, + {0x8001,0x0f}, + {0x8002,0xe0}, + {0x8003,0x02}, + {0x8004,0x09}, + {0x8005,0x28}, + {0x8006,0xc2}, + {0x8007,0x01}, + {0x8008,0x22}, + {0x8009,0x22}, + {0x800a,0x00}, + {0x800b,0x02}, + {0x800c,0x0d}, + {0x800d,0xea}, + {0x800e,0x30}, + {0x800f,0x01}, + {0x8010,0x03}, + {0x8011,0x02}, + {0x8012,0x02}, + {0x8013,0xa6}, + {0x8014,0x30}, + {0x8015,0x02}, + {0x8016,0x03}, + {0x8017,0x02}, + {0x8018,0x02}, + {0x8019,0xa6}, + {0x801a,0x90}, + {0x801b,0x51}, + {0x801c,0xa5}, + {0x801d,0xe0}, + {0x801e,0x78}, + {0x801f,0x93}, + {0x8020,0xf6}, + {0x8021,0xa3}, + {0x8022,0xe0}, + {0x8023,0x08}, + {0x8024,0xf6}, + {0x8025,0xa3}, + {0x8026,0xe0}, + {0x8027,0x08}, + {0x8028,0xf6}, + {0x8029,0xe5}, + {0x802a,0x1f}, + {0x802b,0x70}, + {0x802c,0x4f}, + {0x802d,0x75}, + {0x802e,0x1e}, + {0x802f,0x20}, + {0x8030,0xd2}, + {0x8031,0x35}, + {0x8032,0xd3}, + {0x8033,0x78}, + {0x8034,0x4f}, + {0x8035,0xe6}, + {0x8036,0x94}, + {0x8037,0x00}, + {0x8038,0x18}, + {0x8039,0xe6}, + {0x803a,0x94}, + {0x803b,0x00}, + {0x803c,0x40}, + {0x803d,0x07}, + {0x803e,0xe6}, + {0x803f,0xfe}, + {0x8040,0x08}, + {0x8041,0xe6}, + {0x8042,0xff}, + {0x8043,0x80}, + {0x8044,0x03}, + {0x8045,0x12}, + {0x8046,0x0c}, + {0x8047,0x67}, + {0x8048,0x78}, + {0x8049,0x7e}, + {0x804a,0xa6}, + {0x804b,0x06}, + {0x804c,0x08}, + {0x804d,0xa6}, + {0x804e,0x07}, + {0x804f,0x78}, + {0x8050,0x8b}, + {0x8051,0xa6}, + {0x8052,0x09}, + {0x8053,0x18}, + {0x8054,0x76}, + {0x8055,0x01}, + {0x8056,0x12}, + {0x8057,0x0c}, + {0x8058,0x67}, + {0x8059,0x78}, + {0x805a,0x4e}, + {0x805b,0xa6}, + {0x805c,0x06}, + {0x805d,0x08}, + {0x805e,0xa6}, + {0x805f,0x07}, + {0x8060,0x78}, + {0x8061,0x8b}, + {0x8062,0xe6}, + {0x8063,0x78}, + {0x8064,0x6e}, + {0x8065,0xf6}, + {0x8066,0x75}, + {0x8067,0x1f}, + {0x8068,0x01}, + {0x8069,0x78}, + {0x806a,0x93}, + {0x806b,0xe6}, + {0x806c,0x78}, + {0x806d,0x90}, + {0x806e,0xf6}, + {0x806f,0x78}, + {0x8070,0x94}, + {0x8071,0xe6}, + {0x8072,0x78}, + {0x8073,0x91}, + {0x8074,0xf6}, + {0x8075,0x78}, + {0x8076,0x95}, + {0x8077,0xe6}, + {0x8078,0x78}, + {0x8079,0x92}, + {0x807a,0xf6}, + {0x807b,0x22}, + {0x807c,0x79}, + {0x807d,0x90}, + {0x807e,0xe7}, + {0x807f,0xd3}, + {0x8080,0x78}, + {0x8081,0x93}, + {0x8082,0x96}, + {0x8083,0x40}, + {0x8084,0x05}, + {0x8085,0xe7}, + {0x8086,0x96}, + {0x8087,0xff}, + {0x8088,0x80}, + {0x8089,0x08}, + {0x808a,0xc3}, + {0x808b,0x79}, + {0x808c,0x93}, + {0x808d,0xe7}, + {0x808e,0x78}, + {0x808f,0x90}, + {0x8090,0x96}, + {0x8091,0xff}, + {0x8092,0x78}, + {0x8093,0x88}, + {0x8094,0x76}, + {0x8095,0x00}, + {0x8096,0x08}, + {0x8097,0xa6}, + {0x8098,0x07}, + {0x8099,0x79}, + {0x809a,0x91}, + {0x809b,0xe7}, + {0x809c,0xd3}, + {0x809d,0x78}, + {0x809e,0x94}, + {0x809f,0x96}, + {0x80a0,0x40}, + {0x80a1,0x05}, + {0x80a2,0xe7}, + {0x80a3,0x96}, + {0x80a4,0xff}, + {0x80a5,0x80}, + {0x80a6,0x08}, + {0x80a7,0xc3}, + {0x80a8,0x79}, + {0x80a9,0x94}, + {0x80aa,0xe7}, + {0x80ab,0x78}, + {0x80ac,0x91}, + {0x80ad,0x96}, + {0x80ae,0xff}, + {0x80af,0x12}, + {0x80b0,0x0c}, + {0x80b1,0xb0}, + {0x80b2,0x79}, + {0x80b3,0x92}, + {0x80b4,0xe7}, + {0x80b5,0xd3}, + {0x80b6,0x78}, + {0x80b7,0x95}, + {0x80b8,0x96}, + {0x80b9,0x40}, + {0x80ba,0x05}, + {0x80bb,0xe7}, + {0x80bc,0x96}, + {0x80bd,0xff}, + {0x80be,0x80}, + {0x80bf,0x08}, + {0x80c0,0xc3}, + {0x80c1,0x79}, + {0x80c2,0x95}, + {0x80c3,0xe7}, + {0x80c4,0x78}, + {0x80c5,0x92}, + {0x80c6,0x96}, + {0x80c7,0xff}, + {0x80c8,0x12}, + {0x80c9,0x0c}, + {0x80ca,0xb0}, + {0x80cb,0x12}, + {0x80cc,0x0c}, + {0x80cd,0x67}, + {0x80ce,0x78}, + {0x80cf,0x8a}, + {0x80d0,0xe6}, + {0x80d1,0x25}, + {0x80d2,0xe0}, + {0x80d3,0x24}, + {0x80d4,0x4e}, + {0x80d5,0xf8}, + {0x80d6,0xa6}, + {0x80d7,0x06}, + {0x80d8,0x08}, + {0x80d9,0xa6}, + {0x80da,0x07}, + {0x80db,0x78}, + {0x80dc,0x8a}, + {0x80dd,0xe6}, + {0x80de,0x24}, + {0x80df,0x6e}, + {0x80e0,0xf8}, + {0x80e1,0xa6}, + {0x80e2,0x09}, + {0x80e3,0x90}, + {0x80e4,0x0e}, + {0x80e5,0x93}, + {0x80e6,0xe4}, + {0x80e7,0x93}, + {0x80e8,0x24}, + {0x80e9,0xff}, + {0x80ea,0xff}, + {0x80eb,0xe4}, + {0x80ec,0x34}, + {0x80ed,0xff}, + {0x80ee,0xfe}, + {0x80ef,0x78}, + {0x80f0,0x8a}, + {0x80f1,0xe6}, + {0x80f2,0x24}, + {0x80f3,0x01}, + {0x80f4,0xfd}, + {0x80f5,0xe4}, + {0x80f6,0x33}, + {0x80f7,0xfc}, + {0x80f8,0xd3}, + {0x80f9,0xed}, + {0x80fa,0x9f}, + {0x80fb,0xee}, + {0x80fc,0x64}, + {0x80fd,0x80}, + {0x80fe,0xf8}, + {0x80ff,0xec}, + {0x8100,0x64}, + {0x8101,0x80}, + {0x8102,0x98}, + {0x8103,0x40}, + {0x8104,0x04}, + {0x8105,0x7f}, + {0x8106,0x00}, + {0x8107,0x80}, + {0x8108,0x05}, + {0x8109,0x78}, + {0x810a,0x8a}, + {0x810b,0xe6}, + {0x810c,0x04}, + {0x810d,0xff}, + {0x810e,0x78}, + {0x810f,0x8a}, + {0x8110,0xa6}, + {0x8111,0x07}, + {0x8112,0xe5}, + {0x8113,0x1f}, + {0x8114,0xb4}, + {0x8115,0x01}, + {0x8116,0x0a}, + {0x8117,0xe6}, + {0x8118,0x60}, + {0x8119,0x03}, + {0x811a,0x02}, + {0x811b,0x02}, + {0x811c,0xa6}, + {0x811d,0x75}, + {0x811e,0x1f}, + {0x811f,0x02}, + {0x8120,0x22}, + {0x8121,0x78}, + {0x8122,0x4e}, + {0x8123,0xe6}, + {0x8124,0xfe}, + {0x8125,0x08}, + {0x8126,0xe6}, + {0x8127,0xff}, + {0x8128,0x78}, + {0x8129,0x80}, + {0x812a,0xa6}, + {0x812b,0x06}, + {0x812c,0x08}, + {0x812d,0xa6}, + {0x812e,0x07}, + {0x812f,0x78}, + {0x8130,0x4e}, + {0x8131,0xe6}, + {0x8132,0xfe}, + {0x8133,0x08}, + {0x8134,0xe6}, + {0x8135,0xff}, + {0x8136,0x78}, + {0x8137,0x82}, + {0x8138,0xa6}, + {0x8139,0x06}, + {0x813a,0x08}, + {0x813b,0xa6}, + {0x813c,0x07}, + {0x813d,0x78}, + {0x813e,0x6e}, + {0x813f,0xe6}, + {0x8140,0x78}, + {0x8141,0x8c}, + {0x8142,0xf6}, + {0x8143,0x78}, + {0x8144,0x6e}, + {0x8145,0xe6}, + {0x8146,0x78}, + {0x8147,0x8d}, + {0x8148,0xf6}, + {0x8149,0x7f}, + {0x814a,0x01}, + {0x814b,0x90}, + {0x814c,0x0e}, + {0x814d,0x93}, + {0x814e,0xe4}, + {0x814f,0x93}, + {0x8150,0xfe}, + {0x8151,0xef}, + {0x8152,0xc3}, + {0x8153,0x9e}, + {0x8154,0x50}, + {0x8155,0x5f}, + {0x8156,0xef}, + {0x8157,0x25}, + {0x8158,0xe0}, + {0x8159,0x24}, + {0x815a,0x4f}, + {0x815b,0xf9}, + {0x815c,0xc3}, + {0x815d,0x78}, + {0x815e,0x81}, + {0x815f,0xe6}, + {0x8160,0x97}, + {0x8161,0x18}, + {0x8162,0xe6}, + {0x8163,0x19}, + {0x8164,0x97}, + {0x8165,0x50}, + {0x8166,0x0a}, + {0x8167,0x12}, + {0x8168,0x0c}, + {0x8169,0x98}, + {0x816a,0x78}, + {0x816b,0x80}, + {0x816c,0xa6}, + {0x816d,0x04}, + {0x816e,0x08}, + {0x816f,0xa6}, + {0x8170,0x05}, + {0x8171,0x74}, + {0x8172,0x6e}, + {0x8173,0x2f}, + {0x8174,0xf9}, + {0x8175,0x78}, + {0x8176,0x8c}, + {0x8177,0xe6}, + {0x8178,0xc3}, + {0x8179,0x97}, + {0x817a,0x50}, + {0x817b,0x08}, + {0x817c,0x74}, + {0x817d,0x6e}, + {0x817e,0x2f}, + {0x817f,0xf8}, + {0x8180,0xe6}, + {0x8181,0x78}, + {0x8182,0x8c}, + {0x8183,0xf6}, + {0x8184,0xef}, + {0x8185,0x25}, + {0x8186,0xe0}, + {0x8187,0x24}, + {0x8188,0x4f}, + {0x8189,0xf9}, + {0x818a,0xd3}, + {0x818b,0x78}, + {0x818c,0x83}, + {0x818d,0xe6}, + {0x818e,0x97}, + {0x818f,0x18}, + {0x8190,0xe6}, + {0x8191,0x19}, + {0x8192,0x97}, + {0x8193,0x40}, + {0x8194,0x0a}, + {0x8195,0x12}, + {0x8196,0x0c}, + {0x8197,0x98}, + {0x8198,0x78}, + {0x8199,0x82}, + {0x819a,0xa6}, + {0x819b,0x04}, + {0x819c,0x08}, + {0x819d,0xa6}, + {0x819e,0x05}, + {0x819f,0x74}, + {0x81a0,0x6e}, + {0x81a1,0x2f}, + {0x81a2,0xf9}, + {0x81a3,0x78}, + {0x81a4,0x8d}, + {0x81a5,0xe6}, + {0x81a6,0xd3}, + {0x81a7,0x97}, + {0x81a8,0x40}, + {0x81a9,0x08}, + {0x81aa,0x74}, + {0x81ab,0x6e}, + {0x81ac,0x2f}, + {0x81ad,0xf8}, + {0x81ae,0xe6}, + {0x81af,0x78}, + {0x81b0,0x8d}, + {0x81b1,0xf6}, + {0x81b2,0x0f}, + {0x81b3,0x80}, + {0x81b4,0x96}, + {0x81b5,0xc3}, + {0x81b6,0x79}, + {0x81b7,0x81}, + {0x81b8,0xe7}, + {0x81b9,0x78}, + {0x81ba,0x83}, + {0x81bb,0x96}, + {0x81bc,0xff}, + {0x81bd,0x19}, + {0x81be,0xe7}, + {0x81bf,0x18}, + {0x81c0,0x96}, + {0x81c1,0x78}, + {0x81c2,0x84}, + {0x81c3,0xf6}, + {0x81c4,0x08}, + {0x81c5,0xa6}, + {0x81c6,0x07}, + {0x81c7,0xc3}, + {0x81c8,0x79}, + {0x81c9,0x8c}, + {0x81ca,0xe7}, + {0x81cb,0x78}, + {0x81cc,0x8d}, + {0x81cd,0x96}, + {0x81ce,0x08}, + {0x81cf,0xf6}, + {0x81d0,0x12}, + {0x81d1,0x0c}, + {0x81d2,0xa4}, + {0x81d3,0x40}, + {0x81d4,0x05}, + {0x81d5,0x09}, + {0x81d6,0xe7}, + {0x81d7,0x08}, + {0x81d8,0x80}, + {0x81d9,0x06}, + {0x81da,0xc3}, + {0x81db,0x79}, + {0x81dc,0x7f}, + {0x81dd,0xe7}, + {0x81de,0x78}, + {0x81df,0x81}, + {0x81e0,0x96}, + {0x81e1,0xff}, + {0x81e2,0x19}, + {0x81e3,0xe7}, + {0x81e4,0x18}, + {0x81e5,0x96}, + {0x81e6,0xfe}, + {0x81e7,0x78}, + {0x81e8,0x86}, + {0x81e9,0xa6}, + {0x81ea,0x06}, + {0x81eb,0x08}, + {0x81ec,0xa6}, + {0x81ed,0x07}, + {0x81ee,0x79}, + {0x81ef,0x8c}, + {0x81f0,0xe7}, + {0x81f1,0xd3}, + {0x81f2,0x78}, + {0x81f3,0x8b}, + {0x81f4,0x96}, + {0x81f5,0x40}, + {0x81f6,0x05}, + {0x81f7,0xe7}, + {0x81f8,0x96}, + {0x81f9,0xff}, + {0x81fa,0x80}, + {0x81fb,0x08}, + {0x81fc,0xc3}, + {0x81fd,0x79}, + {0x81fe,0x8b}, + {0x81ff,0xe7}, + {0x8200,0x78}, + {0x8201,0x8c}, + {0x8202,0x96}, + {0x8203,0xff}, + {0x8204,0x78}, + {0x8205,0x8f}, + {0x8206,0xa6}, + {0x8207,0x07}, + {0x8208,0xe5}, + {0x8209,0x1f}, + {0x820a,0x64}, + {0x820b,0x02}, + {0x820c,0x60}, + {0x820d,0x03}, + {0x820e,0x02}, + {0x820f,0x02}, + {0x8210,0x92}, + {0x8211,0x90}, + {0x8212,0x0e}, + {0x8213,0x91}, + {0x8214,0x93}, + {0x8215,0xff}, + {0x8216,0x18}, + {0x8217,0xe6}, + {0x8218,0xc3}, + {0x8219,0x9f}, + {0x821a,0x40}, + {0x821b,0x03}, + {0x821c,0x02}, + {0x821d,0x02}, + {0x821e,0xa6}, + {0x821f,0x78}, + {0x8220,0x84}, + {0x8221,0x12}, + {0x8222,0x0c}, + {0x8223,0x89}, + {0x8224,0x12}, + {0x8225,0x0c}, + {0x8226,0x5e}, + {0x8227,0x90}, + {0x8228,0x0e}, + {0x8229,0x8e}, + {0x822a,0x12}, + {0x822b,0x0c}, + {0x822c,0x77}, + {0x822d,0x78}, + {0x822e,0x80}, + {0x822f,0xe6}, + {0x8230,0xfe}, + {0x8231,0x08}, + {0x8232,0xe6}, + {0x8233,0xff}, + {0x8234,0x12}, + {0x8235,0x0c}, + {0x8236,0xba}, + {0x8237,0x7b}, + {0x8238,0x04}, + {0x8239,0x12}, + {0x823a,0x0c}, + {0x823b,0x4c}, + {0x823c,0xc3}, + {0x823d,0x12}, + {0x823e,0x06}, + {0x823f,0xa6}, + {0x8240,0x50}, + {0x8241,0x64}, + {0x8242,0x90}, + {0x8243,0x0e}, + {0x8244,0x92}, + {0x8245,0xe4}, + {0x8246,0x93}, + {0x8247,0xff}, + {0x8248,0x78}, + {0x8249,0x8f}, + {0x824a,0xe6}, + {0x824b,0x9f}, + {0x824c,0x40}, + {0x824d,0x02}, + {0x824e,0x80}, + {0x824f,0x11}, + {0x8250,0x90}, + {0x8251,0x0e}, + {0x8252,0x90}, + {0x8253,0xe4}, + {0x8254,0x93}, + {0x8255,0xff}, + {0x8256,0xd3}, + {0x8257,0x78}, + {0x8258,0x89}, + {0x8259,0xe6}, + {0x825a,0x9f}, + {0x825b,0x18}, + {0x825c,0xe6}, + {0x825d,0x94}, + {0x825e,0x00}, + {0x825f,0x40}, + {0x8260,0x03}, + {0x8261,0x75}, + {0x8262,0x1f}, + {0x8263,0x05}, + {0x8264,0x78}, + {0x8265,0x86}, + {0x8266,0x12}, + {0x8267,0x0c}, + {0x8268,0x89}, + {0x8269,0x12}, + {0x826a,0x0c}, + {0x826b,0x5e}, + {0x826c,0x90}, + {0x826d,0x0e}, + {0x826e,0x8f}, + {0x826f,0x12}, + {0x8270,0x0c}, + {0x8271,0x77}, + {0x8272,0x12}, + {0x8273,0x0c}, + {0x8274,0xa4}, + {0x8275,0x40}, + {0x8276,0x02}, + {0x8277,0x80}, + {0x8278,0x02}, + {0x8279,0x78}, + {0x827a,0x80}, + {0x827b,0xe6}, + {0x827c,0xfe}, + {0x827d,0x08}, + {0x827e,0xe6}, + {0x827f,0xff}, + {0x8280,0x12}, + {0x8281,0x0c}, + {0x8282,0xba}, + {0x8283,0x7b}, + {0x8284,0x10}, + {0x8285,0x12}, + {0x8286,0x0c}, + {0x8287,0x4c}, + {0x8288,0xd3}, + {0x8289,0x12}, + {0x828a,0x06}, + {0x828b,0xa6}, + {0x828c,0x40}, + {0x828d,0x18}, + {0x828e,0x75}, + {0x828f,0x1f}, + {0x8290,0x05}, + {0x8291,0x22}, + {0x8292,0xe5}, + {0x8293,0x1f}, + {0x8294,0xb4}, + {0x8295,0x05}, + {0x8296,0x0f}, + {0x8297,0xd2}, + {0x8298,0x01}, + {0x8299,0xc2}, + {0x829a,0x02}, + {0x829b,0xe4}, + {0x829c,0xf5}, + {0x829d,0x1f}, + {0x829e,0xf5}, + {0x829f,0x1e}, + {0x82a0,0xd2}, + {0x82a1,0x35}, + {0x82a2,0xd2}, + {0x82a3,0x33}, + {0x82a4,0xd2}, + {0x82a5,0x36}, + {0x82a6,0x22}, + {0x82a7,0xe5}, + {0x82a8,0x1f}, + {0x82a9,0x70}, + {0x82aa,0x72}, + {0x82ab,0xf5}, + {0x82ac,0x1e}, + {0x82ad,0xd2}, + {0x82ae,0x35}, + {0x82af,0xff}, + {0x82b0,0xef}, + {0x82b1,0x25}, + {0x82b2,0xe0}, + {0x82b3,0x24}, + {0x82b4,0x4e}, + {0x82b5,0xf8}, + {0x82b6,0xe4}, + {0x82b7,0xf6}, + {0x82b8,0x08}, + {0x82b9,0xf6}, + {0x82ba,0x0f}, + {0x82bb,0xbf}, + {0x82bc,0x34}, + {0x82bd,0xf2}, + {0x82be,0x90}, + {0x82bf,0x0e}, + {0x82c0,0x94}, + {0x82c1,0xe4}, + {0x82c2,0x93}, + {0x82c3,0xff}, + {0x82c4,0xe5}, + {0x82c5,0x4b}, + {0x82c6,0xc3}, + {0x82c7,0x9f}, + {0x82c8,0x50}, + {0x82c9,0x04}, + {0x82ca,0x7f}, + {0x82cb,0x05}, + {0x82cc,0x80}, + {0x82cd,0x02}, + {0x82ce,0x7f}, + {0x82cf,0xfb}, + {0x82d0,0x78}, + {0x82d1,0xbd}, + {0x82d2,0xa6}, + {0x82d3,0x07}, + {0x82d4,0x12}, + {0x82d5,0x0e}, + {0x82d6,0xb1}, + {0x82d7,0x40}, + {0x82d8,0x04}, + {0x82d9,0x7f}, + {0x82da,0x03}, + {0x82db,0x80}, + {0x82dc,0x02}, + {0x82dd,0x7f}, + {0x82de,0x30}, + {0x82df,0x78}, + {0x82e0,0xbc}, + {0x82e1,0xa6}, + {0x82e2,0x07}, + {0x82e3,0xe6}, + {0x82e4,0x18}, + {0x82e5,0xf6}, + {0x82e6,0x08}, + {0x82e7,0xe6}, + {0x82e8,0x78}, + {0x82e9,0xb9}, + {0x82ea,0xf6}, + {0x82eb,0x78}, + {0x82ec,0xbc}, + {0x82ed,0xe6}, + {0x82ee,0x78}, + {0x82ef,0xba}, + {0x82f0,0xf6}, + {0x82f1,0x78}, + {0x82f2,0xbf}, + {0x82f3,0x76}, + {0x82f4,0x33}, + {0x82f5,0xe4}, + {0x82f6,0x08}, + {0x82f7,0xf6}, + {0x82f8,0x78}, + {0x82f9,0xb8}, + {0x82fa,0x76}, + {0x82fb,0x01}, + {0x82fc,0x75}, + {0x82fd,0x4a}, + {0x82fe,0x02}, + {0x82ff,0x78}, + {0x8300,0xb6}, + {0x8301,0xf6}, + {0x8302,0x08}, + {0x8303,0xf6}, + {0x8304,0x74}, + {0x8305,0xff}, + {0x8306,0x78}, + {0x8307,0xc1}, + {0x8308,0xf6}, + {0x8309,0x08}, + {0x830a,0xf6}, + {0x830b,0x75}, + {0x830c,0x1f}, + {0x830d,0x01}, + {0x830e,0x78}, + {0x830f,0xbc}, + {0x8310,0xe6}, + {0x8311,0x75}, + {0x8312,0xf0}, + {0x8313,0x05}, + {0x8314,0xa4}, + {0x8315,0xf5}, + {0x8316,0x4b}, + {0x8317,0x12}, + {0x8318,0x0b}, + {0x8319,0x39}, + {0x831a,0xc2}, + {0x831b,0x37}, + {0x831c,0x22}, + {0x831d,0x78}, + {0x831e,0xb8}, + {0x831f,0xe6}, + {0x8320,0xd3}, + {0x8321,0x94}, + {0x8322,0x00}, + {0x8323,0x40}, + {0x8324,0x02}, + {0x8325,0x16}, + {0x8326,0x22}, + {0x8327,0xe5}, + {0x8328,0x1f}, + {0x8329,0xb4}, + {0x832a,0x05}, + {0x832b,0x23}, + {0x832c,0xe4}, + {0x832d,0xf5}, + {0x832e,0x1f}, + {0x832f,0xc2}, + {0x8330,0x01}, + {0x8331,0x78}, + {0x8332,0xb6}, + {0x8333,0xe6}, + {0x8334,0xfe}, + {0x8335,0x08}, + {0x8336,0xe6}, + {0x8337,0xff}, + {0x8338,0x78}, + {0x8339,0x4e}, + {0x833a,0xa6}, + {0x833b,0x06}, + {0x833c,0x08}, + {0x833d,0xa6}, + {0x833e,0x07}, + {0x833f,0xa2}, + {0x8340,0x37}, + {0x8341,0xe4}, + {0x8342,0x33}, + {0x8343,0xf5}, + {0x8344,0x3c}, + {0x8345,0x90}, + {0x8346,0x30}, + {0x8347,0x28}, + {0x8348,0xf0}, + {0x8349,0x75}, + {0x834a,0x1e}, + {0x834b,0x10}, + {0x834c,0xd2}, + {0x834d,0x35}, + {0x834e,0x22}, + {0x834f,0xe5}, + {0x8350,0x4b}, + {0x8351,0x75}, + {0x8352,0xf0}, + {0x8353,0x05}, + {0x8354,0x84}, + {0x8355,0x78}, + {0x8356,0xbc}, + {0x8357,0xf6}, + {0x8358,0x90}, + {0x8359,0x0e}, + {0x835a,0x8c}, + {0x835b,0xe4}, + {0x835c,0x93}, + {0x835d,0xff}, + {0x835e,0x25}, + {0x835f,0xe0}, + {0x8360,0x24}, + {0x8361,0x0a}, + {0x8362,0xf8}, + {0x8363,0xe6}, + {0x8364,0xfc}, + {0x8365,0x08}, + {0x8366,0xe6}, + {0x8367,0xfd}, + {0x8368,0x78}, + {0x8369,0xbc}, + {0x836a,0xe6}, + {0x836b,0x25}, + {0x836c,0xe0}, + {0x836d,0x24}, + {0x836e,0x4e}, + {0x836f,0xf8}, + {0x8370,0xa6}, + {0x8371,0x04}, + {0x8372,0x08}, + {0x8373,0xa6}, + {0x8374,0x05}, + {0x8375,0xef}, + {0x8376,0x12}, + {0x8377,0x0e}, + {0x8378,0xf5}, + {0x8379,0xd3}, + {0x837a,0x78}, + {0x837b,0xb7}, + {0x837c,0x96}, + {0x837d,0xee}, + {0x837e,0x18}, + {0x837f,0x96}, + {0x8380,0x40}, + {0x8381,0x0d}, + {0x8382,0x78}, + {0x8383,0xbc}, + {0x8384,0xe6}, + {0x8385,0x78}, + {0x8386,0xb9}, + {0x8387,0xf6}, + {0x8388,0x78}, + {0x8389,0xb6}, + {0x838a,0xa6}, + {0x838b,0x06}, + {0x838c,0x08}, + {0x838d,0xa6}, + {0x838e,0x07}, + {0x838f,0x90}, + {0x8390,0x0e}, + {0x8391,0x8c}, + {0x8392,0xe4}, + {0x8393,0x93}, + {0x8394,0x12}, + {0x8395,0x0e}, + {0x8396,0xf5}, + {0x8397,0xc3}, + {0x8398,0x78}, + {0x8399,0xc2}, + {0x839a,0x96}, + {0x839b,0xee}, + {0x839c,0x18}, + {0x839d,0x96}, + {0x839e,0x50}, + {0x839f,0x0d}, + {0x83a0,0x78}, + {0x83a1,0xbc}, + {0x83a2,0xe6}, + {0x83a3,0x78}, + {0x83a4,0xba}, + {0x83a5,0xf6}, + {0x83a6,0x78}, + {0x83a7,0xc1}, + {0x83a8,0xa6}, + {0x83a9,0x06}, + {0x83aa,0x08}, + {0x83ab,0xa6}, + {0x83ac,0x07}, + {0x83ad,0x78}, + {0x83ae,0xb6}, + {0x83af,0xe6}, + {0x83b0,0xfe}, + {0x83b1,0x08}, + {0x83b2,0xe6}, + {0x83b3,0xc3}, + {0x83b4,0x78}, + {0x83b5,0xc2}, + {0x83b6,0x96}, + {0x83b7,0xff}, + {0x83b8,0xee}, + {0x83b9,0x18}, + {0x83ba,0x96}, + {0x83bb,0x78}, + {0x83bc,0xc3}, + {0x83bd,0xf6}, + {0x83be,0x08}, + {0x83bf,0xa6}, + {0x83c0,0x07}, + {0x83c1,0x90}, + {0x83c2,0x0e}, + {0x83c3,0x96}, + {0x83c4,0xe4}, + {0x83c5,0x18}, + {0x83c6,0x12}, + {0x83c7,0x0e}, + {0x83c8,0xb8}, + {0x83c9,0x40}, + {0x83ca,0x02}, + {0x83cb,0xd2}, + {0x83cc,0x37}, + {0x83cd,0x78}, + {0x83ce,0xbc}, + {0x83cf,0xe6}, + {0x83d0,0x08}, + {0x83d1,0x26}, + {0x83d2,0x08}, + {0x83d3,0xf6}, + {0x83d4,0xe5}, + {0x83d5,0x1f}, + {0x83d6,0x64}, + {0x83d7,0x01}, + {0x83d8,0x70}, + {0x83d9,0x7a}, + {0x83da,0xe6}, + {0x83db,0xc3}, + {0x83dc,0x78}, + {0x83dd,0xc0}, + {0x83de,0x12}, + {0x83df,0x0e}, + {0x83e0,0xa1}, + {0x83e1,0x40}, + {0x83e2,0x08}, + {0x83e3,0x12}, + {0x83e4,0x0e}, + {0x83e5,0x9c}, + {0x83e6,0x50}, + {0x83e7,0x03}, + {0x83e8,0x02}, + {0x83e9,0x04}, + {0x83ea,0xf1}, + {0x83eb,0x12}, + {0x83ec,0x0e}, + {0x83ed,0xaf}, + {0x83ee,0x40}, + {0x83ef,0x04}, + {0x83f0,0x7f}, + {0x83f1,0xfe}, + {0x83f2,0x80}, + {0x83f3,0x02}, + {0x83f4,0x7f}, + {0x83f5,0x02}, + {0x83f6,0x78}, + {0x83f7,0xbd}, + {0x83f8,0xa6}, + {0x83f9,0x07}, + {0x83fa,0x78}, + {0x83fb,0xb9}, + {0x83fc,0xe6}, + {0x83fd,0x24}, + {0x83fe,0x03}, + {0x83ff,0x78}, + {0x8400,0xbf}, + {0x8401,0xf6}, + {0x8402,0x78}, + {0x8403,0xb9}, + {0x8404,0xe6}, + {0x8405,0x24}, + {0x8406,0xfd}, + {0x8407,0x78}, + {0x8408,0xc0}, + {0x8409,0xf6}, + {0x840a,0x18}, + {0x840b,0x12}, + {0x840c,0x0e}, + {0x840d,0xb1}, + {0x840e,0x40}, + {0x840f,0x04}, + {0x8410,0xe6}, + {0x8411,0xff}, + {0x8412,0x80}, + {0x8413,0x02}, + {0x8414,0x7f}, + {0x8415,0x00}, + {0x8416,0x12}, + {0x8417,0x0e}, + {0x8418,0xd1}, + {0x8419,0x40}, + {0x841a,0x04}, + {0x841b,0xe6}, + {0x841c,0xff}, + {0x841d,0x80}, + {0x841e,0x02}, + {0x841f,0x7f}, + {0x8420,0x00}, + {0x8421,0x12}, + {0x8422,0x0e}, + {0x8423,0xdd}, + {0x8424,0x50}, + {0x8425,0x04}, + {0x8426,0xe6}, + {0x8427,0xff}, + {0x8428,0x80}, + {0x8429,0x02}, + {0x842a,0x7f}, + {0x842b,0x33}, + {0x842c,0x12}, + {0x842d,0x0e}, + {0x842e,0xe9}, + {0x842f,0x50}, + {0x8430,0x04}, + {0x8431,0xe6}, + {0x8432,0xff}, + {0x8433,0x80}, + {0x8434,0x02}, + {0x8435,0x7f}, + {0x8436,0x33}, + {0x8437,0x12}, + {0x8438,0x0e}, + {0x8439,0xab}, + {0x843a,0x40}, + {0x843b,0x06}, + {0x843c,0x78}, + {0x843d,0xc0}, + {0x843e,0xe6}, + {0x843f,0xff}, + {0x8440,0x80}, + {0x8441,0x04}, + {0x8442,0x78}, + {0x8443,0xbf}, + {0x8444,0xe6}, + {0x8445,0xff}, + {0x8446,0x78}, + {0x8447,0xbe}, + {0x8448,0xa6}, + {0x8449,0x07}, + {0x844a,0x75}, + {0x844b,0x1f}, + {0x844c,0x02}, + {0x844d,0x78}, + {0x844e,0xb8}, + {0x844f,0x76}, + {0x8450,0x01}, + {0x8451,0x02}, + {0x8452,0x04}, + {0x8453,0xf1}, + {0x8454,0xe5}, + {0x8455,0x1f}, + {0x8456,0x64}, + {0x8457,0x02}, + {0x8458,0x70}, + {0x8459,0x77}, + {0x845a,0x78}, + {0x845b,0xbe}, + {0x845c,0xe6}, + {0x845d,0xff}, + {0x845e,0xc3}, + {0x845f,0x78}, + {0x8460,0xc0}, + {0x8461,0x12}, + {0x8462,0x0e}, + {0x8463,0xa2}, + {0x8464,0x40}, + {0x8465,0x05}, + {0x8466,0x12}, + {0x8467,0x0e}, + {0x8468,0x9c}, + {0x8469,0x40}, + {0x846a,0x64}, + {0x846b,0x12}, + {0x846c,0x0e}, + {0x846d,0xaf}, + {0x846e,0x40}, + {0x846f,0x04}, + {0x8470,0x7f}, + {0x8471,0xff}, + {0x8472,0x80}, + {0x8473,0x02}, + {0x8474,0x7f}, + {0x8475,0x01}, + {0x8476,0x78}, + {0x8477,0xbd}, + {0x8478,0xa6}, + {0x8479,0x07}, + {0x847a,0x78}, + {0x847b,0xb9}, + {0x847c,0xe6}, + {0x847d,0x04}, + {0x847e,0x78}, + {0x847f,0xbf}, + {0x8480,0xf6}, + {0x8481,0x78}, + {0x8482,0xb9}, + {0x8483,0xe6}, + {0x8484,0x14}, + {0x8485,0x78}, + {0x8486,0xc0}, + {0x8487,0xf6}, + {0x8488,0x18}, + {0x8489,0x12}, + {0x848a,0x0e}, + {0x848b,0xd6}, + {0x848c,0x40}, + {0x848d,0x04}, + {0x848e,0xe6}, + {0x848f,0xff}, + {0x8490,0x80}, + {0x8491,0x02}, + {0x8492,0x7f}, + {0x8493,0x00}, + {0x8494,0x12}, + {0x8495,0x0e}, + {0x8496,0xd1}, + {0x8497,0x40}, + {0x8498,0x04}, + {0x8499,0xe6}, + {0x849a,0xff}, + {0x849b,0x80}, + {0x849c,0x02}, + {0x849d,0x7f}, + {0x849e,0x00}, + {0x849f,0x12}, + {0x84a0,0x0e}, + {0x84a1,0xdd}, + {0x84a2,0x50}, + {0x84a3,0x04}, + {0x84a4,0xe6}, + {0x84a5,0xff}, + {0x84a6,0x80}, + {0x84a7,0x02}, + {0x84a8,0x7f}, + {0x84a9,0x33}, + {0x84aa,0x12}, + {0x84ab,0x0e}, + {0x84ac,0xe9}, + {0x84ad,0x50}, + {0x84ae,0x04}, + {0x84af,0xe6}, + {0x84b0,0xff}, + {0x84b1,0x80}, + {0x84b2,0x02}, + {0x84b3,0x7f}, + {0x84b4,0x33}, + {0x84b5,0x12}, + {0x84b6,0x0e}, + {0x84b7,0xab}, + {0x84b8,0x40}, + {0x84b9,0x06}, + {0x84ba,0x78}, + {0x84bb,0xc0}, + {0x84bc,0xe6}, + {0x84bd,0xff}, + {0x84be,0x80}, + {0x84bf,0x04}, + {0x84c0,0x78}, + {0x84c1,0xbf}, + {0x84c2,0xe6}, + {0x84c3,0xff}, + {0x84c4,0x78}, + {0x84c5,0xbe}, + {0x84c6,0xa6}, + {0x84c7,0x07}, + {0x84c8,0x75}, + {0x84c9,0x1f}, + {0x84ca,0x03}, + {0x84cb,0x78}, + {0x84cc,0xb8}, + {0x84cd,0x76}, + {0x84ce,0x01}, + {0x84cf,0x80}, + {0x84d0,0x20}, + {0x84d1,0xe5}, + {0x84d2,0x1f}, + {0x84d3,0x64}, + {0x84d4,0x03}, + {0x84d5,0x70}, + {0x84d6,0x26}, + {0x84d7,0x78}, + {0x84d8,0xbe}, + {0x84d9,0xe6}, + {0x84da,0xff}, + {0x84db,0xc3}, + {0x84dc,0x78}, + {0x84dd,0xc0}, + {0x84de,0x12}, + {0x84df,0x0e}, + {0x84e0,0xa2}, + {0x84e1,0x40}, + {0x84e2,0x05}, + {0x84e3,0x12}, + {0x84e4,0x0e}, + {0x84e5,0x9c}, + {0x84e6,0x40}, + {0x84e7,0x09}, + {0x84e8,0x78}, + {0x84e9,0xb9}, + {0x84ea,0xe6}, + {0x84eb,0x78}, + {0x84ec,0xbe}, + {0x84ed,0xf6}, + {0x84ee,0x75}, + {0x84ef,0x1f}, + {0x84f0,0x04}, + {0x84f1,0x78}, + {0x84f2,0xbe}, + {0x84f3,0xe6}, + {0x84f4,0x75}, + {0x84f5,0xf0}, + {0x84f6,0x05}, + {0x84f7,0xa4}, + {0x84f8,0xf5}, + {0x84f9,0x4b}, + {0x84fa,0x02}, + {0x84fb,0x0b}, + {0x84fc,0x39}, + {0x84fd,0xe5}, + {0x84fe,0x1f}, + {0x84ff,0x64}, + {0x8500,0x04}, + {0x8501,0x70}, + {0x8502,0x1e}, + {0x8503,0x90}, + {0x8504,0x0e}, + {0x8505,0x95}, + {0x8506,0x78}, + {0x8507,0xc3}, + {0x8508,0x12}, + {0x8509,0x0e}, + {0x850a,0xb8}, + {0x850b,0x40}, + {0x850c,0x04}, + {0x850d,0xd2}, + {0x850e,0x37}, + {0x850f,0x80}, + {0x8510,0x0d}, + {0x8511,0x90}, + {0x8512,0x0e}, + {0x8513,0x97}, + {0x8514,0xe4}, + {0x8515,0x93}, + {0x8516,0xff}, + {0x8517,0x60}, + {0x8518,0x05}, + {0x8519,0xf5}, + {0x851a,0x4b}, + {0x851b,0x12}, + {0x851c,0x0b}, + {0x851d,0x39}, + {0x851e,0x75}, + {0x851f,0x1f}, + {0x8520,0x05}, + {0x8521,0x22}, + {0x8522,0xef}, + {0x8523,0x8d}, + {0x8524,0xf0}, + {0x8525,0xa4}, + {0x8526,0xa8}, + {0x8527,0xf0}, + {0x8528,0xcf}, + {0x8529,0x8c}, + {0x852a,0xf0}, + {0x852b,0xa4}, + {0x852c,0x28}, + {0x852d,0xce}, + {0x852e,0x8d}, + {0x852f,0xf0}, + {0x8530,0xa4}, + {0x8531,0x2e}, + {0x8532,0xfe}, + {0x8533,0x22}, + {0x8534,0xbc}, + {0x8535,0x00}, + {0x8536,0x0b}, + {0x8537,0xbe}, + {0x8538,0x00}, + {0x8539,0x29}, + {0x853a,0xef}, + {0x853b,0x8d}, + {0x853c,0xf0}, + {0x853d,0x84}, + {0x853e,0xff}, + {0x853f,0xad}, + {0x8540,0xf0}, + {0x8541,0x22}, + {0x8542,0xe4}, + {0x8543,0xcc}, + {0x8544,0xf8}, + {0x8545,0x75}, + {0x8546,0xf0}, + {0x8547,0x08}, + {0x8548,0xef}, + {0x8549,0x2f}, + {0x854a,0xff}, + {0x854b,0xee}, + {0x854c,0x33}, + {0x854d,0xfe}, + {0x854e,0xec}, + {0x854f,0x33}, + {0x8550,0xfc}, + {0x8551,0xee}, + {0x8552,0x9d}, + {0x8553,0xec}, + {0x8554,0x98}, + {0x8555,0x40}, + {0x8556,0x05}, + {0x8557,0xfc}, + {0x8558,0xee}, + {0x8559,0x9d}, + {0x855a,0xfe}, + {0x855b,0x0f}, + {0x855c,0xd5}, + {0x855d,0xf0}, + {0x855e,0xe9}, + {0x855f,0xe4}, + {0x8560,0xce}, + {0x8561,0xfd}, + {0x8562,0x22}, + {0x8563,0xed}, + {0x8564,0xf8}, + {0x8565,0xf5}, + {0x8566,0xf0}, + {0x8567,0xee}, + {0x8568,0x84}, + {0x8569,0x20}, + {0x856a,0xd2}, + {0x856b,0x1c}, + {0x856c,0xfe}, + {0x856d,0xad}, + {0x856e,0xf0}, + {0x856f,0x75}, + {0x8570,0xf0}, + {0x8571,0x08}, + {0x8572,0xef}, + {0x8573,0x2f}, + {0x8574,0xff}, + {0x8575,0xed}, + {0x8576,0x33}, + {0x8577,0xfd}, + {0x8578,0x40}, + {0x8579,0x07}, + {0x857a,0x98}, + {0x857b,0x50}, + {0x857c,0x06}, + {0x857d,0xd5}, + {0x857e,0xf0}, + {0x857f,0xf2}, + {0x8580,0x22}, + {0x8581,0xc3}, + {0x8582,0x98}, + {0x8583,0xfd}, + {0x8584,0x0f}, + {0x8585,0xd5}, + {0x8586,0xf0}, + {0x8587,0xea}, + {0x8588,0x22}, + {0x8589,0xe8}, + {0x858a,0x8f}, + {0x858b,0xf0}, + {0x858c,0xa4}, + {0x858d,0xcc}, + {0x858e,0x8b}, + {0x858f,0xf0}, + {0x8590,0xa4}, + {0x8591,0x2c}, + {0x8592,0xfc}, + {0x8593,0xe9}, + {0x8594,0x8e}, + {0x8595,0xf0}, + {0x8596,0xa4}, + {0x8597,0x2c}, + {0x8598,0xfc}, + {0x8599,0x8a}, + {0x859a,0xf0}, + {0x859b,0xed}, + {0x859c,0xa4}, + {0x859d,0x2c}, + {0x859e,0xfc}, + {0x859f,0xea}, + {0x85a0,0x8e}, + {0x85a1,0xf0}, + {0x85a2,0xa4}, + {0x85a3,0xcd}, + {0x85a4,0xa8}, + {0x85a5,0xf0}, + {0x85a6,0x8b}, + {0x85a7,0xf0}, + {0x85a8,0xa4}, + {0x85a9,0x2d}, + {0x85aa,0xcc}, + {0x85ab,0x38}, + {0x85ac,0x25}, + {0x85ad,0xf0}, + {0x85ae,0xfd}, + {0x85af,0xe9}, + {0x85b0,0x8f}, + {0x85b1,0xf0}, + {0x85b2,0xa4}, + {0x85b3,0x2c}, + {0x85b4,0xcd}, + {0x85b5,0x35}, + {0x85b6,0xf0}, + {0x85b7,0xfc}, + {0x85b8,0xeb}, + {0x85b9,0x8e}, + {0x85ba,0xf0}, + {0x85bb,0xa4}, + {0x85bc,0xfe}, + {0x85bd,0xa9}, + {0x85be,0xf0}, + {0x85bf,0xeb}, + {0x85c0,0x8f}, + {0x85c1,0xf0}, + {0x85c2,0xa4}, + {0x85c3,0xcf}, + {0x85c4,0xc5}, + {0x85c5,0xf0}, + {0x85c6,0x2e}, + {0x85c7,0xcd}, + {0x85c8,0x39}, + {0x85c9,0xfe}, + {0x85ca,0xe4}, + {0x85cb,0x3c}, + {0x85cc,0xfc}, + {0x85cd,0xea}, + {0x85ce,0xa4}, + {0x85cf,0x2d}, + {0x85d0,0xce}, + {0x85d1,0x35}, + {0x85d2,0xf0}, + {0x85d3,0xfd}, + {0x85d4,0xe4}, + {0x85d5,0x3c}, + {0x85d6,0xfc}, + {0x85d7,0x22}, + {0x85d8,0x75}, + {0x85d9,0xf0}, + {0x85da,0x08}, + {0x85db,0x75}, + {0x85dc,0x82}, + {0x85dd,0x00}, + {0x85de,0xef}, + {0x85df,0x2f}, + {0x85e0,0xff}, + {0x85e1,0xee}, + {0x85e2,0x33}, + {0x85e3,0xfe}, + {0x85e4,0xcd}, + {0x85e5,0x33}, + {0x85e6,0xcd}, + {0x85e7,0xcc}, + {0x85e8,0x33}, + {0x85e9,0xcc}, + {0x85ea,0xc5}, + {0x85eb,0x82}, + {0x85ec,0x33}, + {0x85ed,0xc5}, + {0x85ee,0x82}, + {0x85ef,0x9b}, + {0x85f0,0xed}, + {0x85f1,0x9a}, + {0x85f2,0xec}, + {0x85f3,0x99}, + {0x85f4,0xe5}, + {0x85f5,0x82}, + {0x85f6,0x98}, + {0x85f7,0x40}, + {0x85f8,0x0c}, + {0x85f9,0xf5}, + {0x85fa,0x82}, + {0x85fb,0xee}, + {0x85fc,0x9b}, + {0x85fd,0xfe}, + {0x85fe,0xed}, + {0x85ff,0x9a}, + {0x8600,0xfd}, + {0x8601,0xec}, + {0x8602,0x99}, + {0x8603,0xfc}, + {0x8604,0x0f}, + {0x8605,0xd5}, + {0x8606,0xf0}, + {0x8607,0xd6}, + {0x8608,0xe4}, + {0x8609,0xce}, + {0x860a,0xfb}, + {0x860b,0xe4}, + {0x860c,0xcd}, + {0x860d,0xfa}, + {0x860e,0xe4}, + {0x860f,0xcc}, + {0x8610,0xf9}, + {0x8611,0xa8}, + {0x8612,0x82}, + {0x8613,0x22}, + {0x8614,0xb8}, + {0x8615,0x00}, + {0x8616,0xc1}, + {0x8617,0xb9}, + {0x8618,0x00}, + {0x8619,0x59}, + {0x861a,0xba}, + {0x861b,0x00}, + {0x861c,0x2d}, + {0x861d,0xec}, + {0x861e,0x8b}, + {0x861f,0xf0}, + {0x8620,0x84}, + {0x8621,0xcf}, + {0x8622,0xce}, + {0x8623,0xcd}, + {0x8624,0xfc}, + {0x8625,0xe5}, + {0x8626,0xf0}, + {0x8627,0xcb}, + {0x8628,0xf9}, + {0x8629,0x78}, + {0x862a,0x18}, + {0x862b,0xef}, + {0x862c,0x2f}, + {0x862d,0xff}, + {0x862e,0xee}, + {0x862f,0x33}, + {0x8630,0xfe}, + {0x8631,0xed}, + {0x8632,0x33}, + {0x8633,0xfd}, + {0x8634,0xec}, + {0x8635,0x33}, + {0x8636,0xfc}, + {0x8637,0xeb}, + {0x8638,0x33}, + {0x8639,0xfb}, + {0x863a,0x10}, + {0x863b,0xd7}, + {0x863c,0x03}, + {0x863d,0x99}, + {0x863e,0x40}, + {0x863f,0x04}, + {0x8640,0xeb}, + {0x8641,0x99}, + {0x8642,0xfb}, + {0x8643,0x0f}, + {0x8644,0xd8}, + {0x8645,0xe5}, + {0x8646,0xe4}, + {0x8647,0xf9}, + {0x8648,0xfa}, + {0x8649,0x22}, + {0x864a,0x78}, + {0x864b,0x18}, + {0x864c,0xef}, + {0x864d,0x2f}, + {0x864e,0xff}, + {0x864f,0xee}, + {0x8650,0x33}, + {0x8651,0xfe}, + {0x8652,0xed}, + {0x8653,0x33}, + {0x8654,0xfd}, + {0x8655,0xec}, + {0x8656,0x33}, + {0x8657,0xfc}, + {0x8658,0xc9}, + {0x8659,0x33}, + {0x865a,0xc9}, + {0x865b,0x10}, + {0x865c,0xd7}, + {0x865d,0x05}, + {0x865e,0x9b}, + {0x865f,0xe9}, + {0x8660,0x9a}, + {0x8661,0x40}, + {0x8662,0x07}, + {0x8663,0xec}, + {0x8664,0x9b}, + {0x8665,0xfc}, + {0x8666,0xe9}, + {0x8667,0x9a}, + {0x8668,0xf9}, + {0x8669,0x0f}, + {0x866a,0xd8}, + {0x866b,0xe0}, + {0x866c,0xe4}, + {0x866d,0xc9}, + {0x866e,0xfa}, + {0x866f,0xe4}, + {0x8670,0xcc}, + {0x8671,0xfb}, + {0x8672,0x22}, + {0x8673,0x75}, + {0x8674,0xf0}, + {0x8675,0x10}, + {0x8676,0xef}, + {0x8677,0x2f}, + {0x8678,0xff}, + {0x8679,0xee}, + {0x867a,0x33}, + {0x867b,0xfe}, + {0x867c,0xed}, + {0x867d,0x33}, + {0x867e,0xfd}, + {0x867f,0xcc}, + {0x8680,0x33}, + {0x8681,0xcc}, + {0x8682,0xc8}, + {0x8683,0x33}, + {0x8684,0xc8}, + {0x8685,0x10}, + {0x8686,0xd7}, + {0x8687,0x07}, + {0x8688,0x9b}, + {0x8689,0xec}, + {0x868a,0x9a}, + {0x868b,0xe8}, + {0x868c,0x99}, + {0x868d,0x40}, + {0x868e,0x0a}, + {0x868f,0xed}, + {0x8690,0x9b}, + {0x8691,0xfd}, + {0x8692,0xec}, + {0x8693,0x9a}, + {0x8694,0xfc}, + {0x8695,0xe8}, + {0x8696,0x99}, + {0x8697,0xf8}, + {0x8698,0x0f}, + {0x8699,0xd5}, + {0x869a,0xf0}, + {0x869b,0xda}, + {0x869c,0xe4}, + {0x869d,0xcd}, + {0x869e,0xfb}, + {0x869f,0xe4}, + {0x86a0,0xcc}, + {0x86a1,0xfa}, + {0x86a2,0xe4}, + {0x86a3,0xc8}, + {0x86a4,0xf9}, + {0x86a5,0x22}, + {0x86a6,0xeb}, + {0x86a7,0x9f}, + {0x86a8,0xf5}, + {0x86a9,0xf0}, + {0x86aa,0xea}, + {0x86ab,0x9e}, + {0x86ac,0x42}, + {0x86ad,0xf0}, + {0x86ae,0xe9}, + {0x86af,0x9d}, + {0x86b0,0x42}, + {0x86b1,0xf0}, + {0x86b2,0xe8}, + {0x86b3,0x9c}, + {0x86b4,0x45}, + {0x86b5,0xf0}, + {0x86b6,0x22}, + {0x86b7,0xe8}, + {0x86b8,0x60}, + {0x86b9,0x0f}, + {0x86ba,0xec}, + {0x86bb,0xc3}, + {0x86bc,0x13}, + {0x86bd,0xfc}, + {0x86be,0xed}, + {0x86bf,0x13}, + {0x86c0,0xfd}, + {0x86c1,0xee}, + {0x86c2,0x13}, + {0x86c3,0xfe}, + {0x86c4,0xef}, + {0x86c5,0x13}, + {0x86c6,0xff}, + {0x86c7,0xd8}, + {0x86c8,0xf1}, + {0x86c9,0x22}, + {0x86ca,0xe8}, + {0x86cb,0x60}, + {0x86cc,0x0f}, + {0x86cd,0xef}, + {0x86ce,0xc3}, + {0x86cf,0x33}, + {0x86d0,0xff}, + {0x86d1,0xee}, + {0x86d2,0x33}, + {0x86d3,0xfe}, + {0x86d4,0xed}, + {0x86d5,0x33}, + {0x86d6,0xfd}, + {0x86d7,0xec}, + {0x86d8,0x33}, + {0x86d9,0xfc}, + {0x86da,0xd8}, + {0x86db,0xf1}, + {0x86dc,0x22}, + {0x86dd,0xe4}, + {0x86de,0x93}, + {0x86df,0xfc}, + {0x86e0,0x74}, + {0x86e1,0x01}, + {0x86e2,0x93}, + {0x86e3,0xfd}, + {0x86e4,0x74}, + {0x86e5,0x02}, + {0x86e6,0x93}, + {0x86e7,0xfe}, + {0x86e8,0x74}, + {0x86e9,0x03}, + {0x86ea,0x93}, + {0x86eb,0xff}, + {0x86ec,0x22}, + {0x86ed,0xe6}, + {0x86ee,0xfb}, + {0x86ef,0x08}, + {0x86f0,0xe6}, + {0x86f1,0xf9}, + {0x86f2,0x08}, + {0x86f3,0xe6}, + {0x86f4,0xfa}, + {0x86f5,0x08}, + {0x86f6,0xe6}, + {0x86f7,0xcb}, + {0x86f8,0xf8}, + {0x86f9,0x22}, + {0x86fa,0xec}, + {0x86fb,0xf6}, + {0x86fc,0x08}, + {0x86fd,0xed}, + {0x86fe,0xf6}, + {0x86ff,0x08}, + {0x8700,0xee}, + {0x8701,0xf6}, + {0x8702,0x08}, + {0x8703,0xef}, + {0x8704,0xf6}, + {0x8705,0x22}, + {0x8706,0xa4}, + {0x8707,0x25}, + {0x8708,0x82}, + {0x8709,0xf5}, + {0x870a,0x82}, + {0x870b,0xe5}, + {0x870c,0xf0}, + {0x870d,0x35}, + {0x870e,0x83}, + {0x870f,0xf5}, + {0x8710,0x83}, + {0x8711,0x22}, + {0x8712,0xd0}, + {0x8713,0x83}, + {0x8714,0xd0}, + {0x8715,0x82}, + {0x8716,0xf8}, + {0x8717,0xe4}, + {0x8718,0x93}, + {0x8719,0x70}, + {0x871a,0x12}, + {0x871b,0x74}, + {0x871c,0x01}, + {0x871d,0x93}, + {0x871e,0x70}, + {0x871f,0x0d}, + {0x8720,0xa3}, + {0x8721,0xa3}, + {0x8722,0x93}, + {0x8723,0xf8}, + {0x8724,0x74}, + {0x8725,0x01}, + {0x8726,0x93}, + {0x8727,0xf5}, + {0x8728,0x82}, + {0x8729,0x88}, + {0x872a,0x83}, + {0x872b,0xe4}, + {0x872c,0x73}, + {0x872d,0x74}, + {0x872e,0x02}, + {0x872f,0x93}, + {0x8730,0x68}, + {0x8731,0x60}, + {0x8732,0xef}, + {0x8733,0xa3}, + {0x8734,0xa3}, + {0x8735,0xa3}, + {0x8736,0x80}, + {0x8737,0xdf}, + {0x8738,0x90}, + {0x8739,0x38}, + {0x873a,0x04}, + {0x873b,0x78}, + {0x873c,0x52}, + {0x873d,0x12}, + {0x873e,0x0b}, + {0x873f,0x0f}, + {0x8740,0x90}, + {0x8741,0x38}, + {0x8742,0x00}, + {0x8743,0xe0}, + {0x8744,0xfe}, + {0x8745,0xa3}, + {0x8746,0xe0}, + {0x8747,0xfd}, + {0x8748,0xed}, + {0x8749,0xff}, + {0x874a,0xc3}, + {0x874b,0x12}, + {0x874c,0x0a}, + {0x874d,0xb0}, + {0x874e,0x90}, + {0x874f,0x38}, + {0x8750,0x10}, + {0x8751,0x12}, + {0x8752,0x0a}, + {0x8753,0xa4}, + {0x8754,0x90}, + {0x8755,0x38}, + {0x8756,0x06}, + {0x8757,0x78}, + {0x8758,0x54}, + {0x8759,0x12}, + {0x875a,0x0b}, + {0x875b,0x0f}, + {0x875c,0x90}, + {0x875d,0x38}, + {0x875e,0x02}, + {0x875f,0xe0}, + {0x8760,0xfe}, + {0x8761,0xa3}, + {0x8762,0xe0}, + {0x8763,0xfd}, + {0x8764,0xed}, + {0x8765,0xff}, + {0x8766,0xc3}, + {0x8767,0x12}, + {0x8768,0x0a}, + {0x8769,0xb0}, + {0x876a,0x90}, + {0x876b,0x38}, + {0x876c,0x12}, + {0x876d,0x12}, + {0x876e,0x0a}, + {0x876f,0xa4}, + {0x8770,0xa3}, + {0x8771,0xe0}, + {0x8772,0xb4}, + {0x8773,0x31}, + {0x8774,0x07}, + {0x8775,0x78}, + {0x8776,0x52}, + {0x8777,0x79}, + {0x8778,0x52}, + {0x8779,0x12}, + {0x877a,0x0b}, + {0x877b,0x2f}, + {0x877c,0x90}, + {0x877d,0x38}, + {0x877e,0x14}, + {0x877f,0xe0}, + {0x8780,0xb4}, + {0x8781,0x71}, + {0x8782,0x15}, + {0x8783,0x78}, + {0x8784,0x52}, + {0x8785,0xe6}, + {0x8786,0xfe}, + {0x8787,0x08}, + {0x8788,0xe6}, + {0x8789,0x78}, + {0x878a,0x02}, + {0x878b,0xce}, + {0x878c,0xc3}, + {0x878d,0x13}, + {0x878e,0xce}, + {0x878f,0x13}, + {0x8790,0xd8}, + {0x8791,0xf9}, + {0x8792,0x79}, + {0x8793,0x53}, + {0x8794,0xf7}, + {0x8795,0xee}, + {0x8796,0x19}, + {0x8797,0xf7}, + {0x8798,0x90}, + {0x8799,0x38}, + {0x879a,0x15}, + {0x879b,0xe0}, + {0x879c,0xb4}, + {0x879d,0x31}, + {0x879e,0x07}, + {0x879f,0x78}, + {0x87a0,0x54}, + {0x87a1,0x79}, + {0x87a2,0x54}, + {0x87a3,0x12}, + {0x87a4,0x0b}, + {0x87a5,0x2f}, + {0x87a6,0x90}, + {0x87a7,0x38}, + {0x87a8,0x15}, + {0x87a9,0xe0}, + {0x87aa,0xb4}, + {0x87ab,0x71}, + {0x87ac,0x15}, + {0x87ad,0x78}, + {0x87ae,0x54}, + {0x87af,0xe6}, + {0x87b0,0xfe}, + {0x87b1,0x08}, + {0x87b2,0xe6}, + {0x87b3,0x78}, + {0x87b4,0x02}, + {0x87b5,0xce}, + {0x87b6,0xc3}, + {0x87b7,0x13}, + {0x87b8,0xce}, + {0x87b9,0x13}, + {0x87ba,0xd8}, + {0x87bb,0xf9}, + {0x87bc,0x79}, + {0x87bd,0x55}, + {0x87be,0xf7}, + {0x87bf,0xee}, + {0x87c0,0x19}, + {0x87c1,0xf7}, + {0x87c2,0x79}, + {0x87c3,0x52}, + {0x87c4,0x12}, + {0x87c5,0x0a}, + {0x87c6,0xeb}, + {0x87c7,0x09}, + {0x87c8,0x12}, + {0x87c9,0x0a}, + {0x87ca,0xeb}, + {0x87cb,0xaf}, + {0x87cc,0x47}, + {0x87cd,0x12}, + {0x87ce,0x0a}, + {0x87cf,0xc4}, + {0x87d0,0xe5}, + {0x87d1,0x44}, + {0x87d2,0xfb}, + {0x87d3,0x7a}, + {0x87d4,0x00}, + {0x87d5,0xfd}, + {0x87d6,0x7c}, + {0x87d7,0x00}, + {0x87d8,0x12}, + {0x87d9,0x05}, + {0x87da,0x34}, + {0x87db,0x78}, + {0x87dc,0x5a}, + {0x87dd,0xa6}, + {0x87de,0x06}, + {0x87df,0x08}, + {0x87e0,0xa6}, + {0x87e1,0x07}, + {0x87e2,0xaf}, + {0x87e3,0x45}, + {0x87e4,0x12}, + {0x87e5,0x0a}, + {0x87e6,0xc4}, + {0x87e7,0xad}, + {0x87e8,0x03}, + {0x87e9,0x7c}, + {0x87ea,0x00}, + {0x87eb,0x12}, + {0x87ec,0x05}, + {0x87ed,0x34}, + {0x87ee,0x78}, + {0x87ef,0x56}, + {0x87f0,0xa6}, + {0x87f1,0x06}, + {0x87f2,0x08}, + {0x87f3,0xa6}, + {0x87f4,0x07}, + {0x87f5,0xaf}, + {0x87f6,0x48}, + {0x87f7,0x78}, + {0x87f8,0x54}, + {0x87f9,0x12}, + {0x87fa,0x0a}, + {0x87fb,0xc6}, + {0x87fc,0xe5}, + {0x87fd,0x43}, + {0x87fe,0xfb}, + {0x87ff,0xfd}, + {0x8800,0x7c}, + {0x8801,0x00}, + {0x8802,0x12}, + {0x8803,0x05}, + {0x8804,0x34}, + {0x8805,0x78}, + {0x8806,0x5c}, + {0x8807,0xa6}, + {0x8808,0x06}, + {0x8809,0x08}, + {0x880a,0xa6}, + {0x880b,0x07}, + {0x880c,0xaf}, + {0x880d,0x46}, + {0x880e,0x7e}, + {0x880f,0x00}, + {0x8810,0x78}, + {0x8811,0x54}, + {0x8812,0x12}, + {0x8813,0x0a}, + {0x8814,0xc8}, + {0x8815,0xad}, + {0x8816,0x03}, + {0x8817,0x7c}, + {0x8818,0x00}, + {0x8819,0x12}, + {0x881a,0x05}, + {0x881b,0x34}, + {0x881c,0x78}, + {0x881d,0x58}, + {0x881e,0xa6}, + {0x881f,0x06}, + {0x8820,0x08}, + {0x8821,0xa6}, + {0x8822,0x07}, + {0x8823,0xc3}, + {0x8824,0x78}, + {0x8825,0x5b}, + {0x8826,0xe6}, + {0x8827,0x94}, + {0x8828,0x08}, + {0x8829,0x18}, + {0x882a,0xe6}, + {0x882b,0x94}, + {0x882c,0x00}, + {0x882d,0x50}, + {0x882e,0x05}, + {0x882f,0x76}, + {0x8830,0x00}, + {0x8831,0x08}, + {0x8832,0x76}, + {0x8833,0x08}, + {0x8834,0xc3}, + {0x8835,0x78}, + {0x8836,0x5d}, + {0x8837,0xe6}, + {0x8838,0x94}, + {0x8839,0x08}, + {0x883a,0x18}, + {0x883b,0xe6}, + {0x883c,0x94}, + {0x883d,0x00}, + {0x883e,0x50}, + {0x883f,0x05}, + {0x8840,0x76}, + {0x8841,0x00}, + {0x8842,0x08}, + {0x8843,0x76}, + {0x8844,0x08}, + {0x8845,0x78}, + {0x8846,0x5a}, + {0x8847,0x12}, + {0x8848,0x0a}, + {0x8849,0xd8}, + {0x884a,0xff}, + {0x884b,0xd3}, + {0x884c,0x78}, + {0x884d,0x57}, + {0x884e,0xe6}, + {0x884f,0x9f}, + {0x8850,0x18}, + {0x8851,0xe6}, + {0x8852,0x9e}, + {0x8853,0x40}, + {0x8854,0x0e}, + {0x8855,0x78}, + {0x8856,0x5a}, + {0x8857,0xe6}, + {0x8858,0x13}, + {0x8859,0xfe}, + {0x885a,0x08}, + {0x885b,0xe6}, + {0x885c,0x78}, + {0x885d,0x57}, + {0x885e,0x12}, + {0x885f,0x0b}, + {0x8860,0x1a}, + {0x8861,0x80}, + {0x8862,0x04}, + {0x8863,0x7e}, + {0x8864,0x00}, + {0x8865,0x7f}, + {0x8866,0x00}, + {0x8867,0x78}, + {0x8868,0x5e}, + {0x8869,0x12}, + {0x886a,0x0a}, + {0x886b,0xd0}, + {0x886c,0xff}, + {0x886d,0xd3}, + {0x886e,0x78}, + {0x886f,0x59}, + {0x8870,0xe6}, + {0x8871,0x9f}, + {0x8872,0x18}, + {0x8873,0xe6}, + {0x8874,0x9e}, + {0x8875,0x40}, + {0x8876,0x0e}, + {0x8877,0x78}, + {0x8878,0x5c}, + {0x8879,0xe6}, + {0x887a,0x13}, + {0x887b,0xfe}, + {0x887c,0x08}, + {0x887d,0xe6}, + {0x887e,0x78}, + {0x887f,0x59}, + {0x8880,0x12}, + {0x8881,0x0b}, + {0x8882,0x1a}, + {0x8883,0x80}, + {0x8884,0x04}, + {0x8885,0x7e}, + {0x8886,0x00}, + {0x8887,0x7f}, + {0x8888,0x00}, + {0x8889,0xe4}, + {0x888a,0xfc}, + {0x888b,0xfd}, + {0x888c,0x78}, + {0x888d,0x62}, + {0x888e,0x12}, + {0x888f,0x06}, + {0x8890,0xfa}, + {0x8891,0x78}, + {0x8892,0x5a}, + {0x8893,0x12}, + {0x8894,0x0a}, + {0x8895,0xd8}, + {0x8896,0x78}, + {0x8897,0x57}, + {0x8898,0x26}, + {0x8899,0xff}, + {0x889a,0xee}, + {0x889b,0x18}, + {0x889c,0x36}, + {0x889d,0xfe}, + {0x889e,0x78}, + {0x889f,0x66}, + {0x88a0,0x12}, + {0x88a1,0x0a}, + {0x88a2,0xd0}, + {0x88a3,0x78}, + {0x88a4,0x59}, + {0x88a5,0x26}, + {0x88a6,0xff}, + {0x88a7,0xee}, + {0x88a8,0x18}, + {0x88a9,0x36}, + {0x88aa,0xfe}, + {0x88ab,0xe4}, + {0x88ac,0xfc}, + {0x88ad,0xfd}, + {0x88ae,0x78}, + {0x88af,0x6a}, + {0x88b0,0x12}, + {0x88b1,0x06}, + {0x88b2,0xfa}, + {0x88b3,0x12}, + {0x88b4,0x0a}, + {0x88b5,0xe0}, + {0x88b6,0x78}, + {0x88b7,0x66}, + {0x88b8,0x12}, + {0x88b9,0x06}, + {0x88ba,0xed}, + {0x88bb,0xd3}, + {0x88bc,0x12}, + {0x88bd,0x06}, + {0x88be,0xa6}, + {0x88bf,0x40}, + {0x88c0,0x08}, + {0x88c1,0x12}, + {0x88c2,0x0a}, + {0x88c3,0xe0}, + {0x88c4,0x78}, + {0x88c5,0x66}, + {0x88c6,0x12}, + {0x88c7,0x06}, + {0x88c8,0xfa}, + {0x88c9,0x78}, + {0x88ca,0x54}, + {0x88cb,0x12}, + {0x88cc,0x0a}, + {0x88cd,0xe2}, + {0x88ce,0x78}, + {0x88cf,0x6a}, + {0x88d0,0x12}, + {0x88d1,0x06}, + {0x88d2,0xed}, + {0x88d3,0xd3}, + {0x88d4,0x12}, + {0x88d5,0x06}, + {0x88d6,0xa6}, + {0x88d7,0x40}, + {0x88d8,0x0a}, + {0x88d9,0x78}, + {0x88da,0x54}, + {0x88db,0x12}, + {0x88dc,0x0a}, + {0x88dd,0xe2}, + {0x88de,0x78}, + {0x88df,0x6a}, + {0x88e0,0x12}, + {0x88e1,0x06}, + {0x88e2,0xfa}, + {0x88e3,0x78}, + {0x88e4,0x61}, + {0x88e5,0xe6}, + {0x88e6,0x90}, + {0x88e7,0x60}, + {0x88e8,0x01}, + {0x88e9,0xf0}, + {0x88ea,0x78}, + {0x88eb,0x65}, + {0x88ec,0xe6}, + {0x88ed,0xa3}, + {0x88ee,0xf0}, + {0x88ef,0x78}, + {0x88f0,0x69}, + {0x88f1,0xe6}, + {0x88f2,0xa3}, + {0x88f3,0xf0}, + {0x88f4,0x78}, + {0x88f5,0x55}, + {0x88f6,0xe6}, + {0x88f7,0xa3}, + {0x88f8,0xf0}, + {0x88f9,0x7d}, + {0x88fa,0x01}, + {0x88fb,0x78}, + {0x88fc,0x61}, + {0x88fd,0x12}, + {0x88fe,0x0a}, + {0x88ff,0xfb}, + {0x8900,0x24}, + {0x8901,0x01}, + {0x8902,0x12}, + {0x8903,0x0a}, + {0x8904,0xb8}, + {0x8905,0x78}, + {0x8906,0x65}, + {0x8907,0x12}, + {0x8908,0x0a}, + {0x8909,0xfb}, + {0x890a,0x24}, + {0x890b,0x02}, + {0x890c,0x12}, + {0x890d,0x0a}, + {0x890e,0xb8}, + {0x890f,0x78}, + {0x8910,0x69}, + {0x8911,0x12}, + {0x8912,0x0a}, + {0x8913,0xfb}, + {0x8914,0x24}, + {0x8915,0x03}, + {0x8916,0x12}, + {0x8917,0x0a}, + {0x8918,0xb8}, + {0x8919,0x78}, + {0x891a,0x6d}, + {0x891b,0x12}, + {0x891c,0x0a}, + {0x891d,0xfb}, + {0x891e,0x24}, + {0x891f,0x04}, + {0x8920,0x12}, + {0x8921,0x0a}, + {0x8922,0xb8}, + {0x8923,0x0d}, + {0x8924,0xbd}, + {0x8925,0x05}, + {0x8926,0xd4}, + {0x8927,0x22}, + {0x8928,0xc0}, + {0x8929,0xe0}, + {0x892a,0xc0}, + {0x892b,0x83}, + {0x892c,0xc0}, + {0x892d,0x82}, + {0x892e,0xc0}, + {0x892f,0xd0}, + {0x8930,0x90}, + {0x8931,0x3f}, + {0x8932,0x0c}, + {0x8933,0xe0}, + {0x8934,0xf5}, + {0x8935,0x32}, + {0x8936,0xe5}, + {0x8937,0x32}, + {0x8938,0x30}, + {0x8939,0xe3}, + {0x893a,0x74}, + {0x893b,0x30}, + {0x893c,0x36}, + {0x893d,0x66}, + {0x893e,0x90}, + {0x893f,0x60}, + {0x8940,0x19}, + {0x8941,0xe0}, + {0x8942,0xf5}, + {0x8943,0x0a}, + {0x8944,0xa3}, + {0x8945,0xe0}, + {0x8946,0xf5}, + {0x8947,0x0b}, + {0x8948,0x90}, + {0x8949,0x60}, + {0x894a,0x1d}, + {0x894b,0xe0}, + {0x894c,0xf5}, + {0x894d,0x14}, + {0x894e,0xa3}, + {0x894f,0xe0}, + {0x8950,0xf5}, + {0x8951,0x15}, + {0x8952,0x90}, + {0x8953,0x60}, + {0x8954,0x21}, + {0x8955,0xe0}, + {0x8956,0xf5}, + {0x8957,0x0c}, + {0x8958,0xa3}, + {0x8959,0xe0}, + {0x895a,0xf5}, + {0x895b,0x0d}, + {0x895c,0x90}, + {0x895d,0x60}, + {0x895e,0x29}, + {0x895f,0xe0}, + {0x8960,0xf5}, + {0x8961,0x0e}, + {0x8962,0xa3}, + {0x8963,0xe0}, + {0x8964,0xf5}, + {0x8965,0x0f}, + {0x8966,0x90}, + {0x8967,0x60}, + {0x8968,0x31}, + {0x8969,0xe0}, + {0x896a,0xf5}, + {0x896b,0x10}, + {0x896c,0xa3}, + {0x896d,0xe0}, + {0x896e,0xf5}, + {0x896f,0x11}, + {0x8970,0x90}, + {0x8971,0x60}, + {0x8972,0x39}, + {0x8973,0xe0}, + {0x8974,0xf5}, + {0x8975,0x12}, + {0x8976,0xa3}, + {0x8977,0xe0}, + {0x8978,0xf5}, + {0x8979,0x13}, + {0x897a,0x30}, + {0x897b,0x01}, + {0x897c,0x06}, + {0x897d,0x30}, + {0x897e,0x33}, + {0x897f,0x03}, + {0x8980,0xd3}, + {0x8981,0x80}, + {0x8982,0x01}, + {0x8983,0xc3}, + {0x8984,0x92}, + {0x8985,0x09}, + {0x8986,0x30}, + {0x8987,0x02}, + {0x8988,0x06}, + {0x8989,0x30}, + {0x898a,0x33}, + {0x898b,0x03}, + {0x898c,0xd3}, + {0x898d,0x80}, + {0x898e,0x01}, + {0x898f,0xc3}, + {0x8990,0x92}, + {0x8991,0x0a}, + {0x8992,0x30}, + {0x8993,0x33}, + {0x8994,0x0c}, + {0x8995,0x30}, + {0x8996,0x03}, + {0x8997,0x09}, + {0x8998,0x20}, + {0x8999,0x02}, + {0x899a,0x06}, + {0x899b,0x20}, + {0x899c,0x01}, + {0x899d,0x03}, + {0x899e,0xd3}, + {0x899f,0x80}, + {0x89a0,0x01}, + {0x89a1,0xc3}, + {0x89a2,0x92}, + {0x89a3,0x0b}, + {0x89a4,0x90}, + {0x89a5,0x30}, + {0x89a6,0x01}, + {0x89a7,0xe0}, + {0x89a8,0x44}, + {0x89a9,0x40}, + {0x89aa,0xf0}, + {0x89ab,0xe0}, + {0x89ac,0x54}, + {0x89ad,0xbf}, + {0x89ae,0xf0}, + {0x89af,0xe5}, + {0x89b0,0x32}, + {0x89b1,0x30}, + {0x89b2,0xe1}, + {0x89b3,0x14}, + {0x89b4,0x30}, + {0x89b5,0x34}, + {0x89b6,0x11}, + {0x89b7,0x90}, + {0x89b8,0x30}, + {0x89b9,0x22}, + {0x89ba,0xe0}, + {0x89bb,0xf5}, + {0x89bc,0x08}, + {0x89bd,0xe4}, + {0x89be,0xf0}, + {0x89bf,0x30}, + {0x89c0,0x00}, + {0x89c1,0x03}, + {0x89c2,0xd3}, + {0x89c3,0x80}, + {0x89c4,0x01}, + {0x89c5,0xc3}, + {0x89c6,0x92}, + {0x89c7,0x08}, + {0x89c8,0xe5}, + {0x89c9,0x32}, + {0x89ca,0x30}, + {0x89cb,0xe5}, + {0x89cc,0x12}, + {0x89cd,0x90}, + {0x89ce,0x56}, + {0x89cf,0xa1}, + {0x89d0,0xe0}, + {0x89d1,0xf5}, + {0x89d2,0x09}, + {0x89d3,0x30}, + {0x89d4,0x31}, + {0x89d5,0x09}, + {0x89d6,0x30}, + {0x89d7,0x05}, + {0x89d8,0x03}, + {0x89d9,0xd3}, + {0x89da,0x80}, + {0x89db,0x01}, + {0x89dc,0xc3}, + {0x89dd,0x92}, + {0x89de,0x0d}, + {0x89df,0x90}, + {0x89e0,0x3f}, + {0x89e1,0x0c}, + {0x89e2,0xe5}, + {0x89e3,0x32}, + {0x89e4,0xf0}, + {0x89e5,0xd0}, + {0x89e6,0xd0}, + {0x89e7,0xd0}, + {0x89e8,0x82}, + {0x89e9,0xd0}, + {0x89ea,0x83}, + {0x89eb,0xd0}, + {0x89ec,0xe0}, + {0x89ed,0x32}, + {0x89ee,0x85}, + {0x89ef,0x08}, + {0x89f0,0x41}, + {0x89f1,0x90}, + {0x89f2,0x30}, + {0x89f3,0x24}, + {0x89f4,0xe0}, + {0x89f5,0xf5}, + {0x89f6,0x3d}, + {0x89f7,0xa3}, + {0x89f8,0xe0}, + {0x89f9,0xf5}, + {0x89fa,0x3e}, + {0x89fb,0xa3}, + {0x89fc,0xe0}, + {0x89fd,0xf5}, + {0x89fe,0x3f}, + {0x89ff,0xa3}, + {0x8a00,0xe0}, + {0x8a01,0xf5}, + {0x8a02,0x40}, + {0x8a03,0xa3}, + {0x8a04,0xe0}, + {0x8a05,0xf5}, + {0x8a06,0x3c}, + {0x8a07,0xd2}, + {0x8a08,0x34}, + {0x8a09,0xe5}, + {0x8a0a,0x41}, + {0x8a0b,0x12}, + {0x8a0c,0x07}, + {0x8a0d,0x12}, + {0x8a0e,0x0a}, + {0x8a0f,0x33}, + {0x8a10,0x03}, + {0x8a11,0x0a}, + {0x8a12,0x40}, + {0x8a13,0x04}, + {0x8a14,0x0a}, + {0x8a15,0x51}, + {0x8a16,0x05}, + {0x8a17,0x0a}, + {0x8a18,0x54}, + {0x8a19,0x06}, + {0x8a1a,0x0a}, + {0x8a1b,0x5d}, + {0x8a1c,0x08}, + {0x8a1d,0x0a}, + {0x8a1e,0x6d}, + {0x8a1f,0x12}, + {0x8a20,0x0a}, + {0x8a21,0x72}, + {0x8a22,0x1a}, + {0x8a23,0x0a}, + {0x8a24,0x7d}, + {0x8a25,0x1b}, + {0x8a26,0x0a}, + {0x8a27,0x6d}, + {0x8a28,0x80}, + {0x8a29,0x0a}, + {0x8a2a,0x6d}, + {0x8a2b,0x81}, + {0x8a2c,0x0a}, + {0x8a2d,0x85}, + {0x8a2e,0xec}, + {0x8a2f,0x00}, + {0x8a30,0x00}, + {0x8a31,0x0a}, + {0x8a32,0xa3}, + {0x8a33,0x12}, + {0x8a34,0x0f}, + {0x8a35,0xd2}, + {0x8a36,0xd2}, + {0x8a37,0x36}, + {0x8a38,0xd2}, + {0x8a39,0x01}, + {0x8a3a,0xc2}, + {0x8a3b,0x02}, + {0x8a3c,0x12}, + {0x8a3d,0x0f}, + {0x8a3e,0xd7}, + {0x8a3f,0x22}, + {0x8a40,0xd2}, + {0x8a41,0x33}, + {0x8a42,0xd2}, + {0x8a43,0x36}, + {0x8a44,0xe5}, + {0x8a45,0x3d}, + {0x8a46,0xd3}, + {0x8a47,0x94}, + {0x8a48,0x00}, + {0x8a49,0x40}, + {0x8a4a,0x03}, + {0x8a4b,0x12}, + {0x8a4c,0x0f}, + {0x8a4d,0xd2}, + {0x8a4e,0xd2}, + {0x8a4f,0x03}, + {0x8a50,0x22}, + {0x8a51,0xd2}, + {0x8a52,0x03}, + {0x8a53,0x22}, + {0x8a54,0xc2}, + {0x8a55,0x03}, + {0x8a56,0x20}, + {0x8a57,0x01}, + {0x8a58,0x4a}, + {0x8a59,0x30}, + {0x8a5a,0x02}, + {0x8a5b,0x2c}, + {0x8a5c,0x22}, + {0x8a5d,0xc2}, + {0x8a5e,0x01}, + {0x8a5f,0xc2}, + {0x8a60,0x02}, + {0x8a61,0xc2}, + {0x8a62,0x03}, + {0x8a63,0x12}, + {0x8a64,0x0d}, + {0x8a65,0x39}, + {0x8a66,0x75}, + {0x8a67,0x1e}, + {0x8a68,0x70}, + {0x8a69,0xd2}, + {0x8a6a,0x35}, + {0x8a6b,0x80}, + {0x8a6c,0x1b}, + {0x8a6d,0x12}, + {0x8a6e,0x0b}, + {0x8a6f,0xcc}, + {0x8a70,0x80}, + {0x8a71,0x16}, + {0x8a72,0x85}, + {0x8a73,0x40}, + {0x8a74,0x4a}, + {0x8a75,0x85}, + {0x8a76,0x3c}, + {0x8a77,0x4b}, + {0x8a78,0x12}, + {0x8a79,0x0b}, + {0x8a7a,0x39}, + {0x8a7b,0x80}, + {0x8a7c,0x0b}, + {0x8a7d,0x85}, + {0x8a7e,0x4a}, + {0x8a7f,0x40}, + {0x8a80,0x85}, + {0x8a81,0x4b}, + {0x8a82,0x3c}, + {0x8a83,0x80}, + {0x8a84,0x03}, + {0x8a85,0x12}, + {0x8a86,0x0f}, + {0x8a87,0x00}, + {0x8a88,0x90}, + {0x8a89,0x30}, + {0x8a8a,0x24}, + {0x8a8b,0xe5}, + {0x8a8c,0x3d}, + {0x8a8d,0xf0}, + {0x8a8e,0xa3}, + {0x8a8f,0xe5}, + {0x8a90,0x3e}, + {0x8a91,0xf0}, + {0x8a92,0xa3}, + {0x8a93,0xe5}, + {0x8a94,0x3f}, + {0x8a95,0xf0}, + {0x8a96,0xa3}, + {0x8a97,0xe5}, + {0x8a98,0x40}, + {0x8a99,0xf0}, + {0x8a9a,0xa3}, + {0x8a9b,0xe5}, + {0x8a9c,0x3c}, + {0x8a9d,0xf0}, + {0x8a9e,0x90}, + {0x8a9f,0x30}, + {0x8aa0,0x23}, + {0x8aa1,0xe4}, + {0x8aa2,0xf0}, + {0x8aa3,0x22}, + {0x8aa4,0xe0}, + {0x8aa5,0xa3}, + {0x8aa6,0xe0}, + {0x8aa7,0x75}, + {0x8aa8,0xf0}, + {0x8aa9,0x02}, + {0x8aaa,0xa4}, + {0x8aab,0xff}, + {0x8aac,0xae}, + {0x8aad,0xf0}, + {0x8aae,0xc3}, + {0x8aaf,0x08}, + {0x8ab0,0xe6}, + {0x8ab1,0x9f}, + {0x8ab2,0xf6}, + {0x8ab3,0x18}, + {0x8ab4,0xe6}, + {0x8ab5,0x9e}, + {0x8ab6,0xf6}, + {0x8ab7,0x22}, + {0x8ab8,0xff}, + {0x8ab9,0xe5}, + {0x8aba,0xf0}, + {0x8abb,0x34}, + {0x8abc,0x60}, + {0x8abd,0x8f}, + {0x8abe,0x82}, + {0x8abf,0xf5}, + {0x8ac0,0x83}, + {0x8ac1,0xec}, + {0x8ac2,0xf0}, + {0x8ac3,0x22}, + {0x8ac4,0x78}, + {0x8ac5,0x52}, + {0x8ac6,0x7e}, + {0x8ac7,0x00}, + {0x8ac8,0xe6}, + {0x8ac9,0xfc}, + {0x8aca,0x08}, + {0x8acb,0xe6}, + {0x8acc,0xfd}, + {0x8acd,0x02}, + {0x8ace,0x05}, + {0x8acf,0x22}, + {0x8ad0,0xe4}, + {0x8ad1,0xfc}, + {0x8ad2,0xfd}, + {0x8ad3,0x12}, + {0x8ad4,0x06}, + {0x8ad5,0xfa}, + {0x8ad6,0x78}, + {0x8ad7,0x5c}, + {0x8ad8,0xe6}, + {0x8ad9,0xc3}, + {0x8ada,0x13}, + {0x8adb,0xfe}, + {0x8adc,0x08}, + {0x8add,0xe6}, + {0x8ade,0x13}, + {0x8adf,0x22}, + {0x8ae0,0x78}, + {0x8ae1,0x52}, + {0x8ae2,0xe6}, + {0x8ae3,0xfe}, + {0x8ae4,0x08}, + {0x8ae5,0xe6}, + {0x8ae6,0xff}, + {0x8ae7,0xe4}, + {0x8ae8,0xfc}, + {0x8ae9,0xfd}, + {0x8aea,0x22}, + {0x8aeb,0xe7}, + {0x8aec,0xc4}, + {0x8aed,0xf8}, + {0x8aee,0x54}, + {0x8aef,0xf0}, + {0x8af0,0xc8}, + {0x8af1,0x68}, + {0x8af2,0xf7}, + {0x8af3,0x09}, + {0x8af4,0xe7}, + {0x8af5,0xc4}, + {0x8af6,0x54}, + {0x8af7,0x0f}, + {0x8af8,0x48}, + {0x8af9,0xf7}, + {0x8afa,0x22}, + {0x8afb,0xe6}, + {0x8afc,0xfc}, + {0x8afd,0xed}, + {0x8afe,0x75}, + {0x8aff,0xf0}, + {0x8b00,0x04}, + {0x8b01,0xa4}, + {0x8b02,0x22}, + {0x8b03,0x12}, + {0x8b04,0x06}, + {0x8b05,0xdd}, + {0x8b06,0x8f}, + {0x8b07,0x48}, + {0x8b08,0x8e}, + {0x8b09,0x47}, + {0x8b0a,0x8d}, + {0x8b0b,0x46}, + {0x8b0c,0x8c}, + {0x8b0d,0x45}, + {0x8b0e,0x22}, + {0x8b0f,0xe0}, + {0x8b10,0xfe}, + {0x8b11,0xa3}, + {0x8b12,0xe0}, + {0x8b13,0xfd}, + {0x8b14,0xee}, + {0x8b15,0xf6}, + {0x8b16,0xed}, + {0x8b17,0x08}, + {0x8b18,0xf6}, + {0x8b19,0x22}, + {0x8b1a,0x13}, + {0x8b1b,0xff}, + {0x8b1c,0xc3}, + {0x8b1d,0xe6}, + {0x8b1e,0x9f}, + {0x8b1f,0xff}, + {0x8b20,0x18}, + {0x8b21,0xe6}, + {0x8b22,0x9e}, + {0x8b23,0xfe}, + {0x8b24,0x22}, + {0x8b25,0xfb}, + {0x8b26,0xd3}, + {0x8b27,0xed}, + {0x8b28,0x9b}, + {0x8b29,0x74}, + {0x8b2a,0x80}, + {0x8b2b,0xf8}, + {0x8b2c,0x6c}, + {0x8b2d,0x98}, + {0x8b2e,0x22}, + {0x8b2f,0xe6}, + {0x8b30,0xc3}, + {0x8b31,0x13}, + {0x8b32,0xf7}, + {0x8b33,0x08}, + {0x8b34,0xe6}, + {0x8b35,0x13}, + {0x8b36,0x09}, + {0x8b37,0xf7}, + {0x8b38,0x22}, + {0x8b39,0x90}, + {0x8b3a,0x0e}, + {0x8b3b,0x7e}, + {0x8b3c,0xe4}, + {0x8b3d,0x93}, + {0x8b3e,0xfe}, + {0x8b3f,0x74}, + {0x8b40,0x01}, + {0x8b41,0x93}, + {0x8b42,0xff}, + {0x8b43,0xc3}, + {0x8b44,0x90}, + {0x8b45,0x0e}, + {0x8b46,0x7c}, + {0x8b47,0x74}, + {0x8b48,0x01}, + {0x8b49,0x93}, + {0x8b4a,0x9f}, + {0x8b4b,0xff}, + {0x8b4c,0xe4}, + {0x8b4d,0x93}, + {0x8b4e,0x9e}, + {0x8b4f,0xfe}, + {0x8b50,0xe4}, + {0x8b51,0x8f}, + {0x8b52,0x3b}, + {0x8b53,0x8e}, + {0x8b54,0x3a}, + {0x8b55,0xf5}, + {0x8b56,0x39}, + {0x8b57,0xf5}, + {0x8b58,0x38}, + {0x8b59,0xab}, + {0x8b5a,0x3b}, + {0x8b5b,0xaa}, + {0x8b5c,0x3a}, + {0x8b5d,0xa9}, + {0x8b5e,0x39}, + {0x8b5f,0xa8}, + {0x8b60,0x38}, + {0x8b61,0xaf}, + {0x8b62,0x4b}, + {0x8b63,0xfc}, + {0x8b64,0xfd}, + {0x8b65,0xfe}, + {0x8b66,0x12}, + {0x8b67,0x05}, + {0x8b68,0x89}, + {0x8b69,0x12}, + {0x8b6a,0x0f}, + {0x8b6b,0x91}, + {0x8b6c,0xe4}, + {0x8b6d,0x7b}, + {0x8b6e,0xff}, + {0x8b6f,0xfa}, + {0x8b70,0xf9}, + {0x8b71,0xf8}, + {0x8b72,0x12}, + {0x8b73,0x06}, + {0x8b74,0x14}, + {0x8b75,0x12}, + {0x8b76,0x0f}, + {0x8b77,0x91}, + {0x8b78,0x90}, + {0x8b79,0x0e}, + {0x8b7a,0x69}, + {0x8b7b,0xe4}, + {0x8b7c,0x12}, + {0x8b7d,0x0f}, + {0x8b7e,0xa6}, + {0x8b7f,0x12}, + {0x8b80,0x0f}, + {0x8b81,0x91}, + {0x8b82,0xe4}, + {0x8b83,0x85}, + {0x8b84,0x4a}, + {0x8b85,0x37}, + {0x8b86,0xf5}, + {0x8b87,0x36}, + {0x8b88,0xf5}, + {0x8b89,0x35}, + {0x8b8a,0xf5}, + {0x8b8b,0x34}, + {0x8b8c,0xaf}, + {0x8b8d,0x37}, + {0x8b8e,0xae}, + {0x8b8f,0x36}, + {0x8b90,0xad}, + {0x8b91,0x35}, + {0x8b92,0xac}, + {0x8b93,0x34}, + {0x8b94,0xa3}, + {0x8b95,0x12}, + {0x8b96,0x0f}, + {0x8b97,0xa6}, + {0x8b98,0x8f}, + {0x8b99,0x37}, + {0x8b9a,0x8e}, + {0x8b9b,0x36}, + {0x8b9c,0x8d}, + {0x8b9d,0x35}, + {0x8b9e,0x8c}, + {0x8b9f,0x34}, + {0x8ba0,0xe5}, + {0x8ba1,0x3b}, + {0x8ba2,0x45}, + {0x8ba3,0x37}, + {0x8ba4,0xf5}, + {0x8ba5,0x3b}, + {0x8ba6,0xe5}, + {0x8ba7,0x3a}, + {0x8ba8,0x45}, + {0x8ba9,0x36}, + {0x8baa,0xf5}, + {0x8bab,0x3a}, + {0x8bac,0xe5}, + {0x8bad,0x39}, + {0x8bae,0x45}, + {0x8baf,0x35}, + {0x8bb0,0xf5}, + {0x8bb1,0x39}, + {0x8bb2,0xe5}, + {0x8bb3,0x38}, + {0x8bb4,0x45}, + {0x8bb5,0x34}, + {0x8bb6,0xf5}, + {0x8bb7,0x38}, + {0x8bb8,0xe4}, + {0x8bb9,0xf5}, + {0x8bba,0x22}, + {0x8bbb,0xf5}, + {0x8bbc,0x23}, + {0x8bbd,0x85}, + {0x8bbe,0x3b}, + {0x8bbf,0x31}, + {0x8bc0,0x85}, + {0x8bc1,0x3a}, + {0x8bc2,0x30}, + {0x8bc3,0x85}, + {0x8bc4,0x39}, + {0x8bc5,0x2f}, + {0x8bc6,0x85}, + {0x8bc7,0x38}, + {0x8bc8,0x2e}, + {0x8bc9,0x02}, + {0x8bca,0x0f}, + {0x8bcb,0x63}, + {0x8bcc,0xe5}, + {0x8bcd,0x3c}, + {0x8bce,0xd3}, + {0x8bcf,0x94}, + {0x8bd0,0x01}, + {0x8bd1,0x40}, + {0x8bd2,0x0b}, + {0x8bd3,0x90}, + {0x8bd4,0x0e}, + {0x8bd5,0x88}, + {0x8bd6,0x12}, + {0x8bd7,0x0b}, + {0x8bd8,0x03}, + {0x8bd9,0x90}, + {0x8bda,0x0e}, + {0x8bdb,0x86}, + {0x8bdc,0x80}, + {0x8bdd,0x09}, + {0x8bde,0x90}, + {0x8bdf,0x0e}, + {0x8be0,0x82}, + {0x8be1,0x12}, + {0x8be2,0x0b}, + {0x8be3,0x03}, + {0x8be4,0x90}, + {0x8be5,0x0e}, + {0x8be6,0x80}, + {0x8be7,0xe4}, + {0x8be8,0x93}, + {0x8be9,0xf5}, + {0x8bea,0x44}, + {0x8beb,0xa3}, + {0x8bec,0xe4}, + {0x8bed,0x93}, + {0x8bee,0xf5}, + {0x8bef,0x43}, + {0x8bf0,0xe5}, + {0x8bf1,0x3c}, + {0x8bf2,0xd3}, + {0x8bf3,0x94}, + {0x8bf4,0x00}, + {0x8bf5,0x40}, + {0x8bf6,0x06}, + {0x8bf7,0x85}, + {0x8bf8,0x3d}, + {0x8bf9,0x45}, + {0x8bfa,0x85}, + {0x8bfb,0x3e}, + {0x8bfc,0x46}, + {0x8bfd,0xe5}, + {0x8bfe,0x47}, + {0x8bff,0xc3}, + {0x8c00,0x13}, + {0x8c01,0xff}, + {0x8c02,0xe5}, + {0x8c03,0x45}, + {0x8c04,0xc3}, + {0x8c05,0x9f}, + {0x8c06,0x50}, + {0x8c07,0x02}, + {0x8c08,0x8f}, + {0x8c09,0x45}, + {0x8c0a,0xe5}, + {0x8c0b,0x48}, + {0x8c0c,0xc3}, + {0x8c0d,0x13}, + {0x8c0e,0xff}, + {0x8c0f,0xe5}, + {0x8c10,0x46}, + {0x8c11,0xc3}, + {0x8c12,0x9f}, + {0x8c13,0x50}, + {0x8c14,0x02}, + {0x8c15,0x8f}, + {0x8c16,0x46}, + {0x8c17,0xe5}, + {0x8c18,0x47}, + {0x8c19,0xc3}, + {0x8c1a,0x13}, + {0x8c1b,0xff}, + {0x8c1c,0xfd}, + {0x8c1d,0xe5}, + {0x8c1e,0x45}, + {0x8c1f,0x2d}, + {0x8c20,0xfd}, + {0x8c21,0xe4}, + {0x8c22,0x33}, + {0x8c23,0xfc}, + {0x8c24,0xe5}, + {0x8c25,0x44}, + {0x8c26,0x12}, + {0x8c27,0x0b}, + {0x8c28,0x25}, + {0x8c29,0x40}, + {0x8c2a,0x05}, + {0x8c2b,0xe5}, + {0x8c2c,0x44}, + {0x8c2d,0x9f}, + {0x8c2e,0xf5}, + {0x8c2f,0x45}, + {0x8c30,0xe5}, + {0x8c31,0x48}, + {0x8c32,0xc3}, + {0x8c33,0x13}, + {0x8c34,0xff}, + {0x8c35,0xfd}, + {0x8c36,0xe5}, + {0x8c37,0x46}, + {0x8c38,0x2d}, + {0x8c39,0xfd}, + {0x8c3a,0xe4}, + {0x8c3b,0x33}, + {0x8c3c,0xfc}, + {0x8c3d,0xe5}, + {0x8c3e,0x43}, + {0x8c3f,0x12}, + {0x8c40,0x0b}, + {0x8c41,0x25}, + {0x8c42,0x40}, + {0x8c43,0x05}, + {0x8c44,0xe5}, + {0x8c45,0x43}, + {0x8c46,0x9f}, + {0x8c47,0xf5}, + {0x8c48,0x46}, + {0x8c49,0x02}, + {0x8c4a,0x07}, + {0x8c4b,0x38}, + {0x8c4c,0xad}, + {0x8c4d,0x39}, + {0x8c4e,0xac}, + {0x8c4f,0x38}, + {0x8c50,0xfa}, + {0x8c51,0xf9}, + {0x8c52,0xf8}, + {0x8c53,0x12}, + {0x8c54,0x05}, + {0x8c55,0x89}, + {0x8c56,0x8f}, + {0x8c57,0x3b}, + {0x8c58,0x8e}, + {0x8c59,0x3a}, + {0x8c5a,0x8d}, + {0x8c5b,0x39}, + {0x8c5c,0x8c}, + {0x8c5d,0x38}, + {0x8c5e,0xab}, + {0x8c5f,0x37}, + {0x8c60,0xaa}, + {0x8c61,0x36}, + {0x8c62,0xa9}, + {0x8c63,0x35}, + {0x8c64,0xa8}, + {0x8c65,0x34}, + {0x8c66,0x22}, + {0x8c67,0x90}, + {0x8c68,0x0e}, + {0x8c69,0x8c}, + {0x8c6a,0xe4}, + {0x8c6b,0x93}, + {0x8c6c,0x25}, + {0x8c6d,0xe0}, + {0x8c6e,0x24}, + {0x8c6f,0x0a}, + {0x8c70,0xf8}, + {0x8c71,0xe6}, + {0x8c72,0xfe}, + {0x8c73,0x08}, + {0x8c74,0xe6}, + {0x8c75,0xff}, + {0x8c76,0x22}, + {0x8c77,0x93}, + {0x8c78,0xff}, + {0x8c79,0xe4}, + {0x8c7a,0xfc}, + {0x8c7b,0xfd}, + {0x8c7c,0xfe}, + {0x8c7d,0x12}, + {0x8c7e,0x05}, + {0x8c7f,0x89}, + {0x8c80,0x8f}, + {0x8c81,0x37}, + {0x8c82,0x8e}, + {0x8c83,0x36}, + {0x8c84,0x8d}, + {0x8c85,0x35}, + {0x8c86,0x8c}, + {0x8c87,0x34}, + {0x8c88,0x22}, + {0x8c89,0xe6}, + {0x8c8a,0xfe}, + {0x8c8b,0x08}, + {0x8c8c,0xe6}, + {0x8c8d,0xff}, + {0x8c8e,0xe4}, + {0x8c8f,0x8f}, + {0x8c90,0x37}, + {0x8c91,0x8e}, + {0x8c92,0x36}, + {0x8c93,0xf5}, + {0x8c94,0x35}, + {0x8c95,0xf5}, + {0x8c96,0x34}, + {0x8c97,0x22}, + {0x8c98,0xef}, + {0x8c99,0x25}, + {0x8c9a,0xe0}, + {0x8c9b,0x24}, + {0x8c9c,0x4e}, + {0x8c9d,0xf8}, + {0x8c9e,0xe6}, + {0x8c9f,0xfc}, + {0x8ca0,0x08}, + {0x8ca1,0xe6}, + {0x8ca2,0xfd}, + {0x8ca3,0x22}, + {0x8ca4,0xd3}, + {0x8ca5,0x79}, + {0x8ca6,0x81}, + {0x8ca7,0xe7}, + {0x8ca8,0x78}, + {0x8ca9,0x7f}, + {0x8caa,0x96}, + {0x8cab,0x19}, + {0x8cac,0xe7}, + {0x8cad,0x18}, + {0x8cae,0x96}, + {0x8caf,0x22}, + {0x8cb0,0x78}, + {0x8cb1,0x89}, + {0x8cb2,0xef}, + {0x8cb3,0x26}, + {0x8cb4,0xf6}, + {0x8cb5,0x18}, + {0x8cb6,0xe4}, + {0x8cb7,0x36}, + {0x8cb8,0xf6}, + {0x8cb9,0x22}, + {0x8cba,0xe4}, + {0x8cbb,0x8f}, + {0x8cbc,0x3b}, + {0x8cbd,0x8e}, + {0x8cbe,0x3a}, + {0x8cbf,0xf5}, + {0x8cc0,0x39}, + {0x8cc1,0xf5}, + {0x8cc2,0x38}, + {0x8cc3,0x22}, + {0x8cc4,0x75}, + {0x8cc5,0x89}, + {0x8cc6,0x03}, + {0x8cc7,0x75}, + {0x8cc8,0xa8}, + {0x8cc9,0x01}, + {0x8cca,0x75}, + {0x8ccb,0xb8}, + {0x8ccc,0x04}, + {0x8ccd,0x75}, + {0x8cce,0x34}, + {0x8ccf,0xff}, + {0x8cd0,0x75}, + {0x8cd1,0x35}, + {0x8cd2,0x0e}, + {0x8cd3,0x75}, + {0x8cd4,0x36}, + {0x8cd5,0x15}, + {0x8cd6,0x75}, + {0x8cd7,0x37}, + {0x8cd8,0x0d}, + {0x8cd9,0x12}, + {0x8cda,0x0d}, + {0x8cdb,0xaa}, + {0x8cdc,0x12}, + {0x8cdd,0x00}, + {0x8cde,0x09}, + {0x8cdf,0x12}, + {0x8ce0,0x0b}, + {0x8ce1,0xcc}, + {0x8ce2,0x12}, + {0x8ce3,0x00}, + {0x8ce4,0x06}, + {0x8ce5,0xd2}, + {0x8ce6,0x00}, + {0x8ce7,0xd2}, + {0x8ce8,0x34}, + {0x8ce9,0xd2}, + {0x8cea,0xaf}, + {0x8ceb,0x75}, + {0x8cec,0x34}, + {0x8ced,0xff}, + {0x8cee,0x75}, + {0x8cef,0x35}, + {0x8cf0,0x0e}, + {0x8cf1,0x75}, + {0x8cf2,0x36}, + {0x8cf3,0x49}, + {0x8cf4,0x75}, + {0x8cf5,0x37}, + {0x8cf6,0x03}, + {0x8cf7,0x12}, + {0x8cf8,0x0d}, + {0x8cf9,0xaa}, + {0x8cfa,0x30}, + {0x8cfb,0x08}, + {0x8cfc,0x09}, + {0x8cfd,0xc2}, + {0x8cfe,0x34}, + {0x8cff,0x12}, + {0x8d00,0x09}, + {0x8d01,0xee}, + {0x8d02,0xc2}, + {0x8d03,0x08}, + {0x8d04,0xd2}, + {0x8d05,0x34}, + {0x8d06,0x30}, + {0x8d07,0x0b}, + {0x8d08,0x09}, + {0x8d09,0xc2}, + {0x8d0a,0x36}, + {0x8d0b,0x12}, + {0x8d0c,0x00}, + {0x8d0d,0x0e}, + {0x8d0e,0xc2}, + {0x8d0f,0x0b}, + {0x8d10,0xd2}, + {0x8d11,0x36}, + {0x8d12,0x30}, + {0x8d13,0x09}, + {0x8d14,0x09}, + {0x8d15,0xc2}, + {0x8d16,0x36}, + {0x8d17,0x12}, + {0x8d18,0x02}, + {0x8d19,0xa7}, + {0x8d1a,0xc2}, + {0x8d1b,0x09}, + {0x8d1c,0xd2}, + {0x8d1d,0x36}, + {0x8d1e,0x30}, + {0x8d1f,0x0e}, + {0x8d20,0x03}, + {0x8d21,0x12}, + {0x8d22,0x07}, + {0x8d23,0x38}, + {0x8d24,0x30}, + {0x8d25,0x35}, + {0x8d26,0xd3}, + {0x8d27,0x90}, + {0x8d28,0x30}, + {0x8d29,0x29}, + {0x8d2a,0xe5}, + {0x8d2b,0x1e}, + {0x8d2c,0xf0}, + {0x8d2d,0xb4}, + {0x8d2e,0x10}, + {0x8d2f,0x05}, + {0x8d30,0x90}, + {0x8d31,0x30}, + {0x8d32,0x23}, + {0x8d33,0xe4}, + {0x8d34,0xf0}, + {0x8d35,0xc2}, + {0x8d36,0x35}, + {0x8d37,0x80}, + {0x8d38,0xc1}, + {0x8d39,0xe4}, + {0x8d3a,0xf5}, + {0x8d3b,0x4b}, + {0x8d3c,0x90}, + {0x8d3d,0x0e}, + {0x8d3e,0x7a}, + {0x8d3f,0x93}, + {0x8d40,0xff}, + {0x8d41,0xe4}, + {0x8d42,0x8f}, + {0x8d43,0x37}, + {0x8d44,0xf5}, + {0x8d45,0x36}, + {0x8d46,0xf5}, + {0x8d47,0x35}, + {0x8d48,0xf5}, + {0x8d49,0x34}, + {0x8d4a,0xaf}, + {0x8d4b,0x37}, + {0x8d4c,0xae}, + {0x8d4d,0x36}, + {0x8d4e,0xad}, + {0x8d4f,0x35}, + {0x8d50,0xac}, + {0x8d51,0x34}, + {0x8d52,0x90}, + {0x8d53,0x0e}, + {0x8d54,0x6a}, + {0x8d55,0x12}, + {0x8d56,0x0f}, + {0x8d57,0xa6}, + {0x8d58,0x8f}, + {0x8d59,0x37}, + {0x8d5a,0x8e}, + {0x8d5b,0x36}, + {0x8d5c,0x8d}, + {0x8d5d,0x35}, + {0x8d5e,0x8c}, + {0x8d5f,0x34}, + {0x8d60,0x90}, + {0x8d61,0x0e}, + {0x8d62,0x72}, + {0x8d63,0x12}, + {0x8d64,0x06}, + {0x8d65,0xdd}, + {0x8d66,0xef}, + {0x8d67,0x45}, + {0x8d68,0x37}, + {0x8d69,0xf5}, + {0x8d6a,0x37}, + {0x8d6b,0xee}, + {0x8d6c,0x45}, + {0x8d6d,0x36}, + {0x8d6e,0xf5}, + {0x8d6f,0x36}, + {0x8d70,0xed}, + {0x8d71,0x45}, + {0x8d72,0x35}, + {0x8d73,0xf5}, + {0x8d74,0x35}, + {0x8d75,0xec}, + {0x8d76,0x45}, + {0x8d77,0x34}, + {0x8d78,0xf5}, + {0x8d79,0x34}, + {0x8d7a,0xe4}, + {0x8d7b,0xf5}, + {0x8d7c,0x22}, + {0x8d7d,0xf5}, + {0x8d7e,0x23}, + {0x8d7f,0x85}, + {0x8d80,0x37}, + {0x8d81,0x31}, + {0x8d82,0x85}, + {0x8d83,0x36}, + {0x8d84,0x30}, + {0x8d85,0x85}, + {0x8d86,0x35}, + {0x8d87,0x2f}, + {0x8d88,0x85}, + {0x8d89,0x34}, + {0x8d8a,0x2e}, + {0x8d8b,0x12}, + {0x8d8c,0x0f}, + {0x8d8d,0x63}, + {0x8d8e,0xe4}, + {0x8d8f,0xf5}, + {0x8d90,0x22}, + {0x8d91,0xf5}, + {0x8d92,0x23}, + {0x8d93,0x90}, + {0x8d94,0x0e}, + {0x8d95,0x72}, + {0x8d96,0x12}, + {0x8d97,0x0f}, + {0x8d98,0x9a}, + {0x8d99,0x12}, + {0x8d9a,0x0f}, + {0x8d9b,0x63}, + {0x8d9c,0xe4}, + {0x8d9d,0xf5}, + {0x8d9e,0x22}, + {0x8d9f,0xf5}, + {0x8da0,0x23}, + {0x8da1,0x90}, + {0x8da2,0x0e}, + {0x8da3,0x6e}, + {0x8da4,0x12}, + {0x8da5,0x0f}, + {0x8da6,0x9a}, + {0x8da7,0x02}, + {0x8da8,0x0f}, + {0x8da9,0x63}, + {0x8daa,0xae}, + {0x8dab,0x35}, + {0x8dac,0xaf}, + {0x8dad,0x36}, + {0x8dae,0xe4}, + {0x8daf,0xfd}, + {0x8db0,0xed}, + {0x8db1,0xc3}, + {0x8db2,0x95}, + {0x8db3,0x37}, + {0x8db4,0x50}, + {0x8db5,0x33}, + {0x8db6,0x12}, + {0x8db7,0x0f}, + {0x8db8,0xec}, + {0x8db9,0xe4}, + {0x8dba,0x93}, + {0x8dbb,0xf5}, + {0x8dbc,0x38}, + {0x8dbd,0x74}, + {0x8dbe,0x01}, + {0x8dbf,0x93}, + {0x8dc0,0xf5}, + {0x8dc1,0x39}, + {0x8dc2,0x45}, + {0x8dc3,0x38}, + {0x8dc4,0x60}, + {0x8dc5,0x23}, + {0x8dc6,0x85}, + {0x8dc7,0x39}, + {0x8dc8,0x82}, + {0x8dc9,0x85}, + {0x8dca,0x38}, + {0x8dcb,0x83}, + {0x8dcc,0xe0}, + {0x8dcd,0xfc}, + {0x8dce,0x12}, + {0x8dcf,0x0f}, + {0x8dd0,0xec}, + {0x8dd1,0x74}, + {0x8dd2,0x03}, + {0x8dd3,0x93}, + {0x8dd4,0x52}, + {0x8dd5,0x04}, + {0x8dd6,0x12}, + {0x8dd7,0x0f}, + {0x8dd8,0xec}, + {0x8dd9,0x74}, + {0x8dda,0x02}, + {0x8ddb,0x93}, + {0x8ddc,0x42}, + {0x8ddd,0x04}, + {0x8dde,0x85}, + {0x8ddf,0x39}, + {0x8de0,0x82}, + {0x8de1,0x85}, + {0x8de2,0x38}, + {0x8de3,0x83}, + {0x8de4,0xec}, + {0x8de5,0xf0}, + {0x8de6,0x0d}, + {0x8de7,0x80}, + {0x8de8,0xc7}, + {0x8de9,0x22}, + {0x8dea,0xc0}, + {0x8deb,0xe0}, + {0x8dec,0xc0}, + {0x8ded,0x83}, + {0x8dee,0xc0}, + {0x8def,0x82}, + {0x8df0,0x90}, + {0x8df1,0x3f}, + {0x8df2,0x0d}, + {0x8df3,0xe0}, + {0x8df4,0xf5}, + {0x8df5,0x33}, + {0x8df6,0xe5}, + {0x8df7,0x33}, + {0x8df8,0xf0}, + {0x8df9,0xd0}, + {0x8dfa,0x82}, + {0x8dfb,0xd0}, + {0x8dfc,0x83}, + {0x8dfd,0xd0}, + {0x8dfe,0xe0}, + {0x8dff,0x32}, + {0x8e00,0x12}, + {0x8e01,0x04}, + {0x8e02,0x13}, + {0x8e03,0x10}, + {0x8e04,0x01}, + {0x8e05,0x03}, + {0x8e06,0x4f}, + {0x8e07,0x56}, + {0x8e08,0x54}, + {0x8e09,0x20}, + {0x8e0a,0x20}, + {0x8e0b,0x20}, + {0x8e0c,0x20}, + {0x8e0d,0x20}, + {0x8e0e,0x13}, + {0x8e0f,0x01}, + {0x8e10,0x10}, + {0x8e11,0x01}, + {0x8e12,0x56}, + {0x8e13,0x40}, + {0x8e14,0x1a}, + {0x8e15,0x30}, + {0x8e16,0x29}, + {0x8e17,0x7e}, + {0x8e18,0x00}, + {0x8e19,0x30}, + {0x8e1a,0x04}, + {0x8e1b,0x20}, + {0x8e1c,0xdf}, + {0x8e1d,0x30}, + {0x8e1e,0x05}, + {0x8e1f,0x40}, + {0x8e20,0xbf}, + {0x8e21,0x50}, + {0x8e22,0x03}, + {0x8e23,0x00}, + {0x8e24,0xfd}, + {0x8e25,0x50}, + {0x8e26,0x27}, + {0x8e27,0x01}, + {0x8e28,0xfe}, + {0x8e29,0x60}, + {0x8e2a,0x00}, + {0x8e2b,0x11}, + {0x8e2c,0x00}, + {0x8e2d,0x3f}, + {0x8e2e,0x05}, + {0x8e2f,0x30}, + {0x8e30,0x00}, + {0x8e31,0x3f}, + {0x8e32,0x06}, + {0x8e33,0x22}, + {0x8e34,0x00}, + {0x8e35,0x3f}, + {0x8e36,0x01}, + {0x8e37,0x2a}, + {0x8e38,0x00}, + {0x8e39,0x3f}, + {0x8e3a,0x02}, + {0x8e3b,0x00}, + {0x8e3c,0x00}, + {0x8e3d,0x36}, + {0x8e3e,0x06}, + {0x8e3f,0x07}, + {0x8e40,0x00}, + {0x8e41,0x3f}, + {0x8e42,0x0b}, + {0x8e43,0x0f}, + {0x8e44,0xf0}, + {0x8e45,0x00}, + {0x8e46,0x00}, + {0x8e47,0x00}, + {0x8e48,0x00}, + {0x8e49,0x30}, + {0x8e4a,0x01}, + {0x8e4b,0x40}, + {0x8e4c,0xbf}, + {0x8e4d,0x30}, + {0x8e4e,0x01}, + {0x8e4f,0x00}, + {0x8e50,0xbf}, + {0x8e51,0x30}, + {0x8e52,0x29}, + {0x8e53,0x70}, + {0x8e54,0x00}, + {0x8e55,0x3a}, + {0x8e56,0x00}, + {0x8e57,0x00}, + {0x8e58,0xff}, + {0x8e59,0x3a}, + {0x8e5a,0x00}, + {0x8e5b,0x00}, + {0x8e5c,0xff}, + {0x8e5d,0x36}, + {0x8e5e,0x03}, + {0x8e5f,0x36}, + {0x8e60,0x02}, + {0x8e61,0x41}, + {0x8e62,0x44}, + {0x8e63,0x58}, + {0x8e64,0x20}, + {0x8e65,0x18}, + {0x8e66,0x10}, + {0x8e67,0x0a}, + {0x8e68,0x04}, + {0x8e69,0x04}, + {0x8e6a,0x00}, + {0x8e6b,0x03}, + {0x8e6c,0xff}, + {0x8e6d,0x64}, + {0x8e6e,0x00}, + {0x8e6f,0x00}, + {0x8e70,0x80}, + {0x8e71,0x00}, + {0x8e72,0x00}, + {0x8e73,0x00}, + {0x8e74,0x00}, + {0x8e75,0x00}, + {0x8e76,0x00}, + {0x8e77,0x02}, + {0x8e78,0x04}, + {0x8e79,0x06}, + {0x8e7a,0x06}, + {0x8e7b,0x00}, + {0x8e7c,0x02}, + {0x8e7d,0x33}, + {0x8e7e,0x01}, + {0x8e7f,0x00}, + {0x8e80,0x50}, + {0x8e81,0x3c}, + {0x8e82,0x28}, + {0x8e83,0x1e}, + {0x8e84,0x10}, + {0x8e85,0x10}, + {0x8e86,0x50}, + {0x8e87,0x2d}, + {0x8e88,0x28}, + {0x8e89,0x16}, + {0x8e8a,0x10}, + {0x8e8b,0x10}, + {0x8e8c,0x02}, + {0x8e8d,0x00}, + {0x8e8e,0x10}, + {0x8e8f,0x30}, + {0x8e90,0x0a}, + {0x8e91,0x04}, + {0x8e92,0x05}, + {0x8e93,0x08}, + {0x8e94,0x64}, + {0x8e95,0x06}, + {0x8e96,0x05}, + {0x8e97,0x01}, + {0x8e98,0x00}, + {0x8e99,0xa5}, + {0x8e9a,0x5a}, + {0x8e9b,0x00}, + {0x8e9c,0x78}, + {0x8e9d,0xbe}, + {0x8e9e,0xe6}, + {0x8e9f,0xd3}, + {0x8ea0,0x08}, + {0x8ea1,0xff}, + {0x8ea2,0xe6}, + {0x8ea3,0x64}, + {0x8ea4,0x80}, + {0x8ea5,0xf8}, + {0x8ea6,0xef}, + {0x8ea7,0x64}, + {0x8ea8,0x80}, + {0x8ea9,0x98}, + {0x8eaa,0x22}, + {0x8eab,0x78}, + {0x8eac,0xc0}, + {0x8ead,0xa6}, + {0x8eae,0x07}, + {0x8eaf,0x78}, + {0x8eb0,0xbd}, + {0x8eb1,0xd3}, + {0x8eb2,0xe6}, + {0x8eb3,0x64}, + {0x8eb4,0x80}, + {0x8eb5,0x94}, + {0x8eb6,0x80}, + {0x8eb7,0x22}, + {0x8eb8,0x93}, + {0x8eb9,0xff}, + {0x8eba,0x7e}, + {0x8ebb,0x00}, + {0x8ebc,0xe6}, + {0x8ebd,0xfc}, + {0x8ebe,0x08}, + {0x8ebf,0xe6}, + {0x8ec0,0xfd}, + {0x8ec1,0x12}, + {0x8ec2,0x05}, + {0x8ec3,0x22}, + {0x8ec4,0x78}, + {0x8ec5,0xc1}, + {0x8ec6,0xe6}, + {0x8ec7,0xfc}, + {0x8ec8,0x08}, + {0x8ec9,0xe6}, + {0x8eca,0xfd}, + {0x8ecb,0xd3}, + {0x8ecc,0xef}, + {0x8ecd,0x9d}, + {0x8ece,0xee}, + {0x8ecf,0x9c}, + {0x8ed0,0x22}, + {0x8ed1,0x78}, + {0x8ed2,0xbf}, + {0x8ed3,0xa6}, + {0x8ed4,0x07}, + {0x8ed5,0x08}, + {0x8ed6,0xd3}, + {0x8ed7,0xe6}, + {0x8ed8,0x64}, + {0x8ed9,0x80}, + {0x8eda,0x94}, + {0x8edb,0x80}, + {0x8edc,0x22}, + {0x8edd,0x78}, + {0x8ede,0xc0}, + {0x8edf,0xa6}, + {0x8ee0,0x07}, + {0x8ee1,0xc3}, + {0x8ee2,0x18}, + {0x8ee3,0xe6}, + {0x8ee4,0x64}, + {0x8ee5,0x80}, + {0x8ee6,0x94}, + {0x8ee7,0xb3}, + {0x8ee8,0x22}, + {0x8ee9,0x78}, + {0x8eea,0xbf}, + {0x8eeb,0xa6}, + {0x8eec,0x07}, + {0x8eed,0xc3}, + {0x8eee,0x08}, + {0x8eef,0xe6}, + {0x8ef0,0x64}, + {0x8ef1,0x80}, + {0x8ef2,0x94}, + {0x8ef3,0xb3}, + {0x8ef4,0x22}, + {0x8ef5,0x25}, + {0x8ef6,0xe0}, + {0x8ef7,0x24}, + {0x8ef8,0x0a}, + {0x8ef9,0xf8}, + {0x8efa,0xe6}, + {0x8efb,0xfe}, + {0x8efc,0x08}, + {0x8efd,0xe6}, + {0x8efe,0xff}, + {0x8eff,0x22}, + {0x8f00,0xe5}, + {0x8f01,0x40}, + {0x8f02,0x24}, + {0x8f03,0xf2}, + {0x8f04,0xf5}, + {0x8f05,0x37}, + {0x8f06,0xe5}, + {0x8f07,0x3f}, + {0x8f08,0x34}, + {0x8f09,0x43}, + {0x8f0a,0xf5}, + {0x8f0b,0x36}, + {0x8f0c,0xe5}, + {0x8f0d,0x3e}, + {0x8f0e,0x34}, + {0x8f0f,0xa2}, + {0x8f10,0xf5}, + {0x8f11,0x35}, + {0x8f12,0xe5}, + {0x8f13,0x3d}, + {0x8f14,0x34}, + {0x8f15,0x28}, + {0x8f16,0xf5}, + {0x8f17,0x34}, + {0x8f18,0xe5}, + {0x8f19,0x37}, + {0x8f1a,0xff}, + {0x8f1b,0xe4}, + {0x8f1c,0xfe}, + {0x8f1d,0xfd}, + {0x8f1e,0xfc}, + {0x8f1f,0x78}, + {0x8f20,0x18}, + {0x8f21,0x12}, + {0x8f22,0x06}, + {0x8f23,0xca}, + {0x8f24,0x8f}, + {0x8f25,0x40}, + {0x8f26,0x8e}, + {0x8f27,0x3f}, + {0x8f28,0x8d}, + {0x8f29,0x3e}, + {0x8f2a,0x8c}, + {0x8f2b,0x3d}, + {0x8f2c,0xe5}, + {0x8f2d,0x37}, + {0x8f2e,0x54}, + {0x8f2f,0xa0}, + {0x8f30,0xff}, + {0x8f31,0xe5}, + {0x8f32,0x36}, + {0x8f33,0xfe}, + {0x8f34,0xe4}, + {0x8f35,0xfd}, + {0x8f36,0xfc}, + {0x8f37,0x78}, + {0x8f38,0x07}, + {0x8f39,0x12}, + {0x8f3a,0x06}, + {0x8f3b,0xb7}, + {0x8f3c,0x78}, + {0x8f3d,0x10}, + {0x8f3e,0x12}, + {0x8f3f,0x0f}, + {0x8f40,0xac}, + {0x8f41,0xe4}, + {0x8f42,0xff}, + {0x8f43,0xfe}, + {0x8f44,0xe5}, + {0x8f45,0x35}, + {0x8f46,0xfd}, + {0x8f47,0xe4}, + {0x8f48,0xfc}, + {0x8f49,0x78}, + {0x8f4a,0x0e}, + {0x8f4b,0x12}, + {0x8f4c,0x06}, + {0x8f4d,0xb7}, + {0x8f4e,0x12}, + {0x8f4f,0x0f}, + {0x8f50,0xaf}, + {0x8f51,0xe4}, + {0x8f52,0xff}, + {0x8f53,0xfe}, + {0x8f54,0xfd}, + {0x8f55,0xe5}, + {0x8f56,0x34}, + {0x8f57,0xfc}, + {0x8f58,0x78}, + {0x8f59,0x18}, + {0x8f5a,0x12}, + {0x8f5b,0x06}, + {0x8f5c,0xb7}, + {0x8f5d,0x78}, + {0x8f5e,0x08}, + {0x8f5f,0x12}, + {0x8f60,0x0f}, + {0x8f61,0xac}, + {0x8f62,0x22}, + {0x8f63,0xa2}, + {0x8f64,0xaf}, + {0x8f65,0x92}, + {0x8f66,0x32}, + {0x8f67,0xc2}, + {0x8f68,0xaf}, + {0x8f69,0xe5}, + {0x8f6a,0x23}, + {0x8f6b,0x45}, + {0x8f6c,0x22}, + {0x8f6d,0x90}, + {0x8f6e,0x0e}, + {0x8f6f,0x5d}, + {0x8f70,0x60}, + {0x8f71,0x0e}, + {0x8f72,0x12}, + {0x8f73,0x0f}, + {0x8f74,0xc7}, + {0x8f75,0xe0}, + {0x8f76,0xf5}, + {0x8f77,0x2c}, + {0x8f78,0x12}, + {0x8f79,0x0f}, + {0x8f7a,0xc4}, + {0x8f7b,0xe0}, + {0x8f7c,0xf5}, + {0x8f7d,0x2d}, + {0x8f7e,0x80}, + {0x8f7f,0x0c}, + {0x8f80,0x12}, + {0x8f81,0x0f}, + {0x8f82,0xc7}, + {0x8f83,0xe5}, + {0x8f84,0x30}, + {0x8f85,0xf0}, + {0x8f86,0x12}, + {0x8f87,0x0f}, + {0x8f88,0xc4}, + {0x8f89,0xe5}, + {0x8f8a,0x31}, + {0x8f8b,0xf0}, + {0x8f8c,0xa2}, + {0x8f8d,0x32}, + {0x8f8e,0x92}, + {0x8f8f,0xaf}, + {0x8f90,0x22}, + {0x8f91,0x8f}, + {0x8f92,0x3b}, + {0x8f93,0x8e}, + {0x8f94,0x3a}, + {0x8f95,0x8d}, + {0x8f96,0x39}, + {0x8f97,0x8c}, + {0x8f98,0x38}, + {0x8f99,0x22}, + {0x8f9a,0x12}, + {0x8f9b,0x06}, + {0x8f9c,0xdd}, + {0x8f9d,0x8f}, + {0x8f9e,0x31}, + {0x8f9f,0x8e}, + {0x8fa0,0x30}, + {0x8fa1,0x8d}, + {0x8fa2,0x2f}, + {0x8fa3,0x8c}, + {0x8fa4,0x2e}, + {0x8fa5,0x22}, + {0x8fa6,0x93}, + {0x8fa7,0xf9}, + {0x8fa8,0xf8}, + {0x8fa9,0x02}, + {0x8faa,0x06}, + {0x8fab,0xca}, + {0x8fac,0x12}, + {0x8fad,0x06}, + {0x8fae,0xca}, + {0x8faf,0xe5}, + {0x8fb0,0x40}, + {0x8fb1,0x2f}, + {0x8fb2,0xf5}, + {0x8fb3,0x40}, + {0x8fb4,0xe5}, + {0x8fb5,0x3f}, + {0x8fb6,0x3e}, + {0x8fb7,0xf5}, + {0x8fb8,0x3f}, + {0x8fb9,0xe5}, + {0x8fba,0x3e}, + {0x8fbb,0x3d}, + {0x8fbc,0xf5}, + {0x8fbd,0x3e}, + {0x8fbe,0xe5}, + {0x8fbf,0x3d}, + {0x8fc0,0x3c}, + {0x8fc1,0xf5}, + {0x8fc2,0x3d}, + {0x8fc3,0x22}, + {0x8fc4,0x90}, + {0x8fc5,0x0e}, + {0x8fc6,0x5f}, + {0x8fc7,0xe4}, + {0x8fc8,0x93}, + {0x8fc9,0xfe}, + {0x8fca,0x74}, + {0x8fcb,0x01}, + {0x8fcc,0x93}, + {0x8fcd,0xf5}, + {0x8fce,0x82}, + {0x8fcf,0x8e}, + {0x8fd0,0x83}, + {0x8fd1,0x22}, + {0x8fd2,0xd2}, + {0x8fd3,0x01}, + {0x8fd4,0xc2}, + {0x8fd5,0x02}, + {0x8fd6,0xe4}, + {0x8fd7,0xf5}, + {0x8fd8,0x1f}, + {0x8fd9,0xf5}, + {0x8fda,0x1e}, + {0x8fdb,0xd2}, + {0x8fdc,0x35}, + {0x8fdd,0xd2}, + {0x8fde,0x33}, + {0x8fdf,0x22}, + {0x8fe0,0x78}, + {0x8fe1,0x7f}, + {0x8fe2,0xe4}, + {0x8fe3,0xf6}, + {0x8fe4,0xd8}, + {0x8fe5,0xfd}, + {0x8fe6,0x75}, + {0x8fe7,0x81}, + {0x8fe8,0xcd}, + {0x8fe9,0x02}, + {0x8fea,0x0c}, + {0x8feb,0xc4}, + {0x8fec,0x8f}, + {0x8fed,0x82}, + {0x8fee,0x8e}, + {0x8fef,0x83}, + {0x8ff0,0x75}, + {0x8ff1,0xf0}, + {0x8ff2,0x04}, + {0x8ff3,0xed}, + {0x8ff4,0x02}, + {0x8ff5,0x07}, + {0x8ff6,0x06}, + {0x3022,0x00}, + {0x3023,0x00}, + {0x3024,0x00}, + {0x3025,0x00}, + {0x3026,0x00}, + {0x3027,0x00}, + {0x3028,0x00}, + {0x3029,0x7F}, + {0x3000,0x00}, + 0xff, +}; diff --git a/CameraWebServer_PDM_Audio/app_httpd.cpp b/CameraWebServer_PDM_Audio/app_httpd.cpp index c10f0ea..f33808d 100644 --- a/CameraWebServer_PDM_Audio/app_httpd.cpp +++ b/CameraWebServer_PDM_Audio/app_httpd.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -26,6 +26,11 @@ #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +// 新增:用于对 WS socket 做 TCP 层调优(TCP_NODELAY / SO_SNDBUF / keepalive) +#include "lwip/sockets.h" +#include "lwip/tcp.h" +// 前向声明:定义在后面,但 ws_audio_handler / ws_audio_v2_handler 会先调用它 +static void ws_tune_socket(int fd); #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" @@ -69,6 +74,27 @@ bool isStreaming = false; #define AUDIO_GAIN 3 // Software gain (1=no gain, 2-4 suitable for PDM mic) #define AUDIO_DISCARD_FRAMES 5 // Discard first N frames after connect (flush stale DMA data) +// ============================================================ +// v5 buffered: timestamped ring buffer (PSRAM-backed) +// Producer (PDM capture) writes packets; consumer (WS sender) drains them. +// Decouples audio capture from WiFi send blocking (camera uploads). +// ============================================================ +#define AUDIO_PKT_SAMPLES 320 // 20ms @ 16kHz +#define AUDIO_PKT_BYTES (AUDIO_PKT_SAMPLES * 2) // 640 bytes PCM +#define AUDIO_RING_CAPACITY 400 // 160 * 20ms = 3.2 s buffer 160改成了400抗抖动,代价是PSRAM 多吃约 160 KB,8MB PSRAM 毫无压力。 +#define AUDIO_WIRE_HDR_BYTES 12 // seq(4) + ts_ms(4) + n_samples(2) + drops(2) +#define AUDIO_WIRE_PKT_BYTES (AUDIO_WIRE_HDR_BYTES + AUDIO_PKT_BYTES) + +#pragma pack(push, 1) +typedef struct { + uint32_t seq; // monotonic packet sequence number + uint32_t ts_ms; // ESP32 timestamp (esp_timer ms) of first sample + uint16_t n_samples; // number of PCM16 samples in this packet + uint16_t reserved; // pad / future use + int16_t pcm[AUDIO_PKT_SAMPLES]; // PCM16 little-endian data +} audio_pkt_t; +#pragma pack(pop) + // ============================================================ // Audio state (cross-task, volatile) // ============================================================ @@ -76,7 +102,19 @@ bool isStreaming = false; static volatile bool g_audio_streaming = false; // Whether audio streaming task is running static i2s_chan_handle_t g_pdm_rx_handle = NULL; // I2S PDM RX channel handle static volatile int g_ws_audio_fd = -1; // WS client socket fd -static volatile TaskHandle_t g_audio_task = NULL; // Audio streaming task handle +static volatile TaskHandle_t g_audio_task = NULL; // v1 single-task (legacy) handle + +// v5: split producer/consumer task handles +static volatile TaskHandle_t g_audio_capture_task_h = NULL; +static volatile TaskHandle_t g_audio_sender_task_h = NULL; + +// v5: ring buffer +static audio_pkt_t *g_audio_ring = NULL; +static volatile uint32_t g_ring_head = 0; // producer writes here (next write slot) +static volatile uint32_t g_ring_tail = 0; // consumer reads here (next read slot) +static volatile uint32_t g_ring_seq = 0; // monotonic seq counter +static volatile uint32_t g_ring_drops = 0; // total dropped-oldest count since init +static portMUX_TYPE g_ring_mux = portMUX_INITIALIZER_UNLOCKED; // External: camera init/deinit (defined in .ino) extern bool init_camera(); @@ -331,6 +369,252 @@ static void audio_stream_task(void *param) { vTaskDelete(NULL); } +// ============================================================ +// v5 BUFFERED: Ring buffer helpers +// ============================================================ + +static bool audio_ring_init() { + if (g_audio_ring) { + // already allocated — just reset pointers + taskENTER_CRITICAL(&g_ring_mux); + g_ring_head = g_ring_tail = g_ring_seq = g_ring_drops = 0; + taskEXIT_CRITICAL(&g_ring_mux); + return true; + } + size_t total = (size_t)AUDIO_RING_CAPACITY * sizeof(audio_pkt_t); + g_audio_ring = (audio_pkt_t *)heap_caps_malloc(total, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if (!g_audio_ring) { + Serial.printf("[RING] OOM: cannot alloc %u bytes in PSRAM (free PSRAM=%u)\n", + (unsigned)total, + (unsigned)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + return false; + } + memset(g_audio_ring, 0, total); + g_ring_head = g_ring_tail = g_ring_seq = g_ring_drops = 0; + Serial.printf("[RING] Alloc %u bytes PSRAM for %d packets (%.1fs buffer)\n", + (unsigned)total, AUDIO_RING_CAPACITY, + AUDIO_RING_CAPACITY * 20.0f / 1000.0f); + return true; +} + +static void audio_ring_deinit() { + if (g_audio_ring) { + heap_caps_free(g_audio_ring); + g_audio_ring = NULL; + } + g_ring_head = g_ring_tail = g_ring_seq = g_ring_drops = 0; +} + +// ============================================================ +// v5 BUFFERED: Audio capture task (PRODUCER) +// - Reads 20ms chunks from PDM +// - Applies DC-offset removal + software gain (same as legacy path) +// - Tags each packet with seq + ts_ms and writes to ring buffer +// - Drops OLDEST packet if ring full (consumer fell behind due to WiFi stall) +// ============================================================ +static void audio_capture_task(void *param) { + uint8_t *tmp = (uint8_t *)malloc(AUDIO_PKT_BYTES); + if (!tmp) { + Serial.printf("[CAP] OOM! Cannot allocate %d bytes\n", AUDIO_PKT_BYTES); + g_audio_capture_task_h = NULL; + vTaskDelete(NULL); + return; + } + + Serial.println("[CAP] Capture task started (ring-buffered)"); + int32_t dc_acc = 0; + uint32_t frame_count = 0; + uint32_t last_log_ms = millis(); + + while (g_audio_streaming && g_pdm_rx_handle != NULL) { + size_t bytes_read = 0; + esp_err_t err = i2s_channel_read(g_pdm_rx_handle, tmp, AUDIO_PKT_BYTES, + &bytes_read, 200); + if (err != ESP_OK) { + if (err == ESP_ERR_TIMEOUT) continue; + Serial.printf("[CAP] i2s_channel_read error: 0x%x\n", err); + break; + } + if (bytes_read != AUDIO_PKT_BYTES) continue; // partial reads skipped + + frame_count++; + if (frame_count <= AUDIO_DISCARD_FRAMES) continue; + + // DC offset removal (EMA) + software gain + clipping + { + int16_t *samples = (int16_t *)tmp; + int n = bytes_read / 2; + for (int i = 0; i < n; i++) { + dc_acc = dc_acc - (dc_acc >> 8) + (int32_t)samples[i]; + int32_t val = (int32_t)samples[i] - (dc_acc >> 8); + val *= AUDIO_GAIN; + if (val > 32767) val = 32767; + if (val < -32768) val = -32768; + samples[i] = (int16_t)val; + } + } + + uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000ULL); + + taskENTER_CRITICAL(&g_ring_mux); + uint32_t head = g_ring_head; + uint32_t next_head = (head + 1) % AUDIO_RING_CAPACITY; + if (next_head == g_ring_tail) { + // Ring full — drop oldest (advance tail) + g_ring_tail = (g_ring_tail + 1) % AUDIO_RING_CAPACITY; + g_ring_drops++; + } + audio_pkt_t *slot = &g_audio_ring[head]; + slot->seq = ++g_ring_seq; + slot->ts_ms = ts_ms; + slot->n_samples = AUDIO_PKT_SAMPLES; + slot->reserved = 0; + memcpy(slot->pcm, tmp, AUDIO_PKT_BYTES); + g_ring_head = next_head; + taskEXIT_CRITICAL(&g_ring_mux); + + uint32_t now_ms = millis(); + if (now_ms - last_log_ms >= 10000) { + uint32_t h, t, drops, seq; + taskENTER_CRITICAL(&g_ring_mux); + h = g_ring_head; t = g_ring_tail; drops = g_ring_drops; seq = g_ring_seq; + taskEXIT_CRITICAL(&g_ring_mux); + uint32_t pending = (h + AUDIO_RING_CAPACITY - t) % AUDIO_RING_CAPACITY; + Serial.printf("[CAP] seq=%u ring=%u/%d drops=%u heap=%u\n", + seq, pending, AUDIO_RING_CAPACITY, drops, + (unsigned)ESP.getFreeHeap()); + last_log_ms = now_ms; + } + } + + free(tmp); + Serial.println("[CAP] Capture task exit"); + g_audio_capture_task_h = NULL; + vTaskDelete(NULL); +} + +// ============================================================ +// v5 BUFFERED: Audio sender task (CONSUMER) +// - Peeks one packet from ring tail +// - Sends [header(12) | PCM16 data(640)] as a single WS BINARY frame +// - On send success: advances tail +// - On send error (typically WiFi congested while camera HTTP is uploading): +// retries same packet after a brief delay; does NOT advance tail. +// This is the core mechanism that gives "timestamp retransmit" semantics. +// - After persistent failure (~ N retries = WS dead), stops streaming. +// ============================================================ +static void audio_sender_task(void *param) { + Serial.println("[SND] Sender task started (Core 0)"); + uint32_t total_bytes = 0; + uint32_t total_packets = 0; + uint32_t send_errors = 0; + uint32_t start_ms = millis(); + uint32_t last_log_ms = start_ms; + + // Wire buffer is allocated once (stack too small for ~652 bytes); in DRAM to avoid PSRAM latency for TCP + uint8_t *wire = (uint8_t *)malloc(AUDIO_WIRE_PKT_BYTES); + if (!wire) { + Serial.printf("[SND] OOM wire buf %d\n", AUDIO_WIRE_PKT_BYTES); + g_audio_sender_task_h = NULL; + vTaskDelete(NULL); + return; + } + + while (g_audio_streaming && g_ws_audio_fd >= 0) { + // Peek from ring tail (copy to avoid race with producer drop-oldest) + audio_pkt_t pkt; + uint32_t read_pos = 0; + bool have_pkt = false; + + taskENTER_CRITICAL(&g_ring_mux); + if (g_ring_tail != g_ring_head) { + read_pos = g_ring_tail; + pkt = g_audio_ring[read_pos]; + have_pkt = true; + } + taskEXIT_CRITICAL(&g_ring_mux); + + if (!have_pkt) { + vTaskDelay(pdMS_TO_TICKS(5)); + continue; + } + + // Build wire packet: [seq(4) | ts_ms(4) | n_samples(2) | drops(2) | pcm(640)] + uint32_t seq_le = pkt.seq; + uint32_t ts_le = pkt.ts_ms; + uint16_t n_le = pkt.n_samples; + uint32_t drops_cur; + taskENTER_CRITICAL(&g_ring_mux); + drops_cur = g_ring_drops; + taskEXIT_CRITICAL(&g_ring_mux); + uint16_t drops_le = (drops_cur > 0xFFFFu) ? 0xFFFFu : (uint16_t)drops_cur; + + memcpy(wire + 0, &seq_le, 4); + memcpy(wire + 4, &ts_le, 4); + memcpy(wire + 8, &n_le, 2); + memcpy(wire + 10, &drops_le, 2); + memcpy(wire + 12, pkt.pcm, AUDIO_PKT_BYTES); + + httpd_ws_frame_t ws_frame; + memset(&ws_frame, 0, sizeof(ws_frame)); + ws_frame.type = HTTPD_WS_TYPE_BINARY; + ws_frame.payload = wire; + ws_frame.len = AUDIO_WIRE_PKT_BYTES; + ws_frame.final = true; + + esp_err_t err = httpd_ws_send_frame_async(camera_httpd, g_ws_audio_fd, &ws_frame); + if (err != ESP_OK) { + // Keep the packet in the ring; retry later. Camera HTTP upload typically + // blocks 100-500ms; we back off and try again — this is the whole point. + send_errors++; + if (send_errors >= 125) { // ~1 sec of continuous failures → give up 20260509,50改为125,2.5s + Serial.printf("[SND] WS send failed %u times (last 0x%x), closing\n", + send_errors, err); + break; + } + vTaskDelay(pdMS_TO_TICKS(20)); + continue; + } + + // Success: advance tail. Guard against producer having already advanced it + // past read_pos (ring-full drop case). Only advance if tail is still where + // we read from. + taskENTER_CRITICAL(&g_ring_mux); + if (g_ring_tail == read_pos) { + g_ring_tail = (read_pos + 1) % AUDIO_RING_CAPACITY; + } + taskEXIT_CRITICAL(&g_ring_mux); + + send_errors = 0; + total_bytes += AUDIO_WIRE_PKT_BYTES; + total_packets++; + + uint32_t now_ms = millis(); + if (now_ms - last_log_ms >= 5000) { + float elapsed_s = (now_ms - start_ms) / 1000.0f; + uint32_t h, t, drops; + taskENTER_CRITICAL(&g_ring_mux); + h = g_ring_head; t = g_ring_tail; drops = g_ring_drops; + taskEXIT_CRITICAL(&g_ring_mux); + uint32_t pending = (h + AUDIO_RING_CAPACITY - t) % AUDIO_RING_CAPACITY; + Serial.printf("[SND] sent=%u pkts, %.1f KB/s, ring_pending=%u/%d drops=%u\n", + total_packets, + elapsed_s > 0 ? (total_bytes / 1024.0f / elapsed_s) : 0, + pending, AUDIO_RING_CAPACITY, drops); + last_log_ms = now_ms; + } + } + + free(wire); + Serial.printf("[SND] Sender task exit: sent=%u pkts\n", total_packets); + + // Signal shutdown to capture task + g_audio_streaming = false; + g_ws_audio_fd = -1; + g_audio_sender_task_h = NULL; + vTaskDelete(NULL); +} + // ============================================================ // HTTP Handlers: Original camera handlers (with audio mode guard) // ============================================================ @@ -628,6 +912,13 @@ static esp_err_t cmd_handler(httpd_req_t *req) { } else if (!strcmp(variable, "ae_level")) { res = s->set_ae_level(s, val); } + else if (!strcmp(variable, "af")) { + // 单次自动对焦: 写 0x3022=0x03, 和原 loop 触发动作一致。 + // AF 走 SCCB, 与抓图共用总线, PC 端已限流 >1s, 勿高频调。 + res = s->set_reg(s, 0x3022, 0xff, 0x03); + +} + #if CONFIG_LED_ILLUMINATOR_ENABLED else if (!strcmp(variable, "led_intensity")) { led_duty = val; @@ -962,6 +1253,8 @@ static esp_err_t ws_audio_handler(httpd_req_t *req) { g_ws_audio_fd = httpd_req_to_sockfd(req); Serial.printf("[WS_AUDIO] Client connected, fd=%d\n", g_ws_audio_fd); + ws_tune_socket(g_ws_audio_fd); // ← 新增 + // Start audio streaming task (Core 1, priority 5) g_audio_streaming = true; BaseType_t ok = xTaskCreatePinnedToCore( @@ -1020,12 +1313,139 @@ static esp_err_t ws_audio_handler(httpd_req_t *req) { return ESP_OK; } +// ============================================================ +// WebSocket handler for /ws_audio_v2 (v5 BUFFERED) +// Wire format per BINARY frame: +// [seq:u32 LE][ts_ms:u32 LE][n_samples:u16 LE][drops:u16 LE][PCM16 x n_samples] +// Packet cadence: 1 frame per 20ms (50 Hz) +// ============================================================ +static esp_err_t ws_audio_v2_handler(httpd_req_t *req) { + if (req->method == HTTP_GET) { + if (g_ws_audio_fd >= 0 || g_audio_streaming) { + Serial.println("[WS_AUDIO_V2] Rejected: another audio client already connected"); + httpd_resp_set_status(req, "409 Conflict"); + httpd_resp_set_type(req, "text/plain"); + return httpd_resp_send(req, "Another audio client already connected", HTTPD_RESP_USE_STRLEN); + } + + if (!audio_ring_init()) { + Serial.println("[WS_AUDIO_V2] Ring buffer init failed"); + httpd_resp_set_status(req, "500 Internal Server Error"); + return httpd_resp_send(req, "Ring buffer alloc failed", HTTPD_RESP_USE_STRLEN); + } + + g_ws_audio_fd = httpd_req_to_sockfd(req); + g_audio_streaming = true; + Serial.printf("[WS_AUDIO_V2] Client connected, fd=%d\n", g_ws_audio_fd); + + ws_tune_socket(g_ws_audio_fd); // ← 新增:TCP_NODELAY / SNDBUF / KEEPALIVE + + // Producer on Core 1 (near PDM) + BaseType_t ok1 = xTaskCreatePinnedToCore( + audio_capture_task, "aud_cap", 4096, NULL, 5, + (TaskHandle_t *)&g_audio_capture_task_h, 1); + + if (ok1 != pdPASS) { + Serial.printf("[WS_AUDIO_V2] Capture task create failed err=%d heap=%u\n", + ok1, (unsigned)ESP.getFreeHeap()); + g_audio_streaming = false; + g_ws_audio_fd = -1; + audio_ring_deinit(); + return ESP_FAIL; + } + + + + + + // Consumer on Core 0 (near WiFi stack → WS send blocks don't stall PDM) + BaseType_t ok2 = xTaskCreatePinnedToCore( + audio_sender_task, "aud_snd", 6144, NULL, 6, //优先级4改成了6 + (TaskHandle_t *)&g_audio_sender_task_h, 0); + + if (ok2 != pdPASS) { + Serial.printf("[WS_AUDIO_V2] Sender task create failed err=%d heap=%u\n", + ok2, (unsigned)ESP.getFreeHeap()); + g_audio_streaming = false; + g_ws_audio_fd = -1; + // capture task will self-exit on flag + return ESP_FAIL; + } + + Serial.println("[WS_AUDIO_V2] Capture+Sender tasks launched (v5 buffered)"); + return ESP_OK; + } + + // Non-handshake: handle incoming frames (expect only CLOSE) + httpd_ws_frame_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.type = HTTPD_WS_TYPE_BINARY; + + esp_err_t ret = httpd_ws_recv_frame(req, &pkt, 0); + if (ret != ESP_OK) { + Serial.printf("[WS_AUDIO_V2] recv_frame error: 0x%x, client disconnected\n", ret); + g_audio_streaming = false; + g_ws_audio_fd = -1; + return ret; + } + + if (pkt.type == HTTPD_WS_TYPE_CLOSE) { + Serial.println("[WS_AUDIO_V2] Client sent CLOSE frame"); + g_audio_streaming = false; + g_ws_audio_fd = -1; + } + + if (pkt.len > 0) { + uint8_t *temp = (uint8_t *)malloc(pkt.len); + if (temp) { + pkt.payload = temp; + httpd_ws_recv_frame(req, &pkt, pkt.len); + free(temp); + } + } + return ESP_OK; +} + + +// ============================================================ + // WS socket 调优:降低小包延迟、加大在途窗口、启用 keepalive + // 对 WAIC 这种高抖动 WiFi 环境尤其重要。 + // ============================================================ + static void ws_tune_socket(int fd) { + if (fd < 0) return; + + int one = 1; + // 关闭 Nagle:音频 652B 小包不再等合并,直接发 + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); + + // 加大发送缓冲,允许更多在途数据(默认一般 5744B) + int sndbuf = 32 * 1024; + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); + + // TCP keepalive:5s 无流量开始探测,每 2s 一次,3 次失败判死(≈11s) + int ka = 1, idle = 5, intvl = 2, cnt = 3; + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)); + setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)); + setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)); + setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)); + + Serial.printf("[WS] socket tuned: fd=%d NODELAY=1 SNDBUF=%d KA=%d/%d/%d\n", + fd, sndbuf, idle, intvl, cnt); + } + + + // ============================================================ // Server startup // ============================================================ void startCameraServer() { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - config.max_uri_handlers = 20; // Increased to accommodate new endpoints + config.max_uri_handlers = 20; // Increased to accommodate new endpoints + config.task_priority = 6; // 默认 5,略高于 sender,避免互相阻塞 + config.stack_size = 8192; // 默认 4096,防 WS 处理爆栈 + config.lru_purge_enable = true; // 连接过多时自动淘汰最老 + config.recv_wait_timeout = 10; // 秒 + config.send_wait_timeout = 10; // 秒 // ---- URI definitions ---- @@ -1171,6 +1591,17 @@ void startCameraServer() { .supported_subprotocol = NULL }; + // v5 BUFFERED: ring-buffered + timestamped audio (for duplex_v5 bridge) + httpd_uri_t ws_audio_v2_uri = { + .uri = "/ws_audio_v2", + .method = HTTP_GET, + .handler = ws_audio_v2_handler, + .user_ctx = NULL, + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL + }; + // ---- Start server ---- ra_filter_init(&ra_filter, 20); @@ -1193,8 +1624,9 @@ void startCameraServer() { httpd_register_uri_handler(camera_httpd, &audio_begin_uri); httpd_register_uri_handler(camera_httpd, &audio_end_uri); httpd_register_uri_handler(camera_httpd, &ws_audio_uri); + httpd_register_uri_handler(camera_httpd, &ws_audio_v2_uri); - Serial.println("[HTTP] Registered: / /capture /bmp /control /status + /audio_begin /audio_end /ws_audio"); + Serial.println("[HTTP] Registered: / /capture /bmp /control /status + /audio_begin /audio_end /ws_audio /ws_audio_v2"); } config.server_port += 1; From 5885f4716e198978b808fe02f9cb5bce8108c095 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Tue, 8 Sep 2026 00:18:35 +0800 Subject: [PATCH 5/6] fix: reject hint no longer deadlocks; panel cleans up stale processes esp32_runtime: - The ownership token for the reject hint was read *before* sending funnel.stop. Since that stop is applied asynchronously (8021 -> rokid -> gate.stop), the hint's own stop bumped the counter, so the guard always matched and resume was never sent. The model stayed paused indefinitely and no speech got through. Read the counter after the propagation delay instead. - A user STOP during a hint is respected, but no longer permanent: if no further stop arrives within the timeout, the conversation resumes on its own. - Import only DocImgOrientationClassification, never import paddleocr or import paddle. The package import pulls in paddlex -> modelscope -> torch, which fails on environments where torch's shm.dll won't load, and the orientation check silently degrades to the early heuristic. panel: - Stop only waited on the gateway port; llama/worker/harness/web UI could survive and keep their ports. A stale gateway session then left every new session stuck at 'queue position=1' with the model never responding, while the funnel kept sending frames and the chain looked healthy. Now every known port is verified and force-freed. - Stop covered only the current chain's stop_order, missing processes from a previously selected chain. - Cleanup on exit was unreachable if webview raised; now registered via atexit, signal handlers, and try/finally. - Sweep stale port owners before starting, so a previous unclean exit recovers without a reboot. --- .../phase_b/esp32_runtime.py | 39 +++++- runtime/openglass_omni/panel.py | 123 ++++++++++++++++-- 2 files changed, 152 insertions(+), 10 deletions(-) diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py index 285eec2..3105be2 100644 --- a/extensions/assistive_harness/phase_b/esp32_runtime.py +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -1044,6 +1044,32 @@ async def _do_reject_interrupt(reason): finally: _hint_playing = False + _USER_STOP_AUTO_RESUME_S = 20.0 # 用户 STOP 后多久自动恢复对话 + + async def _auto_resume_later(cnt_at_stop): + """用户在提示音期间按了 STOP —— 尊重它,但别永久锁死。 + + 等一段时间后,如果 stop_count 没再变(说明用户没有反复要求 + 停止),就自动 resume,让系统回到可对话状态。 + 期间若又有新的 stop,放弃这次兜底(由那次的兜底接手)。 + """ + try: + await asyncio.sleep(_USER_STOP_AUTO_RESUME_S) + except asyncio.CancelledError: + return + _g = getattr(manager, "gate", None) + now = getattr(_g, "stop_count", None) if _g else None + if now is not None and now != cnt_at_stop: + LOG.debug("[强制措施] 自动恢复取消:期间又有新的 STOP") + return + try: + await harness.send({"type": "funnel.resume", + "reason": "user_stop_timeout"}) + LOG.info("[强制措施] 用户 STOP 已过 %.0fs,自动恢复对话", + _USER_STOP_AUTO_RESUME_S) + except Exception as e: + LOG.warning("[强制措施] 自动恢复失败: %s", e) + async def _do_reject_interrupt_inner(reason): wav_pcm = _load_reject_wav(reject_wav_dir, reason) if wav_pcm is None: @@ -1057,13 +1083,19 @@ async def _do_reject_interrupt_inner(reason): # 就把用户的停止状态覆盖掉了。 # (播报改成后台任务之后,这个并发窗口更大了。) _gate = getattr(manager, "gate", None) - _owned = getattr(_gate, "stop_count", None) if _gate else None try: await harness.send({"type": "funnel.stop", "reason": reason}) LOG.info("[强制措施] funnel.stop 已发 (%s)", reason) except Exception as e: LOG.warning("[强制措施] funnel.stop 失败: %s", e) await asyncio.sleep(0.35) # 等 STOP 经 8021→rokid→block_and_flush + # ★ 必须在上面这个 sleep **之后**读 stop_count 作为所有权凭据。 + # funnel.stop 是异步生效的(8021→rokid→gate.stop()), + # 在发送**之前**读的话,自己这一次 stop 也会把计数器 +1, + # 于是播完时 _now != _owned 恒成立 —— resume 一次都发不出去, + # 模型永远停着,说什么都进不去(实测:开局第一次 reject 就锁死, + # 只能靠 harness 那条腿说"恢复对话"才能救回来)。 + _owned = getattr(_gate, "stop_count", None) if _gate else None try: await speaker.resume() await speaker.enqueue(wav_pcm, generation=0) @@ -1078,6 +1110,11 @@ async def _do_reject_interrupt_inner(reason): # 有新的 stop 进来(用户按的),此时保持停止状态不动。 _now_cnt = getattr(_gate, "stop_count", None) if _gate else None if _owned is not None and _now_cnt is not None and _now_cnt != _owned: + # 用户的 STOP 优先,但**不能永远停着** —— 用户按"停一下" + # 是想让当前这句别说了,不是想让系统从此哑掉。 + # 挂一个兜底:过 _USER_STOP_AUTO_RESUME_S 之后,若期间 + # 没有再新增 stop,就自动恢复对话。 + asyncio.create_task(_auto_resume_later(_now_cnt)) LOG.info("[强制措施] 播报期间收到新的 STOP" "(stop_count %s→%s),保留用户的停止状态,不 resume", _owned, _now_cnt) diff --git a/runtime/openglass_omni/panel.py b/runtime/openglass_omni/panel.py index e16bcb6..0c94c3b 100644 --- a/runtime/openglass_omni/panel.py +++ b/runtime/openglass_omni/panel.py @@ -25,6 +25,7 @@ import json import os +import signal import socket import subprocess import sys @@ -1037,6 +1038,32 @@ def _force_kill(self, proc): except Exception: pass + def _llama_port(self): + """从 llama_health_url 解析端口,别硬编码 —— 用户改了配置这里要跟着变。""" + try: + from urllib.parse import urlparse + u = urlparse(self.cfg.get("llama_health_url", "")) + return u.port or 22500 + except Exception: + return 22500 + + def _all_ports(self): + """所有需要确认释放的端口。清理时逐个检查,别只盯 gateway。""" + c = self.cfg + out = [("gateway", c.get("gateway_port", 8006)), + ("worker", c.get("worker_ready_port", 22400)), + ("llama", self._llama_port()), + ("harness", 8021)] + # 第一视角:demo / demo_funnel / rokid 各自可能开着 + for _p in (8080, 18080): + out.append(("demo", _p)) + seen, uniq = set(), [] + for label, port in out: + if port and port not in seen: + seen.add(port) + uniq.append((label, int(port))) + return uniq + def _kill_by_port(self, port): if not self.cfg["is_windows"]: return @@ -1235,9 +1262,39 @@ def _tail_fingerprint(self): return (self.current_chain, c.get("funnel", 0), self.current_scene, self.current_device, self.current_prompt) + def _sweep_stale(self): + """启动前扫一遍:上次没清干净的残留进程,现在杀掉。 + + 为什么需要:panel 异常退出、或用户直接关窗口时,子进程可能还活着。 + 它们占着端口,而且 gateway 里的旧 session 还挂着 —— 下次启动的会话 + 就永远卡在 `[GW] queue position=1 eta=0.0`,模型一句话都不回, + 表面上却是"链路正常、漏斗照常送图",极难看出问题在哪。 + (实测踩过,只能重启电脑。) + """ + stale = [] + for label, port in self._all_ports(): + if self.procs.get(label) is not None and self._alive(label): + continue # 本次自己起的,不动 + if self._port_open(port): + stale.append((label, port)) + if not stale: + return + self._log("gateway", "启动前清理:发现上次残留的端口占用 " + + ", ".join(f"{l}:{p}" for l, p in stale)) + for label, port in stale: + self._kill_by_port(port) + time.sleep(1.0) + left = [f"{l}:{p}" for l, p in stale if self._port_open(p)] + if left: + self._log("gateway", "!! 仍被占用: " + ", ".join(left) + + "(可能是别的程序在用这些端口)") + else: + self._log("gateway", "启动前清理完成,端口已释放") + def _do_start_all(self): # ②③④ 的两个前置检查:extensions 复制了没、档位④的 wav 有没有。 # 提前拦住比跑起来才发现好 —— 后者时 duplex 已在跑,没法当场补。 + self._sweep_stale() if (not self._check_extensions() or not self._check_deps() or not self._check_reject_wav()): return @@ -1299,6 +1356,13 @@ def _stop_all_sync(self): for name in self.chain()["stop_order"]: self._kill(name, graceful=(name in tails)) time.sleep(0.3) + # 当前链路的 stop_order 只覆盖这条链;切过链路的话别的进程会漏掉。 + # 兜底:把 procs 里所有还活着的都停掉。 + for name in self.cfg["procs"]: + if self._alive(name): + self._log(name, "不在当前链路但仍在运行,一并停止") + self._kill(name, graceful=(name in tails)) + time.sleep(0.2) for name in self.cfg["procs"]: proc = self.procs.get(name) if proc is not None and proc.poll() is not None: @@ -1306,13 +1370,33 @@ def _stop_all_sync(self): if proc is not None: self._log(name, "!! 仍在运行,强杀兜底") self._force_kill(proc) - if self._wait_port(self.cfg["gateway_port"], up=False, timeout=8): - self._log("gateway", f"端口 {self.cfg['gateway_port']} 已释放,全部已停止") + # ★ 逐个清理所有已知端口,不只 gateway。 + # 以前只等 gateway 释放,llama/worker/harness/web_ui 的残留进程会一直 + # 占着端口;下次启动时 gateway 那边旧 session 还挂着,新会话就永远 + # 卡在 `[GW] queue position=1 eta=0.0` —— 表现是"链路看着活的、 + # 漏斗照常送图,但模型一句话都不回",只能重启电脑。 + for _label, _port in self._all_ports(): + if self._wait_port(_port, up=False, timeout=4): + continue + self._log(_label, f"!! 端口 {_port} 仍被占用,按端口强杀") + self._kill_by_port(_port) + # 再确认一遍;还占着就再杀一次(有些进程要两拍才退) + _still = [(l, p) for l, p in self._all_ports() + if not self._wait_port(p, up=False, timeout=2)] + for _label, _port in _still: + self._log(_label, f"!! 端口 {_port} 二次强杀") + self._kill_by_port(_port) + time.sleep(0.5) + _left = [f"{l}:{p}" for l, p in self._all_ports() + if not self._wait_port(p, up=False, timeout=1)] + if _left: + self._log("gateway", "!! 以下端口仍被占用,可能需要手动处理: " + + ", ".join(_left)) else: - self._log("gateway", f"!! {self.cfg['gateway_port']} 仍被占用,尝试按端口强杀") - self._kill_by_port(self.cfg["gateway_port"]) + self._log("gateway", "所有端口已释放,全部已停止") for name in self.cfg["procs"]: self.status[name] = "stopped" + self._forget_tail_fp(name) def stop_all(self): """全部停止:等同三个 Ctrl+C。先发急停打断任何正在进行的启动,再彻底杀干净。""" @@ -1495,11 +1579,32 @@ def main(): height=780, min_size=(900, 640), ) - webview.start() - # 关窗时兜底:确保所有子进程被清掉 - mgr.shutdown() - #mgr.stop_all() - #time.sleep(1) + # 兜底 ①:进程正常退出时(含异常传播)一定会跑 + import atexit + atexit.register(mgr.shutdown) + + # 兜底 ②:Ctrl+C / 控制台关闭 + def _sig_cleanup(signum, frame): + try: + mgr.shutdown() + finally: + os._exit(0) + for _s in ("SIGINT", "SIGTERM", "SIGBREAK"): + _sv = getattr(signal, _s, None) + if _sv is not None: + try: + signal.signal(_sv, _sig_cleanup) + except Exception: + pass + + try: + webview.start() + finally: + # 兜底 ③:webview 抛异常时也要清 + # 以前只在 start() 之后直接调 shutdown(),异常路径下压根不执行 —— + # 于是 llama/worker/gateway/harness 全留着,端口占着、 + # gateway 里旧 session 挂着,下次启动永远卡在 queue position=1。 + mgr.shutdown() if __name__ == "__main__": From 0307edbfcb40149cb291929542dda91194d80437 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Tue, 8 Sep 2026 11:04:55 +0800 Subject: [PATCH 6/6] fix: reject and resume delay --- .../phase_b/esp32_runtime.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py index 3105be2..a19a673 100644 --- a/extensions/assistive_harness/phase_b/esp32_runtime.py +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -1044,7 +1044,7 @@ async def _do_reject_interrupt(reason): finally: _hint_playing = False - _USER_STOP_AUTO_RESUME_S = 20.0 # 用户 STOP 后多久自动恢复对话 + _USER_STOP_AUTO_RESUME_S = 1.5 # 用户 STOP 后多久自动恢复对话 async def _auto_resume_later(cnt_at_stop): """用户在提示音期间按了 STOP —— 尊重它,但别永久锁死。 @@ -1525,7 +1525,7 @@ async def _wrapped_handle_result(session, result): self.manager.handle_result = _wrapped_handle_result async def _gate_open_when_ready(self, ready_evt: asyncio.Event) -> None: - """等 gateway 就绪后放行回放任务。""" + """等 gateway 就绪后放行音视频任务(live 和 rerun 共用)。""" try: await self._wait_gateway_ready() finally: @@ -1533,7 +1533,7 @@ async def _gate_open_when_ready(self, ready_evt: asyncio.Event) -> None: # 会把排队那几十秒也算进去,两个 arm 无法对齐。 if self.live_rec is not None: self.live_rec.start() - LOG.info("[LIVE] rerun 录制已开(就绪后启动,结束自动出 mp4)") + LOG.info("[LIVE] 录制已开(gateway 就绪后启动,结束自动出 mp4)") # 统一回放零点:音频按 40ms 绝对时钟推、图按 frames.jsonl 的 t 等待, # 两者必须用同一个 t0,否则各自以"自己被调度到的那一刻"为零点, # 起跑差多少全看事件循环,音图就对不齐。 @@ -1712,9 +1712,17 @@ async def start(self) -> None: LOG.info("[ESP32] 设分辨率 1280×720(UXGA档): %s", "成功" if ok else "失败(检查ESP32 /control)") await asyncio.sleep(0.3) # 切分辨率后固件重配,稍等 - if self.live_rec is not None: - self.live_rec.start() - LOG.info("[LIVE] -o record started") + # 就绪门:等 duplex session 真正 running 再开始推音视频。 + # 两个 rerun 分支早就有这个(见 _gate_open_when_ready),live 分支漏了。 + # panel 判 gateway 就绪的依据只是"端口开了",而 gateway 绑上端口之后 + # 还要十几秒才能接会话(日志里 gateway=preparing 持续到 10:43:49)。 + # 这期间 image_loop 照常抓图、audio_reader 照常推音频: + # · 音频推给一个还不存在的 session → queue=96 塞满、drops 一路涨到 552 + # · 队列操作和重试占住事件循环 → capture 的 1s 超时到点 → 连续掉图 + # · 掉够次数就判 no_frames → 停模型播"没有拿到画面" + # 现象就是"开头一段时间画面丢失 + 模型不回话",gateway 一 running 就自愈。 + _ready = asyncio.Event() + asyncio.create_task(self._gate_open_when_ready(_ready)) self._tasks = [ # ── 继承自 rokid 的三个骨架 task ── asyncio.create_task(self.harness.run()), @@ -1728,6 +1736,7 @@ async def start(self) -> None: self.config.input_gain, self._stop_evt, probe=self._probe, live_rec=self.live_rec, + ready_evt=_ready, )), asyncio.create_task(esp32_image_loop( self._tcp_img, self.latest_frame, self.harness, self.stats, @@ -1742,6 +1751,7 @@ async def start(self) -> None: live_rec=self.live_rec, web_ui=self._web_ui, no_reject=self._no_reject, + ready_evt=_ready, )), ]

=XkKoj7ze3z_4akQScvSj9jWj@1 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≶Q6aK83u zvyfS|omdw~=?+}YA2yG)t5aaN%`#MSC>1cCX$|N;%sc(6S&|=bb=I~}1tI%z&U(w4W=m}jbB1YX9M{V-e{wHl!?Xz^&km86 zSXsnm>Wehe!U@f)pwy#(3Xj#j>S`{9@@jeQ%Hm`5y_|#jB;*61!pH3->!?XYGCPkP zrcWT(l2LPrb(T_yTA1)wpknqdodtDy7O}}FjrmR%qoP%UzD#_DYWf_1k^Cu-qRRbyiWP`vbRuB=|kQ0NF-U0Vf=A< zx77*SCN70`8ePm^sr>9wD3Ci-#mTxz!2V2UB~HT!vJf3HL#a#t&Q7sSy|)=n1FdDdGcfnxcy<~l7E9ioluK)tQ7mdaGG zTl2Vd>%IOjbq_#!mr0^(Xl>n+#;i;JNp3J5#!hapHQB6ARI?kAovgFQ40L__*denwG0z@u7Pj(H zJLzV|7ri=Li4Zj>5n#&_2}&AOpDhC~T23T)bk|91CY-j1^>V}?v_!6lPqQ)IimZ>U z`3vMW>nM`y&k%n?q0z=HPj{pQV;S)eGt#cD9in{nU36Ge=nz%QdZGs?nI5lRA`a0F z$UX*7HfA{Um05w*Ng1p4Kxz+tORr|s$N6fzIl%Zpt!E0EZE=@h6NSxyoda%2)2xYF za}=?`Xkt%;x+*_$*4|7f5JU7_^lNg8R)u)a-m)j@HJQgmRJ~(&rWw1ZxtKV^WE#IH zdARG;S!hjHvT@WPZI(5h{)PT7UnLWm3uXtKvF>7zu4vT3zDOXo?T8&kdf!Z|EByK| z?X$?_8%3WWvzbNh&d5o8gEZbu^0}@PH`%?`XZBc^|P%mMZ2d8M2 zb=B^}Axl;Jm*2{evER&8;a57pTF1)D{c7jdPJ#lx7jNxo`VG}jUu&JGcEa~FoRWya zh6JLGYSu6qc!(F3C*O)~l*%VnQc+oGw3)@3}S1hS4(sXkU^Jw%TM z4Ne4|c#U1r_)PpsA27<|*Lc@*4|XA-bU&d^soK}F+B;te-6A=>ycbkm>y>t z+D`U5`9?o#9iaOYbM!j)C%Q7x9BP+Z^lSTw@sRkHc#JfbuE@d8X^%9sl4nTSUV+}y zcH+RwFS?TLx9%geF(+BVEMXU-OJOB^Kqk^zj4M_@b`-Hvoofvc4x6v# z*KDGrjV!C{_4WG!qz-NHNOlTk z!WUhZ;;>_vwp&tJfQ!9gpFp;-iGs|uZ`^?fvpj&H1hzz;|+1x0G zzu$)9PJ};sh1tj`MVBOtA*ER*ijt#@Lw0{^oK>8vKpwCi|I5IoXzCHVN6)NvWPQ7n znSc{un7B>!wSyoLo+V1NL#(Q1A}Ld*bx%J^srD~Wx11rzn$@gh^i-;sHqbap&$RQH zuc;m>1Z(Ke}|ag$@|7e)XI0k z4r)p~qf;`bo>#Ma3?$7S0n<>mm|QQ$P>Ch7o864-uwipnIJNqDvd>W^0IXgcnoLuEZ|n;-(-qA@SxK zCj3*$;{;)EwC3PB$RKu*)9m;5bhz+4+UeNUUV)Qz4Eev6k)x}CY~!~uQ6xO%1!5k& zAMfoTt_VRiL^W}os7)NP``FMzpl%t9zS&EV2e1Ya3HX~j6P4lN9zx6|-{ZFwfM)Rq zD43gx-NY$-FjTvB3B$ez5`A|f&KAHkM4?N0@8=OQeu(@t##i`pIfknR8I*HXyHpUb>hlM&?Bh43C7w_V^ahktmoB zzlw;eS0zqiviJ`uq$P>Bpe@EBIc5mzw;IGm`yk$lKEy(Nw+UFauHf3u##G;7uR+b) z+g=W}ZxQ(A=Rk$_*eY)S1c_-pCJ0L{AFh5me4}I5IOHu4vD(;^z{>s8@>mz1wS&)hG7T>rAa>CD`a(jY4^e{Y!-Rzk4(^`buungIP zd;vbf4dMzxVjt{H{*N(nfm%(aK>aWV8Da{39en#Tm<<+Vw=zT7T%3z5j&4+pj}yxA zRWaK=3Qzk??kf6njo5rF!DLV`$u~$1++lSzKS2rfQZ1?0SFTAHpi*U`m%}=AhNU7s z!v!Kw!d*f=!%yIMCssh#y-(ZR%+cCf*`nNF(0kgtZ=@s4}yO z4boGn4A3Td^iMvJC8=weSXtybB8^x^Y{b(!0=vj$Fo}CXS!00c@ej*DOEgC;=V;@+ z?`-Vq;W0d_H#6=d=tEuNC&nL-uN61eyWBJ1Q_`cj27%Vq*YO)S9oh1x(O6qAx0SC( zxp16+zt5dn`bUlQXX!P54od$cBkXJKpY5*~GQ*{!E#(0!Fj`h=vOQ9OwlmwHd{_+S zLmGO;7sYFW2MM+n*cC_wZGycZAK2N$jOIwS`z-w%og8@?c@*gdl~JMSCh2MPY@}ag zqm&1F=a$-h;H{Kh^ z#Ceb>Fy3vsWXDsn1@t+)h0`E2lxMzE5t?HfQigTLSftI4ap?Qif)70{tc2Kr-?un$ zH?Sa-A8gc0P(2lut3x#@fSFXmdW89|4yNuAx*IxS1s&N@4miRne3J$~CyU@@dnwoZ4}1rZ!ox0rlGsTeEh8F!Km?>}Bf7gHfNWeFwAUCW4LdzK;@k;+5)Q@hi@W7n4Z{9A&t9Y{ zee!g4-*k<37IG}&J907h8@-wwW$snW$de;+;bOr!KbN^PV`xUzjJBC&kWDr^NQHMw zvy@F{8lKP@;G2zOr$T8~SGXcP=R0vPpwoPX6;`kof*sagKco8LbzU8<8(9R;(2;0{ z^j`W7eH0C4X(=@ic<(d8d%ZwhK_?W|A9>Vn1YU3g7^@?!Rmg$wXWlSM8q3U!)_6D$ zBE)-iwhU0nvhf{-0**>9hv#okm$-THt^_i1S0bO(Hn9$}TVBBVaLYT)o5Qo#@k012 zYz8^=6xRkF;H``wz0OU>R(V{or@w`7hyP)4N$7Z}Hu9h>-&Nn%;NNnZu^TR+C!h&R z%ng=BCwVTEk2>cEX(9{N-l_t86od4W9nptTIA@>(s|`Z^`0(1uO1YQXAKl(1Rs^}+ z5h@pbfLclo!#i)&aiA~mBO=Bsa6@WoyOnCOta9Gy@`yk39El-YVs*7A`bG0IQIYZT zYsA&g!tRNl(Q&gAq{NEJm6O{gT~Dy%j(Askl093Hm?|Ud;sEHb^U>X(%a!N1@=oEq zu-RG7z1F?m(MPyTBcDB{!RJ;lIw*1`GBnJE!v53#M}euq&e7)Tf95ixHpMcR!4lrU zjAUNYVRY1Qkl*ZfW}1FWDJEZvoD1~|jR=i}1I&Udrj4ASsA^ebh1HT6L|tKyVy5t& zYr@y(r!&Yx1aXJ8%IW9S3QAQuInplp*54@b0F$xVp@EUN(y!`wy|eX*m_Q%m_6p}6 zsmSXc9iJYb1TW1|PdWENXK6ta7*X{NsJ& zH9d1ZGrd*gO2yrEA9tK#x0&^&;r(WHOG;s*c-xO z2j%MG>fvmNAeysWI#ZeS8+ny?kr9D8nY(^IK}Oi#%sIXc-%kI!&?zZRt7jb`2Qfpr z|AZ=zwvMot{TZ{q)*=SUofI!0jJ446n7Ig&p1?L2HaK~Frp)*) zi4&5RC(TK^oOn1vMOJAs?=9D9q_0Q#44#K7<+^K|hmWg|#K=syUo6EoBhD(H0!w}r z`Zno%+4Mg%ONJ`Qf2pU9Im90Jov_Ura2N0naW{1=;G45u$$LgCrCRhs;6lc4>ABKJ zXT0+t58a3qi@noZ5|!vzY=0ptP8FXBz z9?B+ZIP#v)sWeI0AWO(Iry|D0IfP5D=I zT6sqPb$NqwSLe*l*^sj=XA-t7`?D{P73JKAUeKDmmmV&vDVp5mye8d?D~q=jcPdI` zUuad-JXtby=k?oW?z~~&4~O2Zzb!p9@J8f<*hzWK^DilwRxmd2omiW!n()YAXKzsQ z!Mfj%tSJ3>kF)!kl7hp%YVMA|<-Bf3uyB}@^?Gc4?BVRrSqGyP+zzuSQ0M)e>e}#L z)x8zHDqgOrsl26nQf+PBj)or-h3TGn7`?*zcY0asp46E1!Su597WQQ>O#Ch0Ccczg z$XmyU$AgJ`lPlAcy|3+Y*z+ym4%hea&oUwEMu)Oz-Ylyv=M|@9FNo#j*5(e%?^KY^ zzb!u}e|r9R1y2^mnl5PCulUNsPx8;pADN%Z>zH>{Y()5UXF}aO2jhE&?Mm-mdT4Cj z7wP9iS7rY@w>Cdra3nt&8=d8av+=0f+&wYJ*08DeiRzy!=W}o0rPZ(1u5B2Y9OGk%ERlbuS&GGM@PQPZjsX+uiRcF9=ge1iNbh# z!@=79wXfCZ#V5qCZJbv>v+f*xcif&Xvv!51M9ZQD__li}lpDO;n(jv-1xgx%Mv4Zq{{^p&~`>$ca1>K4?O z;lXl#>RI<5`=#KY!qaH)*FmV=>*+3KFD{rKnSLH0cQ3d>`(UtXbPPVmTjyU^@Mhr@ zPM*G8w7jrg!5R3|yAdA?r^kB6ro|@3E{_e$*_?wb?VJ_4lk;;6cI7>kofjx>NR>6) zvuXFP(&H-EHlApI9BG%`5lgpeIa{+zSkG!qU!5vVUC7DZWloRAi>vRd_;cmdnjaeW zB^#XQt?j|fqW!b`XWtNgIrO15HC>;$Be4Zs zJeijaCr5MR!l85<_QO66{w?xI_Ln)wqX+jX_^*QT1@GpE^S9*YoZF@=foLFJ* z&ADIV|MZj_G)r#aV>uQo++@hJ9{_PbSZg%+rG`O?Pz=8>)L?TBUV;;YSWLJ zRy93bG%k02GWhxZn(99d+H}zmvVNkr?V>kHaqyE(rzls-FTxtZTCRXAj94l>bU$izZE)EG}HZ zZQET7*5n_~c{g%{_gcf#6-^HObI&)sZ^cCFE^mA6w&I6dENwBV*`0;cVylBg)14d6 zt65UDyXukZQMDcGV+|#E@wuY0L$aN7gS9kxT=cT+6Y%7Ia`ckm4eqOnCH3uVi#V6m zrM^Y{wB+*C-1IO`EsntMu_fN_<~i@;ud zogaKP^epEd&h?_q6W67tJ8|wL_?!D4H*!7a#<5M^?Hs}WS8hhJYvp*=vD?Xw4zQXHsw?rQc_V>1OqQgo#>8O6L&fvSjThT?8$Hm>xpMr zZJja6-kejou3-cgsqbK0H;@}(W^+eIH|HIEW<83Xz|_#-$oj|y;fn%GoK}gM4V&?& zcoW{_eo7?M4c=FQC)gRQ$I7i&us8qh2p$DKi6G$=$5@>cHa8O@Y0sG zL+tzVS~Wk=y0Gm-t^QhkW~`NWQ(eEqgUVuMe?6F8Ijy#DEGNst1ws@x+O9` z8q2yE9c5AU@8KfWKzqk`)^@9|uBxlKrlD8zLua1V$ebh+vV+U4M(6R=0X+Ae$T^yi z@Z&-y8LV(zZoNqN8G z^YvM7HtU!>FQ-k;pxFGZ){#^o%$-ynI42(V=5WL2es@d!=BmvHuHAP^=~%tEV(vlX}n_6MO-``lGY1h(tL({Dl1r z78gsfV|v-^n!Y1GsQ#MT?KKb7URmEO{^!)U?uYiH*tskVY_hI%8&a|4`|){=T^d7; zGw>C*E^#`eWqx`a9-J$j)3JnHY!41zfR)UG;AT!*6nLjO7vd4EJo!y(h%?V!={>~E zBVcdB9`P@BcHl&8elEeHd`)mJHe;38hn&xOy&`*=y^9mS!y>ad$uKti{_GUDdyS2L zz=~B23)<=k+HBU~>{(gYaMHXXI3EAIo;RI!xY71cfxW@Wp|!!E?1j$6#@wp02iqUK zsw$RVm$k6y(`FN!om||a@ZOy4aFH{ncE!Q#ONW-dRdHVZ{M7ZVOzmcm{oe46;rW3) z?~Byx#H_^OOH*-Vj*@-lM8%rA>X0_mnbc1t|ceB-&y_H*7Js*@DhWGC^jhnb3 zuWhO%wG4f=C98*_z*^Q9Z?!IBEwME=auNGsYc<|sgWL!|jkVy(UK7?Y@8LGJEbm2p z^;UR`p@ANOVSxsF4Zap0!ynyFR`TrN%;4q0=Q(3G2}^~E+`zpd{88i-&U)UIb#_*t zC?{aTZSk=9X!!WZ3~pB+!F|UQIjb=!>q+d_#)sbtof`TVr;m1Fqk6x+#y&MLA&{~U zSP#12CT^(x>Tut(SIeHOJdiv)JUu5|(2hGxUoEQ4ofw(o%&z_Sp+#lA4z@q?Wz}o- zwE4y7lQF)AOCPydS;4yFYOo*uunu_^sSG`c-08a#nhjXS1VQ z!@7<8~OJ38$KNb8fH-LYpUGDaVu@z632g|n} z%BddF7w@+UFb4ZmIig`ayg<&fqrI&ysJXIx>=8w(r8@XSdLecof}df5JJ)&+Q}FU9I69 z#Vk8+edjerBKLEC!P;Y^{Rv)sCxjP--wf{y?Fk-&eu`PS586xYPXZOe{^1iMDW;Wf^EeFFVG~GsDHD@ zZkXmw2~Ur8$h|xFoSdOq?}YkUI}(@HOg;RML&1u|nui*PJHrC2LJPy3vx-g*w+Ni# zZb=5>dmDPhzeq;#8PgjN!-KtrZY%d8XMOr^PH*>f-sTRB=WLCSdhZ4|%GtlF)I$6^ zUy`~qeVThFKHN4k=Y2b{%pT7QeYsW4eN8RAmfrVXqvhHo15E>Su(<7FcVbofeft`_ ziG2b$_E>>Ou|gb<1?F4$SML*O&1vmXco`TL=!xH#YCQ2zX67tQrPqANNKcSm@C2OLerH-UWx{JIMptLVJ2e_Fv>=fq~ z+qk!Ym2V@=E7s z=fiY7<)&W1tIqS-q#p9Byv6K;e&Joq{%O4vb?)V+%mki9Z^Wnc*W6ddP9qj#`|bDa zGws88(S4b{jAyNxtSQ%9x5G*Qf%WN<;DFHILUwp^czJkRcyah8#%Z^3F=ylsa5idX zs4;XVr>!5us&f?QP?v{haYkui=yS&B1%dwZQQ@8HPH=8XPfLwVE{In&?u*}$dd^*B zSB09fnsjS)Nu-|B0At;5sk!mCjqSKUZDO(}b*{6p4Ch8VU=?+@`w_PB zcVWliVW03M)_6{8D7f&FucTI|&t(te4*WQ;WA|yUx5}-?2l(*x3hv7JK6M7OjHO>a~1eI=uNk~unTfR=xO``J_B|>2|X1Y5x4}K`#{T~{?@a3wPK30w zBGzoLg#NvqTg}gO?q+Nr=U(Mb#Cv&L_lOg8`@rc7xxu}IHHBR!ECB8O)@({WpZg=P z;O2VAy53%e)!$O~YHteO9vl#CVBPjl>=f^?x7f`BuLaJg9glE6<=xPT&{pmrv4isi z~Kz~|_oOBoboyU{UvFh)nAK^~=GAAF4 ztGk^o>CSkfoQB8S_35R~Y}aDnascPW*0DQzyIbK*K}T7K7vn)*M|J>n*jrm~pGkY_ zIZyiv8b!y@XQAW51dtlQrOcqxE;tPhs$T zc2pMQ?Y+{fwYu43u?>HObA+?8|17uL1dhY6R~^={!?6B*AaE8E??!gT-ovu2L91Ys-u=NWDO6-O9U3l^?vF2LmauVf1Z;*GYH^KXu{mwhBZRku{ z>;T?u)v0p6djkloWB1Vjt0;f%@t z*4>;dWmeC9h_`YwyoPps$}Z*ER&Vawd(Z01oe7`NuAi)dcv0Hrm3jNHG~NW~D`r$p z!b?rLH;-FB-UYuO0P%zDjlS#O(z(l<;|=uIxR1Hx+&kTA?q_bbdm868XOQ|1Jbq2U zKb7tFbFXp#?v}bm-Z0wr3+?@qedg1>xVr%_sWv6d=FWv>RzG|UzK%8XFW|d1<9HPs z#Cp&3&a)O}R&red{=(GzT7bo3#pU=?{AtlJb4R zGswwGTHJwiuxaZ|`z7|gKWB8EW1mbI$}Z;+Y=0eV54d~UIthQ>28=TLb$}^j0${F@s z_EVhg8ww4Mpik!De=2Dg2f7DZu$MfGG4~+-yq!L~0^RZ+bbwZYcj?ndIOn{{+l!UK zQ`TPV6ngsud``ZIcD@7*PJ+&^!y>H{w^7^!q+hYp^*J^aXR?m5(82!Rsd0L9|M4rp zyWCyE$)a1_mhNU}v9sFArcb}(K7c!s;(LHNi?O(jUHeg3ceKC*+&Reh+tGwxV(eAo z4P^>FVcC7`QE{-r(A9&bd)bli)J5L_KPNUNO6^nu@x0`p1_c=15 z1+7hEUvQ6?#~Hrs89yD|Gw`>x&Fuu`-p}~E-Ma)%SH!u$9#Ha3tQc~w;|axhaM_M* zUWHy;3imk$KV4TsS1++={}whC&sYy(SMn5A8he?aUI;BcW#57>RVpifYX>%AtGq_< zT&z0+_AofYNHn)HIK)`?{mZfQ*y=^G9{JEJv10gm+Xy{$wSMs)!7}0`tadH%sW0H?-L40v!!y@m1h8C>v9sNh@d)&2mM!`SRv>;mW0o?5JC zR(cD;?f2a4RzhEAad+g2^mk`?bRGHEK*#I&R?94_39&86>mr@jajtU_tyxLy_WNZ9 zumP(Eqw9cU8JONoswBOV1!jYciG$$aJK&k+hxdVZ4mB?UCw~BIg7UM$K^7_Z^KL$= z-Xe`CVkd34fEO!JTJQty{s<2KC9v(m9?Z6ImPcGI`8I>WmE>4Yx@u}q(B5slTS`6O z6Z0$BJ4pYTn5~qx0DFax`JYR9Ujg4r@U$KbuO?15emjv*X;x06e*HD%UqhFj+{6X`uUqm|uxE6tV-U zf0)s4p(|%mmSrUW8qs` z@tfajVOXU`eEMK2$oVk`ER`_I*FsNANx6>xi+cr(37z2{3=Ovbt1I8deu16 z;t2V6l5-DuO;V3wECN2|E931RsOAVYhJgDxs{?0$G!ktnt%A{13bj=D{Sl*8tw?b^ zJi0Suq&uUeH}bw0xN7V7y9MPoQj$gc+K{FfvE4}Dg4iq{+W~N2;PcMblqT5Yz+26~ zAj>6Xdmv~{8q2BxvhBcK0=0(8b0R%52(HX-kDOnfRBEp9YDTrye*a`3Oy9# zNtDrpQUr@)qO>ms-G~Ol;6*)_?~ieftvbK00rEEmSM7YBRKzb_?(wD_W%LCq;YxGS z&i<&(0^51eUa_ zWhOg{li25z-{e;N`}t{4_3?E9a_wTm1;n35i@MOFHbB+h$C+rNm(`P?@zagalQ;dS zPc;gUoxyK&+FJw_6!Fv+n7jBqxi7ud-w*wG8UXf{r$5jAXmKCE{F@6Q55!o*-7i-XBEgx^DXe-14_ zpYOrc-ItbV42TW})7o0-AGxU(lRK-GfQp&&O&PFepBw5!w^@P68XJ zP||5f`&m7Gy5Gb7h&_>%qR|Yb9jQ$i>;s$%{d}tI&KU0iq^*EZoI4MijKN882<8V# zQ}viaA^oO!g*<*YV^p{CDIhb#gcos|j((Xf$Qxmt>Mul&ro?sxsxDAWbK)cgqI_l_ z{g)I>!V~KFPcY^K{s?LVzS~nvbLx*#o_Kqh5g{64GnnV#(K^KU^&IeP^pGbFaG*+f zY8_li9K`%d#u&aK&f&rzvw<#;PjRg(a#WD7(bqR()LP8HMzr#KaI+}wF9KV|eCG0A zxoVE)ic_AciK8&SB-@T|@GDa2H*}<3zJzAOg!a|@TzD66*P-)Bif)G|R{?Va@Ct5e zMEiU$UdH=I^2CX&CFU@EUG1tQRQONT_ZA1q>OrM!WjxV z_kpXm%piV5PuWQNQd(TW`-4EHvbK}^5NS34k{*)fYl=I;!7?p_` zPzyXNqyDIj$#7@Y==gnI0G+pi0^2h}oBOno86zBvhaROJaQuq0>cOToGYgz42qy{3 zE=L+4B1XNco;$*uy+FH-R&1oV1b6At7_E)$C0;t#AzF{i7hn_}iyBl?8Q&_;q&PyY zst@xhMnf)j>d*X^)DZO+`{P8KbMPqbN~deWbDGji!MJn}(VmNr-x40v6Asgfk=zst zkR*%nUF>r_jl%+Rdf-vCQwx@Y)YF`N&HeP!WO3!~!)Itzl$RuZ4K=9sf?b%Bw3EIn zjg`y5`IQFalJI$aita45xCHMxr%9aA@x+}tGzA2rse1C6n0z2?Mtcp15ZBR2E%dom zb2ybaQ%lk`VbtbOMvQhC&df;*dRM%;FD(~8Y!5%w*cSGh0FU^hMuN0TjX{khi_$aN zu{e};o0yOP6!CGOO7Wle+bA7HBTE``Q}|goc&~JY<9!LP)~G$MPni+Q6{ks%N7S&7 zo{<)m@MG03m6;jK;v^c&;u+#;W_(rf)CgWxzjJg1nz5>OYh)MDDsg(X%8Y|bsH+r> zYcHSD4AnD&OWaIcT2w9!xPFg_)b26C#sCFB)`HKN4*giFmv%Xz;8ez6e_wV67_U3O7}M(19>Ro8w$ z@BX7@?D-E2!l1N&aTbl*JwUvjGB#6+xSR<)dAF5!n|v;?iD%6L6!!;MkUe8A*E>G(@1N@mmh`6j24X)m8PIP zs-cRy6ss|+(gdGMGunljb(`6@O4q+MF3q#dpV6fxM-(LEBtJ5L;#HYvaistMPqET7 z4EGTq6pz9{!sm#p#bqp-Pm@z~VQCTKebOgXm-IaS+5WfS(HrwiZzatFz64e->5wWx zvmx^xgJ2Q!^`XCUw3XLR+=+l%|MHB>=U=(Z$N|{M(;MOcoL2XdF zOwhA*9Yed>(5zW^5S8aJrljkdu_awobA!y76Nku*JdM9hD)9_y!P1lUWM*m_$7Woc zc+COLSjmhM%`Qz4tZI|yoo3{i-w88cO%kv4(rV3$j`+LLETrQ~chhIW z*GiN-3HLSgF~jXMGri1ASbDBfh>I$h(&|~WDM=J@b2FdSTB?32r&(8(MyORdg*wto z5>z1(%6&N_>7^%0Dh16gq+99RNI2;`8A&I(qxe!^4({jMNWe0Fs~jU8HA7Je=9ft? zd8yfpa!SXOzLJrxdfrERNloQdP6cU$20Amtm1b*Xuja(kew0s8X1=ADNjH*aAzkSY zKKJ|Y_VH^gI)G-GidF6Vh?lM*E#!CpRi5+?X-P__Ql&d7UhmCHtEofv8vV~`tp?6= za+CmLrk%n_Ijs;j4WYNf%H!Jhdoom5yBM0(!Kw?5SxLATq7Ofad9(g>wn zsbyMKHQ$2PXqb8@E!(v8nD(fW)hi{GDY(>L^?}ONJJlwQM{{t|nPwoOdW{Q>rXu+7 zY4BE2T!bA8VXlV!n)N4rD$J~dO9Pg^EI6g13qP9SO2;--wD0I!(T4OD(X^Q%N;i>q zBK<-81JWkUr_n1kbJRG~DuG6cW9PMLA+lpG8z7_C$&d)O0r09=$+=eTFuMI43k5!85oX1(!`gTsz-I36$4YN zq-_r6s9duOWH4yjXz*(!rRfV{CR4MZGOKFBo#`XflS*N9N$IBe>yHVgFmx|D zXGT><3Q9VfKh62gEJCUDml+Q#Px&Q1Giws2Y^BsHkYY53GZIv#ru?8$tdf)>vwA7c zVC1EdZIY>G^lMc}?=sR>yg*z*{6OmwMjC2O<`|DrNhV%-4L{LZtC627$w<^1_?DSf zNnT2xn%SNCHZv|W=Q68);%AbZnhhE$q3?sdHFG_s(r=~FlhzH)tWNPpk{*+&TBR_v zKcz17`LvOKlGFQrsVR9P2sI@=Q&77KNF$42?DY)^{e}NM!TgyftG}Wtnj)ZP{qK;xovQv;d<)nDtS;H~E#Bc3j5eTW6U42}Jmr7t7{^NdpHJe}ng5K2 KqBMG^zyAm8*UJe2 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav new file mode 100644 index 0000000000000000000000000000000000000000..86806fc569cd001b848dc79086d808d4b9b74c54 GIT binary patch literal 105644 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Π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 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav new file mode 100644 index 0000000000000000000000000000000000000000..2b61d877f97b30b84a2673a76df41f4998eb7099 GIT binary patch literal 163244 zcmeFa2b5Jsvnagx$vL0Nff<+~XUT}|!~lo{5yeCh5lmzhkf0zr zXBcuG7$(o0oYUT~>XiFCfO_x!-hKCf|9Z>mH9K@yS65eeS66pe?bE+k_wGNwD`Ez9 z8rbc{v2WBcFbu;&*z+{QO#Pi1rvglC=0T<#)0=sWd4d@T;c=!vJojTB zVR}M*SEe)5foTs=4?t+iv;pWYOfRMn^C*NzAiW*al&QnyFj-6uxaKnr;k`NhH)WbI zjUY5&>ch1uOGf9kp#fY2YH`vDZz zttX^*1(;4uM}X}F_3Q$n8`C462VuHHN;{yTB?RPBM}Y4MshG1fq&xt1s|$6n9S?P( z=8d7|$Rnh*bv)+-KyO2)7L&=OKz)i~aiGP&?y z3(7%GV;i-IQ%Q8TfS87Wvlf(}4pd^x7@?QwAs8SSAtr@Mg&HJ5i<#r8Mz~ubCLO5G ziQ~_OdkqLwR(_nuI`EbW@JdDkJy66b;5i-QkopEdS32NUF)~P3F&YRuMhj0;=&>Q* z4Jycpt>pp;s1`ZD0zz^EBHa2~|MGP<+pdDK^6|N?r zNc=}RUdYAsB7jf}*ZE@J4rM|DC~9taMAFXM}#ybF8* zf094Jp90J`AkGPOLLM;jx?}0lc>NKZ2T~pJfH(tu4B%u?TWozj)D?NcLA)KPzX^4? z33Qf19>gbu+Uw#$1^kZymU5`k?Kng=(2Tf5(Ebd=1H4e09conqbQZ=rbB;d?{J8?p zHz1~vzZEZ`1j;Cfdb{I&Aq06{5OWpkb&Nj>b-M^qWsvRwh-#qhRy_BeKlrNz+OhBP z@P3m&!|&(!@ca1VkiQ!0jeJ14$iuUnuYx#xoK{i1uW~>&atGT|3_V5KsNM22~e(v z*28wxK^n$$0EweO7aze!pgRm$u)kad3huyjlvlur&jD$HvMU+#W6iKWa^PrMTt=7y zuLyEF|DezZcrg{_gAuq90WMSlon=688Bkmi=WYP{nGNVI{TKaJagJb*!x85Nd`^JD z))B``r8e*b*Iba(0WjE`aEwcVo)|!4pRhxU59p>*Yyyf!Krhxc2LCM3iao&y0Y@y# z93=!XKuP2L(LpMvq=B5Q3o0(HSLjUySk!9n{)ptg44-gW5b zm!N%a10RtCVMsyzwm5z-aLo<59PoyvQ~`g>p?4Gk=aK7fNJqKggPcCd%LD)DkA=FS z%*4M)yiR4%{x_i{?3LG{yb{3Zj?1D*obM82&<*Il zIC3i>w=0gf3MeXpR1Da2?*Mf;!mmKzM+tQTM&$_@1sCIeurMw=a0K8}alHQ^WjMMo z$7LEqp94AzAr>Vg;zT)e2?ENHBH)4x>Wxw~477Uw;HwvS5CGnx%%{GHBkd;Oy$+%9 zE}l67E6S5=P|j&6?Ic_aKz<{IDE+XOmv)z;fkZF5HKKLN`XqOE6V>f zAdOMdU4oimz_@b|dj{~Iff6o29M%ByW7=7WKMCPXJOw$667vS&y9K-{ikDCd9IA-7 zdI?a3IFSoT1yYIuYlf6i8{LjmdT-s*n$X)yhT}zW85AekvM|<@fq3oM_! z{SJE`^}aC3su+YQga`zb$tbTV4*MoSBfi*OBbK0W3?e2Ugdmg_f-BwyY=|2rpD=?F z43>-~QCWzIi(|%86LBJ#59A>6aL&-e96=hO8Kk-yWE|>*y0|nX-G*REcT<7nQ~xUs zH82^-7nCp(c#?p$MGXLF5iz`B3hHQd#hesHnT*td$Atlni*n=Zrr>7HF3EpA*-R^I*=yPzPp#x^T|}>0A@i z(*O(350>~Wg5}^7^28LsqA_VxMu$VT$_UKkF!f7xHpQg z6mYfBI393)h5^?O&EbmA2wflQjI>aw4cKv2k_oj*i3j9j2D~F}7>Ariz946CJ(v7P zpcvGc6Lr9v377=_XT@72Cte2P%#PztgV^kNt6-k=e}xQyBW}?O2y0&pYM&3Why!)A z8gZB$$c=4{YZ2rdUJ(Z4F(m`|i?mwf0c(}|M@_I*u&%-?2emxvf$I2^@P<87SYu!c z>JQlGu+4FN5H$5f^B?74o6{J=K0$i5E`F!AmMIR0D=dV=bxl&de+ilkLg9$O9*?6C zOT}@3V+Yq6ILdHTp(ctW7z5HNj2?u6; zN{oc8Ks|!AdV>4AD@q)aG$`RP7h%CGN-7~1^J5vPwNjwk&}t6rgmt9)A@x{KTJfQ5 z!N0qyK}@JSM&c4SA#G7M)9MNJA=I2uuA_X$AV^)5z_|7zoe5<)2Gr$9o1?WB>UD$# zB{4pshD9qg)IL!9V~%PFsGZ@R^fX*)p{9#h)Q~VA>9+)hkT|#C8)|c?Njc-19qN4e zkNPLV;98Gnb<{Ixj;DDOwQgJ|kgkn0A3k9$YGRn@Hq3T~5J-nXZQ>5Z-hp_W2kDBl zDX#Yt>oS}taYn{?S_vXF;z1pVv?+QQG%L!FIt^jL)Z0)F##6q+cnQ}aH);~7T?u(` zMkhT6bD#!8`VYpF7D4HFrTPDATw_6P0d*|YRuB&Lm8%eUHXhE$VNl1t0T85*q2`0@ z@5_(_bE5u$Iu2?zs8Nt+f;GPhaYQ51jc=rjA!kqzLfs7Y7vv`CT+|}SbBZB8;}zjB z4xg}oq)%ZSuAfmeq8QZKFa~uLY8fmQTL)=DZjnYxe4}T)B3H0ZS0G&d*Ar=&SO?@d z>O`nNVt+$zKMiDO0D2paF5Dx~f?PnoKn$xI)OT!+dXj@T&3WcK|PCNXf%<&PWlv%Fw&$@e$11W>?^cNQm_g#dQxgbwSCX$R1^cGoM8e-htK?Zz4$%9v1p;EwICtOXER3h0* zG7RGdX@+>H49ZV$#7Tz(373L&G93Sp8;HusL(w;OToMBM5T7u&(F~V> zM0^-_D)4KHCd>o7kVJH&IW+84_nl>ZSOE^CSKV zcY4DsjvZk<;o1UcOj<|NY6Qm_&8xW5!7(Syvcmd@)-RzrmV0y4&Lz&WIOEaS7G_$E z!#Pu!MQII$akRq1eKVXZan7ch7_T^!;%uClnJE@!4$3o{MRCTYITN37O^2&KoMmyp z1fOx&1m{PbGjYcXSA@6%6?Q9764Sl~#^Mu6cVR~ZV^HdmG)H-lc~Sb4)W@ALlKr?A z##tBxm5Y0iiGSPy#N9!<;uFed;f@sJJMHrb@q`U$cA}1E6QYvJM{0;7x+0yJjm=;q5f@SNBWFF(ir5-49(y+K4CDSJ>NJ6P8{vu=cV0*f z!g$O@ZHQVD=|__#X=BP$wFVI`2%|{ z{?n=**U!}BaVPxoUJ zYLTD@p9D+^iV|>tPQ#e{|Na~!U=Sex43Q}9&rd?G|Ec@^)Cjdqly^TwBIQ4Sx*Hqe z5o&mMUX1(q{_fB5clqxw|KBU&erPN~C`Gv65Az?r-%BykML30cm3>@7h4ckXyP z^>=|Z#FzPY(|GmFImd<~= zp%#RC&7TA5Il>inq(mSMNzjc*W5O%yU5OyP3-?6Iy-%dG;o9S`g0M4ydK~F^!d=kp zgcORu`zq*)i96|%xMN6xw9Uj7V^RAQt^_5(6CR8cVuYte30OXz&)iLk@GR62bLuLP@}cChxt{aW1rMJp9N+r>XRCBl;Zdp=v8Ur+2;#%_CY=q@zB8^+>GTKJnYe$9yF|Dzi}pS^w*TWlgu&B%g2P=DED^8w z=R_?Udtah2(W;Z)QR9yOt5@EuHB%WxM?%`rz73T`&$!!#>ty_=JsYZlAen?c9+F^0 zDe)&EFR&D$yuXtS_ftpv-xy2(bP9;IrF8-T4BZDjdlny zKRr=Trtyt7TEZzN?jRrp_G((2QMnj{WuOfP?l0h-Mh2z`qm0HU;uCi8@dTDeDVBk7 z_l`gsqe!oiia2oBkxp-MwTfc{*Rr(NfN!{B#T^OUf51_MI}f@1-3SJcTHS7?c*c4}g0PxRYX!$K&2Y8SGBr zo(i2e;2sF=R?w~o?zNz`0%9qS-*M-IEI81T11;U~JRW!Z1-k*X{Gfem+)W{C1KKMu z257V_z(6_aim|iV*vJ28p<7qkYzcfx^Cv@e4D_*fF|p3oi$owLxM3hv31 ztr_mc(`g1;px~Z7<`+%^3SlP&&m7RY<1pBtodMoPfu|n8j;9aR@v(%v>SYjv);8ET z{P129-_J)2667AH;+Y8AOH=}k1IoeE60}l4D=?&=P7H|KWSN6pwgF$rHbkg3?ZDFs z1zJ}i%~%6ETeum2r}GSq!xXd~L4IQW1iK6@4{_iw7;y&cjQm30B9{;o=0v)%{V*rB z2JM_-FTg<1_=Y_Ydjg(l;2D7p0;VDb)XOU14O<5B;{F)XfN#{V3gf3YWMS!q+{M5# zJoUHw%)5kYutOSD_Uk%A=<7qE>G7wrVnjwbH((P;_htOjW8cgRH? zZ@7nv{T#;(TG8RTAo2uHR!A1n{wM8#;t3?mCd7ntfX;A8*5Dha(kTs=gw|8oOG#$n z*$m1Oe8WF6&Z&2*OGy7G^jbLF*N?BgL}^I-8*L20ULteUB^-=xmI%K0KGldLa+c>Xa;F@tw+0 zLma|je#(uOvuLwGT)?Zq2jU8ySqK^y@{}xxkWZ+qk&cFM1cTO$_=b86>LZwgG$?Fy z><9Rc+5_qis6&ut74{F*JIE3t6z_SYiBK=2^L!jpXg!T57&!Bhj)C(d_CnHIuvegN zL)s{5B-m%^qyz8tgxZH-U67d3Nw2^;T+lH{7so4VCa4qPxI*n5pU47$BnHVHlrA(& z(KfD$XQB$I**X3Ql(!eCxBz8; zz&GH3=UQ?zxbK*B@w<|y(kG=YC6h(_K`K4Rr}II1xz${Z8_NFClDqBY#kWwQK&cB^_~Gs(OvvX{ww}l zelzGZ=V3-dyL)Pf+t4}^7~N=5ehYZA17P>@2O;c(vR3l*`H%S7{HOfa{5Sj({&V2N z+x(mSTl_43DYRMvi9a~8w{9x0EWh3 z@s<$^7m9-z>U0DGVUPN~TnO#?Av z$Xf$y+5$X%+CxpT#`*Bx5HOKX6-sSAP>9xT7N8NmT!?P6_{S4(vLZtd8uSgonxkg` zN@A47I6GjC(LVrJ_j+gvv{I}A7}0-#WG#*mv=}EX0&T>}VqXQh4FHFdUK>AWN6#3X zX_V08&<+p%i_oSJEe31Esjmk$r~@{N=xK%ai0I`+HhtLuYXr*NFwQQ4?tBWaCD6yv zBZCG0ki{FeNG4E-wu{+-6)hQPK1AOe^bSBN=ZaH^9!PYmu7+GWkfR=05M~0U#yBU4 zb4l=wmM^&G1QhWsQuv`%g29&pnV6L`*E&8c*-N}At3FjDPX`nIOmckNpKiP`UBntS`&K{l%IHj z&xDO+2gTx*;AspIUZjb5hj{Uy-YAbiBT+`VF^Wi^Hn#h&F zO&AFeUh$8x5HzOaAI8xW;iOcGy%&<8{(Dzi1N`@J{B>>|U;mXq9D}H5)0m{|U*|eT#aifFJJy#Jwe9EaIi~Kf~NzGCkkhUP5l73EzaLzq{XC3xX1AfmHnGe*&!p z`Jd$x=txi|l<=SB6yW}&yMO~r`RDJy!-2$HM^AYDui?8JQpkIE&cDO+_wj^Lz?FEr zTSuT02!?clyUYA{pZ|`Qe;3dHd3d5ML0^I^|NCVLTuWg1b4()b|ISmQ#{c#5u@?73 z|2gJytnMcoAC5sFAE_tmyi>AefP8QMsWn4xDs^Y{oW_q`%YlQ zREi@wA?4m&_rD<&{s|P^jp1(CM10~YQ4V29)C^Pp?(beI3G%N>y1$%6X@7_N&+&hb zL9GA${lCru(wXo|`?UY@_21)$fGd&fugbam{G86*@4X6G?!5~zbn;GVe^mzo?yv52 zqE9JzKi>G ziF>d2;!NZbO1PKj^hT8a85ZM-ivlkN7^-7}0wJC#zqjUzwEI&9tO7hi3b^mhN1RB+ z-CgTMEItX?=zeb*Lb`BIa9MZ~%E9+U9KzpSBH7N|8$)qq<$@___afxN{6e_9euP0t zp*zOm6Qw1rX6}BXw0j}Yq6jUK@Jdf)>qGW830Sn+O27&BKV%z3DP++^RzGN=gmzH( z2C{$>EQ5r*;Nx^}4zh7d*l8tfqbQ$XGnA+kSq%wPCTygzR>%c`U(`N$6>2Bs5hxPw z0!I=&BuKncoNy;@Ax11k=tK9fL#bCG6wyjJFb~PTgbXH0naH1bO32Xv-6uN1$1{4g znn0Tcw7)>xOCbo~eIl!Ov|vvJvUd=yEbx1NXemhF7eYHm`u-n%0Z70@9s`J-;0ccG zJjpH+ufjKp@EL7JF(kg(MBi;f3qcHtT*5QO3vYyrzDq>kEu!xo(bo;pBSHA~6MfT3 z_zn}kVZcd>6hkh2Nh-t6co@6n@{6g78M)qoQ<7!FLLjgRc0^szjh~ zUI|zFK4~HqanM&S1x!>f+8ztvD#eoM+n4k$&%5#8O{G8&ed|-G5!IIJNOh)m6)2*& z#5M8#Ey_u)E_{1Sz$1Loi{9~y_Pl6Sj4gV1uSM?`A>7>~65q|DuY3#R4DUF`=o?uy zW)K3sQ4)d14ZaKcaIDg(B&#LC-X>w2biW-G!TpsUk81?7Z4xY*5LSRhNtT#ZNP;G$ z8(Cta6eH_alKONNtXTyaiZYdCGTN__Z7s=Bl80ntiqI7Bi7aes4k7PX#DGu2cb3rm zMDPPc?-TSkLH`W$TSE^S^ctmaTcQUC+P;&mFZr2~^)7xD3Vm46uLSLk(c6oBUkDm; zphp^FL(J&YM*f-fEiHUT-#YYCA#XYKNkN|y3g}fw-_9ccJo0}d>WCupr$sLk`bsC# zfiz$|`r}{@{7SvxLyCSLpH_UDd0CMU9(gj6mjqITWg&Hl(-qfdusqa-s6XNxc~fIf@}Z*M zMBas%OYn-q?~|c_GJ0Ql0G8m;-W+|WoN?N*uHN`~!r2|?XZ&7*3g#C41qJlR!|%#s znTP|aqrQp#82E>x6Fn8stHcUE7U*Y# zzw(2=7FpmykpkGTO!5#w|GH4Tej30g2C1C_|D^q(Ckp;51om}oKM%CE2Vz7(s|ZS0 z10Qmrgofae(J1cGL%%G9-)}Sl)gd1JIj~-6n~%SrA_0t8s~CLu0>7-B3>?XUU%jaf zl+^_fp$>4(2agi;#b^jm=u0629-&7Qax(70`;;VYK;REINP^6_kvBSiTjwlotO@pC*9eDfrzU^fG!Be!-_X z__Wjk%J7TU@{_uL*Tdhc9xc0lf_%#Q?N)0&0{{ zn{?ns6_j5HzHc6={}u2+!{6md0s0%k_dhy=m)9sL|4n8R_;5{OHZt?UAM73QhZ+y* z*+5}38ufmUJQ+6mgJ2&l{fSe9`>9D2m0L!ZNMCSr@Z`Py*J0Dq;? z;8*tsl(Pcp^D-Xb`5Vmdz$^TQtB(1NZ^bX*7x54CseDiVeem0x2;ABL-c0quzpgj@ zuV;=kh0GmB%qk%SnG(o7op}!MbcKG%(F0|)$@Z$T1mjcd9;Ker* zycP@jBxXD0U%}4>E~k+$sP{*D(iy z{=Uq2%-hggjLc;iB?q7{EdW2rE#MKkg8va(^cR?uEWq)z{3fV@8v0Bf=usg)AKGUN zc(PptpdT0PTO1@5GPi+w<4B72Fzb9`_FC;m&gVxjS4B@FH9S zb$F0@1vsC~KFAJZzhTF)ud|P`t=QYl56}y*1HVS`&+uhjB{zic1y5f9HEY2uu_p9p zlphnAHO%MCGr;XN%q*Z{KGfI-BkKroXfS`2`TlCc4IU5)BkRB>IgV$tJOz07Esj#4c_J_Z4U2T5x*qSnQ|Rv)op$H~45~^G}1f z;|cy1=#f*H9neAz*lBD>)(n1~FT-8V@=Snv7e?OzkWgd!;ovbjif_vI1Fy*#^zTja zUV09Ax*L2ylXwx|oaeZ85NzBW{zK?nY8YV~nM2HHzy}H2o?XYbVYe~cp|+2}h~EvZ z+6H=~ntz2~%Jvjeie(F$V(Q*Fei}08Ts#ewTxorOYX& zk~zWr47^&%ya%IW8;ragT$sBEJetEj&TZ!ypz3@0U8ajLPEIgG*k0@%#>`FxFVt?urWW53vtf_1(&!(To?Wzw-!q2#q0_PCD-2%VQHVMXcSH6nd18uf|+sAQS z6(7cs`rCjcNjVQD{yBGNVP7^80I3h@fX0iCQvskjQEzk z1aLItzvooYf_C7}IDRox0djFS$h0lc(u-gO?Eo1(ksks7CcZCk=Pd9`RYfqnT;zX> ze>Fr6V_^XE68P)J_({;7V?l~(p`K%)ZKm+G`HfJ|>D-IllicB$ggeKzf-%#I&t~R< zG-?9l=@Q672aKu(AO#K3?|Vb<*MbMI3tFm@ugC8OE}8gh?lAWTjIM3mQ_u%Kf}Z*S zNR2e;m)k(H)r_~~Q0SSbVRYc{o{ium+(R&)&VpQ629jeknmS z43J)FOeu4P%@>J9UiJggXCgm4l>LM$fmZ6w|HLhe$zu=4Dr2L-gZU6=gx>uybCcN# z(pV2N*9W}3!)@VCaL2hUei+ERCD8VZL2fLEx;+e-Qdk?a8GL?IK$6;l;~e)QNX7+x zBR-2)f%NDJGtMROL2l0!Gf_stb^(b#6Goqu9SHJeEx!?Z(vy5$7!51AAkc7>o5IZk z9yEqJ+F>-0x40Z`cx-0$$>>wj(@|xt7MB9jeH}BGy&`&0{JChf=#pr?C|5L| z{eqG6gMoXexlC?r>;iCeF!wm{X*oZV>BRoRo&mhgfcsb2Eo>J13e4AE0#}D|TCO5i z5qkmZT@yxs8^+1J#ExUXV7swuq=4xSl6N7O&eh}O+(!`d_#I51=ta>`(Pq(Tu}HjF z^pWT=`x{>lGN>+>6Dy1kk4=qjjlBtw8~EwWAa*f~s0j3)?_h+ifR@+|^GZYL{X3xF zw}#Pj9rUX4{7r5NaBw-aax3UBZkU0#GyPa6`?RP`^rNVneU*IzB9q zb07_h06qmg(Vu|X?K!C959|P#Kbo;o#?S19@%ak$fQMmj_whr)*GApnUP3X5gr!W7+M<+ zN4|@NInYno=A!8$v#5%Bj8EaNMn^_wh5~_0{-yrQ{<(obU}11u=())7*mT~{JTLlE zd{lB&I!*Smtc%PiT`qk^+D3XpGEcHs@}jhh?7XZ*enP>j9#U&GW=)ocQ-7}Bu9~Dg zA=@D7BVNX~now$*q3 z>^T=W8etfN^exps-8^G|^DgsVlf$qlmt?GOIFl&?4vuW?8y_(Y6JYCaKc7VAQZsY6je5m@v zinA5Nt8<)9d>taE*lvpchUF>GXS1~)uKit|j5-(cBDqgz)k-NhoL9~j%ed*GH~n9D z=Xhp#s=S>8(?Uza*`Y?hD~|3}P0P%8>J;W*d;Rj{EA0!vDWB^e5Y3jg(Kk#!lBv&a znEQL?b4eSuCF0yrQ^(_FeT%*+oLcyC(Ff%(I%kCji)GrcEKjBl%f4JQB|j_wg*;cy zuWNjfQJiwhGDN>nIa%6QG=U!)vqdI^GhzGX!SJtPOL%$kMgLQ-ZIyjWY8F{;Id0s( ze&oiHTbD}@I%b5lqH7ALzCqIGsp7PbDT~aU`YrJ%kz4K&l?RJoEc*1ewy1GQq_Vfi z8#|~-Gp$Q~xrR8uU%kABriO3VJydgA=H%pG4c{r-ikESZN2-E{1JR%_vVsqZ6tdBZ zhRS)0Hu47IZNWKhm|aQ} z)617u+4=T&*Q{5Qu7?Wy6i=Jnfd-SC3~MTDQ^Sb6;LvSF+19SG?DBBx`TJ zr+(YU1Dg06U8$E;YfQ#DOPThLytcSCQZO6p@D+)~I4(5opeeM3u+qRk2YIBpi`O}l1l4iMg-)whk z{Qf8RK6$9&=>u2tO7h%(=5^!g8qx;I&3ZKdqDkEbzvij4MJdgU162*gpK*O+MX?>s zcuA6Cy=t%KB|{qY+G*)!X(=f$n?kCQ%y8H28#%|5b_IT0xOMbzjdrd%a`4Jv=l6>F zneR3@(W0o0tMzkD`_b-C(09^32KwPpX?r}Wq6m!`f_cjI&iT>1JjV=pSx=xM+^_HRU30WAoCK))~Vx>tyUq>0-{+ydVzx z+m<|W=Ik#0*0N2@x908`ap;rtkuohaI91VbaqHRbHSKyfx8!G8tJ$XZme-Ug()THL zkJ;br)VJ3sR<#c95x=eXqy=-0`QPU?tvNsY$&5j1M^koL?-<+aMyg*^7RcAgevm#O zZ6nK9%vO&u?6lTS+nlj9qeDtP!;`WTk%NxvTXj$Af0wQA|MMeT9@#tM%!S+2yzeSk zXXiJo-~P!5Uv0(Le>h`}(j2&1I{M1Dr^*fwJ9P0_!TIGyyPb8SH^p;QzZjEK^Rvd( zxL)J;8qd_Yk*&y{mf0n(uGOMvmF41YjFQh{f}(}8j_PVdX;SNSN#^YI8A&~L4W(a1 zjyr$4V>~x$&$*2SKd;@=cW>m>vBLM=ugW6n-I`2puXyN_HmQw9W=55gz_n86mAPk{ z97{hk_IRiBb#9ebKOdaIKBRb7x6Lvy?W3#*at7ASsHLd6tcELdWm?OmF@`FoOWcv) zAMMF0#itZ4w3iI)ER9lLPivKaA*Ge+D>)a*a2+o#ytejKVAsZtAFY3LTi~eW#zNO& zX>#(#{LB^=?W^0SHhm{2sBIIfSJv$6&Vuxl;bTXS>kDpOJ6CZea7iRmy`W7o?6+)A ztD8M7=W_1F++8(VXVysTm)y_1UAsj-S|s6L;%c*BNn^@awNDue%`21h(uSvvOR&6Avn;bTMQyENNKXoETQY}azMlGlv7c;0=zR67w=I{(9`CmE%?*>*7w`D8 zU~K8I$a9ACH7+!Kzg5k4IW2b8{ygc1_%&z$TapWFPOUhx=j7`J`pct=itP;|E=fS0 zWC)o&Nf$B>=hUlJqt?*evDu%dE0SHtE}Ac7F7`=&0rw8ST69~Us(au3O!A`CfoYbs z#VJo%MA{u9N#LofeYa&-2b^ts_`96AhmIe=a5m$HxoUi*w(4EWkEylNUWbu917xBjw^h!!nRzKq&Exb_ z)Kg>=*=?~yk>8`AvX3b`>hD<2rJPQGHFJ1oEN!aw6>XlRD)gfxskH0O{0j|^Oxw2Q zmzTD^b@cMJeYP5+50kpqnb`83hraEwq4}Yla_!Mz?_$w;|IvbjD-R_f|KconJyv-+ zJX>+pFxz5EUXi*YqjR<;Cs4zY)g~h+^^oN~y+jp|q%t$3=OR<5T9P zNivRSe4E}OxrsrkNar8)ZK%q=bK+|G>2doW+5GW(-L@Z3uPU3tG3JxCW;Of%!I_>1UI~}!*>1!`&ilP^kwx=wrKUB@1eu3H|1~B7X~`scAp-9$bR76BQKvC za$)d|#^pMG9hLP`PB3S4_D>lfq*Rzw^uMbrr7y8B#?D7tM8D7#|$=;Mb7ux9;{c}=tB-2%|{Fy@e#bL)c?@HO!ef`oM?_K0w#fkx$ zM;mF{e$;VYr|E6<`IQ>h>%7_O)Q$sd_q}{*!-?{9w(Di(F8?0!80}c|mr18nG#N*- zFX#GmeKk5}RwbV_ex~N6Ynern{ek`dZlTGXL8{eWx3o*&4wB-#+(6FItlv`V8XCzi zgjYF#D9yO}#D#_@J^L%R58C|Tj+ApfoiX`|jGPA9EvK}Nwy$nEJ&#j&^(?#j?3quG zh!1Z#Hm^W?rTo^o%ErE7d}BpZ-MdDO`Kt9uYU`}AIX!ZZWv8T1u^iTx$qekoNWh=( zdo(aJc2as+_ek>P%tvx(=hd&R&)=NWI_<3fXK`9EVrx{=;s$%^$up*-M|Quu?a7^v zGqA6muG}U+)qhfT}$~E=9|cOfw%qM;M3e}X-DlO%aXL$vtO@yJ};2> zT+KmQ4U&&(2a3!AfAz^bovv!moCdrtdUMv`1~0XEx6Q2?ybCsW?IFyrEoQ;iR6ckkL3+_9-(Ky{E68;qH) z>baVFnh$MUmGheRtx$2L?Dl}mi_f+^+w8)tmnU8Q_U7r5u8#LZ?~7RF72Ug5QP!b7fA|GQ(3T18elj`zmiv?%SCUr<^xVQXP=U zm=m%0V+y89vR9=xMN@WXUd&e37+RxVwln=;(k1=d@)=z1z&p;IiXPAw?-ZmQ?)v+v zEi-rSK3`D%6w}&pt;UcB1DlzfwW{ACqm}BLkgD2uYw?v&FFta4&(+Yivg;FXJzCn; z_O>@CIzarJy3%qg^I$Dioy0K z89!&_Wn`zloYdKYqzBC$=0MybE$5$YN=Ghz7nnN zx7$ie*4$Wke#entcCXm8;neH5X4oH!d?;^g4x|mw3Fp*HTclNpPlVfhhua5NeNi!| zd{WsPr5#Flly)yaR{5cAzpFSnSF~Ky%9@)|ojnU=&w^Z8jRonel3JVex`pbx>SWC( z?K)kl{)*vU<8I@R##@FudY5Lps-N60I?eS6|K>a7oL{xRc;40DPbVL_e5~{NH*Wn{ z*~#CJ%~f%RL&>93N1NYQEfiUz&HVe^yIlp&w;h@Gh1FfFKdAQGQXR{jb36lsGXAWr zhwcZLtYl zX&O5`_G756ucjlX;y@95eb3qcCpw*+b!p?B?`?AfaJC?SUL!GmX{j)bfK^Rb?nroI zpoi~KPnx^L>2zGRzh>WWzv+;>S9@Inf8;q>2d>ju%v-G^Qre|;NFScQHa#=_tJL?B zpH7-?{lN0LX}IAV-2u%cRYcK2(MT~;eoH!EJd@cU`!0Mq(9^rfIijk5@$_qp&wqTr z=*p1WpOhW9@AWIW^^$AqJNhBow-s)&g547PHu6ejZMaM5c);!Zz?VD1rxqGX} z@BKM2Iyzr8U)f5ZWiGXjOumt_B(*B_)zk^eZ(6%pbe8Ux-_7++TlH5oqg1adDrB3b zYb9pM6tP(3;Kf{vXe`*(+uPo}e8BCYS5IGf?qc!v@x@cCw|gTXS?Vb!Xo|HDsRzr4 zOPY$FV`5yFm^ykPYzXUvi+uIGqdk*7$2_OJ-}-Yx!Dt&%j(oT3N3F*2wCTLLo%M=! zrnRSahqaHjzGb0lv+*&*P~BL~eAP;v}{iw=_}|dNepB_+8*)pjY5v;Pqg7 zs8MKRP#tOvZV~S5y(>3KwMYK$tm-k4s?pl=gu(eMem9(iry4S z*|#`HbazA+c{rpF7WmcvOa2l5Q@#Vf8~(k4KyY^05n-Z}VtsfS8)mzSFGx;E7sz(V za~01h_9`-ztCh2q66GWXC;w6YjC{4cmtwTydxcS1S2;v6Sw2QqOWI4koE^p-hVzr1 z%s{rQXtnq!NwPFW+F3eDdPg!!{5fmq8*?Mmk0%d`+v1+7hkLpX+Y~?HRi;^26J9CPg zAN?h~Em-Mq@4M)Ux?XnnhJBn*Y!jhZZQMfLb^fmuKHK)Bz;rk8dFzumFYLrQPT<2V3X8z#CX^kGfpynZ8Dl% zhF|ojb>nsIb*r^ejZeKr^^3wQoiAF=Z;FkIo(o$-&VbW@!&l&4>6zhr!Ew`8!xpWo zth7{qU-3yrN@d^5{K~eKfy((+^6HJ%pV)-4`4`*``&0UG->XuZmOUh2_=dH7eRxq*XjsF}YG% zJ;HXtUgkXEkpxDDH^#;@4$(ZRUH*o$y(&rFLi3Jxy>7dHkKrfdQqza#8J28oS8JZN zzBSo;(lXj&Gha3xHVo0t({xb(to%v-t#qUKYxWcVix|vM5mV%o@V3yGFe%LPHTKST zH*{{aHLHHFYHOvka!N(5iqwij6~92c6j$kNSM58TBiu!vZ+*)G(a_ZBDsBujL8Owt zChw$Nr*f+sYUk;^`bxtpt*W zoupgES)xhI$6PR)6x|*<5gr-R2Cw09fzX$1b&fcz3?yo%!eUAmILr+9M z=T0+Pai-KETcPkP1F9s=WNn#FWJohMGNnV`NU^+TdEfG& zBIN^$8L}Ia9^w;hjDLh{7rPK07X2vlYj{;?Q1Fhwk?*Fvk8`R0f~|?|Q8JtY&P5XFj_uvzUunfUE5pj(*{R{pN|@0za>e;N?wvKlwFfgP>xpj(f*<<*Y`7S zH|;l%vTU?0wluY@G@mi;GA=Q^r+-$Lr>(2WQCn2I6vQ8G6X01mwVrH&vQ<690C)nj<(;bXI3At?q{2ATWYImS39DPi_R0SbMAWHB>ywP z*TZSig|Uu&dv>(=MQIDUU-7M~spd0nu`b6j!8p|vGG&`{zZh7a@$ zbp5osnxKke%hP*?x!#CO%75$YIWW5ry5cAq#P%~do~{i1egy6eX3 z^@h(3PaB(p6k*J@%zATysgG%)alPR&{ZZ`f!@o;o77V8;b02pVIg1=V`*M3% zdprA7`$79Hdjm(%@vC#P>oIpDPj_$F_ek*haPw#=24DYWZ;H*bgYx>yw^SwS_S$~B zwt9ztm*FjA6gbk(RL3MUoi}zdHZXjyOVgS(L)1N0Un%y<6w)Q)I->K;TK))UkCjC$ zBEGOHEDogyPx!UI*F8hrKe~Q%Dx8xY^&L7#$X;mw(SFL_*P(TWoE0w4-O#(!H!JXD zs6(V4jM_@(hG>VRvuvq6L%B*-OY^nXt;;afHY%Y{>@b}(-7sx8J!d*`M2fu=UH~)9M~=phoAwR% z>Gp5zJM3AG{f=JFLgzx)XYS3O6koCbP;gdwShPR)Fq0t?Np4Ad%4aD8%AM-&+V6E? zeM@7WX_sk$d7*igd5l?So@ZKP9BcSp_qg^6%{cXgsxgX>W!ohpadUPY--s)XegXPc zZg_HNSa4e4BY#WZZqJ+U4lbi}nj_tD*#4@0ru}F8F?)B%9mhOpwexe=OYY8|KHiJI z8-dNCwuZua!dorWqlJXsO zwWg2m2Ysm_U_5Vn$9&10Z0TUhxBO)O-89B%)9=t7)o#;_RDY_RD_>xlTIe&i5Q* z$9wi+_D}7H?M}M_=<4g3;V?K)InTK~?iaj!eEkA@gWbY~k)^32t4Pv`{wz!d%Jo}?n37o7$YV2&+Rh%QQKsDL(srKmgi_em5 zeZlg!*<%_4?Q>OsSevizt+2{U#MhXav7f?wg9`%h_=ox?dAhiFyL)(gc;>suy8W(6 zu0gIRT_>CeogLlXJ!?GuJ(D~d?_TeCUkl%(-X7kjzD9vDAxm^O*F)35L|2@n#VV6r<$TupEE6=Il*E)6QLHFonl9?A;B-URoJ=BLL>B71`0_y)V*vX7{0Rn^Ou?Ql3UoIkowxxRHj z=UL)?+h_5g2rLR8jJAu-k2=D$fbKs2HU9R&tnm6spXkYG*QhTtC;D3KCoaf4*?!WW z6lJO|nmSsS_FdiU`WuFkrX{94%VtY~g#+2K%JhWMVt81`X~wF*gq2-}ypv=K+n4Vh zyA*yZp!AM)q}mRYUoI;sd%b$0qqSq4{k%=)Z0WLjZur&&o(kqhZbeUXqocouzX;w6 zJQZjYa0LfP_Qu5AtI;LlN#UCj4R?rXF7`_L%X=yNX};Ce(yr9p)DAMp%=y-k)tEdj z=}qg?Aj7gvQ=n(eG~UtupuVY`p?F$8U2I_7(eV*3v>{mLz3F_Xa$-rnBJrJ1t7vQO}=)oKGWPf>7$hQQ#vQlwR+5T%qEi_W?r9hu;H9`tGcGD zhpfG*I@T=OGd3_fC+zg)xsFv96xX<&R=l)wrQ>&JpXw=9Y1Jzo63+#%*QfF?2#kqZ znYsLgNT0y(z5?GOfBVp+=;PdxSbk)EsCW3ANO5cXD?$=3~a1=JVz?mU7Dj7OQcuCQEfyaYz;uw_<1UUvV2_`O$ZS4)>z! z$>oJ57mE*;oT`*~hIuyGx|e=lHrw9Q^P+!hV0PFRPL4Pukq8^)+-E)ZU{$0bQa5@q z_CQn;Z0)}s{3JGzHA#CZ`YQX#&&rxBXRD=}@!EsN)TFw}DJch&omQz?Ysv>TWs&D2M}jAP;{(5jGb0V5hddo^9PJyd6WknmhuJCGC^Cuj z#cIiH#TwXo8LZ9Htk-MIx2?XUGfDfbyDVcYZLK|%ZzV0ThK)af3~8WwL|vlXp|~xr zDf*uO8LUM*MMQ!3JsTW#ZQhD6%BGeqEE#J1(p6*mmB%+qWXnBh)pR>z^2S zHM}zPnSYVr82%{IHhd%WW@Kjgr2hxsi{W8RZ}EGgd{Ha$vl5%^an*LMM6c58%*9Dd zllvw;Y3Xf+{h6dkQYw=lPd;p!Wqeg9)#|lL>O7TSxkk}k+MMmgD`JyFZT&^w49|MU z!piz(ZHk{S9$)^O^8@Fqa^IbcWjUU@{s)4~0+V57aUl?n9E^1jcMMvB<3gRoi^9tz zvGAziT3^)fifmxh#N$OtqIbm2q(c=))cy1w^}p-grWHw_q&$$+);ixh(t6CYB`K6L zF6AS0bAwGgS}jo?RIXF+Q4N*v7qLusw0@{Vpo{N0kJqu(-mSW6d3y2J#dWJ@Ia3|W z%eXR4^)tRJ&|_BmT7oXNHC!D{4nGQdiz#FdSwe%nKNt2VeB}-B(k{-8iG|e|$(e72hqJB&@L7A-R zA=}J89$gnI4L%%v#XH>}z?tIjlnZGWnFp>J{6!h}TK+1_9g`=aPwNks0^O*D))T8$cuE-7lAleEXGwI(NRNclFk zMe=d;bYn+DH*E)XmiiafT;(O{EOBRc0=FsBJLK_i@!C9HT!S2=$_q-57C&D8v7>?a zJ7=$oNhMWP2OQJ=ABKO7yb!$N-S58^Vx#**jYDkckx2VU&FIU~+aZZ>iFZ`+7j6Li zkodT0GkcRcD4s7Lt}QXRjUsbPbGG%ob$rse#1hJJ?n8O2t` zcvZP-h2k5DjQu1wDLf%K5o{qk`&jn|`_RhblK#cVDx@yAd#det$>g#O__2Z$-rxP# z0&fSd1r9;awFE~7&WB!za?t@%arEJEeqgZgF~1?Qo9`>CWDDWfJW82uk`(1Hs*$>O zrjT{7HP1B5SjVhL;Zk!_cO_3uZkSwZK5iJUb7*&J`e~M{2dECo3ndrW$GDr}L80@( z*`bW!M$a}|qw@0Nvv-uG`)rxsL$2+Wn~O8cAGQr~pY=})i6WneehaP)?GEMzJ`P+9 ze+afsTVrFR$ASUhdhdyVGa~h_lH*+Oa8hs}xCKZ#-x6keAF_*bky*? z?v7@Z<{3?i$|cW}y(n2B>dIXTb`R7ITEgYN?;Uf>CzR?-G2bek>Q~ygG~6XP->_hjORUIX_^GqA1fmlg2Vhj2d+mNvWvtAL_0;Pvqs{UhrqhL!rOI=jZLmTFV9^OT>-ypoBG zE1VNp6?_*)haq^&xuNpo;-cHP?u;rIyE^z*+4q+PZfBQ?93Jm4pC z8v;#3b0XEqsqsfCTmBuy3S>`!bW9ldA!_vH0?%Be@#!-CyHg#S!^F}e&|QAPiq!>B2?g=U^`W2C|*^x?vA56+ke#iK=rVq z<|S7vS@(_5sK{gC%)rY5MWkD3cCcBvG`f!)6k7t8iH)Pn0{@Gnvw*JR`nvesJMvtT z_aY<&_W;G+8oao>yHg~%yGwC*EAH;D#T^0!i0A3}z4M*_w^(ggyI%7qGjr|iy?E?2@R~z?X8{jBC%GTU$w!!VW;qX>YZclq}223aL-9bar-H?bK%9AO2jNb16I~5Kb@tqvWrC z8H4?Or5|c}sFUVZUMme{EH_Y}=@eYNi3~QX>J#OSV!U#c`0-qRDz^fUXCl#hwx4;u z!|(nla*d~*XF=o!SRC?=VC`~n-x5EEiGrb)67Paq5dZq zk(~KTki|^eRnzcQ|AZ!b$cFL0W)P2aklYMTQ5h*ioU9T49u_vr&P1DvctfE?u&TfYGR*Y@mt1Q^O+a&)wuciq<&GZF6~uTiYYrQV;)DbJzRZ`F^GE_+2jJM)rWvD`|vwO)IDs*5Xu79j5xV@sxp-LMdhk*{VL3 zW++qij*t)N$n-@2;wY4ciU}u&_(uQQs z_I;9)i50vL80H*C^XQMYbIb`Ng*goAlr!YDk|xKf^YzNiD(uE3(GjCHs=<{qhi&=b zSoTJ>O1lMKjpwW=(NMiGuK3E4ijyQ`(l=B?&eDGZH{uR~J8|iHft9mE6 zQ|;XS9ThC6g=a!XQjC-#W)jwS)3V@-A8zb`eoteK{CX>Gk$OjMLf#o~P;1-}{X`tj z$2YL#wQqJNx#PSOyiU*A$g18f?^N#y@3*MYQDrq zF8afB#Qq}ak%7axdooJ=YY<-1Zx|C@}3dfiu4QAp#Ku|x4~?y_a5!y7T%b0KO*)H4r?{M)m~ z)6_e}do`-H_qaROaot+Oyp)@YUEBz$upeTs=>y~w;fJC9;$+De3i$G5<^GEKnfhyz zuV1jOziHN;^cPuIa*KyMz$lK>){+-Ag$DEvWEsshbmkx+hT1UkbcDWFeXeEbar6k& z0x~FX83k?UPnmRcnmxzWDbf{jDI(}KMNf=kJ+HmPKmqCQX&A}7huTH+SkqI!KUW#% z@e8OS4Jlq}SU5_29ljUb={uQSGri7_AwPzsrv*<1-}~-n)yz1ZS;E&w*#e!)nm{t3 z41GcB=#8LS*c#=>Ga(I>MuuqD)kVryb&X!t2w*R}508b6iORjT5a-SaCE|WW=ZN9n zCQ<)*G*8QD6jRDuKJrs!syoG=Yi?$W6WVk0x%d1n)*wIRs*+i{9X=Hv99j~1o&7zn zP3q_$RWpYLcw7K#_ zc#m~0q@Ob$;dnd%wL)XLfMBz(aUS+;jEaB}HOu=P_Q(0XgS>py0`E)@jVSDVY8fsx z;RXH|JDt77ZbB7_AX}wk(hJcQE)f{+dz1O~*R|AkX%}*92Q0qNIqNg0WL3*qAL^jS z6Z8M)EvwTA`kb18aQ-{4RLc zZ_PfKekFDJ?_#;1{9XNJGIKIJWPi;$7H+M4){7DgjmFoQT`->7GPTiHGK#E&)XpfX z{_pH5T@iESp85ki8@%!_QCU9Qe8f7yw%?(+mwGBkB}bo*=^K3$G_xen?Z|&4oRQbu zl^g{uSNLh%8GIPu#5d47qn5r~8>+6A+esZmKLU+%AEkHy^)a)K1%Gq79JvmOAkjFDEu&D8=E`u!+ACOmJPR6h8gm>qLN?|zEw7t2uRKJo94eOkDkGSh=V#B1yM9w> zng4Cpx9ry0$vJfcvy|%W1^f#=rXI{9NW+qYq=#NcbLeZxe|lc^x_B(u$$!%Sw=|Jz zxGId3hJ1fvzGaQm9J$3a(mN-rXiO;PWbE!3!?W7G%vr|O({%uL72B;3g!}9zyc4fQ z*)Yq$f;;|MTd8eV=Slti^)q+H0yXwaGd?Q$92M_D|W`^m?m zQ{Y*huT@g+OY61cdJFx!>XZwHGyVPjuYxxDFs;BAF*(gk%>heY`wrLE$bH_LF(|fd z?B$p>(V?h85yPCh_G^x8&~EBmikSZ4?%*W648K7WnITMonQR;&e`phw!=Y+9wbJIM zMyJ2cZWmbML%Hj6+vIG_P4ssZAE{IIPsRz{p4-AYaW<1izRQfN%;T)H6IL z7#sLEG*WUZRdj}JYaVDzxAD%?u535*?C|c6cE?nU86RCSYLBNt#0TeZ`(#@e>nC$d z(;-VFfr2o})v0wm3FCQ!F9Bmaa-N%%Q!5Nx^-g^H76JCvCac=6~&*T}>kw zcy@TG$M4zWy%=>nIw`uOHxMz&Rov0ncE|F}w41NTb>X7;9(*INE&DI4F-|&7A46{$ zpY{LbTY;rnwbN|BKcq9+Svl_PP*GUmqYFnUy71+^^+ z>VS6x?%<4YAMpF#7k^2^V6GZ_2v?*RRVu|xg~i{&tAXM{Dbzs95VON;#NJAn)WWes ztmV7CbmW1kgE04XhJB#LQzCLz74E$7%`{8c#&5-| zA-#12GM62QBs)Tx*;ms0XS~e5n)NxOaaJAQhtP;{j(kU{s%5JuHJ%n?GH@yG4l_;H zmDNf?(L*;Cz#05>@kxyn<<^VRjz(aTxP zwb(h_anRA<(Z;saT;4QM@Cpa{H2%1-h@Z^=&0S(!q3T8<`d0m0D(x?w6_eRM^G0^h ztfo01effjIP`k1HZOc94=CG?^9qbw&o!c#2%dVBpWq-()e2s(E#rf(eZK7IJ9j-qi&0tj9 zA^)h;0$O)ah|bDC#iURt|Dl}4xebF`!~4Z$;#cV}eFjPto|_Jst63`8ki+U6={(~q z?QZCr=iKdF;e79ibY?pHI!oJcTMO6}YdOn)^DXlW(|_D0{D4houd>JS2XxC2)cWD6 z{`!G~fuey|zK*^E!2uEj`KlCUC|u2Hy{^Jn1Niy=2=E~d9$w1rCSIMl1Qg2ZUzY|L-lGaM= zr)u&JrMuEwIjL3A`m0g$J~3I$65C6ILKpmH1NlNJq3U8II5X$Sic*Vy!28%y>}76; zu*5XaoMD-2m8~&0)qdC6&0Qv@ua8;!Iz-Xf_+) zVM}qV@DNJXu5zsC4o?pE1$AmcI7SZXMQ9V4nHs61lwy)iKA=5XNtBIu~xI?*viR4d+3^f~pLGkXO|L9dY{a&}nq~Q6?Pl9;U1l9)D`9J7du%&r+iqQ9iLrDso#n!~ z3*HVMGCz*vo^gXY%(2`iEEzw@IK3`pwKl3-p}I6fPExOFZ?%u=I%T352pta>kne(X zWs=lIDWH^)E6B;pJ6MUEfCKylJlp1S9pxav#6(D?GQb)r#v^~n=hMN0Y2y! zyjh#9E3NM>qb!-0g4Xud!BEA0!z*wK`J2(0u6PFXGirdTmlJ*0?P zQa9;eC7%8RspNjRsqn;Xwu~}|%}M24LR-*E zv1 zKS_$x2K-X7T5Y2XUWhv&li@MWL#FnNv4EBa>cTAJKibxqVHAbL`Bq4XD@G5zj=#WP zNhxCmbm8ufKd~LzLF_)hgOHCM%M^q(a${zz;l*89C$clmaebU@ zR3snuot!@Q-j zWC%%SIzv|YGQLcI6V1qEZGLSF6fk*wa=2txGYb}{vH(oF`P)nAY&Re<*nRpgF z;rfv11uvmKR!=d)>>G9-eBTJ5wM3DnT4i`o&OnB@9o>XJ;vei6HU^Jl8p1tZNk2f1 zttL2;8fg}NA1wrTd>OY$*uqc7J5YCaKT0B_@8aSV&7!bUKWcNK| zjxiLfjthWb5J~gsz2W;Ck)HGeq>^Et#^<;Nku_wZIfVt27wcoKUA#@{wLUwx#5 zNeKeuoxCIij4{kv6w7X558~bEf5eV7be$;z??-FBjQ&fnLLTUXK3ChM|7qMuEw~HZ zTedwoaIOgVSlMU@Z|x_&mA;oI8()Y|Uq%lwYk`nag*ggLkN3bKqDU> zgX_SVzbq>%-wN&iA`k_)f`-2*a#fX3iL=n7ObUc(u^rqLJp8f_p|-hw%Vtjrup zlrLtk8|#gEkXauHIq|D#KDh53ObXpdwrXFssrnk-NjssoxFz!&rE^vIb@&@|4dr1@ zklnD0X{B!^b&{Ae7D!?ox z8_7{1LEP6LlHW{s^cNjOrqEd6b(DaleM4iYA)&5pS@afY1?hAKWZ(Y+l1FQNk?n&D z0g<3Kv)33%zv-%aNG+zv18ZeA{bkHy-}1G1H~R(p!=FOWjU;kT6UYI26?Vma*aqBB zv@o7=1`X;{mFI;+d(a1^$MfARS$UZ)yn) zj1Tk$oMvz94X8-_GSBg7j_1#_&0&3-WK1Uc;a%HJX3*8lOyp*+(P73~Agd%WdC@t1 z0Uu{q@V&TIaMm7SywEe%gK)>%s2#PAP@hO;i|`}(WBf60Ka%JxeYI9ptF8~HcZ~TaN#EM+Bk&1AUpibTEMkw zj!NUw%pN_DK8Xw`Gj&Yv0VAY7tq#?snWz*VjNPaRu$o4r-FO@#bUTF(>EOIy3HPTp z${2hn{&1c?haN+lU~VuoPf#7$b2sCLvCHrg zlm$w$k3J*$^y^v~Jx=$KSIlZ|IhP+io+phRv^cOPP5>W-1AfX*G=~kd({KSa31*91 zdQ-hPjNWr3AMFb)oSL``RON4Q4`B8jZVWLF8ms6z>NolVk>~+!0dtWX=C7{s$#D!u zYw=rd2wMy|IJfaLP!+zAUO?km#>@ep(pzIEjJ}R^E-6eru==m3w}4IZ!bkujj1_Ny zn(t&FqG&*KT4Nw%3)E&y(YeMvAgi1}<>AdgXmn?e!@DvA&YQR4zQ2HbJdnu*CQ$`= z8ynMEFtf$MPU8?Zvjbt(sL3Yd#%LsctD(aNu?1HDE8SucN(SR1{!F;UVBZZDfizdBO2BLFg|8xCcxn@T2FD z&a@ivMw%Fnm?*Xjw}#`n_1qcG$vy*i&>A2b?WD6v2YseeS`tM?o~!g%6&=Wiz&n}^ z`e1@FPrm_svcd9JvABFpxvK0`$LWVjir#`G8+)0J#%WkdchibMsoKL#2maC#P=M#+ zb@)4GVSoD%XX66!){W;+3*AgZO|mdsxFQ@g3D%OfkmaZ_gB4K|v7@dLSuxIem%&+~)LD{LE_CRZPOtaYfhs->gQ4d16DG#mI6x`vO3UWHnR zn~B||UvfZGfdBG_6a;e3Rj3GjRRpXo;JOo4^DiP=vx*Jtg?tq|-ZXOW_88h4w` z!v(qT>`UXO9#-0jM+1F***TqZKl$nfnQ&9-x3Wu%B~If6a|)PFQ(yR(uGd^?9qRgq84YQBuwhsIwwIR)si;ESW2m!tb zpMqhvAgrDvj|o2xjthPdqz4LuI#)ALGFV#ds%+5?kw(T9CLUMhw(`ZfrAP$-^irjh z*djbjEG*|&lZeEG*sMPR7oWQ`=YDRPfFoR4^1wB8hV}Cfx(M??K3Hd#8p|PrZjUMaMO=*dR?ELQyiu2pRFS-Bh3X&8%;UZ zWVbJBU+nzoxe;@$dAZ@FPxxw9<=?e`&Pd&#Iydcy?}*q_`^A_{$IKVa18jXvFc4Eee9esI=hw9PD(H8*EjAiwmtc7P5A1)u`Eoc)fkGR2@`aZ$M;|CWm? z_vE8;l=4`uK&Bee2*X)*Id_-OWBLI)fM zsin9s^g8$J)onlft6SWX5Snjy!{PzfvsFoQ$foL>p}Y! z_pc}=Pno>)^UjIimFH~imbiOy7oyzuOhyhX8J6#lK3P6&d0+NZ>2K9Cc7(g&FV3TR zoCO*b2q#>L|2KMrYo+-Xb692qMROZxx6Hhm5s@`M>rU3V>^#1tATP}Y57SwckL%0- z7W$dW^1IPqI2#w1<^+pF{ccF`a;UOYL(SDo8UH&WbYl0gx7k)~YdDkjMi-gWz>+%y zr?vGsl20}Dwnl>Ys$6uBxSWKz0$uW#&X*_QRb00i64BJMo6Zk9)AM{?{jT1-7VqDG z>YJM8>qqXHK1FuUJF>v=f<+2k%y&2TmHV;f25zCf4W7jNKO6GA+^}Ah3WTl z#Nb|KnX!O7VybLeVKJHObK98Op!AQDHiR|@<>1heJzNzk^k3z}N?C0sXiZ3^<7b@Va7*mS_yO$Mo6u!F@Z*o2PW%%zR4fRTVo%d7zBl*td`Q=^f{$Oh_G&hRMB?A?* z@2455@!var`<1fs`+yhf9YghYU_9YgcKgvAN-^y)(@U$YdKln6o zANkTu6-UgHX`4w zf_)1o75<)oPW+qLQ!(eglN@RIqr5k#-%oQ&v#)Kx?MZc{&GmhkW0~jX?Gc@0U&rsw zb0D@~lr19UbXa6;(k&rhR?lDMzW4st?#s$AT~nt0*#CQ6&UxuRlb^p~3R;TTqO3bj z8+Z@fn@(4$+(h0YCWOWWhX#2_B9--z4kn7P<&pXmqYUoGRS=4p#)7`P5IAS2fVMXi z@8HUrzM0$G!p>gaopHPK&n@_0!Ttq?>jNS)8VH)GHdp&^Uaa{e!O~+=3JSPqrF(@MXQ4+F7a&weImgA>0((sa3(d|lq7?uGifKsL~k=sg?ePnmbx&O3P5P4K-J0awl8_&NCx6}X&# zXF`+sWieTiN8L+ZEuB8=Ilc-55u4Cy{~}-EoXD)W?2$e`xG8*ENhPI$Gg+3=&{LQ* zNAvfEqQZ4{E3?9=NN z|1W=oI|4fTPP$I3sN|8aOAn<~sj>W8j#Cn0=Tl$FRLW`niI-{3z7jOcQu_mE@rYvH z?a{Mh*T&yZxRfw7@5a36^2WsNiQXB#EIQM3z%{{og8iws4c`rZ^6v#daqpbzx$eOC zP#4&pypx{*w~N!4(!)$|HZNC%3jt{_5^7^r)pYq+xNPW7pitnw-|b)GYwtUjyEb=M zZYlrJ;Jxq~`JQ@R|3PMqlLWS%}7>N}@NKT-%hJf-yf+D@&Mept(f999~hdxdj zF6EK#hLeLm{A+x3AT4vnS2pl67!0?Su`)~ED{oVFfZF9D>GUg{xPm~Z?a!=+lX!KS zm-eC>y~cFM1KGRmUalZNo6i;=nlD-V+Z#B`yXQo3o>|^qQEQ^UdL>T=P~)hlk9V2( zh3BFBtSwP^iQ*uu`%#UNON;U0BB7dr;(=v>9>IpeI-!5U<;6F^G`XYT6d;1 zN`%vDP%Et+gB^GUZHjtIx+l&T--btqi-aeIP6SJYs)gH$4W$-JEw!q;6l%O96ap*s zSU5#pBRlCvAbReH+SqQWFAoP*G>0#05+Uz>&OF>w#d_3w#d_T4c9d|AaUO7Obhn6@ z5m7BN1(JdXBkDwKcHeRSWuI*=Y3{`hhRVSUx<^Zwzso6d5ve06q3gm!f)4{3!41Kd z!4qLcZlF!q9%zHKDar)7w(JDwT!gw$`$zi=++!;=Mtv#Ik()zGI#%i_{UcWaA9h2@ zDw(7+;(t;fH52|U)SM(g@KaYC!-3b@0X2iYcmb%nr1IN^9zqczMZo6f<|gL4mIBuO z)_%52c87C@^NG`NR(ExDCq!tj4bGa*$&NQRVy$4aS;p`)*zW9A<|t)>!-RR)q@T6w$6kDg6|?>=TR1Q4+7b)0)#mL{oKe1#M6&$X_6%vP51b zCn}@icdMmLS2lw?d7ivfsiZR6L8wrMpbn(co zz7}em+M6p{9M*tUwf%w&Z!za^=PKtU=Nxc#eztwGjkg!KKeC>(-nDK4uRX^%VjG}D zI+;G9rO5|I{+C&!2Pg%5>(h9ZDp*jzd#_7tUXUdVp^B|eghC==A)YOGouGOZr9 zv%;#6wAtD^tpuFZ6184R2_>MkSH3CZ)M45os5cD*_ech*3w7(cbOe0|cRd4`nnR&t zS_`gyHPA`pxP{y+&d<*=U$)kZua6wSr3rQQL>T-Um zrF2cYBF%*Rc|bd=kJG1V#kBt*FTF$=t|e;|wS}6SUZVBrE;uhgBxA@NU{+oLpIvQW zx88x8;wEDq@WM+oiO7kM<3?VgJ6)P)Syana@IRimFR&+BA6j#) zQ*5QId9B&jN9LpEOmmdEn6Qys%!_O!@IGy*gpmjITveCVjq-E(o6=Q@kvmJ9z$LL? z{3tFG{}A_!nNlt&%+r-B@cT7an?VL;pt@Y!s&CQ{>#yKFo=9fsmGy;s68yapT}!8s zqA&+_2a@R=`VhzpzK3a( z$!lI|&TF1y9&R20s^~8BD05@eUC8{lGgaVqwh$NK4&q%v>%9n-wcbGV4Ukp(9?han z)(Yu=>;J&)OVyvs79|=KnQGc=eJ;76rK;n#idwd^OD?E-$x?Du@1}p$+G=5CgxXl| zM8f1PvC`e-ivF2ArWJu|yT+&hjQzz-ebgUF-Q9qoI@{>X)Io{BHa&&j0KK^gYXjG= zjl05)#3}eVUzIP&DjedYVg6aqK4yz^8+nae!rkK^vE$GJypj8avyA-sDtiZ5+Izq+ z*n~+in$u~#xaeAi-ADKdV-~3MisS^j@Hv zJOOw9I#Nh~M7kLl!GHLfd;!kle;U;#$IcHJty<7G!4QszMnwgSuHk_zSd|-?$_j(0|hF>_R41Pcr)P zNvJN(fO_A2ltTMMm8dmMF~%AzXbn=A-OJ`^OXyFg8PJpS7>n7KD4wjsz0oH9h1Skk zh$fSAT0P(suY)HxP9F)Lvc2>=+5=UO;>?BX z>g-Xv&RB^%qwa=}+(H8}_`#WWP=j-*`zX)H8y}VGxHDIr6sC>X8SGZQBk{3=@qF5V z?%+D|HTCDP53Wsi1IK(TBwxnU15kHtq(3uW;`j6>+Q;~z-rtg2BmCC(0G0j*J3xP= zv|z_^707n|K3a_1E02E&5?JSePOIriDz&`b(*$X|UO>Uz6u@rA*Vc%SuDE zkvofa=ozFsp3ZJ24@hlvjVVqm>I;Ms_?9%tSj!*ARi$FYY1+v~sqKsjaIe#~_2f2> zP_Fm{9}#xaI`S~~fXSh~S5)Q*zh3{P?BH55|7chBR$Kv8L-~wnnHrE7trOlNYy$^L zbGD$lVE7foInw0za$Cy)oGd2l9qeUjpHLE)YkjOX2_~8+Tc!dJgmFwaqu`&~QRe|; zmADp_vUUPzz(=l*S(NT*KGRb4TWerMus30rk?A|;EmZsK7=`h5y#oHp)Kv}R0bZz2 zGIl`nrW4IV4UFmfPJEu3X(Z4c#vyJ#>8LtcAO0XVW3KS+^%#^!uNkSJ-M!)OtKC2` z>uq>xF5~5M^v&`O%R=sw)Qh>qUnU3DMaavQ)4OXQ`Lei+woYwm+QA+b`y0q!m)w`$ z2;GGd>Ja6!`98nYKL_1$lrbuYhT(;#(`c?%Q2Eo`)+UHg<*+Tr)HK*!e{46SDgMtW z6ycP+=Z?2Guow0(7n?bznm-42%GCA{?+7N5eD*C`Dd_{Z8x__!(}IGDTogC+cZ8nu zXwuM>gmk5?kDDTTyLc%ro^Ss(Oa=m^bQUr2dxY z!cwV~+R8SIeHh%!B-AyTYGxqP9_p;*UWFk>|?rucR^B8tZg4Ks;f5wM5gg z;$PegVG_BgEJN9*+WI4@5Z6R_59{GM@PS^_ziR3DA)BF2qJ{ZVz@M&-eu4_V8@~Yh z_)l=0?qaB(iDS`9EnvLC)zNt}LA?Mukk?9YW-psaF4Cr`ALr9O>Mih$dDIzXsL9T@ zRX#91OyBgAdI7FKs5RxGT00G>-N}#x=%Ws2T5+9eK{Y?R#ceUd+I0FIXxN2~a{3+A z9%t&Wadi&B6j~Zrgs-mLCMm)ZrlZ`1+RQ05Ry_t4T232kECq-AGd-J5$7_sD`U0aQ zDuU{RqIe%~plkH{XeLTv>#MEkeW5%)q%0zzg=9mM11tee!l$fbcA9GHjn#(yRb1BC zN>`z~_ywszY~VRB2+qxaIR}c-qm4Vb0lo>J?vIXvKJ&xq#T*BccmZ&U{?s*?rQRDi zpqIpGSc$)(IZP4o>!v`3nbng)t!n~Q?Y~hY;~cqyT}*Gi6Y?7^nc2`g;9v9x{{aew z#H|E&@?J*5)r^&76rPXw&{T3AjRVDb9z7`7=xTUVZVMj0k$j#Ng$v+bSOV)vAMKXD ziZkQaY9guvX@(uDl{V&YGON{@#x3E8@sHer-OT?1tf5p;*=1!fX4(0q7X1cfnJij_ ze#YIHuu_tbW5;Sw)#iLUQ%75CJjRs0A}>Z=`4(giSxck1DE60TL54n)en78{Gt3_1 zBkkBFMmIgjh(Mb$2TsS9#&xzQqiS)m^LU`9Fhfm;NUS`P5m*t3)<4lJRE+5e^zEm3 z8?iIbP=9LY%j&7bW9p7IX)-Bk-j2t}eiF&AL!y!dMEHH6XXP+E*)2pNacp%a691x) zjFI>$GeFzPa2Pt#Xig@XZ>pD6d!YrU$s|TeACWOoI(DOt8; zes8!CDQX!)%ScW5;=*3>551iID03r_#7?su(u*iN_*X)tbeSYst{Mx)3G7r`b*aB{ z97v3c`qfy*DMpTbiW|$0(0FaQsXLko?ZK{a7uc7|d*d&DBz>S>;0E9v!h=HwU}Y!`r&J8e%gV3it4IsaR%N*hC^MdA>*e* zjXby|;~`U+CFmthqzl12@(kUi4{09gC9xgNWrE}@Y0jn_hG9lsjB4~MjMqKrAqhcN zrxtWrI0~xSe`p6?PO3A@*i@9RCot9V70`}mk)qg5ZqpO|9tMFnSq81bgXwUlf{_fm zLPtm_)I@ukt|T4z;os`JJ2nj5+BM`IXCKqFvJ-kJQS zo59oYoz$koP(^MZ^a?79_86CFE$D%ugMPQ!n8JKOlc}t6s2Dq4_Za0+C)inTWI8hs zfwZ4(OlL&h1G?{VyuheIr=e%)59TIa1e#nYV;XY~G$su=_J`0#qZ`=;UKR_pS1$k> zU>#;BIY?LF_RMIKgeP#fASF_QDT4DekLYeVo6QIJ{!V5n{zxS)AIeX^=%t|Fzy*T` zjqW$9tRL6MGUZVP<0SML`bcgDwcIjXq3wwlF@(?4tXLiS$B!xHQ8? zROUY%$JpskqdqPUpB@Yv{uJ~J`b%_T>VgCPGxS;ckBou4`hoF+x>y7B=qYFn^h=m) zv}7-X$~6+Iz5VGb(wFIny3#s^le4lbK=V6egm5$+pl$`{)jQB^=YtcZljb&B;9Q`e z-DZ}v)s0{JS?EJyK)qrO`UniJT1+KQHwuuRpohEz>VJaqnJEn^i9SpzqZRli`l06iq2J2`+Kt(T&QU9LwYbU5qJJ6%(QacjO=7k~PndU<&<4hA$Ss zXTqTC<}` z7)^EhzwS9d=t<)u^!n%xC&pHk0T0MjV!Z$$Y5pa&o zMPtx0=yJ0M)ZI+bMq1$SOncBHuW=o@!OLr0*N*IAq`?iCM7t$~tNT)GMWoFrFL@~d?aSz_$x107`toA~#jS-Ea z?#1Y_Z)09Z_l%wu^D?#{BoYg`(j7Wn(@d@&rp#&Z<@b}0%g-RExiUN|tOb?_-$>om zhl;L>kam$sA7eF;s>;!wWD@LfDv^z_i@c&%l|PGm_*SS|aA&|3j0!yPp9!oF6%N-D zPk_g8j9gDCuBGW?{{JmK#NFU0KrP<_1jb6{($-J*Kiq8~^X7;?8*;5;u3CothtxTI zJ5)VzE_XrB+??^bwfw7td&12n;PjAE%n9fx)Rg%NKDlDXTktcE#aW<>`C*T>hb_pJ zV0YjnTt7=s$02uKZ|~Um30D&i#?_4aD{_!4#q455ATgAbJmF~Rv1AcJaS!K&s)Qbe zFUT|1#@b@S!j5w=FPR*sUEC7z8!ceQ5~Tlzk+xX=Ppm2;F){ok*x!E=6qsNB89@?u zD09@uutx1gpVbUfLY+b{f?I>V!vm!wN<;7rrV{8p$QoQb;Wf7w z*F;|C9?%2ZY8LeY_|uUxUkSbVnF*bZYWD~RHwdxp+qo0`5>@=P=l{S|)hfHZg zI==wUQPc1~REB9zH|Rxm7r8+j8I57Jm~R?o`|fxVaT91Chdj4k6CH0Y*<3Z|t=>U- z7Pf`Xgjd-{;&nylQC=ZQ7pNxleO4#kBp zh#lk;%4}^R*-YcXO?d`-QRRaBd5eBXE2aGj6}kQDQ|++Mz`j2gR*e63E^NotHQK@4 zzaOWtJy<(u=Zlz&Lk6RSI~~Z0XY8NMYs}^O=FB1Ovh+P92T#hcbqC4NOVW4vu5j9v z7y5{-;`?#Mz&(GB?TnpxF}lUn0Iy#X*{qZd&jr?1u5Y`)N$^zoos^)~Bu$~pw7}>G z1fnCrr|GIRR4S_}>RU}F`Jo5X873ciTmqm`6okKKL(i=ooWk`IUW4NQ!!iJ}S9jcR zJgHF|qdrGGbX2nDH`PXdbx$ZUusg6fI9nVjFH)=O$k>OEa{b_n{$_`R7xfUDhALqK zdG+q#mP}!4(RYy9ofP<;yCo->H7NUU-^kD+327g}JK3Cp9-77p@b{im+9|h`scJoK z2^kBjc?lMAAE7lb=E?(q?G$u+8pPh_QiRjyY|AWLA!lWvk@WU{jh-0O!n4#71wAny zvnTYL@;aatzX>LZZWwu@xJi3!9EF~1JHQ857*%J2upS?R&SNbQV#l*HQ7m1kos}nr zulj?)Ec=>0I%l&#F}zf2sCL$?L$!1WbdGzj7to4B=_i94Ci|Be8D>Yy1sJ21sVlB#NPh1q5MD-tD-&E z??e8(Jre?VS_X9A8Vr3J4>J!@FSY~!R!~jv&G{|EEGHrHv(>WS^33wXQr?`s6%Q9(KITAFVq~1_ zvE5_tj*F30xm);Fa9F5u_;jdxI3RV<-h#(w0rXdlHJXCobB^9XTcwVH#Ls;-O8c!A z1P;vs359nDD+TujD)@&0olfBdW+#OvYjp{UT4 z;Kg7E@Ge{l=7buHSH$g7ZP4}V>jTJAx(zzH%|q4LF`UHJ;(1|<;5F4Z?KJV`e&%;@ zjo+=3Ez(}ao^G%1JmD%7F+K8;r-!$Or+&l@S3gIlnc=E4EA<8PT2ToHLZ^dqp`GG; z*{pTZ^MOt}gbt;r$s=$Z4gp1Rv9d?`Urux%B)1EQ!$Ei46*>?EB6>gw?hkGY-3p%& z7f7v?RazWmen-$}h82Myj-AUr2On`3e_qf9y9t5Y>Lg^|PFcEwdNkX1&R)%V&GpJX zBcckhA2)b&Bfh&jItto)n{KkiIH2EGEJ`nV9&n6%i8bU`N)4^Kc2qk6uGH4rZuO3` zT}e>B5Z)bX0d&d}!TjM!&}iJ!d8xSa2ps#TVLq7!?257I z1&-%5ZaqI;h&J^$4KW=z-7@`Ss&4LR8EYMDt!(?#E<3I`+qrv1SUj@#GMhRRmhN%jGi zbFnl5l)BpD2yrqnx{|_2!~Mc8@hb3JPs>k$@sU?A0(wzTV+->V?Z*e$=Ae3>=Z^?Y z;JO}|Mwkm&oYocAXVy>F8IY+|92cCj^Q)_tdxd)#I1i@6TG_{J5e~7<(0ghI#rURL zUD+%bRQ^?dDh1X5)c5Kc^)WaN%R`m89@KmG%M0bra%X4-oguvh?%z4!s5KJLgu8?X zg=d9dg;$Clq&OLLP$f&9t+fOlOd_x8dr)NTxF5Tco5e2@2Ags~lj>-`Z{{ssEx#>G zfUY#wHp!ms$m<;JeCKQn6mRToVt;NeZMh=!Ml6r0C`#s zs2Qq7I|C`or^-d8F;G0t%g5yc@*cRq4WwP-VsVxD0QNj}#Uo<2m;{=kCQXwYgW{b} z8=)1~f9ec$wfvJA2Fai%>=14kPvF^p5DX#FwA)k+nCDB(1ue%cXRH@(qTS_8b#8ZU zbB%O$a>m~0+#gxR4R60Sz7f6wzSX`hzKOmY zScw&tlS;V%g1?j+uVz3)uPyjEH_)H9>3fW&U`pMBSKuVzhsV+HX@;o`*T3d$DjUa5 z;A;wD;yKYIjg_`buVAYCQtBrK#SY>fA%#!iHnY2!Z*&6n9KMF1;U>Mr7-B>l%aK{w za04F#%=Og34fTdU#P3lSE5)&Ee*stX)|cp`m2{~4r}-Kx7crip{(4X?84I=0*3iW1 zp(SfagBA28x(HTL8+85tLK$KUY6Rn{i%{+OLceAPvyWI{V!2;<#=HDkek*2rgs?`~ z3TEUk#OiW_4e@6NcaC*4QA|1dF4YC>77IKfH{#^32p!_@&;pvTWd#PKBG6d1`#JTh zzq`LD)W1@2BNz-s#UQN4i`c7k{J+8P>#9CMcYkl7zIF%w(5b-_!7lKAtqX_iKE!Dv zh&o0-YCYUH8`C#1ihsc=ti?2DIx%;c-fS7p!i~hPzRI8BPvA5;#rNf#@`dB>$sQYKZhxQwClJ#1B?P;JIcJ_UBtJ+tctyaK{TTv${q5g-w z@{^xZ$EdOD5=5dxz=Wg(8fmM*LfD7ro2w^);qe?9$}r@_Wl37Z4$tti&noR5k|`MjkL{upa)<%jlkTHLwq>Km+0$IRn1G z^WcRV5C7mVdTUffCxAO8ffqFx+VGaobzSA%t>p$@f-3?SEjK$+=Ibbop}-3ou| z&_OCMy^p?$l~5mFn@=~TpM(9ioEnBPL~)4PPacE6XjPyM>~L_Mjl8ocx+}|!e{R+> zh64_?1N8j53>L$t;Ck$+v%$yEsQna74c>xUiwx|B8YJ{QdbC~@_s>RH&okf+yi1=4 zM$$RB*WSausI##WPP7%_n7fU52AAc0@L66D-_{@C6IP@e;fClSU0~pR0@6M|b(K6q zE+$Wd1=xmsM5=HCEl7^X*IJW9!4>jD_vxP#bw}{&BEXeA1Ux_sD6`1m<^9&7W@gYv z9q>K`bUXerB71}DB*OQ$9T=0hkWpFTK71cou$!3g|4%vCiswcy*m0$$NBjA#k`_ci=PDtybm`1!YZqfhwctN6Wn@jdzQGZpZB0`U!AvmwwJ zy8v!nE6hg+tig_O!|nl>;WrqIbhygzHD<#fI2Ai}1bpBBIUhg5p3Q)l^KUSXoN%${ zur3t%)t7-=a5&~*4E}b-ycS0f;tT4Z*WvbFgm{b3%fxS?@&9!EY!Do*k9a00-r0ju za$ppGq0(K4cx`mWsoWJDH7C~aM_}2~@x2=6@&#u0BxaPre_c0X;3J#^2#d9NzT?13 zv;YrpIp+Tkp79m@+(R)#|8~J4e8Ocg8=Dm&?Afu4`=#Z zL;~I}4P#OYPQ4;}BJZFJwhA8OrLYc55cAMqz6`ZQGgyH^BbFfXB(pFJ4~!ugMFJhx z2+VLU+|WxCKk#I_Q60z|2kQ5)@zjs7${g_UmQW)*jlC9!*+Wedz1X7gU4Mg02ZQ}0 zgF)5?YqdQw0KJTg7{!K|pFY5mR6s8`0<#b>>f`-$;%%;CX03Q46Y+00S76uZ7;mf5 zj`)MoxCFP!Ow7%{wYV3f;>2D#4qxsyc)}PUb{b&)6~YK~f=_h=yh~YPDOUYOthRUf zoOf8acCd7_4L_b>5x#pJ>i5^Ni|eA&_ZgTX0+G~?HM0!t%VJm;v3TcbJR=7_YI)qp zi(=%;Ap^>R)%pf&#)`PXqPoxH*;}KA@ffT96PT-af$({Wk?Muf3B&HLkC~YS&Qdds zX%~D#VT@jT%tu~~TT9GLE<9Upd^$~-Fq0oJLd&pQt`qt3{Vg$qJu#klv3F99sc^Xd z7gaK_`f}qpd@vM@Q$xIy2J}u6_SDG=PTVZ4rQ!eoP2GuK81*ff^=;rK z7RN}HA;#f(#t^F0)ASQhhIfEbLZ(-|v)M@+6rY{ff-5U;SW<1jYO@ZN*4OKKpRe?WY^hqdt* zUfXx^T!rvN7qPOQU_TAQN-hU(acQjLO8C4Yn5Vp$qn~)QkJwpRMh#Sw3gDT)Sd$y`W5a6YF*m2Ny9Z)7uE%f8i*dGKRnvIKB+NrG%*0=#AL4rq zo^K3R)?hqiCya6m)@^=#?JMTypT^cAtWpcSxS#$%TDdUt_wcq$5$zbfqm1?Q5Tm;X zYc(FxsuTXb6MlLq@aArKxQAkv6hs=hz~kAf;JL3O>maZftK$tG;e@J=wK*57y&Lw{ z2mIFeh^2e64@)B|UBb@$jurI`tC_}_K13a87gk9M#^)5?s1Wu@DB_bD@6rje^cEt; z5X^0L?BKG9vNQ2yH4#NuVsy3=qv3JSBT6;Etlz`jwZfiqVQ=k1#5e`6>UE6rAH?pP znEAtqHaCDhS%mw_d%WR#;~G}bK73jf_SAVJ8FTXpCqxPCfF!Ke?l}7zAV=$m`Fx45 zw#FMpVSFxOXWqj|ea5N11I$Yo&eH_^jrxD|If0QFi_`4}*3M|mvyAunh|l^17xXC@ zwX=xU7r{3DY)nON(ExiV-dF+_?l*kb4PYTFVQ22c+DXLkxQNJ6o+t~%%tP=*C*m|s z#H!ecJaRcAV=Jtg#zbH2>-fE&oFDq>kzRIVg2_o{Q7F_fL%EKJ{otyEZd1pBMN6*U!%eQbBc#J4;AD@ z7maWD9xEcoO}y(stmio3IwOd1%uzgkb~v8>Umx{5qHaHY?m;}?2fT@bXP=F@Rv1rR zn5Yb8j(mt)t+2NUxMFlgLO_iVW9ib1}XUWMb4zL?N7m ze~>f9<2T;Gt~rbu+Ks&ImeCLE!!Qox)V`0%+6!EwcNjGp>`Vp`@Gv4eux8jV7Oa93 z_??xp$NFIfOX#&`5N2aLK4Tq05!-=Dx{P_U8?iXK2O)bKLafBTK8!Uo;9n;n^F)B@ zPvAR$8Xa+J^uU_jh1I$V`W^%^0CR8&r}H3#LO*+lQ3i889CJkzx^d1}h3|fW=T88N zAvbct26!J}H1XU`5Vr_COAx2pJEI4(pCs((@AwT{FvgV-1L_fva3&{WzXUMLG`{QK zsGPzx+*pB zR5wsp?@tWD9uI>aMmg*>3+|AkFvkUmVo=KHkM)v>Q#~K%b1(M8ag0JKeBwfk$tmO& z8CX{Y&b{hH8lL+-X7D@m1P)Ogj(hl*W4P-)!b~*A8SF+3ZAVDhulW%{qVNebhy>)_ zxACMR{;LwkY5-PrF`N^Hu{Zx>m;FRk%)}^VVvlx5R4ant{O=Z75OL-_a{Sgfvx*~c zdxpSZDLnJS2l3&4ne{{PvUf)!Z^ zZ!qNl=hJ4)>0#`=e+nUe@O_O4H}Mhq&>HA;eTMdsMhpV#;2XH(-_VUY0hNhNoLk{o zQNs{F7D3%22@xbe<~SB_xDB%@ z4q@>14%iD$TxHtWnT!_qD(aY-7f>nZbG_U&Ie;pN~HvS-L2b5ApIjRuo{Nz;EsvgwgeCpUh z67UIowEfyOt#>dQ=!M6)e~toD;gGgK%MPf4ML;j?3Ob;rI)GS2y<%Q+RmEd+FZ0t7 zA?$ki0r=%5hF=MDgw74E7?Q(0%amyPZF*x~A6hX~G{2KhiTk)n@`qN)f6L9-#q14P zo{Y@&7MY1zRkKsAmmHHk$9<3eZMFVJD#LYN|)B({Vz)SQr*u;bwsBc?>Gjcl3YUC!{_x$_msyEJ-U#Nd#pd;#O0Coy|K zYR;q{zpDL8`Smv`{_lm19+n)AYd|^=XL1N{OzXnBM|Q}Wk+W)!(cv3R1$l+AszFZ? zd&R6(se_Yi{&}7}Ev1>zGXQSYi& z^tVzDc^A8@xTk`#9IlXoYDNdT5Bo@XW^Nw&A?KA`d_Fzj@H|Chp5=_qF(AB9NL)z8 z@c8hiVav=x;WAZ2tK}O2b>d&igZ}))=ax$i&)Vv!>74WieV-OUwh_R2WD`oOp2bw{)tW*o;oGtYxYjpbY)RsAefcEgb4YbX>~}g zkn-|zVI-GLJ=a$S%KO)Nsyhogm%BE&ce~GdPeM2QEL1gr3-`?1!e2+FKxuSk%$8i% zT*IOtMw-I*$us%Y^iirlbqUDZRopH<5}t4!nG|Ag@Q|W7DVxV~C7ZI@?ZaFzJyn!p z>N;(*v53mW7T{+Jcf{8cY4V$jn?{PS7?QZF4)JWWf42lO7NpDR*=aY^RSW6f?2ihp z4)!H0vb&VcD-C(;4ZRNsd zF+?%@%{Fs=b0brJ`GHW1tHLZ`#`-JtclqzzTx7@ zsK9f##s1b>!5VF29G#sH+^u}Y{o!hYR+ucoj^?YPXH*hhtSM45pP#Oww^Gk}UpY(J z)3b+Lre_tj*sL=gb6j!Izl#DRBLVp7uhe+@INb_-iPmICVxci2xK1_sNBNzKU&&Tq z1V8Dkp#RdB7)#ct*3$pcX;dKPz zi{?Sl9Ie3@XLC{CgO&Ui*B@)ktZV7R(r%_T&nTI>Kl4v^758+tukoHt28PzeCG(Sk z?>Wrv0>bBvF+hI;zt$wUA71yi0PE+WGFNq|w*v~WzvqZhsw>@wX~jN=`%?>!M4fb- za91n?2TIjEIjna?MAYmkdt`q&*!Bqx4b?-2g|-M?4=3Ld{0Z`LV5PUC?Ogi40|@O$visu|kHbWnWE&7?{PUEY%RyXjq%d;hNbtHv+S z@9wGJEu&rI)mcV0>LqobJpoP6xh6%-mKI5a`B26|*4M`=i`#yI9@s!NDHvV7YH-(a5RM#bPGq z2!x%KE3^6a@&3i$BaZc12T~(be*Jlwl=`Ra-!18@EQaHmvYr?z)DK-ASuW~O#J-St zVKw8)uGmX+Oxs?6qu>5?w9T^z7zf-noe|NlX*oLDP9+M2vPiB#zwx? zb?vt{OveqCveWgrgF?JqHY7gmXhhGbZaIrZw~y|c^8=K6Plc9{SMr0IQuH!I&@4(l z?_hU~)8uUHI^;U$Ij+18z9(PN9!?Z#nUT&4o%ruGZG2LH`*L`*ou!;h9Gu;0^;-#t z$8phl-5u{8qEuBcXcogoTt-dw9kf5b81HmP@I1I+8*nxi0kdsbfYmO6OZY6X3Y;n) z9wjruv^Zz1CqqzY4QC!OpMcm7BRNz9x}xSd56HiH)C#5_A1akF6$U$VGZc{LL@kS& z7j-0RL6kM3V_0jG#+@Z^K*{M7*nUT}_d&wgKzOKzY-^@I`9ur#$M~vy|H4^U@}>BP zY1{NHVlud}c`2y21qtXg-bAb(0DbMl?slF&o<#T|4)8iXqIauzwbCNcUr!}uazAp5 zAatmTPnEDa6xMjxE&~{oe%nnFZ5=%5}(PvW$I8B$(7)A zn_1Hrbm*EC10;gSc_>yoD5u4CM$iELEfI= z=nZonaPD_5c9n3G?vdyYulKtGpZ<*va?66y{JBVH(@AhySY`AMs)4+LBxM4e2^v82 zvz9MLJ*_eN6(fVJ14WsBh`+7ra4L%2Og=;3p$iyMD`^4xfTe+yyh!h5EkZwYo$&lo z1#{+%nU$+!Ozs>xu}^Y_Y&La~4sk4f-&h*_8f>U5dL5v_exuGZ9)B`};OF>0du%}b z753dwcA^{jB+%VB2Tpub<~tQ68U+Wc6Tzpi>8|Er?LBO)&0|Y}j^Mt`+`WMj4zr)A(J&JRy}n zqVG_;x^CKPX8SGEvd3EII+nZgdb)d;DyF~_bW;Zfng!aK3T5N& zP#Epv->JM&RR3Hs+}8u?_|W$Z3P0VH)#^}a?Cu6fEljVc-++GpxS&aM2i|LMgI~~_ z-Var_weZNufD+`F8wTt_XJ#OyY%1TOb_YF{jbN?!`BT?$BA} z&(7PEvnL+We_feSMqx)w?+ZRBp!O0gvruwF14`37n&gY{ylEhH0p$S86c z*_DXacdK`NtKF)-sqL*b+DoJ$pM_G zqfEC=H=yD>PJGYz<8*cvw^|q}rAh~+^3r!;Zf5W_v&DF!*7LVguK*o7*n7ZL&(XlP z0G_XhZ8`13?WZ zDeYPCp7DhoL04gGaaXwrj%9Ds^T}?;f}jmp9O$Wn$@41sK`%u#04t*=^usfNG5kc< zroN*Cv`wXUNASz+A$$|3$>U6iOf{fDenhG%iO}yEAo>NDkV~8e z|LP`Es(4?d&*(oB9J`kzg%{#0>7cyTRLZ;`?%JEgT!Mp}!Ij{{g)|{a{3fN#!%dp}NqQ{w z0=BFRe~15wTVNzxh3QBugiTL|>g#`MnxFAs2SdDtcadkBJJy-Qamya*_zXwXwZOra z3V5L1l2bneb-5YZ6J(czfIRB%g_j02kgaeUk=;2wvEFgMVt$)CODm1_*%O`E?etIj z1-$`C!#2<|t50U(ZfZu~Vg|Z>&Gpcrp-m5(^aJ`n-0-&(JxPN8NY9}&sTf*hx*%gp zXOD2>jPHhrT4s-@fG%FxJuc3XFtx`lX)}quw|CLyXS!N zTRUiw)L!Zrd<2dLgZ{eSH|{vsZnyxPfab$hS0#5I?;77pB{a}ae@$MZC2lOA#sB2? zFq^2~MsGa~YH0(tHCk-&2as0}^v~$0Z`N5LtmBAmaw+X)hO_Hf8`Rw!f(1~HtchCh z3L=~u$Xwvo3unZ4(iyp(sfVeisWLDVXQ0wN!}Qs-!Bo+-N=}euX|ni2EGuo2RLps{ z$z?id+9q>SB7cjqlXJnpeIHorf8a~U+~oD<_SAKy+Fo1ATGB0DvaeW{W!r3|bD*2> z)eO|c8Ce7>iZz2Su)YyRJ;$8;9J3s&92UnfS4pqk*HPUV{MYyDOxWS7K!dxz0v+g= z=LA3l2*xUOpncFL(@V}g|>wk`Ug`dxrOvmY$Mha-C|z3l_>@O_9k;@lPK>M zD++%&n(Mwu{b- zuJ+y*YL{R;C^}64r*o>d^$+v4_4IL{bv<;S^&V6f_#XhPeHm4Xyij1hf(qM9qA3_n zf2ht>9I8C4P?hT2x0OxPx9RTm8S+)VTQ?{eFx3(*`k+w3{3)wmGzN#fI zJKmP&wEJ2^*DOk32mOE{!8d{0{?*=o?q#mq?pvP2-X6Z{il*%L+tqmOUhts4#b^%w zsP}YNrXll{t_VHm;fSL?R1*pGe;T6B9)dT#k4n}i;8n7TUgQ(=#nM1&khDaididaK%5rxVIBw=u4+Po-s~b^d z8E^s`Q>~z7nvNBEhnz_6z)$h!vz1X)d(Vdzi+W)|xJxR+(e1J*FyE43C?(vQxHqko7(#kU0 z(m7kpCU8QUt@*9C?EcnHHpSk^{lt4)`3#rNErI-jm;SDb>do@B_Kfsso+#g7rIk8T zYosqhKP&<3co3?_F+>_Ng%~OoJo+m1WGa?A32o;xsDM@@dy#9%RB|CIEGwuzP!2pn zJ*IeiAu1Ptm`%{aprII74Y;HCf-LqIQ^X-s5BU>L(oZIz>4~YIX|idqDbmzT{ve%| zu0dgCfK(RlmXbJ7c*|Gkmvbg=5!;I$h1#RY?POapSD{u~oM;MtWG_(njaAWK(O1KB z*}1^J)f$t%$a2h*Gn>x7V5w{QW+{>VIs0$+H|suoEcE(b`!2$Lc@ePx8&qJb;0(!u zBU2HsN8!+&*amN%Yrw&D#vZMKvt@^oMG&Za#vxOVr&FlP)K;QN>-1oxwI^$FtSguFNDl4Y#?OMiuPF0opOB zHLvr_%5Tq6R}05TTP^Fj?AqCirFixcOT5Lf{K_6?t8Q=Z=;AEv&gb3XYoh#whRl5b zOdv!H_~DYExRvVu9Pnv~)^;P_62KYw(AO&mz2Ad`3awEdDl8e)eY{;9HHvCOmB6j3 z6IGBZ0JV@o)Jm!kzB+>H4V}pUpb}Xa!m}BfBt{UdLhF})AiyfpLKu~YSUGcJ9 zQ~rt_oGd;P7m0DeS$_Zme683~tSBB6!i0%@Y5q0`Wp}O{H;-$;y=D8c$B|<$p?0B; zJki*zpTpU3T-y_vq&`x9d*8XAI9EEV+soPFtj(<>tR1YOz)CqI19`cQSLI^ZyxDS@J?f2buJ5Q|-@F_`OI^lN${6VC1j^0Ohglq40|lG}wf&J?WvuX9>}aU& zPhfH|=jl>(H)3|6Hm`NG z?U^mY-p(HFIP8?&t311*je1KN1Z>_ne`R&18Vbex*T{Ic2jA%H(61Z|MA3HiN+N+Z zm{uGUwQYsuR41<8r$pJ z_uE2kTdeME-s;URWIcot$YI~;XzjY^=DfeXUwuoI+e$5Kplt{Em0` zk^jDKV4W8LDs&~4jS-5YpVGroHW+{baDY&H=S>487DzKw%Crs-p8A1h(M?ZpOK&Q0hJ2b^{qtt|DJx z&ZDX3)O6|~{%oRRs4RT_Fj(KYs0q{~DwfviCn?=M)v_>~aRJeci`(qOEB!N|udOJ(rxuf=#o^=NUpa0-0D>0Ej4CcBR<3#{yM zW)0@ug{XRmYE6A5OT#sw7AmGSjU#$_y&1Ho?Z6mMR`U25?|HYwCAeBT=Qvi|vrs=< zXf2BOPq0q2HL>?{TmT0x&OO4@+}p)>(050f3x3LkKx3^EP^u51?R^obgEZhO+5!_a zgeZVFdX4p67;jz)ZXHj_gXDI&pPWa|vJ&3O?UAQGM34Cp`m-DVkEQ+sgz9+8PBo3D{grKz?YM2Mt$_Wd{i0*Ov#G0sdl_oJxxBfs?)yRywV^r#y;CuGJGdQ) z>#0EBlmJrn2=N=3=2OU5bKvBjMa_h=?|0mbjI14dOM1Lt6C*6FpvshgG z4;o?L`6+xT|AyQI9_kuX=u313X76fu)h`~cW{#`Jr)zpdy zYN%h8INuoW6weWNx+}sJ@7(A}u>ZAPv>mbSw(Ybvu-9_TbCw5Z=%jmxX9VuuuY5}t z3zVQ7fyMA!IEiXvB2XkFfdF^`Ex9tN=O2ZVUo~n5^vw!T8t}(w!K<&2d)H!gw<`l{ z9E%$FA7B6;qRx{)*nyZghrULahcb86ys#>H#>%PF)NrsOcuK0uW*Kp#QfL8 z>aPdZLO$Rjcfir&JX{dItBL*<%4pw8Z+A~UcR|-7=P^XQe{)~m*2p&1cFcCzzQA$P zIo? pcIG-0=?c#VTFk9J~U2iZ-aI`1KP&%M<`!;5XjBC{!MNqMwelBGqvC$HHC}d zzwteVDBQIUh|k5I;zDs6Zd{6(3T3;-(nQIQ5h#gl{TVOtHn?K#=i<5kTsiItyPD0z zo`K&}f4U%jfjUdIqfFFd@*^+{*MJeJs1FPF(t3gKHOhZeS?*f_AHH4g`>s9C*N(6D za`u_FrM6UCQ~M!A`x4H#U{?)tGoHVmliowVmC6>sgbu@dZ4y}I1%U3b0ZZ}>GuaSp zn*{57J3Oae!7Jhhb&q1O?iP~!Fe-g8?-g-#IR)fG$qeL@OB_TCXU(=h3b$cYn#GQxeV{rtR} zOM^mfPn>w?*iNXG)&&RTBC2fT=_q&2|z!fm@%0V%%6;uiQK}tE~@i)F)%d zk08)_K?dVNRx0zcWrLSQN>K;arY2A) zpNR56dGw}&R9{+!rb1psuFAN%t>I$@3hO&fw4e^r1<@{t6om>yK>UqZZxyd%ExdpV zw~gP3yV^T$D%T2_kN{L^I^v{n2cOh(^bcx2Rf9T$O3!JG_bXtlYT~57t0f1_fl9c& z(aKBcNfz=HcK35ta&AM#unU~!YTC=%X?v1=qNAqsEc8`#yA#|m;5*pEw_i#1KgVfz zODhLe)PG2rP4FlgMb1I|GEv(y7>@gE1p42_nG~iDqTU8>G4JB%3!jD2;&(9u@7xkhp9Rt`X_6Et zwa3msBx=GhVZSg7{(X(nIdgDZP;1_SHUA%~jvDq*SDK?YQ9L*oP2tj!gJ^-f3YvHbRW0cWx)f)mbFAa9UAAAg&9_aqy|l^p@AfH=LOWy=^*jZvO`2ZPP9_j#2tv0y5)Q3jwaC#5@7rG%8;SI48`#lfN zx!mMj)Rsr!PdT9GQjrlgLi7tooXkaCplZ^$vFFbr%X`Oe<(lv&;kHl#TwSj?5?O4l zR2yepRjCHfy~?i{pH zBal%&joZ2_SSMIjs}U#+ozMhv!26@dEVk%;J7*!N^F*6uAqu}`aoIVd#@On^P z??~Myub}!`4*t(eu--cXE9FB4ZaFY>Z-IeZh~7m7oRB@Bf>saOox>3851?96g)c0` z3(?{Rk&xy|$E8Qof6_kbvt&b_dmPFbwWJJjGVbb|1S{W)f5O$^zTk`xWp^;Sm>2X& z+E2|!7Ci)dPpfgxoi=J4ufdZ!0ES;9tr8Rh6vggycprHJ?qrwCna^3#amZfDe%IF0 zmJAK%ceauCk@mihI?mxP*1g^x4Q}69h4%MUcLh?whqUN_fezk|2zQWrNY#N;+I`f< z-@xayB<_v};L!3Mu|Anx4tCEqbTK-hE|h@V{ZrsOI|7Bf9=G0R_>)fTBIi*zp=;3| z-bb6*2Ixdx;BO1%Fyp!Krv2r$@??3m+yRv+ANXxku;LwHT$=ITWrgj$i|fsuWxKK& z%v3mP#G=-|2K9kGWHIOj6$E;|J9hbXy*etxM6i!`Ij~Dz;Gdz)^DXvH@T_xx0h4!$ ztRc4Xw&wORc0Zg*VW;gX?cVMg?hREEz`-3IIIH!7cS{v8bbjKQZ$nkB z9OgMUGlkKBe<;rWfga8vpds?o)u~Hl4e;sbqvIWddh1oJx-cj~f7XA3D-@0Y9t+le z2wckG^Tl*yZ{T!OxljB-p*nPGCZo>!OeRg?rnaV{Cen0No-Lc@SJH6w12*HlKP40q z`tX;yG~_i;m^{oeIvt$0TDULOAx{94J>7T!#m{rW?ohPbr`3ZFDii3U7V`%&-w!+= z-5$7vra68>4JF1t%4W5CtxatwZFTMO_6?3X&H=6o?sx8j-u1qCCDXr4T?q%Mw!p4N z0DG5@UW{ncjCsPmMoxAMPd=Vqgsl1+Gl>!5fO`%uJBy*{Fc)|F+d%Y9#EmBld@R3S z+Gq|`!eb!&qjA&gOLe64L65m2_lVoWj}*out~HdtO3UH6n-5i~>85zoMpJInZuzF% z9(P$4XC94{of5k7C%By4T67$IP#;-}x_tq15YXoRFuLva+tAl$f~zsl*=j*`t^crc z*>}Tx(!+a7x`(+6I14$B+j)C$+h(iTR@dgUb+B9P#hi^?kKBIu3D0}z<5%%-@ppwj za4zV*4j=}gu5_5*0yg(bsKPvBWVQfX9BeywKVPC|RRG+O%ivEf z0ZQ|yo&-OsCb<8M2l{g#?t3H^j_TcAu!p0O#cziOK_$^Cj+J!jyZlRzLQiX`X}_rn z-hQdPSk5EQmLB7r_amFVfPCgSSCCu4?qlB3`REzc4cyqg=)v68OF~z-Ec8h8Y4roM z)YIUE|M6Axp7lI-$GDF=CpjV=W$kNhx2-j;lJ$c1v$Z;6`ceBB=S^oeyoLLFfA|#T zsCp+bEBITFB3hG0Q8_%r)MN#=C(hla+yKrDWMwGUn$9jkzrGnzSwY-i?vT%rwLJm8 zwlF*md%+EG57faoLy_#JUIRS1rl_+&g(mArcoLe}>ufByfUhh>h$El?ZIj~U5~fO~ zg{BVBBkpE0(DP~|3-Sbs!;Q6z_yy~GFtYcq+&K6Mf}@Gb@_XEn;(!T`Hu{5|UpF{I zn+MgQfPb%lk8<2M*SpIT;|JKA5UV_h!1X9I9|H_+*@1U&RA> zUz4c?>gr!iMa=cgis`(mg6WBzUp|2yJyHB11c4ZP#C7Htv$vV|7~hH1QL-f2204lY z`Wjz?^`K__Bp^dYe2~AIvc^{q>ghS%qN}v?vwf58nsrh3BTIy3N7f+p#`?ga*I}J$ z&vg88K5(7zZ1*kz{-J6hLF=nmAmjb{|3UtQK@G%(@z^tyk3N>khp)urM2m1bDe9^jBsfyN{dB z&jA~LwOC8KD=m=ya({I5WOFOC6@2OLrn07Z`8sarD^YFjFI?p#_yh3RYzP0e`Seft zIF%=BgEfVk0Thl|D8}qT7uW3%^WXKo@=o;d?z_&Zj(F4{QnKG#R%dZpgEPNo8OHj zO5 za!dHy=(mr-4a6oMl|(oOACya(;!J6#tENV#jj|IFt&X@Cm8YTnVQw^PtAE%&KvUkP zHL5l>9Qwk)a5go80^5(^l;AS$V?a^stEtLD-+fOx_Z+9k{=qiT%4Ao{I+0l>^Kgcg z5uPzM^F^j5YaP6@pV#0O19<|k{HK(%zLAK`lbov^pKPRcr)5WG-OQF5b%1Ck z((h*kGe2a#wEhOZIUg#Ey_FsQLt2b}06d!^w1=^@0CQ@tZ7t~_1#W$!loJAetppaiMP*L+T7R2R7 zxZQ|k6`&@nLO=I0Jk+iQhiN?n)l`cT^!9-V)kB=O!?SN>-O0F-J}GV2UoQ2=-|}e- zGrDBn%6@HY<8Gi_RO?)=-TbVu2Tt+8D2fv;Mvi~75 z4cT}q{29kGVVK(+LT)h;_=-fSt~?kySCUN2v!t2m8`P6nu>r=oH5|&@v(K1&@VV)Q zUc?h9EN#N+YryNwjB{uW(0rTJjf&2M8|ml z&_4%P1g{5&26F{tgInRE5rDU7f||>p-`l}8+rG+H%DOu%HNAdnv%kGk_NMgzdo*oy zrWJ2G(A`W0Lz0O_74j7SMLaA&6PL3espg~`$fhZQt7>cH8_)bNl`YCxe+4*QwAMIi zDi>njac{(l@;XzbnGYFi-YBmUFYpVw*-SXCK@*8bW;w;k05AU+o{0<|My2&Lv4axX zGJHuv7klBRG!uKYzf?txN4@Z)uuf=!NR@!TN0?|4A_R#a0AH~hY#Fv5a+&s6_pwX~ zdIvBNK19B{K}O366xA+jx3!CbALs!%z3ttx4vRHk)|a$HDHHz4Ni%;9`+e)r+0;3i zvTckfG0=>9%{>=C$SqBMO|9jY(mZ|xofj^aGqpviEaX;#o__A-pN4s4^#66 zKS2q$i+sb>!h9ukT!bmIa(KRwR#H2D7RG)!HOE*NjD{9LGiYEqgTtX!;SN?dnvip8 zC!@2w_-Eo|`G@I(ISY>CJ|RVDEEW}jm*noU*eTowcm|Ms2jniFaU0BHKe3nDns6)W zh2Gvuwmnmv{zS$QiHN-iH3fOoQ{@M;{PRAiXT9@`{h{rw)nqA|mM7&!(t+Qzex3T$ zDs@lRcWb1(sMeiaBP2TmC50x2(&i^pL%s={iyjG%*=OKX*`N~GpiS2j;eGejNF`d4 zJL&D*dEvTflOD>6@&M#WqP$ZqC+tBs7=n7X36@v0zDm{-;>FLb9#s89UJN(EU z=jL*m+<0ybJBQ)v>117FG1Qh?1RnTbC_dj--%`&h*9OOW`$gNI?1x#&=`+*h)XbDC z$tRN=r54I;lpS=azMn=RcD4{>js!1YnbbiHa5_;YcuTG3U+-z`iUIQSj^`fE+hfWs zI9F^9O5|Q(rVmINA;rV%M~sN96sd((44Ea*5l%5L$i7Cm;72G>jn+QH+j4NQ1~_RX zkbDZxmPBc1$I=Q&__2vj4 z(6@?0WpfZapXoqXp!SkuP|-bNG}X^&X9HIClz*X8%e%p~*0J2y#M;A>l^K_DB6VGg z^UwA_ZBuHela{SE%{ka#hA7HcHEE{LauO=amBkzEG-8W3(_h)w!d=LH0$8weu1I$~ z?`CD7+ADaCuu?%X?kILE>96p3weajSfx$bLX1L{rki5_))8WbbYZNR zE|x?-%!_ue0eb{KE;{OGJHUpj4Tknk;Cgx()q_0)9L|RRAB~MR?Ow(6^VPBDl(b;$d6zDX##Af17 ze2pxDsGFPUOZupKOmnWZP)dwMReq}c#Iz0BeRXM(@B+2i_vk<+vxnFyZWh;yZz~KG zC*fW6+{5bKeki-|}%W?`6MHc}^a&54lmLo7wedf0-$;wV8RLSdo^`%lL^nsw7bg+_ZtZtQA%}pbquUx5j(j+r^X9nPqEi zO|sO^D3V$yC3jM>#QeXv{{5BJ#9Ga@EwGgKOTR+PM)VI$m-~ndxqjrzfXy@6;kHKE z{&Nfkj_9xNhu=`k2hSQ#^v_mNdl?VMNDlMr@QdNC!sxK4VP!)Sg#YNj@cfv7p8go< z<+arV1j9(c1K;DH3jG9@UxIr3f4C)Nb54G+_({x(id!z}u5bX=)t+pCPN2I$sXUea z29?yuaPPSwpOgNg)0l_DS@I9hjb6qu)U{fo(-J~nFjVc8I>TSym(!KY*3&x2>dC%j z>6#UqSv2j@--~~#)L*IhGFa;xM~G)vpcV5)u!;{v4{BV+_?GlyW1@e!+wW-Pyp3Dj zA$PjBmH&639$Z1bP^GBR^d)vMKSby$tuW0u7cy51kwd?js*4-B)2y9B7Jy9YX)qF* zKm_VcxuErPjyum?g-hm8IJ49N`dQ_>OD*K)au-u~^JDW)(@k*Zbk>R+|7Ksm|YyNarM1SGVFW z>1(S#hmZ0Q_>4TIo3q8?Q=cNYGOskZHrChAMRu~# zU+e=kS9vLsTMhn}g(j%h@F=f`TI@h>pmfOe7`27rsH&WiUQ5s9-O^_`7i|&GNqxlq zd<$+P!_iCWeauz5IvI`1-F0-KC!-HtfHg1ZT5oUdPbZG@LHLL+Lx(ztu!c#~3FV<{x#NxVr%Q##>O7xE5#iID zMA)DQFqS+??FZ|lx7gpj9*oI6=Gvh}LaIt;ZVT-;)@r)~Gqi|cL45}CgVxyde1EB( zd`z@)BXE})Mn6Jl=?gO1k8~M+g1AshlXIICsXGu{cjQp%Bl6%iP{=!i1}lDF<}+=oy--i>#ye<>ni4Gc>a-GnKN3d(-282>@&D0h@kqQhHF^oXHiVSyCt;|7012tre95ocjefN`>& zY6qlaUv!!RV1v(tzLHGjFzni1zZG}OOy_w=hV4{#-mIk=`!gz}pGwV>_Bef1W@6?D z>s9v&^&)&PelQD}8Q=*7*)%d!UE>{%-oOKQ1@{&ATIlsAs-N@;KV+71^SK{f zcj1SiK`*NS?$nD>N%6Dy=t9uKuLZ>667==I&?5Vmt-${V-uVi;v7Z>3PKMt67iu-_ zglFwlZj-nO6~N6vKRe|e@@cHhbHZ@`Dc?zWh^#yTIr(8G4(_VQ=o#cND95fr*VKeQ zS}l0*I^bmRK+CJ-fOhXvcLm2j%eIVM=_}JV{B50bAo+VrNb0lnaBCg+Pj$bM%$(pj zo)VgfpSjM4TiNL?=Ben6bG(Er@ox7$WpVHYageME?d(NNe&~{QVDGcVkTqUF2W~cW z>Y57;xZTVgIu35$PSgmek!IRP$FNtqE5b@3UMCBa*!px;sxTbUq2yt7CYLbP;RU?1WG5CGtAziWk9@ z-eb+N<;(nagawy#<34DKk5pJ2CJ7Qhc-MKsieVMADqpk$3_CB~K+sT1cIeH1R6^Jh@dqgnHFQIAIM!3NG zQPGS7!|OGw9*f8!bbYoiG>kQ{kh`JJ@`=rhdv!1B7j%HuAf`0H?YooMUS4kcYfcEs zYu+Lq2mUHfqQ%+#Jgzl6g&E6uamy}Bs=$Iwg5t$8;yk&Vil%=9iQ1MbWGsP8&j;^t z_gVWf%eaimsiqVoS^ArvnwGjhy|~rl^!wxWhg1wQ*;P1yFEAa+a$0X6>q>-f=>zm^ zemQq}pQyZ{QDIOP>ND;H6bHMokKp21liG?};uex- zpMWj>Q1HV8d8D|FZ^I2@mXobfsrX4$$35c|CyS-PMR;JYADSI<0^VtF(Upi0JM(T} zrkVhiUm6uNKiwGKx*N%s1ZOz)2G9Z9Z3Kzwq^3X7{%A7;3zRReK8{Y-cNw`;ho+25 zY5liu>V%Bzmc@=TK8LoQ+(GG7A@s?PQ3s8RffK$ocYgOi*9dnx&oXb4GCfdGZ$cEN zmLU?P0v|Vp{)JH(4pqNv%ucQt_P&d|#*PI`cOLqTHsIR9ZX$vNeYV3h>fs$%{M3W=VWLphuZOexA4}UAB3TegC<;<* z+;FL$bUf7rYK8mB3EF4hD|ednuVbZi6ndz&ys!KZg2f0P@3o08j2KXdw$Oio_1MO& zW*>0(`5Sycem2(J9UhD=IvJUhgj8TndW4`Sr{c>L{wX9{M_C z=1%jO!f|l`x+nAHslY-lMpde>Xcv-%4#HDDi7$v-MPv3GFfc)Iz?wsY(<~ijS2kmO>&pBpUW<1nU-<4-V9q8@Y|Vx&w-SMKlRM zweMX!9L=qRGW({*q%BNenf^9oy5*aFuIISA622A1flKTRynJOiohDBaoe7WBUUN`1vod{v&| zr*J)3foTi9@@cdLb?^45eUyeaUoRp~kI`PM{h_HC3V&w8^WNFS`Ja7m_M}WDqjhGL z%+r}|v-3OGdvs-WU=4f|%fUC|kTEbY)E5Dt(LL@??rZLTs4HIfH`YmXB2}UdP#1Zr z^HgzWJ-rCHv+GPOw;lb+AFLgi(7Lpb9!9l;lKNfp9GrC1`Mu&q(ZG`rlOBi@__AO> zB>-X3g1OCJXzybbPbOg3~BE4&%0$d(Qyi02LU`05E_>5jeY3dXZ@m=7P*cje}ui4)~RLGo< z89@IBlu=_!CW``_mq5ib`H<~5M@J$NXoJVV7d7Yava6Xb%z8E&XC@ED+fk^V?U2Le zD9I3-2(S2DLJy&+aEt%N_Z3urJ#XThaCI4)T8%SoDRRc@!6w=JK8a#{I}yo}r)rKf2xn%&H=0{66KDZS2x}?;yP>O#}szqKF_Ohz(Rgq$nT)qM#s% zpoof66;J^Y6%hp$DbjmWdhf8k+;+a6e=q0{*tat~ylzMXPw)UBSkKE3(!&BxQL=H3WB6zv>qW8cKb zKF29*H;+DEke}Nl&!0b;?DXoPtjOlrW;;VWY3$Q~!U|0#!hWIFS}#V9(hlPgo~}Uf zqriuO4uNLq(i*<)#6=f2&Y2VaPX+b`Zzp6C=luk8%oTwi{toy{-tdj{eH3WH`Ngax z4@_Q#UZ2jcrJ492dgI&NjL)Q=-y}9<7yj0z<^=NCnrr>tB~&tV6C6m#;HxzU>=N%vDmatBA}>2gd<$AQH)yzIOAZPOm5ii&EPmFnH3Gz{YWgWjkpn<;#(I@NRn^8W~f63Po*v|yh5)Lt+ z))OYM()TRusdcHJ@HP=Hb%|TgOt_giH0i6Pqr~z)kl2w}mi>79caksF+dNBr#c{Gi zpGTv#Adc20R`Y%9VRp=Ug}mWn5iMLe^iIL^`SWrc=KP)g1kvd`GB0E;$QhTnFaO`r zu5jzfPxzu9u@}TPMkYrhkztW;;k{J%tsNd685VoZZsH7g-ggV@b&UIrvt*OJL0o-l z^OiZrH^rAu{f{5$fqB?f+leGUpgf`o3M!NfeA!fPVyh}oy80C zEMC@yfvn)FgjR_w6I-#%?ApZoi9-{52Q&Pqd{6p5CI0MLR*&x@kL0TJ1|IBG`%UW; zDmuSl6|s`7ZLzAc`=Sp<+J>g*HOp<9Q$D+F=GBZrS~oMt+VAveuEix7993?X`x~I$Nx@*SqVBh`+2tbjo7i14PZw^Is(U z`B>nI!2SMRXt0~U^+bsN=6edSz+Cd&o=BL_DCtdp-d_U{ z9q%449y*l&YhGUNq?}pVYqL-1bYQRUjDmLIUn1-r!k)C_iNX9K)}36UQIVF^v|hwY zW=pF*apZ^HEau7Ui3$D<4Yk*(XFiQ>n?%ixe|&3*O}L*p*S7x7{(k<){O@A_z86@E zFQ-j#OmIrDOR#ouSKuY$CjRwrVJ#`O;9!1F>h%xE>y|em?^E`a zs2)1T_@B*Q%#~v;W9QlZcyBb1+Uw1zZ@xM@GB(8O#9a3#nTeZ-4@f0mt>^c-j#-7;pmZg7*fae7h0YM|5X3?4%HO zeQhd_ydPK+_?NopHv*FaB?5!}%aJRmiE?$Q&$!QR$y)jWe0j~BEc*$2wDlW&HjW&- z7?q^Ug(t9o&&vgu^7~MsK9yL4arsjVR)oq^?L05soSMz8V>!{2RK9+eTFD>9wv(^6 zKlYdPyS>bQle~`h#C%L8?{%AgFR`xAny5(;uL?NrgKGNwX>)>-jG%4Vu3v3g1-09@V`LR$xh#EzKHpO zshJ&&zWPXN+NBsdXJgOB?v6EyRgZ0qcEMZPm&)fg!@Wb@i0yiXOu7~MX2FDl z3k83L+;Gw8%VeW`A8kUd=MFK0Y9d>xKR*?({3i77TlUlBD@-LSO{$!2CaTRLbM&?` zo>4Lz4`+h^vhTX@qHhIRGS3i4KgTy1?i=La$qcq{;1eo+cMZH47!t_!kCXWc8Q~jP zc_|qv6S$wTG>Ckv#{OMA`y*?z<&7cwX`){TP>b;m@=fk>b#@F+aVD~>+MVMek$~@E@&BA7djUz!fv*=!m}bbBO$7O7iO2RBhi}dknjvOL?&5f z?AKZQE5x2rFFD((%KRd0fN4}9c}cHgT*e+Xd~JzeYQ{J*fMz?k>o?3f=K7W)?Ixg? zlA!&#z|}Ic^oz)~@YL{v@MNmeCx%;u2ZjfS+l9x3M~1%-$HGsu zYr=bx?8v-mbt=ZMh#Axxi&;adVEz&7jwPvt{VO|id_t_`+gcC3K(9u|o6H#3GsErd z8|3SPA7Qp{o9`$P-bJQfbM((B{}{4vn_v@+_PqMW74vIbyZ4hk|4Msze2GI|R40fXvVx`$puqIfvaHcsIoo9%WtxVm! zHP{8yi4(3sl;RR&1#^Zz=1gJ;tHM`DeI;Ad^ zkC58eeDlHKM`rp}%oug&N0D6-rA}N`{bwrqO>{N)WA+=LW4B|Z+!LvWJUbP+57{<0`g!!9Xzf_nSR>>^i`b~xFEK0Dor-XdHJx~$ zX~gg~Be$a%vC6yIb@4MI^_vrOc*IB|0-z<;R7RU0n=8r4`-k~LHR`{Nq2k8pM9YPJ zL8`U4q6$Z2eBvJ9|xc0zAY}=F<&8H5g)4r*uxclcN6KEYi>1vHJ6#A$hOWR-uXj%pbHWHzu`0Ps3+-b znE&2jwW_BZa%Qsg>;Zc`F^M5-J-atFwu-XH#1ZxlnI4<$?UOJN>H1`BNNj5CgV@B_ zTa1G(v0br$VgaiwbDfLU-8S{QygoS0ju#!MD49Xr@mwum>rU17RNDRun`UKd+__}+LkFuKl zjW$#?Or{Padni&hbFurJTh848Q) zlXZ+vWUfykns^_zF-)^0e9_jt&unOxHiPT}ca+)Or)0*?q?-P8X#NHHVl%+L8^Sf|_44aDWsy>uK=rr1)}Ciiq{`t_ zb`SeuyD!+iZcninlFM__j^TOl%zm+-QBnUo(NL9<*8Rvz{+wE!X*1KWve@tG}5vmH5WX-Y@-rufds!~6L>UWKedPaRRn46NxTh1topRq7e$|uPF z`hz_7xAZ5-n2C`C^$XF3gPD~#rlzDrM$KRDS5&lmk~*>hymRY_%o^;pCE_rdJjHxF z)3)qlPJQ4U;!GwA@f&skSmUgsTFwfpaV&9GBFl~u#g*(fAR_o}GV-=jk29aDsg=n_ zyqB5~uTU9b1v>8^=98LUmT0ur)cx;GMBiBUwSS+e)`@&3>!b8%^hb&2Zm&OpwbzZf z^5^x@!2LRZA0*!;Mil>-vg8rIF?cP_2%pMEo zUy_Tkh1~|WvfIFq>~k=d%B%Mh&#F_6ID<;9*+gzfsDPVKcFQ>`luEVMx4~qXI~e`? z3VsW!ksNrcwOh}vOP*_c^4JHHQ@R40AA{;=$cQ|EPkRIPTV+>*?VKq< zL)V3mq>}&he0oqVyCr>J3;$d-@T*6a)7C(AANO=1TeuUSN2nFrAFK!P#8XJJ)?WQl z4NZKG5qln8c^m2^knKTddUw8u zvtT4N5-MduS>Z&X>?v^D2KR5EAOC_E4+H6WsF2C^8$fUz%(rr7BmMX%f2DW#LJ>K3 z^L-cC?cmH2?mR=k<-#QzaAJmY2)t2xhjeD32-AByJ(0}e=ZZ^jg}73{UkyA8Q&*%c z{8f>jP3C$&?>kN_(*9QHe;jzydBWyy2g+mu{~5SuA8>Eu*zrG{C%tqCYV7r{Yz9B! z!j054-preJf%6fbJHgZEd8Zr~;ED5hdgv0AyG~1)^hyrUMW`XIL1iEGE((N|7)7<1 zaW_CFHQ;DS=FMH4sg7hS2genr{(l1fqkh;EkzNv~X;npxomfGL{a}qsQps6MT;G{V?bDf#E^E9r3OyY|im!IWBm-oIzWPwnc!e z6wnFm)u^Og19)p8OX~u8eGiAm{JzUOBfAQSq?J3Wb7ysLtQCg~15iPO+d|$U{hCX^ z=0K_2Kz<3hPje{FmT{56l`N09Zvf9(pcnX$dz^n2Y=s*IYvKD7;H5B$%bOfHMz~2s z+B^JJJfFl^C<&KTqZV{kek%wCC)pXK37LOwJ*oCESu)+p2YU#;cOUYvDZSMY3`K(o z-m1UK^R6QFt8i2d`4IKwvfw3HWdPqTAe7Gy@3;o6(o=Fs6@PWdZI4@oUlgYoK%X%0 ziUGfRt9-LPKGLCLGB^}RI#qyUs(Q4Reo#Fj7_u&8)c+dd2m=jpne?SDS$h2=%0)`d>*~S z<&;8TeEOibP+s7V@Y_Wa1>x+%jDcc&(%=UK_lR|k5l4Hz{6qZ&k?RsfgMP^*Y{q}~}x zN%WZ<2^{h_=t&#HgIPF6cm-D|he*j}56(0X_M*UE*gMiZsTx09j5bQrQW-{x=(s9y zRvmC^M1P33Y=^d#<35hI-v18(ZCBv$Nxoq}^z1We&OZFtowLGot-!o7JSQ@uK3caf zM?DVd={n$6nRd$2W?|q9dK6dkUH4>-?D3EYy%m)U@l9bXvLpprqW%-S<&b+5_)RG^ z?~rfmyWpM%&VpMx+EgP&MzxF|89j2yh?ntGA9xi9wgF4QRpHy39&N@IIT}L~IT~=k z>{L+-3=%zgr^b+QI&LnwrofX9S&S6X>Ngopa)@S^9ROrZ$i0|n-YA!T`|n5h`cQgN zcu}aKFp}O(f$Ivx57K8PIEr%!SIU2arAWD&(6}D>h;$R`%TXJAt8lFvzpH?K73fik z@lpmHO7Oly;2~OzFdq*P8{W_JMu@;IV_qb*`YVz^*(&l)zF$ReT;?N3T)N%%MpqW^ z5Unc~jp!8hO|-CR7wZoG25l>Dj_V86r*cm8M;z-o_XW;^ACquByvSG>TXZtZ^zQyg$6pr zRk3Bx@tY3jfJgPW^l1`3sSd#-k$#SkVUbe;I~z;V2id@% z=^fG!*F8K0hqHI|=zcWi4s3wGIktMgx1;;TLfOgr?VJ-U;4kmk%za|>?dRCXv4^|1 zd(X(TTd|6_OkdL3vC0(Uw5Dr8(Z#D7MNIJ zV$JU4++OfH<9jtHNp@#H|8UyFRQ1raw8-YMRVnvJ1ve$!H;UzsKR+~Vq`a=3c4x#)$ z?@0x3oNA}M_sYAEd53UroO`98PJq`rI8jL(>65q(BD=4NJ@J2KjbI}>T4rN17UOzS zWRl`Nkzq;(i1n-_fMBW)HP+*te}Nu83k0V;+KQDghy0Z>CL>H>m7YHfltOi(m^`hl zPqE$}OI4I|&n^G#{xx=8fK=potHsSdKdB3H%Y zDdWu^#HOmmGiA_t#h`%b$|Ud2#nBDrxgzfqi=q(p&^?}3ye*cxXk4)iWX_lXoC2X} z1CdJVUhjeb^ULsPr>uOjheX>JqjiC&Jcq!p+Esc+#b zYU)`Jf@4ijV^sw+p@upXeS{_z?;K+Hm8M;p^U8ctX$OHvIHEW(iQOi!#r3Al3FIio z9fdskt2ji_OW~k;LA|*o_sZ^Bvcpz&w5dQ|kKSlVUkKcH-?9GMV8OM*hP%hJ|C(|w zezg_0pxB44?pQ|+JnTd(%f2XaN{Llm^$upDodv77Wv2L{tOs=wa1%^ZfnMxTnc>9W zA+!Hd9yJ7Nd0O5tv&+h~R)ycn5|WvmqJDD^;=6&l8Ha*e!QIk>S75*A&Uu+j2+ntN zMxJQS_lBN@A@d5^6HRzfpb;oadmjaZf}#S@$dzJP9Rj_;U)bvx=_kQf?iTn3dikyX zihUy%su~Rn6R~8(rm24CkeQMCh+QYMxZ2*K<~_;+6-!k9m#cEU4j-An3OB`JmNrZ9 z5$j4gN2o1aB8SKn`6$^TV??ah|L>1@Dbzh;qx-nWE>&$6 z=4{IUaIjEDFpu|O++q_>{?FTB1MJc%=wr#+Z zJ7Ukt5vQw?k&0T1QgMn1{bi(zpvS-&Ix6NLTc74T0k%tdoAo81$T7D|GqABN%_cK;)_%5 z$Xk?uN-Phtrp1z0hqCfcdltnp&)adtvti=4sn`Kxw<@2MSQyH(JK$LlhqqVAIW#ABrFXr=Q-zl*Ibo<5=K89t)- z{{dRDeU$YjP>6Rb?w?W?sSA}E2YzL*2+nbPRInAB^gQ>7ZT){O7iDYxXV-~ECv;a>DeEo{ zp}@H3PG88pK`c6#IqHLRC-bR@et?4-z9dR^p-#`^j6lCqODl1%6byZTew|p zaPi$LpOWGy#h=3a%5D>nP5cngP5hAAi98v%#H44%GE=iVvGs%-RbR(vI5LV<4~sue z`d!&}%B~jsPT6=uW#JQb2*u-XkQt+zH;9K!?5emGCDxppK`Vch*jO@FWba=YTVi9$ z+(^wYB*vyXdd#O{)rt#Fa{JMzEpSCUiNYszz=U=Yh!*|@4jX;ZtOGoSl@j{5+{ZHr1y~=`=`$R8` z?Gm?!#R8D~;~HA*2;~7$I#D#BXw&~7P*!6(PeTd>%EE|SM9N-KoDl#MTkI zNIT`ZBW}SdyIS5O{iXUsQD510a$fvR%CjuCy0X*beI9RBo+(W$Vs$I{R7-MR?v=NR z%_Tfml5+y5n)@ibM_QJnviE*v1F8O1wykPMEMvtLa!oK-P^%e{_{tOnWqG@@v&F|M ze5-6c;T*+FGAmH_nOITko0?lH9#gXku?uC~%IFmMRvsP-T$u3-O3{_^b+{QJFV6lWpzvWO5)y7)wVnl zw|&JPRx4Qr$X!{F6HTM^f~?Zz-I4WTl?tRXqt55fbo9m*G|5@dHWB?I9s*f0&E~pD zW@%ITUu9iU^qjm+`QAitD1V1|1mzG9k9bDnUfVp*h@Q-%Jvl2Dv8+|!pe6BI$cm-- zQbgZ~k2jOn)e4&IESkj?p`OdrH-S>wn6g?b>$hSji#JbN5Z{LAMtMrsAVgEAbM~V5 zjA;6^T#c``2+m?@UH00LHA7j4%0_oz^=KiQ_KF9!=q}OdN`p%c$$YR7OI&(A$}?AK zLA;%^3V4dQsx@4}S#0L(yyrg;>2dVC?C~I&iI zLgAz<{El0MCwb;1|4A^cez98jf%ipPjX?1Ty?GWZ@K@IT z*I~b&04@zVA=)Q}Dr1+yOL_YaL(l7QhK$!dAP~I7`zb56XTUVVb24`fgNKX{;dPm7 z$$UpvvBg$B&$ke3RLP9OBu25U4_^l-v1g@!WduZBS$|fm(gmEmNJ}TUp3VD3&x_AT zXWjWc6xzai@eUxozLw@D`c(#O>GXwBtkWiswvb`?AU=xCMB!Dw@73a0%U&JTbtfFmEag zMmpzh_UujJdujAdIq#fE5akb4veM*v+5fj5{+9cIybgDk;4K<49`Th(8Oce|PFB@w za<6z&l7aLxxSRzip{$`K!Ez$-J>5wvX~C$qHFD z@YL8zK99JS%Fy;+vgEq3X4?Sz{ex$pNOT}7&Qo`JezAJIPbe?iL;Sg=u$k^9hV%he z6kDUsh1#k7Ek{cwz`iziOagT{kJ5vsSwHQ|ifUI@S|5XcrM+F4chMWwxgsmAU3o_t z-XNaYT>2>rhtvh00j$Y(f!=k&Ck$ttfQv#zWl9y5&p{+y;RRqFj@LL6XGXR%}7s3M1+IaVBaZaL~vccTX zowaFCW+P&k6yd2MR2W`Ht>uRqH6`eUY(~{T^k)(7P4XhAuJNP^o|S;&VdCar(_SSK z@=1E53B7z7+DYupenw@?t;6}Dtclm>O?hy$%-8ejQ-Qt<>&yM2Qc3o_K2FcE13Hw< zhWdXa0c4hc5eS+cZ{7HP`R3f~x*c-eHxYYD~pB0dX=egSi-@-s6YcB zIG*Uji?lDZibB9y0M#Yxbv`|p%Ky~MA$D>-b;)}J+XHZHA{y)jv3+mSL)Y0$_-FP$ ze+LRL0=v0HH@-%V+Ru?uVyg*XU-9HYglBd^+bnpu8uG0l{d1e$7M}s?AGk9WNH+rA z7-AzQvRmjDsQolO-xr#sYMb1l?l@L;uhG-8E5aMZO@6~0C1&g#cFi$*Xdn@jjc7f? zZAtv@M0RQ)0jF-|zAfCj7d$5uOSzfeKL_-GL4|to?Rg-6!F`H0SFq}O(XF9P1*4a= z{p3uygQj!Yd803QU-Y8Nz9as1E8KeyZcu*6UxD>S_NUn7wuNV2LW|{r=eI=p)?+`6 z&W!c3@M=-=9#;_OISv@Bfb%A|5Tp7YPv=!b7VUD`eUs?V6}-6^T-1Y+*93~JrXJo6 zVp^YrlHHL&v$;~AD+YT*wjjoJ2ApvPN@u|D55l!o$jD>MP`4D}45o$iiF# zkv{ts-i{DqI~2+Jk#?9m+z-GzCi-ob`#8`(NG}Q{`g{5?NcPY)xa=!h7fCjVh}pMk zE9OyXGL=^j!&!Y8Pu19=Y8f%U8yIn7)fnit(Vh&Eh@48=3HtqGIP4p)oucUV?SlN>OI-A1C_DiDLEgKznen_Be*F{PO+%vWV*FIp z+Odnq7tS(bm{+*dwD!cJ|3NhRa5#SvQtwrF1km-Q4)<{SXEmHM&#lO_nM4Tpgaba- zj+56Lfy>VzeMQeXw0+Czg`|6zIRBq`vN}~WGvV(BaLOcFJx#7`2lj1w)XgQ9dYIdc zeEQ1ljrALx5Fo3y6g~P1^-m_!V{3_PE>2ckfB2#pyHdQbuh4qCKDa=*>lAtKt+?X{ z;-IT*?*r{3>=2PY8k%J=y1o(mum(993mND2;gu;w1^)^4ceyW+&oUb6egrM3qxWm0 znd*{zeVT9GiG==%arzkAw-s1D24t!xE^DN=X;5>AE~|Rwk5WF6+Pbp`n&~oJAl;%W&mP+FM|); zY6plJ{{URRbZ;}M-{am3=2aQH{o(44P-G*|YmD>Cn#?YDB5Ag|_Y*=f ze?dKFiHCXx^w|>RNg?cs1N2uT@&sg`)NeGCDj4r*v!MQOP<%X< zcfV#&r3baYf$<-w4Dh{y^>~V1wof7F`jaQT+_CH(&Qt71@PM92gntKWmTaLv!elB` z=c&Gox?iYYe@M?JH@S`bw$qME$Od+77PG~1&~O@-S7A7>8oDLGconbR{b=z9oPQ7) zyD-WMqpSLB$DphZ{WrPo;H$o9wa1aNx!QyJWoXgGt>kv%>N%=QKj*&44xWZS0lq$r zHT4#nq92lZvUZn#0U5iW??c^7>^{^4`s87`hy_#)IJQB_z2G#P^9zuA4Z(XgJy?l4 zxKFqToGDIWIO{QN+GXTN48s0QM8>vp)5sY)iXC(xeSHBfv=$w^9UJjFlz9UkAlMGl zE}~n0M60~*)`mY)w0yFBno{egp*{_n^)^q;LL04R_a{F)pOn?-YrnfSsHFENc{zQZ zlTK%?DZ4nX#R?xtdt=<{NVEr$gZClDU3Ve5HN&(yaLsbG% zLqDiZcaM`NGmzcmvz>R`;Z%$Mnhd>3`U~tWo#_l>NBY?gHNTGAhe!5xt`k(r!D`$zMuf+!s*S;Rs{r55`D6D$mYv zK1F*x#!hj~^e$LAvftE9+Ngqt*bCjhamzEZThLnz7-3@VH^)AB7s#eDE@v`dIVn9u zPtS9IM@F4yME1tse9Zlv9ks>YYQ>Hnlgap*r0qeT*K{k=Kg)r48#*C|g>f%d;GfKh z#OE`R{hKbp-(oqI$4+>M(K^k2n#$G>xg*hc+34ZB;iUD*wHLLYpmu-8R~DSu38+pX z0VXmYv#}{I(vM^C!t{aqRj}jMush;sWc3V08tz2`e?|t5#)xvEZXw3)6IyAiu5{5# z!yOB-N-EITt9g0^bC9OU&5LN|Li*2)tv|5$2O|w9vJ=M_(EB(oG^W+R>CI#AKCL!1 z=*3uH%zZPEo;TtDvPkJ}$iohBl8z1aGPgMSwCa@>}Gb5%Lp7r|9^oTd={Cx3QpG0 zqr0?{=&af3tXk|E-9qc@)`o)1+(gDiTVzFTa-t8zQ&Zre;rI>8Vhvr^67(r(;NQsu z-UbA9(JgJUrgWgbj1@2ie%t}HPiv2}FVpAjMfD~7{vB}&VQsYl`djWZz&nt)xt?y? z!$>c|41NZ0{stJ2qJb7L_AfE+dSYkgx_@i6&_T;??JNXJ1?-0cs??+68gCvGHMeNC6oSdLEq-m!)wq%o1y9_z<3*-a?7d1w+iT~ z%2>Fw!K4x6>pYg}YIgwk%>b~gh5Y*no%1H2-8}USTJam~g^tLi_E5f|cG{aCu0;y2 zM9**1lJvpaVkC4QW|niALkva>G)3FA!3J9CzE9@ZQE0mWPMd+W8pEiXiv5Enra#AB zPk{SaC^d|hYUvyCGaNvouf;MQ1&a+Or+(AN+VhN}MO5}5tG%l4WezY4+4egem&2%@<62G^bk%ystOh<^koXnY z@9cAL#EGx(Z}L-Xc{cMe@cH-5+NiO@*gD8Obq@W$o&HJ#njlh9!;V^sWU2)08l!$Y z{V)WJeh)o5oV?R*Ze8U2ZgzbA4Vv~v#^_Xzf7N-5d;Zcov0qlQUPOC^O2Q+Z4QR0( zcRrTEP&HY z`{Bj!*qOex{wjNfog#m-Dc0N@4=otcP9s0FeKQ{csRVaV40wp$9r)L$s&;e(>sg;Oc>-naq6l zK4kO)<{MKOVFMXE>}JAjwYi&xHhBrTvkuy{LZkhm6_d(VT6MPoiBW_8Z%qxGw%D^S zJ7d?QzS~4HkLMyMcQezNjOO?QD{+XsoowEk%)c6e+slm9U%}xj(p6(F)eD;~4P7a* zc8_Aw_G2`igcIHYnkn47MD|jL(u24<3v1&c&aB4c(3ZFNWz4=r8{^RdAEMdwobvF- zlk}RblDXhC3Qt6PIOZBwX&of*o6sW*J{k?ByCb0<0j8h9CYdqxDHQk^e(T1avMSpY zIoKTj*$)RSK&w3lhcAW4&oM6BF$c1c>6$i)ryGLLOr+|4JhcgFmhY}%EcL|pu8j4v z#rX-z)I+PLx6rTQ@5sSdaRGgl4vnTUujqnh`vv){57O_qq0=xdR14}Bz`q5|EsKKb zmvG2tB*9hY4@>FI>&&A}S}TbxS%rV5w%%0V0KcYCUu7uyzkk68>ltq|7;iP*vsB%? zj;?$K%k3L9cX2GY^T;5bx!OF&+SlN^0B!GMEd7F=JQUt9uKxy>|G@c0v84B-r+$Lc z&!NE&0RNA`Pznq`K*C+byRrtGSvcZq@>e;#8oHdKy`jvz8zC1nfoBCh=|fjZ z%!sUKG-6DA3TJJKl%VaHZG-MVMJLQ%BaPV2v-Q6>8VPZyn&BGxYif@VMrF!fxpY(IDyA z@eP^HPD0L=#x~xH)apeh{y%PKdbK|mzT`e9z{i7;$hq#DNV$1K0$gN;0t{q`)j%E~m29CY)8`J{MqddKlkvap(J`zrgG8&%3ZokUBqZ*dpecBcD z#Iy9;3$zi!(*75o90mnt1@t1l))pK`p#|1M*M9WDVdy*_S(oFEV(-AMj5b-l*$pQS zL9YIZ-Bycv$tia9Sb~4zE&@iMf=Ake@ocP%1pR9y(|hoLf3$2%&TZltgM507kv$DN zqYph*5sA?gymFAmlX$Bio|^$@e+uoI(b@)PU~Rcl2b<+4J9CbU5BfI3C$kq-W-cBt2q|I zGxSbnu>KH^Eyt{KDb#%gTLD=D?>&L-aS+?&Iru#Vn!SaU`!H>2NRWltRvPbk46d_~ zZ?bMLtF_7C^#o%qigvuf*{aaDBb-&65!D0foWV$wsJa_zRA00;5B#zOkaV6S7MD;fG@TnCu*>gGy=Tuf(9XYd4p#^KZsqL&)jM` zcfG)T{YTE}3uQ0O+8tpU#@FiU`{w~;sRL8CQ{q+9eRrVily$NzQx# zg(X7sJUB*x?=9vi!+~c6yWB|Lh@5YYM5xJ|GCl4Z2R@q^tJN5Jb@8Iiz`7dB9OPr5sfu0EhfyO^ zZ6tF#sSsHY2~(FgMDxlFc0U}PgcbG>GT=ILX(aD@4}1cQ%2IraL)l&Q zzzpu+;n`3RqfJD5EQf*;%Pf&3M?H?I3vF8gX)UBr0^?5NR}yGVc5;21YbD^avy86= zP#~9CMMp+!B4d3E5>$FP$8C;|or1J0O$#E6mU0|J-`0Rf8*uIr-0=-`oeBRNymJy` zq#11;#a39$o#{wOgFY$-r-t}Xa@miA&2Iim+(tgXD?`a-q<#jHDi!>ak$nb2La(i6Os#;+9s0ZsS})8qvhF7FxvDCHffXw=hlaQI(JfC zoby#_LwMWdZx!0E2gK#+NvZJgFK;ddpQYea*an;urE`%MR5c8Vy_MLE!thFMJ|;M2 z^F$)_kr>7DSR*$W0kT>v5g+AgFTfKnxCll8+Io=LVhj3FLx)N%(^cqG9qzabI#l*> z5`Rn{bGKIXM+bVTHaKL`pI3QHF(mL~aMazry*TG3vP|eG(Lc4}B*~fX4$Z22wtSE) zF|?1YLiC~+AD{(^iIJ!y3mZjzn9ZzpOU7aPws-S07q*1NZLWUX*^9sG9OX+nN^dhR3S| zMG4+4@r&hoP9kI_PNWv?hf60TAJg_#vA(1W}X{9yq zZOnDaG-~9Hb>Sn4&yn1{inP!K$nWEtRF+Zks`A!aT&W1mk{KlJ$tY=#S&*MnQ~RQU*wNOCrgB}MCGa+brp|V7L4TH>fDt~Ul#(Ssyul&a7rzOySY-5 z79|r=MvI)k9}HwIPvmQHIHWqb2zBc6c8QNxk<7JdTVis{0j1<(sT}k8@9K9TDaRWm zYFT1{g^DWrwW!zcL0XlVT@}$Pv80JWp)$TCr%6>nkc>vjX-wse#FTCBvMJD<|SH5V3%_$l2+cLGOpD7ihI4Psw{|Hk|-VFI;kch`TZ(KOENTzdUO{| zRSdRdZV4=k69uFH;&dh3DR8H4$-|NeJBh?k01kmFh3_J(@Et7`<{%GUi35NffNa;>GiRB`Q&l|6Q3Qj8>7{ z3YF6!84U7fiN932!4i2Z5tov!q~d5Ll2&qBB_3C0Wyn>@|B|RG$v#mzQxd_XvP>k( zR^s9$swrMGL{$(Gi7W4wDhW~{L85Wv*|u^{qVy!jSLKoX-zO)!p&j6^VqDCsd^8C1iCxJ4NN{tJq`7zEV%9$W_T~mpp2LQ~V?nSsSm0AT3Ho z0m;`=(Vzl}9O^CSX-i@w<2hy$rztZ%$&FFJ&)$JX;xq+A`77t-qcW}pYV|#yQ6uk^ z@9Hh`c9qF4enrcDe{(m#DRrISsE;U{R2X(i~h!S|^DFwO8 z{gLQViHTKJZ6y0#BEVE8kYszyA<<4!Jwc9mU4^6GUH{!7xnuIQk=a@ zSyz%*BoWbqso<&ZI|C);P?QqLSgXBJYz-IF;okZ7M_b|YbhR7<0W26L&cQKcvP9`DpN`QC*R|7>S8-cZj>7Tl7A?-f60xqT>Bu>`Q)NO* zhJu1EepT{MywM0G2oJ`4a(Gg1P6uG0(L_3L|P#Ibx=f%bm9VGHzavoInmz@1C zt3>76izbq%RbGk8T2fg&qRr)y|Kx8xQ%B_`OOCx{%!qE6%oe#Po=+m@#afXw@|@(w zs63gtEuks}h)p3@jH-ww8a;l9^`LU9MW3szeW^hhKPMSWqWdeOBPCBq;D}op0*}h& z5&8&T@r*2$-J>#nltm$SfE+4cTr42bykZZEZ71I(-dA$6q`sK48-x~Ohe@`OV5V}= z6r}`bd0RYxOkfhLB%TK)?-8gggGm+dyI@k;`z|?0lIJB5sBEx!rjp8&lK-TYIAzse z$>&j7M{#=pXC*3VRKEyZ0%<9zA=MbvQxcCV|Ha=cwvP0sqM5u~XeKs^JQdG_mwuM> zD#J)+A&G4zmb>~-{))|^a*tF-xWulD?V;-C2tP~Z1K~g6Y_`20Ld$q5g`08XH{;uv@N_Ze^vIP{4dqw)Sc>CRhJ`) zQ7Ge3G8Pj&dq>8lWZFwcf&3MVNainczqBEioU-o(>oi~%%TVk=v1e7K1c5kS5kuwQ ztE@_ulO!<5GcHx0m1J?MD1VhTr7B^FWYPae?x?&Wm4Pa|m zK)E983X;DidNH5B@*b&lDOp;g5A(ghqMamGMDnZIU;(L&+q70ym@ZOtV+u{ik3-B_K*P?$VcS8=LZU+BJE0WoC zi&h0w$sd!fC0QjDPl{v^NcP$_sG5f@qO!#Q!4^#CzI4v!@|5tDXj$n`$*dAfR3Lj0%K8fg9W{ zZqL#fTd&v6oAWBV36E>$lSbZ{E6zkIUdP;gmRm~77C;cGRO=bS6A=ia}Tn~C5eIrsc$a%4>Qqa