From a7345e1d66e266de5deeba4f7b176c1731fed07c Mon Sep 17 00:00:00 2001 From: TMCRA Open Source Date: Sun, 6 Sep 2026 03:34:34 +0800 Subject: [PATCH 1/3] feat: unified 1.0.0-rc.1 memory workspace and server-independent local setup --- .gitattributes | 1 + .github/workflows/release-gate.yml | 3 + .gitignore | 2 + .../deploy/local-model-profiles.json | 132 + .../run_tmcra_v4_build.py | 7 + .../shared_core_manifest.json | 26 +- .../tmcra_local_models.py | 101 + .../tmcra_local_only.py | 193 + .../tmcra_v3_online_runtime.py | 46 +- .../tmcra_v4_batch_writer.py | 11 +- .../tmcra_v4_online_runtime.py | 9 + .../tmcra_v4_slow_graph.py | 2 +- .../tmp_tmcra_v2_lme_pipeline.py | 51 +- .../deploy/Install-TmcraLocal.ps1 | 68 + .../deploy/Local-SetupHelpers.ps1 | 91 + .../deploy/Start-TmcraLocal.ps1 | 11 + .../deploy/local-bootstrap/sitecustomize.py | 12 + .../deploy/local-model-profiles.json | 132 + .../ops/test_local_pipeline.py | 96 + 02-tmcra-memory-api/run_tmcra_v4_build.py | 7 + 02-tmcra-memory-api/tmcra_local_models.py | 101 + 02-tmcra-memory-api/tmcra_local_only.py | 193 + 02-tmcra-memory-api/tmcra_service/__init__.py | 2 +- 02-tmcra-memory-api/tmcra_service/__main__.py | 20 +- .../tmcra_service/adapters/v4.py | 38 +- .../tmcra_service/api_models.py | 17 + 02-tmcra-memory-api/tmcra_service/app.py | 60 +- .../tmcra_service/commercial.py | 53 +- .../tmcra_service/evidence_view.py | 13 +- .../tmcra_service/feedback_effects.py | 69 + .../tmcra_service/local_deployment.py | 390 + .../tmcra_service/qwen36_planner_adapter.py | 3 +- 02-tmcra-memory-api/tmcra_service/runtime.py | 11 + .../tmcra_service/session_graph.py | 2 +- .../tmcra_service/shared_core_manifest.json | 24 +- 02-tmcra-memory-api/tmcra_service/startup.py | 19 +- .../tests/test_feedback_effects.py | 141 + .../tests/test_local_deployment.py | 159 + .../tmcra_v3_online_runtime.py | 46 +- 02-tmcra-memory-api/tmcra_v4_batch_writer.py | 11 +- .../tmcra_v4_online_runtime.py | 9 + 02-tmcra-memory-api/tmcra_v4_slow_graph.py | 2 +- .../tmp_tmcra_v2_lme_pipeline.py | 51 +- .../package.json | 2 +- .../desktop/tmcra-memory/package-lock.json | 4 +- .../desktop/tmcra-memory/package.json | 4 +- .../tmcra-memory/src/renderer/index.html | 2 +- 03-tmcra-web-console/package-lock.json | 12 +- 03-tmcra-web-console/package.json | 2 +- .../tmcra-codex-1.0.0-rc.1.zip.sha256 | 1 + .../downloads/tmcra-codex-latest.zip.sha256 | 2 +- .../public/downloads/tmcra-codex-release.json | 14 +- 03-tmcra-web-console/public/openapi.json | 2 +- 04-tmcra-desktop/package-lock.json | 4 +- 04-tmcra-desktop/package.json | 4 +- 04-tmcra-desktop/src/renderer/index.html | 2 +- 05-tmcra-mobile/android/app/build.gradle | 8 +- .../memory/mobile/net/TmcraApiClient.java | 2 +- .../ios/App/App.xcodeproj/project.pbxproj | 8 +- 05-tmcra-mobile/package-lock.json | 4 +- 05-tmcra-mobile/package.json | 2 +- .../integrations/hermes/plugin.yaml | 2 +- .../integrations/hermes/pyproject.toml | 2 +- .../integrations/langgraph/pyproject.toml | 4 +- .../TMCRA.AgentFramework.csproj | 2 +- .../integrations/openai-agents/pyproject.toml | 4 +- .../integrations/openclaw/package-lock.json | 4 +- .../integrations/openclaw/package.json | 2 +- .../vercel-ai-sdk/package-lock.json | 8 +- .../integrations/vercel-ai-sdk/package.json | 4 +- .../sdk/python/pyproject.toml | 2 +- .../sdk/python/tmcra_client/__init__.py | 2 +- .../sdk/typescript/package-lock.json | 4 +- .../sdk/typescript/package.json | 2 +- .../sdk/typescript/src/models.ts | 6 + .../tmcra-memory/.claude-plugin/plugin.json | 2 +- .../tmcra-memory/.codex-plugin/plugin.json | 7 +- .../tmcra-memory/.codexignore | 15 + .../tmcra-memory/.gitattributes | 4 + .../tmcra-memory/.gitignore | 16 +- .../tmcra-memory/.plugin-scanner.toml | 4 + .../tmcra-memory/CHANGELOG.md | 53 + 07-tmcra-codex-plugins/tmcra-memory/LICENSE | 201 + 07-tmcra-codex-plugins/tmcra-memory/NOTICE | 7 + 07-tmcra-codex-plugins/tmcra-memory/README.md | 20 +- .../tmcra-memory/README.zh-CN.md | 95 + .../tmcra-memory/SECURITY.md | 22 + .../tmcra-memory/assets/tmcra-logo.png | Bin 0 -> 1036093 bytes .../tmcra-memory/docs/memory-controls.md | 76 + .../tmcra-memory/hooks/hook_common.mjs | 71 +- .../tmcra-memory/package-lock.json | 16 + .../tmcra-memory/package.json | 23 + .../packaging/INSTALL-TMCRA-CODEX.md | 8 + .../tmcra-memory/packaging/Install-Local.cmd | 3 + .../tmcra-memory/packaging/Install-TMCRA.ps1 | 4 +- .../resources/local-model-profiles.json | 132 + .../tmcra-memory/resources/memory-center.html | 197 + .../resources/workspace-panels.css | 6 + .../resources/workspace-panels.js | 138 + .../tmcra-memory/runtime/LICENSE | 203 + .../memory-api/build_v3_runtime_dataset.py | 791 ++ .../runtime/memory-api/core/__init__.py | 89 + .../memory-api/core/advanced_renderer.py | 332 + .../memory-api/core/advanced_renderer_v2.py | 407 + .../runtime/memory-api/core/comfyui_client.py | 670 ++ .../memory-api/core/concept_extractor.py | 180 + .../runtime/memory-api/core/concept_graph.py | 126 + .../runtime/memory-api/core/concept_memory.py | 311 + .../runtime/memory-api/core/console.py | 19 + .../memory-api/core/default_model_paths.py | 97 + .../runtime/memory-api/core/gradio_compat.py | 26 + .../memory-api/core/gru_text_generator.py | 142 + .../runtime/memory-api/core/kb/__init__.py | 6 + .../memory-api/core/kb/conceptnet_store.py | 193 + .../memory-api/core/kb/embedding_store.py | 98 + .../core/local_concept_extractor.py | 327 + .../runtime/memory-api/core/maze_engine.py | 852 ++ .../memory-api/core/multimodal_generator.py | 1792 ++++ .../core/native_concept_extractor.py | 187 + .../memory-api/core/native_generator.py | 2586 +++++ .../runtime/memory-api/core/natural_layout.py | 882 ++ .../memory-api/core/natural_layout_trainer.py | 141 + .../runtime/memory-api/core/nlg/__init__.py | 6 + .../memory-api/core/nlg/path_realizer.py | 130 + .../memory-api/core/nlg/pattern_bank.py | 54 + .../memory-api/core/object_sketch_backend.py | 578 ++ .../memory-api/core/object_sketch_dataset.py | 791 ++ .../memory-api/core/object_sketch_model.py | 517 + .../runtime/memory-api/core/policy_dataset.py | 804 ++ .../runtime/memory-api/core/policy_network.py | 880 ++ .../memory-api/core/query_understanding.py | 197 + .../memory-api/core/scene_harmonizer.py | 44 + .../memory-api/core/scene_line_generator.py | 103 + .../memory-api/core/scene_training_dataset.py | 299 + .../memory-api/core/scene_training_model.py | 95 + .../memory-api/core/sd_sketch_generator.py | 1716 ++++ .../runtime/memory-api/core/semantic_scene.py | 1436 +++ .../memory-api/core/semantic_scene_v2.py | 1377 +++ .../runtime/memory-api/core/session_memory.py | 620 ++ .../runtime/memory-api/core/sketch_edit_v1.py | 1738 ++++ .../memory-api/core/sketch_quality_schema.py | 330 + .../memory-api/core/sketch_style_spec.py | 333 + .../runtime/memory-api/core/sketch_v2.py | 1478 +++ .../core/tmcra_reasoning_runtime.py | 200 + .../core/tri_maze_neural_trainer.py | 1057 ++ .../memory-api/core/tri_maze_supervision.py | 1136 +++ .../memory-api/core/tri_maze_trainer.py | 331 + .../core/unified_scene_generator.py | 275 + .../memory-api/core/visual_prototypes.py | 596 ++ .../memory-api/core/visual_query_parser.py | 780 ++ .../core/whole_scene_sketch_generator.py | 771 ++ .../memory-api/deploy/Install-TmcraLocal.ps1 | 68 + .../memory-api/deploy/Local-SetupHelpers.ps1 | 91 + .../memory-api/deploy/Start-TmcraLocal.ps1 | 11 + .../deploy/local-bootstrap/sitecustomize.py | 12 + .../deploy/local-model-profiles.json | 132 + .../memory-api/models/tmcra_v3_reranker.pt | Bin 0 -> 4234837 bytes .../analyze_remaining400_writer_failures.py | 201 + ...apply_remaining400_provenance_migration.py | 258 + .../ops/approve_tmcra_v4_partition_diff.py | 101 + .../ops/audit_remaining400_chain.py | 250 + .../audit_remaining400_writer_integrity.py | 297 + .../ops/audit_tmcra_v4_subject_attribution.py | 886 ++ .../authorize_remaining400_writer_recovery.py | 253 + .../ops/build_tmcra_service_release.py | 301 + .../ops/compare_tmcra_v4_slow_reviews.py | 197 + .../ops/continue_tmcra_v4_writer_sampling.py | 289 + .../diagnose_remaining400_chain_failures.py | 337 + .../ops/enrich_tmcra_v4_source_timestamps.py | 248 + .../memory-api/ops/export_tmcra_openapi.py | 105 + .../ops/export_tmcra_v4_active_slow_review.py | 172 + .../ops/export_tmcra_v4_slow_review.py | 336 + .../finalize_tmcra_v4_slow_quality_gate.py | 216 + .../ops/gpu_scheduler_baseline_sampler.py | 219 + .../ops/preflight_tmcra_api_configs.py | 74 + .../ops/prepare_tmcra_v4_fresh_slow_copy.py | 313 + .../ops/prepare_tmcra_v4_fresh_slow_run.py | 316 + .../ops/prepare_writer_success_subset.py | 173 + .../ops/promote_writer_smoke_state.py | 210 + ...ecover_tmcra_service_interrupted_writer.py | 394 + .../ops/recover_tmcra_v4_failed_slow_jobs.py | 312 + .../recover_tmcra_v4_interrupted_slow_jobs.py | 320 + .../ops/repair_tmcra_v4_slow_coverage.py | 463 + .../ops/restore_tmcra_v4_worker_databases.py | 299 + .../memory-api/ops/resume_writer_workers.py | 123 + .../ops/retry_remaining400_writer_failures.py | 318 + ...llback_tmcra_v4_spurious_prompt_enqueue.py | 423 + .../ops/run_commercial_api_smoke.py | 523 + .../memory-api/ops/run_launch_api_smoke.py | 125 + .../ops/run_memory_graph_api_smoke.py | 350 + .../ops/run_memory_graph_api_smoke_0_2_3.py | 350 + ...aining400_fast_exact_evidence_migration.py | 122 + .../run_remaining400_provenance_dry_run.py | 139 + .../ops/run_tmcra_service_preflight.py | 68 + .../ops/smoke_commercial_contract.py | 167 + .../memory-api/ops/test_local_pipeline.py | 96 + .../memory-api/ops/tmcra_api_log_report.py | 140 + .../memory-api/ops/tmcra_diagnostic_report.py | 259 + ...4_batch_writer_claim_identity_candidate.py | 5312 ++++++++++ .../memory-api/ops/verify_tmcra_migration.py | 120 + .../memory-api/prepare_tmcra_v4_e2e_data.py | 261 + .../memory-api/requirements-tmcra-service.txt | 9 + .../runtime/memory-api/run_tmcra_v4_build.py | 1000 ++ .../run_tmcra_v4_compile_evidence.py | 1023 ++ .../runtime/memory-api/runtime-files.json | 184 + .../memory-api/test_portable_release.py | 149 + .../test_tmcra_service_model_flexibility.py | 152 + .../runtime/memory-api/tmcra_local_models.py | 101 + .../runtime/memory-api/tmcra_local_only.py | 193 + .../memory-api/tmcra_service/__init__.py | 5 + .../memory-api/tmcra_service/__main__.py | 406 + .../tmcra_service/actor_provenance.py | 324 + .../tmcra_service/adapters/__init__.py | 1 + .../memory-api/tmcra_service/adapters/v4.py | 9067 +++++++++++++++++ .../tmcra_service/api_access_log.py | 244 + .../memory-api/tmcra_service/api_models.py | 1350 +++ .../runtime/memory-api/tmcra_service/app.py | 4608 +++++++++ .../tmcra_service/audio_asr_proxy.py | 164 + .../runtime/memory-api/tmcra_service/auth.py | 654 ++ .../runtime/memory-api/tmcra_service/cli.py | 132 + .../memory-api/tmcra_service/client_cli.py | 781 ++ .../memory-api/tmcra_service/commercial.py | 2630 +++++ .../memory-api/tmcra_service/control_db.py | 3186 ++++++ .../memory-api/tmcra_service/control_plane.py | 1502 +++ .../memory-api/tmcra_service/costing.py | 254 + .../tmcra_service/diagnostic_log.py | 308 + .../memory-api/tmcra_service/evidence_view.py | 422 + .../tmcra_service/feedback_effects.py | 69 + .../memory-api/tmcra_service/gpu_capacity.py | 96 + .../memory-api/tmcra_service/gpu_scheduler.py | 710 ++ .../tmcra_service/graph_projection.py | 1561 +++ .../memory-api/tmcra_service/health.py | 88 + .../tmcra_service/health_monitor.py | 413 + .../runtime/memory-api/tmcra_service/jobs.py | 2712 +++++ .../tmcra_service/local_deployment.py | 390 + .../tmcra_service/narrative_graph.py | 366 + .../tmcra_service/native_harness.py | 207 + .../tmcra_service/personal_knowledge.py | 837 ++ .../memory-api/tmcra_service/planner.py | 376 + .../tmcra_service/planner_provider.py | 100 + .../memory-api/tmcra_service/provider_pool.py | 700 ++ .../tmcra_service/qwen36_planner_adapter.py | 302 + .../tmcra_service/qwen36_writer_adapter.py | 284 + .../memory-api/tmcra_service/rate_limit.py | 116 + .../memory-api/tmcra_service/recall_pool.py | 1519 +++ .../memory-api/tmcra_service/routing.py | 44 + .../memory-api/tmcra_service/runtime.py | 4963 +++++++++ .../memory-api/tmcra_service/session_graph.py | 6346 ++++++++++++ .../memory-api/tmcra_service/settings.py | 748 ++ .../memory-api/tmcra_service/shared_core.py | 71 + .../tmcra_service/shared_core_manifest.json | 91 + .../memory-api/tmcra_service/staff_runtime.py | 465 + .../memory-api/tmcra_service/startup.py | 918 ++ .../tmcra_service/subject_attribution.py | 418 + .../memory-api/tmcra_service/supervisor.py | 299 + .../tmcra_service/usage_attribution.py | 169 + .../tmcra_service/user_provider_client.py | 237 + .../tmcra_service/user_provider_slow_graph.py | 276 + .../tmcra_service/user_provider_tasks.py | 688 ++ .../memory-api/tmcra_service/visual_atlas.py | 2524 +++++ .../memory-api/tmcra_service/writer.py | 1813 ++++ .../tmcra_service/writer_context.py | 112 + .../memory-api/tmcra_service/writer_daemon.py | 380 + .../memory-api/tmcra_service/writer_pool.py | 635 ++ .../tmcra_service/writer_provider.py | 334 + .../memory-api/tmcra_v2_lme_pipeline.py | 10 + .../memory-api/tmcra_v3_online_runtime.py | 2478 +++++ .../memory-api/tmcra_v3_product_writer.py | 3276 ++++++ .../memory-api/tmcra_v3_recall_planner.py | 404 + .../runtime/memory-api/tmcra_v3_reranker.py | 1011 ++ .../runtime/memory-api/tmcra_v3_schema.py | 168 + .../runtime/memory-api/tmcra_v3_slow_graph.py | 2143 ++++ .../memory-api/tmcra_v4_batch_writer.py | 6402 ++++++++++++ .../memory-api/tmcra_v4_cost_report.py | 562 + .../tmcra_v4_evidence_operations.py | 1083 ++ .../memory-api/tmcra_v4_evidence_planner.py | 580 ++ .../memory-api/tmcra_v4_online_runtime.py | 4135 ++++++++ .../memory-api/tmcra_v4_recall_planner.py | 367 + .../memory-api/tmcra_v4_route_policy.py | 553 + .../runtime/memory-api/tmcra_v4_slow_graph.py | 8165 +++++++++++++++ .../memory-api/tmcra_v4_task_contract.py | 641 ++ .../memory-api/tmcra_v4_typed_semantics.py | 674 ++ .../memory-api/tmp_tmcra_v2_lme_pipeline.py | 979 ++ .../tmcra-memory/scripts/build_release.ps1 | 53 +- .../tmcra-memory/scripts/device_login.mjs | 4 +- .../tmcra-memory/scripts/drain_outbox.mjs | 4 + .../tmcra-memory/scripts/install.ps1 | 14 +- .../tmcra-memory/scripts/local_binding.d.mts | 3 + .../tmcra-memory/scripts/local_binding.mjs | 32 + .../tmcra-memory/scripts/local_deployment.mjs | 110 + .../tmcra-memory/scripts/local_setup.mjs | 11 + .../tmcra-memory/scripts/mcp_server.mjs | 95 +- .../tmcra-memory/scripts/memory_center.mjs | 151 + .../tmcra-memory/scripts/memory_controls.mjs | 206 + .../tmcra-memory/scripts/provider_config.mjs | 19 +- .../scripts/provider_executor.mjs | 3 + .../tmcra-memory/scripts/smoke_mcp.mjs | 2 +- .../tmcra-memory/scripts/test_codex_e2e.mjs | 8 + .../tmcra-memory/scripts/tmcra_client.mjs | 59 +- .../skills/manage-tmcra-memory/SKILL.md | 23 +- .../tests/chat_confirmation_contract.mjs | 41 + .../tmcra-memory/tests/codex_e2e_mock.mjs | 28 +- .../tests/fixtures/memory_center_fixture.mjs | 81 + .../tests/full_local_contract.mjs | 47 + .../tests/live_provider_synthetic.mjs | 27 + .../tests/local_setup_contract.mjs | 45 + .../tests/memory_center_browser.mjs | 203 + .../tests/memory_controls_contract.mjs | 83 + 08-tmcra-mcp-server/CHANGELOG.md | 24 + 08-tmcra-mcp-server/README.md | 143 +- 08-tmcra-mcp-server/README.zh-CN.md | 134 + 08-tmcra-mcp-server/pyproject.toml | 3 +- 08-tmcra-mcp-server/src/tmcra_mcp/__init__.py | 2 +- 08-tmcra-mcp-server/src/tmcra_mcp/client.py | 84 +- 08-tmcra-mcp-server/src/tmcra_mcp/config.py | 153 +- 08-tmcra-mcp-server/src/tmcra_mcp/controls.py | 189 + 08-tmcra-mcp-server/src/tmcra_mcp/durable.py | 450 + 08-tmcra-mcp-server/src/tmcra_mcp/receipts.py | 207 + 08-tmcra-mcp-server/src/tmcra_mcp/server.py | 519 +- .../src/tmcra_mcp/server_smoke.py | 158 +- .../src/tmcra_mcp/setup_cli.py | 521 + 08-tmcra-mcp-server/tests/test_client.py | 185 +- 08-tmcra-mcp-server/tests/test_config.py | 90 + 08-tmcra-mcp-server/tests/test_controls.py | 123 + 08-tmcra-mcp-server/tests/test_durable.py | 187 + 08-tmcra-mcp-server/tests/test_server.py | 225 +- 08-tmcra-mcp-server/tests/test_setup_cli.py | 266 + CHANGELOG.md | 12 + CITATION.cff | 4 +- README.md | 4 +- README.zh-CN.md | 4 +- VERSION | 2 +- docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md | 72 + scripts/build_local_runtime.py | 72 + scripts/check_release_versions.py | 20 +- scripts/sync_local_runtime_core.py | 34 + 336 files changed, 149370 insertions(+), 287 deletions(-) create mode 100644 01-tmcra-agent-memory-algorithm/deploy/local-model-profiles.json create mode 100644 01-tmcra-agent-memory-algorithm/tmcra_local_models.py create mode 100644 01-tmcra-agent-memory-algorithm/tmcra_local_only.py create mode 100644 02-tmcra-memory-api/deploy/Install-TmcraLocal.ps1 create mode 100644 02-tmcra-memory-api/deploy/Local-SetupHelpers.ps1 create mode 100644 02-tmcra-memory-api/deploy/Start-TmcraLocal.ps1 create mode 100644 02-tmcra-memory-api/deploy/local-bootstrap/sitecustomize.py create mode 100644 02-tmcra-memory-api/deploy/local-model-profiles.json create mode 100644 02-tmcra-memory-api/ops/test_local_pipeline.py create mode 100644 02-tmcra-memory-api/tmcra_local_models.py create mode 100644 02-tmcra-memory-api/tmcra_local_only.py create mode 100644 02-tmcra-memory-api/tmcra_service/feedback_effects.py create mode 100644 02-tmcra-memory-api/tmcra_service/local_deployment.py create mode 100644 02-tmcra-memory-api/tmcra_service/tests/test_feedback_effects.py create mode 100644 02-tmcra-memory-api/tmcra_service/tests/test_local_deployment.py create mode 100644 03-tmcra-web-console/public/downloads/tmcra-codex-1.0.0-rc.1.zip.sha256 create mode 100644 07-tmcra-codex-plugins/tmcra-memory/.codexignore create mode 100644 07-tmcra-codex-plugins/tmcra-memory/.gitattributes create mode 100644 07-tmcra-codex-plugins/tmcra-memory/.plugin-scanner.toml create mode 100644 07-tmcra-codex-plugins/tmcra-memory/CHANGELOG.md create mode 100644 07-tmcra-codex-plugins/tmcra-memory/LICENSE create mode 100644 07-tmcra-codex-plugins/tmcra-memory/NOTICE create mode 100644 07-tmcra-codex-plugins/tmcra-memory/README.zh-CN.md create mode 100644 07-tmcra-codex-plugins/tmcra-memory/SECURITY.md create mode 100644 07-tmcra-codex-plugins/tmcra-memory/assets/tmcra-logo.png create mode 100644 07-tmcra-codex-plugins/tmcra-memory/docs/memory-controls.md create mode 100644 07-tmcra-codex-plugins/tmcra-memory/package-lock.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/package.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/packaging/Install-Local.cmd create mode 100644 07-tmcra-codex-plugins/tmcra-memory/resources/local-model-profiles.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/resources/memory-center.html create mode 100644 07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.css create mode 100644 07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.js create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/LICENSE create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/build_v3_runtime_dataset.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/__init__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer_v2.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/comfyui_client.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_extractor.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_memory.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/console.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/default_model_paths.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gradio_compat.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gru_text_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/__init__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/conceptnet_store.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/embedding_store.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/local_concept_extractor.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/maze_engine.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/multimodal_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_concept_extractor.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout_trainer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/__init__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/path_realizer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/pattern_bank.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_backend.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_dataset.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_model.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_dataset.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_network.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/query_understanding.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_harmonizer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_line_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_dataset.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_model.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sd_sketch_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene_v2.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/session_memory.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_edit_v1.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_quality_schema.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_style_spec.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_v2.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tmcra_reasoning_runtime.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_neural_trainer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_supervision.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_trainer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/unified_scene_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_prototypes.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_query_parser.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/whole_scene_sketch_generator.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Install-TmcraLocal.ps1 create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Local-SetupHelpers.ps1 create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Start-TmcraLocal.ps1 create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-bootstrap/sitecustomize.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-model-profiles.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/models/tmcra_v3_reranker.pt create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/analyze_remaining400_writer_failures.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/apply_remaining400_provenance_migration.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/approve_tmcra_v4_partition_diff.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/audit_remaining400_chain.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/audit_remaining400_writer_integrity.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/audit_tmcra_v4_subject_attribution.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/authorize_remaining400_writer_recovery.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/build_tmcra_service_release.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/compare_tmcra_v4_slow_reviews.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/continue_tmcra_v4_writer_sampling.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/diagnose_remaining400_chain_failures.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/enrich_tmcra_v4_source_timestamps.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/export_tmcra_openapi.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/export_tmcra_v4_active_slow_review.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/export_tmcra_v4_slow_review.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/finalize_tmcra_v4_slow_quality_gate.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/gpu_scheduler_baseline_sampler.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/preflight_tmcra_api_configs.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/prepare_tmcra_v4_fresh_slow_copy.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/prepare_tmcra_v4_fresh_slow_run.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/prepare_writer_success_subset.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/promote_writer_smoke_state.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/recover_tmcra_service_interrupted_writer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/recover_tmcra_v4_failed_slow_jobs.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/recover_tmcra_v4_interrupted_slow_jobs.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/repair_tmcra_v4_slow_coverage.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/restore_tmcra_v4_worker_databases.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/resume_writer_workers.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/retry_remaining400_writer_failures.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/rollback_tmcra_v4_spurious_prompt_enqueue.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_commercial_api_smoke.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_launch_api_smoke.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_memory_graph_api_smoke.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_memory_graph_api_smoke_0_2_3.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_remaining400_fast_exact_evidence_migration.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_remaining400_provenance_dry_run.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/run_tmcra_service_preflight.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/smoke_commercial_contract.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/test_local_pipeline.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/tmcra_api_log_report.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/tmcra_diagnostic_report.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/tmcra_v4_batch_writer_claim_identity_candidate.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/ops/verify_tmcra_migration.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/prepare_tmcra_v4_e2e_data.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/requirements-tmcra-service.txt create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/run_tmcra_v4_build.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/run_tmcra_v4_compile_evidence.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/runtime-files.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/test_portable_release.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/test_tmcra_service_model_flexibility.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_local_models.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_local_only.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/__init__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/__main__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/actor_provenance.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/adapters/__init__.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/adapters/v4.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/api_access_log.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/api_models.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/app.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/audio_asr_proxy.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/auth.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/cli.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/client_cli.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/commercial.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/control_db.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/control_plane.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/costing.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/diagnostic_log.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/evidence_view.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/feedback_effects.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/gpu_capacity.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/gpu_scheduler.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/graph_projection.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/health.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/health_monitor.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/jobs.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/local_deployment.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/narrative_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/native_harness.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/personal_knowledge.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/planner.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/planner_provider.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/provider_pool.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/qwen36_planner_adapter.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/qwen36_writer_adapter.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/rate_limit.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/recall_pool.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/routing.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/runtime.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/session_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/settings.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/shared_core.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/shared_core_manifest.json create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/staff_runtime.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/startup.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/subject_attribution.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/supervisor.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/usage_attribution.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/user_provider_client.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/user_provider_slow_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/user_provider_tasks.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/visual_atlas.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/writer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/writer_context.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/writer_daemon.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/writer_pool.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_service/writer_provider.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v2_lme_pipeline.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_online_runtime.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_product_writer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_recall_planner.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_reranker.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_schema.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v3_slow_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_batch_writer.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_cost_report.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_evidence_operations.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_evidence_planner.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_online_runtime.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_recall_planner.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_route_policy.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_slow_graph.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_task_contract.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmcra_v4_typed_semantics.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/tmp_tmcra_v2_lme_pipeline.py create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/local_binding.d.mts create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/local_binding.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/local_deployment.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/local_setup.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/memory_center.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/scripts/memory_controls.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/chat_confirmation_contract.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/fixtures/memory_center_fixture.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/full_local_contract.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/live_provider_synthetic.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/local_setup_contract.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/memory_center_browser.mjs create mode 100644 07-tmcra-codex-plugins/tmcra-memory/tests/memory_controls_contract.mjs create mode 100644 08-tmcra-mcp-server/CHANGELOG.md create mode 100644 08-tmcra-mcp-server/README.zh-CN.md create mode 100644 08-tmcra-mcp-server/src/tmcra_mcp/controls.py create mode 100644 08-tmcra-mcp-server/src/tmcra_mcp/durable.py create mode 100644 08-tmcra-mcp-server/src/tmcra_mcp/receipts.py create mode 100644 08-tmcra-mcp-server/src/tmcra_mcp/setup_cli.py create mode 100644 08-tmcra-mcp-server/tests/test_config.py create mode 100644 08-tmcra-mcp-server/tests/test_controls.py create mode 100644 08-tmcra-mcp-server/tests/test_durable.py create mode 100644 08-tmcra-mcp-server/tests/test_setup_cli.py create mode 100644 docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md create mode 100644 scripts/build_local_runtime.py create mode 100644 scripts/sync_local_runtime_core.py diff --git a/.gitattributes b/.gitattributes index 8228a11..17c6847 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,7 @@ *.sh text eol=lf 02-tmcra-memory-api/deploy/tmcra text eol=lf *.py text eol=lf +*.ps1 text eol=lf *.js text eol=lf *.mjs text eol=lf *.ts text eol=lf diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index 593e28d..d8ab519 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -44,6 +44,9 @@ jobs: - name: Verify portable service and model substitution working-directory: 02-tmcra-memory-api run: python -m unittest test_portable_release.py test_tmcra_service_model_flexibility.py + - name: Verify feedback and local-runtime safety contracts + working-directory: 02-tmcra-memory-api + run: python -m unittest discover -s tmcra_service/tests -q - name: Run frozen benchmark contracts working-directory: 09-tmcra-benchmarks env: diff --git a/.gitignore b/.gitignore index 9335a3c..9ae2dac 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ tmcra_service_state/ 03-tmcra-web-console/public/downloads/tmcra-codex-*.zip 03-tmcra-web-console/desktop/tmcra-memory/resources/tmcra-codex-* 04-tmcra-desktop/resources/tmcra-codex-* +release/ +docs/LOCAL_DEPLOYMENT_PRODUCTION_AUDIT.zh-CN.md diff --git a/01-tmcra-agent-memory-algorithm/deploy/local-model-profiles.json b/01-tmcra-agent-memory-algorithm/deploy/local-model-profiles.json new file mode 100644 index 0000000..460605c --- /dev/null +++ b/01-tmcra-agent-memory-algorithm/deploy/local-model-profiles.json @@ -0,0 +1,132 @@ +{ + "schema_version": "tmcra.local-model-profiles.1", + "verified_upstream_on": "2026-09-06", + "status": "windows_local_preview_partial_validation", + "installation_enabled": true, + "scope": "full_local_runtime_preview", + "full_memory_system_ready": false, + "hardware_requirements_are": "conservative_planning_estimates_not_benchmark_results", + "profiles": [ + { + "id": "lite-cpu", + "name_zh": "轻量版", + "recommendation_zh": "普通笔记本、无独显电脑;中英文短记忆,低并发", + "validation": "cpu_ingest_and_raw_recall_passed_complex_compile_timed_out", + "system_ram_gib_min": 8, + "system_ram_gib_recommended_for_full_memory": 16, + "retrieval_vram_gib_recommended": 0, + "weights_bytes": 941234298, + "embedding": { + "repo_id": "intfloat/multilingual-e5-small", + "revision": "614241f622f53c4eeff9890bdc4f31cfecc418b3", + "license": "MIT", + "upstream": "https://huggingface.co/intfloat/multilingual-e5-small", + "weights": [{"file": "model.safetensors", "bytes": 470641600, "sha256": "1a55775f53449dac10a2bcbc312469fac40b96d53198c407081a831f81c98477"}], + "dimensions": 384, + "model_max_tokens": 512, + "pooling": "mean", + "normalize": true, + "query_prefix": "query: ", + "document_prefix": "passage: ", + "padding_side": "right" + }, + "reranker": { + "repo_id": "cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "revision": "1427fd652930e4ba29e8149678df786c240d8825", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "weights": [{"file": "model.safetensors", "bytes": 470592698, "sha256": "5daeca2481a76b5976a2bdc32f0a78532b6716da4f8cd3ff59460ef8d2f359b4"}], + "adapter": "sequence-classification", + "model_max_tokens": 512, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["memory_pressure_retest", "complex_compile_latency", "organizer_validation", "full_service_restart_validation"] + }, + { + "id": "balanced-bge", + "name_zh": "均衡版", + "recommendation_zh": "优先复现现有生产检索模型;16GB 以上内存,建议有独显", + "validation": "production_model_stack_verified_consumer_installer_pending", + "system_ram_gib_min": 16, + "system_ram_gib_recommended_for_full_memory": 32, + "retrieval_vram_gib_recommended": 6, + "weights_bytes": 4542217682, + "embedding": { + "repo_id": "BAAI/bge-m3", + "revision": "5617a9f61b028005a4858fdac845db406aefb181", + "license": "MIT", + "upstream": "https://huggingface.co/BAAI/bge-m3", + "weights": [{"file": "pytorch_model.bin", "bytes": 2271145830, "sha256": "b5e0ce3470abf5ef3831aa1bd5553b486803e83251590ab7ff35a117cf6aad38"}], + "dimensions": 1024, + "model_max_tokens": 8192, + "pooling": "cls", + "normalize": true, + "query_prefix": "", + "document_prefix": "", + "padding_side": "right" + }, + "reranker": { + "repo_id": "BAAI/bge-reranker-v2-m3", + "revision": "953dc6f6f85a1b2dbfca4c34a2796e7dde08d41e", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/BAAI/bge-reranker-v2-m3", + "weights": [{"file": "model.safetensors", "bytes": 2271071852, "sha256": "d9e3e081faff1eefb84019509b2f5558fd74c1a05a2c7db22f74174fcedb5286"}], + "adapter": "sequence-classification", + "model_max_tokens": 8192, + "production_runtime_max_tokens": 1280, + "tmcra_fusion_checkpoint_compatible": true + }, + "required_work": ["single_recall_lane", "desktop_worker_and_context_budgets", "desktop_installer", "offline_end_to_end_validation"] + }, + { + "id": "quality-qwen", + "name_zh": "增强版候选", + "recommendation_zh": "32GB 以上内存、高显存电脑;长文本和跨语言检索候选,需与均衡版实测比较", + "validation": "upstream_artifacts_verified_runtime_pending", + "system_ram_gib_min": 32, + "system_ram_gib_recommended_for_full_memory": 64, + "retrieval_vram_gib_recommended": 16, + "weights_bytes": 9235180368, + "embedding": { + "repo_id": "Qwen/Qwen3-Embedding-4B", + "revision": "5cf2132abc99cad020ac570b19d031efec650f2b", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Embedding-4B", + "weights": [ + {"file": "model-00001-of-00002.safetensors", "bytes": 4965826464, "sha256": "e70bfe3c970523fb7ef4eddffed2254ce3f1e7150c3de2af4342de129dd756f8"}, + {"file": "model-00002-of-00002.safetensors", "bytes": 3077765624, "sha256": "ed1b87c8e9eb7e535a1a155e4fd00d9f4dba80e58a6db48a4c9f82cede7079c1"} + ], + "dimensions": 2560, + "model_max_tokens": 32768, + "pooling": "last_token", + "normalize": true, + "query_prefix": "Instruct: Given a query about previous conversations, retrieve the relevant source passages.\nQuery: ", + "document_prefix": "", + "padding_side": "left" + }, + "reranker": { + "repo_id": "Qwen/Qwen3-Reranker-0.6B", + "revision": "e61197ed45024b0ed8a2d74b80b4d909f1255473", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Reranker-0.6B", + "weights": [{"file": "model.safetensors", "bytes": 1191588280, "sha256": "27cd75a405b9c1b46b59abfd88aaa209e6fed2a1972cde9b70e7659537c5e65b"}], + "adapter": "causal-lm-yes-no", + "model_max_tokens": 32768, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["qwen_yes_no_reranker_adapter", "service_variable_embedding_dimensions", "bounded_gpu_batches", "full_index_rebuild", "quality_and_latency_comparison"] + } + ], + "deployment_contract": { + "automatic_profile_switch_on_existing_index": false, + "cloud_fallback_in_full_local_mode": false, + "cloud_account_required_in_full_local_mode": false, + "generation_model_included_in_weights_bytes": false, + "model_cache_and_python_runtime_included_in_weights_bytes": false, + "required_index_identity": ["repo_id", "revision", "dimensions", "pooling", "query_prefix", "document_prefix", "normalization", "precision", "chunking_policy"], + "existing_sources_must_be_preserved": true, + "existing_indexes_must_be_rebuilt_before_activation": true, + "runtime_downloads_after_setup": false, + "readiness_requires_actual_inference": true + } +} diff --git a/01-tmcra-agent-memory-algorithm/run_tmcra_v4_build.py b/01-tmcra-agent-memory-algorithm/run_tmcra_v4_build.py index 5e16fe8..a74c35b 100644 --- a/01-tmcra-agent-memory-algorithm/run_tmcra_v4_build.py +++ b/01-tmcra-agent-memory-algorithm/run_tmcra_v4_build.py @@ -47,6 +47,9 @@ def _stage(root: Path, name: str, **values: Any) -> None: def _load_shell_environment(path: Path) -> dict[str, str]: + from tmcra_local_only import enabled, read_environment + if enabled(): + return read_environment(path) if not path.is_file(): raise BuildError(f"writer environment file is missing: {path}") command = 'set -a; source "$1"; env -0' @@ -82,6 +85,10 @@ def _rotated(keys: Sequence[str], worker_index: int) -> str: def _worker_environment(base: Mapping[str, str], keys: Sequence[str], worker_index: int) -> dict[str, str]: environment = dict(base) + from tmcra_local_only import enabled, validate_environment + if enabled(environment): + validate_environment(environment) + return environment pool = _rotated(keys, worker_index) base_url = environment.get("TMCRA_DEEPSEEK_WRITER_BASE_URL") or environment.get("TMCRA_WRITER_BASE_URL") or "https://api.deepseek.com/v1" max_tokens = environment.get("TMCRA_WRITER_MAX_TOKENS", "16384") diff --git a/01-tmcra-agent-memory-algorithm/shared_core_manifest.json b/01-tmcra-agent-memory-algorithm/shared_core_manifest.json index 5588abf..d1de7b5 100644 --- a/01-tmcra-agent-memory-algorithm/shared_core_manifest.json +++ b/01-tmcra-agent-memory-algorithm/shared_core_manifest.json @@ -1,7 +1,7 @@ { "schema_version": "tmcra.service.shared-core-manifest.1", - "service_version": "0.3.0-rc2", - "generated_on": "2026-08-17", + "service_version": "1.0.0-rc.1", + "generated_on": "2026-09-06", "algorithm_files": [ { "path": "prepare_tmcra_v4_e2e_data.py", @@ -9,7 +9,7 @@ }, { "path": "run_tmcra_v4_build.py", - "sha256": "1ebc54751fcfea91bbd8ea019cac45ca79cf60ce229bf7249d0427955093f93e" + "sha256": "4172caaa4e5a9b75dc2dec7c8188e6f585376aecb41e4f08a2514b25193ee4b9" }, { "path": "run_tmcra_v4_compile_evidence.py", @@ -17,7 +17,7 @@ }, { "path": "tmp_tmcra_v2_lme_pipeline.py", - "sha256": "22768faa73f61050373791179f83a33595b46a3d9fb35476ef8054222a446cbd" + "sha256": "7e1ade3b1902c14c405be975c99764b6fac4843bd3b2a8ace5185593ec2fe365" }, { "path": "tmcra_v2_lme_pipeline.py", @@ -25,7 +25,7 @@ }, { "path": "tmcra_v3_online_runtime.py", - "sha256": "75186638496fe9271b711e0ba76cb93b232a5684e75b565dfe4721bf821c0a12" + "sha256": "18b55050ff04bc8235b6c5aa2d53adf891a793179b4478bf4cfdfd6038c7195d" }, { "path": "tmcra_v3_product_writer.py", @@ -41,7 +41,7 @@ }, { "path": "tmcra_v4_batch_writer.py", - "sha256": "352568d64d831dbb28a228e9cd898f688636330b13ac2ff99e5ed36226a4dbf2" + "sha256": "a46a3695b08a8a5bd205863a43c416340863976f274d851ed2db4d04f5c125f5" }, { "path": "tmcra_v4_cost_report.py", @@ -53,15 +53,15 @@ }, { "path": "tmcra_v4_evidence_planner.py", - "sha256": "99dd6cd40bd205a4e9f10bc748b05aff848e187c9ce5f5f6fca9237a9d32aa99" + "sha256": "dfe546149fc8a5596ed311032020f36737eab37290a9e69255d2fae0fd708c7a" }, { "path": "tmcra_v4_online_runtime.py", - "sha256": "4fee0d591cd4140353d0adf57287e93534607e06db7c92b5ab42fbb0afe45db2" + "sha256": "7ef1bb4ec78094fa166750b78b567079b7048ca52787cfbefd7e3aaf8a9a8a2e" }, { "path": "tmcra_v4_slow_graph.py", - "sha256": "985e2aab12eba2b96bd53cc05e7352412fb45bd3d9fee3a0a8213b26ff4dba0b" + "sha256": "7ebf6d258b85c9a463e55c0dcdc817e9fc27b42fc93af7abdf48e62ecf8acf42" }, { "path": "tmcra_v4_recall_planner.py", @@ -78,6 +78,14 @@ { "path": "tmcra_v4_typed_semantics.py", "sha256": "367917528c80829a9b99ecebc1f9c533fb77f39753713b65abadbddb9c4e43e5" + }, + { + "path": "tmcra_local_only.py", + "sha256": "16da1be2c9d8bf881481ea64a09de30b423e3c4c496017e0b693e0bd2ba45e05" + }, + { + "path": "tmcra_local_models.py", + "sha256": "f464a241c7f7ca2f78a52f7c03d7157520795281ac5c7e01faeaea4606274fb4" } ] } diff --git a/01-tmcra-agent-memory-algorithm/tmcra_local_models.py b/01-tmcra-agent-memory-algorithm/tmcra_local_models.py new file mode 100644 index 0000000..9a655b9 --- /dev/null +++ b/01-tmcra-agent-memory-algorithm/tmcra_local_models.py @@ -0,0 +1,101 @@ +"""Pinned retrieval profiles shared by the API and its real index workers.""" +from __future__ import annotations + +import hashlib +import json +import os +from pathlib import Path + +PROFILE_FILE = Path(__file__).resolve().parent / "deploy" / "local-model-profiles.json" + + +def profiles(): + return json.loads(PROFILE_FILE.read_text(encoding="utf-8"))["profiles"] + + +def profile_by_id(identity): + for profile in profiles(): + if profile["id"] == identity: + return profile + raise ValueError("unknown local model profile") + + +def signature(profile): + # A model change, pooling change or window-policy change requires reindexing. + contract = {"embedding": profile["embedding"], "source_windows": "token-char-covered-v1", + "long_slow_embedding": "normalized-window-mean-v1"} + return hashlib.sha256(json.dumps(contract, sort_keys=True, separators=(",", ":")).encode()).hexdigest() + + +def apply_local_profile(args): + if os.getenv("TMCRA_DEPLOYMENT_MODE") != "local": + return args + profile = profile_by_id(os.environ["TMCRA_LOCAL_PROFILE"]) + embed = profile["embedding"] + rerank = profile["reranker"] + args.embedding_profile_id = profile["id"] + args.embedding_index_signature = signature(profile) + args.embedding_model = os.environ["TMCRA_EMBEDDING_MODEL"] + args.cross_model = os.environ["TMCRA_CROSS_MODEL"] + args.text_dim = embed["dimensions"] + args.embedding_max_length = embed["model_max_tokens"] + args.embedding_pooling = embed["pooling"] + args.embedding_query_prefix = embed["query_prefix"] + args.embedding_document_prefix = embed["document_prefix"] + args.embedding_padding_side = embed["padding_side"] + args.embedding_strict_max_length = True + args.embedding_long_document_policy = "window_mean" + args.reranker_mode = "fusion" if rerank["tmcra_fusion_checkpoint_compatible"] else "semantic-only" + args.reranker_adapter = rerank["adapter"] + args.cross_max_length = min(rerank["model_max_tokens"], 1280) + args.cross_batch_size = 2 if args.device == "cpu" else 8 + args.batch_size = 4 if args.device == "cpu" else 8 + return args + + +def verify_index_identity(payload, args): + expected = getattr(args, "embedding_index_signature", "") + if expected and (payload.get("embedding_index_signature") != expected + or payload.get("text_dim") != args.text_dim): + raise RuntimeError("index embedding identity differs; rebuild into a new generation before recall") + + +def sha256_file(path): + digest = hashlib.sha256() + with Path(path).open("rb") as handle: + for block in iter(lambda: handle.read(8 * 1024 * 1024), b""): + digest.update(block) + return digest.hexdigest() + + +def verify_weights(model, directory): + directory = Path(directory) + for asset in model["weights"]: + path = directory / asset["file"] + if (not path.is_file() or path.stat().st_size != asset["bytes"] + or sha256_file(path) != asset["sha256"]): + raise RuntimeError(f"model asset is missing or failed SHA-256 verification: {asset['file']}") + + +QWEN_SYSTEM = ("<|im_start|>system\nJudge whether the Document meets the requirements based on the Query " + "and the Instruct provided. Note that the answer can only be \"yes\" or \"no\"." + "<|im_end|>\n<|im_start|>user\n") +QWEN_SUFFIX = "<|im_end|>\n<|im_start|>assistant\n\n\n\n\n" + + +def qwen_rerank_windows(tokenizer, query, document, *, max_length): + prefix = QWEN_SYSTEM + (": Given a query about previous conversations, retrieve the relevant " + f"source passages.\n: {query}\n: ") + head = tokenizer.encode(prefix, add_special_tokens=False) + tail = tokenizer.encode(QWEN_SUFFIX, add_special_tokens=False) + body = tokenizer.encode(document, add_special_tokens=False) + capacity = max_length - len(head) - len(tail) + if capacity < 32: + raise ValueError("reranker query leaves insufficient document context; shorten the query") + step = max(1, capacity - min(192, capacity // 4)) + windows = [] + for start in range(0, max(1, len(body)), step): + windows.append(head + body[start:start + capacity] + tail) + if start + capacity >= len(body): + break + return windows diff --git a/01-tmcra-agent-memory-algorithm/tmcra_local_only.py b/01-tmcra-agent-memory-algorithm/tmcra_local_only.py new file mode 100644 index 0000000..e5dd8f5 --- /dev/null +++ b/01-tmcra-agent-memory-algorithm/tmcra_local_only.py @@ -0,0 +1,193 @@ +"""Explicit full-local runtime boundary, also used by Python worker processes. + +Installation/downloads run outside this boundary. This is a process-level guard, +not an OS firewall or a sandbox for untrusted plugins/native code. +""" +from __future__ import annotations + +import ipaddress +import json +import os +import sys +import time +from contextlib import contextmanager +from pathlib import Path +from urllib.parse import urlsplit + +_guard_installed = False +ROLES = ("WRITER", "WRITER_REVIEWER", "RECALL_PLANNER", "SLOW_GRAPH", + "SUBJECT_ATTRIBUTION", "EVIDENCE_COMPILER", "SESSION_GRAPH") + + +def enabled(environment=None): + return (os.environ if environment is None else environment).get("TMCRA_DEPLOYMENT_MODE") == "local" + + +def loopback_url(value, *, port=None, path=None): + parsed = urlsplit(value) + try: + address = ipaddress.ip_address(parsed.hostname or "") + valid_port = parsed.port + except ValueError as exc: + raise ValueError("local URLs require a numeric loopback address and valid port") from exc + if (parsed.scheme != "http" or not address.is_loopback or not valid_port + or parsed.username is not None or parsed.password is not None + or parsed.query or parsed.fragment + or (port is not None and valid_port != int(port)) + or (path is not None and parsed.path.rstrip("/") != path)): + raise ValueError("full-local URLs must use the configured loopback HTTP endpoint") + return parsed + + +def validate_environment(environment): + if not enabled(environment): + raise ValueError("full-local deployment mode is required") + generation = loopback_url(environment["TMCRA_LOCAL_WRITER_BASE_URL"], path="/v1") + public = loopback_url(environment["TMCRA_SERVICE_PUBLIC_BASE_URL"], + port=environment["TMCRA_SERVICE_BIND_PORT"], path="") + if public.hostname != environment.get("TMCRA_SERVICE_BIND_HOST"): + raise ValueError("local service URL and bind host differ") + for role in ROLES: + loopback_url(environment[f"TMCRA_{role}_BASE_URL"], port=generation.port, path="/v1") + if environment[f"TMCRA_{role}_BASE_URL"] != environment["TMCRA_LOCAL_WRITER_BASE_URL"]: + raise ValueError(f"local model route differs: {role}") + if not environment.get(f"TMCRA_{role}_MODEL"): + raise ValueError(f"local model identity is missing: {role}") + for name, value in environment.items(): + if name.lower() in {"http_proxy", "https_proxy", "all_proxy"} and value: + raise ValueError("proxies must be cleared in full-local mode") + if name.startswith("TMCRA_") and name.endswith(("_BASE_URL", "_ENDPOINT", "_URL")) and value: + loopback_url(value) + return environment + + +def configure_routes(environment, *, base_url, model, key): + """Return a private child environment; never mutate host/cloud credentials.""" + loopback_url(base_url, path="/v1") + if not model or not key or any(c in key for c in ",\r\n"): + raise ValueError("one local model alias and API key are required") + clean = {} + for name, value in environment.items(): + upper = name.upper() + if (upper.startswith(("TMCRA_", "OPENAI_", "ANTHROPIC_", "DEEPSEEK_", "ARK_", "DASHSCOPE_")) + or upper in {"HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"}): + continue + clean[name] = value + # Keep service settings explicitly selected by the local installer only. + clean.update({name: value for name, value in environment.items() + if name.startswith(("TMCRA_SERVICE_", "TMCRA_LOCAL_", "TMCRA_EMBEDDING_"))}) + clean.update({"TMCRA_DEPLOYMENT_MODE": "local", "HF_HUB_OFFLINE": "1", + "TRANSFORMERS_OFFLINE": "1", "HF_HUB_DISABLE_TELEMETRY": "1", + "HF_HUB_DISABLE_IMPLICIT_TOKEN": "1", "NO_PROXY": "*", + "TMCRA_LOCAL_WRITER_BASE_URL": base_url, "TMCRA_LOCAL_WRITER_MODEL": model}) + for role in ROLES: + clean.update({f"TMCRA_{role}_BASE_URL": base_url, f"TMCRA_{role}_MODEL": model, + f"TMCRA_{role}_API_KEY_POOL": key, f"TMCRA_{role}_KEY_POOL": key, + f"TMCRA_{role}_PROVIDER": "local-qwen"}) + clean.update({"TMCRA_WRITER_PROMPT_ADAPTER": "qwen36-v5", + "TMCRA_WRITER_REVIEWER_PROMPT_ADAPTER": "qwen36-reconciliation-v1", + "TMCRA_RECALL_PLANNER_PROMPT_ADAPTER": "qwen36-planner-v1", + "TMCRA_SLOW_GRAPH_PROMPT_ADAPTER": "qwen36-slow-graph-v1", + "TMCRA_WRITER_MAX_TOKENS": "16384", + "TMCRA_SLOW_GRAPH_MAX_TOKENS": "16384", + "TMCRA_RECALL_PLANNER_MAX_TOKENS": "512", + "TMCRA_RECALL_PLANNER_TIMEOUT_SECONDS": "600"}) + # Older core modules read these aliases. They contain ONLY the local endpoint + # and its generated key, with zero cloud prices and no inherited cloud pool. + for role in ("DEEPSEEK_WRITER", "DEEPSEEK_FLASH", "DEEPSEEK_PRO"): + clean.update({f"TMCRA_{role}_BASE_URL": base_url, f"TMCRA_{role}_MODEL": model, + f"TMCRA_{role}_KEY_POOL": key, f"TMCRA_{role}_MAX_TOKENS": "16384"}) + for cost in ("PROMPT", "COMPLETION", "CACHE"): + clean[f"TMCRA_{role}_{cost}_COST_PER_MILLION"] = "0" + return clean + + +def read_environment(path): + data = json.loads(Path(path).read_text(encoding="utf-8")) + if not isinstance(data, dict) or data.get("schema_version") != "tmcra.local-environment.1": + raise ValueError("invalid local environment schema") + values = data.get("environment") + if not isinstance(values, dict) or any(not isinstance(k, str) or not isinstance(v, str) for k, v in values.items()): + raise ValueError("local environment must be a string mapping") + # No shell expansion or executable configuration. + result = dict(os.environ) + operation_names = {"TMCRA_SERVICE_TENANT_ID", "TMCRA_SERVICE_SCOPE_NAME", "TMCRA_SERVICE_JOB_ID", + "TMCRA_SERVICE_STAGE_ID", "TMCRA_SERVICE_STAGE_ATTEMPT", "TMCRA_USAGE_ATTRIBUTION_JSON"} + operation = {name: result[name] for name in operation_names if name in result} + for name in list(result): + if name.upper().startswith(("TMCRA_", "OPENAI_", "ANTHROPIC_", "DEEPSEEK_", "ARK_", "DASHSCOPE_")) or name.upper() in {"HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"}: + result.pop(name) + result.update(values) + result.update(operation) + validate_environment(result) + return result + + +def install_network_guard(): + global _guard_installed + if _guard_installed: + return + + def check_host(host): + if host in (None, ""): + return + if isinstance(host, bytes): + host = host.decode("ascii", errors="strict") + try: + address = ipaddress.ip_address(host) + except ValueError: + raise PermissionError("TMCRA full-local mode blocks DNS and non-numeric network hosts") from None + if not address.is_loopback: + raise PermissionError("TMCRA full-local mode blocks external network connections") + + def audit(event, args): + if event == "socket.getaddrinfo": + check_host(args[0]) + elif event in {"socket.gethostbyname", "socket.gethostbyaddr"}: + check_host(args[0]) + elif event in {"socket.connect", "socket.bind"}: + address = args[1] + if isinstance(address, tuple): + check_host(address[0]) + elif event == "socket.sendto": + address = args[-1] + if isinstance(address, tuple): + check_host(address[0]) + + sys.addaudithook(audit) + _guard_installed = True + + +@contextmanager +def process_lock(path, *, timeout=60): + """Cooperating process lock on Windows and POSIX; state survives crashes.""" + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("a+b") as handle: + if handle.tell() == 0: + handle.write(b"\0") + handle.flush() + if os.name == "nt": + import msvcrt + deadline = time.monotonic() + timeout + while True: + handle.seek(0) + try: + msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1) + break + except OSError: + if time.monotonic() >= deadline: + raise TimeoutError("another local process holds the state lock") from None + time.sleep(0.1) + try: + yield + finally: + handle.seek(0) + msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1) + else: + import fcntl + fcntl.flock(handle, fcntl.LOCK_EX) + try: + yield + finally: + fcntl.flock(handle, fcntl.LOCK_UN) diff --git a/01-tmcra-agent-memory-algorithm/tmcra_v3_online_runtime.py b/01-tmcra-agent-memory-algorithm/tmcra_v3_online_runtime.py index ef308db..9668672 100644 --- a/01-tmcra-agent-memory-algorithm/tmcra_v3_online_runtime.py +++ b/01-tmcra-agent-memory-algorithm/tmcra_v3_online_runtime.py @@ -878,6 +878,7 @@ def parent_subchunks( scope_id: str, subchunk_chars: int, subchunk_overlap: int, + vectorizer: Any = None, ) -> list[dict[str, Any]]: candidates: list[dict[str, Any]] = [] for parent in parents: @@ -892,7 +893,10 @@ def parent_subchunks( f"parent_chunk={int(parent['parent_chunk_index']):02d}" ) payload_chars = int(subchunk_chars) - len(prefix) - 1 - spans = covered_windows(str(parent["text"]), payload_chars, int(subchunk_overlap)) + spans = (vectorizer.source_spans(str(parent["text"]), prefix=prefix + "\n", + max_chars=payload_chars, overlap_chars=int(subchunk_overlap)) + if vectorizer is not None and hasattr(vectorizer, "source_spans") + else covered_windows(str(parent["text"]), payload_chars, int(subchunk_overlap))) for subchunk_index, (char_start, char_end) in enumerate(spans, start=1): text = f"{prefix}\n{str(parent['text'])[char_start:char_end]}" if len(text) > subchunk_chars: @@ -1335,6 +1339,8 @@ def __call__( class OnlineModels: def __init__(self, args: argparse.Namespace): + from tmcra_local_models import apply_local_profile + apply_local_profile(args) self.device = torch.device(args.device) if self.device.type == "cuda" and not torch.cuda.is_available(): raise RuntimeError("CUDA is unavailable") @@ -1348,6 +1354,7 @@ def __init__(self, args: argparse.Namespace): query_prefix=str(getattr(args, "embedding_query_prefix", "")), document_prefix=str(getattr(args, "embedding_document_prefix", "")), padding_side=str(getattr(args, "embedding_padding_side", "right")), + long_document_policy=str(getattr(args, "embedding_long_document_policy", "reject")), ) self.reranker_mode = str( getattr(args, "reranker_mode", "fusion") or "fusion" @@ -1370,7 +1377,7 @@ def __init__(self, args: argparse.Namespace): self.fusion = _SemanticOnlyFusion() return - from transformers import AutoModelForSequenceClassification, AutoTokenizer + from transformers import AutoModelForCausalLM, AutoModelForSequenceClassification, AutoTokenizer cross_path = Path(args.cross_model).resolve() model_manifest_path = cross_path / "TMCRA_MODEL_MANIFEST.json" @@ -1378,7 +1385,14 @@ def __init__(self, args: argparse.Namespace): raise FileNotFoundError(f"pinned cross model manifest is required: {model_manifest_path}") self.cross_manifest = json.loads(model_manifest_path.read_text(encoding="utf-8")) self.cross_tokenizer = AutoTokenizer.from_pretrained(str(cross_path), local_files_only=True) - self.cross_model = AutoModelForSequenceClassification.from_pretrained( + self.reranker_adapter = getattr(args, "reranker_adapter", "sequence-classification") + if self.reranker_adapter not in {"sequence-classification", "causal-lm-yes-no"}: + raise ValueError("unsupported reranker adapter") + causal = self.reranker_adapter == "causal-lm-yes-no" + if causal and self.reranker_mode != "semantic-only": + raise ValueError("Qwen yes/no reranker requires semantic-only scoring") + model_class = AutoModelForCausalLM if causal else AutoModelForSequenceClassification + self.cross_model = model_class.from_pretrained( str(cross_path), local_files_only=True, torch_dtype=torch.float16 if self.device.type == "cuda" else torch.float32, @@ -1412,6 +1426,8 @@ def __init__(self, args: argparse.Namespace): self.checkpoint_sha256 = sha256_file(checkpoint_path) def encode_cross(self, query: str, texts: Sequence[str]) -> tuple[torch.Tensor, torch.Tensor]: + if getattr(self, "reranker_adapter", "") == "causal-lm-yes-no": + return self._encode_causal_cross(query, texts) if self.reranker_mode == "dense-only": if not texts: raise RuntimeError("dense-only reranker got no texts") @@ -1498,6 +1514,30 @@ def encode_cross(self, query: str, texts: Sequence[str]) -> tuple[torch.Tensor, logits.append(torch.stack(selected_logits, dim=0)) return torch.cat(representations, dim=0), torch.cat(logits, dim=0) + def _encode_causal_cross(self, query, texts): + from tmcra_local_models import qwen_rerank_windows + if not texts: + raise ValueError("reranker got no documents") + tokenizer = self.cross_tokenizer + tokenizer.padding_side = "left" + labels = [tokenizer.encode(label, add_special_tokens=False) for label in ("no", "yes")] + if any(len(label) != 1 for label in labels) or labels[0] == labels[1]: + raise RuntimeError("Qwen yes/no token contract differs") + scores = [] + with torch.inference_mode(): + for text in texts: + windows = qwen_rerank_windows(tokenizer, query, text, max_length=self.cross_max_length) + window_scores = [] + for start in range(0, len(windows), self.cross_batch_size): + encoded = tokenizer.pad({"input_ids": windows[start:start + self.cross_batch_size]}, + padding=True, return_tensors="pt") + encoded = {key: value.to(self.device) for key, value in encoded.items()} + output = self.cross_model(**encoded, logits_to_keep=1, return_dict=True) + logits = output.logits[:, -1, [labels[0][0], labels[1][0]]].float() + window_scores.append(torch.log_softmax(logits, dim=-1)[:, 1]) + scores.append(torch.cat(window_scores).max()) + return torch.empty((len(texts), 0), device=self.device), torch.stack(scores) + def load_online_index(path: Path, expected_db: Path, expected_scope: str) -> tuple[list[dict[str, Any]], torch.Tensor, list[dict[str, Any]], torch.Tensor, list[dict[str, Any]], dict[str, Any]]: payload = torch.load(path, map_location="cpu", weights_only=False) diff --git a/01-tmcra-agent-memory-algorithm/tmcra_v4_batch_writer.py b/01-tmcra-agent-memory-algorithm/tmcra_v4_batch_writer.py index dd8df64..99965a9 100644 --- a/01-tmcra-agent-memory-algorithm/tmcra_v4_batch_writer.py +++ b/01-tmcra-agent-memory-algorithm/tmcra_v4_batch_writer.py @@ -2766,20 +2766,13 @@ def _commit_guard(self): f".{Path(self.adapter.storage_path).name}.{sha256_text(self.scope_id)[:16]}.commit.lock" ) lock_path.parent.mkdir(parents=True, exist_ok=True) - with self._process_commit_lock(), lock_path.open("a+b") as lock_file: - try: - import fcntl - except ImportError: - fcntl = None - if fcntl is not None: - fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX) + from tmcra_local_only import process_lock + with self._process_commit_lock(), process_lock(lock_path, timeout=600): self._scope_lock_depth = 1 try: yield finally: self._scope_lock_depth = 0 - if fcntl is not None: - fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN) @contextmanager def mutation_batch(self): diff --git a/01-tmcra-agent-memory-algorithm/tmcra_v4_online_runtime.py b/01-tmcra-agent-memory-algorithm/tmcra_v4_online_runtime.py index 1784615..a63f30c 100644 --- a/01-tmcra-agent-memory-algorithm/tmcra_v4_online_runtime.py +++ b/01-tmcra-agent-memory-algorithm/tmcra_v4_online_runtime.py @@ -3038,6 +3038,8 @@ def finish_phase(name: str) -> None: base_candidates, base_payload = load_online_index_catalog( base_index_path, base_db_path, scope_id ) + from tmcra_local_models import verify_index_identity + verify_index_identity(base_payload, args) text_dim = int(base_payload["text_dim"]) if text_dim != int(_arg(args, "text_dim", text_dim)): raise RuntimeError("online delta text dimension differs from the active base") @@ -3120,6 +3122,7 @@ def finish_phase(name: str) -> None: scope_id=scope_id, subchunk_chars=int(base_payload["subchunk_chars"]), subchunk_overlap=int(base_payload["subchunk_overlap"]), + vectorizer=vectorizer, ) if parents else [] @@ -3162,6 +3165,7 @@ def finish_phase(name: str) -> None: scope_id=scope_id, subchunk_chars=int(base_payload["subchunk_chars"]), subchunk_overlap=int(base_payload["subchunk_overlap"]), + vectorizer=vectorizer, ) base_ids_for_diff = { _clean(item.get("candidate_id")) for item in base_candidates @@ -3369,6 +3373,7 @@ def build_online_base_index( scope_id=scope_id, subchunk_chars=expected["subchunk_chars"], subchunk_overlap=expected["subchunk_overlap"], + vectorizer=vectorizer, ) slow, semantic_records = load_v4_layered_inventory(db_path, scope_id, parents) slow_counts = _validated_slow_inventory_counts(slow) @@ -3600,6 +3605,7 @@ def command_build_index(args: argparse.Namespace) -> None: padding_side=str( getattr(args, "embedding_padding_side", "right") ), + long_document_policy=str(getattr(args, "embedding_long_document_policy", "reject")), ) graph_fingerprint = v3.scope_fingerprint(db_path, scope_id) parents = v3.load_persisted_parent_chunks(db_path, scope_id) @@ -3608,6 +3614,7 @@ def command_build_index(args: argparse.Namespace) -> None: scope_id=scope_id, subchunk_chars=args.subchunk_chars, subchunk_overlap=args.subchunk_overlap, + vectorizer=vectorizer, ) slow, semantic_records = load_v4_layered_inventory( db_path, scope_id, parents @@ -4118,6 +4125,8 @@ def main() -> int: retrieve = sub.add_parser("retrieve") retrieve.add_argument("--query-manifest", required=True); retrieve.add_argument("--out-dir", required=True); retrieve.add_argument("--resume", action="store_true"); retrieve.add_argument("--planner-replay-dir"); retrieve.add_argument("--checkpoint", required=True); retrieve.add_argument("--cross-model", default="/opt/tmcra-models/BAAI/bge-reranker-v2-m3"); retrieve.add_argument("--cross-max-length", type=int, default=1280); retrieve.add_argument("--cross-batch-size", type=int, default=24); retrieve.add_argument("--repo", required=True); retrieve.add_argument("--harness", required=True); retrieve.add_argument("--node-model", required=True); retrieve.add_argument("--path-model", required=True); retrieve.add_argument("--graph-device", default="cuda"); retrieve.add_argument("--candidate-event-k", type=int, default=24); retrieve.add_argument("--support-path-k", type=int, default=3); retrieve.add_argument("--path-tunnel-rescue-k", type=int, default=2); retrieve.add_argument("--graph-top-k", type=int, default=12); retrieve.add_argument("--dense-k", type=int, default=32); retrieve.add_argument("--slow-dense-k", type=int, default=24); retrieve.add_argument("--graph-k", type=int, default=24); retrieve.add_argument("--execution-lane", choices=sorted(EXECUTION_LANES), default="production"); retrieve.add_argument("--composition-mode", choices=sorted(COMPOSITION_MODES), default="layered"); retrieve.add_argument("--packing-budget-mode", choices=sorted(PACKING_BUDGET_MODES), default="fixed"); retrieve.add_argument("--top-k", type=int, default=8); retrieve.add_argument("--adaptive-simple-k", type=int, default=8); retrieve.add_argument("--adaptive-standard-k", type=int, default=12); retrieve.add_argument("--adaptive-complex-k", type=int, default=16); add_common_model_args(retrieve) args = parser.parse_args() + from tmcra_local_models import apply_local_profile + apply_local_profile(args) (command_build_index if args.command == "build-index" else command_retrieve)(args) return 0 diff --git a/01-tmcra-agent-memory-algorithm/tmcra_v4_slow_graph.py b/01-tmcra-agent-memory-algorithm/tmcra_v4_slow_graph.py index e4b2091..d9cadc2 100644 --- a/01-tmcra-agent-memory-algorithm/tmcra_v4_slow_graph.py +++ b/01-tmcra-agent-memory-algorithm/tmcra_v4_slow_graph.py @@ -1232,7 +1232,7 @@ def _propose( self.config.provider == LOCAL_QWEN_PROVIDER and self.config.base_url == LOCAL_QWEN_BASE_URL ): - body["id_slot"] = LOCAL_QWEN_GRAPH_SLOT_ID + body["id_slot"] = 0 if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else LOCAL_QWEN_GRAPH_SLOT_ID if self.config.provider == DEEPSEEK_PROVIDER: body.update( { diff --git a/01-tmcra-agent-memory-algorithm/tmp_tmcra_v2_lme_pipeline.py b/01-tmcra-agent-memory-algorithm/tmp_tmcra_v2_lme_pipeline.py index 229e117..42e69b8 100644 --- a/01-tmcra-agent-memory-algorithm/tmp_tmcra_v2_lme_pipeline.py +++ b/01-tmcra-agent-memory-algorithm/tmp_tmcra_v2_lme_pipeline.py @@ -348,6 +348,7 @@ def __init__( query_prefix: str = "", document_prefix: str = "", padding_side: str = "right", + long_document_policy: str = "reject", ): from transformers import AutoModel, AutoTokenizer self.dim = int(dim) @@ -359,6 +360,9 @@ def __init__( self.query_prefix = str(query_prefix or "") self.document_prefix = str(document_prefix or "") self.padding_side = clean_text(padding_side).lower() or "right" + self.long_document_policy = long_document_policy + if long_document_policy not in {"reject", "window_mean"}: + raise ValueError("unknown long document policy") if self.max_length <= 0: raise RuntimeError("--embedding-max-length must be positive") if self.pooling not in {"cls", "mean", "last_token"}: @@ -369,7 +373,10 @@ def __init__( self.model_path = str(resolved) self.tokenizer = AutoTokenizer.from_pretrained(str(resolved), local_files_only=True) self.tokenizer.padding_side = self.padding_side - self.model = AutoModel.from_pretrained(str(resolved), local_files_only=True).to(self.device) + self.model = AutoModel.from_pretrained( + str(resolved), local_files_only=True, + torch_dtype=torch.float16 if self.device.type == "cuda" and os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else torch.float32, + ).to(self.device) self.model.eval() hidden_size = int(getattr(self.model.config, "hidden_size", 0) or 0) if hidden_size != self.dim: @@ -415,6 +422,48 @@ def encode_batch( *, purpose: str = "document", ) -> torch.Tensor: + prefix = self._purpose_prefix(purpose) + if purpose == "document" and self.long_document_policy == "window_mean": + spans = [self.source_spans(clean_text(text)) for text in texts] + if any(len(value) > 1 for value in spans): + # Slow capsules retain their full evidence text. Their one-vector + # representation pools all windows explicitly; source messages + # are independently windowed with exact source coordinates. + windows = [clean_text(text)[start:end] for text, values in zip(texts, spans) for start, end in values] + encoded_windows = self._encode_short_batch(windows, batch_size, purpose=purpose) + output = [] + cursor = 0 + for values in spans: + vec = encoded_windows[cursor:cursor + len(values)].mean(dim=0) + output.append(vec / vec.norm().clamp_min(1e-6)) + cursor += len(values) + return torch.stack(output) + return self._encode_short_batch(texts, batch_size, purpose=purpose) + + def source_spans(self, text, *, prefix="", max_chars=None, overlap_chars=64): + """Cover every original character; tokenize prefix too; never truncate.""" + limit = len(text) if max_chars is None else max(1, int(max_chars)) + if len(self.tokenizer.encode(self.document_prefix + prefix, add_special_tokens=True)) >= self.max_length: + raise ValueError("source metadata exceeds embedding token budget") + if not text: + return [(0, 0)] + spans = [] + start = 0 + while start < len(text): + end = min(len(text), start + limit) + while len(self.tokenizer.encode(self.document_prefix + prefix + text[start:end], add_special_tokens=True)) > self.max_length: + # Token length need not be monotonic at subword boundaries. + # Geometric shrink is conservative and always makes progress. + end = start + max(0, (end - start) * 3 // 4) + if end <= start: + raise ValueError("a source character cannot fit the embedding token budget") + spans.append((start, end)) + if end == len(text): + break + start = max(start + 1, end - min(overlap_chars, (end - start) // 4)) + return spans + + def _encode_short_batch(self, texts, batch_size=4, *, purpose="document"): prefix = self._purpose_prefix(purpose) cleaned = [prefix + clean_text(t) for t in texts] if not cleaned: diff --git a/02-tmcra-memory-api/deploy/Install-TmcraLocal.ps1 b/02-tmcra-memory-api/deploy/Install-TmcraLocal.ps1 new file mode 100644 index 0000000..6067506 --- /dev/null +++ b/02-tmcra-memory-api/deploy/Install-TmcraLocal.ps1 @@ -0,0 +1,68 @@ +[CmdletBinding()] +param( + [ValidateSet('lite-cpu','balanced-bge','quality-qwen')][string]$Profile = 'lite-cpu', + [string]$DataDir = (Join-Path $env:LOCALAPPDATA 'TMCRA\local'), + [ValidateSet('auto','cpu','cuda')][string]$Device = 'auto', + [switch]$PrepareOnly, + [switch]$WaitReady +) +$ErrorActionPreference = 'Stop' +$apiRoot = Split-Path -Parent $PSScriptRoot +$localData = [IO.Path]::GetFullPath($DataDir) +if ([IO.Path]::GetPathRoot($localData) -eq $localData) { throw 'Choose a dedicated TMCRA data folder.' } +foreach ($broadPath in @($env:USERPROFILE,$env:LOCALAPPDATA,$env:APPDATA)) { + if ($broadPath -and $localData.TrimEnd('\') -eq [IO.Path]::GetFullPath($broadPath).TrimEnd('\')) { throw 'Choose a dedicated TMCRA data folder.' } +} +if ($env:TMCRA_CONFIG_FILE) { throw 'An explicit TMCRA_CONFIG_FILE override is active. Clear this advanced override before choosing automatic local installation.' } +. (Join-Path $PSScriptRoot 'Local-SetupHelpers.ps1') +Protect-TmcraLocalPath $localData -Directory +$setupLock = [IO.File]::Open((Join-Path $localData 'setup.lock'),[IO.FileMode]::OpenOrCreate,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None) +try { + # The supervisor holds run.lock for its full lifetime. Do not update an active environment. + $runProbe = [IO.File]::Open((Join-Path $localData 'run.lock'),[IO.FileMode]::OpenOrCreate,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None) + $runProbe.Dispose() + Select-TmcraLocalProfile $localData $Profile + $apiRoot = Copy-TmcraManagedRuntime $apiRoot $localData + Remove-Item Env:TMCRA_DEPLOYMENT_MODE,Env:PYTHONPATH -ErrorAction SilentlyContinue + Enable-TmcraDownloadProxy + $localPython = Get-TmcraLocalPython $localData +$useCuda = $Device -eq 'cuda' +if ($Device -eq 'auto' -and (Get-Command nvidia-smi -ErrorAction SilentlyContinue)) { + & nvidia-smi --query-gpu=name --format=csv,noheader 2>$null | Out-Null + $useCuda = $LASTEXITCODE -eq 0 +} +if ($useCuda) { + & $localPython -m pip install 'torch==2.10.0' --index-url https://download.pytorch.org/whl/cu128 +} else { + & $localPython -m pip install 'torch==2.10.0' --index-url https://download.pytorch.org/whl/cpu +} +if ($LASTEXITCODE -ne 0) { throw 'PyTorch installation failed.' } +& $localPython -m pip install -r (Join-Path $apiRoot 'requirements-tmcra-service.txt') 'transformers==4.57.6' 'huggingface-hub==0.36.2' 'sentencepiece==0.2.1' 'safetensors==0.8.0' +if ($LASTEXITCODE -ne 0) { throw 'Local dependency installation failed.' } +$env:PATH = (Split-Path -Parent $localPython) + [IO.Path]::PathSeparator + $env:PATH +Push-Location $apiRoot +try { + $runtimeDevice = if ($useCuda) { 'cuda' } else { 'cpu' } + & $localPython -m tmcra_service.local_deployment prepare --root $localData --profile $Profile --device $runtimeDevice --auto-ports + if ($LASTEXITCODE -ne 0) { throw 'Local model preparation failed; retained downloads can be resumed.' } + if (-not $PrepareOnly) { + $arguments = '-m tmcra_service.local_deployment run --root "{0}"' -f $localData + $service = Start-Process -FilePath $localPython -ArgumentList $arguments -WorkingDirectory $apiRoot -WindowStyle Hidden -RedirectStandardError (Join-Path $localData 'launcher-error.log') -RedirectStandardOutput (Join-Path $localData 'launcher.log') -PassThru + Write-Output '{"event":"starting","message":"Local services are performing their full startup checks."}' + if ($WaitReady) { + $receipt = Get-Content -Raw -LiteralPath (Join-Path $localData 'installation.json') | ConvertFrom-Json + $deadline = [DateTime]::UtcNow.AddMinutes(15) + do { + $service.Refresh() + if ($service.HasExited) { throw 'Local service exited during startup; inspect launch-error.json. The local selection is retained.' } + try { + $ready = Invoke-RestMethod -Uri "http://127.0.0.1:$($receipt.api_port)/readyz" -TimeoutSec 3 + if ($ready.status -eq 'ready' -or $ready.ready -eq $true) { Write-Output '{"event":"ready","message":"Local memory is ready; no TMCRA account or server is required."}'; return } + } catch { } + Start-Sleep -Seconds 2 + } while ([DateTime]::UtcNow -lt $deadline) + throw 'Startup did not reach ready in 15 minutes; inspect the retained local logs.' + } + } +} finally { Pop-Location } +} finally { $setupLock.Dispose() } diff --git a/02-tmcra-memory-api/deploy/Local-SetupHelpers.ps1 b/02-tmcra-memory-api/deploy/Local-SetupHelpers.ps1 new file mode 100644 index 0000000..3373d4a --- /dev/null +++ b/02-tmcra-memory-api/deploy/Local-SetupHelpers.ps1 @@ -0,0 +1,91 @@ +function Protect-TmcraLocalPath([string]$Path, [switch]$Directory) { + if ($Directory) { New-Item -ItemType Directory -Force -Path $Path | Out-Null } + $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value + $rights = if ($Directory) { '(OI)(CI)F' } else { 'F' } + & icacls.exe $Path /inheritance:r /grant:r "*${sid}:$rights" "*S-1-5-18:$rights" | Out-Null + if ($LASTEXITCODE -ne 0) { throw 'Could not protect the local installation directory.' } +} + +function Select-TmcraLocalProfile([string]$DataRoot, [string]$Profile) { + if ($Profile -notin @('lite-cpu','balanced-bge','quality-qwen')) { throw 'Unknown local model profile.' } + $selectionFile = if ($env:TMCRA_LOCAL_BINDING_FILE) { $env:TMCRA_LOCAL_BINDING_FILE } else { Join-Path $env:USERPROFILE '.config\tmcra\local-memory.json' } + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $selectionFile) | Out-Null + $temporarySelection = "$selectionFile.$([guid]::NewGuid().ToString('N')).tmp" + $selection = @{schemaVersion=1;mode='local';dataRoot=[IO.Path]::GetFullPath($DataRoot);profile=$Profile} + [IO.File]::WriteAllText($temporarySelection, ($selection | ConvertTo-Json), [Text.UTF8Encoding]::new($false)) + Protect-TmcraLocalPath $temporarySelection + if (Test-Path -LiteralPath $selectionFile) { + # Windows PowerShell 5 converts a null backup argument to an invalid empty path. + # Retain a private, non-secret selection backup and replace the marker atomically. + $previousSelection = "$temporarySelection.previous" + [IO.File]::Replace($temporarySelection,$selectionFile,$previousSelection) + Protect-TmcraLocalPath $previousSelection + } + else { [IO.File]::Move($temporarySelection,$selectionFile) } + Protect-TmcraLocalPath $selectionFile +} + +function Copy-TmcraManagedRuntime([string]$Source, [string]$DataRoot) { + $manifestPath = Join-Path $Source 'runtime-files.json' + if (-not (Test-Path -LiteralPath $manifestPath)) { throw 'Runtime inventory is missing; use the complete local installation package.' } + $manifest = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json + $identity = (Get-FileHash -Algorithm SHA256 -LiteralPath $manifestPath).Hash.ToLowerInvariant().Substring(0,24) + $destination = Join-Path $DataRoot "service\$identity" + $sourcePrefix = [IO.Path]::GetFullPath($Source).TrimEnd('\') + '\' + $destinationPrefix = [IO.Path]::GetFullPath($destination).TrimEnd('\') + '\' + foreach ($entry in $manifest.PSObject.Properties) { + $inputPath = [IO.Path]::GetFullPath((Join-Path $Source $entry.Name)) + $outputPath = [IO.Path]::GetFullPath((Join-Path $destination $entry.Name)) + if (-not $inputPath.StartsWith($sourcePrefix,[StringComparison]::OrdinalIgnoreCase) -or + -not $outputPath.StartsWith($destinationPrefix,[StringComparison]::OrdinalIgnoreCase)) { throw 'Unsafe runtime inventory path.' } + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $inputPath).Hash.ToLowerInvariant() -ne $entry.Value) { throw "Runtime integrity check failed: $($entry.Name)" } + if (Test-Path -LiteralPath $outputPath) { + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $outputPath).Hash.ToLowerInvariant() -ne $entry.Value) { throw 'Existing managed runtime was modified; inspect it before upgrading.' } + } else { + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $outputPath) | Out-Null + Copy-Item -LiteralPath $inputPath -Destination $outputPath + } + } + Copy-Item -LiteralPath $manifestPath -Destination (Join-Path $destination 'runtime-files.json') + return $destination +} + +function Enable-TmcraDownloadProxy { + # Respect a user's Windows proxy for installation only. Runtime strips proxies. + if ($env:HTTPS_PROXY) { return } + $settings = Get-ItemProperty -LiteralPath 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -ErrorAction SilentlyContinue + if ($settings.ProxyEnable -eq 1 -and $settings.ProxyServer -match '^(?:http://)?(127\.0\.0\.1:\d{1,5})$') { + $env:HTTPS_PROXY = "http://$($Matches[1])" + $env:HTTP_PROXY = $env:HTTPS_PROXY + $env:NO_PROXY = '127.0.0.1,localhost,::1' + } +} + +function Get-TmcraLocalPython([string]$DataRoot) { + $localPython = Join-Path $DataRoot 'venv\Scripts\python.exe' + if (Test-Path -LiteralPath $localPython) { + & $localPython -c 'import sys; assert (3,11) <= sys.version_info[:2] < (3,13) and sys.maxsize > 2**32' + if ($LASTEXITCODE -ne 0) { throw 'The existing local Python is incompatible; retain its data and inspect the environment.' } + return $localPython + } + $uvRoot = Join-Path $DataRoot 'runtime\uv-0.12.10' + New-Item -ItemType Directory -Force -Path $uvRoot | Out-Null + $archive = Join-Path $uvRoot 'uv.zip' + $expected = 'f65744f94072152b1f86ba2aace4d01f1124d9a8ecb235805039e3718c36cac2' + if (-not (Test-Path -LiteralPath $archive) -or (Get-FileHash -Algorithm SHA256 -LiteralPath $archive).Hash.ToLowerInvariant() -ne $expected) { + Write-Output '{"event":"installing_python","message":"Downloading the pinned Python environment manager."}' | Write-Host + $partial = "$archive.partial" + $download = @{UseBasicParsing=$true;Uri='https://github.com/astral-sh/uv/releases/download/0.12.10/uv-x86_64-pc-windows-msvc.zip';OutFile=$partial} + if ($env:HTTPS_PROXY) { $download.Proxy = $env:HTTPS_PROXY } + Invoke-WebRequest @download + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $partial).Hash.ToLowerInvariant() -ne $expected) { throw 'Python bootstrap checksum mismatch.' } + Move-Item -LiteralPath $partial -Destination $archive -Force + } + Expand-Archive -LiteralPath $archive -DestinationPath $uvRoot -Force + $uv = Join-Path $uvRoot 'uv.exe' + $env:UV_PYTHON_INSTALL_DIR = Join-Path $DataRoot 'runtime\python' + $env:UV_CACHE_DIR = Join-Path $DataRoot 'cache\uv' + & $uv venv --python 3.12 --managed-python --seed (Join-Path $DataRoot 'venv') | Out-Host + if ($LASTEXITCODE -ne 0) { throw 'Automatic Python installation failed; downloaded files are retained for retry.' } + return $localPython +} diff --git a/02-tmcra-memory-api/deploy/Start-TmcraLocal.ps1 b/02-tmcra-memory-api/deploy/Start-TmcraLocal.ps1 new file mode 100644 index 0000000..e7b00e5 --- /dev/null +++ b/02-tmcra-memory-api/deploy/Start-TmcraLocal.ps1 @@ -0,0 +1,11 @@ +[CmdletBinding()] +param([string]$DataDir = (Join-Path $env:LOCALAPPDATA 'TMCRA\local')) +$ErrorActionPreference = 'Stop' +$apiRoot = Split-Path -Parent $PSScriptRoot +$localData = [IO.Path]::GetFullPath($DataDir) +$localPython = Join-Path $localData 'venv\Scripts\python.exe' +if (-not (Test-Path -LiteralPath $localPython)) { throw 'Run Install-TmcraLocal.ps1 first.' } +$receipt = Get-Content -Raw -LiteralPath (Join-Path $localData 'installation.json') | ConvertFrom-Json +if ($receipt.api_root) { $apiRoot = $receipt.api_root } +$arguments = '-m tmcra_service.local_deployment run --root "{0}"' -f $localData +Start-Process -FilePath $localPython -ArgumentList $arguments -WorkingDirectory $apiRoot -WindowStyle Hidden -RedirectStandardError (Join-Path $localData 'launcher-error.log') -RedirectStandardOutput (Join-Path $localData 'launcher.log') diff --git a/02-tmcra-memory-api/deploy/local-bootstrap/sitecustomize.py b/02-tmcra-memory-api/deploy/local-bootstrap/sitecustomize.py new file mode 100644 index 0000000..76a9071 --- /dev/null +++ b/02-tmcra-memory-api/deploy/local-bootstrap/sitecustomize.py @@ -0,0 +1,12 @@ +"""Loaded by every Python worker in the explicit full-local launch environment.""" +import os + +if os.environ.get("TMCRA_DEPLOYMENT_MODE") == "local": + try: + from tmcra_local_only import install_network_guard, validate_environment + validate_environment(os.environ) + install_network_guard() + except Exception: + # CPython normally ignores sitecustomize exceptions. Fail closed instead. + os.write(2, b"TMCRA local network boundary failed; refusing to start.\n") + os._exit(78) diff --git a/02-tmcra-memory-api/deploy/local-model-profiles.json b/02-tmcra-memory-api/deploy/local-model-profiles.json new file mode 100644 index 0000000..460605c --- /dev/null +++ b/02-tmcra-memory-api/deploy/local-model-profiles.json @@ -0,0 +1,132 @@ +{ + "schema_version": "tmcra.local-model-profiles.1", + "verified_upstream_on": "2026-09-06", + "status": "windows_local_preview_partial_validation", + "installation_enabled": true, + "scope": "full_local_runtime_preview", + "full_memory_system_ready": false, + "hardware_requirements_are": "conservative_planning_estimates_not_benchmark_results", + "profiles": [ + { + "id": "lite-cpu", + "name_zh": "轻量版", + "recommendation_zh": "普通笔记本、无独显电脑;中英文短记忆,低并发", + "validation": "cpu_ingest_and_raw_recall_passed_complex_compile_timed_out", + "system_ram_gib_min": 8, + "system_ram_gib_recommended_for_full_memory": 16, + "retrieval_vram_gib_recommended": 0, + "weights_bytes": 941234298, + "embedding": { + "repo_id": "intfloat/multilingual-e5-small", + "revision": "614241f622f53c4eeff9890bdc4f31cfecc418b3", + "license": "MIT", + "upstream": "https://huggingface.co/intfloat/multilingual-e5-small", + "weights": [{"file": "model.safetensors", "bytes": 470641600, "sha256": "1a55775f53449dac10a2bcbc312469fac40b96d53198c407081a831f81c98477"}], + "dimensions": 384, + "model_max_tokens": 512, + "pooling": "mean", + "normalize": true, + "query_prefix": "query: ", + "document_prefix": "passage: ", + "padding_side": "right" + }, + "reranker": { + "repo_id": "cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "revision": "1427fd652930e4ba29e8149678df786c240d8825", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "weights": [{"file": "model.safetensors", "bytes": 470592698, "sha256": "5daeca2481a76b5976a2bdc32f0a78532b6716da4f8cd3ff59460ef8d2f359b4"}], + "adapter": "sequence-classification", + "model_max_tokens": 512, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["memory_pressure_retest", "complex_compile_latency", "organizer_validation", "full_service_restart_validation"] + }, + { + "id": "balanced-bge", + "name_zh": "均衡版", + "recommendation_zh": "优先复现现有生产检索模型;16GB 以上内存,建议有独显", + "validation": "production_model_stack_verified_consumer_installer_pending", + "system_ram_gib_min": 16, + "system_ram_gib_recommended_for_full_memory": 32, + "retrieval_vram_gib_recommended": 6, + "weights_bytes": 4542217682, + "embedding": { + "repo_id": "BAAI/bge-m3", + "revision": "5617a9f61b028005a4858fdac845db406aefb181", + "license": "MIT", + "upstream": "https://huggingface.co/BAAI/bge-m3", + "weights": [{"file": "pytorch_model.bin", "bytes": 2271145830, "sha256": "b5e0ce3470abf5ef3831aa1bd5553b486803e83251590ab7ff35a117cf6aad38"}], + "dimensions": 1024, + "model_max_tokens": 8192, + "pooling": "cls", + "normalize": true, + "query_prefix": "", + "document_prefix": "", + "padding_side": "right" + }, + "reranker": { + "repo_id": "BAAI/bge-reranker-v2-m3", + "revision": "953dc6f6f85a1b2dbfca4c34a2796e7dde08d41e", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/BAAI/bge-reranker-v2-m3", + "weights": [{"file": "model.safetensors", "bytes": 2271071852, "sha256": "d9e3e081faff1eefb84019509b2f5558fd74c1a05a2c7db22f74174fcedb5286"}], + "adapter": "sequence-classification", + "model_max_tokens": 8192, + "production_runtime_max_tokens": 1280, + "tmcra_fusion_checkpoint_compatible": true + }, + "required_work": ["single_recall_lane", "desktop_worker_and_context_budgets", "desktop_installer", "offline_end_to_end_validation"] + }, + { + "id": "quality-qwen", + "name_zh": "增强版候选", + "recommendation_zh": "32GB 以上内存、高显存电脑;长文本和跨语言检索候选,需与均衡版实测比较", + "validation": "upstream_artifacts_verified_runtime_pending", + "system_ram_gib_min": 32, + "system_ram_gib_recommended_for_full_memory": 64, + "retrieval_vram_gib_recommended": 16, + "weights_bytes": 9235180368, + "embedding": { + "repo_id": "Qwen/Qwen3-Embedding-4B", + "revision": "5cf2132abc99cad020ac570b19d031efec650f2b", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Embedding-4B", + "weights": [ + {"file": "model-00001-of-00002.safetensors", "bytes": 4965826464, "sha256": "e70bfe3c970523fb7ef4eddffed2254ce3f1e7150c3de2af4342de129dd756f8"}, + {"file": "model-00002-of-00002.safetensors", "bytes": 3077765624, "sha256": "ed1b87c8e9eb7e535a1a155e4fd00d9f4dba80e58a6db48a4c9f82cede7079c1"} + ], + "dimensions": 2560, + "model_max_tokens": 32768, + "pooling": "last_token", + "normalize": true, + "query_prefix": "Instruct: Given a query about previous conversations, retrieve the relevant source passages.\nQuery: ", + "document_prefix": "", + "padding_side": "left" + }, + "reranker": { + "repo_id": "Qwen/Qwen3-Reranker-0.6B", + "revision": "e61197ed45024b0ed8a2d74b80b4d909f1255473", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Reranker-0.6B", + "weights": [{"file": "model.safetensors", "bytes": 1191588280, "sha256": "27cd75a405b9c1b46b59abfd88aaa209e6fed2a1972cde9b70e7659537c5e65b"}], + "adapter": "causal-lm-yes-no", + "model_max_tokens": 32768, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["qwen_yes_no_reranker_adapter", "service_variable_embedding_dimensions", "bounded_gpu_batches", "full_index_rebuild", "quality_and_latency_comparison"] + } + ], + "deployment_contract": { + "automatic_profile_switch_on_existing_index": false, + "cloud_fallback_in_full_local_mode": false, + "cloud_account_required_in_full_local_mode": false, + "generation_model_included_in_weights_bytes": false, + "model_cache_and_python_runtime_included_in_weights_bytes": false, + "required_index_identity": ["repo_id", "revision", "dimensions", "pooling", "query_prefix", "document_prefix", "normalization", "precision", "chunking_policy"], + "existing_sources_must_be_preserved": true, + "existing_indexes_must_be_rebuilt_before_activation": true, + "runtime_downloads_after_setup": false, + "readiness_requires_actual_inference": true + } +} diff --git a/02-tmcra-memory-api/ops/test_local_pipeline.py b/02-tmcra-memory-api/ops/test_local_pipeline.py new file mode 100644 index 0000000..0966760 --- /dev/null +++ b/02-tmcra-memory-api/ops/test_local_pipeline.py @@ -0,0 +1,96 @@ +"""Opt-in live synthetic acceptance test. Never reads user/provider credentials to stdout.""" +import argparse +import json +import time +import urllib.error +import urllib.request +from datetime import datetime, timezone +from pathlib import Path + +parser = argparse.ArgumentParser() +parser.add_argument("--root", type=Path, required=True) +parser.add_argument("--recall-only", action="store_true") +parser.add_argument("--organize", action="store_true") +parser.add_argument("--compiled", action="store_true") +args = parser.parse_args() +receipt = json.loads((args.root / "installation.json").read_text(encoding="utf-8")) +state = args.root / "state" / receipt["profile"] +credentials = json.loads((state / "secrets/client.json").read_text(encoding="utf-8")) +base = f"http://127.0.0.1:{receipt['api_port']}" +headers = {"Authorization": "Bearer " + credentials["api_key"], "Content-Type": "application/json"} +scope = "synthetic-local-acceptance" +report_path = state / "synthetic-acceptance.json" +results = json.loads(report_path.read_text(encoding="utf-8")) if report_path.exists() else {} + + +def request(path, payload=None, key=None): + request_headers = dict(headers) + if key: + request_headers["Idempotency-Key"] = key + req = urllib.request.Request(base + path, data=json.dumps(payload).encode() if payload is not None else None, + headers=request_headers, method="POST" if payload is not None else "GET") + try: + with urllib.request.urlopen(req, timeout=900) as response: + return json.load(response) + except urllib.error.HTTPError as exc: + detail = exc.read().decode(errors="replace") + raise RuntimeError(f"API {exc.code}: {detail[:2000]}") from None + + +def wait_job(job, timeout=1500): + job_id = job["job_id"] + deadline = time.monotonic() + timeout + last = None + while time.monotonic() < deadline: + status = request("/v1/jobs/" + job_id) + phase = status.get("status") or status.get("state") + if phase != last: + print(json.dumps({"job_id": job_id, "status": phase}), flush=True) + last = phase + if phase == "succeeded": + return status + if phase in {"failed", "cancelled"}: + raise RuntimeError(json.dumps(status, ensure_ascii=False)[:4000]) + time.sleep(2) + raise TimeoutError("synthetic memory job still incomplete; inspect the retained job") + + +results["health"] = request("/healthz") +results["ready"] = request("/readyz") +if not args.recall_only: + started = time.monotonic() + job = request(f"/v1/scopes/{scope}/ingest", { + "session_id": "local-synthetic-20260906", "consistency": "read_your_writes", "slow_policy": "deferred", + "messages": [{"message_id": "synthetic-01", "role": "user", "timestamp": "2026-09-06T01:00:00Z", + "content": "这是一条合成测试记忆。我把测试项目命名为蓝鲸,演示安排在周五下午三点。我喜欢用 Markdown 保存项目说明。"}], + }, "local-synthetic-acceptance-v1") + results["ingest"] = wait_job(job) + results["ingest_seconds"] = round(time.monotonic() - started, 3) + report_path.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8") +started = time.monotonic() +results["recall"] = request(f"/v1/scopes/{scope}/recall", { + "query": "蓝鲸测试项目的演示安排在什么时候?", "evidence_mode": "raw", "recall_profile": "interactive"}) +results["recall_seconds"] = round(time.monotonic() - started, 3) +report_path.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8") +rendered = json.dumps(results["recall"], ensure_ascii=False) +if "周五" not in rendered or "三点" not in rendered: + raise AssertionError("recall omitted the synthetic source fact") +if args.compiled: + started = time.monotonic() + results["compiled"] = request(f"/v1/scopes/{scope}/recall", { + "query": "蓝鲸测试项目的演示安排在什么时候?", "evidence_mode": "compiled", "recall_profile": "quality"}) + results["compiled_seconds"] = round(time.monotonic() - started, 3) + report_path.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8") + print(json.dumps({"test": "compiled_evidence", "seconds": results["compiled_seconds"]}), flush=True) +if args.organize: + started = time.monotonic() + job = request(f"/v1/scopes/{scope}/consolidate", {}, "local-synthetic-organize-v1") + results["consolidation"] = wait_job(job) + results["consolidation_seconds"] = round(time.monotonic() - started, 3) + results["knowledge"] = request(f"/v1/scopes/{scope}/knowledge-base") + results["graph"] = request(f"/v1/scopes/{scope}/memory-graph/visual-atlas") + report_path.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8") + print(json.dumps({"test": "consolidation", "seconds": results["consolidation_seconds"]}), flush=True) +print(json.dumps({"test": "synthetic_ingest_recall", "passed": True, + "ingest_seconds": results.get("ingest_seconds"), "recall_seconds": results["recall_seconds"], + "report": str(report_path)}, ensure_ascii=False), flush=True) diff --git a/02-tmcra-memory-api/run_tmcra_v4_build.py b/02-tmcra-memory-api/run_tmcra_v4_build.py index 5e16fe8..a74c35b 100644 --- a/02-tmcra-memory-api/run_tmcra_v4_build.py +++ b/02-tmcra-memory-api/run_tmcra_v4_build.py @@ -47,6 +47,9 @@ def _stage(root: Path, name: str, **values: Any) -> None: def _load_shell_environment(path: Path) -> dict[str, str]: + from tmcra_local_only import enabled, read_environment + if enabled(): + return read_environment(path) if not path.is_file(): raise BuildError(f"writer environment file is missing: {path}") command = 'set -a; source "$1"; env -0' @@ -82,6 +85,10 @@ def _rotated(keys: Sequence[str], worker_index: int) -> str: def _worker_environment(base: Mapping[str, str], keys: Sequence[str], worker_index: int) -> dict[str, str]: environment = dict(base) + from tmcra_local_only import enabled, validate_environment + if enabled(environment): + validate_environment(environment) + return environment pool = _rotated(keys, worker_index) base_url = environment.get("TMCRA_DEEPSEEK_WRITER_BASE_URL") or environment.get("TMCRA_WRITER_BASE_URL") or "https://api.deepseek.com/v1" max_tokens = environment.get("TMCRA_WRITER_MAX_TOKENS", "16384") diff --git a/02-tmcra-memory-api/tmcra_local_models.py b/02-tmcra-memory-api/tmcra_local_models.py new file mode 100644 index 0000000..9a655b9 --- /dev/null +++ b/02-tmcra-memory-api/tmcra_local_models.py @@ -0,0 +1,101 @@ +"""Pinned retrieval profiles shared by the API and its real index workers.""" +from __future__ import annotations + +import hashlib +import json +import os +from pathlib import Path + +PROFILE_FILE = Path(__file__).resolve().parent / "deploy" / "local-model-profiles.json" + + +def profiles(): + return json.loads(PROFILE_FILE.read_text(encoding="utf-8"))["profiles"] + + +def profile_by_id(identity): + for profile in profiles(): + if profile["id"] == identity: + return profile + raise ValueError("unknown local model profile") + + +def signature(profile): + # A model change, pooling change or window-policy change requires reindexing. + contract = {"embedding": profile["embedding"], "source_windows": "token-char-covered-v1", + "long_slow_embedding": "normalized-window-mean-v1"} + return hashlib.sha256(json.dumps(contract, sort_keys=True, separators=(",", ":")).encode()).hexdigest() + + +def apply_local_profile(args): + if os.getenv("TMCRA_DEPLOYMENT_MODE") != "local": + return args + profile = profile_by_id(os.environ["TMCRA_LOCAL_PROFILE"]) + embed = profile["embedding"] + rerank = profile["reranker"] + args.embedding_profile_id = profile["id"] + args.embedding_index_signature = signature(profile) + args.embedding_model = os.environ["TMCRA_EMBEDDING_MODEL"] + args.cross_model = os.environ["TMCRA_CROSS_MODEL"] + args.text_dim = embed["dimensions"] + args.embedding_max_length = embed["model_max_tokens"] + args.embedding_pooling = embed["pooling"] + args.embedding_query_prefix = embed["query_prefix"] + args.embedding_document_prefix = embed["document_prefix"] + args.embedding_padding_side = embed["padding_side"] + args.embedding_strict_max_length = True + args.embedding_long_document_policy = "window_mean" + args.reranker_mode = "fusion" if rerank["tmcra_fusion_checkpoint_compatible"] else "semantic-only" + args.reranker_adapter = rerank["adapter"] + args.cross_max_length = min(rerank["model_max_tokens"], 1280) + args.cross_batch_size = 2 if args.device == "cpu" else 8 + args.batch_size = 4 if args.device == "cpu" else 8 + return args + + +def verify_index_identity(payload, args): + expected = getattr(args, "embedding_index_signature", "") + if expected and (payload.get("embedding_index_signature") != expected + or payload.get("text_dim") != args.text_dim): + raise RuntimeError("index embedding identity differs; rebuild into a new generation before recall") + + +def sha256_file(path): + digest = hashlib.sha256() + with Path(path).open("rb") as handle: + for block in iter(lambda: handle.read(8 * 1024 * 1024), b""): + digest.update(block) + return digest.hexdigest() + + +def verify_weights(model, directory): + directory = Path(directory) + for asset in model["weights"]: + path = directory / asset["file"] + if (not path.is_file() or path.stat().st_size != asset["bytes"] + or sha256_file(path) != asset["sha256"]): + raise RuntimeError(f"model asset is missing or failed SHA-256 verification: {asset['file']}") + + +QWEN_SYSTEM = ("<|im_start|>system\nJudge whether the Document meets the requirements based on the Query " + "and the Instruct provided. Note that the answer can only be \"yes\" or \"no\"." + "<|im_end|>\n<|im_start|>user\n") +QWEN_SUFFIX = "<|im_end|>\n<|im_start|>assistant\n\n\n\n\n" + + +def qwen_rerank_windows(tokenizer, query, document, *, max_length): + prefix = QWEN_SYSTEM + (": Given a query about previous conversations, retrieve the relevant " + f"source passages.\n: {query}\n: ") + head = tokenizer.encode(prefix, add_special_tokens=False) + tail = tokenizer.encode(QWEN_SUFFIX, add_special_tokens=False) + body = tokenizer.encode(document, add_special_tokens=False) + capacity = max_length - len(head) - len(tail) + if capacity < 32: + raise ValueError("reranker query leaves insufficient document context; shorten the query") + step = max(1, capacity - min(192, capacity // 4)) + windows = [] + for start in range(0, max(1, len(body)), step): + windows.append(head + body[start:start + capacity] + tail) + if start + capacity >= len(body): + break + return windows diff --git a/02-tmcra-memory-api/tmcra_local_only.py b/02-tmcra-memory-api/tmcra_local_only.py new file mode 100644 index 0000000..e5dd8f5 --- /dev/null +++ b/02-tmcra-memory-api/tmcra_local_only.py @@ -0,0 +1,193 @@ +"""Explicit full-local runtime boundary, also used by Python worker processes. + +Installation/downloads run outside this boundary. This is a process-level guard, +not an OS firewall or a sandbox for untrusted plugins/native code. +""" +from __future__ import annotations + +import ipaddress +import json +import os +import sys +import time +from contextlib import contextmanager +from pathlib import Path +from urllib.parse import urlsplit + +_guard_installed = False +ROLES = ("WRITER", "WRITER_REVIEWER", "RECALL_PLANNER", "SLOW_GRAPH", + "SUBJECT_ATTRIBUTION", "EVIDENCE_COMPILER", "SESSION_GRAPH") + + +def enabled(environment=None): + return (os.environ if environment is None else environment).get("TMCRA_DEPLOYMENT_MODE") == "local" + + +def loopback_url(value, *, port=None, path=None): + parsed = urlsplit(value) + try: + address = ipaddress.ip_address(parsed.hostname or "") + valid_port = parsed.port + except ValueError as exc: + raise ValueError("local URLs require a numeric loopback address and valid port") from exc + if (parsed.scheme != "http" or not address.is_loopback or not valid_port + or parsed.username is not None or parsed.password is not None + or parsed.query or parsed.fragment + or (port is not None and valid_port != int(port)) + or (path is not None and parsed.path.rstrip("/") != path)): + raise ValueError("full-local URLs must use the configured loopback HTTP endpoint") + return parsed + + +def validate_environment(environment): + if not enabled(environment): + raise ValueError("full-local deployment mode is required") + generation = loopback_url(environment["TMCRA_LOCAL_WRITER_BASE_URL"], path="/v1") + public = loopback_url(environment["TMCRA_SERVICE_PUBLIC_BASE_URL"], + port=environment["TMCRA_SERVICE_BIND_PORT"], path="") + if public.hostname != environment.get("TMCRA_SERVICE_BIND_HOST"): + raise ValueError("local service URL and bind host differ") + for role in ROLES: + loopback_url(environment[f"TMCRA_{role}_BASE_URL"], port=generation.port, path="/v1") + if environment[f"TMCRA_{role}_BASE_URL"] != environment["TMCRA_LOCAL_WRITER_BASE_URL"]: + raise ValueError(f"local model route differs: {role}") + if not environment.get(f"TMCRA_{role}_MODEL"): + raise ValueError(f"local model identity is missing: {role}") + for name, value in environment.items(): + if name.lower() in {"http_proxy", "https_proxy", "all_proxy"} and value: + raise ValueError("proxies must be cleared in full-local mode") + if name.startswith("TMCRA_") and name.endswith(("_BASE_URL", "_ENDPOINT", "_URL")) and value: + loopback_url(value) + return environment + + +def configure_routes(environment, *, base_url, model, key): + """Return a private child environment; never mutate host/cloud credentials.""" + loopback_url(base_url, path="/v1") + if not model or not key or any(c in key for c in ",\r\n"): + raise ValueError("one local model alias and API key are required") + clean = {} + for name, value in environment.items(): + upper = name.upper() + if (upper.startswith(("TMCRA_", "OPENAI_", "ANTHROPIC_", "DEEPSEEK_", "ARK_", "DASHSCOPE_")) + or upper in {"HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"}): + continue + clean[name] = value + # Keep service settings explicitly selected by the local installer only. + clean.update({name: value for name, value in environment.items() + if name.startswith(("TMCRA_SERVICE_", "TMCRA_LOCAL_", "TMCRA_EMBEDDING_"))}) + clean.update({"TMCRA_DEPLOYMENT_MODE": "local", "HF_HUB_OFFLINE": "1", + "TRANSFORMERS_OFFLINE": "1", "HF_HUB_DISABLE_TELEMETRY": "1", + "HF_HUB_DISABLE_IMPLICIT_TOKEN": "1", "NO_PROXY": "*", + "TMCRA_LOCAL_WRITER_BASE_URL": base_url, "TMCRA_LOCAL_WRITER_MODEL": model}) + for role in ROLES: + clean.update({f"TMCRA_{role}_BASE_URL": base_url, f"TMCRA_{role}_MODEL": model, + f"TMCRA_{role}_API_KEY_POOL": key, f"TMCRA_{role}_KEY_POOL": key, + f"TMCRA_{role}_PROVIDER": "local-qwen"}) + clean.update({"TMCRA_WRITER_PROMPT_ADAPTER": "qwen36-v5", + "TMCRA_WRITER_REVIEWER_PROMPT_ADAPTER": "qwen36-reconciliation-v1", + "TMCRA_RECALL_PLANNER_PROMPT_ADAPTER": "qwen36-planner-v1", + "TMCRA_SLOW_GRAPH_PROMPT_ADAPTER": "qwen36-slow-graph-v1", + "TMCRA_WRITER_MAX_TOKENS": "16384", + "TMCRA_SLOW_GRAPH_MAX_TOKENS": "16384", + "TMCRA_RECALL_PLANNER_MAX_TOKENS": "512", + "TMCRA_RECALL_PLANNER_TIMEOUT_SECONDS": "600"}) + # Older core modules read these aliases. They contain ONLY the local endpoint + # and its generated key, with zero cloud prices and no inherited cloud pool. + for role in ("DEEPSEEK_WRITER", "DEEPSEEK_FLASH", "DEEPSEEK_PRO"): + clean.update({f"TMCRA_{role}_BASE_URL": base_url, f"TMCRA_{role}_MODEL": model, + f"TMCRA_{role}_KEY_POOL": key, f"TMCRA_{role}_MAX_TOKENS": "16384"}) + for cost in ("PROMPT", "COMPLETION", "CACHE"): + clean[f"TMCRA_{role}_{cost}_COST_PER_MILLION"] = "0" + return clean + + +def read_environment(path): + data = json.loads(Path(path).read_text(encoding="utf-8")) + if not isinstance(data, dict) or data.get("schema_version") != "tmcra.local-environment.1": + raise ValueError("invalid local environment schema") + values = data.get("environment") + if not isinstance(values, dict) or any(not isinstance(k, str) or not isinstance(v, str) for k, v in values.items()): + raise ValueError("local environment must be a string mapping") + # No shell expansion or executable configuration. + result = dict(os.environ) + operation_names = {"TMCRA_SERVICE_TENANT_ID", "TMCRA_SERVICE_SCOPE_NAME", "TMCRA_SERVICE_JOB_ID", + "TMCRA_SERVICE_STAGE_ID", "TMCRA_SERVICE_STAGE_ATTEMPT", "TMCRA_USAGE_ATTRIBUTION_JSON"} + operation = {name: result[name] for name in operation_names if name in result} + for name in list(result): + if name.upper().startswith(("TMCRA_", "OPENAI_", "ANTHROPIC_", "DEEPSEEK_", "ARK_", "DASHSCOPE_")) or name.upper() in {"HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"}: + result.pop(name) + result.update(values) + result.update(operation) + validate_environment(result) + return result + + +def install_network_guard(): + global _guard_installed + if _guard_installed: + return + + def check_host(host): + if host in (None, ""): + return + if isinstance(host, bytes): + host = host.decode("ascii", errors="strict") + try: + address = ipaddress.ip_address(host) + except ValueError: + raise PermissionError("TMCRA full-local mode blocks DNS and non-numeric network hosts") from None + if not address.is_loopback: + raise PermissionError("TMCRA full-local mode blocks external network connections") + + def audit(event, args): + if event == "socket.getaddrinfo": + check_host(args[0]) + elif event in {"socket.gethostbyname", "socket.gethostbyaddr"}: + check_host(args[0]) + elif event in {"socket.connect", "socket.bind"}: + address = args[1] + if isinstance(address, tuple): + check_host(address[0]) + elif event == "socket.sendto": + address = args[-1] + if isinstance(address, tuple): + check_host(address[0]) + + sys.addaudithook(audit) + _guard_installed = True + + +@contextmanager +def process_lock(path, *, timeout=60): + """Cooperating process lock on Windows and POSIX; state survives crashes.""" + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("a+b") as handle: + if handle.tell() == 0: + handle.write(b"\0") + handle.flush() + if os.name == "nt": + import msvcrt + deadline = time.monotonic() + timeout + while True: + handle.seek(0) + try: + msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1) + break + except OSError: + if time.monotonic() >= deadline: + raise TimeoutError("another local process holds the state lock") from None + time.sleep(0.1) + try: + yield + finally: + handle.seek(0) + msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1) + else: + import fcntl + fcntl.flock(handle, fcntl.LOCK_EX) + try: + yield + finally: + fcntl.flock(handle, fcntl.LOCK_UN) diff --git a/02-tmcra-memory-api/tmcra_service/__init__.py b/02-tmcra-memory-api/tmcra_service/__init__.py index fd2f3c3..7fb6f27 100644 --- a/02-tmcra-memory-api/tmcra_service/__init__.py +++ b/02-tmcra-memory-api/tmcra_service/__init__.py @@ -2,4 +2,4 @@ __all__ = ["__version__"] -__version__ = "0.3.0rc2" +__version__ = "1.0.0rc1" diff --git a/02-tmcra-memory-api/tmcra_service/__main__.py b/02-tmcra-memory-api/tmcra_service/__main__.py index 2bb034d..6237bca 100644 --- a/02-tmcra-memory-api/tmcra_service/__main__.py +++ b/02-tmcra-memory-api/tmcra_service/__main__.py @@ -31,6 +31,12 @@ def _load_shell_environment(path: str | Path) -> None: + from tmcra_local_only import enabled, read_environment + if enabled(): + environment = read_environment(path) + os.environ.clear() + os.environ.update(environment) + return env_path = Path(path).expanduser() if not env_path.is_file(): raise RuntimeError(f"writer env file is missing or not a file: {env_path}") @@ -92,6 +98,10 @@ def _local_writer_key(path_value: str) -> str: def _configure_writer_aliases() -> None: + from tmcra_local_only import enabled, validate_environment + if enabled(): + validate_environment(os.environ) + return deepseek_base_url = str( os.getenv("TMCRA_DEEPSEEK_WRITER_BASE_URL") or "" ).strip() @@ -321,7 +331,12 @@ def _validate_startup(settings: ServiceSettings) -> None: ) parsed_url = urlparse(settings.public_base_url) - if parsed_url.scheme.lower() != "https" or not parsed_url.netloc: + from tmcra_local_only import enabled, loopback_url + if enabled(): + if not bind_address.is_loopback: + raise RuntimeError("full-local service must bind loopback") + loopback_url(settings.public_base_url, port=settings.bind_port, path="") + elif parsed_url.scheme.lower() != "https" or not parsed_url.netloc: raise RuntimeError( "service startup validation failed: TMCRA_SERVICE_PUBLIC_BASE_URL " "must be an HTTPS URL served by a trusted TLS reverse proxy" @@ -366,6 +381,9 @@ def main() -> int: writer_env = os.getenv("TMCRA_WRITER_ENV", DEFAULT_WRITER_ENV) _load_shell_environment(writer_env) _configure_writer_aliases() + from tmcra_local_only import enabled, install_network_guard + if enabled(): + install_network_guard() settings = ServiceSettings.from_env() _validate_startup(settings) app = create_app(settings) diff --git a/02-tmcra-memory-api/tmcra_service/adapters/v4.py b/02-tmcra-memory-api/tmcra_service/adapters/v4.py index 47355a3..d5b426e 100644 --- a/02-tmcra-memory-api/tmcra_service/adapters/v4.py +++ b/02-tmcra-memory-api/tmcra_service/adapters/v4.py @@ -54,6 +54,10 @@ ) +class LocalEvidenceCompilationUnavailable(RuntimeError): + """A local model failed to finish a validated evidence plan.""" + + class V4AdapterError(RuntimeError): pass @@ -2266,11 +2270,17 @@ def _run_with_writer_env( if not key or "=" in key: raise V4AdapterError("writer extra environment keys must be valid names") environment[key] = str(value) + from tmcra_local_only import enabled, validate_environment + if enabled(environment): + validate_environment(environment) + invocation = list(command) + else: + invocation = ["bash", "-c", shell, "tmcra-service", str(self.settings.writer_env), *command] with log_path.open("x", encoding="utf-8") as log: log.write(json.dumps({"command": [str(item) for item in command]}) + "\n") log.flush() subprocess.run( - ["bash", "-c", shell, "tmcra-service", str(self.settings.writer_env), *command], + invocation, check=True, stdout=log, stderr=subprocess.STDOUT, @@ -8447,6 +8457,13 @@ def compile_evidence( str(self.settings.writer_env), "--workers", "1", + *([ + "--planner-provider", "openai-compatible", + "--planner-model", os.environ["TMCRA_EVIDENCE_COMPILER_MODEL"], + "--planner-base-url", os.environ["TMCRA_EVIDENCE_COMPILER_BASE_URL"], + "--planner-key-file", os.environ["TMCRA_LOCAL_WRITER_API_KEY_FILE"], + "--timeout", "600", + ] if os.environ.get("TMCRA_DEPLOYMENT_MODE") == "local" else []), ], log_path=operation / "compiler.log", ) @@ -8488,6 +8505,11 @@ def compile_evidence( usage_attribution=usage_attribution, ) if compile_error is not None: + if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local": + raise LocalEvidenceCompilationUnavailable( + "Local evidence compilation did not complete. Inspect the private compiler log; " + "the original memory and raw evidence remain available." + ) from compile_error raise compile_error compiled_path = output / "evidence_windows.jsonl" if not compiled_path.is_file(): @@ -8621,6 +8643,8 @@ def __init__( subchunk_overlap=200, batch_size=16, ) + from tmcra_local_models import apply_local_profile + apply_local_profile(self.args) self.v3.graph_runtime_env(self.args) self.harness = self.v3.load_native_harness( settings.native_harness, settings.integrated_repo @@ -8767,10 +8791,10 @@ def _load_base_index_cached( if cached is not None: self._index_cache.move_to_end(key) return cached - return self._remember_index_bundle( - key, - self.runtime.load_online_index(index_path, database_path, scope_id), - ) + bundle = self.runtime.load_online_index(index_path, database_path, scope_id) + from tmcra_local_models import verify_index_identity + verify_index_identity(bundle[-1], self.args) + return self._remember_index_bundle(key, bundle) def _load_delta_index_cached( self, @@ -8875,8 +8899,8 @@ def warmup(self, snapshots: Sequence[Mapping[str, Any]]) -> dict[str, Any]: representations, logits = self.models.encode_cross( "TMCRA startup preflight", ["resident model readiness probe"] ) - if tuple(dense.shape) != (1024,) or not bool(torch.isfinite(dense).all()): - raise RuntimeError("BGE-M3 startup probe returned an invalid vector") + if tuple(dense.shape) != (self.args.text_dim,) or not bool(torch.isfinite(dense).all()): + raise RuntimeError("embedding startup probe returned an invalid vector") if representations.shape[0] != 1 or logits.shape[0] != 1: raise RuntimeError("cross encoder startup probe returned invalid shapes") if not bool(torch.isfinite(representations).all()) or not bool( diff --git a/02-tmcra-memory-api/tmcra_service/api_models.py b/02-tmcra-memory-api/tmcra_service/api_models.py index 63e82cf..1839312 100644 --- a/02-tmcra-memory-api/tmcra_service/api_models.py +++ b/02-tmcra-memory-api/tmcra_service/api_models.py @@ -949,6 +949,18 @@ class FeedbackRequest(StrictModel): memory_ids: list[str] = Field(default_factory=list, max_length=100) comment: str | None = Field(default=None, max_length=4000) metadata: dict[str, Any] = Field(default_factory=dict) + action: Literal["note", "ignore", "correct", "restore"] = "note" + replacement: str | None = Field(default=None, min_length=1, max_length=4000) + + @model_validator(mode="after") + def targeted_action(self) -> "FeedbackRequest": + if self.action != "note" and (not self.memory_ids or any(not item.strip() for item in self.memory_ids)): + raise ValueError("memory_ids are required for an effective feedback action") + if self.action == "correct" and not self.replacement: + raise ValueError("replacement is required for correct") + if self.action != "correct" and self.replacement is not None: + raise ValueError("replacement is supported only by correct") + return self class FeedbackView(StrictModel): @@ -956,6 +968,10 @@ class FeedbackView(StrictModel): scope_name: str rating: str created_at: float + action: str = "note" + effective: bool = False + correction_job_id: str | None = None + correction_index_status: str | None = None WebhookEvent = Literal[ @@ -1009,6 +1025,7 @@ class PromptEvidenceView(StrictModel): source_block_count: int | None = None neighbor_block_count: int | None = None memory_context_block_count: int | None = None + sources: list[dict[str, Any]] = Field(default_factory=list) class RecallResponse(StrictModel): diff --git a/02-tmcra-memory-api/tmcra_service/app.py b/02-tmcra-memory-api/tmcra_service/app.py index e77e084..cc8f1c9 100644 --- a/02-tmcra-memory-api/tmcra_service/app.py +++ b/02-tmcra-memory-api/tmcra_service/app.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import logging import hashlib import os import re @@ -25,6 +26,7 @@ from .adapters.v4 import ( ContentDeletionTargetNotFound, V4AdapterError, + LocalEvidenceCompilationUnavailable, V4StorageAdapter, ) from .api_models import ( @@ -154,6 +156,7 @@ RecallPoolTimeoutError, ) from .routing import select_evidence_route +from .feedback_effects import apply_feedback from .runtime import LazyOnlineEngine, ServiceWorker from .session_graph import ( SessionGraphAgentRouter, @@ -1091,6 +1094,13 @@ async def recall_pool_saturated_error( headers={"Retry-After": retry_after_header}, ) + @app.exception_handler(LocalEvidenceCompilationUnavailable) + async def local_evidence_compilation_unavailable(request: Request, exc: LocalEvidenceCompilationUnavailable) -> JSONResponse: + return JSONResponse(status_code=503, content={"error": { + "code": "local_evidence_compilation_failed", "message": str(exc), + "request_id": getattr(request.state, "request_id", None), + }}) + @app.exception_handler(RecallPoolTimeoutError) async def recall_pool_timeout_error( request: Request, exc: RecallPoolTimeoutError @@ -1181,7 +1191,7 @@ async def commercial_contract_error( ) -> JSONResponse: if exc.code == "scope_deleted": status_code = 410 - elif exc.code in {"scope_deleting", "scope_content_deleting"}: + elif exc.code in {"scope_deleting", "scope_content_deleting", "feedback_idempotency_conflict"}: status_code = 409 elif exc.code == "webhook_signing_not_configured": status_code = 503 @@ -1603,6 +1613,11 @@ def requested_provider_execution( route = str(value or "").strip() if not route: return None + if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local": + raise HTTPException(status_code=422, detail={ + "code": "local_provider_handoff_disabled", + "message": "Full-local memory executes all model stages inside the local runtime", + }) if route != "user-provider": raise HTTPException( status_code=422, @@ -2817,7 +2832,8 @@ def admit_online_recall() -> None: {"query_id": query_id, "physical_api_calls": planner_call_count}, worker_id=planner_worker_id, ) - route = select_evidence_route(body.evidence_mode, evidence) + evidence = apply_feedback(evidence, components.commercial.feedback_effects(context.tenant_id, scope_name)) + route = select_evidence_route(body.evidence_mode if evidence.get("evidence_windows") else "raw", evidence) compiled = None if route.selected == "compiled": compiler_stage_id = f"{query_id}:compiler" @@ -3462,20 +3478,54 @@ def get_retention_policy( def submit_feedback( scope_name: str, body: FeedbackRequest, + request: Request, + idempotency_key: str | None = Header(default=None, alias="Idempotency-Key", min_length=8, max_length=200), context: AuthContext = Depends(require_permission("memory:feedback")), ) -> dict[str, Any]: scope_name = _scope_name(scope_name) require_active_scope(context.tenant_id, scope_name) - return components.commercial.add_feedback( + if body.action == "correct" and not context.allows("memory:write"): + raise AuthorizationError("memory:write is required to save a correction") + if body.action != "note": + if not idempotency_key: + raise HTTPException(status_code=422, detail="Idempotency-Key is required for effective feedback") + body.memory_ids = components.commercial.resolve_feedback_targets(context.tenant_id, scope_name, body.memory_ids) + if not body.memory_ids or len(body.memory_ids) > 100: + raise HTTPException(status_code=422, detail="Feedback targets must resolve to 1..100 memory IDs") + projection = MemoryGraphProjection.from_available_storage(components.storage, tenant_id=context.tenant_id, scope_name=scope_name) + for memory_id in body.memory_ids: + projection.neighbors(memory_id, limit=1) + result = components.commercial.add_feedback( context.tenant_id, scope_name, query_id=body.query_id, rating=body.rating, memory_ids=body.memory_ids, comment=body.comment, - metadata=body.metadata, + metadata={**body.metadata, "_tmcra_action": body.action, "_tmcra_replacement": body.replacement}, credential_id=context.credential_id, + operation_key=idempotency_key, ) + result.update(action=body.action, effective=body.action != "note") + if body.action == "correct": + feedback_id = result["feedback_id"] + correction = IngestRequest.model_validate({ + "session_id": f"correction-{feedback_id}", + "messages": [{"message_id": feedback_id, "role": "user", "content": body.replacement, + "timestamp": result["created_at"]}], + "metadata": {"integration": "memory-correction", "supersedes_memory_ids": body.memory_ids}, + }) + try: + job = ingest(scope_name, correction, request, idempotency_key=f"correction-{feedback_id}", + writer_execution=request.headers.get("X-TMCRA-Writer-Execution"), + organizer_execution=request.headers.get("X-TMCRA-Organizer-Execution"), context=context, _={}) + result.update(correction_job_id=job["job_id"], correction_index_status=job["status"]) + except Exception as exc: + # The targeted recall correction is durable already. Expose the + # pending index state; retrying this same key retries only indexing. + result["correction_index_status"] = "submission_pending" + logging.getLogger(__name__).warning("correction indexing pending: %s", type(exc).__name__) + return result @app.get( "/v1/scopes/{scope_name}/memory-graph", @@ -4056,6 +4106,8 @@ def claim_user_provider_task( ), ) -> dict[str, Any]: require_user_provider_stage_permission(context, body.stage) + if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local": + return {"task": None, "retry_after_seconds": 60.0} claimed = components.user_provider_tasks.claim_next( tenant_id=context.tenant_id, auth_key_id=context.key_id, diff --git a/02-tmcra-memory-api/tmcra_service/commercial.py b/02-tmcra-memory-api/tmcra_service/commercial.py index 7d12afd..4efa24a 100644 --- a/02-tmcra-memory-api/tmcra_service/commercial.py +++ b/02-tmcra-memory-api/tmcra_service/commercial.py @@ -2181,11 +2181,22 @@ def add_feedback( comment: str | None, metadata: Mapping[str, Any], credential_id: str, + operation_key: str | None = None, ) -> dict[str, Any]: - feedback_id = f"fb_{uuid.uuid4().hex}" + feedback_id = "fb_" + (hashlib.sha256(f"{tenant_id}\0{scope_name}\0{credential_id}\0{operation_key}".encode()).hexdigest() + if operation_key else uuid.uuid4().hex) created_at = time.time() memory_id_values = list(dict.fromkeys(str(item) for item in memory_ids)) with self.database.transaction() as connection: + previous = connection.execute("SELECT * FROM memory_feedback WHERE feedback_id=?", (feedback_id,)).fetchone() + if previous is not None: + same = (previous["rating"] == rating and previous["comment"] == comment + and json.loads(previous["memory_ids_json"]) == memory_id_values + and json.loads(previous["metadata_json"]) == dict(metadata)) + if not same: + raise CommercialContractError("feedback_idempotency_conflict", "feedback key was reused for different content") + return {"feedback_id": feedback_id, "scope_name": scope_name, "rating": rating, + "created_at": float(previous["created_at"])} connection.execute( """ INSERT INTO memory_feedback( @@ -2213,6 +2224,46 @@ def add_feedback( "created_at": created_at, } + def resolve_feedback_targets(self, tenant_id: str, scope_name: str, memory_ids: Iterable[str]) -> list[str]: + targets: list[str] = [] + with self.database.transaction() as connection: + for memory_id in memory_ids: + row = connection.execute("SELECT memory_ids_json FROM memory_feedback WHERE tenant_id=? AND scope_name=? AND feedback_id=?", + (tenant_id, scope_name, memory_id)).fetchone() + targets.extend(json.loads(row["memory_ids_json"]) if row else [memory_id]) + return list(dict.fromkeys(targets)) + + def feedback_effects(self, tenant_id: str, scope_name: str) -> dict[str, Any]: + with self.database.transaction() as connection: + rows = connection.execute( + "SELECT * FROM memory_feedback WHERE tenant_id=? AND scope_name=? ORDER BY created_at, rowid", + (tenant_id, scope_name), + ).fetchall() + effects: dict[str, Any] = {} + correction_targets: dict[str, list[str]] = {} + for row in rows: + metadata = json.loads(row["metadata_json"]) + action = metadata.get("_tmcra_action") + if action not in {"ignore", "correct", "restore"}: + continue + targets = json.loads(row["memory_ids_json"]) + if action == "correct": + correction_targets[row["feedback_id"]] = targets + for memory_id in targets: + if action == "restore": + effects.pop(memory_id, None) + else: + effects[memory_id] = {"action": action, "feedback_id": row["feedback_id"], + "replacement": metadata.get("_tmcra_replacement", ""), + "created_at": float(row["created_at"])} + for feedback_id, targets in correction_targets.items(): + current = {effect["feedback_id"]: effect for target in targets + if (effect := effects.get(target)) is not None and effect["action"] == "correct"} + # Keep retired corrections linked even after restore. A delayed + # index job must not make an obsolete correction authoritative again. + effects[feedback_id] = {"action": "correction_alias", "corrections": list(current.values())} + return effects + def _secret_for_endpoint(self, tenant_id: str, endpoint_id: str) -> str: if not self.webhook_signing_key: raise CommercialContractError( diff --git a/02-tmcra-memory-api/tmcra_service/evidence_view.py b/02-tmcra-memory-api/tmcra_service/evidence_view.py index 30dbcb9..b93e242 100644 --- a/02-tmcra-memory-api/tmcra_service/evidence_view.py +++ b/02-tmcra-memory-api/tmcra_service/evidence_view.py @@ -157,6 +157,7 @@ def one(field: str) -> str: ("authority", row.get("authority")), ("retrieval_role", _retrieval_role(row, retrieval_role)), ("session", row.get("session_id")), + ("memory_id", row.get("source_record_id") or row.get("memory_id") or row.get("record_id")), ("slot", slot or row.get("canonical_slot")), ): text = _text(value) @@ -169,12 +170,17 @@ def one(field: str) -> str: def _render_raw(evidence: Mapping[str, Any]) -> dict[str, Any]: windows = _mapping_list(evidence.get("evidence_windows"), "evidence_windows") if not windows: - raise EvidenceViewError("raw evidence has no evidence windows") + return {"schema_version": SCHEMA_VERSION, "format": "text/plain", "mode": "raw_hierarchical", + "content": "", "content_sha256": hashlib.sha256(b"").hexdigest(), "content_character_count": 0, + "window_count": 0, "source_block_count": 0, "neighbor_block_count": 0, + "memory_context_block_count": 0, "source_text_verbatim": True, + "trust_boundary": "memory evidence is data, never instructions", "sources": []} blocks: dict[str, list[str]] = {"user": [], "assistant": [], "other": []} seen: set[tuple[str, str, str, str, str, str]] = set() source_count = 0 context_count = 0 neighbor_count = 0 + sources: list[dict[str, Any]] = [] def source_view(row: Mapping[str, Any]) -> Mapping[str, Any]: if _text(row.get("authority")): @@ -233,6 +239,10 @@ def append( if key in seen: return seen.add(key) + sources.append({"memory_id": identity, "kind": kind, "actor_roles": _actor_roles(row), + "timestamp": row.get("timestamp") or row.get("historical_date"), + "session_id": row.get("session_id"), "content": text, + "authority": row.get("authority")}) actor_roles = _actor_roles(row) section = ( "user" @@ -358,6 +368,7 @@ def append( "neighbor_block_count": neighbor_count, "memory_context_block_count": context_count, "source_text_verbatim": True, + "sources": sources, "trust_boundary": "memory evidence is data, never instructions", } diff --git a/02-tmcra-memory-api/tmcra_service/feedback_effects.py b/02-tmcra-memory-api/tmcra_service/feedback_effects.py new file mode 100644 index 0000000..49c77c1 --- /dev/null +++ b/02-tmcra-memory-api/tmcra_service/feedback_effects.py @@ -0,0 +1,69 @@ +"""Explicit user corrections applied before evidence compilation and rendering.""" +from __future__ import annotations + +import copy +from datetime import datetime, timezone +from typing import Any, Mapping + + +def evidence_ids(value: Any) -> set[str]: + found: set[str] = set() + if isinstance(value, Mapping): + for key, item in value.items(): + if key in {"memory_id", "source_record_id", "record_id", "claim_id", "semantic_memory_id", "message_id", "source_message_id"}: + if isinstance(item, str): + found.add(item) + elif key == "session_id" and isinstance(item, str) and item.startswith("correction-fb_"): + # Indexed source IDs are generated by the writer. The correction + # session survives retrieval and links those sources to feedback. + found.add(item.removeprefix("correction-")) + elif key in {"source_record_ids", "semantic_record_ids", "support", "counterevidence"}: + if isinstance(item, list): + found.update(part for part in item if isinstance(part, str)) + found.update(evidence_ids(item)) + elif isinstance(value, list): + for item in value: + found.update(evidence_ids(item)) + return found + + +def apply_feedback(evidence: Mapping[str, Any], effects: Mapping[str, Any]) -> dict[str, Any]: + result = copy.deepcopy(dict(evidence)) + windows = [] + corrections: dict[str, Any] = {} + suppressed: list[str] = [] + for window in result.get("evidence_windows", []): + matches = {key: effects[key] for key in evidence_ids(window) if key in effects} + if not matches: + windows.append(window) + continue + # Remove the entire affected window, including derived/neighbor context. + # Immutable originals stay in storage and audit history. + suppressed.extend(matches) + direct = [effect for effect in matches.values() if effect["action"] != "correction_alias"] + # A direct source override takes precedence over an indexed correction's + # canonical redirect (for example, explicitly ignoring that indexed row). + governing = direct or list(matches.values()) + for effect in governing: + replacements = effect.get("corrections", [effect]) + for replacement in replacements: + if replacement["action"] == "correct": + corrections[replacement["feedback_id"]] = replacement + for feedback_id, effect in corrections.items(): + windows.append({ + "source_record_id": feedback_id, + "text": effect["replacement"], + "actor_role": "user", + "authority": "explicit_user_correction", + "timestamp": datetime.fromtimestamp(effect["created_at"], timezone.utc).isoformat(), + "session_id": f"correction-{feedback_id}", + "memory_contexts": [], "attachments": [], "source_group_context": [], + }) + result["evidence_windows"] = windows + if suppressed: + # The compiler must receive only the filtered evidence, with no stale + # flattened packet or cached answer-facing content from the retriever. + result = {"evidence_windows": windows, "recall_plan": result.get("recall_plan", {}), + "feedback_applied": {"suppressed_ids": sorted(set(suppressed)), + "correction_ids": list(corrections)}} + return result diff --git a/02-tmcra-memory-api/tmcra_service/local_deployment.py b/02-tmcra-memory-api/tmcra_service/local_deployment.py new file mode 100644 index 0000000..24b5ceb --- /dev/null +++ b/02-tmcra-memory-api/tmcra_service/local_deployment.py @@ -0,0 +1,390 @@ +"""Local model installer and supervisor; uses the production memory API unchanged. + +Downloads require the network only during `prepare`. `run` installs the full-local +Python boundary before starting the API and verifies all pinned model weights. +""" +from __future__ import annotations + +import argparse +import csv +import io +import json +import os +import platform +import secrets +import shutil +import socket +import subprocess +import sys +import time +import urllib.request +import zipfile +from pathlib import Path + +from tmcra_local_models import profile_by_id, profiles, sha256_file, signature, verify_weights +from tmcra_local_only import configure_routes, process_lock, read_environment, validate_environment + +API_ROOT = Path(__file__).resolve().parents[1] +GENERATION = { + "repo_id": "Qwen/Qwen3-4B-GGUF", "revision": "bc640142c66e1fdd12af0bd68f40445458f3869b", + "license": "Apache-2.0", "model": "tmcra-qwen3-4b-q4km", + "weights": [{"file": "Qwen3-4B-Q4_K_M.gguf", "bytes": 2497280256, + "sha256": "7485fe6f11af29433bc51cab58009521f205840f5b4ae3a32fa7f92e8534fdf5"}], +} +LLAMA = { + "version": "b10276", "archive": "llama-b10276-bin-win-cpu-x64.zip", + "sha256": "b1db7fc5b3d2728dcead5b792b0565da045dec688df81c9272ce5aef5f55a3e8", + "url": "https://github.com/ggml-org/llama.cpp/releases/download/b10276/llama-b10276-bin-win-cpu-x64.zip", +} + + +def emit(event, **values): + print(json.dumps({"event": event, **values}, ensure_ascii=False), flush=True) + + +def atomic_json(path, data): + path = Path(path) + temporary = path.with_name(path.name + ".tmp-" + secrets.token_hex(4)) + with temporary.open("x", encoding="utf-8") as handle: + json.dump(data, handle, ensure_ascii=False, indent=2) + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary, path) + + +def private_directory(path): + path.mkdir(parents=True, exist_ok=True) + if os.name == "nt": + result = subprocess.run(["whoami", "/user", "/fo", "csv", "/nh"], check=True, + capture_output=True, text=True) + sid = list(csv.reader(io.StringIO(result.stdout)))[0][-1] + if not sid.startswith("S-1-"): + raise RuntimeError("cannot determine current Windows user SID") + subprocess.run(["icacls", str(path), "/inheritance:r", "/grant:r", + f"*{sid}:(OI)(CI)F", "*S-1-5-18:(OI)(CI)F"], + check=True, capture_output=True) + else: + path.chmod(0o700) + + +def hardware(): + import psutil + import torch + ram = psutil.virtual_memory() + gpu = torch.cuda.is_available() + vram = torch.cuda.get_device_properties(0).total_memory / 1024**3 if gpu else 0 + recommended = "lite-cpu" + if ram.total / 1024**3 >= 30 and vram >= 6: + recommended = "balanced-bge" + if ram.total / 1024**3 >= 60 and vram >= 16: + recommended = "quality-qwen" + return {"ram_gib": round(ram.total / 1024**3, 1), "available_ram_gib": round(ram.available / 1024**3, 1), + "cuda_available": gpu, "vram_gib": round(vram, 1), "recommended_profile": recommended, + "recommendation_basis": "capacity_estimate_not_quality_benchmark"} + + +def download_model(model, directory): + directory.mkdir(parents=True, exist_ok=True) + try: + verify_weights(model, directory) + if model is GENERATION or (directory / "config.json").is_file(): + emit("model_cached", repo=model["repo_id"]) + return + except RuntimeError: + pass + hf = shutil.which("hf") + if not hf: + raise RuntimeError("Hugging Face CLI missing; run the local setup script first") + includes = [item["file"] for item in model["weights"]] + if model is not GENERATION: + includes += ["*.json", "*.model", "vocab.txt", "merges.txt", "README.md", "LICENSE*"] + emit("downloading", repo=model["repo_id"], revision=model["revision"]) + subprocess.run([hf, "download", model["repo_id"], "--revision", model["revision"], + "--local-dir", str(directory), "--include", *includes], check=True) + verify_weights(model, directory) + + +def install_llama(root): + if platform.system() != "Windows" or platform.machine().lower() not in {"amd64", "x86_64"}: + raise RuntimeError("this portable launcher currently supports Windows x64; other platforms remain unvalidated") + directory = root / "runtime" / LLAMA["version"] + directory.mkdir(parents=True, exist_ok=True) + archive = directory / LLAMA["archive"] + if not archive.is_file() or sha256_file(archive) != LLAMA["sha256"]: + emit("downloading_runtime", version=LLAMA["version"]) + partial = archive.with_suffix(".partial") + with urllib.request.urlopen(LLAMA["url"], timeout=60) as response, partial.open("wb") as output: + shutil.copyfileobj(response, output) + if sha256_file(partial) != LLAMA["sha256"]: + raise RuntimeError("llama.cpp archive failed SHA-256 verification") + os.replace(partial, archive) + with zipfile.ZipFile(archive) as zipped: + for item in zipped.infolist(): + target = (directory / item.filename).resolve() + if not target.is_relative_to(directory.resolve()) or (item.external_attr >> 16) & 0o170000 == 0o120000: + raise RuntimeError("unsafe path in llama.cpp archive") + zipped.extractall(directory) + servers = list(directory.rglob("llama-server.exe")) + if len(servers) != 1: + raise RuntimeError("llama.cpp archive must contain exactly one server") + return servers[0] + + +def initialize_identity(state): + from .auth import APIKeyAuth + from .cli import DEFAULT_SCOPES + from .control_db import ControlDB + private_directory(state) + secrets_dir = state / "secrets" + private_directory(secrets_dir) + auth = APIKeyAuth(ControlDB(state / "control.sqlite3")) + credentials = secrets_dir / "client.json" + if credentials.exists(): + saved = json.loads(credentials.read_text(encoding="utf-8")) + auth.authenticate(saved["api_key"]) + else: + tenant = "local-" + secrets.token_hex(12) + auth.set_tenant_scopes(tenant, frozenset(DEFAULT_SCOPES)) + issued = auth.create_key(tenant) + saved = {"schema_version": "tmcra.local-client.1", "tenant_id": tenant, + "api_key": issued.api_key, "key_id": issued.key_id, "scope": "personal"} + atomic_json(credentials, saved) + key_file = secrets_dir / "generation.key" + if not key_file.exists(): + with key_file.open("x", encoding="utf-8") as handle: + handle.write(secrets.token_urlsafe(48)) + return key_file + + +def prepare(root, profile_id, *, device="auto", api_port=2009, model_port=2010, auto_ports=False): + if api_port == model_port or not all(1024 <= port <= 65535 for port in (api_port, model_port)): + raise ValueError("choose two different non-privileged local ports") + root = root.resolve() + private_directory(root) + with process_lock(root / "run.lock", timeout=0), process_lock(root / "install.lock", timeout=0): + if auto_ports: + # Hold both reservations while selecting distinct ports; run() checks again. + with socket.socket() as first, socket.socket() as second: + previous = root / "installation.json" + ports = json.loads(previous.read_text(encoding="utf-8")) if previous.is_file() else {} + for probe, name in ((first, "api_port"), (second, "model_port")): + preferred = ports.get(name, 0) + if not isinstance(preferred, int) or not 1024 <= preferred <= 65535: + preferred = 0 + try: + probe.bind(("127.0.0.1", preferred)) + except OSError: + probe.bind(("127.0.0.1", 0)) + api_port, model_port = first.getsockname()[1], second.getsockname()[1] + profile = profile_by_id(profile_id) + resources = hardware() + minimum = profile["system_ram_gib_min"] + if resources["ram_gib"] < minimum * 0.95: + raise RuntimeError(f"profile requires at least {minimum} GiB physical RAM") + free = shutil.disk_usage(root).free + required = profile["weights_bytes"] + GENERATION["weights"][0]["bytes"] + 5 * 1024**3 + if free < required: + raise RuntimeError("insufficient disk space for models, verification and memory state") + device = ("cuda" if resources["cuda_available"] else "cpu") if device == "auto" else device + if device == "cuda" and not resources["cuda_available"]: + raise RuntimeError("CUDA requested but this Python runtime has no usable CUDA device") + model_root = root / "models" / profile_id + for role in ("embedding", "reranker"): + download_model(profile[role], model_root / role) + atomic_json(model_root / role / "TMCRA_MODEL_MANIFEST.json", profile[role]) + download_model(GENERATION, root / "models" / "generation") + server = install_llama(root) + state = root / "state" / profile_id + key_file = initialize_identity(state) + client = json.loads((state / "secrets/client.json").read_text(encoding="utf-8")) + atomic_json(state / "secrets/client-plugin.json", { + "schemaVersion": 2, "authMode": "api-key", "baseUrl": f"http://127.0.0.1:{api_port}", + "apiKey": client["api_key"], "tokenType": "Bearer", "scopeNamespace": "local", + "globalScope": "local-global", "projectScopePrefix": "local-project", "timeoutMs": 180000, + "defaultScope": "personal", + "deploymentMode": "local", "integrationIds": {}, + }) + config = state / "local-environment.json" + settings = { + "TMCRA_SERVICE_STATE_DIR": str(state), "TMCRA_SERVICE_CONTROL_DB": str(state / "control.sqlite3"), + "TMCRA_SERVICE_BIND_HOST": "127.0.0.1", "TMCRA_SERVICE_BIND_PORT": str(api_port), + "TMCRA_SERVICE_PUBLIC_BASE_URL": f"http://127.0.0.1:{api_port}", + "TMCRA_SERVICE_DEVICE": device, "TMCRA_SERVICE_GRAPH_DEVICE": device, + "TMCRA_SERVICE_WORKER_CONCURRENCY": "1", "TMCRA_SERVICE_REQUEST_MAX_CONCURRENCY": "4", + "TMCRA_SERVICE_RECALL_POOL_MIN_SIZE": "1", "TMCRA_SERVICE_RECALL_POOL_MAX_SIZE": "1", + "TMCRA_SERVICE_WRITER_EXECUTION_MODE": "resident", "TMCRA_SERVICE_WRITER_POOL_SIZE": "1", + "TMCRA_SERVICE_LOCAL_WRITER_RECOVERY_CONCURRENCY": "1", + "TMCRA_SERVICE_WRITER_POOL_REQUEST_TIMEOUT_SECONDS": "1800", + "TMCRA_SERVICE_STARTUP_PREFLIGHT_MODE": "full", "TMCRA_SERVICE_RECALL_QUEUE_TIMEOUT_SECONDS": "600", + "TMCRA_LOCAL_PROFILE": profile_id, "TMCRA_LOCAL_WRITER_API_KEY_FILE": str(key_file), + "TMCRA_EMBEDDING_MODEL": str(model_root / "embedding"), + } + environment = configure_routes(settings, base_url=f"http://127.0.0.1:{model_port}/v1", + model=GENERATION["model"], key=key_file.read_text().strip()) + environment.update({"TMCRA_V4_ROOT": str(API_ROOT), "TMCRA_INTEGRATED_REPO": str(API_ROOT), + "TMCRA_WRITER_ENV": str(config), "TMCRA_CROSS_MODEL": str(model_root / "reranker"), + "TMCRA_CHECKPOINT": str(API_ROOT / "models" / "tmcra_v3_reranker.pt"), + "TMCRA_LEARNED_GRAPH_ENABLED": "0", "PYTHONUTF8": "1", + "TMCRA_LOCAL_LLM_PARALLEL": "1", "TMCRA_PROJECTION_RESERVED_PRODUCTION_SLOTS": "0", + "TMCRA_SESSION_GRAPH_AGENT_TIMEOUT_SECONDS": "600", + "OMP_NUM_THREADS": "4", "MKL_NUM_THREADS": "4", + "PYTHONPATH": os.pathsep.join([str(API_ROOT / "deploy" / "local-bootstrap"), str(API_ROOT)])}) + validate_environment(environment) + atomic_json(config, {"schema_version": "tmcra.local-environment.1", "environment": environment}) + # Receipt is public metadata only; credentials live under private state. + receipt = {"schema_version": "tmcra.local-installation.1", "profile": profile_id, + "api_root": str(API_ROOT), + "embedding_signature": signature(profile), "environment_file": str(config), + "llama_server": str(server), "llama_sha256": sha256_file(server), + "model_port": model_port, "api_port": api_port, "hardware": resources, + "generation": GENERATION, "runtime": LLAMA, + "status": "installed_runtime_validation_required", "external_network_at_runtime": "python_loopback_only"} + atomic_json(root / "installation.json", receipt) + emit("installed", profile=profile_id, root=str(root), full_pipeline_verified=False) + return receipt + + +def port_free(port): + with socket.socket() as probe: + try: + probe.bind(("127.0.0.1", port)) + except OSError as exc: + raise RuntimeError(f"local port {port} is occupied; existing services were left running") from exc + + +def run(root): + import psutil + root = root.resolve() + with process_lock(root / "run.lock", timeout=0): + receipt = json.loads((root / "installation.json").read_text(encoding="utf-8")) + profile = profile_by_id(receipt["profile"]) + if receipt["embedding_signature"] != signature(profile): + raise RuntimeError("installed embedding contract changed; prepare a new profile/state first") + for role in ("embedding", "reranker"): + verify_weights(profile[role], root / "models" / profile["id"] / role) + verify_weights(GENERATION, root / "models" / "generation") + if sha256_file(receipt["llama_server"]) != receipt["llama_sha256"]: + raise RuntimeError("local generation executable changed") + env = read_environment(receipt["environment_file"]) + for port in (receipt["api_port"], receipt["model_port"]): + port_free(port) + available = psutil.virtual_memory().available + # Reserve OS/application headroom as well as model + KV + Python memory. + required_available = max(6 * 1024**3, int(profile["weights_bytes"] * 1.4 + 5 * 1024**3)) + if available < required_available: + raise RuntimeError(f"insufficient available memory: {available / 1024**3:.1f} GiB available; " + f"{required_available / 1024**3:.1f} GiB required before starting; close other workloads and retry") + state = Path(env["TMCRA_SERVICE_STATE_DIR"]) + logs = state / "logs" + logs.mkdir(exist_ok=True) + children = [] + handles = [] + run_id = secrets.token_hex(16) + try: + commands = [ + [receipt["llama_server"], "--model", str(root / "models" / "generation" / GENERATION["weights"][0]["file"]), + "--alias", GENERATION["model"], "--host", "127.0.0.1", "--port", str(receipt["model_port"]), + "--api-key-file", env["TMCRA_LOCAL_WRITER_API_KEY_FILE"], "--ctx-size", "32768", + "--parallel", "1", "--threads", str(min(8, os.cpu_count() or 4)), + "--batch-size", "128", "--ubatch-size", "64", "--cache-ram", "0", + "--n-gpu-layers", "0", "--cache-type-k", "q8_0", "--cache-type-v", "q8_0", + "--flash-attn", "on", "--jinja", "--reasoning-budget", "0"], + [sys.executable, "-m", "tmcra_service"], + ] + for index, command in enumerate(commands): + handle = (logs / ("generation.log" if index == 0 else "api.log")).open("ab") + handles.append(handle) + child = subprocess.Popen(command, cwd=API_ROOT, env=env, stdin=subprocess.DEVNULL, + stdout=handle, stderr=subprocess.STDOUT, + creationflags=subprocess.CREATE_NO_WINDOW if os.name == "nt" else 0) + children.append(child) + if index == 0: + deadline = time.monotonic() + 180 + while True: + if child.poll() is not None: + raise RuntimeError("generation service exited; inspect its local log") + try: + request = urllib.request.Request(f"http://127.0.0.1:{receipt['model_port']}/health") + with urllib.request.urlopen(request, timeout=2) as response: + if response.status == 200: + break + except (OSError, TimeoutError): + pass + if time.monotonic() >= deadline: + raise RuntimeError("generation service did not become healthy within 180 seconds") + time.sleep(0.5) + atomic_json(root / "running.json", {"run_id": run_id, "supervisor_pid": os.getpid(), + "supervisor_created": psutil.Process().create_time(), "api_port": receipt["api_port"], + "profile": profile["id"], "pids": [child.pid for child in children]}) + emit("started", api_url=f"http://127.0.0.1:{receipt['api_port']}", run_id=run_id) + while all(child.poll() is None for child in children): + stop = root / "stop-request.json" + if stop.exists() and json.loads(stop.read_text(encoding="utf-8"))["run_id"] == run_id: + break + time.sleep(0.5) + else: + raise RuntimeError("a local service exited; inspect private logs") + finally: + for child in reversed(children): + if child.poll() is None: + descendants = psutil.Process(child.pid).children(recursive=True) + child.terminate() + try: + child.wait(timeout=15) + except subprocess.TimeoutExpired: + child.kill() + child.wait(timeout=10) + for descendant in reversed(descendants): + try: + descendant.terminate() + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + _, survivors = psutil.wait_procs(descendants, timeout=5) + for descendant in survivors: + try: + descendant.kill() + except (psutil.NoSuchProcess, psutil.AccessDenied): + pass + for handle in handles: + handle.close() + atomic_json(root / "running.json", {"run_id": run_id, "stopped": True}) + + +def main(argv=None): + parser = argparse.ArgumentParser(description="TMCRA full-local Windows deployment") + parser.add_argument("command", choices=["recommend", "prepare", "run", "stop", "status"]) + parser.add_argument("--root", type=Path, default=Path(os.getenv("LOCALAPPDATA", str(Path.home()))) / "TMCRA" / "local") + parser.add_argument("--profile", choices=[p["id"] for p in profiles()], default="lite-cpu") + parser.add_argument("--device", choices=["auto", "cpu", "cuda"], default="auto") + parser.add_argument("--api-port", type=int, default=2009) + parser.add_argument("--model-port", type=int, default=2010) + parser.add_argument("--auto-ports", action="store_true") + args = parser.parse_args(argv) + if args.command == "recommend": + emit("recommendation", **hardware(), profiles=profiles()) + elif args.command == "prepare": + prepare(args.root, args.profile, device=args.device, api_port=args.api_port, model_port=args.model_port, auto_ports=args.auto_ports) + elif args.command == "run": + try: + run(args.root) + except Exception as exc: + atomic_json(args.root / "launch-error.json", {"error_type": type(exc).__name__, + "detail": str(exc), "at": time.time()}) + raise + else: + running = args.root / "running.json" + data = json.loads(running.read_text(encoding="utf-8")) if running.exists() else {"stopped": True} + if args.command == "stop" and not data.get("stopped"): + import psutil + process = psutil.Process(data["supervisor_pid"]) + if abs(process.create_time() - data["supervisor_created"]) > 0.01: + raise RuntimeError("stored supervisor PID was reused; refusing to stop") + atomic_json(args.root / "stop-request.json", {"run_id": data["run_id"]}) + emit("stop_requested") + else: + emit("status", **data) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/02-tmcra-memory-api/tmcra_service/qwen36_planner_adapter.py b/02-tmcra-memory-api/tmcra_service/qwen36_planner_adapter.py index 0b3846e..f5484cf 100644 --- a/02-tmcra-memory-api/tmcra_service/qwen36_planner_adapter.py +++ b/02-tmcra-memory-api/tmcra_service/qwen36_planner_adapter.py @@ -2,6 +2,7 @@ import hashlib import json +import os import time import urllib.error import urllib.request @@ -170,7 +171,7 @@ def plan( "thinking": {"type": "disabled"}, "enable_thinking": False, } - body["id_slot"] = LOCAL_QWEN_PLANNER_SLOT_ID + body["id_slot"] = 0 if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else LOCAL_QWEN_PLANNER_SLOT_ID encoded_body = json.dumps(body, ensure_ascii=False).encode("utf-8") request_sha256 = _sha256( json.dumps(body, ensure_ascii=False, sort_keys=True) diff --git a/02-tmcra-memory-api/tmcra_service/runtime.py b/02-tmcra-memory-api/tmcra_service/runtime.py index 8b2d562..16ef823 100644 --- a/02-tmcra-memory-api/tmcra_service/runtime.py +++ b/02-tmcra-memory-api/tmcra_service/runtime.py @@ -806,7 +806,16 @@ def _scope_execution_lock( if not local_lock.acquire(blocking=blocking): raise BlockingIOError("scope mutation lane is active") lock_file = None + windows_lock = None try: + if os.name == "nt": + from tmcra_local_only import process_lock + windows_lock = process_lock(self._scope_lock_path(lock_key), timeout=600 if blocking else 0) + try: + windows_lock.__enter__() + except TimeoutError as exc: + windows_lock = None + raise BlockingIOError("scope mutation lane is active") from exc if os.name == "posix": import fcntl @@ -820,6 +829,8 @@ def _scope_execution_lock( raise yield finally: + if windows_lock is not None: + windows_lock.__exit__(None, None, None) if lock_file is not None: import fcntl diff --git a/02-tmcra-memory-api/tmcra_service/session_graph.py b/02-tmcra-memory-api/tmcra_service/session_graph.py index a972cdb..d55a155 100644 --- a/02-tmcra-memory-api/tmcra_service/session_graph.py +++ b/02-tmcra-memory-api/tmcra_service/session_graph.py @@ -1942,7 +1942,7 @@ def _call( "projection_slot_invalid", "projection work may use only the graph slot or the borrowed planner slot", ) - body["id_slot"] = local_slot_id + body["id_slot"] = 0 if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else local_slot_id if ( self.provider == SESSION_GRAPH_PROVIDER_DEDICATED or self.base_url == LOCAL_QWEN_BASE_URL diff --git a/02-tmcra-memory-api/tmcra_service/shared_core_manifest.json b/02-tmcra-memory-api/tmcra_service/shared_core_manifest.json index a7ddb22..d1de7b5 100644 --- a/02-tmcra-memory-api/tmcra_service/shared_core_manifest.json +++ b/02-tmcra-memory-api/tmcra_service/shared_core_manifest.json @@ -1,7 +1,7 @@ { "schema_version": "tmcra.service.shared-core-manifest.1", - "service_version": "0.3.0-rc2", - "generated_on": "2026-08-17", + "service_version": "1.0.0-rc.1", + "generated_on": "2026-09-06", "algorithm_files": [ { "path": "prepare_tmcra_v4_e2e_data.py", @@ -9,7 +9,7 @@ }, { "path": "run_tmcra_v4_build.py", - "sha256": "1ebc54751fcfea91bbd8ea019cac45ca79cf60ce229bf7249d0427955093f93e" + "sha256": "4172caaa4e5a9b75dc2dec7c8188e6f585376aecb41e4f08a2514b25193ee4b9" }, { "path": "run_tmcra_v4_compile_evidence.py", @@ -17,7 +17,7 @@ }, { "path": "tmp_tmcra_v2_lme_pipeline.py", - "sha256": "647629e0f68f06afe4a6159e60ecc0307b2749fc6f4bebbf129d1789b14e5c85" + "sha256": "7e1ade3b1902c14c405be975c99764b6fac4843bd3b2a8ace5185593ec2fe365" }, { "path": "tmcra_v2_lme_pipeline.py", @@ -25,7 +25,7 @@ }, { "path": "tmcra_v3_online_runtime.py", - "sha256": "52bc316478d2c3502b0f8f88eed4242740ff1fcddf789d656842f4efd028809a" + "sha256": "18b55050ff04bc8235b6c5aa2d53adf891a793179b4478bf4cfdfd6038c7195d" }, { "path": "tmcra_v3_product_writer.py", @@ -41,7 +41,7 @@ }, { "path": "tmcra_v4_batch_writer.py", - "sha256": "352568d64d831dbb28a228e9cd898f688636330b13ac2ff99e5ed36226a4dbf2" + "sha256": "a46a3695b08a8a5bd205863a43c416340863976f274d851ed2db4d04f5c125f5" }, { "path": "tmcra_v4_cost_report.py", @@ -57,11 +57,11 @@ }, { "path": "tmcra_v4_online_runtime.py", - "sha256": "4fee0d591cd4140353d0adf57287e93534607e06db7c92b5ab42fbb0afe45db2" + "sha256": "7ef1bb4ec78094fa166750b78b567079b7048ca52787cfbefd7e3aaf8a9a8a2e" }, { "path": "tmcra_v4_slow_graph.py", - "sha256": "985e2aab12eba2b96bd53cc05e7352412fb45bd3d9fee3a0a8213b26ff4dba0b" + "sha256": "7ebf6d258b85c9a463e55c0dcdc817e9fc27b42fc93af7abdf48e62ecf8acf42" }, { "path": "tmcra_v4_recall_planner.py", @@ -78,6 +78,14 @@ { "path": "tmcra_v4_typed_semantics.py", "sha256": "367917528c80829a9b99ecebc1f9c533fb77f39753713b65abadbddb9c4e43e5" + }, + { + "path": "tmcra_local_only.py", + "sha256": "16da1be2c9d8bf881481ea64a09de30b423e3c4c496017e0b693e0bd2ba45e05" + }, + { + "path": "tmcra_local_models.py", + "sha256": "f464a241c7f7ca2f78a52f7c03d7157520795281ac5c7e01faeaea4606274fb4" } ] } diff --git a/02-tmcra-memory-api/tmcra_service/startup.py b/02-tmcra-memory-api/tmcra_service/startup.py index 6a86c02..8c38483 100644 --- a/02-tmcra-memory-api/tmcra_service/startup.py +++ b/02-tmcra-memory-api/tmcra_service/startup.py @@ -32,6 +32,8 @@ ServiceSettings, ) from .writer_provider import ( + DESKTOP_LOCAL_QWEN_MODEL, + DESKTOP_LOCAL_QWEN_MIN_CONTEXT_TOKENS, LOCAL_QWEN_MIN_CONTEXT_TOKENS, LOCAL_QWEN_PROVIDER, primary_writer_route, @@ -647,14 +649,18 @@ def _local_model_context_check(route: Any) -> Mapping[str, Any]: context_tokens = int(raw_context) except (TypeError, ValueError) as exc: raise RuntimeError("local Qwen context probe omitted n_ctx") from exc - if context_tokens < LOCAL_QWEN_MIN_CONTEXT_TOKENS: + required_context = (DESKTOP_LOCAL_QWEN_MIN_CONTEXT_TOKENS + if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" + and route.model == DESKTOP_LOCAL_QWEN_MODEL + else LOCAL_QWEN_MIN_CONTEXT_TOKENS) + if context_tokens < required_context: raise RuntimeError( "local Qwen context is below the Writer contract: " - f"{context_tokens} < {LOCAL_QWEN_MIN_CONTEXT_TOKENS}" + f"{context_tokens} < {required_context}" ) return { "n_ctx": context_tokens, - "required_n_ctx": LOCAL_QWEN_MIN_CONTEXT_TOKENS, + "required_n_ctx": required_context, "paid_probe": False, } @@ -666,7 +672,12 @@ def _network_check(self) -> Mapping[str, Any]: ): raise RuntimeError("public bind is not protected by the configured TLS proxy") public = urlparse(self.settings.public_base_url) - if public.scheme != "https" or not public.netloc: + from tmcra_local_only import enabled, loopback_url + if enabled(): + if not address.is_loopback: + raise RuntimeError("full-local service must bind loopback") + loopback_url(self.settings.public_base_url, port=self.settings.bind_port, path="") + elif public.scheme != "https" or not public.netloc: raise RuntimeError("public base URL must be HTTPS") return { "bind_mode": "loopback" if address.is_loopback else "tls_proxy", diff --git a/02-tmcra-memory-api/tmcra_service/tests/test_feedback_effects.py b/02-tmcra-memory-api/tmcra_service/tests/test_feedback_effects.py new file mode 100644 index 0000000..bbd807e --- /dev/null +++ b/02-tmcra-memory-api/tmcra_service/tests/test_feedback_effects.py @@ -0,0 +1,141 @@ +from __future__ import annotations +import copy +import tempfile +import unittest +from pathlib import Path +from unittest import mock + +from fastapi.testclient import TestClient +from tmcra_service.app import create_app +from tmcra_service.api_models import FeedbackRequest, PromptEvidenceView +from tmcra_service.feedback_effects import apply_feedback +from tmcra_service.evidence_view import build_prompt_evidence +from tmcra_service.tests.test_content_deletion_contract import _settings, _seed_scope + + +class FeedbackEffectsTests(unittest.TestCase): + def test_filters_derived_and_neighbor_evidence_without_mutating_original(self): + evidence = {"evidence_windows": [ + {"source_record_id": "a", "text": "OLD SECRET", "actor_role": "user", "memory_contexts": [{"memory_id": "derived-a", "claim_text": "OLD DERIVED"}]}, + {"source_record_id": "b", "text": "unrelated", "actor_role": "user", "source_group_context": [{"source_record_id": "a", "text": "OLD NEIGHBOR"}]}, + {"source_record_id": "c", "text": "keep this", "actor_role": "assistant"}, + ], "compiled_evidence_packet": {"stale": "OLD SECRET"}} + original = copy.deepcopy(evidence) + effect = {"a": {"action": "correct", "feedback_id": "fb1", "replacement": "Correct user fact", "created_at": 100.0}} + filtered = apply_feedback(evidence, effect) + prompt = build_prompt_evidence(filtered, selected_route="raw") + PromptEvidenceView.model_validate(prompt) + self.assertNotIn("OLD", str(filtered)) + self.assertEqual(prompt["content"].count("Correct user fact"), 1) + self.assertIn("keep this", prompt["content"]) + self.assertIn("explicit_user_correction", prompt["content"]) + self.assertEqual(evidence, original) + self.assertEqual(len(prompt["sources"]), 2) + + def test_ignored_all_is_valid_empty_recall(self): + filtered = apply_feedback({"evidence_windows": [{"source_record_id": "a", "text": "old"}]}, + {"a": {"action": "ignore"}}) + result = build_prompt_evidence(filtered, selected_route="raw") + self.assertEqual(result["content"], "") + PromptEvidenceView.model_validate(result) + + def test_correction_requires_replacement_and_targets(self): + for body in ({"rating": "incorrect", "action": "correct", "memory_ids": ["a"]}, + {"rating": "incorrect", "action": "ignore"}): + with self.assertRaises(ValueError): + FeedbackRequest.model_validate(body) + + def test_indexed_corrections_follow_recorrection_ignore_and_restore(self): + with tempfile.TemporaryDirectory() as directory: + commercial = create_app(_settings(Path(directory))).state.components.commercial + + def feedback(action, replacement=None, targets=None): + return commercial.add_feedback("tenant-a", "scope-a", query_id=None, rating="incorrect", + memory_ids=targets or ["source-a"], comment=None, credential_id="test", + metadata={"_tmcra_action": action, "_tmcra_replacement": replacement}) + + first = feedback("correct", "First corrected value") + # The writer creates its own source ID; V4 recall retains session_id. + indexed = {"evidence_windows": [{"source_record_id": "indexed-source-random-id", + "session_id": f"correction-{first['feedback_id']}", "text": "First corrected value", + "memory_contexts": [{"memory_id": "derived-correction", "claim_text": "First derived value"}]}]} + second = feedback("correct", "Final corrected value") + effects = commercial.feedback_effects("tenant-a", "scope-a") + rendered = build_prompt_evidence(apply_feedback(indexed, effects), selected_route="raw") + self.assertNotIn("First", rendered["content"]) + self.assertEqual(rendered["content"].count("Final corrected value"), 1) + self.assertIn(second["feedback_id"], rendered["content"]) + + feedback("ignore", targets=["indexed-source-random-id"]) + self.assertEqual(apply_feedback(indexed, commercial.feedback_effects("tenant-a", "scope-a"))["evidence_windows"], []) + feedback("restore", targets=["indexed-source-random-id"]) + feedback("restore") + restored = apply_feedback({"evidence_windows": [ + {"source_record_id": "source-a", "text": "Original source"}, *indexed["evidence_windows"]]}, + commercial.feedback_effects("tenant-a", "scope-a")) + self.assertEqual([window["text"] for window in restored["evidence_windows"]], ["Original source"]) + + def test_api_correction_idempotency_restore_scope_and_write_permission(self): + with tempfile.TemporaryDirectory() as directory: + app = create_app(_settings(Path(directory))) + components = app.state.components + components.auth.set_tenant_scopes("tenant-a", {"memory:read", "memory:write", "memory:feedback"}) + key = components.auth.create_key("tenant-a").api_key + _seed_scope(components.storage, "tenant-a", "scope-a") + headers = {"Authorization": f"Bearer {key}", "Idempotency-Key": "correction-test-one"} + client = TestClient(app) + self.addCleanup(client.close) + body = {"rating": "incorrect", "memory_ids": ["source-a"], "action": "correct", "replacement": "The new value is 42"} + result = client.post("/v1/scopes/scope-a/feedback", headers=headers, json=body) + self.assertEqual(result.status_code, 201, result.text) + self.assertTrue(result.json()["effective"]) + self.assertIsNotNone(result.json()["correction_job_id"], result.text) + self.assertIn(result.json()["correction_index_status"], {"pending", "queued", "submission_pending"}) + replay = client.post("/v1/scopes/scope-a/feedback", headers=headers, json=body) + self.assertEqual(replay.status_code, 201, replay.text) + self.assertEqual(replay.json()["feedback_id"], result.json()["feedback_id"]) + changed = client.post("/v1/scopes/scope-a/feedback", headers=headers, json={**body, "replacement": "Different"}) + self.assertEqual(changed.status_code, 409, changed.text) + self.assertEqual(components.commercial.feedback_effects("tenant-b", "scope-a"), {}) + self.assertEqual(components.commercial.feedback_effects("tenant-a", "scope-b"), {}) + effects = components.commercial.feedback_effects("tenant-a", "scope-a") + self.assertEqual(effects["source-a"]["replacement"], body["replacement"]) + restore = client.post("/v1/scopes/scope-a/feedback", headers={**headers, "Idempotency-Key": "restore-feedback-one"}, + json={"rating": "helpful", "action": "restore", "memory_ids": [result.json()["feedback_id"]]}) + self.assertEqual(restore.status_code, 201, restore.text) + restored_effects = components.commercial.feedback_effects("tenant-a", "scope-a") + self.assertNotIn("source-a", restored_effects) + self.assertEqual(restored_effects[result.json()["feedback_id"]]["corrections"], []) + unknown = client.post("/v1/scopes/scope-a/feedback", headers={**headers, "Idempotency-Key": "unknown-feedback-one"}, + json={"rating": "incorrect", "action": "ignore", "memory_ids": ["nonexistent"]}) + self.assertEqual(unknown.status_code, 404, unknown.text) + components.auth.set_tenant_scopes("tenant-read", {"memory:feedback"}) + read_key = components.auth.create_key("tenant-read").api_key + denied = client.post("/v1/scopes/scope-a/feedback", headers={**headers, "Authorization": f"Bearer {read_key}"}, json=body) + self.assertEqual(denied.status_code, 403, denied.text) + + def test_recall_endpoint_applies_feedback_before_rendering(self): + with tempfile.TemporaryDirectory() as directory: + app = create_app(_settings(Path(directory))) + components = app.state.components + components.auth.set_tenant_scopes("tenant-a", {"memory:read", "memory:feedback"}) + key = components.auth.create_key("tenant-a").api_key + _seed_scope(components.storage, "tenant-a", "scope-a") + paths = components.storage.scope_paths("tenant-a", "scope-a") + components.commercial.add_feedback("tenant-a", "scope-a", query_id=None, rating="incorrect", memory_ids=["source-a"], + comment=None, metadata={"_tmcra_action": "ignore"}, credential_id="test") + snapshot = {"database": paths.database, "scope_id": paths.scope_id, "job_id": "index-test"} + evidence = {"evidence_windows": [{"source_record_id": "source-a", "text": "SHOULD DISAPPEAR", "actor_role": "user"}]} + online = mock.Mock() + online.recall.return_value = (evidence, {}) + with mock.patch.object(components.storage, "active_snapshot", return_value=snapshot), \ + mock.patch.object(components.online, "get", return_value=online), \ + mock.patch.object(components.worker, "start"), mock.patch.object(components.worker, "stop"), TestClient(app) as client: + result = client.post("/v1/scopes/scope-a/recall", headers={"Authorization": f"Bearer {key}"}, + json={"query": "old value", "max_windows": 8, "evidence_mode": "raw"}) + self.assertEqual(result.status_code, 200, result.text) + self.assertEqual(result.json()["prompt_evidence"]["content"], "") + + +if __name__ == "__main__": + unittest.main() diff --git a/02-tmcra-memory-api/tmcra_service/tests/test_local_deployment.py b/02-tmcra-memory-api/tmcra_service/tests/test_local_deployment.py new file mode 100644 index 0000000..5d7846c --- /dev/null +++ b/02-tmcra-memory-api/tmcra_service/tests/test_local_deployment.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import argparse +import json +import os +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +from tmcra_local_models import profile_by_id, qwen_rerank_windows, signature, verify_index_identity +from tmcra_local_only import ROLES, configure_routes, loopback_url, validate_environment + +ROOT = Path(__file__).resolve().parents[2] + + +def local_env(): + result = configure_routes({"TMCRA_SERVICE_BIND_HOST": "127.0.0.1", "TMCRA_SERVICE_BIND_PORT": "2009", + "TMCRA_SERVICE_PUBLIC_BASE_URL": "http://127.0.0.1:2009", + "DEEPSEEK_API_KEY": "test-cloud-secret", "HTTPS_PROXY": "http://192.0.2.1:9"}, + base_url="http://127.0.0.1:2010/v1", model="tmcra-qwen3-4b-q4km", key="local-test-only") + return result + + +class LocalBoundaryTests(unittest.TestCase): + def test_prepare_discovers_ports_and_reuses_identity_without_account(self): + from tmcra_service.local_deployment import prepare + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + server = root / "synthetic-server.exe" + server.write_bytes(b"synthetic installer test; never executed") + with patch("tmcra_service.local_deployment.hardware", return_value={"ram_gib": 64, "cuda_available": False}), \ + patch("tmcra_service.local_deployment.download_model", side_effect=lambda model, path: path.mkdir(parents=True, exist_ok=True)), \ + patch("tmcra_service.local_deployment.install_llama", return_value=server): + first = prepare(root, "lite-cpu", auto_ports=True) + identity = (root / "state/lite-cpu/secrets/client-plugin.json").read_text() + second = prepare(root, "lite-cpu", auto_ports=True) + self.assertNotEqual(first["api_port"], first["model_port"]) + self.assertEqual(first["api_port"], second["api_port"]) + self.assertEqual(identity, (root / "state/lite-cpu/secrets/client-plugin.json").read_text()) + self.assertEqual(first["api_root"], str(ROOT)) + + def test_all_routes_local_cloud_keys_removed(self): + env = local_env() + validate_environment(env) + self.assertNotIn("DEEPSEEK_API_KEY", env) + self.assertNotIn("HTTPS_PROXY", env) + for role in ROLES: + self.assertEqual(env[f"TMCRA_{role}_BASE_URL"], "http://127.0.0.1:2010/v1") + + def test_each_hidden_route_rejects_cloud(self): + for role in ROLES: + with self.subTest(role=role): + env = local_env() + env[f"TMCRA_{role}_BASE_URL"] = "https://api.example.invalid/v1" + with self.assertRaises(ValueError): + validate_environment(env) + + def test_loopback_url_rejects_ambiguous_hosts(self): + for value in ["http://localhost:2009", "http://127.1:2009", "http://2130706433:2009", + "http://127.0.0.1.example.com:2009", "http://user@127.0.0.1:2009", + "http://0.0.0.0:2009", "http://[::ffff:192.0.2.1]:2009", "http://127.0.0.1:2009?x=1"]: + with self.subTest(url=value), self.assertRaises(ValueError): + loopback_url(value) + + def test_guard_blocks_tcp_dns_udp_and_wildcard(self): + code = ''' +import socket +from tmcra_local_only import install_network_guard +install_network_guard() +checks = [lambda: socket.getaddrinfo("example.invalid", 443), + lambda: socket.socket().connect(("192.0.2.1", 9)), + lambda: socket.socket(type=socket.SOCK_DGRAM).sendto(b"synthetic", ("192.0.2.1", 9)), + lambda: socket.socket().bind(("0.0.0.0", 0))] +for check in checks: + try: check() + except PermissionError: pass + else: raise AssertionError("external network operation permitted") +with socket.socket() as server: server.bind(("127.0.0.1", 0)) +print("guard_ok") +''' + result = subprocess.run([sys.executable, "-c", code], cwd=ROOT, capture_output=True, text=True, timeout=20) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("guard_ok", result.stdout) + + def test_child_bootstrap_fails_closed(self): + env = dict(os.environ) + env.update(local_env()) + env["PYTHONPATH"] = os.pathsep.join([str(ROOT / "deploy" / "local-bootstrap"), str(ROOT)]) + env["TMCRA_WRITER_BASE_URL"] = "https://example.invalid/v1" + result = subprocess.run([sys.executable, "-c", "print('should_not_run')"], env=env, + capture_output=True, text=True, timeout=20) + self.assertEqual(result.returncode, 78) + self.assertNotIn("should_not_run", result.stdout) + + def test_local_identity_reused_without_account_server(self): + from tmcra_service.local_deployment import initialize_identity + with tempfile.TemporaryDirectory() as directory: + state = Path(directory) / "state" + with patch("tmcra_service.local_deployment.private_directory", side_effect=lambda p: p.mkdir(parents=True, exist_ok=True)): + key = initialize_identity(state) + credential = (state / "secrets" / "client.json").read_text() + self.assertEqual(initialize_identity(state), key) + self.assertEqual((state / "secrets" / "client.json").read_text(), credential) + + +class ModelContractTests(unittest.TestCase): + def test_token_windows_cover_all_source_characters(self): + from tmp_tmcra_v2_lme_pipeline import HuggingFaceDenseVectorizer + class CharacterTokenizer: + def encode(self, text, **_): + return list(range(len(text) + 2)) + vectorizer = HuggingFaceDenseVectorizer.__new__(HuggingFaceDenseVectorizer) + vectorizer.tokenizer = CharacterTokenizer() + vectorizer.document_prefix = "passage: " + vectorizer.max_length = 64 + text = "中文来源🙂mixed long source " * 31 + prefix = "message=001 role=user\n" + spans = vectorizer.source_spans(text, prefix=prefix, max_chars=1800, overlap_chars=200) + covered = set() + self.assertGreater(len(spans), 1) + for start, end in spans: + self.assertLessEqual(len(vectorizer.tokenizer.encode(vectorizer.document_prefix + prefix + text[start:end])), 64) + covered.update(range(start, end)) + self.assertEqual(covered, set(range(len(text)))) + self.assertTrue(all(b[0] > a[0] for a, b in zip(spans, spans[1:]))) + + def test_embedding_index_identity(self): + profile = profile_by_id("lite-cpu") + args = argparse.Namespace(text_dim=384, embedding_index_signature=signature(profile)) + verify_index_identity({"text_dim": 384, "embedding_index_signature": signature(profile)}, args) + for payload in [{"text_dim": 1024}, {"text_dim": 384, "embedding_index_signature": "older"}]: + with self.assertRaises(RuntimeError): + verify_index_identity(payload, args) + + def test_profile_signatures_unique_and_change_on_pooling(self): + first = profile_by_id("lite-cpu") + before = signature(first) + first["embedding"]["pooling"] = "cls" + self.assertNotEqual(signature(first), before) + self.assertEqual(len({signature(profile_by_id(p)) for p in ["lite-cpu", "balanced-bge", "quality-qwen"]}), 3) + + def test_qwen_format_and_document_coverage(self): + class CharacterTokenizer: + def encode(self, text, **_): + return list(map(ord, text)) + document = "记忆证据" * 500 + windows = qwen_rerank_windows(CharacterTokenizer(), "synthetic question", document, max_length=512) + self.assertGreater(len(windows), 1) + self.assertTrue(all(len(w) <= 512 for w in windows)) + self.assertTrue(all("<|im_start|>system" in "".join(map(chr, w)) for w in windows)) + with self.assertRaises(ValueError): + qwen_rerank_windows(CharacterTokenizer(), "Q" * 500, document, max_length=512) + + +if __name__ == "__main__": + unittest.main() diff --git a/02-tmcra-memory-api/tmcra_v3_online_runtime.py b/02-tmcra-memory-api/tmcra_v3_online_runtime.py index ef308db..9668672 100644 --- a/02-tmcra-memory-api/tmcra_v3_online_runtime.py +++ b/02-tmcra-memory-api/tmcra_v3_online_runtime.py @@ -878,6 +878,7 @@ def parent_subchunks( scope_id: str, subchunk_chars: int, subchunk_overlap: int, + vectorizer: Any = None, ) -> list[dict[str, Any]]: candidates: list[dict[str, Any]] = [] for parent in parents: @@ -892,7 +893,10 @@ def parent_subchunks( f"parent_chunk={int(parent['parent_chunk_index']):02d}" ) payload_chars = int(subchunk_chars) - len(prefix) - 1 - spans = covered_windows(str(parent["text"]), payload_chars, int(subchunk_overlap)) + spans = (vectorizer.source_spans(str(parent["text"]), prefix=prefix + "\n", + max_chars=payload_chars, overlap_chars=int(subchunk_overlap)) + if vectorizer is not None and hasattr(vectorizer, "source_spans") + else covered_windows(str(parent["text"]), payload_chars, int(subchunk_overlap))) for subchunk_index, (char_start, char_end) in enumerate(spans, start=1): text = f"{prefix}\n{str(parent['text'])[char_start:char_end]}" if len(text) > subchunk_chars: @@ -1335,6 +1339,8 @@ def __call__( class OnlineModels: def __init__(self, args: argparse.Namespace): + from tmcra_local_models import apply_local_profile + apply_local_profile(args) self.device = torch.device(args.device) if self.device.type == "cuda" and not torch.cuda.is_available(): raise RuntimeError("CUDA is unavailable") @@ -1348,6 +1354,7 @@ def __init__(self, args: argparse.Namespace): query_prefix=str(getattr(args, "embedding_query_prefix", "")), document_prefix=str(getattr(args, "embedding_document_prefix", "")), padding_side=str(getattr(args, "embedding_padding_side", "right")), + long_document_policy=str(getattr(args, "embedding_long_document_policy", "reject")), ) self.reranker_mode = str( getattr(args, "reranker_mode", "fusion") or "fusion" @@ -1370,7 +1377,7 @@ def __init__(self, args: argparse.Namespace): self.fusion = _SemanticOnlyFusion() return - from transformers import AutoModelForSequenceClassification, AutoTokenizer + from transformers import AutoModelForCausalLM, AutoModelForSequenceClassification, AutoTokenizer cross_path = Path(args.cross_model).resolve() model_manifest_path = cross_path / "TMCRA_MODEL_MANIFEST.json" @@ -1378,7 +1385,14 @@ def __init__(self, args: argparse.Namespace): raise FileNotFoundError(f"pinned cross model manifest is required: {model_manifest_path}") self.cross_manifest = json.loads(model_manifest_path.read_text(encoding="utf-8")) self.cross_tokenizer = AutoTokenizer.from_pretrained(str(cross_path), local_files_only=True) - self.cross_model = AutoModelForSequenceClassification.from_pretrained( + self.reranker_adapter = getattr(args, "reranker_adapter", "sequence-classification") + if self.reranker_adapter not in {"sequence-classification", "causal-lm-yes-no"}: + raise ValueError("unsupported reranker adapter") + causal = self.reranker_adapter == "causal-lm-yes-no" + if causal and self.reranker_mode != "semantic-only": + raise ValueError("Qwen yes/no reranker requires semantic-only scoring") + model_class = AutoModelForCausalLM if causal else AutoModelForSequenceClassification + self.cross_model = model_class.from_pretrained( str(cross_path), local_files_only=True, torch_dtype=torch.float16 if self.device.type == "cuda" else torch.float32, @@ -1412,6 +1426,8 @@ def __init__(self, args: argparse.Namespace): self.checkpoint_sha256 = sha256_file(checkpoint_path) def encode_cross(self, query: str, texts: Sequence[str]) -> tuple[torch.Tensor, torch.Tensor]: + if getattr(self, "reranker_adapter", "") == "causal-lm-yes-no": + return self._encode_causal_cross(query, texts) if self.reranker_mode == "dense-only": if not texts: raise RuntimeError("dense-only reranker got no texts") @@ -1498,6 +1514,30 @@ def encode_cross(self, query: str, texts: Sequence[str]) -> tuple[torch.Tensor, logits.append(torch.stack(selected_logits, dim=0)) return torch.cat(representations, dim=0), torch.cat(logits, dim=0) + def _encode_causal_cross(self, query, texts): + from tmcra_local_models import qwen_rerank_windows + if not texts: + raise ValueError("reranker got no documents") + tokenizer = self.cross_tokenizer + tokenizer.padding_side = "left" + labels = [tokenizer.encode(label, add_special_tokens=False) for label in ("no", "yes")] + if any(len(label) != 1 for label in labels) or labels[0] == labels[1]: + raise RuntimeError("Qwen yes/no token contract differs") + scores = [] + with torch.inference_mode(): + for text in texts: + windows = qwen_rerank_windows(tokenizer, query, text, max_length=self.cross_max_length) + window_scores = [] + for start in range(0, len(windows), self.cross_batch_size): + encoded = tokenizer.pad({"input_ids": windows[start:start + self.cross_batch_size]}, + padding=True, return_tensors="pt") + encoded = {key: value.to(self.device) for key, value in encoded.items()} + output = self.cross_model(**encoded, logits_to_keep=1, return_dict=True) + logits = output.logits[:, -1, [labels[0][0], labels[1][0]]].float() + window_scores.append(torch.log_softmax(logits, dim=-1)[:, 1]) + scores.append(torch.cat(window_scores).max()) + return torch.empty((len(texts), 0), device=self.device), torch.stack(scores) + def load_online_index(path: Path, expected_db: Path, expected_scope: str) -> tuple[list[dict[str, Any]], torch.Tensor, list[dict[str, Any]], torch.Tensor, list[dict[str, Any]], dict[str, Any]]: payload = torch.load(path, map_location="cpu", weights_only=False) diff --git a/02-tmcra-memory-api/tmcra_v4_batch_writer.py b/02-tmcra-memory-api/tmcra_v4_batch_writer.py index dd8df64..99965a9 100644 --- a/02-tmcra-memory-api/tmcra_v4_batch_writer.py +++ b/02-tmcra-memory-api/tmcra_v4_batch_writer.py @@ -2766,20 +2766,13 @@ def _commit_guard(self): f".{Path(self.adapter.storage_path).name}.{sha256_text(self.scope_id)[:16]}.commit.lock" ) lock_path.parent.mkdir(parents=True, exist_ok=True) - with self._process_commit_lock(), lock_path.open("a+b") as lock_file: - try: - import fcntl - except ImportError: - fcntl = None - if fcntl is not None: - fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX) + from tmcra_local_only import process_lock + with self._process_commit_lock(), process_lock(lock_path, timeout=600): self._scope_lock_depth = 1 try: yield finally: self._scope_lock_depth = 0 - if fcntl is not None: - fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN) @contextmanager def mutation_batch(self): diff --git a/02-tmcra-memory-api/tmcra_v4_online_runtime.py b/02-tmcra-memory-api/tmcra_v4_online_runtime.py index 1784615..a63f30c 100644 --- a/02-tmcra-memory-api/tmcra_v4_online_runtime.py +++ b/02-tmcra-memory-api/tmcra_v4_online_runtime.py @@ -3038,6 +3038,8 @@ def finish_phase(name: str) -> None: base_candidates, base_payload = load_online_index_catalog( base_index_path, base_db_path, scope_id ) + from tmcra_local_models import verify_index_identity + verify_index_identity(base_payload, args) text_dim = int(base_payload["text_dim"]) if text_dim != int(_arg(args, "text_dim", text_dim)): raise RuntimeError("online delta text dimension differs from the active base") @@ -3120,6 +3122,7 @@ def finish_phase(name: str) -> None: scope_id=scope_id, subchunk_chars=int(base_payload["subchunk_chars"]), subchunk_overlap=int(base_payload["subchunk_overlap"]), + vectorizer=vectorizer, ) if parents else [] @@ -3162,6 +3165,7 @@ def finish_phase(name: str) -> None: scope_id=scope_id, subchunk_chars=int(base_payload["subchunk_chars"]), subchunk_overlap=int(base_payload["subchunk_overlap"]), + vectorizer=vectorizer, ) base_ids_for_diff = { _clean(item.get("candidate_id")) for item in base_candidates @@ -3369,6 +3373,7 @@ def build_online_base_index( scope_id=scope_id, subchunk_chars=expected["subchunk_chars"], subchunk_overlap=expected["subchunk_overlap"], + vectorizer=vectorizer, ) slow, semantic_records = load_v4_layered_inventory(db_path, scope_id, parents) slow_counts = _validated_slow_inventory_counts(slow) @@ -3600,6 +3605,7 @@ def command_build_index(args: argparse.Namespace) -> None: padding_side=str( getattr(args, "embedding_padding_side", "right") ), + long_document_policy=str(getattr(args, "embedding_long_document_policy", "reject")), ) graph_fingerprint = v3.scope_fingerprint(db_path, scope_id) parents = v3.load_persisted_parent_chunks(db_path, scope_id) @@ -3608,6 +3614,7 @@ def command_build_index(args: argparse.Namespace) -> None: scope_id=scope_id, subchunk_chars=args.subchunk_chars, subchunk_overlap=args.subchunk_overlap, + vectorizer=vectorizer, ) slow, semantic_records = load_v4_layered_inventory( db_path, scope_id, parents @@ -4118,6 +4125,8 @@ def main() -> int: retrieve = sub.add_parser("retrieve") retrieve.add_argument("--query-manifest", required=True); retrieve.add_argument("--out-dir", required=True); retrieve.add_argument("--resume", action="store_true"); retrieve.add_argument("--planner-replay-dir"); retrieve.add_argument("--checkpoint", required=True); retrieve.add_argument("--cross-model", default="/opt/tmcra-models/BAAI/bge-reranker-v2-m3"); retrieve.add_argument("--cross-max-length", type=int, default=1280); retrieve.add_argument("--cross-batch-size", type=int, default=24); retrieve.add_argument("--repo", required=True); retrieve.add_argument("--harness", required=True); retrieve.add_argument("--node-model", required=True); retrieve.add_argument("--path-model", required=True); retrieve.add_argument("--graph-device", default="cuda"); retrieve.add_argument("--candidate-event-k", type=int, default=24); retrieve.add_argument("--support-path-k", type=int, default=3); retrieve.add_argument("--path-tunnel-rescue-k", type=int, default=2); retrieve.add_argument("--graph-top-k", type=int, default=12); retrieve.add_argument("--dense-k", type=int, default=32); retrieve.add_argument("--slow-dense-k", type=int, default=24); retrieve.add_argument("--graph-k", type=int, default=24); retrieve.add_argument("--execution-lane", choices=sorted(EXECUTION_LANES), default="production"); retrieve.add_argument("--composition-mode", choices=sorted(COMPOSITION_MODES), default="layered"); retrieve.add_argument("--packing-budget-mode", choices=sorted(PACKING_BUDGET_MODES), default="fixed"); retrieve.add_argument("--top-k", type=int, default=8); retrieve.add_argument("--adaptive-simple-k", type=int, default=8); retrieve.add_argument("--adaptive-standard-k", type=int, default=12); retrieve.add_argument("--adaptive-complex-k", type=int, default=16); add_common_model_args(retrieve) args = parser.parse_args() + from tmcra_local_models import apply_local_profile + apply_local_profile(args) (command_build_index if args.command == "build-index" else command_retrieve)(args) return 0 diff --git a/02-tmcra-memory-api/tmcra_v4_slow_graph.py b/02-tmcra-memory-api/tmcra_v4_slow_graph.py index e4b2091..d9cadc2 100644 --- a/02-tmcra-memory-api/tmcra_v4_slow_graph.py +++ b/02-tmcra-memory-api/tmcra_v4_slow_graph.py @@ -1232,7 +1232,7 @@ def _propose( self.config.provider == LOCAL_QWEN_PROVIDER and self.config.base_url == LOCAL_QWEN_BASE_URL ): - body["id_slot"] = LOCAL_QWEN_GRAPH_SLOT_ID + body["id_slot"] = 0 if os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else LOCAL_QWEN_GRAPH_SLOT_ID if self.config.provider == DEEPSEEK_PROVIDER: body.update( { diff --git a/02-tmcra-memory-api/tmp_tmcra_v2_lme_pipeline.py b/02-tmcra-memory-api/tmp_tmcra_v2_lme_pipeline.py index 229e117..42e69b8 100644 --- a/02-tmcra-memory-api/tmp_tmcra_v2_lme_pipeline.py +++ b/02-tmcra-memory-api/tmp_tmcra_v2_lme_pipeline.py @@ -348,6 +348,7 @@ def __init__( query_prefix: str = "", document_prefix: str = "", padding_side: str = "right", + long_document_policy: str = "reject", ): from transformers import AutoModel, AutoTokenizer self.dim = int(dim) @@ -359,6 +360,9 @@ def __init__( self.query_prefix = str(query_prefix or "") self.document_prefix = str(document_prefix or "") self.padding_side = clean_text(padding_side).lower() or "right" + self.long_document_policy = long_document_policy + if long_document_policy not in {"reject", "window_mean"}: + raise ValueError("unknown long document policy") if self.max_length <= 0: raise RuntimeError("--embedding-max-length must be positive") if self.pooling not in {"cls", "mean", "last_token"}: @@ -369,7 +373,10 @@ def __init__( self.model_path = str(resolved) self.tokenizer = AutoTokenizer.from_pretrained(str(resolved), local_files_only=True) self.tokenizer.padding_side = self.padding_side - self.model = AutoModel.from_pretrained(str(resolved), local_files_only=True).to(self.device) + self.model = AutoModel.from_pretrained( + str(resolved), local_files_only=True, + torch_dtype=torch.float16 if self.device.type == "cuda" and os.getenv("TMCRA_DEPLOYMENT_MODE") == "local" else torch.float32, + ).to(self.device) self.model.eval() hidden_size = int(getattr(self.model.config, "hidden_size", 0) or 0) if hidden_size != self.dim: @@ -415,6 +422,48 @@ def encode_batch( *, purpose: str = "document", ) -> torch.Tensor: + prefix = self._purpose_prefix(purpose) + if purpose == "document" and self.long_document_policy == "window_mean": + spans = [self.source_spans(clean_text(text)) for text in texts] + if any(len(value) > 1 for value in spans): + # Slow capsules retain their full evidence text. Their one-vector + # representation pools all windows explicitly; source messages + # are independently windowed with exact source coordinates. + windows = [clean_text(text)[start:end] for text, values in zip(texts, spans) for start, end in values] + encoded_windows = self._encode_short_batch(windows, batch_size, purpose=purpose) + output = [] + cursor = 0 + for values in spans: + vec = encoded_windows[cursor:cursor + len(values)].mean(dim=0) + output.append(vec / vec.norm().clamp_min(1e-6)) + cursor += len(values) + return torch.stack(output) + return self._encode_short_batch(texts, batch_size, purpose=purpose) + + def source_spans(self, text, *, prefix="", max_chars=None, overlap_chars=64): + """Cover every original character; tokenize prefix too; never truncate.""" + limit = len(text) if max_chars is None else max(1, int(max_chars)) + if len(self.tokenizer.encode(self.document_prefix + prefix, add_special_tokens=True)) >= self.max_length: + raise ValueError("source metadata exceeds embedding token budget") + if not text: + return [(0, 0)] + spans = [] + start = 0 + while start < len(text): + end = min(len(text), start + limit) + while len(self.tokenizer.encode(self.document_prefix + prefix + text[start:end], add_special_tokens=True)) > self.max_length: + # Token length need not be monotonic at subword boundaries. + # Geometric shrink is conservative and always makes progress. + end = start + max(0, (end - start) * 3 // 4) + if end <= start: + raise ValueError("a source character cannot fit the embedding token budget") + spans.append((start, end)) + if end == len(text): + break + start = max(start + 1, end - min(overlap_chars, (end - start) // 4)) + return spans + + def _encode_short_batch(self, texts, batch_size=4, *, purpose="document"): prefix = self._purpose_prefix(purpose) cleaned = [prefix + clean_text(t) for t in texts] if not cleaned: diff --git a/03-tmcra-web-console/deploy/gpuhome/miniflare-loopback-api-plugin/package.json b/03-tmcra-web-console/deploy/gpuhome/miniflare-loopback-api-plugin/package.json index 6f02cd4..458790a 100644 --- a/03-tmcra-web-console/deploy/gpuhome/miniflare-loopback-api-plugin/package.json +++ b/03-tmcra-web-console/deploy/gpuhome/miniflare-loopback-api-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tmcra/miniflare-loopback-api-plugin", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "private": true, "type": "module", "exports": "./index.mjs", diff --git a/03-tmcra-web-console/desktop/tmcra-memory/package-lock.json b/03-tmcra-web-console/desktop/tmcra-memory/package-lock.json index d86c6d9..43e298e 100644 --- a/03-tmcra-web-console/desktop/tmcra-memory/package-lock.json +++ b/03-tmcra-web-console/desktop/tmcra-memory/package-lock.json @@ -1,12 +1,12 @@ { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "UNLICENSED", "devDependencies": { "electron": "43.1.1", diff --git a/03-tmcra-web-console/desktop/tmcra-memory/package.json b/03-tmcra-web-console/desktop/tmcra-memory/package.json index a26510f..6057503 100644 --- a/03-tmcra-web-console/desktop/tmcra-memory/package.json +++ b/03-tmcra-web-console/desktop/tmcra-memory/package.json @@ -1,6 +1,6 @@ { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "private": true, "description": "TMCRA Memory desktop installer and account console for Codex", "author": "TMCRA", @@ -27,7 +27,7 @@ "tmcra": { "pluginArchive": "tmcra-codex-latest.zip", "pluginReleaseManifest": "tmcra-codex-release.json", - "fallbackPluginVersion": "0.3.0-rc.10", + "fallbackPluginVersion": "1.0.0-rc.1", "authorizationBaseUrl": "https://euvbyqa1jpvdm7yq-2000.sc01-webservice.gpuhome.cc:8443", "consolePath": "/personal", "allowedAuthenticationOrigins": [ diff --git a/03-tmcra-web-console/desktop/tmcra-memory/src/renderer/index.html b/03-tmcra-web-console/desktop/tmcra-memory/src/renderer/index.html index 269b1e8..0c4104a 100644 --- a/03-tmcra-web-console/desktop/tmcra-memory/src/renderer/index.html +++ b/03-tmcra-web-console/desktop/tmcra-memory/src/renderer/index.html @@ -41,7 +41,7 @@

让 Codex 记住项目,
但不把项目混在 尚未连接 - WINDOWS x64 · v0.3.0-rc2 + WINDOWS x64 · v1.0.0-rc.1

准备连接 Codex

应用会检查 Codex、安装记忆插件,再在安全窗口内完成登录。

diff --git a/03-tmcra-web-console/package-lock.json b/03-tmcra-web-console/package-lock.json index e4cecb3..4d35049 100644 --- a/03-tmcra-web-console/package-lock.json +++ b/03-tmcra-web-console/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tmcra/web-console", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tmcra/web-console", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "dependencies": { "@ai-sdk/openai-compatible": "^3.0.30", "@assistant-ui/react": "^0.15.14", @@ -50,7 +50,7 @@ }, "../06-tmcra-sdk-integrations/integrations/vercel-ai-sdk": { "name": "@tmcra/vercel-ai-sdk", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "MIT", "devDependencies": { "@ai-sdk/provider": "4.0.3", @@ -60,12 +60,12 @@ }, "peerDependencies": { "@ai-sdk/provider": ">=4 <5", - "@tmcra/typescript": ">=0.3.0-rc.2 <0.4.0" + "@tmcra/typescript": ">=1.0.0-rc.1 <0.4.0" } }, "../06-tmcra-sdk-integrations/sdk/typescript": { "name": "@tmcra/typescript", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "MIT", "devDependencies": { "typescript": "^5.7.2" @@ -76,7 +76,7 @@ }, "deploy/gpuhome/miniflare-loopback-api-plugin": { "name": "@tmcra/miniflare-loopback-api-plugin", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "dev": true, "dependencies": { "zod": "4.4.3" diff --git a/03-tmcra-web-console/package.json b/03-tmcra-web-console/package.json index dbbd34c..d9dcc49 100644 --- a/03-tmcra-web-console/package.json +++ b/03-tmcra-web-console/package.json @@ -1,6 +1,6 @@ { "name": "@tmcra/web-console", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "private": true, "engines": { "node": ">=22.13.0" diff --git a/03-tmcra-web-console/public/downloads/tmcra-codex-1.0.0-rc.1.zip.sha256 b/03-tmcra-web-console/public/downloads/tmcra-codex-1.0.0-rc.1.zip.sha256 new file mode 100644 index 0000000..e7b67bc --- /dev/null +++ b/03-tmcra-web-console/public/downloads/tmcra-codex-1.0.0-rc.1.zip.sha256 @@ -0,0 +1 @@ +ef6fb5c06e88e81c2a8164dcf4e18ae2c9bdc4cdb868cbc7130b125bf77fb17d tmcra-codex-1.0.0-rc.1.zip diff --git a/03-tmcra-web-console/public/downloads/tmcra-codex-latest.zip.sha256 b/03-tmcra-web-console/public/downloads/tmcra-codex-latest.zip.sha256 index 4ff59fa..8d92087 100644 --- a/03-tmcra-web-console/public/downloads/tmcra-codex-latest.zip.sha256 +++ b/03-tmcra-web-console/public/downloads/tmcra-codex-latest.zip.sha256 @@ -1 +1 @@ -df576ff7be026f67628124f402d5b06ceaf3f0a94ab0c6e516d96be70cbaa20a tmcra-codex-latest.zip +ef6fb5c06e88e81c2a8164dcf4e18ae2c9bdc4cdb868cbc7130b125bf77fb17d tmcra-codex-latest.zip diff --git a/03-tmcra-web-console/public/downloads/tmcra-codex-release.json b/03-tmcra-web-console/public/downloads/tmcra-codex-release.json index 715cf20..9198ce3 100644 --- a/03-tmcra-web-console/public/downloads/tmcra-codex-release.json +++ b/03-tmcra-web-console/public/downloads/tmcra-codex-release.json @@ -2,16 +2,16 @@ "schemaVersion": 1, "plugin": { "name": "tmcra-memory", - "version": "0.3.0-rc.10" + "version": "1.0.0-rc.1" }, "archive": { "latest": "tmcra-codex-latest.zip", - "versioned": "tmcra-codex-0.3.0-rc.10.zip", + "versioned": "tmcra-codex-1.0.0-rc.1.zip", "latestSha256": "tmcra-codex-latest.zip.sha256", - "versionedSha256": "tmcra-codex-0.3.0-rc.10.zip.sha256", - "bytes": 608689, - "sha256": "df576ff7be026f67628124f402d5b06ceaf3f0a94ab0c6e516d96be70cbaa20a", - "entryCount": 37 + "versionedSha256": "tmcra-codex-1.0.0-rc.1.zip.sha256", + "bytes": 6709156, + "sha256": "ef6fb5c06e88e81c2a8164dcf4e18ae2c9bdc4cdb868cbc7130b125bf77fb17d", + "entryCount": 235 }, "install": { "windows": ".\\Install-TMCRA.ps1", @@ -21,5 +21,5 @@ "node": ">=18", "codexPluginCli": true }, - "generatedAtUtc": "2026-09-04T00:02:14.7544528Z" + "generatedAtUtc": "2026-09-05T19:32:37.2863365Z" } diff --git a/03-tmcra-web-console/public/openapi.json b/03-tmcra-web-console/public/openapi.json index 610b418..0b0e251 100644 --- a/03-tmcra-web-console/public/openapi.json +++ b/03-tmcra-web-console/public/openapi.json @@ -6186,7 +6186,7 @@ "info": { "description": "Tenant-isolated long-term memory ingestion and prompt-ready recall. TMCRA does not generate the final assistant answer.", "title": "TMCRA Memory API", - "version": "0.3.0-rc2" + "version": "1.0.0-rc.1" }, "openapi": "3.1.0", "paths": { diff --git a/04-tmcra-desktop/package-lock.json b/04-tmcra-desktop/package-lock.json index d86c6d9..43e298e 100644 --- a/04-tmcra-desktop/package-lock.json +++ b/04-tmcra-desktop/package-lock.json @@ -1,12 +1,12 @@ { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "UNLICENSED", "devDependencies": { "electron": "43.1.1", diff --git a/04-tmcra-desktop/package.json b/04-tmcra-desktop/package.json index a26510f..6057503 100644 --- a/04-tmcra-desktop/package.json +++ b/04-tmcra-desktop/package.json @@ -1,6 +1,6 @@ { "name": "tmcra-memory-desktop", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "private": true, "description": "TMCRA Memory desktop installer and account console for Codex", "author": "TMCRA", @@ -27,7 +27,7 @@ "tmcra": { "pluginArchive": "tmcra-codex-latest.zip", "pluginReleaseManifest": "tmcra-codex-release.json", - "fallbackPluginVersion": "0.3.0-rc.10", + "fallbackPluginVersion": "1.0.0-rc.1", "authorizationBaseUrl": "https://euvbyqa1jpvdm7yq-2000.sc01-webservice.gpuhome.cc:8443", "consolePath": "/personal", "allowedAuthenticationOrigins": [ diff --git a/04-tmcra-desktop/src/renderer/index.html b/04-tmcra-desktop/src/renderer/index.html index 269b1e8..0c4104a 100644 --- a/04-tmcra-desktop/src/renderer/index.html +++ b/04-tmcra-desktop/src/renderer/index.html @@ -41,7 +41,7 @@

让 Codex 记住项目,
但不把项目混在 尚未连接 - WINDOWS x64 · v0.3.0-rc2 + WINDOWS x64 · v1.0.0-rc.1

准备连接 Codex

应用会检查 Codex、安装记忆插件,再在安全窗口内完成登录。

diff --git a/05-tmcra-mobile/android/app/build.gradle b/05-tmcra-mobile/android/app/build.gradle index b3fb0be..37345a5 100644 --- a/05-tmcra-mobile/android/app/build.gradle +++ b/05-tmcra-mobile/android/app/build.gradle @@ -52,7 +52,7 @@ def fetchSherpaAar = tasks.register('fetchSherpaAar') { URLConnection connection = new URL(assetUrl).openConnection() connection.connectTimeout = 30_000 connection.readTimeout = 300_000 - connection.setRequestProperty('User-Agent', 'TMCRA-Android-Build/0.3.0-rc2') + connection.setRequestProperty('User-Agent', 'TMCRA-Android-Build/1.0.0-rc.1') connection.inputStream.withCloseable { input -> temporary.withOutputStream { output -> input.transferTo(output) } } @@ -134,7 +134,7 @@ modelSpecs.each { spec -> URLConnection connection = new URL(assetUrl).openConnection() connection.connectTimeout = 30_000 connection.readTimeout = 300_000 - connection.setRequestProperty('User-Agent', 'TMCRA-Android-Build/0.3.0-rc2') + connection.setRequestProperty('User-Agent', 'TMCRA-Android-Build/1.0.0-rc.1') connection.inputStream.withCloseable { input -> temporary.withOutputStream { output -> input.transferTo(output) } } @@ -179,8 +179,8 @@ android { applicationId "com.tmcra.memory.mobile" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 4 - versionName "0.3.0-rc2" + versionCode 5 + versionName "1.0.0-rc.1" // The first hardware-validation build targets modern Android phones. // x86_64 is available only through -PtmcraTestAbi=x86_64 for the server emulator gate. // Release invocations keep the default arm64-v8a ABI. diff --git a/05-tmcra-mobile/android/app/src/main/java/com/tmcra/memory/mobile/net/TmcraApiClient.java b/05-tmcra-mobile/android/app/src/main/java/com/tmcra/memory/mobile/net/TmcraApiClient.java index 58b8360..06492a0 100644 --- a/05-tmcra-mobile/android/app/src/main/java/com/tmcra/memory/mobile/net/TmcraApiClient.java +++ b/05-tmcra-mobile/android/app/src/main/java/com/tmcra/memory/mobile/net/TmcraApiClient.java @@ -28,7 +28,7 @@ public final class TmcraApiClient { public static final String BASE_URL = "https://tmcra.com"; - public static final String CLIENT_VERSION = "0.3.0-rc2"; + public static final String CLIENT_VERSION = "1.0.0-rc.1"; private static final String CLIENT_HEADER = "com.tmcra.memory.mobile/" + CLIENT_VERSION; private static final int MAX_RESPONSE_BYTES = 4 * 1024 * 1024; private static final Pattern SESSION_COOKIE = Pattern.compile( diff --git a/05-tmcra-mobile/ios/App/App.xcodeproj/project.pbxproj b/05-tmcra-mobile/ios/App/App.xcodeproj/project.pbxproj index 08137f1..639ccc9 100644 --- a/05-tmcra-mobile/ios/App/App.xcodeproj/project.pbxproj +++ b/05-tmcra-mobile/ios/App/App.xcodeproj/project.pbxproj @@ -300,14 +300,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.3.0; + MARKETING_VERSION = 1.0.0; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.tmcra.memory.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -322,14 +322,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.3.0; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.tmcra.memory.mobile; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; diff --git a/05-tmcra-mobile/package-lock.json b/05-tmcra-mobile/package-lock.json index 1720be5..e794955 100644 --- a/05-tmcra-mobile/package-lock.json +++ b/05-tmcra-mobile/package-lock.json @@ -1,12 +1,12 @@ { "name": "tmcra-memory-mobile", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tmcra-memory-mobile", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "UNLICENSED", "dependencies": { "@capacitor/android": "8.5.0", diff --git a/05-tmcra-mobile/package.json b/05-tmcra-mobile/package.json index ee6e4fb..32e66d2 100644 --- a/05-tmcra-mobile/package.json +++ b/05-tmcra-mobile/package.json @@ -1,6 +1,6 @@ { "name": "tmcra-memory-mobile", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "private": true, "description": "TMCRA native Android audio-memory client with local speaker identity and text-only remote memory retrieval", "license": "UNLICENSED", diff --git a/06-tmcra-sdk-integrations/integrations/hermes/plugin.yaml b/06-tmcra-sdk-integrations/integrations/hermes/plugin.yaml index 1669c37..a19160f 100644 --- a/06-tmcra-sdk-integrations/integrations/hermes/plugin.yaml +++ b/06-tmcra-sdk-integrations/integrations/hermes/plugin.yaml @@ -1,5 +1,5 @@ name: tmcra-hermes -version: 0.3.0rc2 +version: 1.0.0rc1 description: "TMCRA recall and completed-turn ingestion for Hermes Agent" kind: exclusive requires_env: diff --git a/06-tmcra-sdk-integrations/integrations/hermes/pyproject.toml b/06-tmcra-sdk-integrations/integrations/hermes/pyproject.toml index 731d35c..c958b9a 100644 --- a/06-tmcra-sdk-integrations/integrations/hermes/pyproject.toml +++ b/06-tmcra-sdk-integrations/integrations/hermes/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tmcra-hermes-plugin" -version = "0.3.0rc2" +version = "1.0.0rc1" description = "Native Hermes Agent MemoryProvider for TMCRA" requires-python = ">=3.10" dependencies = [] diff --git a/06-tmcra-sdk-integrations/integrations/langgraph/pyproject.toml b/06-tmcra-sdk-integrations/integrations/langgraph/pyproject.toml index f946043..f8f002d 100644 --- a/06-tmcra-sdk-integrations/integrations/langgraph/pyproject.toml +++ b/06-tmcra-sdk-integrations/integrations/langgraph/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "tmcra-langgraph" -version = "0.3.0rc2" +version = "1.0.0rc1" description = "LangGraph long-term memory nodes for TMCRA" requires-python = ">=3.10" readme = "README.md" -dependencies = ["tmcra-client>=0.3.0rc2,<0.4", "langgraph>=1.2,<2"] +dependencies = ["tmcra-client>=1.0.0rc1,<2", "langgraph>=1.2,<2"] license = { text = "MIT" } [project.optional-dependencies] diff --git a/06-tmcra-sdk-integrations/integrations/microsoft-agent-framework/src/TMCRA.AgentFramework/TMCRA.AgentFramework.csproj b/06-tmcra-sdk-integrations/integrations/microsoft-agent-framework/src/TMCRA.AgentFramework/TMCRA.AgentFramework.csproj index e136bfb..63cf20b 100644 --- a/06-tmcra-sdk-integrations/integrations/microsoft-agent-framework/src/TMCRA.AgentFramework/TMCRA.AgentFramework.csproj +++ b/06-tmcra-sdk-integrations/integrations/microsoft-agent-framework/src/TMCRA.AgentFramework/TMCRA.AgentFramework.csproj @@ -5,7 +5,7 @@ enable true TMCRA.AgentFramework - 0.3.0-rc.2 + 1.0.0-rc.1 Microsoft Agent Framework AIContextProvider for TMCRA memory. MIT README.md diff --git a/06-tmcra-sdk-integrations/integrations/openai-agents/pyproject.toml b/06-tmcra-sdk-integrations/integrations/openai-agents/pyproject.toml index 0eec04c..a2e132b 100644 --- a/06-tmcra-sdk-integrations/integrations/openai-agents/pyproject.toml +++ b/06-tmcra-sdk-integrations/integrations/openai-agents/pyproject.toml @@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta" [project] name = "tmcra-openai-agents" -version = "0.3.0rc2" +version = "1.0.0rc1" description = "OpenAI Agents SDK lifecycle integration for TMCRA" requires-python = ">=3.10" readme = "README.md" -dependencies = ["tmcra-client>=0.3.0rc2,<0.4", "openai-agents>=0.18,<1"] +dependencies = ["tmcra-client>=1.0.0rc1,<2", "openai-agents>=0.18,<1"] license = { text = "MIT" } [project.optional-dependencies] diff --git a/06-tmcra-sdk-integrations/integrations/openclaw/package-lock.json b/06-tmcra-sdk-integrations/integrations/openclaw/package-lock.json index fda89ef..0f00067 100644 --- a/06-tmcra-sdk-integrations/integrations/openclaw/package-lock.json +++ b/06-tmcra-sdk-integrations/integrations/openclaw/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tmcra/openclaw-memory", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tmcra/openclaw-memory", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "MIT", "engines": { "node": ">=22.22.3" diff --git a/06-tmcra-sdk-integrations/integrations/openclaw/package.json b/06-tmcra-sdk-integrations/integrations/openclaw/package.json index dc2559c..6dd3dd4 100644 --- a/06-tmcra-sdk-integrations/integrations/openclaw/package.json +++ b/06-tmcra-sdk-integrations/integrations/openclaw/package.json @@ -1,6 +1,6 @@ { "name": "@tmcra/openclaw-memory", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "description": "Native OpenClaw lifecycle plugin for TMCRA memory recall and turn ingestion.", "type": "module", "license": "MIT", diff --git a/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package-lock.json b/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package-lock.json index d192240..1294bd5 100644 --- a/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package-lock.json +++ b/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tmcra/vercel-ai-sdk", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tmcra/vercel-ai-sdk", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "MIT", "devDependencies": { "@ai-sdk/provider": "4.0.3", @@ -16,12 +16,12 @@ }, "peerDependencies": { "@ai-sdk/provider": ">=4 <5", - "@tmcra/typescript": ">=0.3.0-rc.2 <0.4.0" + "@tmcra/typescript": ">=1.0.0-rc.1 <2.0.0" } }, "../../sdk/typescript": { "name": "@tmcra/typescript", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "dev": true, "license": "MIT", "devDependencies": { diff --git a/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package.json b/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package.json index ef41dd7..d4df0a5 100644 --- a/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package.json +++ b/06-tmcra-sdk-integrations/integrations/vercel-ai-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@tmcra/vercel-ai-sdk", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "description": "TMCRA LanguageModelV3 middleware for the Vercel AI SDK", "type": "module", "license": "MIT", @@ -19,7 +19,7 @@ }, "peerDependencies": { "@ai-sdk/provider": ">=4 <5", - "@tmcra/typescript": ">=0.3.0-rc.2 <0.4.0" + "@tmcra/typescript": ">=1.0.0-rc.1 <2.0.0" }, "devDependencies": { "@ai-sdk/provider": "4.0.3", diff --git a/06-tmcra-sdk-integrations/sdk/python/pyproject.toml b/06-tmcra-sdk-integrations/sdk/python/pyproject.toml index 35e0fcb..7f42d3a 100644 --- a/06-tmcra-sdk-integrations/sdk/python/pyproject.toml +++ b/06-tmcra-sdk-integrations/sdk/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tmcra-client" -version = "0.3.0rc2" +version = "1.0.0rc1" description = "Typed synchronous and asynchronous Python client for the TMCRA Memory API" readme = "README.md" requires-python = ">=3.10" diff --git a/06-tmcra-sdk-integrations/sdk/python/tmcra_client/__init__.py b/06-tmcra-sdk-integrations/sdk/python/tmcra_client/__init__.py index fd05539..2fb3ed8 100644 --- a/06-tmcra-sdk-integrations/sdk/python/tmcra_client/__init__.py +++ b/06-tmcra-sdk-integrations/sdk/python/tmcra_client/__init__.py @@ -173,4 +173,4 @@ "WebhookView", ] -__version__ = "0.3.0rc2" +__version__ = "1.0.0rc1" diff --git a/06-tmcra-sdk-integrations/sdk/typescript/package-lock.json b/06-tmcra-sdk-integrations/sdk/typescript/package-lock.json index 86913cb..fa51aab 100644 --- a/06-tmcra-sdk-integrations/sdk/typescript/package-lock.json +++ b/06-tmcra-sdk-integrations/sdk/typescript/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tmcra/typescript", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tmcra/typescript", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "license": "MIT", "devDependencies": { "typescript": "^5.7.2" diff --git a/06-tmcra-sdk-integrations/sdk/typescript/package.json b/06-tmcra-sdk-integrations/sdk/typescript/package.json index aefe9cd..50f8e10 100644 --- a/06-tmcra-sdk-integrations/sdk/typescript/package.json +++ b/06-tmcra-sdk-integrations/sdk/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@tmcra/typescript", - "version": "0.3.0-rc.2", + "version": "1.0.0-rc.1", "description": "Zero-runtime-dependency TypeScript client for the TMCRA Memory API", "type": "module", "license": "MIT", diff --git a/06-tmcra-sdk-integrations/sdk/typescript/src/models.ts b/06-tmcra-sdk-integrations/sdk/typescript/src/models.ts index d667d6b..6f1eace 100644 --- a/06-tmcra-sdk-integrations/sdk/typescript/src/models.ts +++ b/06-tmcra-sdk-integrations/sdk/typescript/src/models.ts @@ -92,6 +92,8 @@ export interface RetentionPolicy { export type FeedbackRating = "helpful" | "incorrect" | "stale" | "unsafe" | "missing"; export interface FeedbackRequest { + action?: "note" | "ignore" | "correct" | "restore"; + replacement?: string; query_id?: string; rating: FeedbackRating; memory_ids?: readonly string[]; @@ -100,6 +102,10 @@ export interface FeedbackRequest { } export interface FeedbackResponse { + action?: "note" | "ignore" | "correct" | "restore"; + effective?: boolean; + correction_job_id?: string | null; + correction_index_status?: string | null; feedback_id: string; scope_name: string; rating: FeedbackRating | string; diff --git a/07-tmcra-codex-plugins/tmcra-memory/.claude-plugin/plugin.json b/07-tmcra-codex-plugins/tmcra-memory/.claude-plugin/plugin.json index 1fef203..4704048 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/.claude-plugin/plugin.json +++ b/07-tmcra-codex-plugins/tmcra-memory/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "tmcra-memory", "displayName": "TMCRA Memory", - "version": "0.3.0-rc.10+claude.20260904", + "version": "1.0.0-rc.1+claude.20260906", "description": "Auditable long-term memory recall and turn capture for Claude Code.", "author": { "name": "TMCRA", diff --git a/07-tmcra-codex-plugins/tmcra-memory/.codex-plugin/plugin.json b/07-tmcra-codex-plugins/tmcra-memory/.codex-plugin/plugin.json index 44bb695..4cf5bbc 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/.codex-plugin/plugin.json +++ b/07-tmcra-codex-plugins/tmcra-memory/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "tmcra-memory", - "version": "0.3.0-rc.10", + "version": "1.0.0-rc.1", "description": "Automatic long-term memory recall and capture for Codex.", "author": { "name": "TMCRA", @@ -29,10 +29,7 @@ ], "defaultPrompt": [ "Show the TMCRA memories that were injected for my latest completed answer.", - "Show which TMCRA memories are relevant to this task.", - "Remember this decision for future coding sessions.", - "Check whether the latest TMCRA memory write completed.", - "Show TMCRA installation and lifecycle status.", + "Open the memory control panel for this session.", "Open TMCRA local Writer and background-organizer settings." ], "brandColor": "#49E5C2", diff --git a/07-tmcra-codex-plugins/tmcra-memory/.codexignore b/07-tmcra-codex-plugins/tmcra-memory/.codexignore new file mode 100644 index 0000000..6f0ea24 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/.codexignore @@ -0,0 +1,15 @@ +.git +.git/ +.github/ +node_modules/ +tests/ +packaging/ +release/ +*.log +*.tmp +*.key +*.pem +.env +.env.* +.tmcra/ +scanner-report.* diff --git a/07-tmcra-codex-plugins/tmcra-memory/.gitattributes b/07-tmcra-codex-plugins/tmcra-memory/.gitattributes new file mode 100644 index 0000000..e1dd794 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf +*.png binary +*.pt binary +runtime/** linguist-vendored -whitespace diff --git a/07-tmcra-codex-plugins/tmcra-memory/.gitignore b/07-tmcra-codex-plugins/tmcra-memory/.gitignore index 3f93eb0..8bc79ff 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/.gitignore +++ b/07-tmcra-codex-plugins/tmcra-memory/.gitignore @@ -1 +1,15 @@ -.smoke-data/ +node_modules/ +.DS_Store +Thumbs.db +*.log +*.tmp +*.key +*.pem +.env +.env.* +.tmcra/ +scanner-report.* +release/ +test-artifacts/ +__pycache__/ +*.py[cod] diff --git a/07-tmcra-codex-plugins/tmcra-memory/.plugin-scanner.toml b/07-tmcra-codex-plugins/tmcra-memory/.plugin-scanner.toml new file mode 100644 index 0000000..3cac978 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/.plugin-scanner.toml @@ -0,0 +1,4 @@ +[scanner] +# Mock tests intentionally contain token-shaped sentinel values to verify +# redaction. They are development fixtures and are excluded from releases. +ignore_paths = ["tests/*"] diff --git a/07-tmcra-codex-plugins/tmcra-memory/CHANGELOG.md b/07-tmcra-codex-plugins/tmcra-memory/CHANGELOG.md new file mode 100644 index 0000000..b3b5770 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/CHANGELOG.md @@ -0,0 +1,53 @@ +# Changelog + +## 1.0.0-rc.1 - 2026-09-06 + +- Add the redesigned memory workspace, local Writer/organizer settings, knowledge and graph views, session controls, task continuity, and bounded recall budgets. +- Require interactive host confirmation for conversational memory corrections; protect the correction discussion from automatic capture and replay. +- Add three pinned embedding/reranker profiles and Windows local-runtime preview controls. Local identity disables inherited cloud-provider task handoff. +- Preserve binary image bytes in release ZIPs and verify packaged assets against their sources. +- Bundle the verified backend, automatic private Python bootstrap and shared local identity discovery. `Install-Local.cmd` installs without TMCRA servers/accounts. Runtime files survive plugin-cache updates; stale cloud connections are blocked after local selection. +- Full-local acceptance remains partial: CPU ingest/raw recall passed; complex compilation timed out, with organizer and restart recovery still pending. Production is unchanged. + +## 0.3.0-rc.10 - 2026-09-04 + +- Include the icon and overview image referenced by the Codex marketplace manifest in every release archive. + +## 0.3.0-rc.9 - 2026-09-04 + +- Add complete Codex marketplace presentation metadata so the current plugin bundle can be mirrored and refreshed by community marketplaces. + +## 0.3.0-rc.8 - 2026-09-04 + +- Execute configured Writer and background-organizer calls from the authenticated local Codex process. +- Add a durable, credential-bound task lease protocol with heartbeat and idempotent terminal receipts. +- Return only parsed JSON, normalized usage, and provider request identity to TMCRA; keep API keys and raw provider envelopes local. +- Add explicit `tmcra_consolidate` routing, bounded response handling, fair stage scheduling, and quiet exponential recovery. + +## 0.3.0-rc.7 - 2026-09-04 + +- Add a loopback-only local settings UI for separate Writer and background-organizer model providers. +- Keep provider credentials in the local user configuration and redact them from every MCP response. +- Prevent a saved credential from being reused after its provider or Base URL changes. + +## 0.3.0-rc.6 - 2026-09-04 + +- Canonicalize ZIP creator and file-mode metadata so Windows and Linux now produce the same archive and SHA-256 digest. + +## 0.3.0-rc.5 - 2026-09-04 + +- Normalize every release entry to UTF-8 with LF line endings. +- Remove a race in the Claude Code ingestion contract on slower CI runners. +- Scope plugin security scanning to shipped code while retaining high-severity enforcement. + +## 0.3.0-rc.4 - 2026-09-04 + +- Replace the obsolete owner-local four-Hook bridge with the current nine-Hook TMCRA lifecycle implementation. +- Add browser device authorization, protected credential storage, explicit recall inspection, durable asynchronous capture, long-task checkpoints, history migration, and repository bootstrap. +- Bundle the MCP server and the complete `manage-tmcra-memory` skill in the self-contained release ZIP. +- Add deterministic Codex, Claude Code, device-authorization, security, and cross-platform release contracts. +- Align the Claude Code manifest with the Apache-2.0 repository license and verify sensitive `userConfig` injection. + +## 0.1.1 - 2026-08-16 + +- Initial owner-local Codex plugin preview. diff --git a/07-tmcra-codex-plugins/tmcra-memory/LICENSE b/07-tmcra-codex-plugins/tmcra-memory/LICENSE new file mode 100644 index 0000000..effcced --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Yu Haoxin and TMCRA contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/07-tmcra-codex-plugins/tmcra-memory/NOTICE b/07-tmcra-codex-plugins/tmcra-memory/NOTICE new file mode 100644 index 0000000..ab5b899 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/NOTICE @@ -0,0 +1,7 @@ +TMCRA Memory for Codex and Claude Code +Copyright 2026 Yu Haoxin and TMCRA contributors + +Development and release-validation assistance was provided by OpenAI Codex. + +This repository contains the Codex and Claude Code integration layer for +TMCRA: https://github.com/reshuibuduo/tmcra diff --git a/07-tmcra-codex-plugins/tmcra-memory/README.md b/07-tmcra-codex-plugins/tmcra-memory/README.md index e33d03e..78ebee4 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/README.md +++ b/07-tmcra-codex-plugins/tmcra-memory/README.md @@ -1,13 +1,15 @@ # TMCRA Memory for Codex -TMCRA Memory adds automatic long-term memory to Codex through the public TMCRA API. It does not require access to the TMCRA server. +TMCRA Memory adds automatic long-term memory to Codex through a local Memory API or the hosted TMCRA service. Windows local installation runs independently of TMCRA servers and accounts. This repository is the standalone distribution mirror of the plugin maintained in the [TMCRA monorepo](https://github.com/reshuibuduo/tmcra/tree/main/07-tmcra-codex-plugins/tmcra-memory). Download the versioned ZIP and its SHA-256 file from [GitHub Releases](https://github.com/reshuibuduo/tmcra-plugin-codex/releases). ## What it does +Version 1.0.0-rc.1 adds session controls, task handoff, bounded evidence selection and a loopback memory control panel. See [the control contract and rollout checklist](docs/memory-controls.md). `tmcra_open_memory_center(session_id, project_path)` opens the panel; `tmcra_memory_control` exposes the same actions to explicit tools. Effective source corrections require the matching backend update, included in the local runtime. + - Initializes the global/project scope at `SessionStart` without recalling or injecting memory. -- Recalls relevant global and project memory only after `UserPromptSubmit`, using the current prompt as the query. +- Recalls relevant global and project memory after `UserPromptSubmit`; short continuations use the bound task objective and observed progress. - Includes both user records (requirements and facts) and assistant records (Codex work progress and results) in recall, while keeping their actor and provenance labels separate. - Applies authority in this order: current user instruction, historical user requirements/facts, then historical Codex progress/results. Assistant records never become user statements. - Captures the completed user/assistant turn at `Stop`. @@ -25,6 +27,12 @@ Codex Hooks do not expose a third-party custom side panel. The explicit inspecti ## Windows installation +For server-independent installation, extract the release ZIP and double-click **`Install-Local.cmd`**. It registers the plugin, installs a private Python runtime, downloads verified model files, creates a local identity, and starts the local memory service. No TMCRA account, API key or preinstalled Python is required. First-time dependency/model downloads require internet access. Restart Codex and review its nine Hooks when prompted; host consent remains yours. Windows x64 is supported; the light profile needs 16 GB RAM and approximately 6.3 GiB free at startup. + +For the hosted service, use the account-based installer below. + +Marketplace users can ask “Open TMCRA local installation”; `tmcra_open_local_install` opens the same workspace without login. Downloads begin after the user chooses and confirms a profile in the page. + Download the versioned release ZIP, verify the adjacent SHA-256 file, extract it to a stable local directory, then run: ```powershell @@ -90,6 +98,14 @@ This is a repository snapshot, not reconstructed conversation history. ## Configuration +### Full-local Windows preview + +The workspace offers three pinned embedding/reranker profiles: E5-small + multilingual MiniLM, BGE-M3 + BGE-reranker-v2-m3, and Qwen3-Embedding-4B + Qwen3-Reranker-0.6B. + +The release and marketplace packages include the actual backend with a SHA-256 inventory. Use `Install-Local.cmd`, or run `node scripts/local_setup.mjs` from the plugin directory to open the installation page without login. Python and model files are downloaded automatically. The installer registers a private local selection; Codex, DSH and generic TMCRA MCP discover it after restarting their host. Existing cloud credentials remain stored, while stale cloud memory connections and background model requests are blocked after local selection. Failed setup keeps this local selection. Advanced `TMCRA_CONFIG_FILE` overrides must be cleared before automatic installation. A standalone [runtime package](https://github.com/reshuibuduo/tmcra/releases/tag/v1.0.0-rc.1) serves other MCP hosts. + +Acceptance is partial: synthetic CPU ingest took 112 seconds and raw recall 0.52 seconds; complex compilation timed out at 600 seconds. Organizer and full-service restart recovery remain unverified. Lightweight startup requires approximately 6.3 GiB free memory. See the [acceptance record](https://github.com/reshuibuduo/tmcra/blob/v1.0.0-rc.1/docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md). A cloud-hosted agent can still send recalled evidence to its own model provider. + ### Local Writer and background organizer Ask Codex **“Open TMCRA local model settings”** to open the setup page. The MCP response contains no credential value or setup-session token. The page is served from a temporary random-token session bound to `127.0.0.1`, and it supports separate Writer and background-organizer providers or one shared provider. diff --git a/07-tmcra-codex-plugins/tmcra-memory/README.zh-CN.md b/07-tmcra-codex-plugins/tmcra-memory/README.zh-CN.md new file mode 100644 index 0000000..d4de4f9 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/README.zh-CN.md @@ -0,0 +1,95 @@ +# TMCRA Memory for Codex + +TMCRA Memory 通过本机 Memory API 或 TMCRA 托管服务为 Codex 提供自动长期记忆。Windows 本地安装独立于 TMCRA 服务器和账号。此仓库是 [TMCRA 主仓库](https://github.com/reshuibuduo/tmcra/tree/main/07-tmcra-codex-plugins/tmcra-memory)中插件源码的独立发行镜像。 + +[English](README.md) + +## 1.0.0-rc.1 新增记忆控制 + +- 任务接续:短句“继续”使用当前绑定目标、最近结果和下一步;多个候选任务会要求明确选择。 +- 可操作控制台:调用 `tmcra_open_memory_center`,传当前 `session_id` 和 `project_path`,可以查看任务、来源、写入状态,执行纠错、忽略与恢复。 +- 统一工作台:集成记忆写入 / 后台整理 API 配置、知识库和知识图谱,支持来源追溯与范围筛选;密钥只在本机表单输入,保存后不回显。 +- 聊天纠错:识别真实纠错意图后先暂停当前回合自动写入,核对来源与新内容,再请求宿主聊天确认。拒绝、取消、过期和缺少确认能力均不提交。 +- 会话开关:`normal` 正常读写、`recall_only` 仅召回、`off` 关闭;恢复后不会补写关闭期间的回合。已经提交的远端写入不受此开关撤回。 +- 召回预算:默认每轮 12000 字符,按完整证据块裁选;只对本轮重复和仍在宿主上下文中的相同证据去重。Token 用量为估计值。 +- 有效纠错:需要同步部署服务端反馈接口更新。旧来源的召回会立即受控,新内容独立可搜索需要等待返回的索引任务完成。 + +任务与会话控制状态按服务地址、凭据指纹和项目隔离。切换登录凭据会创建独立的本机任务状态;跨应用已提交的长期记忆继续通过同一服务端项目 scope 共享。`TMCRA_MEMORY_STATE_DIR` 可显式指定多个本机适配器共用的状态目录。API Key 不会写入这个状态目录。 + +新增功能和部署验收说明见 [memory-controls.md](docs/memory-controls.md)。 + +## 核心能力 + +- `SessionStart` 初始化全局、项目和会话边界。 +- `UserPromptSubmit` 根据当前问题召回相关证据,并保留用户与 Agent 的来源区别。 +- `PostToolUse` 只在达到阈值时形成经过脱敏的长任务检查点。 +- `PreCompact`、`PostCompact` 保存并恢复上下文压缩前后的任务状态。 +- `Stop` 写入真实完成的用户/assistant 回合;`StopFailure` 只保存用户请求检查点。 +- `SubagentStart`、`SubagentStop` 隔离并记录子 Agent 生命周期。 +- 内置 MCP 工具可查看上一轮实际使用的召回、主动召回、写入记忆和检查异步任务。 + +全部九项 Hook 都需要用户在 Codex 中明确审核和信任。 + +## 安装 + +**脱离 TMCRA 服务器:**下载 Release ZIP 并解压,双击 `Install-Local.cmd`。安装器自动注册插件、准备独立 Python、下载并校验模型、生成本机身份并启动记忆服务,无需 TMCRA 账号、API Key 或预装 Python。首次下载需要联网。完成后重启 Codex,并由你审核九项 Hook。当前支持 Windows x64;轻量档建议 16GB 内存,启动时约需 6.3GiB 空闲内存。 + +托管服务账号模式使用下面的安装方式。 + +从插件市场安装的用户,可直接说“打开 TMCRA 本地安装”,调用 `tmcra_open_local_install` 免账号打开同一工作台。选好档位并在页面确认后才开始下载安装。 + +从 [GitHub Releases](https://github.com/reshuibuduo/tmcra-plugin-codex/releases) 下载带版本号的 ZIP 和对应 SHA-256 文件。校验后解压到稳定目录。 + +Windows: + +```powershell +.\Install-TMCRA.ps1 +``` + +macOS / Linux: + +```sh +sh ./install.sh +``` + +安装器会注册并启用插件,然后打开 TMCRA 设备授权页面。登录账号、确认短码并重启 Codex;随后运行 `/hooks`,审核九项 TMCRA Hook。访问 Token、设备码、PKCE 校验值和交付回执不会打印到终端。 + +## 记忆边界 + +- 稳定用户事实进入全局层,每个项目使用独立 scope,每个 Codex 任务作为项目内 session。 +- 当前用户指令的优先级高于历史用户事实,历史 Agent 进度保持 assistant 来源。 +- 自动 Hook 短超时并 fail-open;显式 MCP 操作使用独立的较长超时。 +- 凭据、私钥、验证码、开发者指令和 chain-of-thought 不会进入记忆。 +- 旧 Codex 历史与仓库基线只能先本地预览,再由用户明确确认导入。 + +## 本地 Writer 与后台整理模型 + +### 完整本地部署预览 + +工作台新增三档 embedding / reranker:E5-small + 多语言 MiniLM、BGE-M3 + BGE-reranker-v2-m3、Qwen3-Embedding-4B + Qwen3-Reranker-0.6B,以及安装、推荐、状态和启动/停止入口。 + +Release 和市场插件包均内置真实后端及 SHA-256 清单。使用 `Install-Local.cmd`,或在插件目录运行 `node scripts/local_setup.mjs`,即可免登录打开安装页。Python 与模型自动下载,身份自动生成并登记;重启宿主后 Codex、DSH 和通用 TMCRA MCP 自动发现本地连接。选择本地后,旧云端连接和后台云模型请求会被拦截;安装失败保留本地选择。原云端凭据保留在原位置。高级用户先清除显式 `TMCRA_CONFIG_FILE` 覆盖再进行自动安装。其他 MCP 宿主可使用[独立运行包](https://github.com/reshuibuduo/tmcra/releases/tag/v1.0.0-rc.1)。 + +完整验收仍在进行:CPU 合成写入 112 秒、原文召回 0.52 秒;复杂编译 600 秒超时,后台整理和完整重启恢复待测。轻量启动需约 6.3GiB 空闲内存。详见[验收记录](https://github.com/reshuibuduo/tmcra/blob/v1.0.0-rc.1/docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md)。宿主 Agent 使用云端主模型时,召回证据仍可能由宿主发往云端。 + +### 配置独立模型 API + +在 Codex 中输入“打开 TMCRA 本地模型设置”即可打开配置页。MCP 返回结果不含 API Key 和页面会话令牌。配置页只监听 `127.0.0.1`,每次启动生成随机令牌;Writer 与后台整理可以共用模型,也可以分别填写 Provider、Base URL、模型名称和 API Key。 + +Codex 与 DeepSeek Harness 共用 `~/.config/tmcra/local-providers.json`。API Key 只保存在当前系统用户的本地文件中,测试连接时只发往用户填写的模型服务。Provider 或 Base URL 改变后必须重新填写 Key,已保存的 Key 不会转发到新地址。macOS/Linux 使用 `0600` 权限;Windows 移除继承 ACL,只授权当前用户与 SYSTEM。同一系统用户运行的其他进程仍可能读取该文件,因此这项功能适合可信的本地账号。 + +保存后的配置会在 Codex MCP 进程运行期间生效。写入请求会把 Writer 工作(包括强制慢阶段)路由到已认证的本机执行器;`tmcra_consolidate` 会用同一路径处理显式后台整理任务。执行器只领取由当前设备凭据创建的任务,调用用户配置的 OpenAI 兼容端点,并回传解析后的 JSON、标准化 Token 用量和服务商请求 ID。API Key 与服务商原始响应包保留在当前用户的本机进程中。 + +## 开发验证 + +```sh +npm ci +npm run verify +npm run build:release +``` + +确定性测试使用隔离的 mock 服务,不读取日常 Codex 历史,也不访问公开 TMCRA API。测试覆盖 Codex/Claude Code 生命周期、设备授权、项目隔离、可靠写入、敏感信息脱敏、MCP 工具和跨平台发布包。 + +## 许可 + +Apache-2.0。详见 [LICENSE](LICENSE) 与 [NOTICE](NOTICE)。 diff --git a/07-tmcra-codex-plugins/tmcra-memory/SECURITY.md b/07-tmcra-codex-plugins/tmcra-memory/SECURITY.md new file mode 100644 index 0000000..c482a9e --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/SECURITY.md @@ -0,0 +1,22 @@ +# Security policy + +## Supported version + +Security fixes are applied to the latest release on the default branch. + +## Reporting a vulnerability + +Use this repository's private vulnerability-reporting form. Do not place credentials, private memory, account identifiers, working exploits, or another user's local paths in a public issue. + +Revoke any exposed TMCRA credential immediately. Include only the affected plugin, Codex or Claude Code version, operating system, reproduction steps, and the smallest redacted diagnostic sample. + +## Security boundary + +- Production API origins require HTTPS; explicit localhost endpoints are accepted for development and tests. +- Normal installation uses browser device authorization and writes the scoped credential to a protected local configuration file. +- Credentials, device codes, PKCE verifiers, delivery receipts, private keys, verification codes, developer instructions, and chain-of-thought are excluded from memory and logs. +- Recalled material is marked as untrusted evidence. Current user instructions retain higher authority. +- Automatic lifecycle hooks use short timeouts and fail open so a memory-service outage cannot block the host Agent. +- User, assistant, tool, session, project, and Agent provenance remain distinct. + +The hosted TMCRA service, account console, deployment infrastructure, and other integrations have their own security boundaries. diff --git a/07-tmcra-codex-plugins/tmcra-memory/assets/tmcra-logo.png b/07-tmcra-codex-plugins/tmcra-memory/assets/tmcra-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..253945491e972f7d6030f08d7fae13b0055ccffe GIT binary patch literal 1036093 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 z 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%0Af%4H@+`6(wiQKrna4(p- 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 1) blocks.unshift(`Multiple active tasks; ask which task to continue:\n${JSON.stringify(continuation.candidates)}`); const successfulLayers = [globalMemory, projectMemory] .filter((layer) => layer.status === "success"); const failedLayers = [globalMemory, projectMemory] @@ -430,8 +440,7 @@ export async function recallForContext(input, query) { : failedLayers.length === 0 ? "completed" : "degraded"; - const sessionId = await resolveLifecycleSessionId(input); - await saveRecallReceipt({ + if (await mayWrite(policy)) await saveRecallReceipt({ projectId: scopes.projectId, sessionId, turnId: pairingTurnId(input), @@ -443,6 +452,7 @@ export async function recallForContext(input, query) { requestId: globalMemory.requestId, count: globalMemory.windowCount, content: globalMemory.content, + sources: globalMemory.sources, }, project: { status: projectMemory.status, @@ -450,8 +460,11 @@ export async function recallForContext(input, query) { requestId: projectMemory.requestId, count: projectMemory.windowCount, content: projectMemory.content, + sources: projectMemory.sources, }, }); + await recordMemoryActivity(policy, { kind: "recall", query: safeQuery, selection, + layers: [globalMemory, projectMemory] }); await appendLog(`recall_${status}`, { host, lifecycleContractVersion: LIFECYCLE_CONTRACT_VERSION, @@ -479,14 +492,26 @@ export async function recallForContext(input, query) { }; } +function visibleMemoryContext(messages) { + if (!Array.isArray(messages)) return ""; + return messages.filter((row) => ["user", "assistant", "system"].includes(row.role)) + .map((row) => typeof row.content === "string" ? row.content + : Array.isArray(row.content) ? row.content.map((part) => part.text || "").join("\n") : "") + .join("\n"); +} + export async function rememberPrompt(input) { const prompt = bounded(input.prompt); if (!prompt) return null; - const { scopes, host } = await resolveHookContext(input); + const { config, scopes, host } = await resolveHookContext(input); const sessionId = await resolveLifecycleSessionId(input); + let capture = await memoryPolicy(controlKey(config, scopes.projectScope), sessionId); + if (!capture.write) return null; + const continuation = await taskContext(capture.key, sessionId, prompt, { capture }); let value; await withTaskStateLock(sessionId, async () => { const turnId = await allocatePendingTurnId(sessionId, pairingTurnId(input), input); + capture = await beginMemoryTurn(capture.key, sessionId, turnId); value = { host, sessionId, @@ -497,6 +522,7 @@ export async function rememberPrompt(input) { promptAt: new Date().toISOString(), cwd: String(input.cwd || ""), scopes, + capture, }; await savePendingTurn(value); await registerPendingTurn(value); @@ -518,7 +544,8 @@ export async function rememberPrompt(input) { } : { host, activeTurnId: value.turnId, - objective: prompt, + objective: continuation.task?.objective || prompt, + capture, objectiveAt: value.promptAt, cwd: value.cwd, scopes, @@ -591,6 +618,7 @@ function taskHandoff(objective, progress, checkpoint) { } async function queueTaskCheckpoint(sessionId, state, checkpoint) { + if (state.capture && !await mayWrite(state.capture)) return null; const host = state.host || "codex"; const normalizedSessionId = stableSessionId(host, sessionId); const isFinalCheckpoint = checkpoint.reason.startsWith("pre_compact_") || @@ -640,6 +668,7 @@ async function queueTaskCheckpoint(sessionId, state, checkpoint) { pluginVersion: PLUGIN_VERSION, lifecycleContractVersion: LIFECYCLE_CONTRACT_VERSION, projectId: state.scopes.projectId, + capture: state.capture, scope, sessionId: normalizedSessionId, messages, @@ -663,6 +692,7 @@ export async function checkpointTaskContinuity( return withTaskStateLock(sessionId, async () => { const state = await loadTaskState(sessionId); if (!state) return null; + if (state.capture && !await mayWrite(state.capture)) return null; const events = await listTaskEvents(sessionId); const previous = await loadTaskCheckpoint(sessionId); if (!force && !shouldCheckpointTask(state, events)) return null; @@ -713,6 +743,7 @@ export async function recordToolUse(input) { const sessionId = await resolveLifecycleSessionId(input); const state = await loadTaskState(sessionId); if (!state) return null; + if (state.capture && !await mayWrite(state.capture)) return null; const toolName = bounded(input.tool_name || input.tool || "tool", 200); if (/tmcra(?:-|_)?memory|^tmcra_/iu.test(toolName)) return null; const event = await appendTaskEvent(sessionId, { @@ -750,6 +781,8 @@ export async function resumeTaskContinuity(input) { const sessionId = await resolveLifecycleSessionId(input); let state = await loadTaskState(sessionId); if (!state) return ""; + const { config, scopes } = await resolveHookContext(input); + if (!(await memoryPolicy(controlKey(config, scopes.projectScope), sessionId)).read) return ""; let checkpoint = await loadTaskCheckpoint(sessionId); const pendingEvents = await listTaskEvents(sessionId); if (pendingEvents.length || !checkpoint) { @@ -826,6 +859,11 @@ export async function ingestCompletedTurn(input) { return null; } const pending = await loadPendingTurn(sessionId, turnId); + if (pending?.capture && !await mayWrite(pending.capture)) { + await removePendingTurn(sessionId, turnId); + await removePendingIndexEntry(sessionId, turnId); + return { skipped: true, reason: "memory_mode_changed" }; + } const assistant = bounded(input.last_assistant_message); if (!pending || !assistant) { await appendLog("ingest_skipped", { @@ -889,6 +927,7 @@ export async function ingestCompletedTurn(input) { pluginVersion: PLUGIN_VERSION, projectId: pending.scopes.projectId, scope, + capture: pending.capture, sessionId: normalizedSessionId, messages, metadata, @@ -916,6 +955,10 @@ export async function ingestCompletedTurn(input) { } await removePendingTurn(sessionId, turnId); await removePendingIndexEntry(sessionId, turnId); + if (pending.capture) { + await finishObservedTurn(pending.capture, pending.prompt, assistant); + await recordMemoryActivity(pending.capture, { kind: "write", state: "queued", outboxId: queued.outboxId }); + } await appendLog("ingest_queued", { host, pluginVersion: PLUGIN_VERSION, diff --git a/07-tmcra-codex-plugins/tmcra-memory/package-lock.json b/07-tmcra-codex-plugins/tmcra-memory/package-lock.json new file mode 100644 index 0000000..0e93c2f --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/package-lock.json @@ -0,0 +1,16 @@ +{ + "name": "tmcra-memory-codex-plugin", + "version": "1.0.0-rc.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tmcra-memory-codex-plugin", + "version": "1.0.0-rc.1", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + } + } +} diff --git a/07-tmcra-codex-plugins/tmcra-memory/package.json b/07-tmcra-codex-plugins/tmcra-memory/package.json new file mode 100644 index 0000000..b395e0c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/package.json @@ -0,0 +1,23 @@ +{ + "name": "tmcra-memory-codex-plugin", + "version": "1.0.0-rc.1", + "private": true, + "description": "Automatic TMCRA long-term memory for Codex and Claude Code", + "type": "module", + "engines": { + "node": ">=18.0.0" + }, + "scripts": { + "test": "node scripts/test_codex_e2e.mjs", + "test:claude": "node tests/claude_code_contract.mjs", + "test:provider-setup": "node tests/provider_setup_contract.mjs", + "build:release": "pwsh -NoProfile -File scripts/build_release.ps1", + "verify": "node --check hooks/run_hook.mjs && node --check hooks/claude_run_hook.mjs && node --check scripts/tmcra_client.mjs && node --check scripts/provider_config.mjs && node --check scripts/provider_setup.mjs && node --check scripts/provider_executor.mjs && npm run test:provider-setup && npm test" + }, + "repository": { + "type": "git", + "url": "https://github.com/reshuibuduo/tmcra-plugin-codex.git" + }, + "author": "TMCRA", + "license": "Apache-2.0" +} diff --git a/07-tmcra-codex-plugins/tmcra-memory/packaging/INSTALL-TMCRA-CODEX.md b/07-tmcra-codex-plugins/tmcra-memory/packaging/INSTALL-TMCRA-CODEX.md index e636cff..ae52443 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/packaging/INSTALL-TMCRA-CODEX.md +++ b/07-tmcra-codex-plugins/tmcra-memory/packaging/INSTALL-TMCRA-CODEX.md @@ -1,5 +1,13 @@ # TMCRA Memory for Codex +## 独立本地安装 / Server-independent installation + +Windows x64:解压后双击 `Install-Local.cmd`。自动安装 Python、依赖、校验后的模型和本机 Memory API,自动生成私有本地身份。无需 TMCRA 账号、服务器或预装 Python;首次下载需联网。完成后重启 Codex,并由用户审核九项 Hook。轻量档建议 16GB 内存且启动时约 6.3GiB 空闲。完整模型验收仍有限制,详见插件 README 的本地部署章节。 + +On Windows x64, double-click `Install-Local.cmd` after extracting the entire archive. Setup automatically prepares private Python, verified models and the Memory API, with local identity discovery. No TMCRA server, account or preinstalled Python is required. Internet is needed for first-time downloads. Restart Codex and personally review all nine Hooks. See the bundled README for resource requirements and partial model acceptance results. + +## 托管服务 / Hosted service + 保留解压后的 `.agents`、`plugins` 和根目录安装脚本,然后在解压目录中运行: ```powershell diff --git a/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-Local.cmd b/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-Local.cmd new file mode 100644 index 0000000..6963f88 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-Local.cmd @@ -0,0 +1,3 @@ +@echo off +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0Install-TMCRA.ps1" -LocalMemory +if errorlevel 1 pause diff --git a/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-TMCRA.ps1 b/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-TMCRA.ps1 index 5dd2999..d298f42 100644 --- a/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-TMCRA.ps1 +++ b/07-tmcra-codex-plugins/tmcra-memory/packaging/Install-TMCRA.ps1 @@ -9,7 +9,9 @@ param( [switch]$SkipPluginInstall, [switch]$NoBrowser, [switch]$ProgressJson, - [switch]$ApiOnlyCheck + [switch]$ApiOnlyCheck, + [switch]$LocalMemory, + [ValidateSet('lite-cpu','balanced-bge','quality-qwen')][string]$LocalProfile = 'lite-cpu' ) $ErrorActionPreference = "Stop" diff --git a/07-tmcra-codex-plugins/tmcra-memory/resources/local-model-profiles.json b/07-tmcra-codex-plugins/tmcra-memory/resources/local-model-profiles.json new file mode 100644 index 0000000..460605c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/resources/local-model-profiles.json @@ -0,0 +1,132 @@ +{ + "schema_version": "tmcra.local-model-profiles.1", + "verified_upstream_on": "2026-09-06", + "status": "windows_local_preview_partial_validation", + "installation_enabled": true, + "scope": "full_local_runtime_preview", + "full_memory_system_ready": false, + "hardware_requirements_are": "conservative_planning_estimates_not_benchmark_results", + "profiles": [ + { + "id": "lite-cpu", + "name_zh": "轻量版", + "recommendation_zh": "普通笔记本、无独显电脑;中英文短记忆,低并发", + "validation": "cpu_ingest_and_raw_recall_passed_complex_compile_timed_out", + "system_ram_gib_min": 8, + "system_ram_gib_recommended_for_full_memory": 16, + "retrieval_vram_gib_recommended": 0, + "weights_bytes": 941234298, + "embedding": { + "repo_id": "intfloat/multilingual-e5-small", + "revision": "614241f622f53c4eeff9890bdc4f31cfecc418b3", + "license": "MIT", + "upstream": "https://huggingface.co/intfloat/multilingual-e5-small", + "weights": [{"file": "model.safetensors", "bytes": 470641600, "sha256": "1a55775f53449dac10a2bcbc312469fac40b96d53198c407081a831f81c98477"}], + "dimensions": 384, + "model_max_tokens": 512, + "pooling": "mean", + "normalize": true, + "query_prefix": "query: ", + "document_prefix": "passage: ", + "padding_side": "right" + }, + "reranker": { + "repo_id": "cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "revision": "1427fd652930e4ba29e8149678df786c240d8825", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "weights": [{"file": "model.safetensors", "bytes": 470592698, "sha256": "5daeca2481a76b5976a2bdc32f0a78532b6716da4f8cd3ff59460ef8d2f359b4"}], + "adapter": "sequence-classification", + "model_max_tokens": 512, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["memory_pressure_retest", "complex_compile_latency", "organizer_validation", "full_service_restart_validation"] + }, + { + "id": "balanced-bge", + "name_zh": "均衡版", + "recommendation_zh": "优先复现现有生产检索模型;16GB 以上内存,建议有独显", + "validation": "production_model_stack_verified_consumer_installer_pending", + "system_ram_gib_min": 16, + "system_ram_gib_recommended_for_full_memory": 32, + "retrieval_vram_gib_recommended": 6, + "weights_bytes": 4542217682, + "embedding": { + "repo_id": "BAAI/bge-m3", + "revision": "5617a9f61b028005a4858fdac845db406aefb181", + "license": "MIT", + "upstream": "https://huggingface.co/BAAI/bge-m3", + "weights": [{"file": "pytorch_model.bin", "bytes": 2271145830, "sha256": "b5e0ce3470abf5ef3831aa1bd5553b486803e83251590ab7ff35a117cf6aad38"}], + "dimensions": 1024, + "model_max_tokens": 8192, + "pooling": "cls", + "normalize": true, + "query_prefix": "", + "document_prefix": "", + "padding_side": "right" + }, + "reranker": { + "repo_id": "BAAI/bge-reranker-v2-m3", + "revision": "953dc6f6f85a1b2dbfca4c34a2796e7dde08d41e", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/BAAI/bge-reranker-v2-m3", + "weights": [{"file": "model.safetensors", "bytes": 2271071852, "sha256": "d9e3e081faff1eefb84019509b2f5558fd74c1a05a2c7db22f74174fcedb5286"}], + "adapter": "sequence-classification", + "model_max_tokens": 8192, + "production_runtime_max_tokens": 1280, + "tmcra_fusion_checkpoint_compatible": true + }, + "required_work": ["single_recall_lane", "desktop_worker_and_context_budgets", "desktop_installer", "offline_end_to_end_validation"] + }, + { + "id": "quality-qwen", + "name_zh": "增强版候选", + "recommendation_zh": "32GB 以上内存、高显存电脑;长文本和跨语言检索候选,需与均衡版实测比较", + "validation": "upstream_artifacts_verified_runtime_pending", + "system_ram_gib_min": 32, + "system_ram_gib_recommended_for_full_memory": 64, + "retrieval_vram_gib_recommended": 16, + "weights_bytes": 9235180368, + "embedding": { + "repo_id": "Qwen/Qwen3-Embedding-4B", + "revision": "5cf2132abc99cad020ac570b19d031efec650f2b", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Embedding-4B", + "weights": [ + {"file": "model-00001-of-00002.safetensors", "bytes": 4965826464, "sha256": "e70bfe3c970523fb7ef4eddffed2254ce3f1e7150c3de2af4342de129dd756f8"}, + {"file": "model-00002-of-00002.safetensors", "bytes": 3077765624, "sha256": "ed1b87c8e9eb7e535a1a155e4fd00d9f4dba80e58a6db48a4c9f82cede7079c1"} + ], + "dimensions": 2560, + "model_max_tokens": 32768, + "pooling": "last_token", + "normalize": true, + "query_prefix": "Instruct: Given a query about previous conversations, retrieve the relevant source passages.\nQuery: ", + "document_prefix": "", + "padding_side": "left" + }, + "reranker": { + "repo_id": "Qwen/Qwen3-Reranker-0.6B", + "revision": "e61197ed45024b0ed8a2d74b80b4d909f1255473", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Reranker-0.6B", + "weights": [{"file": "model.safetensors", "bytes": 1191588280, "sha256": "27cd75a405b9c1b46b59abfd88aaa209e6fed2a1972cde9b70e7659537c5e65b"}], + "adapter": "causal-lm-yes-no", + "model_max_tokens": 32768, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["qwen_yes_no_reranker_adapter", "service_variable_embedding_dimensions", "bounded_gpu_batches", "full_index_rebuild", "quality_and_latency_comparison"] + } + ], + "deployment_contract": { + "automatic_profile_switch_on_existing_index": false, + "cloud_fallback_in_full_local_mode": false, + "cloud_account_required_in_full_local_mode": false, + "generation_model_included_in_weights_bytes": false, + "model_cache_and_python_runtime_included_in_weights_bytes": false, + "required_index_identity": ["repo_id", "revision", "dimensions", "pooling", "query_prefix", "document_prefix", "normalization", "precision", "chunking_policy"], + "existing_sources_must_be_preserved": true, + "existing_indexes_must_be_rebuilt_before_activation": true, + "runtime_downloads_after_setup": false, + "readiness_requires_actual_inference": true + } +} diff --git a/07-tmcra-codex-plugins/tmcra-memory/resources/memory-center.html b/07-tmcra-codex-plugins/tmcra-memory/resources/memory-center.html new file mode 100644 index 0000000..46f5ee5 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/resources/memory-center.html @@ -0,0 +1,197 @@ + + + + + + +TMCRA · 记忆工作台 + + + + + +跳到主要内容 +

+ + +
+
+ + + +
+ + +
+
+
+
+ + + + + + + + + +
+
+
+
+ +
+

MEMORY WORKSPACE

+
+ + + + + + +

+
+ +
+
+ + + diff --git a/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.css b/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.css new file mode 100644 index 0000000..d1ea435 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.css @@ -0,0 +1,6 @@ +.workspace-toolbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 22px}.workspace-toolbar input,.workspace-toolbar select,.provider-form input,.provider-form select{font:inherit;color:var(--ink);background:var(--paper);border:1px solid var(--line);border-radius:7px;padding:10px 12px;min-width:0;max-width:100%}.workspace-toolbar input{flex:1;min-width:180px}.workspace-toolbar label{font-size:12px;color:var(--muted);display:flex;gap:8px;align-items:center}.workspace-status{color:var(--muted);font-size:12px;line-height:1.8;margin:14px 0 22px}.workspace-error{padding:20px;border:1px solid #dabeb8;border-radius:9px;background:#fcf6f3;line-height:1.8;font-size:13px}.provider-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.provider-stage{padding:26px;min-width:0}.provider-stage header{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:10px}.provider-stage h2{font-size:20px}.provider-stage>p{font-size:12px;color:var(--muted);line-height:1.9;margin:0 0 22px}.provider-form label.field{display:flex;flex-direction:column;gap:8px;margin:17px 0;font-size:12px}.provider-form input{width:100%}.provider-form input[type=checkbox]{width:auto;accent-color:#333}.provider-form .inherit-label{display:flex;gap:10px;align-items:center;line-height:1.8;font-size:12px}.provider-form small{display:block;font-size:11px;color:var(--muted);line-height:1.8}.provider-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-top:20px}.provider-actions .btn{font-size:12px}.provider-test{margin:14px 0 0;font-size:12px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere}.provider-savebar{display:flex;justify-content:space-between;align-items:center;gap:16px;border-top:1px solid var(--line);padding-top:23px;margin-top:25px}.provider-savebar p{font-size:12px;line-height:1.8;color:var(--muted)}.knowledge-layout{display:grid;grid-template-columns:310px minmax(0,1fr);gap:24px;align-items:start}.knowledge-index{max-height:780px;overflow:auto;padding-right:12px;border-right:1px solid var(--line)}.knowledge-entry{display:block;width:100%;padding:17px;text-align:left;background:transparent;border:1px solid transparent;border-radius:8px;margin-bottom:7px;color:var(--ink)}.knowledge-entry:hover,.knowledge-entry[aria-current=true]{background:#eeeeea;border-color:#deded8}.knowledge-entry strong{display:block;font-size:14px;line-height:1.8}.knowledge-entry p{font-size:12px;line-height:1.8;color:var(--muted);margin-top:6px}.knowledge-entry small{display:block;margin-top:11px;color:var(--muted);font-size:10px}.knowledge-article{padding:30px;min-width:0}.knowledge-article h2{font-size:25px;line-height:1.6;margin:14px 0}.knowledge-article .abstract{font-size:14px;color:var(--muted);line-height:2;border-bottom:1px solid var(--line);padding-bottom:20px}.knowledge-claim{padding:20px 0;border-bottom:1px solid var(--line)}.knowledge-claim p,.knowledge-article section p{white-space:pre-wrap;overflow-wrap:anywhere;font-size:14px;line-height:2;margin:10px 0}.knowledge-article h3{font-size:16px;margin-top:24px}.knowledge-evidence{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px}.knowledge-evidence .btn{font-size:11px}.evidence-reader{border:1px solid var(--line);border-radius:9px;padding:20px;margin-top:18px;background:#f8f8f4}.evidence-reader h3{margin:0 0 12px}.evidence-reader p{white-space:pre-wrap;font-size:12px;line-height:1.9;overflow-wrap:anywhere}.evidence-reader .source-id{font-size:10px}.graph-layout{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:20px;align-items:start}.graph-canvas{min-width:0;background:#fafaf7;border:1px solid var(--line);border-radius:12px;overflow:hidden}.graph-controls{display:flex;justify-content:space-between;gap:10px;align-items:center;padding:13px 16px;border-bottom:1px solid var(--line);font-size:11px;color:var(--muted)}.graph-controls>div{display:flex;gap:6px}.graph-canvas svg.map{display:block;width:100%;height:590px;touch-action:none;cursor:grab}.graph-canvas svg.map:active{cursor:grabbing}.map .graph-edge{stroke:#cacbc5;stroke-width:1.3}.map .graph-node{cursor:pointer;outline:none}.map .graph-node circle{fill:#383d36;stroke:#fafaf7;stroke-width:3}.map .graph-node[data-actor=assistant] circle{fill:#909487}.map .graph-node text{fill:#45493f;font:13px 'Microsoft YaHei','Segoe UI',sans-serif;paint-order:stroke;stroke:#fafaf7;stroke-width:4px;stroke-linejoin:round}.map .graph-node:focus circle,.map .graph-node[aria-pressed=true] circle{stroke:#a4b87a;stroke-width:6}.graph-detail{padding:22px;min-width:0}.graph-detail h2{font-size:18px;line-height:1.7;margin:12px 0}.graph-detail>p{font-size:12px;line-height:1.9;color:var(--muted);overflow-wrap:anywhere}.graph-relationship{padding-top:15px;margin-top:15px;border-top:1px solid var(--line);font-size:12px;line-height:1.8}.graph-relationship strong{font-weight:500}.graph-relationship p{color:var(--muted);font-size:11px;margin:6px 0}.graph-legend{display:flex;gap:20px;flex-wrap:wrap;font-size:11px;color:var(--muted);padding:14px 17px;border-top:1px solid var(--line)}.graph-legend span{display:flex;align-items:center;gap:7px}.graph-legend i{height:8px;width:8px;border-radius:50%;background:#383d36}.graph-legend span:nth-child(2) i{background:#909487}.projection-pagination{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:18px;font-size:12px;color:var(--muted)}.projection-pagination>div{display:flex;gap:8px}.sidebar{overflow-y:auto}.sidebar .nav-button{min-height:42px}.sidebar .local-card{margin-top:20px}.provider-form :focus-visible,.workspace-toolbar :focus-visible,.knowledge-entry:focus-visible{outline:2px solid #718550;outline-offset:3px} +.graph-canvas svg.map .graph-node text{font-size:16px}.graph-canvas svg.map .graph-edge{stroke:#adb3a5;stroke-width:1.6}.graph-node-list{display:none} +@media(max-width:1100px){.graph-layout{grid-template-columns:minmax(0,1fr)}.graph-detail{display:block}.graph-canvas svg.map{height:500px}.knowledge-layout{grid-template-columns:235px minmax(0,1fr)}.knowledge-article{padding:24px}.provider-grid{gap:15px}.provider-stage{padding:21px}} +@media(max-width:660px){.graph-node-list{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding:14px;border-top:1px solid var(--line)}.graph-node-list .btn{text-align:left;justify-content:flex-start;font-size:11px;line-height:1.7}} +@media(max-width:660px){.provider-grid,.knowledge-layout{grid-template-columns:1fr}.provider-savebar{align-items:flex-start;flex-direction:column}.provider-stage{padding:21px}.knowledge-index{display:flex;gap:7px;max-width:100%;border-right:0;border-bottom:1px solid var(--line);padding:0 0 13px;overflow:auto}.knowledge-entry{width:230px;min-width:230px;border-color:var(--line);padding:14px}.knowledge-entry strong{font-size:12px}.knowledge-article{padding:21px}.knowledge-article h2{font-size:21px}.workspace-toolbar{align-items:stretch;gap:10px}.workspace-toolbar label{width:100%}.workspace-toolbar select{flex:1}.graph-canvas svg.map{height:420px}.graph-controls{flex-wrap:wrap}.graph-controls .btn{min-height:34px;font-size:11px}.graph-legend{font-size:10px;gap:12px}.projection-pagination{flex-wrap:wrap}} +.local-deployment{margin:0 0 28px;padding:26px}.local-deployment>header{display:flex;align-items:center;justify-content:space-between;gap:16px}.local-model-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;margin:24px 0}.local-model-card{border:1px solid var(--line,#e4e5dd);border-radius:14px;padding:20px;display:flex;flex-direction:column;gap:10px}.local-model-card h3,.local-model-card p{margin:0}.local-model-card strong{overflow-wrap:anywhere;font-size:13px}.local-model-card small{color:var(--muted,#72766d);display:block}.local-model-card button{margin-top:auto}.local-config-path{display:block;overflow-wrap:anywhere;font-size:12px;margin-top:12px}@media(max-width:900px){.local-model-grid{grid-template-columns:1fr}.local-deployment>header{align-items:flex-start;flex-direction:column}} diff --git a/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.js b/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.js new file mode 100644 index 0000000..d78abfc --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/resources/workspace-panels.js @@ -0,0 +1,138 @@ +'use strict'; +(() => { + const pages = new Map(); + const labels = { confirmed:'已确认',provisional:'待验证',superseded:'已更新',open:'待解决',learned:'学习知识',project:'项目知识',personal:'个人信息',user:'用户',assistant:'助手',goal:'目标',requirement:'需求',decision:'决定',action:'行动',result:'结果',problem:'问题',solution:'方案',lesson:'经验',preference:'偏好',fact:'事实',open_question:'待解决',depends_on:'依赖',resolves:'解决',updates:'更新',supersedes:'替代',contradicts:'存在矛盾',reinforces:'相互支持',derived_from:'来源于',applies_to:'应用于',related:'相关',leads_to:'推动',continues:'延续',branches:'分支',converges:'汇合',contains:'包含',parent:'上级',supports:'支持'}; + const word = (row, key) => String(row?.display?.zh?.[key] || row?.[key] || ''); + const heading = (root, eyebrow, title, description) => { const h=el('div',undefined,root,'page-head');const box=el('div',undefined,h);el('div',eyebrow,box,'eyebrow');el('h1',title,box);el('p',description,box);return h; }; + function fail(root,error,retry){root.replaceChildren();const box=el('div',undefined,root,'workspace-error');box.setAttribute('role','alert');el('p',errorText(error),box);button('重试',box,retry,{style:'btn small'});} + function field(parent,label,id,type='text'){const box=el('label',label,parent,'field');const input=el('input',undefined,box);input.id=id;input.type=type;input.autocomplete='off';input.required=type!=='password';input.setAttribute('aria-label',label);return input;} + async function localModels(root){ + const value=await api('local_deployment_status');if(!root.isConnected)return;root.replaceChildren(); + const head=el('header',undefined,root);el('h2','把记忆系统放在这台电脑',head);pill(value.ready?'本机服务已就绪':'本地部署 · 预览版',head); + el('p','向量检索、重排、记忆写入与后台整理均在本机运行。使用独立身份和数据目录,现有云端记忆保留。',root); + el('small',`${value.requirement}。检测到 ${value.ramGiB}GB 内存;推荐基于容量估算。`,root); + if(value.missing)el('p',value.missing,root,'workspace-status'); + const grid=el('div',undefined,root,'local-model-grid');const busy=['installing','starting'].includes(value.operation.state); + for(const profile of value.profiles){ + const card=el('article',undefined,grid,'local-model-card');const recommended=profile.id===value.recommendedProfile; + if(recommended)pill('本机推荐',card);el('h3',profile.name_zh,card);el('p',profile.recommendation_zh,card); + el('strong',profile.embedding.repo_id.split('/').pop(),card);el('small',`Embedding · ${profile.embedding.dimensions} 维`,card); + el('strong',profile.reranker.repo_id.split('/').pop(),card);el('small','Reranker · 检索结果重排',card); + el('p',`检索权重约 ${(profile.weights_bytes/1e9).toFixed(2)}GB · 完整系统建议 ${profile.system_ram_gib_recommended_for_full_memory}GB 内存`,card); + el('small',`${profile.embedding.license} / ${profile.reranker.license};生成模型另需约 2.50GB。`,card); + if(profile.id!=='lite-cpu')el('small','此档位尚待对应硬件的完整实测。',card); + else el('small','CPU 写入和原文召回已测;复杂编译与后台整理尚待验收。',card); + button(value.installedProfile===profile.id?'重新准备此档位':'一键安装',card,()=>openEditor({kind:'confirm',title:`安装${profile.name_zh}?`, + note:`首次安装会下载检索权重、2.50GB 生成模型和 Python 运行环境,保存在 ${value.dataRoot}。将自动切换到本机记忆,无需 TMCRA 账号和服务器。原云端配置与记忆保留;安装失败时保持本地模式。完成后重启宿主即可自动接入。此版本支持 Windows x64。`, + confirm:'确认下载并安装',save:async()=>{await api('local_deployment_install',{profile:profile.id});await localModels(root);}}), + {style:recommended?'btn primary':'btn',disabled:!value.available||busy||value.running||value.ramGiBlocalModels(root),{style:'btn small',symbol:'refresh'}); + if(value.installedProfile&&!value.running)button('启动本地服务',actions,async()=>{await api('local_deployment_start');await localModels(root);},{style:'btn small',disabled:busy||!value.available}); + if(value.running)button('停止本地服务',actions,()=>openEditor({kind:'confirm',title:'停止本地记忆服务?',note:'本机写入与召回将暂停,模型和已保存的记忆保留。',confirm:'停止服务',save:async()=>{await api('local_deployment_stop');await localModels(root);}}),{style:'btn small'}); + if(value.connectionConfig){el('p','独立本地身份已生成并自动选用。重启宿主后即可接入,无需填写账号或 API Key。',root);const path=el('code',value.connectionConfig,root,'local-config-path');} + if(busy&&!value.ready)setTimeout(()=>{if(root.isConnected&&!$('page-providers').hidden)void localModels(root).catch(error=>fail(root,error,()=>localModels(root)));},4000); + } + async function providers(root){ + const current=await api('providers_read');root.replaceChildren(); + heading(root,'MODELS, ON YOUR TERMS','模型配置','为记忆写入与后台整理分别选择 API,密钥保存在本机。'); + const local=el('section',undefined,root,'panel local-deployment'); + void localModels(local).catch(error=>fail(local,error,()=>localModels(local))); + const form=el('form',undefined,root,'provider-form');form.autocomplete='off'; + const grid=el('div',undefined,form,'provider-grid');const stages={};let dirty=false; + for(const stage of ['writer','organizer']){ + const card=el('section',undefined,grid,'panel provider-stage');const header=el('header',undefined,card); + el('h2',stage==='writer'?'记忆写入':'后台整理',header);pill(stage==='writer'?'WRITER':'ORGANIZER',header); + el('p',stage==='writer'?'从对话中提取记忆,保存事实与来源。':'整理已有记忆、更新长期关系,支持独立配置模型。',card); + let inherit; + if(stage==='organizer'){const label=el('label',undefined,card,'inherit-label');inherit=el('input',undefined,label);inherit.type='checkbox';inherit.id='provider-inherit';inherit.checked=current.organizer?.inheritWriter!==false;el('span','沿用记忆写入的 API 和模型',label);} + const fields=el('div',undefined,card);const providerLabel=el('label','接口类型',fields,'field');const provider=el('select',undefined,providerLabel);provider.id=stage+'-provider';provider.setAttribute('aria-label',stage+' 接口类型'); + for(const [value,name] of [['openai-compatible','OpenAI 兼容接口'],['deepseek','DeepSeek'],['local-openai-compatible','本机兼容接口']]){const o=el('option',name,provider);o.value=value;} + const base=field(fields,'API 地址',stage+'-base');base.placeholder='https://provider.example/v1'; + const model=field(fields,'模型名称',stage+'-model');model.placeholder='填写服务商提供的模型 ID'; + const key=field(fields,'API Key',stage+'-key','password');key.placeholder=current[stage]?.credentialPresent?'密钥已保存;留空保留':'仅保存在当前电脑';key.autocomplete='new-password'; + el('small','切换 API 地址后,需要重新填写该接口的密钥。',fields); + const old=current[stage]||{};provider.value=old.provider||'openai-compatible';base.value=old.baseUrl||'';model.value=old.model||''; + const actions=el('div',undefined,card,'provider-actions');const status=el('p',undefined,card,'provider-test');status.id=stage+'-test-result';status.setAttribute('role','status'); + button('测试推理',actions,async()=>{if(!form.reportValidity())return;status.textContent='正在使用虚构样本测试,不会发送真实记忆…';try{const result=await api('providers_test',{stage,config:payload()});status.textContent=`测试通过 · ${result.latencyMs} ms\n实际响应模型:${result.servedModel}\nJSON 输出校验通过;尚未执行正式记忆作业。`;}catch(error){status.textContent='测试失败:'+errorText(error);throw error;}},{symbol:'activity'}); + const clear=button('移除密钥',actions,()=>openEditor({kind:'confirm',title:'移除本机模型密钥?',note:stage==='writer'?'沿用此配置的后台整理也会失去访问凭据。':'仅移除后台整理的本机密钥。',confirm:'确认移除',save:async()=>{await api('providers_clear',{stage});dirty=false;await providers(root);}}),{style:'btn text',disabled:!old.credentialPresent||Boolean(inherit?.checked)}); + stages[stage]={provider,base,model,key,inherit,fields,clear}; + if(inherit){const update=()=>{fields.hidden=inherit.checked;fields.querySelectorAll('input,select').forEach(n=>n.disabled=inherit.checked);clear.disabled=inherit.checked||!old.credentialPresent;};inherit.onchange=update;update();} + } + const savebar=el('div',undefined,form,'provider-savebar');const saveNote=el('p','密钥只在本机输入和保存。测试会向所填服务商发送少量虚构内容。',savebar); + const save=el('button','保存配置',savebar,'btn primary');save.type='submit';save.id='saveProviders'; + function payload(){const get=s=>({provider:s.provider.value,baseUrl:s.base.value.trim(),model:s.model.value.trim(),...(s.key.value.trim()?{apiKey:s.key.value.trim()}:{})});return {writer:get(stages.writer),organizer:stages.organizer.inherit.checked?{inheritWriter:true}:{inheritWriter:false,...get(stages.organizer)}};} + form.oninput=()=>{dirty=true;saveNote.textContent='有尚未保存的配置。测试使用当前填写内容。';}; + form.onsubmit=event=>{event.preventDefault();if(!form.reportValidity())return;run(async()=>{const value=await api('providers_save',{config:payload()});for(const stage of Object.values(stages))stage.key.value='';dirty=false;await providers(root);note(value.configured?'模型配置已保存到本机':'配置已更新');},save);}; + const oldHandler=pages.get('providerUnload');if(oldHandler)window.removeEventListener('beforeunload',oldHandler); + const before=event=>{if(dirty){event.preventDefault();event.returnValue='';}};pages.set('providerUnload',before);window.addEventListener('beforeunload',before); + } + function scopePicker(root,onChange){const toolbar=el('div',undefined,root,'workspace-toolbar');const label=el('label','记忆范围',toolbar);const select=el('select',undefined,label);select.setAttribute('aria-label','记忆范围');for(const item of data.availableScopes||[{scope:data.scope,label:'当前项目'}]){const o=el('option',item.label,select);o.value=item.scope;}select.value=(data.availableScopes||[]).find(x=>x.label==='个人全局')?.scope||data.scope;select.onchange=()=>onChange(select.value);return {toolbar,select};} + function projectionStatus(root,value){el('p',`${value.projection_state==='ready'?'已整理视图':'基础视图 · 等待后台整理'}${value.stale?' · 内容有更新,当前投影待刷新':''}。内容与关系来自服务端,原始记录保留用于核对。`,root,'workspace-status');} + async function evidence(container,node,scope){ + container.replaceChildren();el('h3','原始证据',container); + const ids=[...new Set(node.source_record_ids?.length?node.source_record_ids:[node.source_record_id||node.memory_id].filter(Boolean))]; + if(!ids.length){el('p','此条目尚未提供可查询的来源标识。',container);return;} + for(const id of ids){const block=el('div',undefined,container);const load=async cursor=>{ + const result=await api('evidence',{scope,memory_id:id,...(cursor?{cursor}:{})}); + for(const item of result.items||[]){const article=el('article',undefined,block,'knowledge-claim');pill(labels[item.actor_role]||item.role||'来源',article);el('p',item.text,article);el('div',item.source_record_id,article,'source-id mono'); + if(item.source_record_id&&data.policy.write){const actions=el('div',undefined,article,'knowledge-evidence');button('纠正此来源',actions,()=>sourceFeedback('correct',{memory_id:item.source_record_id,content:item.text},{scope},{}),{style:'btn small'});} + } + if(result.page?.next_cursor){const next=button('加载更多来源',block,async()=>{await load(result.page.next_cursor);next.remove();},{style:'btn small'});} + };await load();} + } + async function knowledge(root){ + root.replaceChildren();heading(root,'KNOWLEDGE THAT STAYS WITH YOU','知识库','把学过的知识、项目决定与个人偏好,整理成可追溯的条目。'); + let loaded,selected=null,offset=0;const scope=scopePicker(root,()=>load());const input=el('input',undefined,scope.toolbar);input.type='search';input.placeholder='搜索知识标题、事实与正文';input.setAttribute('aria-label','搜索知识库'); + const collection=el('select',undefined,scope.toolbar);collection.setAttribute('aria-label','知识分类');for(const [v,t] of [['','全部分类'],['learned','学习知识'],['project','项目知识'],['personal','个人信息']]){const o=el('option',t,collection);o.value=v;} + button('刷新知识库',scope.toolbar,()=>load(),{symbol:'refresh'});const content=el('div',undefined,root);let generation=0; + async function load(){const seq=++generation;content.replaceChildren();el('p','正在读取知识库…',content,'workspace-status');try{const value=await api('knowledge',{scope:scope.select.value});if(seq!==generation)return;if(!Array.isArray(value.pages))throw Error('服务尚未返回知识库页面,请检查服务版本与整理状态。');loaded=value;selected=null;offset=0;render();}catch(error){if(seq===generation)fail(content,error,load);}} + function render(){content.replaceChildren();projectionStatus(content,loaded);const q=input.value.trim().toLowerCase();const filtered=loaded.pages.filter(p=>(!collection.value||p.collection===collection.value)&&(!q||JSON.stringify(p).toLowerCase().includes(q))); + if(!filtered.length){empty(content,'暂时没有匹配的知识',loaded.pages.length?'调整搜索词或分类,查看其他条目。':'记忆进入后台整理后,知识条目会出现在这里。');return;} + const list=filtered.slice(offset,offset+40);if(!list.some(p=>p.page_id===selected?.page_id))selected=list[0];const layout=el('div',undefined,content,'knowledge-layout');const index=el('div',undefined,layout,'knowledge-index');index.setAttribute('aria-label','知识条目');const article=el('article',undefined,layout,'panel knowledge-article'); + for(const p of list){const b=button('',index,()=>{selected=p;render();},{style:'knowledge-entry'});b.setAttribute('aria-current',String(p.page_id===selected.page_id));b.replaceChildren();el('strong',word(p,'title'),b);el('p',word(p,'abstract').slice(0,95),b);el('small',labels[p.collection]||p.collection||'知识条目',b);} + pill(labels[selected.collection]||'知识条目',article);el('h2',word(selected,'title'),article);el('p',word(selected,'abstract'),article,'abstract'); + const reader=el('div',undefined,article,'evidence-reader');reader.hidden=true; + function citations(item,parent){const refs=el('div',undefined,parent,'knowledge-evidence');for(const [i,id] of (item.evidence_ids||[]).entries()){const node=loaded.evidence_catalog?.[id];button('来源 '+(i+1),refs,async()=>{reader.hidden=false;try{await evidence(reader,node||{},scope.select.value);}catch(error){fail(reader,error,()=>evidence(reader,node||{},scope.select.value));}reader.scrollIntoView({block:'nearest'});},{style:'btn small',disabled:!node});}} + for(const claim of selected.claims||[]){const box=el('div',undefined,article,'knowledge-claim');pill(labels[claim.status]||claim.status||'待验证',box);el('p',word(claim,'text'),box);citations(claim,box);} + for(const section of selected.sections||[]){const box=el('section',undefined,article);el('h3',word(section,'heading'),box);el('p',word(section,'body'),box);citations(section,box);} + article.append(reader);pager(content,offset,list.length,filtered.length,n=>{offset=n;render();},40); + } + input.oninput=collection.onchange=()=>{offset=0;if(loaded)render();};await load(); + } + function pager(root,offset,count,total,change,size){const row=el('div',undefined,root,'projection-pagination');el('span',`展示 ${offset+1}–${offset+count} / ${total}`,row);const controls=el('div',undefined,row);button('上一页',controls,()=>change(Math.max(0,offset-size)),{style:'btn small',disabled:!offset});button('下一页',controls,()=>change(offset+size),{style:'btn small',disabled:offset+count>=total});} + async function graph(root){ + root.replaceChildren();heading(root,'SEE HOW YOUR KNOWLEDGE CONNECTS','知识图谱','沿着真实关系探索记忆,点开节点查看内容与证据。');let loaded,offset=0,selected; + const scope=scopePicker(root,()=>load());const search=el('input',undefined,scope.toolbar);search.type='search';search.placeholder='搜索记忆主题与内容';search.setAttribute('aria-label','搜索图谱'); + button('刷新图谱',scope.toolbar,()=>load(),{symbol:'refresh'});const content=el('div',undefined,root);let generation=0; + async function load(){const seq=++generation;content.replaceChildren();el('p','正在读取知识图谱…',content,'workspace-status');try{const value=await api('graph',{scope:scope.select.value});if(seq!==generation)return;if(!Array.isArray(value.nodes)||!Array.isArray(value.edges))throw Error('服务尚未返回有效的知识图谱。');loaded=value;offset=0;selected=null;render();}catch(error){if(seq===generation)fail(content,error,load);}} + function render(){content.replaceChildren();projectionStatus(content,loaded);const q=search.value.toLowerCase().trim();const all=loaded.nodes.filter(n=>n.level==='evidence'&&n.evidence_kind==='memory'&&(!q||JSON.stringify(n).toLowerCase().includes(q)));const nodes=all.slice(offset,offset+40); + if(!nodes.length){empty(content,'暂时没有匹配的记忆节点',all.length?'调整搜索词查看其他记忆。':'记忆整理后会形成可浏览的节点;关系仅展示服务端已提供的内容。',{symbol:'branch'});return;} + const ids=new Set(nodes.map(n=>n.id));const edges=loaded.edges.filter(e=>ids.has(e.source)&&ids.has(e.target));const allMap=new Map(loaded.nodes.map(n=>[n.id,n]));if(!ids.has(selected?.id))selected=nodes[0]; + const layout=el('div',undefined,content,'graph-layout');const canvas=el('div',undefined,layout,'graph-canvas');const controls=el('div',undefined,canvas,'graph-controls');el('span',`${nodes.length} 个节点 · ${edges.length} 条可见关系`,controls);const zoom=el('div',undefined,controls); + const ns='http://www.w3.org/2000/svg';const svg=document.createElementNS(ns,'svg');svg.classList.add('map');svg.setAttribute('aria-label','记忆关系图,可缩放、拖动并选择节点');canvas.append(svg); + const make=(tag,attrs,parent=svg)=>{const n=document.createElementNS(ns,tag);for(const [k,v]of Object.entries(attrs))n.setAttribute(k,String(v));parent.append(n);return n;}; + const defs=make('defs',{});const marker=make('marker',{id:'memory-arrow',viewBox:'0 0 10 10',refX:19,refY:5,markerWidth:5,markerHeight:5,orient:'auto-start-reverse'},defs);make('path',{d:'M 0 0 L 10 5 L 0 10 z',fill:'#a9ada2'},marker); + let view={x:0,y:0,w:1000,h:670};const apply=()=>svg.setAttribute('viewBox',`${view.x} ${view.y} ${view.w} ${view.h}`);const scale=f=>{const w=view.w*f,h=view.h*f;if(w<220||w>4000)return;view={x:view.x+(view.w-w)/2,y:view.y+(view.h-h)/2,w,h};apply();};apply();button('−',zoom,()=>scale(1.25),{style:'btn small'}).setAttribute('aria-label','缩小图谱');button('+',zoom,()=>scale(.8),{style:'btn small'}).setAttribute('aria-label','放大图谱');button('复位',zoom,()=>{view={x:0,y:0,w:1000,h:670};apply();},{style:'btn small'}); + const cols=Math.max(2,Math.ceil(Math.sqrt(nodes.length*1.5))),rows=Math.ceil(nodes.length/cols);const pos=new Map(nodes.map((n,i)=>[n.id,{x:100+(i%cols)*800/Math.max(1,cols-1),y:90+Math.floor(i/cols)*490/Math.max(1,rows-1)}])); + // Deterministic layout only. Edges and their direction always come from the API. + for(let k=0;k<85;k++){const force=new Map(nodes.map(n=>[n.id,{x:0,y:0}]));for(let i=0;i{reader.hidden=false;try{await evidence(reader,n,scope.select.value);}catch(error){fail(reader,error,()=>evidence(reader,n,scope.select.value));}},{style:'btn small',symbol:'document'}); + const relations=loaded.edges.filter(e=>(e.source===n.id||e.target===n.id)&&allMap.get(e.source)?.evidence_kind==='memory'&&allMap.get(e.target)?.evidence_kind==='memory'); + for(const edge of relations){const box=el('div',undefined,detail,'graph-relationship');const from=allMap.get(edge.source),to=allMap.get(edge.target);el('strong',`${word(from,'label')} → ${labels[edge.type]||edge.type} → ${word(to,'label')}`,box);if(edge.reason)el('p',edge.reason,box);el('p',edge.origin==='agent'?'模型整理关系,请结合证据核对':'服务端记录关系',box);} + if(!relations.length)el('p','当前节点尚无已记录的语义关系。',detail,'workspace-status');detail.append(reader); + } + for(const n of nodes){const p=pos.get(n.id);const g=make('g',{transform:`translate(${p.x},${p.y})`,class:'graph-node',role:'button',tabindex:0,'aria-label':word(n,'label'),'aria-pressed':String(selected.id===n.id),'data-actor':n.actor_role||'user'});groups.set(n.id,g);make('circle',{r:8},g);const text=make('text',{y:27,'text-anchor':'middle'},g);text.textContent=word(n,'label').slice(0,18);make('title',{},g).textContent=word(n,'label');g.onclick=()=>select(n);g.onkeydown=e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();select(n);}};} + select(selected);let drag; + svg.onpointerdown=e=>{if(e.target.closest('.graph-node'))return;drag={x:e.clientX,y:e.clientY,base:{...view}};svg.setPointerCapture(e.pointerId);};svg.onpointermove=e=>{if(!drag)return;const r=svg.getBoundingClientRect();view.x=drag.base.x-(e.clientX-drag.x)*view.w/r.width;view.y=drag.base.y-(e.clientY-drag.y)*view.h/r.height;apply();};svg.onpointerup=svg.onpointercancel=()=>drag=null; + const legend=el('div',undefined,canvas,'graph-legend');for(const t of ['用户来源','助手来源','箭头表示服务端关系方向']){const row=el('span',undefined,legend);if(t!=='箭头表示服务端关系方向')el('i',undefined,row);el('span',t,row);} + const list=el('div',undefined,canvas,'graph-node-list');list.setAttribute('aria-label','可选择的记忆节点');for(const n of nodes)button(word(n,'label'),list,()=>select(n),{style:'btn small'}); + pager(content,offset,nodes.length,all.length,n=>{offset=n;render();},40); + } + search.oninput=()=>{offset=0;if(loaded)render();};await load(); + } + window.mountWorkspacePage = page => {if(!['providers','knowledge','graph'].includes(page)||pages.get(page))return;pages.set(page,true);const root=$('page-'+page);el('p','正在加载…',root,'workspace-status');const start=()=>({providers,knowledge,graph}[page])(root);void start().catch(error=>fail(root,error,start));}; +})(); diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/LICENSE b/07-tmcra-codex-plugins/tmcra-memory/runtime/LICENSE new file mode 100644 index 0000000..a9c3e2f --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/build_v3_runtime_dataset.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/build_v3_runtime_dataset.py new file mode 100644 index 0000000..a429a1c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/build_v3_runtime_dataset.py @@ -0,0 +1,791 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import time +from collections import Counter +from pathlib import Path +from typing import Any, Iterable, Mapping, Sequence + +import torch + +from tmcra_v2_lme_pipeline import EmbeddingCacheVectorizer, session_text_chunks +from tmcra_v3_schema import ( + CHANNEL_NAMES, + SCHEMA_VERSION, + clean_text, + read_jsonl, + validate_sample, + validate_split_isolation, + write_jsonl, +) + + +EVENT_INDEX_RE = re.compile( + r"^event::longmemeval:(?P[^:]+):s(?P\d+)_c(?P\d+)$" +) +TEACHER_EVENT_INDEX_RE = re.compile(r":s(?P\d+)_c(?P\d+)$") +RAW_TEACHER_EVENT_RE = re.compile( + r"^lme:[^:]+:session:(?P[^:]+):turn:(?P\d+)$" +) +TURN_BOUNDARY_RE = re.compile(r"\n\[[^\]]+ turn=\d+ role=") + + +def stable_int(value: str) -> int: + return int.from_bytes(hashlib.blake2b(value.encode("utf-8"), digest_size=8).digest(), "big") + + +def normalized_question(value: Any) -> str: + return clean_text(value).casefold() + + +def load_teacher_supervision(path: Path) -> dict[str, dict[str, Any]]: + output: dict[str, dict[str, Any]] = {} + for row in read_jsonl(path): + question_key = normalized_question(row.get("question")) + if not question_key: + raise RuntimeError("teacher row is missing question text") + if question_key in output: + raise RuntimeError(f"duplicate teacher question after exact normalization: {row.get('question')!r}") + if not bool(row.get("usable_for_training", False)): + continue + if not list(row.get("positive_event_ids") or []): + raise RuntimeError(f"teacher row has no positive events: {row.get('question_id')}") + output[question_key] = row + if not output: + raise RuntimeError(f"no usable teacher supervision rows: {path}") + return output + + +def teacher_parent_locations(event_ids: Iterable[Any], valid_locations: set[tuple[int, int]], qid: str) -> list[tuple[int, int]]: + output: list[tuple[int, int]] = [] + seen: set[tuple[int, int]] = set() + for raw in event_ids: + event_id = clean_text(raw) + match = TEACHER_EVENT_INDEX_RE.search(event_id) + if match is None: + raise RuntimeError(f"{qid}: teacher event is not a runtime parent event: {event_id}") + location = (int(match.group("session")), int(match.group("parent"))) + if location not in valid_locations: + raise RuntimeError(f"{qid}: teacher event has no parent in the current inventory: {event_id}") + if location not in seen: + seen.add(location) + output.append(location) + return output + + +def reconstruct_parent_text(candidates: Sequence[Mapping[str, Any]], indexes: Sequence[int], qid: str) -> str: + if not indexes: + raise RuntimeError(f"{qid}: cannot reconstruct an empty parent") + total = max(int(candidates[index]["source_char_end"]) for index in indexes) + characters: list[str | None] = [None] * total + for index in indexes: + candidate = candidates[index] + text = str(candidate["text"]) + if "\n" not in text: + raise RuntimeError(f"{qid}: inventory candidate is missing its payload separator") + payload = text.split("\n", 1)[1] + start = int(candidate["source_char_start"]) + end = int(candidate["source_char_end"]) + if len(payload) != end - start: + raise RuntimeError(f"{qid}: inventory candidate payload length does not match its source span") + for offset, character in enumerate(payload, start=start): + existing = characters[offset] + if existing is not None and existing != character: + raise RuntimeError(f"{qid}: overlapping inventory subchunks disagree") + characters[offset] = character + if any(character is None for character in characters): + raise RuntimeError(f"{qid}: reconstructed parent contains a character coverage gap") + return "".join(character for character in characters if character is not None) + + +def teacher_turn_candidate_indexes( + event_ids: Iterable[Any], + *, + candidates: Sequence[Mapping[str, Any]], + parent_candidates: Mapping[tuple[int, int], Sequence[int]], + qid: str, +) -> set[int]: + output: set[int] = set() + session_locations: dict[str, list[tuple[int, int]]] = {} + for location, indexes in parent_candidates.items(): + session_id = clean_text(candidates[indexes[0]].get("session_id")) + session_locations.setdefault(session_id, []).append(location) + parent_text_cache: dict[tuple[int, int], str] = {} + for raw in event_ids: + event_id = clean_text(raw) + match = RAW_TEACHER_EVENT_RE.match(event_id) + if match is None: + raise RuntimeError(f"{qid}: teacher raw event is malformed: {event_id}") + session_id = clean_text(match.group("session")) + turn = int(match.group("turn")) + marker = f"[{session_id} turn={turn} role=" + matches: list[tuple[tuple[int, int], int, int]] = [] + for location in session_locations.get(session_id, []): + if location not in parent_text_cache: + parent_text_cache[location] = reconstruct_parent_text( + candidates, parent_candidates[location], qid + ) + parent_text = parent_text_cache[location] + turn_start = parent_text.find(marker) + if turn_start < 0: + continue + next_turn = TURN_BOUNDARY_RE.search(parent_text, turn_start + len(marker)) + turn_end = next_turn.start() if next_turn else len(parent_text) + matches.append((location, turn_start, turn_end)) + if len(matches) != 1: + raise RuntimeError( + f"{qid}: teacher event must map to exactly one current parent turn, got {len(matches)}: {event_id}" + ) + location, turn_start, turn_end = matches[0] + matched_subchunks = { + index + for index in parent_candidates[location] + if int(candidates[index]["source_char_start"]) < turn_end + and int(candidates[index]["source_char_end"]) > turn_start + } + if not matched_subchunks: + raise RuntimeError(f"{qid}: teacher turn has no overlapping subchunk: {event_id}") + output.update(matched_subchunks) + return output + + +def covered_windows(text: str, max_chars: int, overlap: int) -> list[tuple[int, int]]: + if max_chars <= 0: + raise RuntimeError("subchunk payload size must be positive") + if overlap < 0 or overlap >= max_chars: + raise RuntimeError("subchunk overlap must be non-negative and smaller than the payload") + if not text: + return [] + spans: list[tuple[int, int]] = [] + start = 0 + while start < len(text): + hard_end = min(len(text), start + max_chars) + end = hard_end + if hard_end < len(text): + floor = max(start + max_chars // 2, hard_end - 160) + split_at = text.rfind(" ", floor, hard_end) + if split_at > start: + end = split_at + if end <= start: + end = hard_end + spans.append((start, end)) + if end >= len(text): + break + start = max(start + 1, end - overlap) + if spans[0][0] != 0 or spans[-1][1] != len(text): + raise AssertionError("subchunk coverage does not reach both text boundaries") + if any(right_start > left_end for (_, left_end), (right_start, _) in zip(spans, spans[1:])): + raise AssertionError("subchunk coverage contains a gap") + return spans + + +def load_lme(path: Path) -> list[dict[str, Any]]: + value = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(value, list) or not value: + raise RuntimeError(f"LongMemEval data must be a non-empty list: {path}") + rows = [row for row in value if isinstance(row, dict)] + qids = [clean_text(row.get("question_id")) for row in rows] + if len(qids) != len(set(qids)): + raise RuntimeError("LongMemEval question_id values are not unique") + return rows + + +def choose_holdout(rows: Sequence[Mapping[str, Any]], count: int) -> list[str]: + if count <= 0 or count >= len(rows): + raise RuntimeError(f"holdout count must be between 1 and {len(rows) - 1}") + by_type: dict[str, list[str]] = {} + for row in rows: + qid = clean_text(row.get("question_id")) + qtype = clean_text(row.get("question_type")) or "unknown" + by_type.setdefault(qtype, []).append(qid) + selected: list[str] = [] + for qtype, qids in sorted(by_type.items()): + qids.sort(key=lambda qid: (stable_int(f"tmcra-v3-holdout:{qid}"), qid)) + quota = int(len(qids) * count / len(rows)) + selected.extend(qids[:quota]) + selected_set = set(selected) + remaining = [clean_text(row.get("question_id")) for row in rows if clean_text(row.get("question_id")) not in selected_set] + remaining.sort(key=lambda qid: (stable_int(f"tmcra-v3-holdout-fill:{qid}"), qid)) + selected.extend(remaining[: max(0, count - len(selected))]) + selected = sorted(selected[:count]) + if len(selected) != count or len(set(selected)) != count: + raise RuntimeError("failed to construct an exact unique holdout") + return selected + + +def make_inventory_row( + row: Mapping[str, Any], + split: str, + parent_chars: int, + subchunk_chars: int, + subchunk_overlap: int, +) -> dict[str, Any]: + qid = clean_text(row.get("question_id")) + question = clean_text(row.get("question")) + question_date = clean_text(row.get("question_date")) + query_text = f"{question}\nQuestion date: {question_date}" if question_date else question + sessions = list(row.get("haystack_sessions") or []) + session_ids = [clean_text(value) for value in list(row.get("haystack_session_ids") or [])] + dates = [clean_text(value) for value in list(row.get("haystack_dates") or [])] + answer_session_ids = {clean_text(value) for value in list(row.get("answer_session_ids") or []) if clean_text(value)} + if not sessions or len(sessions) != len(session_ids): + raise RuntimeError(f"{qid}: haystack session/id mismatch") + candidates: list[dict[str, Any]] = [] + found_gold: set[str] = set() + parent_chunk_count = 0 + source_parent_chars = 0 + for index, session in enumerate(sessions): + session_id = session_ids[index] + date = dates[index] if index < len(dates) else "" + if not isinstance(session, Sequence) or isinstance(session, (str, bytes, bytearray)): + raise RuntimeError(f"{qid}: session {index} is not a turn list") + turns = list(session) + if any(not isinstance(turn, Mapping) for turn in turns): + raise RuntimeError(f"{qid}: session {index} contains a non-object turn") + parent_chunks = session_text_chunks( + session_id=session_id, + date=date, + turns=turns, + max_chars=parent_chars, + max_chunks=0, + ) + if not parent_chunks: + parent_chunks = [f"LongMemEval session_id={session_id} date={date}"] + relevant = session_id in answer_session_ids + if relevant: + found_gold.add(session_id) + for parent_index, parent_text in enumerate(parent_chunks, start=1): + parent_chunk_count += 1 + source_parent_chars += len(parent_text) + prefix = ( + f"LongMemEval session_id={session_id} date={date} " + f"parent_chunk={parent_index:02d}" + ) + payload_chars = subchunk_chars - len(prefix) - 1 + spans = covered_windows(parent_text, payload_chars, subchunk_overlap) + for subchunk_index, (char_start, char_end) in enumerate(spans, start=1): + text = f"{prefix}\n{parent_text[char_start:char_end]}" + if len(text) > subchunk_chars: + raise AssertionError(f"{qid}: generated subchunk exceeds configured character cap") + candidates.append( + { + "candidate_id": ( + f"chunk::longmemeval:{qid}:s{index:03d}_c{parent_index:02d}_p{subchunk_index:02d}" + ), + "text": text, + "session_id": session_id, + "session_index": index, + "parent_chunk_index": parent_index, + "subchunk_index": subchunk_index, + "source_char_start": char_start, + "source_char_end": char_end, + "labels": { + "relevance": relevant, + "hard_negative": False, + "evidence_role": "positive" if relevant else "negative", + "target_scope": "answer_session_bag", + }, + } + ) + if found_gold != answer_session_ids: + raise RuntimeError(f"{qid}: answer sessions missing from haystack: {sorted(answer_session_ids - found_gold)}") + return { + "schema_version": SCHEMA_VERSION, + "question_id": qid, + "question": question, + "question_date": question_date, + "query_text": query_text, + "question_type": clean_text(row.get("question_type")), + "split": split, + "gold_answer": clean_text(row.get("answer")), + "answer_session_ids": sorted(answer_session_ids), + "supervision": { + "target_type": "multi_instance_answer_session_bag", + "loss": "negative_log_positive_probability_mass", + }, + "inventory_metadata": { + "session_count": len(sessions), + "parent_chunk_count": parent_chunk_count, + "candidate_subchunk_count": len(candidates), + "source_parent_chars": source_parent_chars, + "parent_chars": parent_chars, + "subchunk_chars": subchunk_chars, + "subchunk_overlap": subchunk_overlap, + "truncated": False, + }, + "candidates": candidates, + } + + +def command_inventory(args: argparse.Namespace) -> None: + out_dir = Path(args.out_dir) + out_dir.mkdir(parents=True, exist_ok=False) + rows = load_lme(Path(args.data)) + holdout = set(choose_holdout(rows, args.holdout_count)) + inventory_rows = [ + make_inventory_row( + row, + "holdout" if clean_text(row.get("question_id")) in holdout else "train", + args.parent_chars, + args.subchunk_chars, + args.subchunk_overlap, + ) + for row in rows + ] + holdout_rows = [row for row in inventory_rows if row["split"] == "holdout"] + train_rows = [row for row in inventory_rows if row["split"] == "train"] + isolation = validate_split_isolation(train_rows, holdout_rows) + write_jsonl(out_dir / "inventory.jsonl", inventory_rows) + (out_dir / "holdout_qids.txt").write_text("\n".join(sorted(holdout)) + "\n", encoding="utf-8") + report = { + "schema_version": SCHEMA_VERSION, + "created_at": time.strftime("%Y-%m-%dT%H:%M:%S%z"), + "data": str(Path(args.data).resolve()), + "row_count": len(inventory_rows), + "train_count": len(train_rows), + "holdout_count": len(holdout_rows), + "candidate_count": sum(len(row["candidates"]) for row in inventory_rows), + "candidate_count_avg": round(sum(len(row["candidates"]) for row in inventory_rows) / len(inventory_rows), 4), + "parent_chunk_count": sum(row["inventory_metadata"]["parent_chunk_count"] for row in inventory_rows), + "session_count": sum(row["inventory_metadata"]["session_count"] for row in inventory_rows), + "positive_bag_candidate_count": sum( + int(candidate["labels"]["relevance"]) + for row in inventory_rows + for candidate in row["candidates"] + ), + "max_candidate_chars": max(len(candidate["text"]) for row in inventory_rows for candidate in row["candidates"]), + "truncated_candidate_count": 0, + "parent_chars": args.parent_chars, + "subchunk_chars": args.subchunk_chars, + "subchunk_overlap": args.subchunk_overlap, + "question_types": dict(Counter(row["question_type"] for row in inventory_rows)), + "holdout_question_types": dict(Counter(row["question_type"] for row in holdout_rows)), + "isolation": isolation, + } + (out_dir / "inventory_report.json").write_text(json.dumps(report, indent=2, sort_keys=True), encoding="utf-8") + print(json.dumps(report, indent=2, sort_keys=True)) + + +def load_graph_debug(run_dir: Path) -> dict[str, dict[str, Any]]: + output: dict[str, dict[str, Any]] = {} + paths = sorted(run_dir.glob("shard_*_out/samples_debug.jsonl")) + if not paths: + raise FileNotFoundError(f"no graph debug shards under {run_dir}") + for path in paths: + for row in read_jsonl(path): + qid = clean_text(row.get("question_id")) + if qid: + output[qid] = row + return output + + +def ordered_parent_locations( + event_ids: Iterable[Any], + *, + qid: str, + valid_locations: set[tuple[int, int]], +) -> list[tuple[int, int]]: + output: list[tuple[int, int]] = [] + seen: set[tuple[int, int]] = set() + for raw in event_ids: + event_id = clean_text(raw) + match = EVENT_INDEX_RE.match(event_id) + if match is None: + continue + if clean_text(match.group("qid")) != qid: + raise RuntimeError(f"{qid}: graph debug contains an event for another question: {event_id}") + location = (int(match.group("session")), int(match.group("parent"))) + if location not in valid_locations: + raise RuntimeError(f"{qid}: graph event has no exact parent chunk mapping: {event_id}") + if location in seen: + continue + seen.add(location) + output.append(location) + return output + + +def expand_parent_locations( + locations: Iterable[tuple[int, int]], + parent_candidates: Mapping[tuple[int, int], Sequence[int]], +) -> list[int]: + output: list[int] = [] + seen: set[int] = set() + for location in locations: + for index in parent_candidates[location]: + if index not in seen: + seen.add(index) + output.append(index) + return output + + +def rrank(rank: int | None) -> float: + return 0.0 if rank is None else 1.0 / float(rank + 1) + + +def canonical_candidate( + raw: Mapping[str, Any], + *, + relevant: bool, + session_relevant: bool, + teacher_relevant: bool | None, + dense_score: float, + dense_rank: int, + graph_rank: int | None, + graph_selected: bool, + graph_final: bool, + session_count: int, + forced_positive: bool, + hard_negative: bool, +) -> dict[str, Any]: + relevant = bool(relevant) + hard_negative = bool(hard_negative and not relevant) + channels = { + "dense_score": float(dense_score), + "dense_rank_rr": rrank(dense_rank), + "graph_rank_rr": rrank(graph_rank), + "graph_selected": float(bool(graph_selected)), + "graph_final": float(bool(graph_final)), + "recency_norm": float(raw["session_index"]) / float(max(1, session_count - 1)), + } + if tuple(channels.keys()) != CHANNEL_NAMES: + raise AssertionError("channel construction order changed") + return { + "candidate_id": raw["candidate_id"], + "text": raw["text"], + "session_id": raw["session_id"], + "session_index": int(raw["session_index"]), + "parent_chunk_index": int(raw["parent_chunk_index"]), + "subchunk_index": int(raw["subchunk_index"]), + "source_char_start": int(raw["source_char_start"]), + "source_char_end": int(raw["source_char_end"]), + "channels": channels, + "labels": { + "relevance": relevant, + "session_relevance": bool(session_relevant), + "teacher_evidence_relevance": teacher_relevant, + "hard_negative": hard_negative, + "evidence_role": "positive" if relevant else ("hard_negative" if hard_negative else "negative"), + "target_scope": "answer_session_bag", + }, + "provenance": { + "dense_retrieved": dense_rank >= 0, + "graph_retrieved": graph_rank is not None, + "graph_selected": bool(graph_selected), + "graph_final": bool(graph_final), + "forced_positive_for_training": bool(forced_positive), + }, + } + + +def metric_hit(order: Sequence[int], positives: set[int], k: int) -> int: + return int(any(index in positives for index in order[:k])) + + +def command_finalize(args: argparse.Namespace) -> None: + inventory_rows = read_jsonl(Path(args.inventory)) + graph_debug = load_graph_debug(Path(args.graph_debug_run)) + teacher_by_question = load_teacher_supervision(Path(args.teacher_labels)) + vectorizer = EmbeddingCacheVectorizer( + cache_dir=args.embedding_cache, + dim=args.text_dim, + expected_backend="hf", + expected_model=args.embedding_model, + ) + out_dir = Path(args.out_dir) + out_dir.mkdir(parents=True, exist_ok=False) + train_rows: list[dict[str, Any]] = [] + holdout_rows: list[dict[str, Any]] = [] + full_rows: list[dict[str, Any]] = [] + full_inventory_rows: list[dict[str, Any]] = [] + provider = Counter() + teacher_provider = Counter() + supervision_counts = Counter() + for source in inventory_rows: + qid = clean_text(source["question_id"]) + candidates = list(source["candidates"]) + session_count = int(source["inventory_metadata"]["session_count"]) + candidate_count = len(candidates) + parent_candidates: dict[tuple[int, int], list[int]] = {} + for index, candidate in enumerate(candidates): + location = (int(candidate["session_index"]), int(candidate["parent_chunk_index"])) + parent_candidates.setdefault(location, []).append(index) + valid_parent_locations = set(parent_candidates) + qvec = vectorizer.encode_one(source["query_text"]) + evec = torch.stack([vectorizer.encode_one(candidate["text"]) for candidate in candidates]) + dense_scores = (evec @ qvec).tolist() + dense_order = sorted(range(candidate_count), key=lambda index: (-dense_scores[index], index)) + dense_rank = {index: rank for rank, index in enumerate(dense_order)} + debug = graph_debug.get(qid, {}) + retrieval = dict(debug.get("retrieval") or {}) + selected_parents = ordered_parent_locations( + retrieval.get("selected_event_ids") or [], qid=qid, valid_locations=valid_parent_locations + ) + final_parents = ordered_parent_locations( + retrieval.get("final_hit_event_ids") or [], qid=qid, valid_locations=valid_parent_locations + ) + recall_parents = ordered_parent_locations( + retrieval.get("recall_event_ids") or [], qid=qid, valid_locations=valid_parent_locations + ) + graph_parents: list[tuple[int, int]] = [] + graph_parent_seen: set[tuple[int, int]] = set() + for location in [*selected_parents, *recall_parents]: + if location not in graph_parent_seen: + graph_parent_seen.add(location) + graph_parents.append(location) + graph_parent_rank = {location: rank for rank, location in enumerate(graph_parents)} + graph_order = expand_parent_locations(graph_parents, parent_candidates) + graph_rank = { + index: graph_parent_rank[(int(candidates[index]["session_index"]), int(candidates[index]["parent_chunk_index"]))] + for index in graph_order + } + selected_indexes = set(expand_parent_locations(selected_parents, parent_candidates)) + final_indexes = set(expand_parent_locations(final_parents, parent_candidates)) + session_positives = {index for index, candidate in enumerate(candidates) if candidate["labels"]["relevance"]} + teacher_row = teacher_by_question.get(normalized_question(source["question"])) + teacher_positives: set[int] | None = None + teacher_hard: set[int] = set() + if teacher_row is not None: + teacher_metadata = dict(teacher_row.get("metadata") or {}) + raw_teacher_positive = list(teacher_metadata.get("raw_teacher_positive_event_ids") or []) + raw_teacher_hard = list(teacher_metadata.get("raw_teacher_hard_negative_event_ids") or []) + if not raw_teacher_positive: + raise RuntimeError(f"{qid}: aligned teacher row is missing raw positive turn ids") + teacher_positives = teacher_turn_candidate_indexes( + raw_teacher_positive, + candidates=candidates, + parent_candidates=parent_candidates, + qid=qid, + ) + teacher_hard = teacher_turn_candidate_indexes( + raw_teacher_hard, + candidates=candidates, + parent_candidates=parent_candidates, + qid=qid, + ) + if not teacher_positives: + raise RuntimeError(f"{qid}: teacher supervision produced no positive subchunks") + mixed_teacher_subchunks = teacher_positives & teacher_hard + if mixed_teacher_subchunks: + supervision_counts["teacher_mixed_positive_hard_subchunks"] += len(mixed_teacher_subchunks) + teacher_hard -= teacher_positives + positives = teacher_positives + supervision = { + "target_type": "teacher_aligned_turn_bag", + "loss": "negative_log_positive_probability_mass", + "training_weight": float(teacher_row.get("training_weight_hint", 1.0) or 1.0), + "teacher_label_model": clean_text((teacher_row.get("metadata") or {}).get("teacher_label_model")), + "teacher_verify_model": clean_text((teacher_row.get("metadata") or {}).get("teacher_verify_model")), + "teacher_confidence": clean_text(teacher_row.get("label_confidence")), + } + else: + positives = session_positives + supervision = { + "target_type": "multi_instance_answer_session_bag", + "loss": "negative_log_positive_probability_mass", + "training_weight": float(args.weak_supervision_weight), + } + supervision_counts[supervision["target_type"]] += 1 + provider["n"] += 1 + for k in (1, 5, 10, 20, 32): + provider[f"primary_dense_r@{k}"] += metric_hit(dense_order, positives, k) + provider[f"primary_graph_r@{k}"] += metric_hit(graph_order, positives, k) + provider[f"session_dense_r@{k}"] += metric_hit(dense_order, session_positives, k) + provider[f"session_graph_r@{k}"] += metric_hit(graph_order, session_positives, k) + if teacher_positives is not None: + teacher_provider[f"dense_r@{k}"] += metric_hit(dense_order, teacher_positives, k) + teacher_provider[f"graph_r@{k}"] += metric_hit(graph_order, teacher_positives, k) + if teacher_positives is not None: + teacher_provider["n"] += 1 + runtime_indexes: list[int] = [] + runtime_seen: set[int] = set() + graph_runtime_order = expand_parent_locations(graph_parents[: args.graph_k], parent_candidates) + for index in [*dense_order[: args.dense_k], *graph_runtime_order]: + if index not in runtime_seen: + runtime_seen.add(index) + runtime_indexes.append(index) + provider["union_gold_hit"] += int(bool(positives & runtime_seen)) + provider["union_session_hit"] += int(bool(session_positives & runtime_seen)) + if teacher_positives is not None: + teacher_provider["union_hit"] += int(bool(teacher_positives & runtime_seen)) + pre_force_hit = bool(positives & runtime_seen) + training_indexes = list(runtime_indexes) + forced_indexes: set[int] = set() + if source["split"] == "train" and not pre_force_hit: + best_positive = next(index for index in dense_order if index in positives) + training_indexes.append(best_positive) + runtime_seen.add(best_positive) + forced_indexes.add(best_positive) + def build_row(indexes: Sequence[int], split: str, allow_forced: bool) -> dict[str, Any]: + output_candidates = [] + for index in indexes: + hard = index not in positives and ( + index in teacher_hard + or dense_rank[index] < args.hard_negative_k + or graph_rank.get(index, 10**9) < args.hard_negative_k + ) + output_candidates.append( + canonical_candidate( + candidates[index], + relevant=index in positives, + session_relevant=index in session_positives, + teacher_relevant=None if teacher_positives is None else index in teacher_positives, + dense_score=dense_scores[index], + dense_rank=dense_rank[index], + graph_rank=graph_rank.get(index), + graph_selected=index in selected_indexes, + graph_final=index in final_indexes, + session_count=session_count, + forced_positive=allow_forced and index in forced_indexes, + hard_negative=hard, + ) + ) + return { + "schema_version": SCHEMA_VERSION, + "question_id": qid, + "question": source["question"], + "question_date": source["question_date"], + "query_text": source["query_text"], + "question_type": source["question_type"], + "split": split, + "gold_answer": source["gold_answer"], + "answer_session_ids": source["answer_session_ids"], + "supervision": supervision, + "candidates": output_candidates, + "pool_metadata": { + "session_count": session_count, + "inventory_count": candidate_count, + "graph_parent_event_count": len(graph_parents), + "graph_runtime_candidate_count": len(graph_runtime_order), + "runtime_pool_count": len(runtime_indexes), + "pre_force_gold_hit": pre_force_hit, + "pre_force_session_hit": bool(session_positives & set(runtime_indexes)), + "pre_force_teacher_hit": None if teacher_positives is None else bool(teacher_positives & set(runtime_indexes)), + "forced_positive_count": len(forced_indexes) if allow_forced else 0, + "dense_k": args.dense_k, + "graph_k": args.graph_k, + "graph_debug_available": bool(debug), + "graph_retrieval_mode": retrieval.get("retrieval_mode"), + }, + } + runtime_row = build_row(runtime_indexes, "full_eval", False) + validate_sample(runtime_row, require_positive=False) + full_rows.append(runtime_row) + all_row = build_row(list(range(candidate_count)), "full_eval", False) + validate_sample(all_row, require_positive=True) + full_inventory_rows.append(all_row) + if source["split"] == "train": + train_row = build_row(training_indexes, "train", True) + validate_sample(train_row, require_positive=True) + train_rows.append(train_row) + else: + holdout_row = build_row(runtime_indexes, "holdout", False) + validate_sample(holdout_row, require_positive=False) + holdout_rows.append(holdout_row) + isolation = validate_split_isolation(train_rows, holdout_rows) + if len(train_rows) + len(holdout_rows) != len(inventory_rows): + raise RuntimeError("finalized row count mismatch") + write_jsonl(out_dir / "train.jsonl", train_rows) + write_jsonl(out_dir / "holdout.jsonl", holdout_rows) + write_jsonl(out_dir / "full_eval.jsonl", full_rows) + write_jsonl(out_dir / "full_inventory_eval.jsonl", full_inventory_rows) + if args.dev_count <= 0 or args.dev_count >= len(train_rows): + raise RuntimeError("dev_count must leave non-empty optimization train and dev sets") + ordered_train_qids = sorted( + (row["question_id"] for row in train_rows), + key=lambda qid: (stable_int(f"tmcra-v3-dev:{qid}"), qid), + ) + dev_qids = set(ordered_train_qids[: args.dev_count]) + model_train_rows = [row for row in train_rows if row["question_id"] not in dev_qids] + full_by_qid = {row["question_id"]: row for row in full_rows} + model_dev_rows = [full_by_qid[qid] for qid in ordered_train_qids[: args.dev_count]] + if any(row["pool_metadata"]["forced_positive_count"] for row in model_dev_rows): + raise RuntimeError("runtime dev rows must never contain forced positives") + write_jsonl(out_dir / "model_train.jsonl", model_train_rows) + write_jsonl(out_dir / "model_dev_runtime.jsonl", model_dev_rows) + (out_dir / "model_dev_qids.txt").write_text("\n".join(ordered_train_qids[: args.dev_count]) + "\n", encoding="utf-8") + cross_cache_rows = [*train_rows, *holdout_rows] + if len({row["question_id"] for row in cross_cache_rows}) != len(inventory_rows): + raise RuntimeError("cross-cache input must contain exactly one row per question") + write_jsonl(out_dir / "cross_cache_samples.jsonl", cross_cache_rows) + n = max(1, int(provider["n"])) + report = { + "schema_version": SCHEMA_VERSION, + "created_at": time.strftime("%Y-%m-%dT%H:%M:%S%z"), + "train_count": len(train_rows), + "holdout_count": len(holdout_rows), + "full_eval_count": len(full_rows), + "full_inventory_eval_count": len(full_inventory_rows), + "cross_cache_sample_count": len(cross_cache_rows), + "cross_cache_pair_count": sum(len(row["candidates"]) for row in cross_cache_rows), + "model_train_count": len(model_train_rows), + "model_dev_runtime_count": len(model_dev_rows), + "model_dev_runtime_candidate_miss_count": sum( + int(not any(candidate["labels"]["relevance"] for candidate in row["candidates"])) + for row in model_dev_rows + ), + "isolation": isolation, + "candidate_pool": { + "dense_k": args.dense_k, + "graph_k": args.graph_k, + "hard_negative_k": args.hard_negative_k, + "train_candidate_avg": round(sum(len(row["candidates"]) for row in train_rows) / max(1, len(train_rows)), 4), + "holdout_candidate_avg": round(sum(len(row["candidates"]) for row in holdout_rows) / max(1, len(holdout_rows)), 4), + "full_inventory_candidate_avg": round(sum(len(row["candidates"]) for row in full_inventory_rows) / max(1, len(full_inventory_rows)), 4), + "train_forced_positive_rows": sum(int(row["pool_metadata"]["forced_positive_count"] > 0) for row in train_rows), + }, + "provider_metrics": { + key: round(value / n, 6) for key, value in sorted(provider.items()) if key != "n" + }, + "teacher_provider_metrics": { + key: round(value / max(1, int(teacher_provider["n"])), 6) + for key, value in sorted(teacher_provider.items()) + if key != "n" + }, + "teacher_supervision_count": int(teacher_provider["n"]), + "supervision_counts": dict(supervision_counts), + "teacher_labels": str(Path(args.teacher_labels).resolve()), + "weak_supervision_weight": args.weak_supervision_weight, + "embedding_cache": str(Path(args.embedding_cache).resolve()), + "graph_debug_run": str(Path(args.graph_debug_run).resolve()), + } + (out_dir / "report.json").write_text(json.dumps(report, indent=2, sort_keys=True), encoding="utf-8") + print(json.dumps(report, indent=2, sort_keys=True)) + + +def main() -> int: + parser = argparse.ArgumentParser() + sub = parser.add_subparsers(dest="command", required=True) + inventory = sub.add_parser("inventory") + inventory.add_argument("--data", required=True) + inventory.add_argument("--out-dir", required=True) + inventory.add_argument("--holdout-count", type=int, default=100) + inventory.add_argument("--parent-chars", type=int, default=7000) + inventory.add_argument("--subchunk-chars", type=int, default=1800) + inventory.add_argument("--subchunk-overlap", type=int, default=200) + finalize = sub.add_parser("finalize") + finalize.add_argument("--inventory", required=True) + finalize.add_argument("--embedding-cache", required=True) + finalize.add_argument("--embedding-model", required=True) + finalize.add_argument("--graph-debug-run", required=True) + finalize.add_argument("--teacher-labels", required=True) + finalize.add_argument("--out-dir", required=True) + finalize.add_argument("--text-dim", type=int, default=1024) + finalize.add_argument("--dense-k", type=int, default=32) + finalize.add_argument("--graph-k", type=int, default=24) + finalize.add_argument("--hard-negative-k", type=int, default=12) + finalize.add_argument("--dev-count", type=int, default=40) + finalize.add_argument("--weak-supervision-weight", type=float, default=0.35) + args = parser.parse_args() + if args.command == "inventory": + command_inventory(args) + else: + command_finalize(args) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/__init__.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/__init__.py new file mode 100644 index 0000000..cc1c7ec --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/__init__.py @@ -0,0 +1,89 @@ +"""TMCRA core package exports. + +Keep package-level imports best-effort so focused submodules such as the +object-sketch trainer can run without pulling in every optional runtime +dependency from the broader app stack. +""" + +__all__ = [] + +try: + from .maze_engine import MazeEdge, MazeNode, MazePath, TriMazeEngine + + __all__.extend(["MazeNode", "MazeEdge", "MazePath", "TriMazeEngine"]) +except Exception: # pragma: no cover - optional dependency + MazeNode = None + MazeEdge = None + MazePath = None + TriMazeEngine = None + +try: + from .native_concept_extractor import NativeConceptExtractor, NativeExtractorConfig + + __all__.extend(["NativeConceptExtractor", "NativeExtractorConfig"]) +except Exception: # pragma: no cover - optional dependency + NativeConceptExtractor = None + NativeExtractorConfig = None + +try: + from .concept_graph import ConceptGraph + + __all__.append("ConceptGraph") +except Exception: # pragma: no cover - optional dependency + ConceptGraph = None + +try: + from .concept_memory import ConceptMemory + + __all__.append("ConceptMemory") +except Exception: # pragma: no cover - optional dependency + ConceptMemory = None + +try: + from .query_understanding import QueryUnderstandingLayer + + __all__.append("QueryUnderstandingLayer") +except Exception: # pragma: no cover - optional dependency + QueryUnderstandingLayer = None + +try: + from .gru_text_generator import GRUTextGenerator + + __all__.append("GRUTextGenerator") +except Exception: # pragma: no cover - optional dependency + GRUTextGenerator = None + +try: + from .policy_network import EdgePolicy + + __all__.append("EdgePolicy") +except Exception: # pragma: no cover - optional dependency + EdgePolicy = None + +try: + from .policy_dataset import ( + CurriculumConfig, + PolicyBatch, + PolicyStepDataset, + PolicyStepRecord, + PolicyVocabulary, + ) + from .policy_network import PolicyModelConfig + + __all__.extend( + [ + "CurriculumConfig", + "PolicyBatch", + "PolicyModelConfig", + "PolicyStepDataset", + "PolicyStepRecord", + "PolicyVocabulary", + ] + ) +except Exception: # pragma: no cover - optional dependency + CurriculumConfig = None + PolicyBatch = None + PolicyModelConfig = None + PolicyStepDataset = None + PolicyStepRecord = None + PolicyVocabulary = None diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer.py new file mode 100644 index 0000000..0e4d3da --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer.py @@ -0,0 +1,332 @@ +""" +Tri-Maze 高级渲染引擎 v1.0 +完善基础渲染能力,支持渐变、阴影、模糊、纹理、图层等效果 +完全模块化,与核心推理逻辑解耦 +""" +from PIL import Image, ImageDraw, ImageFilter, ImageChops +import numpy as np +import math +from typing import Tuple, List, Dict + +class AdvancedRenderer: + """ + 高级渲染引擎,支持丰富的图形效果 + 完全独立于核心推理逻辑,可单独升级完善 + """ + + def __init__(self, width: int = 1024, height: int = 768, bg_color: Tuple[int, int, int] = (255, 255, 255)): + self.width = width + self.height = height + self.layers = [] + self.current_layer = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + self.draw = ImageDraw.Draw(self.current_layer) + self.bg_color = bg_color + (255,) + + def create_layer(self) -> int: + """创建新图层""" + self.layers.append(self.current_layer) + self.current_layer = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) + self.draw = ImageDraw.Draw(self.current_layer) + return len(self.layers) + + def merge_layers(self) -> Image.Image: + """合并所有图层""" + final = Image.new("RGBA", (self.width, self.height), self.bg_color) + for layer in self.layers + [self.current_layer]: + final = Image.alpha_composite(final, layer) + return final.convert("RGB") + + # ===== 基础形状绘制 ===== + def draw_rectangle(self, x: int, y: int, width: int, height: int, + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1, + corner_radius: int = 0): + """绘制矩形,支持圆角""" + if corner_radius == 0: + self.draw.rectangle([x, y, x + width, y + height], fill=fill, outline=outline, width=stroke_width) + return + + # 圆角矩形 + radius = corner_radius + self.draw.ellipse([x, y, x + 2*radius, y + 2*radius], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x + width - 2*radius, y, x + width, y + 2*radius], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x, y + height - 2*radius, x + 2*radius, y + height], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x + width - 2*radius, y + height - 2*radius, x + width, y + height], fill=fill, outline=outline, width=stroke_width) + + self.draw.rectangle([x + radius, y, x + width - radius, y + height], fill=fill, outline=None) + self.draw.rectangle([x, y + radius, x + width, y + height - radius], fill=fill, outline=None) + + if outline: + self.draw.line([x + radius, y, x + width - radius, y], fill=outline, width=stroke_width) + self.draw.line([x + radius, y + height, x + width - radius, y + height], fill=outline, width=stroke_width) + self.draw.line([x, y + radius, x, y + height - radius], fill=outline, width=stroke_width) + self.draw.line([x + width, y + radius, x + width, y + height - radius], fill=outline, width=stroke_width) + + def draw_circle(self, x: int, y: int, radius: int, + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1): + """绘制圆形""" + self.draw.ellipse([x - radius, y - radius, x + radius, y + radius], + fill=fill, outline=outline, width=stroke_width) + + def draw_ellipse(self, x: int, y: int, width: int, height: int, + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1): + """绘制椭圆""" + self.draw.ellipse([x, y, x + width, y + height], + fill=fill, outline=outline, width=stroke_width) + + def draw_polygon(self, points: List[Tuple[int, int]], + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1): + """绘制多边形""" + self.draw.polygon(points, fill=fill, outline=outline, width=stroke_width) + + def draw_line(self, start: Tuple[int, int], end: Tuple[int, int], + color: Tuple[int, int, int, int] = (0, 0, 0, 255), + width: int = 1, + dashed: bool = False, + dash_length: int = 10): + """绘制直线,支持虚线""" + if not dashed: + self.draw.line([start, end], fill=color, width=width) + return + + # 虚线 + x1, y1 = start + x2, y2 = end + dx = x2 - x1 + dy = y2 - y1 + distance = math.hypot(dx, dy) + dashes = int(distance / dash_length) + + for i in range(dashes): + if i % 2 == 0: + s = i / dashes + e = (i + 1) / dashes + sx = x1 + dx * s + sy = y1 + dy * s + ex = x1 + dx * e + ey = y1 + dy * e + self.draw.line([(sx, sy), (ex, ey)], fill=color, width=width) + + def draw_bezier_curve(self, points: List[Tuple[int, int]], + color: Tuple[int, int, int, int] = (0, 0, 0, 255), + width: int = 1, + segments: int = 100): + """绘制贝塞尔曲线""" + if len(points) < 2: + return + + def bezier(t, points): + n = len(points) - 1 + x = 0 + y = 0 + for i, (px, py) in enumerate(points): + binom = math.comb(n, i) * (t ** i) * ((1 - t) ** (n - i)) + x += px * binom + y += py * binom + return (int(x), int(y)) + + curve_points = [] + for t in np.linspace(0, 1, segments): + curve_points.append(bezier(t, points)) + + for i in range(len(curve_points) - 1): + self.draw.line([curve_points[i], curve_points[i+1]], fill=color, width=width) + + # ===== 渐变效果 ===== + def draw_linear_gradient(self, x: int, y: int, width: int, height: int, + start_color: Tuple[int, int, int, int], + end_color: Tuple[int, int, int, int], + direction: str = "vertical"): + """绘制线性渐变""" + gradient = Image.new("RGBA", (width, height)) + draw = ImageDraw.Draw(gradient) + + if direction == "vertical": + for i in range(height): + ratio = i / height + r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) + g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) + b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) + a = int(start_color[3] * (1 - ratio) + end_color[3] * ratio) + draw.line([(0, i), (width, i)], fill=(r, g, b, a)) + elif direction == "horizontal": + for i in range(width): + ratio = i / width + r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) + g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) + b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) + a = int(start_color[3] * (1 - ratio) + end_color[3] * ratio) + draw.line([(i, 0), (i, height)], fill=(r, g, b, a)) + + self.current_layer.paste(gradient, (x, y), gradient) + + def draw_radial_gradient(self, x: int, y: int, radius: int, + center_color: Tuple[int, int, int, int], + edge_color: Tuple[int, int, int, int]): + """绘制径向渐变(光晕效果)""" + size = radius * 2 + gradient = Image.new("RGBA", (size, size)) + draw = ImageDraw.Draw(gradient) + + for r in range(radius, 0, -1): + ratio = r / radius + rc = int(center_color[0] * ratio + edge_color[0] * (1 - ratio)) + gc = int(center_color[1] * ratio + edge_color[1] * (1 - ratio)) + bc = int(center_color[2] * ratio + edge_color[2] * (1 - ratio)) + ac = int(center_color[3] * ratio + edge_color[3] * (1 - ratio)) + draw.ellipse([radius - r, radius - r, radius + r, radius + r], + fill=(rc, gc, bc, ac)) + + self.current_layer.paste(gradient, (x - radius, y - radius), gradient) + + # ===== 效果滤镜 ===== + def apply_blur(self, radius: float = 2.0, layer_index: int = None): + """应用模糊效果""" + if layer_index is None: + self.current_layer = self.current_layer.filter(ImageFilter.GaussianBlur(radius)) + else: + self.layers[layer_index] = self.layers[layer_index].filter(ImageFilter.GaussianBlur(radius)) + + def apply_shadow(self, offset: Tuple[int, int] = (5, 5), blur_radius: float = 5.0, + color: Tuple[int, int, int, int] = (0, 0, 0, 100), + layer_index: int = None): + """应用阴影效果""" + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + + # 创建阴影层 + shadow = Image.new("RGBA", target_layer.size, (0, 0, 0, 0)) + alpha = target_layer.getchannel("A") + shadow.paste(color, mask=alpha) + shadow = shadow.filter(ImageFilter.GaussianBlur(blur_radius)) + + # 合并阴影和原图层 + result = Image.new("RGBA", target_layer.size, (0, 0, 0, 0)) + result.paste(shadow, offset, shadow) + result = Image.alpha_composite(result, target_layer) + + if layer_index is None: + self.current_layer = result + else: + self.layers[layer_index] = result + + def apply_glow(self, blur_radius: float = 10.0, color: Tuple[int, int, int, int] = (255, 255, 200, 150), + layer_index: int = None): + """应用发光效果""" + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + + # 创建发光层 + glow = Image.new("RGBA", target_layer.size, (0, 0, 0, 0)) + alpha = target_layer.getchannel("A") + glow.paste(color, mask=alpha) + glow = glow.filter(ImageFilter.GaussianBlur(blur_radius)) + + # 合并发光和原图层 + result = Image.alpha_composite(glow, target_layer) + + if layer_index is None: + self.current_layer = result + else: + self.layers[layer_index] = result + + def apply_noise(self, amount: float = 0.1, monochrome: bool = False, layer_index: int = None): + """应用噪点纹理效果""" + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + np_img = np.array(target_layer) + + if monochrome: + noise = np.random.normal(0, amount * 255, np_img.shape[:2]) + np_img[..., :3] = np.clip(np_img[..., :3] + noise[..., np.newaxis], 0, 255) + else: + noise = np.random.normal(0, amount * 255, np_img.shape) + np_img[..., :3] = np.clip(np_img[..., :3] + noise[..., :3], 0, 255) + + result = Image.fromarray(np_img.astype(np.uint8), "RGBA") + + if layer_index is None: + self.current_layer = result + else: + self.layers[layer_index] = result + + # ===== 变换 ===== + def rotate_layer(self, angle: float, expand: bool = False, layer_index: int = None): + """旋转图层""" + if layer_index is None: + self.current_layer = self.current_layer.rotate(angle, expand=expand, resample=Image.Resampling.BILINEAR) + else: + self.layers[layer_index] = self.layers[layer_index].rotate(angle, expand=expand, resample=Image.Resampling.BILINEAR) + + def scale_layer(self, scale_x: float, scale_y: float = None, layer_index: int = None): + """缩放图层""" + if scale_y is None: + scale_y = scale_x + + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + new_width = int(target_layer.width * scale_x) + new_height = int(target_layer.height * scale_y) + resized = target_layer.resize((new_width, new_height), resample=Image.Resampling.LANCZOS) + + if layer_index is None: + self.current_layer = resized + else: + self.layers[layer_index] = resized + + def translate_layer(self, dx: int, dy: int, layer_index: int = None): + """平移图层""" + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + translated = Image.new("RGBA", target_layer.size, (0, 0, 0, 0)) + translated.paste(target_layer, (dx, dy), target_layer) + + if layer_index is None: + self.current_layer = translated + else: + self.layers[layer_index] = translated + + +# 示例使用 +if __name__ == "__main__": + # 创建渲染器 + renderer = AdvancedRenderer(800, 600, bg_color=(10, 20, 40)) + + # 背景渐变 + renderer.draw_linear_gradient(0, 0, 800, 600, + start_color=(10, 20, 40, 255), + end_color=(30, 50, 80, 255), + direction="vertical") + + # 新建图层画月亮 + renderer.create_layer() + renderer.draw_radial_gradient(650, 150, 80, + center_color=(255, 255, 220, 255), + edge_color=(255, 255, 220, 0)) + renderer.draw_circle(650, 150, 50, fill=(255, 255, 220, 255)) + + # 新建图层画荷花 + renderer.create_layer() + # 花茎 + renderer.draw_line((200, 300), (200, 500), color=(0, 100, 0, 255), width=4) + # 花瓣 + for angle in range(0, 360, 30): + rad = math.radians(angle) + x = 200 + math.cos(rad) * 40 + y = 300 + math.sin(rad) * 60 + renderer.draw_ellipse(x - 15, y - 30, x + 15, y + 30, + fill=(255, 150, 180, 220), + outline=(200, 80, 120, 255), + stroke_width=1) + # 花心 + renderer.draw_circle(200, 300, 20, fill=(255, 200, 100, 255)) + + # 应用阴影 + renderer.apply_shadow(offset=(3, 3), blur_radius=5.0, layer_index=1) + + # 合并图层并保存 + final_image = renderer.merge_layers() + final_image.save("渲染引擎测试.png") + print("✅ 高级渲染引擎测试完成,图片已保存为 渲染引擎测试.png") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer_v2.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer_v2.py new file mode 100644 index 0000000..b394324 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/advanced_renderer_v2.py @@ -0,0 +1,407 @@ +""" +Tri-Maze 高级渲染引擎 v2.0 +扩展优化版,增加更多高级特效、3D效果、材质系统、粒子系统 +""" +from PIL import Image, ImageDraw, ImageFilter, ImageChops, ImageOps +import numpy as np +import math +from typing import Tuple, List, Dict, Optional +import random + +class AdvancedRendererV2: + """ + 高级渲染引擎v2.0,扩展优化版 + 增加3D效果、材质系统、粒子系统、高级滤镜等 + """ + + def __init__(self, width: int = 1024, height: int = 768, bg_color: Tuple[int, int, int] = (255, 255, 255)): + self.width = width + self.height = height + self.layers = [] + self.current_layer = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + self.draw = ImageDraw.Draw(self.current_layer) + self.bg_color = bg_color + (255,) + self.light_sources = [] # 光源列表,支持3D光照 + + def create_layer(self) -> int: + """创建新图层""" + self.layers.append(self.current_layer) + self.current_layer = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) + self.draw = ImageDraw.Draw(self.current_layer) + return len(self.layers) + + def merge_layers(self) -> Image.Image: + """合并所有图层,支持光照计算""" + final = Image.new("RGBA", (self.width, self.height), self.bg_color) + + # 应用全局光照 + if self.light_sources: + final = self._apply_global_lighting(final) + + for layer in self.layers + [self.current_layer]: + final = Image.alpha_composite(final, layer) + + return final.convert("RGB") + + # ===== 光照系统 ===== + def add_light_source(self, x: int, y: int, intensity: float = 1.0, + color: Tuple[int, int, int] = (255, 255, 255), + radius: int = 300): + """添加光源,支持3D光照效果""" + self.light_sources.append({ + "x": x, + "y": y, + "intensity": intensity, + "color": color, + "radius": radius + }) + + def _apply_global_lighting(self, image: Image.Image) -> Image.Image: + """应用全局光照效果""" + light_layer = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) + draw = ImageDraw.Draw(light_layer) + + for light in self.light_sources: + # 径向渐变光晕 + for r in range(light["radius"], 0, -10): + ratio = r / light["radius"] + alpha = int(200 * light["intensity"] * (1 - ratio)) + if alpha <= 0: + break + color = ( + int(light["color"][0] * (1 - ratio * 0.7)), + int(light["color"][1] * (1 - ratio * 0.7)), + int(light["color"][2] * (1 - ratio * 0.7)), + alpha + ) + draw.ellipse( + [light["x"] - r, light["y"] - r, + light["x"] + r, light["y"] + r], + fill=color + ) + + # 屏幕混合模式 + return ImageChops.screen(image, light_layer) + + # ===== 3D效果 ===== + def draw_3d_cube(self, x: int, y: int, size: int, + face_colors: List[Tuple[int, int, int, int]] = None, + rotation: float = 0.5): + """绘制3D立方体""" + if face_colors is None: + face_colors = [ + (200, 200, 200, 255), # 前面 + (150, 150, 150, 255), # 侧面 + (100, 100, 100, 255) # 顶面 + ] + + # 立方体顶点坐标(透视投影) + z = size * 0.5 + points = [ + # 前面四个点 + (x - size, y - size, z), + (x + size, y - size, z), + (x + size, y + size, z), + (x - size, y + size, z), + # 后面四个点 + (x - size + size*rotation, y - size - size*rotation, -z), + (x + size + size*rotation, y - size - size*rotation, -z), + (x + size + size*rotation, y + size - size*rotation, -z), + (x - size + size*rotation, y + size - size*rotation, -z), + ] + + # 投影到2D平面 + projected = [] + for px, py, pz in points: + scale = 1 + (pz / (size * 3)) + projected.append((int(px * scale), int(py * scale))) + + # 绘制面 + faces = [ + ([0, 1, 2, 3], face_colors[0]), # 前面 + ([1, 5, 6, 2], face_colors[1]), # 右面 + ([0, 4, 7, 3], face_colors[1]), # 左面 + ([4, 5, 6, 7], face_colors[2]), # 后面 + ([0, 1, 5, 4], face_colors[2]), # 顶面 + ([3, 2, 6, 7], face_colors[1]), # 底面 + ] + + # 按z轴排序,远处的面先画 + faces.sort(key=lambda f: sum(points[i][2] for i in f[0])/4) + + for face_indices, color in faces: + face_points = [projected[i] for i in face_indices] + self.draw.polygon(face_points, fill=color, outline=(50, 50, 50, 255), width=1) + + def draw_3d_sphere(self, x: int, y: int, radius: int, + color: Tuple[int, int, int, int] = (100, 150, 255, 255), + light_pos: Tuple[int, int] = None): + """绘制3D球体,带光照效果""" + if light_pos is None: + light_pos = (x - radius//2, y - radius//2) + + # 径向渐变模拟3D效果 + for r in range(radius, 0, -1): + # 计算光照 + dx = light_pos[0] - x + dy = light_pos[1] - y + distance = math.hypot(dx, dy) + light_ratio = 1 - (r / radius) * 0.7 + + r_color = int(color[0] * light_ratio) + g_color = int(color[1] * light_ratio) + b_color = int(color[2] * light_ratio) + + self.draw.ellipse( + [x - r, y - r, x + r, y + r], + fill=(r_color, g_color, b_color, color[3]) + ) + + # 高光 + highlight_radius = radius // 5 + highlight_x = x - radius//3 + highlight_y = y - radius//3 + self.draw.ellipse( + [highlight_x - highlight_radius, highlight_y - highlight_radius, + highlight_x + highlight_radius, highlight_y + highlight_radius], + fill=(255, 255, 255, 180) + ) + + # ===== 材质系统 ===== + def apply_material(self, layer_index: int = None, material_type: str = "glass"): + """应用材质效果""" + target_layer = self.current_layer if layer_index is None else self.layers[layer_index] + + if material_type == "glass": + # 玻璃材质:透明+模糊+高光 + blurred = target_layer.filter(ImageFilter.GaussianBlur(2)) + result = Image.blend(target_layer, blurred, 0.3) + # 添加高光 + highlight = Image.new("RGBA", target_layer.size, (255, 255, 255, 30)) + result = Image.alpha_composite(result, highlight) + + elif material_type == "metal": + # 金属材质:高对比度+反光 + np_img = np.array(target_layer) + np_img[..., :3] = np.clip(np_img[..., :3] * 1.3, 0, 255) + result = Image.fromarray(np_img.astype(np.uint8), "RGBA") + # 添加反光 + edge = ImageOps.expand(target_layer, border=2, fill=(255, 255, 255, 100)) + result.paste(edge, (0, 0), edge) + + elif material_type == "wood": + # 木质材质:木纹纹理+暖色调 + noise = np.random.normal(0, 15, target_layer.size + (3,)) + np_img = np.array(target_layer) + np_img[..., :3] = np.clip(np_img[..., :3] + noise, 0, 255) + # 暖色调 + np_img[..., 0] = np.clip(np_img[..., 0] * 1.2, 0, 255) + np_img[..., 1] = np.clip(np_img[..., 1] * 1.1, 0, 255) + np_img[..., 2] = np.clip(np_img[..., 2] * 0.8, 0, 255) + result = Image.fromarray(np_img.astype(np.uint8), "RGBA") + + else: # 默认材质 + result = target_layer + + if layer_index is None: + self.current_layer = result + else: + self.layers[layer_index] = result + + # ===== 粒子系统 ===== + def draw_particle_system(self, x: int, y: int, count: int = 50, + particle_color: Tuple[int, int, int, int] = (255, 200, 100, 200), + spread: int = 100, + particle_size: Tuple[int, int] = (2, 6)): + """绘制粒子系统,用于火焰、星光、烟雾等效果""" + for _ in range(count): + # 随机位置 + offset_x = random.randint(-spread, spread) + offset_y = random.randint(-spread, spread) + px = x + offset_x + py = y + offset_y + + # 随机大小 + size = random.randint(particle_size[0], particle_size[1]) + + # 随机透明度 + alpha = random.randint(100, particle_color[3]) + color = (particle_color[0], particle_color[1], particle_color[2], alpha) + + # 绘制粒子 + self.draw_circle(px, py, size, fill=color) + + # ===== 高级滤镜 ===== + def apply_vignette(self, intensity: float = 0.5): + """应用暗角效果""" + vignette = Image.new("L", (self.width, self.height), 0) + draw = ImageDraw.Draw(vignette) + + for r in range(max(self.width, self.height), 0, -10): + brightness = int(255 * (1 - intensity * (1 - r / max(self.width, self.height)))) + draw.ellipse( + [self.width//2 - r, self.height//2 - r, + self.width//2 + r, self.height//2 + r], + fill=brightness + ) + + # 应用暗角到所有图层 + for i in range(len(self.layers)): + layer = self.layers[i] + layer.putalpha(vignette) + self.layers[i] = layer + + current_vignette = Image.new("RGBA", (self.width, self.height)) + current_vignette.putalpha(vignette) + self.current_layer = Image.alpha_composite(self.current_layer, current_vignette) + + def apply_color_grading(self, brightness: float = 1.0, contrast: float = 1.0, + saturation: float = 1.0, temperature: float = 0.0): + """应用色彩分级,调整亮度、对比度、饱和度、色温""" + np_img = np.array(self.current_layer) + + # 亮度调整 + np_img[..., :3] = np.clip(np_img[..., :3] * brightness, 0, 255) + + # 对比度调整 + mean = np.mean(np_img[..., :3]) + np_img[..., :3] = np.clip((np_img[..., :3] - mean) * contrast + mean, 0, 255) + + # 色温调整 + if temperature > 0: # 暖色调 + np_img[..., 0] = np.clip(np_img[..., 0] * (1 + temperature), 0, 255) + np_img[..., 2] = np.clip(np_img[..., 2] * (1 - temperature), 0, 255) + else: # 冷色调 + np_img[..., 0] = np.clip(np_img[..., 0] * (1 + temperature), 0, 255) + np_img[..., 2] = np.clip(np_img[..., 2] * (1 - temperature), 0, 255) + + self.current_layer = Image.fromarray(np_img.astype(np.uint8), "RGBA") + + def apply_bloom(self, threshold: int = 200, blur_radius: float = 10.0): + """应用 Bloom 发光效果,亮部溢出""" + # 提取亮部 + np_img = np.array(self.current_layer) + bright_mask = (np_img[..., 0] > threshold) & (np_img[..., 1] > threshold) & (np_img[..., 2] > threshold) + bright_parts = np.zeros_like(np_img) + bright_parts[bright_mask] = np_img[bright_mask] + + bright_layer = Image.fromarray(bright_parts.astype(np.uint8), "RGBA") + blurred_bright = bright_layer.filter(ImageFilter.GaussianBlur(blur_radius)) + + # 混合发光效果 + self.current_layer = Image.alpha_composite(self.current_layer, blurred_bright) + + # ===== 基础形状(继承v1版并增强) ===== + def draw_rectangle(self, x: int, y: int, width: int, height: int, + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1, + corner_radius: int = 0): + """绘制矩形,支持圆角""" + if corner_radius == 0: + self.draw.rectangle([x, y, x + width, y + height], fill=fill, outline=outline, width=stroke_width) + return + + # 圆角矩形 + radius = corner_radius + self.draw.ellipse([x, y, x + 2*radius, y + 2*radius], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x + width - 2*radius, y, x + width, y + 2*radius], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x, y + height - 2*radius, x + 2*radius, y + height], fill=fill, outline=outline, width=stroke_width) + self.draw.ellipse([x + width - 2*radius, y + height - 2*radius, x + width, y + height], fill=fill, outline=outline, width=stroke_width) + + self.draw.rectangle([x + radius, y, x + width - radius, y + height], fill=fill, outline=None) + self.draw.rectangle([x, y + radius, x + width, y + height - radius], fill=fill, outline=None) + + if outline: + self.draw.line([x + radius, y, x + width - radius, y], fill=outline, width=stroke_width) + self.draw.line([x + radius, y + height, x + width - radius, y + height], fill=outline, width=stroke_width) + self.draw.line([x, y + radius, x, y + height - radius], fill=outline, width=stroke_width) + self.draw.line([x + width, y + radius, x + width, y + height - radius], fill=outline, width=stroke_width) + + def draw_circle(self, x: int, y: int, radius: int, + fill: Tuple[int, int, int, int] = (255, 255, 255, 255), + outline: Tuple[int, int, int, int] = None, + stroke_width: int = 1): + """绘制圆形""" + self.draw.ellipse([x - radius, y - radius, x + radius, y + radius], + fill=fill, outline=outline, width=stroke_width) + + def draw_linear_gradient(self, x: int, y: int, width: int, height: int, + start_color: Tuple[int, int, int, int], + end_color: Tuple[int, int, int, int], + direction: str = "vertical"): + """绘制线性渐变""" + gradient = Image.new("RGBA", (width, height)) + draw = ImageDraw.Draw(gradient) + + if direction == "vertical": + for i in range(height): + ratio = i / height + r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) + g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) + b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) + a = int(start_color[3] * (1 - ratio) + end_color[3] * ratio) + draw.line([(0, i), (width, i)], fill=(r, g, b, a)) + elif direction == "horizontal": + for i in range(width): + ratio = i / width + r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio) + g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio) + b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio) + a = int(start_color[3] * (1 - ratio) + end_color[3] * ratio) + draw.line([(i, 0), (i, height)], fill=(r, g, b, a)) + + self.current_layer.paste(gradient, (x, y), gradient) + + def draw_radial_gradient(self, x: int, y: int, radius: int, + center_color: Tuple[int, int, int, int], + edge_color: Tuple[int, int, int, int]): + """绘制径向渐变""" + size = radius * 2 + gradient = Image.new("RGBA", (size, size)) + draw = ImageDraw.Draw(gradient) + + for r in range(radius, 0, -1): + ratio = r / radius + rc = int(center_color[0] * ratio + edge_color[0] * (1 - ratio)) + gc = int(center_color[1] * ratio + edge_color[1] * (1 - ratio)) + bc = int(center_color[2] * ratio + edge_color[2] * (1 - ratio)) + ac = int(center_color[3] * ratio + edge_color[3] * (1 - ratio)) + draw.ellipse([radius - r, radius - r, radius + r, radius + r], + fill=(rc, gc, bc, ac)) + + self.current_layer.paste(gradient, (x - radius, y - radius), gradient) + + +# 示例测试 +if __name__ == "__main__": + renderer = AdvancedRendererV2(800, 600, bg_color=(10, 20, 40)) + + # 添加光源 + renderer.add_light_source(600, 100, intensity=0.8, color=(255, 255, 200)) + + # 背景渐变 + renderer.draw_linear_gradient(0, 0, 800, 600, + start_color=(10, 20, 40, 255), + end_color=(30, 50, 80, 255)) + + # 3D球体 + renderer.create_layer() + renderer.draw_3d_sphere(200, 300, 80, color=(255, 100, 100, 255)) + + # 3D立方体 + renderer.create_layer() + renderer.draw_3d_cube(400, 300, 60, rotation=0.3) + + # 粒子系统 + renderer.create_layer() + renderer.draw_particle_system(600, 300, count=80, particle_color=(255, 200, 100, 200), spread=80) + + # 应用效果 + renderer.apply_bloom(threshold=180, blur_radius=8.0) + renderer.apply_vignette(intensity=0.4) + + # 保存 + final = renderer.merge_layers() + final.save("渲染引擎v2测试.png") + print("✅ 高级渲染引擎v2测试完成,图片已保存为 渲染引擎v2测试.png") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/comfyui_client.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/comfyui_client.py new file mode 100644 index 0000000..b9fee78 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/comfyui_client.py @@ -0,0 +1,670 @@ +from __future__ import annotations + +import mimetypes +import os +import random +import time +import uuid +from pathlib import Path +from typing import Any, Dict, Optional +from urllib.parse import quote + +import requests + + +class ComfyUIClient: + def __init__(self, api_url: str = "", output_dir: str = "outputs") -> None: + self.api_url = str(api_url or "").strip().rstrip("/") + self.output_dir = output_dir + Path(self.output_dir).mkdir(parents=True, exist_ok=True) + self._is_comfyui: Optional[bool] = None + self._checkpoint_cache: list[str] | None = None + self._lora_cache: list[str] | None = None + self._controlnet_cache: list[str] | None = None + + def set_api_url(self, api_url: str) -> None: + self.api_url = str(api_url or "").strip().rstrip("/") + self._is_comfyui = None + self._checkpoint_cache = None + self._lora_cache = None + self._controlnet_cache = None + + @property + def available(self) -> bool: + return self.api_url.startswith("http") + + def is_comfyui_server(self) -> bool: + if not self.available: + return False + if self._is_comfyui is not None: + return self._is_comfyui + try: + response = requests.get(f"{self.api_url}/system_stats", timeout=5) + self._is_comfyui = response.ok and "application/json" in response.headers.get("Content-Type", "") + except Exception: + self._is_comfyui = False + return bool(self._is_comfyui) + + def _sampler_config(self, sampler_name: str | None = None) -> tuple[str, str]: + sampler = str(sampler_name or "").strip().lower() + mapping = { + "dpm++ 2m karras": ("dpmpp_2m", "karras"), + "dpm++ sde karras": ("dpmpp_sde", "karras"), + "euler": ("euler", "normal"), + "euler a": ("euler_ancestral", "normal"), + "heun": ("heun", "normal"), + "ddim": ("ddim", "normal"), + } + return mapping.get(sampler, ("dpmpp_2m", "karras")) + + def _sanitize_dimension(self, value: int, minimum: int = 512) -> int: + value = max(minimum, int(value or minimum)) + return max(64, (value // 64) * 64) + + def _request_json(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]: + response = requests.request(method, f"{self.api_url}{path}", timeout=kwargs.pop("timeout", 60), **kwargs) + response.raise_for_status() + payload = response.json() + return payload if isinstance(payload, dict) else {} + + def _extract_choice_names(self, payload: Dict[str, Any], node_name: str, field_name: str) -> list[str]: + if node_name in payload and isinstance(payload[node_name], dict): + payload = payload[node_name] + required = ((payload.get("input") or {}).get("required") or {}).get(field_name) + if isinstance(required, list) and required and isinstance(required[0], list): + return [str(item) for item in required[0] if str(item).strip() and "put_" not in str(item)] + if isinstance(required, list): + return [str(item) for item in required if str(item).strip() and "put_" not in str(item)] + return [] + + def get_available_checkpoints(self) -> list[str]: + if self._checkpoint_cache is not None: + return list(self._checkpoint_cache) + if not self.is_comfyui_server(): + self._checkpoint_cache = [] + return [] + try: + payload = self._request_json("GET", "/object_info/CheckpointLoaderSimple", timeout=15) + except Exception: + self._checkpoint_cache = [] + return [] + self._checkpoint_cache = self._extract_choice_names(payload, "CheckpointLoaderSimple", "ckpt_name") + return list(self._checkpoint_cache) + + def get_available_loras(self) -> list[str]: + if self._lora_cache is not None: + return list(self._lora_cache) + if not self.is_comfyui_server(): + self._lora_cache = [] + return [] + try: + payload = self._request_json("GET", "/object_info/LoraLoader", timeout=15) + except Exception: + self._lora_cache = [] + return [] + self._lora_cache = self._extract_choice_names(payload, "LoraLoader", "lora_name") + return list(self._lora_cache) + + def get_available_controlnets(self) -> list[str]: + if self._controlnet_cache is not None: + return list(self._controlnet_cache) + if not self.is_comfyui_server(): + self._controlnet_cache = [] + return [] + try: + payload = self._request_json("GET", "/object_info/ControlNetLoader", timeout=15) + except Exception: + self._controlnet_cache = [] + return [] + self._controlnet_cache = self._extract_choice_names(payload, "ControlNetLoader", "control_net_name") + return list(self._controlnet_cache) + + def pick_checkpoint(self, preferred_name: str | None = None) -> str: + checkpoints = self.get_available_checkpoints() + if preferred_name: + marker = str(preferred_name).strip().casefold() + for name in checkpoints: + if name.casefold() == marker: + return name + for name in checkpoints: + if marker in name.casefold(): + return name + for matcher in ("sd_xl_base_1.0", "xl_base", "sdxl", "base"): + for name in checkpoints: + if matcher in name.casefold(): + return name + if checkpoints: + return checkpoints[0] + raise RuntimeError("ComfyUI 未返回可用 checkpoint") + + def pick_lora(self, preferred_name: str | None = None) -> str: + loras = self.get_available_loras() + if preferred_name: + marker = str(preferred_name).strip().casefold() + for name in loras: + if name.casefold() == marker: + return name + for name in loras: + if marker in name.casefold(): + return name + if loras: + return loras[0] + raise RuntimeError("ComfyUI 未返回可用 LoRA") + + def pick_controlnet(self, preferred_name: str | list[str] | None = None) -> str: + controlnets = self.get_available_controlnets() + preferred: list[str] = [] + if isinstance(preferred_name, list): + preferred = [str(item).strip().casefold() for item in preferred_name if str(item).strip()] + elif preferred_name: + preferred = [str(preferred_name).strip().casefold()] + for marker in preferred: + for name in controlnets: + if name.casefold() == marker: + return name + for name in controlnets: + if marker in name.casefold(): + return name + for matcher in ("canny", "sketch", "scribble", "lineart", "depth"): + for name in controlnets: + if matcher in name.casefold(): + return name + if controlnets: + return controlnets[0] + raise RuntimeError("ComfyUI 未返回可用 ControlNet/T2I 模型") + + def upload_image(self, image_path: str, *, overwrite: bool = True) -> str: + mime_type = mimetypes.guess_type(image_path)[0] or "image/png" + with open(image_path, "rb") as handle: + response = requests.post( + f"{self.api_url}/upload/image", + files={"image": (os.path.basename(image_path), handle, mime_type)}, + data={"overwrite": "true" if overwrite else "false"}, + timeout=180, + ) + response.raise_for_status() + payload = response.json() + name = str(payload.get("name") or "").strip() + subfolder = str(payload.get("subfolder") or "").strip() + return f"{subfolder}/{name}".strip("/") if subfolder else name + + def _submit_prompt(self, workflow: Dict[str, Any]) -> str: + payload = { + "prompt": workflow, + "client_id": uuid.uuid4().hex, + } + response = requests.post(f"{self.api_url}/prompt", json=payload, timeout=60) + response.raise_for_status() + result = response.json() + prompt_id = str(result.get("prompt_id") or "").strip() + if not prompt_id: + raise RuntimeError("ComfyUI 未返回 prompt_id") + return prompt_id + + def _history_outputs(self, prompt_id: str) -> Dict[str, Any]: + payload = self._request_json("GET", f"/history/{quote(prompt_id, safe='')}", timeout=30) + if prompt_id in payload and isinstance(payload[prompt_id], dict): + return payload[prompt_id] + return payload + + def _wait_for_image_descriptor(self, prompt_id: str, *, timeout_seconds: int = 600) -> Dict[str, Any]: + deadline = time.time() + max(30, timeout_seconds) + while time.time() < deadline: + history = self._history_outputs(prompt_id) + outputs = history.get("outputs") or {} + for node_output in outputs.values(): + if not isinstance(node_output, dict): + continue + images = node_output.get("images") or [] + if images and isinstance(images[0], dict): + return images[0] + status = history.get("status") or {} + completed = ((status.get("status_str") or "") == "success") or bool(status.get("completed") is True) + if completed: + break + time.sleep(1.2) + raise TimeoutError("ComfyUI 生成超时或未返回图片") + + def _download_image(self, descriptor: Dict[str, Any], output_name: str) -> str: + filename = str(descriptor.get("filename") or "").strip() + if not filename: + raise RuntimeError("ComfyUI 返回图片描述缺少 filename") + params = { + "filename": filename, + "subfolder": str(descriptor.get("subfolder") or ""), + "type": str(descriptor.get("type") or "output"), + } + response = requests.get(f"{self.api_url}/view", params=params, timeout=180) + response.raise_for_status() + extension = os.path.splitext(filename)[1] or ".png" + output_path = os.path.join(self.output_dir, f"{output_name}{extension}") + with open(output_path, "wb") as handle: + handle.write(response.content) + return output_path + + def _workflow_refs( + self, + workflow: Dict[str, Any], + *, + checkpoint: str, + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + lora_node_id: str = "90", + ) -> tuple[list[Any], list[Any]]: + workflow["1"] = {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": checkpoint}} + if str(lora_name or "").strip(): + workflow[lora_node_id] = { + "class_type": "LoraLoader", + "inputs": { + "model": ["1", 0], + "clip": ["1", 1], + "lora_name": self.pick_lora(lora_name), + "strength_model": float(lora_strength_model), + "strength_clip": float(lora_strength_clip), + }, + } + return [lora_node_id, 0], [lora_node_id, 1] + return ["1", 0], ["1", 1] + + def render_img2img( + self, + *, + prompt: str, + negative_prompt: str, + control_image_path: str, + width: int, + height: int, + steps: int, + cfg_scale: float, + denoising_strength: float, + sampler_name: str = "", + filename_prefix: str = "comfy_img2img", + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + uploaded_name = self.upload_image(control_image_path) + checkpoint = self.pick_checkpoint(checkpoint_name) + sampler, scheduler = self._sampler_config(sampler_name) + workflow: Dict[str, Any] = {} + model_ref, clip_ref = self._workflow_refs( + workflow, + checkpoint=checkpoint, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + workflow.update( + { + "2": {"class_type": "LoadImage", "inputs": {"image": uploaded_name}}, + "3": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": clip_ref}}, + "4": {"class_type": "CLIPTextEncode", "inputs": {"text": negative_prompt, "clip": clip_ref}}, + "5": {"class_type": "VAEEncode", "inputs": {"pixels": ["2", 0], "vae": ["1", 2]}}, + "6": { + "class_type": "KSampler", + "inputs": { + "seed": random.randint(1, 2**31 - 1), + "steps": max(1, int(steps)), + "cfg": float(cfg_scale), + "sampler_name": sampler, + "scheduler": scheduler, + "denoise": max(0.0, min(1.0, float(denoising_strength))), + "model": model_ref, + "positive": ["3", 0], + "negative": ["4", 0], + "latent_image": ["5", 0], + }, + }, + "7": {"class_type": "VAEDecode", "inputs": {"samples": ["6", 0], "vae": ["1", 2]}}, + "8": {"class_type": "SaveImage", "inputs": {"filename_prefix": filename_prefix, "images": ["7", 0]}}, + } + ) + prompt_id = self._submit_prompt(workflow) + descriptor = self._wait_for_image_descriptor(prompt_id) + return self._download_image(descriptor, f"{filename_prefix}_{prompt_id}") + + def render_controlnet_img2img( + self, + *, + prompt: str, + negative_prompt: str, + init_image_path: str, + control_inputs: list[Dict[str, Any]], + width: int, + height: int, + steps: int, + cfg_scale: float, + denoising_strength: float, + sampler_name: str = "", + filename_prefix: str = "comfy_controlnet_img2img", + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + normalized_inputs = [dict(item) for item in control_inputs if isinstance(item, dict) and str(item.get("image_path") or "").strip()] + if not normalized_inputs: + return self.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=init_image_path, + width=width, + height=height, + steps=steps, + cfg_scale=cfg_scale, + denoising_strength=denoising_strength, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + + uploaded_init = self.upload_image(init_image_path) + checkpoint = self.pick_checkpoint(checkpoint_name) + sampler, scheduler = self._sampler_config(sampler_name) + workflow: Dict[str, Any] = {} + model_ref, clip_ref = self._workflow_refs( + workflow, + checkpoint=checkpoint, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + workflow.update( + { + "2": {"class_type": "LoadImage", "inputs": {"image": uploaded_init}}, + "3": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": clip_ref}}, + "4": {"class_type": "CLIPTextEncode", "inputs": {"text": negative_prompt, "clip": clip_ref}}, + "5": {"class_type": "VAEEncode", "inputs": {"pixels": ["2", 0], "vae": ["1", 2]}}, + } + ) + + positive_ref: list[Any] = ["3", 0] + negative_ref: list[Any] = ["4", 0] + next_node_id = 20 + for item in normalized_inputs: + uploaded_control = self.upload_image(str(item.get("image_path") or "").strip()) + control_model = self.pick_controlnet(item.get("control_net_name") or item.get("controlnet_name")) + load_image_id = str(next_node_id) + load_controlnet_id = str(next_node_id + 1) + apply_id = str(next_node_id + 2) + next_node_id += 3 + workflow[load_image_id] = {"class_type": "LoadImage", "inputs": {"image": uploaded_control}} + workflow[load_controlnet_id] = {"class_type": "ControlNetLoader", "inputs": {"control_net_name": control_model}} + workflow[apply_id] = { + "class_type": "ControlNetApplyAdvanced", + "inputs": { + "positive": positive_ref, + "negative": negative_ref, + "control_net": [load_controlnet_id, 0], + "image": [load_image_id, 0], + "strength": float(item.get("strength", 0.8)), + "start_percent": float(item.get("start_percent", 0.0)), + "end_percent": float(item.get("end_percent", 1.0)), + "vae": ["1", 2], + }, + } + positive_ref = [apply_id, 0] + negative_ref = [apply_id, 1] + + workflow["6"] = { + "class_type": "KSampler", + "inputs": { + "seed": random.randint(1, 2**31 - 1), + "steps": max(1, int(steps)), + "cfg": float(cfg_scale), + "sampler_name": sampler, + "scheduler": scheduler, + "denoise": max(0.0, min(1.0, float(denoising_strength))), + "model": model_ref, + "positive": positive_ref, + "negative": negative_ref, + "latent_image": ["5", 0], + }, + } + workflow["7"] = {"class_type": "VAEDecode", "inputs": {"samples": ["6", 0], "vae": ["1", 2]}} + workflow["8"] = {"class_type": "SaveImage", "inputs": {"filename_prefix": filename_prefix, "images": ["7", 0]}} + prompt_id = self._submit_prompt(workflow) + descriptor = self._wait_for_image_descriptor(prompt_id) + return self._download_image(descriptor, f"{filename_prefix}_{prompt_id}") + + def render_controlnet_txt2img( + self, + *, + prompt: str, + negative_prompt: str, + control_inputs: list[Dict[str, Any]], + width: int, + height: int, + steps: int, + cfg_scale: float, + sampler_name: str = "", + filename_prefix: str = "comfy_controlnet_txt2img", + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + normalized_inputs = [dict(item) for item in control_inputs if isinstance(item, dict) and str(item.get("image_path") or "").strip()] + if not normalized_inputs: + return self.render_txt2img( + prompt=prompt, + negative_prompt=negative_prompt, + width=width, + height=height, + steps=steps, + cfg_scale=cfg_scale, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + + checkpoint = self.pick_checkpoint(checkpoint_name) + sampler, scheduler = self._sampler_config(sampler_name) + workflow: Dict[str, Any] = {} + model_ref, clip_ref = self._workflow_refs( + workflow, + checkpoint=checkpoint, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + workflow.update( + { + "2": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": clip_ref}}, + "3": {"class_type": "CLIPTextEncode", "inputs": {"text": negative_prompt, "clip": clip_ref}}, + } + ) + + positive_ref: list[Any] = ["2", 0] + negative_ref: list[Any] = ["3", 0] + next_node_id = 20 + for item in normalized_inputs: + uploaded_control = self.upload_image(str(item.get("image_path") or "").strip()) + control_model = self.pick_controlnet(item.get("control_net_name") or item.get("controlnet_name")) + load_image_id = str(next_node_id) + load_controlnet_id = str(next_node_id + 1) + apply_id = str(next_node_id + 2) + next_node_id += 3 + workflow[load_image_id] = {"class_type": "LoadImage", "inputs": {"image": uploaded_control}} + workflow[load_controlnet_id] = {"class_type": "ControlNetLoader", "inputs": {"control_net_name": control_model}} + workflow[apply_id] = { + "class_type": "ControlNetApplyAdvanced", + "inputs": { + "positive": positive_ref, + "negative": negative_ref, + "control_net": [load_controlnet_id, 0], + "image": [load_image_id, 0], + "strength": float(item.get("strength", 0.8)), + "start_percent": float(item.get("start_percent", 0.0)), + "end_percent": float(item.get("end_percent", 1.0)), + "vae": ["1", 2], + }, + } + positive_ref = [apply_id, 0] + negative_ref = [apply_id, 1] + + workflow["4"] = { + "class_type": "EmptyLatentImage", + "inputs": { + "width": self._sanitize_dimension(width), + "height": self._sanitize_dimension(height), + "batch_size": 1, + }, + } + workflow["5"] = { + "class_type": "KSampler", + "inputs": { + "seed": random.randint(1, 2**31 - 1), + "steps": max(1, int(steps)), + "cfg": float(cfg_scale), + "sampler_name": sampler, + "scheduler": scheduler, + "denoise": 1.0, + "model": model_ref, + "positive": positive_ref, + "negative": negative_ref, + "latent_image": ["4", 0], + }, + } + workflow["6"] = {"class_type": "VAEDecode", "inputs": {"samples": ["5", 0], "vae": ["1", 2]}} + workflow["7"] = {"class_type": "SaveImage", "inputs": {"filename_prefix": filename_prefix, "images": ["6", 0]}} + prompt_id = self._submit_prompt(workflow) + descriptor = self._wait_for_image_descriptor(prompt_id) + return self._download_image(descriptor, f"{filename_prefix}_{prompt_id}") + + def render_inpaint( + self, + *, + prompt: str, + negative_prompt: str, + init_image_path: str, + mask_image_path: str, + steps: int, + cfg_scale: float, + denoising_strength: float, + sampler_name: str = "", + filename_prefix: str = "comfy_inpaint", + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + grow_mask_by: int = 12, + ) -> str: + uploaded_init = self.upload_image(init_image_path) + uploaded_mask = self.upload_image(mask_image_path) + checkpoint = self.pick_checkpoint(checkpoint_name) + sampler, scheduler = self._sampler_config(sampler_name) + workflow: Dict[str, Any] = {} + model_ref, clip_ref = self._workflow_refs( + workflow, + checkpoint=checkpoint, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + workflow.update( + { + "2": {"class_type": "LoadImage", "inputs": {"image": uploaded_init}}, + "3": {"class_type": "LoadImage", "inputs": {"image": uploaded_mask}}, + "4": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": clip_ref}}, + "5": {"class_type": "CLIPTextEncode", "inputs": {"text": negative_prompt, "clip": clip_ref}}, + "6": { + "class_type": "VAEEncodeForInpaint", + "inputs": { + "pixels": ["2", 0], + "mask": ["3", 1], + "vae": ["1", 2], + "grow_mask_by": max(0, int(grow_mask_by)), + }, + }, + "7": { + "class_type": "KSampler", + "inputs": { + "seed": random.randint(1, 2**31 - 1), + "steps": max(1, int(steps)), + "cfg": float(cfg_scale), + "sampler_name": sampler, + "scheduler": scheduler, + "denoise": max(0.0, min(1.0, float(denoising_strength))), + "model": model_ref, + "positive": ["4", 0], + "negative": ["5", 0], + "latent_image": ["6", 0], + }, + }, + "8": {"class_type": "VAEDecode", "inputs": {"samples": ["7", 0], "vae": ["1", 2]}}, + "9": {"class_type": "SaveImage", "inputs": {"filename_prefix": filename_prefix, "images": ["8", 0]}}, + } + ) + prompt_id = self._submit_prompt(workflow) + descriptor = self._wait_for_image_descriptor(prompt_id) + return self._download_image(descriptor, f"{filename_prefix}_{prompt_id}") + + def render_txt2img( + self, + *, + prompt: str, + negative_prompt: str, + width: int, + height: int, + steps: int, + cfg_scale: float, + sampler_name: str = "", + filename_prefix: str = "comfy_txt2img", + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + checkpoint = self.pick_checkpoint(checkpoint_name) + sampler, scheduler = self._sampler_config(sampler_name) + workflow: Dict[str, Any] = {} + model_ref, clip_ref = self._workflow_refs( + workflow, + checkpoint=checkpoint, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + workflow.update( + { + "2": {"class_type": "CLIPTextEncode", "inputs": {"text": prompt, "clip": clip_ref}}, + "3": {"class_type": "CLIPTextEncode", "inputs": {"text": negative_prompt, "clip": clip_ref}}, + "4": { + "class_type": "EmptyLatentImage", + "inputs": { + "width": self._sanitize_dimension(width), + "height": self._sanitize_dimension(height), + "batch_size": 1, + }, + }, + "5": { + "class_type": "KSampler", + "inputs": { + "seed": random.randint(1, 2**31 - 1), + "steps": max(1, int(steps)), + "cfg": float(cfg_scale), + "sampler_name": sampler, + "scheduler": scheduler, + "denoise": 1.0, + "model": model_ref, + "positive": ["2", 0], + "negative": ["3", 0], + "latent_image": ["4", 0], + }, + }, + "6": {"class_type": "VAEDecode", "inputs": {"samples": ["5", 0], "vae": ["1", 2]}}, + "7": {"class_type": "SaveImage", "inputs": {"filename_prefix": filename_prefix, "images": ["6", 0]}}, + } + ) + prompt_id = self._submit_prompt(workflow) + descriptor = self._wait_for_image_descriptor(prompt_id) + return self._download_image(descriptor, f"{filename_prefix}_{prompt_id}") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_extractor.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_extractor.py new file mode 100644 index 0000000..fc849e0 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_extractor.py @@ -0,0 +1,180 @@ +""" +概念提取器 +从文本中提取机制级概念和因果关系,生成适合 Tri-Maze 推理的高质量 Concept Graph +""" +from __future__ import annotations + +import json +import os +from typing import Dict + +from loguru import logger +from openai import OpenAI + + +class ConceptExtractor: + """机制级概念提取器""" + + def __init__(self, api_key: str | None = None, base_url: str | None = None, model: str | None = None): + """初始化概念提取器""" + self.api_key = (api_key if api_key is not None else os.getenv("API_KEY", "")).strip() + self.base_url = (base_url if base_url is not None else os.getenv("API_BASE_URL", "https://api.deepseek.com/v1")).strip() + self.model = (model if model is not None else os.getenv("TMCRA_LLM_MODEL", "deepseek-chat")).strip() or "deepseek-chat" + self.client = self._build_client() + + self.MAX_CONCEPTS = None + self.MAX_RELATIONS = 25 + self.system_prompt = """ +你是专业的机制级概念提取专家。请从用户输入的文本中提取可用于推理的 Concept Graph,优先生成机制型、因果型的概念和关系,生成适合路径推理的高质量概念图。 + +# 核心规则: +## 1. 概念提取规则 +优先提取以下类型的具体概念,禁止提取抽象无价值概念: +✅ 允许的概念类型: +- structure: 具体结构、部件、实体 +- entity: 具体物体、物质、对象 +- property: 可测量的属性、特征 +- process: 具体过程、动作、机制 +- material: 具体材料、物质 +- energy: 能量、物理量、信号 +- biological structure: 生物结构、组织 +- physical mechanism: 物理/化学/生物机制 + +❌ 禁止提取的抽象概念(绝对不要出现): +系统、情况、问题、东西、方面、部分、类型、方法、方式、技术、效果、作用、功能 + +## 2. 关系提取规则 +优先提取机制型、因果型关系,禁止模糊关系: +✅ 允许的关系类型: +导致、产生、影响、依赖、组成、包含、调节、转化、传递、驱动、阻碍、催化、生成、连接、控制、供给 + +❌ 禁止的模糊关系(绝对不要出现): +相关、有关、涉及、属于、包括、是、有、存在 + +## 3. 概念链结构要求 +尽量构建多层机制因果链,例如: +- 猫 → 有 → 浓密毛发 → 导致 → 隔热 → 维持 → 体温 +- 机翼弯曲 → 导致 → 气流速度差 → 产生 → 压力差 → 生成 → 升力 +- 光照 → 触发 → 光合作用 → 生成 → 有机物 → 支持 → 植物生长 +- 电流 → 流过 → 电阻 → 产生 → 热量 → 升高 → 温度 + +目标是生成适合路径搜索和推理的链式结构概念图。 + +## 4. 关系权重规则 +权重范围 0-1,根据关系确定性和强度赋值: +- 0.9–1.0:强因果关系、物理定律、确定的机制 +- 0.6–0.8:明确的机制关系、组成关系、过程关系 +- 0.3–0.5:弱关联、间接影响、不确定关系 + +## 5. 其他规则 +- 避免生成循环关系(A→B 且 B→A),除非是真实的循环过程 +- 概念和关系要具体、可推理,不要模糊笼统 +- 优先提取能形成长推理链的概念和关系 +- 概念数量不设固定上限,尽量完整保留机制链中的关键概念 +- 关系优先输出高质量机制关系,受模型上下文窗口约束 + +# 输出格式要求: +严格输出 JSON 格式,不要任何解释文字、说明、前置或后置内容: +{ + "concepts": [ + {"concept": "概念名称", "type": "structure/entity/property/process/material/energy"}, + {"concept": "概念名称", "type": "structure/entity/property/process/material/energy"} + ], + "relations": [ + {"from": "源概念", "to": "目标概念", "relation": "关系描述", "weight": 0.8} + ] +} +""" + + def _build_client(self): + if not self.api_key: + return None + return OpenAI(api_key=self.api_key, base_url=self.base_url) + + def set_api_config(self, api_key: str, base_url: str | None = None, model: str | None = None): + """设置 API 配置""" + self.api_key = (api_key or "").strip() + if base_url is not None and base_url.strip(): + self.base_url = base_url.strip() + if model is not None and model.strip(): + self.model = model.strip() + self.client = self._build_client() + if self.client: + logger.info("✅ API 配置已更新") + else: + logger.info("ℹ️ 概念提取 API 配置已清空") + + def _filter_and_trim_graph(self, result: Dict) -> Dict: + """过滤和修剪概念图,控制规模,删除低权重关系和孤立节点""" + concepts = result.get("concepts", []) + relations = result.get("relations", []) + + if not relations: + return result + + relations.sort(key=lambda x: x.get("weight", 0), reverse=True) + if self.MAX_RELATIONS and self.MAX_RELATIONS > 0: + relations = relations[:self.MAX_RELATIONS] + + used_concepts = set() + for rel in relations: + used_concepts.add(rel.get("from", "")) + used_concepts.add(rel.get("to", "")) + + filtered_concepts = [c for c in concepts if c.get("concept", "") in used_concepts] + if self.MAX_CONCEPTS and self.MAX_CONCEPTS > 0: + filtered_concepts = filtered_concepts[:self.MAX_CONCEPTS] + + existing_concept_names = {c.get("concept", "") for c in filtered_concepts} + for concept_name in used_concepts: + if concept_name and concept_name not in existing_concept_names and (not self.MAX_CONCEPTS or self.MAX_CONCEPTS <= 0 or len(filtered_concepts) < self.MAX_CONCEPTS): + filtered_concepts.append({ + "concept": concept_name, + "type": "entity" + }) + + logger.info( + "✂️ 概念图修剪:{}→{} 个概念,{}→{} 个关系", + len(concepts), + len(filtered_concepts), + len(result.get("relations", [])), + len(relations), + ) + + return { + "concepts": filtered_concepts, + "relations": relations, + } + + def extract(self, text: str) -> Dict | None: + """从任意文本中提取机制级概念和因果关系,生成高质量 Concept Graph。""" + if not self.api_key or not self.client: + logger.error("❌ 未设置 API Key,请先调用 set_api_config()") + return None + + logger.info("🔍 提取机制级概念图:{}...", text[:80]) + + try: + response = self.client.chat.completions.create( + model=self.model, + messages=[ + {"role": "system", "content": self.system_prompt}, + {"role": "user", "content": text}, + ], + temperature=0.1, + max_tokens=2000, + response_format={"type": "json_object"}, + ) + + result = json.loads(response.choices[0].message.content) + if "concepts" not in result or "relations" not in result: + logger.error("❌ API 返回格式错误,缺少 concepts 或 relations 字段") + return None + + result = self._filter_and_trim_graph(result) + logger.info("✅ 提取完成:{} 个概念,{} 个关系", len(result["concepts"]), len(result["relations"])) + logger.debug("提取结果: {}", json.dumps(result, ensure_ascii=False, indent=2)) + return result + except Exception as exc: + logger.error("❌ 概念提取失败: {}", exc) + return None diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_graph.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_graph.py new file mode 100644 index 0000000..725bd02 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_graph.py @@ -0,0 +1,126 @@ +""" +概念图存储 +基于 NetworkX 实现 +""" +import networkx as nx +from typing import Dict, List +from loguru import logger + + +class ConceptGraph: + """概念图存储""" + + def __init__(self): + self.graph = nx.DiGraph() + logger.info("✅ 概念图初始化完成") + + def add_concept(self, concept: str, concept_type: str = "general"): + """添加概念""" + if not self.graph.has_node(concept): + self.graph.add_node(concept, type=concept_type) + logger.debug(f"添加概念: {concept} ({concept_type})") + + def add_relation(self, from_concept: str, to_concept: str, relation: str, weight: float = 0.5): + """添加概念之间的关系""" + if not self.graph.has_node(from_concept): + self.add_concept(from_concept) + if not self.graph.has_node(to_concept): + self.add_concept(to_concept) + + self.graph.add_edge(from_concept, to_concept, relation=relation, weight=weight) + logger.debug(f"添加关系: {from_concept} → {to_concept}: {relation} (权重: {weight})") + + def remove_concept(self, concept: str): + """删除概念""" + if self.graph.has_node(concept): + self.graph.remove_node(concept) + logger.debug(f"删除概念: {concept}") + + def remove_relation(self, from_concept: str, to_concept: str): + """删除关系""" + if self.graph.has_edge(from_concept, to_concept): + self.graph.remove_edge(from_concept, to_concept) + logger.debug(f"删除关系: {from_concept} → {to_concept}") + + def get_concepts(self) -> List[str]: + """获取所有概念""" + return list(self.graph.nodes) + + def get_relations(self) -> List[Dict]: + """获取所有关系""" + relations = [] + for u, v, data in self.graph.edges(data=True): + relations.append({ + "from": u, + "to": v, + "relation": data.get("relation", ""), + "weight": data.get("weight", 0.5) + }) + return relations + + def find_paths(self, start: str, end: str = None, max_depth: int = 5) -> List[List[str]]: + """查找概念之间的路径""" + if end: + # 查找两点之间的所有简单路径 + paths = list(nx.all_simple_paths(self.graph, source=start, target=end, cutoff=max_depth)) + else: + # 从起点出发的所有路径 + paths = [] + for node in self.graph.nodes: + if node != start: + try: + paths.extend(nx.all_simple_paths(self.graph, source=start, target=node, cutoff=max_depth)) + except nx.NetworkXNoPath: + pass + + logger.debug(f"找到 {len(paths)} 条路径从 {start} 出发") + return paths + + def clear(self): + """清空概念图""" + self.graph.clear() + logger.debug("概念图已清空") + + def get_graph(self) -> nx.DiGraph: + """获取 NetworkX 图对象""" + return self.graph + + def export_json(self) -> Dict: + """导出为 JSON 格式""" + data = { + "concepts": [], + "relations": [] + } + + for node, attrs in self.graph.nodes(data=True): + data["concepts"].append({ + "concept": node, + "type": attrs.get("type", "general") + }) + + for u, v, attrs in self.graph.edges(data=True): + data["relations"].append({ + "from": u, + "to": v, + "relation": attrs.get("relation", ""), + "weight": attrs.get("weight", 0.5) + }) + + return data + + def import_json(self, data: Dict): + """从 JSON 导入""" + self.clear() + + for concept in data.get("concepts", []): + self.add_concept(concept["concept"], concept.get("type", "general")) + + for relation in data.get("relations", []): + self.add_relation( + relation["from"], + relation["to"], + relation["relation"], + relation.get("weight", 0.5) + ) + + logger.info(f"导入了 {len(self.graph.nodes)} 个概念,{len(self.graph.edges)} 个关系") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_memory.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_memory.py new file mode 100644 index 0000000..bfc1465 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/concept_memory.py @@ -0,0 +1,311 @@ +""" +Concept long-term memory for TMCRA. +Stores concepts, successful paths, and explicit facts with relation types. +""" +from __future__ import annotations + +import json +import os +from collections import defaultdict +from typing import Dict, List + +from loguru import logger + + +class ConceptMemory: + """Long-term concept memory.""" + + def __init__(self, memory_file: str = "data/concept_memory.json"): + self.memory_file = memory_file + self.max_concepts = None + self.max_paths = None + self.max_facts = 2000 + self.importance_threshold = 0.2 + self.reinforcement_factor = 0.05 + + self.concepts: Dict[str, Dict] = {} + self.paths: List[Dict] = [] + self.facts: List[Dict] = [] + self.edge_counts: Dict[tuple, int] = defaultdict(int) + + self._load_memory() + logger.info( + "✅ Concept memory initialized: {} concepts, {} paths, {} facts", + len(self.concepts), + len(self.paths), + len(self.facts), + ) + + def _normalize_path_record(self, record: Dict) -> Dict: + path_concepts = [str(item).strip() for item in (record.get("path") or []) if str(item).strip()] + mode = str(record.get("mode") or "forward").strip().lower() or "forward" + if mode not in {"forward", "reverse", "boundary"}: + mode = "forward" + source = str(record.get("source") or "engine_runtime").strip() or "engine_runtime" + try: + score = float(record.get("score", 0.8)) + except Exception: + score = 0.8 + try: + uses = int(record.get("uses", 1) or 1) + except Exception: + uses = 1 + + normalized = { + "path": path_concepts, + "score": max(0.0, min(1.0, score)), + "uses": max(1, uses), + "mode": mode, + "source": source, + } + for key, value in record.items(): + if key not in normalized: + normalized[key] = value + return normalized + + def _load_memory(self) -> None: + os.makedirs(os.path.dirname(self.memory_file), exist_ok=True) + if not os.path.exists(self.memory_file): + self._init_empty_memory() + return + try: + with open(self.memory_file, "r", encoding="utf-8") as f: + data = json.load(f) + self.concepts = data.get("concepts", {}) + self.paths = [self._normalize_path_record(item) for item in data.get("paths", []) if isinstance(item, dict)] + self.facts = data.get("facts", []) + + for path in self.paths: + concept_list = path.get("path", []) + for i in range(len(concept_list) - 1): + edge = (concept_list[i], concept_list[i + 1]) + self.edge_counts[edge] += path.get("uses", 1) + + logger.info( + "📥 Loaded memory: {} concepts, {} paths, {} facts", + len(self.concepts), + len(self.paths), + len(self.facts), + ) + except Exception as exc: + logger.error("❌ Failed to load memory: {}", exc) + self._init_empty_memory() + + def _init_empty_memory(self) -> None: + self.concepts = {} + self.paths = [] + self.facts = [] + self.edge_counts = defaultdict(int) + self._save_memory() + + def _save_memory(self) -> None: + try: + data = { + "concepts": self.concepts, + "paths": [self._normalize_path_record(item) for item in self.paths], + "facts": self.facts, + } + with open(self.memory_file, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + except Exception as exc: + logger.error("❌ Failed to save memory: {}", exc) + + def _cleanup_memory(self) -> None: + if self.max_concepts and self.max_concepts > 0 and len(self.concepts) > self.max_concepts: + sorted_concepts = sorted( + self.concepts.items(), + key=lambda x: x[1].get("importance_score", 0), + reverse=True, + ) + keep_count = int(self.max_concepts * 0.9) + self.concepts = dict(sorted_concepts[:keep_count]) + logger.info("🧹 Trim concepts: kept {}", keep_count) + + if self.max_paths and self.max_paths > 0 and len(self.paths) > self.max_paths: + sorted_paths = sorted( + self.paths, + key=lambda x: (x.get("uses", 0), x.get("score", 0)), + reverse=True, + ) + keep_count = int(self.max_paths * 0.9) + self.paths = sorted_paths[:keep_count] + logger.info("🧹 Trim paths: kept {}", keep_count) + + if len(self.facts) > self.max_facts: + sorted_facts = sorted( + self.facts, + key=lambda x: (x.get("uses", 0), x.get("weight", 0)), + reverse=True, + ) + keep_count = int(self.max_facts * 0.9) + self.facts = sorted_facts[:keep_count] + logger.info("🧹 Trim facts: kept {}", keep_count) + + self._save_memory() + + def update_concept_importance(self, concept: str, score_delta: float = 0.1): + if concept in self.concepts: + self.concepts[concept]["importance_score"] = min( + 1.0, + self.concepts[concept].get("importance_score", 0) + score_delta, + ) + else: + self.concepts[concept] = { + "concept": concept, + "type": "unknown", + "importance_score": max(0.3, score_delta), + "created_from": "inferred", + } + self._save_memory() + + def add_concept( + self, + concept: str, + concept_type: str = "general", + created_from: str = "original", + importance_score: float = 0.5, + ): + if concept in self.concepts: + self.concepts[concept]["importance_score"] = max( + self.concepts[concept]["importance_score"], importance_score + ) + if concept_type != "general" and self.concepts[concept].get("type") == "unknown": + self.concepts[concept]["type"] = concept_type + else: + self.concepts[concept] = { + "concept": concept, + "type": concept_type, + "importance_score": importance_score, + "created_from": created_from, + } + self._cleanup_memory() + + def save_successful_path( + self, + path_concepts: List[str], + score: float = 0.8, + *, + mode: str = "forward", + source: str = "engine_runtime", + ): + if not path_concepts or len(path_concepts) < 2: + return + normalized_mode = str(mode or "forward").strip().lower() or "forward" + if normalized_mode not in {"forward", "reverse", "boundary"}: + normalized_mode = "forward" + normalized_source = str(source or "engine_runtime").strip() or "engine_runtime" + existing_idx = None + for i, p in enumerate(self.paths): + normalized = self._normalize_path_record(p) + if normalized.get("path") == path_concepts and normalized.get("mode") == normalized_mode: + existing_idx = i + break + if existing_idx is not None: + current = self._normalize_path_record(self.paths[existing_idx]) + current["uses"] = current.get("uses", 1) + 1 + current["score"] = max(float(current.get("score", 0.8)), score) + current["mode"] = normalized_mode + current["source"] = normalized_source + self.paths[existing_idx] = current + else: + self.paths.append( + self._normalize_path_record( + { + "path": path_concepts, + "score": score, + "uses": 1, + "mode": normalized_mode, + "source": normalized_source, + } + ) + ) + + for i in range(len(path_concepts) - 1): + edge = (path_concepts[i], path_concepts[i + 1]) + self.edge_counts[edge] += 1 + for concept in path_concepts: + self.update_concept_importance(concept, 0.05) + + self._cleanup_memory() + + def add_fact(self, src: str, relation: str, dst: str, weight: float = 0.7): + if not src or not dst or not relation: + return + for fact in self.facts: + if fact.get("from") == src and fact.get("to") == dst and fact.get("relation") == relation: + fact["uses"] = fact.get("uses", 1) + 1 + fact["weight"] = max(fact.get("weight", weight), weight) + self._cleanup_memory() + return + self.facts.append( + {"from": src, "to": dst, "relation": relation, "weight": weight, "uses": 1} + ) + self._cleanup_memory() + + def retrieve_related_concepts(self, concept: str, max_results: int = 10) -> List[Dict]: + def _is_injectable(item: Dict) -> bool: + concept_type = str(item.get("type", "")).strip().lower() + return concept_type not in {"ngram", "unknown"} + + related: List[Dict] = [] + concept_lower = concept.lower() + if concept in self.concepts: + related.append(self.concepts[concept].copy()) + for path in self.paths: + path_concepts = path.get("path", []) + if concept in path_concepts: + idx = path_concepts.index(concept) + if idx > 0: + prev_concept = path_concepts[idx - 1] + if prev_concept in self.concepts and not any(c["concept"] == prev_concept for c in related): + candidate = self.concepts[prev_concept].copy() + if _is_injectable(candidate): + related.append(candidate) + if idx < len(path_concepts) - 1: + next_concept = path_concepts[idx + 1] + if next_concept in self.concepts and not any(c["concept"] == next_concept for c in related): + candidate = self.concepts[next_concept].copy() + if _is_injectable(candidate): + related.append(candidate) + if len(concept_lower.strip()) >= 2: + for mem_concept, data in self.concepts.items(): + if concept_lower in mem_concept.lower() and not any(c["concept"] == mem_concept for c in related): + candidate = data.copy() + if _is_injectable(candidate): + related.append(candidate) + if len(related) >= max_results: + break + related.sort(key=lambda x: x.get("importance_score", 0), reverse=True) + return related[:max_results] + + def get_related_facts(self, concept: str, max_results: int = 10) -> List[Dict]: + related = [f for f in self.facts if f.get("from") == concept or f.get("to") == concept] + related.sort(key=lambda x: (x.get("uses", 0), x.get("weight", 0)), reverse=True) + return related[:max_results] + + def get_edge_reinforcement(self, from_concept: str, to_concept: str) -> float: + edge = (from_concept, to_concept) + count = self.edge_counts.get(edge, 0) + return min(1.0, count * self.reinforcement_factor) + + def get_all_concepts(self) -> Dict[str, Dict]: + return self.concepts.copy() + + def get_all_paths(self) -> List[Dict]: + return [self._normalize_path_record(item) for item in self.paths] + + def get_all_facts(self) -> List[Dict]: + return self.facts.copy() + + def clear_memory(self): + self._init_empty_memory() + logger.warning("🧹 All memory cleared.") + + +if __name__ == "__main__": + memory = ConceptMemory() + memory.add_concept("Arduino", "device", "original", 0.8) + memory.add_concept("LED", "component", "expansion", 0.7) + memory.save_successful_path(["Arduino", "LED", "电阻", "GND"], 0.9) + memory.add_fact("电阻", "用于", "限制电流", 0.85) + print("Facts:", memory.get_related_facts("电阻")) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/console.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/console.py new file mode 100644 index 0000000..975edbd --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/console.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import os +import sys + + +def configure_stdio_utf8() -> None: + """Prefer UTF-8 stdio so Windows terminals don't garble Chinese output.""" + os.environ.setdefault("PYTHONIOENCODING", "utf-8") + + for stream_name in ("stdout", "stderr"): + stream = getattr(sys, stream_name, None) + reconfigure = getattr(stream, "reconfigure", None) + if not callable(reconfigure): + continue + try: + reconfigure(encoding="utf-8", errors="replace") + except Exception: + continue diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/default_model_paths.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/default_model_paths.py new file mode 100644 index 0000000..c86be1d --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/default_model_paths.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +import os +from pathlib import Path + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +REMOTE_IMPORTS_DIR = PROJECT_ROOT / "outputs" / "remote_imports" + +LEGACY_OBJECT_VARIANTS_PATH = PROJECT_ROOT / "data" / "object_sketch" / "exported_shape_variants.json" +LEGACY_OBJECT_STROKE_VARIANTS_PATH = PROJECT_ROOT / "data" / "object_sketch" / "exported_stroke_variants_v1.json" +LEGACY_SCENE_DATASET_CANDIDATES = ( + PROJECT_ROOT / "data" / "scene_training_prep" / "scene_stage1_v2_fscoco_legacy-user_remote", + PROJECT_ROOT / "data" / "scene_training_prep" / "scene_stage1_v2_fscoco_remote", + PROJECT_ROOT / "data" / "scene_training_prep" / "scene_stage1_v1", +) +LEGACY_SKETCH_LORA_RUN_DIR = PROJECT_ROOT / "outputs" / "sketch_v2_lora_v1" +DEFAULT_SKETCH_LORA_ALIAS = "tmcra_sketch_v2_preview.safetensors" + + +def _env_path(name: str) -> Path | None: + raw = os.getenv(name, "").strip() + if not raw: + return None + return Path(raw).expanduser() + + +def _pick_existing(*candidates: Path | None) -> Path | None: + for candidate in candidates: + if candidate is not None and candidate.exists(): + return candidate + return None + + +def resolve_remote_import_root() -> Path | None: + env_root = _env_path("TMCRA_IMPORTED_ARTIFACT_ROOT") + if env_root and env_root.exists(): + return env_root + if not REMOTE_IMPORTS_DIR.exists(): + return None + candidates = sorted( + [item for item in REMOTE_IMPORTS_DIR.iterdir() if item.is_dir()], + key=lambda item: (item.name, item.stat().st_mtime), + reverse=True, + ) + return candidates[0] if candidates else None + + +def resolve_default_object_variants_path() -> Path: + remote_root = resolve_remote_import_root() + candidate = _pick_existing( + remote_root / "object" / "runtime_export" / "exported_shape_variants_scale.json" if remote_root else None, + remote_root / "object" / "runtime_export" / "exported_shape_variants.json" if remote_root else None, + LEGACY_OBJECT_VARIANTS_PATH, + ) + return candidate or LEGACY_OBJECT_VARIANTS_PATH + + +def resolve_default_object_stroke_variants_path() -> Path: + remote_root = resolve_remote_import_root() + candidate = _pick_existing( + remote_root / "object" / "runtime_export" / "exported_stroke_variants_v1.json" if remote_root else None, + LEGACY_OBJECT_STROKE_VARIANTS_PATH, + ) + return candidate or LEGACY_OBJECT_STROKE_VARIANTS_PATH + + +def resolve_default_scene_dataset_dir() -> Path: + remote_root = resolve_remote_import_root() + candidate = _pick_existing( + remote_root / "scene" / "datasets" / "scene_stage1_v2_fscoco_legacy-user_remote" if remote_root else None, + remote_root / "scene" / "datasets" / "scene_stage1_fscoco_only_legacy-user_remote" if remote_root else None, + *LEGACY_SCENE_DATASET_CANDIDATES, + ) + return candidate or LEGACY_SCENE_DATASET_CANDIDATES[0] + + +def resolve_default_sketch_lora_run_dir() -> Path: + remote_root = resolve_remote_import_root() + candidate = _pick_existing( + remote_root / "sketch" / "latest_run" if remote_root else None, + LEGACY_SKETCH_LORA_RUN_DIR, + ) + return candidate or LEGACY_SKETCH_LORA_RUN_DIR + + +def resolve_default_sketch_lora_path() -> Path: + run_dir = resolve_default_sketch_lora_run_dir() + candidate = _pick_existing( + run_dir / "pytorch_lora_weights.safetensors", + run_dir / "checkpoint-2000" / "pytorch_lora_weights.safetensors", + ) + return candidate or (run_dir / "pytorch_lora_weights.safetensors") + + +def resolve_default_sketch_lora_alias() -> str: + return str(os.getenv("TMCRA_SKETCH_LORA_ALIAS", DEFAULT_SKETCH_LORA_ALIAS) or DEFAULT_SKETCH_LORA_ALIAS).strip() diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gradio_compat.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gradio_compat.py new file mode 100644 index 0000000..89a9e52 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gradio_compat.py @@ -0,0 +1,26 @@ +from __future__ import annotations + + +def patch_gradio_schema_bool_support() -> None: + """ + Work around a Gradio 4.44.1 bug where nested JSON schema values like + `additionalProperties: true` are passed into `_json_schema_to_python_type()` + as booleans, but the upstream helper assumes every schema node is a dict. + """ + try: + from gradio_client import utils as client_utils + except Exception: + return + + if getattr(client_utils, "_tmcra_bool_schema_patch", False): + return + + original = client_utils._json_schema_to_python_type + + def patched(schema, defs): + if isinstance(schema, bool): + return "Any" + return original(schema, defs) + + client_utils._json_schema_to_python_type = patched + client_utils._tmcra_bool_schema_patch = True diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gru_text_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gru_text_generator.py new file mode 100644 index 0000000..2bfac5b --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/gru_text_generator.py @@ -0,0 +1,142 @@ +""" +GRU-based character generator (self-trained, no external embeddings/LLM). +""" +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, List, Tuple, Iterable, Optional + +try: + import torch + from torch import nn +except Exception: # pragma: no cover - optional runtime dependency + torch = None + nn = None + + +SPECIAL_TOKENS = ["", "", "", "", ""] + + +@dataclass +class GRUConfig: + embed_dim: int = 128 + hidden_dim: int = 256 + num_layers: int = 2 + dropout: float = 0.1 + + +class CharVocab: + def __init__(self, tokens: List[str]): + self.tokens = tokens + self.token_to_id = {t: i for i, t in enumerate(tokens)} + self.id_to_token = {i: t for i, t in enumerate(tokens)} + + @classmethod + def build(cls, corpus_iter: Iterable[str]) -> "CharVocab": + chars = set() + for text in corpus_iter: + chars.update(list(text)) + tokens = SPECIAL_TOKENS + sorted(chars) + return cls(tokens) + + def encode(self, text: str) -> List[int]: + return [self.token_to_id.get(ch, self.token_to_id[""]) for ch in text] + + def decode(self, ids: Iterable[int]) -> str: + return "".join(self.id_to_token.get(i, "") for i in ids) + + +if nn is not None: + class GRUCharModel(nn.Module): + def __init__(self, vocab_size: int, config: GRUConfig): + super().__init__() + self.embedding = nn.Embedding(vocab_size, config.embed_dim) + self.gru = nn.GRU( + input_size=config.embed_dim, + hidden_size=config.hidden_dim, + num_layers=config.num_layers, + dropout=config.dropout if config.num_layers > 1 else 0.0, + batch_first=True, + ) + self.fc = nn.Linear(config.hidden_dim, vocab_size) + + def forward(self, x, hidden=None): + emb = self.embedding(x) + out, hidden = self.gru(emb, hidden) + logits = self.fc(out) + return logits, hidden +else: # pragma: no cover - fallback when torch is unavailable + class GRUCharModel: + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use GRUCharModel") + + +class GRUTextGenerator: + def __init__(self, vocab: CharVocab, config: GRUConfig | None = None): + if torch is None: + raise RuntimeError("torch not available; install torch to use GRUTextGenerator") + self.vocab = vocab + self.config = config or GRUConfig() + self.model = GRUCharModel(len(vocab.tokens), self.config) + + @classmethod + def load(cls, model_path: str | Path) -> "GRUTextGenerator": + if torch is None: + raise RuntimeError("torch not available; install torch to load GRUTextGenerator") + data = torch.load(str(model_path), map_location="cpu") + vocab = CharVocab(data["vocab"]) + config = GRUConfig(**data["config"]) + gen = cls(vocab, config) + gen.model.load_state_dict(data["state_dict"]) + gen.model.eval() + return gen + + def save(self, model_path: str | Path) -> None: + data = { + "vocab": self.vocab.tokens, + "config": self.config.__dict__, + "state_dict": self.model.state_dict(), + } + Path(model_path).parent.mkdir(parents=True, exist_ok=True) + torch.save(data, str(model_path)) + + def _prefix_ids(self, path_text: str) -> List[int]: + prefix = "" + path_text + "" + return [self.vocab.token_to_id[""]] + self.vocab.encode(prefix) + + def generate( + self, + path_text: str, + max_len: int = 400, + temperature: float = 0.9, + device: str = "cpu", + ) -> str: + self.model.to(device) + self.model.eval() + ids = self._prefix_ids(path_text) + input_ids = torch.tensor([ids], dtype=torch.long, device=device) + hidden = None + generated: List[int] = [] + for _ in range(max_len): + logits, hidden = self.model(input_ids, hidden) + next_logits = logits[:, -1, :] / max(temperature, 1e-6) + probs = torch.softmax(next_logits, dim=-1) + next_id = torch.multinomial(probs, num_samples=1).item() + if next_id == self.vocab.token_to_id[""]: + break + generated.append(next_id) + input_ids = torch.tensor([[next_id]], dtype=torch.long, device=device) + return self.vocab.decode(generated) + + @staticmethod + def build_corpus_iter(corpus_path: str | Path, max_chars: int | None = None) -> Iterable[str]: + total = 0 + with open(corpus_path, "r", encoding="utf-8", errors="ignore") as handle: + for line in handle: + if not line.strip(): + continue + if max_chars and total >= max_chars: + break + total += len(line) + yield line.strip() diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/__init__.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/__init__.py new file mode 100644 index 0000000..7307cd8 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/__init__.py @@ -0,0 +1,6 @@ +"""Knowledge base helpers for TMCRA.""" + +from .conceptnet_store import ConceptNetStore +from .embedding_store import EmbeddingStore + +__all__ = ["ConceptNetStore", "EmbeddingStore"] diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/conceptnet_store.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/conceptnet_store.py new file mode 100644 index 0000000..bb7c511 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/conceptnet_store.py @@ -0,0 +1,193 @@ +from __future__ import annotations + +import os +import sqlite3 +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Sequence, Tuple + +from loguru import logger + + +def _has_cjk(text: str) -> bool: + return any("\u4e00" <= ch <= "\u9fff" for ch in text) + + +def _normalize_en(text: str) -> str: + text = text.strip().lower().replace("_", " ") + while " " in text: + text = text.replace(" ", " ") + return text + + +def _normalize_zh(text: str) -> str: + return text.strip() + + +def _guess_lang(text: str) -> str: + return "zh" if _has_cjk(text) else "en" + + +class ConceptNetStore: + """Read-only ConceptNet SQLite store.""" + + def __init__(self, db_path: str, vocab_path: Optional[str] = None) -> None: + self.db_path = Path(db_path) + self.vocab_path = Path(vocab_path) if vocab_path else None + self._conn: Optional[sqlite3.Connection] = None + self._vocab: Optional[set[str]] = None + self._concept_cache: Dict[Tuple[str, str], Optional[str]] = {} + self._open() + self._load_vocab() + + @classmethod + def from_env(cls) -> Optional["ConceptNetStore"]: + root = Path(__file__).resolve().parents[2] + default_db = root / "data" / "kb" / "conceptnet_full.db" + default_vocab = root / "data" / "kb" / "conceptnet_vocab.txt" + db_path = Path(os.getenv("TMCRA_KB_PATH", str(default_db))) + vocab_path = Path(os.getenv("TMCRA_KB_VOCAB", str(default_vocab))) + if not db_path.exists(): + logger.warning("ConceptNet DB not found at {}", db_path) + return None + return cls(str(db_path), str(vocab_path) if vocab_path.exists() else None) + + def _open(self) -> None: + if not self.db_path.exists(): + self._conn = None + return + uri = f"file:{self.db_path.as_posix()}?mode=ro" + self._conn = sqlite3.connect(uri, uri=True, check_same_thread=False) + self._conn.row_factory = sqlite3.Row + + def close(self) -> None: + if self._conn is not None: + self._conn.close() + self._conn = None + + def __del__(self) -> None: + try: + self.close() + except Exception: + pass + + def _load_vocab(self) -> None: + if not self.vocab_path or not self.vocab_path.exists(): + self._vocab = None + return + try: + with self.vocab_path.open("r", encoding="utf-8") as handle: + self._vocab = {line.strip() for line in handle if line.strip()} + logger.info("Loaded ConceptNet vocab: {} entries", len(self._vocab)) + except Exception as exc: + logger.warning("Failed to load vocab: {}", exc) + self._vocab = None + + @property + def available(self) -> bool: + return self._conn is not None + + def _normalize(self, text: str, lang: Optional[str] = None) -> Tuple[str, str]: + language = lang or _guess_lang(text) + if language == "zh": + return language, _normalize_zh(text) + return language, _normalize_en(text) + + def concept_exists(self, text: str, lang: Optional[str] = None) -> bool: + normalized_lang, normalized = self._normalize(text, lang) + cache_key = (normalized_lang, normalized) + if cache_key in self._concept_cache: + return self._concept_cache[cache_key] is not None + if self._vocab is not None: + exists = normalized in self._vocab + self._concept_cache[cache_key] = normalized if exists else None + return exists + if not self._conn: + self._concept_cache[cache_key] = None + return False + row = self._conn.execute( + "SELECT concept FROM concepts WHERE lang=? AND normalized=? LIMIT 1", + (normalized_lang, normalized), + ).fetchone() + self._concept_cache[cache_key] = row["concept"] if row else None + return row is not None + + def resolve_concept(self, text: str, lang: Optional[str] = None) -> Optional[str]: + normalized_lang, normalized = self._normalize(text, lang) + cache_key = (normalized_lang, normalized) + if cache_key in self._concept_cache: + return self._concept_cache[cache_key] + if self._vocab is not None: + if normalized in self._vocab: + self._concept_cache[cache_key] = normalized + return normalized + self._concept_cache[cache_key] = None + return None + if not self._conn: + self._concept_cache[cache_key] = None + return None + row = self._conn.execute( + "SELECT concept FROM concepts WHERE lang=? AND normalized=? LIMIT 1", + (normalized_lang, normalized), + ).fetchone() + concept = row["concept"] if row else None + self._concept_cache[cache_key] = concept + return concept + + def find_concepts(self, candidates: Iterable[str], lang: Optional[str] = None) -> List[str]: + if not candidates: + return [] + normalized_lang = lang or "en" + normalized_map: Dict[str, str] = {} + for item in candidates: + language, normalized = self._normalize(item, lang) + normalized_lang = language + if normalized: + normalized_map[normalized] = normalized + if not normalized_map: + return [] + normalized_list = list(normalized_map.keys()) + if self._vocab is not None: + return [n for n in normalized_list if n in self._vocab] + if not self._conn: + return [] + results: List[str] = [] + chunk_size = 900 + for i in range(0, len(normalized_list), chunk_size): + chunk = normalized_list[i:i + chunk_size] + placeholders = ",".join("?" for _ in chunk) + query = f"SELECT concept, normalized FROM concepts WHERE lang=? AND normalized IN ({placeholders})" + rows = self._conn.execute(query, (normalized_lang, *chunk)).fetchall() + results.extend([row["concept"] for row in rows]) + return list(dict.fromkeys(results)) + + def get_neighbors(self, concept: str, limit: int = 12) -> List[Dict]: + if not self._conn: + return [] + canonical = self.resolve_concept(concept) or concept + rows = self._conn.execute( + "SELECT source, target, relation, weight FROM edges WHERE source=? ORDER BY weight DESC LIMIT ?", + (canonical, limit), + ).fetchall() + return [dict(row) for row in rows] + + def get_edges_between(self, concepts: Sequence[str], limit_per_concept: int = 25) -> List[Dict]: + if not self._conn or not concepts: + return [] + canonical_concepts = [self.resolve_concept(concept) or concept for concept in concepts] + concept_set = set(canonical_concepts) + results: List[Dict] = [] + chunk_size = 700 + for source in canonical_concepts: + canonical = self.resolve_concept(source) or source + targets = list(concept_set) + for i in range(0, len(targets), chunk_size): + chunk = targets[i:i + chunk_size] + placeholders = ",".join("?" for _ in chunk) + query = ( + f"SELECT source, target, relation, weight FROM edges " + f"WHERE source=? AND target IN ({placeholders}) " + f"ORDER BY weight DESC LIMIT ?" + ) + rows = self._conn.execute(query, (canonical, *chunk, limit_per_concept)).fetchall() + results.extend([dict(row) for row in rows]) + return results diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/embedding_store.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/embedding_store.py new file mode 100644 index 0000000..bb52f49 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/kb/embedding_store.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +import json +import os +from pathlib import Path +from typing import Dict, Optional + +import numpy as np +from loguru import logger + + +def _has_cjk(text: str) -> bool: + return any("\u4e00" <= ch <= "\u9fff" for ch in text) + + +class EmbeddingStore: + """Lazy-loading embedding store for Numberbatch vectors.""" + + def __init__(self, emb_path: str, vocab_path: str) -> None: + self.emb_path = Path(emb_path) + self.vocab_path = Path(vocab_path) + self._vectors = None + self._vocab: Dict[str, int] = {} + self._load_vocab() + + @classmethod + def from_env(cls) -> Optional["EmbeddingStore"]: + root = Path(__file__).resolve().parents[2] + default_emb = root / "data" / "kb" / "numberbatch.npy" + default_vocab = root / "data" / "kb" / "numberbatch_vocab.json" + emb_path = Path(os.getenv("TMCRA_EMB_PATH", str(default_emb))) + vocab_path = Path(os.getenv("TMCRA_EMB_VOCAB", str(default_vocab))) + if not emb_path.exists() or not vocab_path.exists(): + logger.warning("Embedding files not found: {} / {}", emb_path, vocab_path) + return None + return cls(str(emb_path), str(vocab_path)) + + def _load_vocab(self) -> None: + if not self.vocab_path.exists(): + return + try: + with self.vocab_path.open("r", encoding="utf-8") as handle: + self._vocab = json.load(handle) + except Exception as exc: + logger.warning("Failed to load embedding vocab: {}", exc) + self._vocab = {} + + def _load_vectors(self) -> None: + if self._vectors is None and self.emb_path.exists(): + self._vectors = np.load(self.emb_path, mmap_mode="r") + + @property + def available(self) -> bool: + return bool(self._vocab) and self.emb_path.exists() + + def _normalize_key(self, concept: str) -> str: + if _has_cjk(concept): + return concept.strip() + text = concept.strip().lower() + return text.replace(" ", "_") + + def _resolve_index(self, concept: str) -> Optional[int]: + if not self._vocab: + return None + key = self._normalize_key(concept) + if key in self._vocab: + return int(self._vocab[key]) + alt = key.replace("_", " ") + if alt in self._vocab: + return int(self._vocab[alt]) + if concept in self._vocab: + return int(self._vocab[concept]) + if _has_cjk(concept): + prefixed = f"/c/zh/{key}" + else: + prefixed = f"/c/en/{key}" + if prefixed in self._vocab: + return int(self._vocab[prefixed]) + return None + + def get_vector(self, concept: str) -> Optional[np.ndarray]: + idx = self._resolve_index(concept) + if idx is None: + return None + self._load_vectors() + if self._vectors is None: + return None + return self._vectors[idx] + + def cosine_similarity(self, left: str, right: str) -> Optional[float]: + vec_left = self.get_vector(left) + vec_right = self.get_vector(right) + if vec_left is None or vec_right is None: + return None + denom = float(np.linalg.norm(vec_left) * np.linalg.norm(vec_right)) + if denom <= 0: + return None + return float(np.dot(vec_left, vec_right) / denom) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/local_concept_extractor.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/local_concept_extractor.py new file mode 100644 index 0000000..ca5631c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/local_concept_extractor.py @@ -0,0 +1,327 @@ +from __future__ import annotations + +import re +from collections import Counter +from typing import Dict, Iterable, List, Optional + +from loguru import logger + +from .kb.conceptnet_store import ConceptNetStore, _has_cjk +from .kb.embedding_store import EmbeddingStore + + +CAUSAL_MARKERS_ZH = ( + "导致", "引起", "造成", "使得", "因此", "从而", "所以", "促使", "引发", "产生", +) +CAUSAL_MARKERS_EN = ( + "causes", "cause", "leads to", "lead to", "results in", "result in", + "drives", "drive", "triggers", "trigger", +) + +FUNCTION_MARKERS_ZH = ("用于", "用来", "适用于") +STRUCTURAL_MARKERS_ZH = ("由", "组成", "包括", "包含") + +PROCESS_HINTS_ZH = ("过程", "变化", "流动", "转换", "生成", "传递", "驱动", "扩散", "反应") +PROPERTY_HINTS_ZH = ("温度", "电压", "速度", "压力", "浓度", "功率", "能量", "电流", "阻力") +PROCESS_HINTS_EN = ("process", "flow", "transfer", "conversion", "generation", "drive", "trigger") +PROPERTY_HINTS_EN = ("temperature", "voltage", "speed", "pressure", "density", "power", "energy", "current", "resistance") + +STOPWORDS_EN = { + "what", "is", "are", "was", "were", "do", "does", "did", + "a", "an", "the", "to", "of", "for", "in", "on", "with", + "and", "or", "as", "by", "from", "into", "that", "this", + "these", "those", "used", "use", "using", "about", "why", + "how", "when", "where", "which", "who", "whom", "whose", +} + +STOPWORDS_ZH = { + "什么", "为何", "为什么", "怎么", "怎样", "如何", "是否", "是不是", + "的", "了", "在", "与", "和", "以及", "或", "及", "对", "为", + "有", "没有", "能", "不能", "会", "不会", "应该", "可能", + "用于", "导致", "能够", "由", "组成", "包括", "限制", "阻止", + "如果", "把", "将", "使", "让", "会产生", "会导致", "作用", "功能", +} + +RELATION_MAP = { + "Causes": "导致", + "CausesDesire": "触发", + "HasA": "具有", + "PartOf": "组成", + "IsA": "属于", + "UsedFor": "用途", + "CapableOf": "能够", + "HasProperty": "具有", + "LocatedNear": "靠近", + "AtLocation": "位于", + "RelatedTo": "相关", + "ReceivesAction": "受到", + "CreatedBy": "产生", + "MotivatedByGoal": "动机", + "ObstructedBy": "阻碍", +} + + +def _split_sentences(text: str) -> List[str]: + parts = re.split(r"[。!?;;!?]\s*", text) + return [part.strip() for part in parts if part.strip()] + + +def _tokenize_en(text: str) -> List[str]: + return re.findall(r"[a-zA-Z][a-zA-Z0-9\-]*", text.lower()) + + +def _extract_cjk_sequences(text: str) -> List[str]: + return re.findall(r"[\u4e00-\u9fff]{2,}", text) + + +def _order_concepts_by_text(text: str, concepts: Iterable[str]) -> List[str]: + hits = [] + for concept in concepts: + idx = text.find(concept) + if idx >= 0: + hits.append((idx, concept)) + hits.sort(key=lambda item: item[0]) + return [concept for _, concept in hits] + + +def _generate_ngrams(tokens: List[str], min_n: int, max_n: int) -> List[str]: + results: List[str] = [] + for n in range(min_n, max_n + 1): + for i in range(0, max(len(tokens) - n + 1, 0)): + results.append(" ".join(tokens[i:i + n])) + return results + + +def _generate_cjk_ngrams(text: str, min_n: int, max_n: int) -> List[str]: + results: List[str] = [] + length = len(text) + for n in range(min_n, max_n + 1): + for i in range(0, max(length - n + 1, 0)): + results.append(text[i:i + n]) + return results + + +def _infer_type(concept: str) -> str: + lowered = concept.lower() + if _has_cjk(concept): + if any(hint in concept for hint in PROCESS_HINTS_ZH): + return "process" + if any(hint in concept for hint in PROPERTY_HINTS_ZH): + return "property" + return "entity" + if any(hint in lowered for hint in PROCESS_HINTS_EN): + return "process" + if any(hint in lowered for hint in PROPERTY_HINTS_EN): + return "property" + return "entity" + + +def _dedupe_relations(relations: Iterable[Dict]) -> List[Dict]: + seen = set() + unique: List[Dict] = [] + for rel in relations: + key = (rel.get("from"), rel.get("to"), rel.get("relation")) + if key in seen: + continue + seen.add(key) + unique.append(rel) + return unique + + +class LocalConceptExtractor: + """Rule-based concept extractor backed by ConceptNet.""" + + def __init__(self, store: Optional[ConceptNetStore] = None, embedding_store: Optional[EmbeddingStore] = None) -> None: + self.store = store + self.embedding_store = embedding_store + self.MAX_CONCEPTS = None + self.MAX_RELATIONS = 25 + self.DEDUPE_SIM_THRESHOLD = 0.88 + self.last_warnings: List[str] = [] + + def _apply_limit(self, items, limit): + if limit and limit > 0: + return items[:limit] + return items + + def _filter_candidates(self, candidates: List[str]) -> List[str]: + filtered = [] + for term in candidates: + if not term: + continue + if len(term) > 40: + continue + if _has_cjk(term): + if len(term) < 2: + continue + if term in STOPWORDS_ZH: + continue + else: + if len(term) < 2: + continue + if term.lower() in STOPWORDS_EN: + continue + filtered.append(term) + return filtered + + def _dedupe_by_embedding(self, concepts: List[str]) -> List[str]: + if not concepts: + return [] + if not self.embedding_store or not self.embedding_store.available: + return self._apply_limit(concepts, self.MAX_CONCEPTS) + kept: List[str] = [] + for concept in concepts: + duplicate = False + for existing in kept: + score = self.embedding_store.cosine_similarity(concept, existing) + if score is not None and score >= self.DEDUPE_SIM_THRESHOLD: + duplicate = True + break + if not duplicate: + kept.append(concept) + if self.MAX_CONCEPTS and self.MAX_CONCEPTS > 0 and len(kept) >= self.MAX_CONCEPTS: + break + return kept + + def _extract_concepts(self, text: str) -> List[str]: + text = text.strip() + if not text: + return [] + candidates: List[str] = [] + cjk_segments = _extract_cjk_sequences(text) + for seg in cjk_segments: + candidates.extend(_generate_cjk_ngrams(seg, 2, 4)) + candidates.append(seg) + en_tokens = _tokenize_en(text) + candidates.extend(_generate_ngrams(en_tokens, 1, 3)) + candidates = self._filter_candidates(candidates) + if len(candidates) > 600: + unique = list(dict.fromkeys(candidates)) + unique.sort(key=lambda item: (-len(item), item)) + candidates = unique[:600] + + if self.store and self.store.available: + zh_candidates = [c for c in candidates if _has_cjk(c)] + en_candidates = [c for c in candidates if not _has_cjk(c)] + known: List[str] = [] + if zh_candidates: + known.extend(self.store.find_concepts(zh_candidates, lang="zh")) + if en_candidates: + known.extend(self.store.find_concepts(en_candidates, lang="en")) + if known: + counts = Counter(candidates) + unique_known = list(dict.fromkeys(known)) + unique_known.sort(key=lambda item: (-counts.get(item, 0), -len(item), item)) + return self._dedupe_by_embedding(unique_known) + + counts = Counter(candidates) + ranked = sorted(counts.items(), key=lambda item: (-item[1], -len(item[0]), item[0])) + ranked_terms = [term for term, _ in ranked] + ranked_terms = self._apply_limit(ranked_terms, self.MAX_CONCEPTS) + return self._dedupe_by_embedding(ranked_terms) + + def _extract_marker_relations(self, sentences: List[str], concepts: List[str]) -> List[Dict]: + relations: List[Dict] = [] + if not concepts: + return relations + concept_set = set(concepts) + for sentence in sentences: + lowered = sentence.lower() + for marker in CAUSAL_MARKERS_ZH: + if marker in sentence: + left, right = sentence.split(marker, 1) + left_concepts = _order_concepts_by_text(left, concept_set) + right_concepts = _order_concepts_by_text(right, concept_set) + if left_concepts and right_concepts: + relations.append({ + "from": left_concepts[-1], + "to": right_concepts[0], + "relation": "导致", + "weight": 0.85, + "source": "text", + }) + for marker in CAUSAL_MARKERS_EN: + if marker in lowered: + parts = lowered.split(marker, 1) + if len(parts) != 2: + continue + left, right = parts + left_concepts = _order_concepts_by_text(left, [c for c in concept_set if c.lower() in left]) + right_concepts = _order_concepts_by_text(right, [c for c in concept_set if c.lower() in right]) + if left_concepts and right_concepts: + relations.append({ + "from": left_concepts[-1], + "to": right_concepts[0], + "relation": "causes", + "weight": 0.85, + "source": "text", + }) + for marker in FUNCTION_MARKERS_ZH: + if marker in sentence: + left, right = sentence.split(marker, 1) + left_concepts = _order_concepts_by_text(left, concept_set) + right_concepts = _order_concepts_by_text(right, concept_set) + if left_concepts and right_concepts: + relations.append({ + "from": left_concepts[-1], + "to": right_concepts[0], + "relation": "用于", + "weight": 0.82, + "source": "text", + }) + for marker in STRUCTURAL_MARKERS_ZH: + if marker in sentence: + left, right = sentence.split(marker, 1) + left_concepts = _order_concepts_by_text(left, concept_set) + right_concepts = _order_concepts_by_text(right, concept_set) + if left_concepts and right_concepts: + relations.append({ + "from": left_concepts[-1], + "to": right_concepts[0], + "relation": "组成", + "weight": 0.8, + "source": "text", + }) + return relations + + def _extract_kb_relations(self, concepts: List[str]) -> List[Dict]: + if not self.store or not self.store.available: + return [] + kb_edges = self.store.get_edges_between(concepts, limit_per_concept=20) + relations: List[Dict] = [] + for edge in kb_edges: + weight = min(0.7, max(0.35, float(edge.get("weight", 0.5)) / 2.0)) + relations.append({ + "from": edge.get("source"), + "to": edge.get("target"), + "relation": RELATION_MAP.get(edge.get("relation", ""), edge.get("relation", "related_to")), + "weight": weight, + "source": "kb", + }) + return relations + + def extract(self, text: str) -> Optional[Dict]: + self.last_warnings = [] + concepts = self._extract_concepts(text) + if not concepts: + self.last_warnings.append("未命中ConceptNet词表,已退化为文本关键词抽取。") + fallback_candidates = _tokenize_en(text) + for seg in _extract_cjk_sequences(text): + fallback_candidates.append(seg) + concepts = self._apply_limit(self._filter_candidates(fallback_candidates), self.MAX_CONCEPTS) + + concept_records = [{"concept": concept, "type": _infer_type(concept)} for concept in concepts] + + sentences = _split_sentences(text) + relations = [] + relations.extend(self._extract_marker_relations(sentences, concepts)) + relations.extend(self._extract_kb_relations(concepts)) + relations = _dedupe_relations(relations) + relations = sorted(relations, key=lambda item: (-item.get("weight", 0.5), item.get("relation", ""))) + relations = self._apply_limit(relations, self.MAX_RELATIONS) + + if not relations: + self.last_warnings.append("未抽取到显式关系,建议提高文本中的因果连接词密度。") + + logger.info("Local extractor: {} concepts, {} relations", len(concept_records), len(relations)) + return {"concepts": concept_records, "relations": relations} diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/maze_engine.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/maze_engine.py new file mode 100644 index 0000000..c05c154 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/maze_engine.py @@ -0,0 +1,852 @@ +""" +真正的迷宫引擎核心 +实现 Tri-Maze 概念推理架构 + 隧穿机制 + 自适应概念扩展 + 长期概念记忆 + 回溯式路径研磨机制 +""" +import networkx as nx +import math +import os +import random +from typing import List, Dict, Tuple, Set, Any, Literal, Optional +from collections import deque +import asyncio +from loguru import logger +import numpy as np +import json +from .concept_memory import ConceptMemory +from .multimodal_generator import MultimodalGenerator +from .policy_network import EdgePolicy + + +class MazeNode: + """迷宫节点 = 概念节点""" + def __init__(self, concept: str, concept_type: str = "general", context_profile: Dict[str, int] | None = None): + self.concept = concept + self.type = concept_type + self.visited = False + self.resistance = 0.0 # 节点阻力 + self.connections = [] # 连接的边 + self.expanded = False # 是否已扩展/研磨过 + self.expand_level = 0 # 研磨层级,0=未研磨,越大越细 + self.expand_time = None + self.context_profile = context_profile or {} + self.activation = 0.0 # 扩展时间 + + def __repr__(self): + return f"Node({self.concept}, level={self.expand_level}, expanded={self.expanded})" + + +class MazeEdge: + """迷宫边 = 概念关系""" + def __init__(self, from_node: MazeNode, to_node: MazeNode, + relation: str, resistance: float = 0.5): + self.from_node = from_node + self.to_node = to_node + self.relation = relation + self.resistance = resistance # 通道阻力,0-1,越小越容易通过 + self.valid = True + self.is_tunneling = False # 是否是隧穿生成的边 + self.is_expanded = False # 是否是扩展生成的边 + self.is_memory = False # 是否来自记忆 + + def __repr__(self): + return f"Edge({self.from_node.concept} → {self.to_node.concept}: {self.relation})" + + +class MazePath: + """迷宫路径 = 推理路径""" + def __init__(self, nodes: List[MazeNode], edges: List[MazeEdge]): + self.nodes = nodes + self.edges = edges + self.total_resistance = sum(e.resistance for e in edges) + self.valid = True + self.score_value = 0.0 + self.has_tunneling = any(e.is_tunneling for e in edges) # 是否包含隧穿 + self.has_expanded = any(e.is_expanded for e in edges) # 是否包含扩展节点 + self.has_memory = any(e.is_memory for e in edges) # 是否包含记忆边 + self.failed = False # 路径是否走不通 + + @property + def length(self): + return len(self.edges) + + def add_step(self, node: MazeNode, edge: MazeEdge): + self.nodes.append(node) + self.edges.append(edge) + self.total_resistance += edge.resistance + if edge.is_tunneling: + self.has_tunneling = True + if edge.is_expanded: + self.has_expanded = True + if edge.is_memory: + self.has_memory = True + + def copy(self): + return MazePath(self.nodes.copy(), self.edges.copy()) + + def get_concept_list(self) -> List[str]: + """获取路径上的概念列表""" + return [n.concept for n in self.nodes] + + def get_last_n_nodes(self, n: int) -> List[MazeNode]: + """获取最后n个节点,用于回溯""" + return self.nodes[-n:] if len(self.nodes) >=n else self.nodes + + def score(self, length_penalty: float = 0.05) -> float: + return self.total_resistance + length_penalty * self.length + + + def __repr__(self): + path_str = " → ".join([n.concept for n in self.nodes]) + tags = [] + if self.has_tunneling: + tags.append("TUNNELING") + if self.has_expanded: + tags.append("EXPANDED") + if self.has_memory: + tags.append("MEMORY") + if self.failed: + tags.append("FAILED") + tag_str = f" [{','.join(tags)}]" if tags else "" + return f"Path({path_str}, resistance={self.total_resistance:.2f}){tag_str}" + + +class ReasoningMonitor: + """推理监控器:实时监控推理状态,决定是否触发回溯研磨""" + + def __init__(self, engine): + self.engine = engine + self.best_resistance_history = [] # 历史最优路径阻力 + self.stagnation_rounds = 0 # 停滞轮数 + self.max_stagnation_rounds = 3 # 最大停滞轮数,超过触发回溯研磨 + self.min_connectivity_threshold = 2 # 最小连接度阈值 + self.total_nodes_limit = 200 # 总节点数上限 + self.max_expansions_per_round = 3 # 每轮最多研磨节点数 + self.max_grind_level = 3 # 最大研磨层级,避免无限细化 + self.high_resistance_threshold = 0.9 # 高阻力阈值,超过认为路径走不通 + self.backtrack_steps = 1 # 回溯步数,走不通时回退n个节点研磨 + + def update(self, current_best_resistance: float): + """更新监控状态""" + self.best_resistance_history.append(current_best_resistance) + + # 检查是否停滞 + if len(self.best_resistance_history) >= 2: + if abs(current_best_resistance - self.best_resistance_history[-2]) < 0.01: + self.stagnation_rounds += 1 + else: + self.stagnation_rounds = 0 + + def should_grind_path(self, path: MazePath) -> Tuple[bool, Optional[MazeNode], str]: + """判断是否需要研磨该路径 + :return: (是否需要研磨, 要研磨的节点, 原因) + """ + def _can_grind(node: MazeNode | None) -> bool: + return bool(node and node.expand_level < self.max_grind_level and (node.context_profile or {})) + + # 全局限制 + if len(self.engine.nodes) >= self.total_nodes_limit: + return False, None, "节点总数已达上限" + + # 条件1:路径阻力过高,走不通 + if path.score(self.engine.length_penalty) >= self.high_resistance_threshold: + # 回溯到上一个节点 + backtrack_node = path.get_last_n_nodes(self.backtrack_steps)[0] + if _can_grind(backtrack_node): + return True, backtrack_node, "high_resistance" + return False, None, "节点缺少可研磨上下文" + + # 条件2:连续多轮停滞 + if self.stagnation_rounds >= self.max_stagnation_rounds: + # 选择当前路径中间的节点研磨 + if path.nodes: + mid_idx = len(path.nodes) // 2 + grind_node = path.nodes[mid_idx] + if _can_grind(grind_node): + return True, grind_node, "stagnation" + return False, None, "没有适合研磨的节点" + + # 条件3:节点连接度过低,没有足够路径可选 + if path.nodes: + current_node = path.nodes[-1] + node_degree = len(current_node.connections) + if node_degree < self.min_connectivity_threshold and _can_grind(current_node): + return True, current_node, "low_connectivity" + + return False, None, "no_need" + + +class TriMazeEngine: + """三迷宫引擎核心 + 隧穿机制 + 自适应概念扩展 + 长期记忆 + 回溯式路径研磨""" + + def __init__( + self, + concept_graph: nx.DiGraph, + concept_memory: Optional[ConceptMemory] = None, + multimodal_generator: Optional[MultimodalGenerator] = None, + policy: EdgePolicy | None = None, + policy_enabled: bool = True, + policy_checkpoint_path: str | None = None, + policy_rollout: Literal["off", "blend"] = "off", + policy_alpha: float = 0.35, + ): + self.graph = concept_graph + self.memory = concept_memory or ConceptMemory() # ?????? + self.multimodal_generator = multimodal_generator or MultimodalGenerator(None) # ?????? + self.nodes: Dict[str, MazeNode] = {} + self.edges: List[MazeEdge] = [] + self._build_maze() + self._max_degree = max((len(n.connections) for n in self.nodes.values()), default=1) + + # 迷宫配置 + self.max_exploration_steps = 80 + self.max_paths = None + self.resistance_threshold = 0.8 # 高阻力阈值 + self.exploration_rate = 0.3 # ??????????????? + self.length_penalty = 0.05 # ?????? # 探索率,越大越喜欢尝试未知路径 + + # 隧穿配置 + self.tunneling_enabled = True + self.tunneling_probability = 0.2 # 隧穿触发概率 + self.tunneling_max_distance = 5 # 隧穿最大跳跃距离(节点数) + self.tunneling_min_resistance = 0.3 # 隧穿路径最小阻力 + self.tunneling_validation_enabled = True # 隧穿路径双重验证 + + # 路径研磨配置 + self.grinding_enabled = True + self.reasoning_monitor = ReasoningMonitor(self) + + # Policy network (optional) + self.policy = policy or EdgePolicy() + self.policy_enabled = bool(policy_enabled) and self.policy.enabled + self.policy_branch_factor = 2 + self.policy_rollout: Literal["off", "blend"] = "blend" if policy_rollout == "blend" else "off" + self.policy_alpha = max(0.0, min(1.0, float(policy_alpha))) + env_policy_checkpoint = os.getenv("TMCRA_POLICY_CHECKPOINT_PATH", "").strip() + self.policy_checkpoint_path = (policy_checkpoint_path or env_policy_checkpoint or "").strip() or None + self.policy_loaded = False + self.policy_metadata: Dict[str, Any] = {} + if self.policy_enabled: + self.policy.set_max_degree(self._max_degree) + if self.policy_checkpoint_path: + try: + self.policy_metadata = self.policy.load_checkpoint(self.policy_checkpoint_path, load_optimizer=False) + self.policy.set_max_degree(self._max_degree) + self.policy_loaded = True + logger.info("✅ Tri-Maze policy checkpoint loaded: {}", self.policy_checkpoint_path) + except Exception as exc: + logger.warning("Policy checkpoint load failed; fallback to heuristic mode: {}", exc) + self.policy_loaded = False + self.policy_metadata = {} + elif policy is not None and self.policy_rollout == "blend": + self.policy_loaded = True + if not self.policy_enabled or not self.policy_loaded or self.policy_rollout != "blend": + self.policy_rollout = "off" + logger.info("Tri-Maze policy rollout: {}", self.policy_rollout) + + logger.info("✅ 三迷宫引擎 + 隧穿 + 回溯研磨 + 长期记忆 初始化完成") + + def _build_maze(self): + """从概念图构建迷宫""" + # 创建节点 + for node in self.graph.nodes: + node_data = self.graph.nodes[node] + self.nodes[node] = MazeNode( + concept=node, + concept_type=node_data.get("type", "general"), + context_profile=node_data.get("context_profile", {}), + ) + + # 创建边 + for u, v, data in self.graph.edges(data=True): + # 应用记忆强化 + reinforcement = self.memory.get_edge_reinforcement(u, v) + source_kind = str(data.get("source_kind", "")).strip().lower() + if "resistance" in data: + try: + base_resistance = max(0.0, min(1.0, float(data.get("resistance", 0.5)))) + except Exception: + base_resistance = 0.5 + else: + try: + relation_weight = max(0.0, min(1.0, float(data.get("weight", 0.5)))) + except Exception: + relation_weight = 0.5 + base_resistance = 1.0 - relation_weight + final_resistance = max(0.1, base_resistance - reinforcement) # 强化后阻力降低 + + edge = MazeEdge( + from_node=self.nodes[u], + to_node=self.nodes[v], + relation=data.get("relation", "related_to"), + resistance=final_resistance + ) + if reinforcement > 0: + edge.is_memory = True # 标记为记忆边 + + edge.source_kind = source_kind + if source_kind.endswith("memory"): + edge.is_memory = True + self.edges.append(edge) + self.nodes[u].connections.append(edge) + + def reset_visits(self): + """重置所有节点访问状态""" + for node in self.nodes.values(): + node.visited = False + + def _softmax_scores(self, scores: List[float]) -> np.ndarray: + if not scores: + return np.asarray([], dtype=np.float64) + arr = np.asarray(scores, dtype=np.float64) + shifted = arr - np.max(arr) + exp = np.exp(shifted) + total = float(exp.sum()) + if total <= 0: + return np.full(len(scores), 1.0 / max(1, len(scores)), dtype=np.float64) + return exp / total + + def _forward_heuristic_probabilities(self, candidate_edges: List[MazeEdge]) -> np.ndarray: + scores: List[float] = [] + for edge in candidate_edges: + resistance = float(edge.resistance) + if resistance < 0.6: + score = max(0.05, 1.2 - resistance) + else: + score = max(0.01, self.exploration_rate * max(0.05, 1.0 - resistance)) + scores.append(score) + return self._softmax_scores(scores) + + def _select_forward_edges_blend( + self, + current_node: MazeNode, + candidate_edges: List[MazeEdge], + current_path: MazePath, + current_visited: Set[str], + ) -> List[MazeEdge]: + if not candidate_edges: + return [] + k = min(self.policy_branch_factor, len(candidate_edges)) + heuristic_prob = self._forward_heuristic_probabilities(candidate_edges) + evaluated = self.policy.evaluate_candidates( + engine=self, + current_node=current_node, + candidate_edges=candidate_edges, + path=current_path, + visited=current_visited, + mode="forward", + ) + if evaluated is None: + return candidate_edges[:k] + policy_prob = evaluated["probs"].detach().cpu().numpy().astype(np.float64) + combined = (1.0 - self.policy_alpha) * heuristic_prob + self.policy_alpha * policy_prob + if not np.isfinite(combined).all() or float(combined.sum()) <= 0.0: + combined = heuristic_prob + top_indices = np.argsort(-combined)[:k] + return [candidate_edges[int(index)] for index in top_indices] + + def _token_set(self, concept: str) -> Set[str]: + text = concept.lower().replace("_", " ").replace("-", " ") + if " " in text: + return {part for part in text.split() if part} + return {char for char in text if char.strip()} + + + def _semantic_similarity(self, left: str, right: str) -> float: + if left == right: + return 1.0 + left_node = self.nodes.get(left) + right_node = self.nodes.get(right) + if left_node and right_node: + left_profile = left_node.context_profile or {} + right_profile = right_node.context_profile or {} + if left_profile and right_profile: + left_top = {k for k, _ in sorted(left_profile.items(), key=lambda item: -item[1])[:10]} + right_top = {k for k, _ in sorted(right_profile.items(), key=lambda item: -item[1])[:10]} + if left_top or right_top: + overlap = len(left_top & right_top) / max(1, len(left_top | right_top)) + return max(0.0, min(1.0, overlap)) + # fallback to token overlap + overlap = 0.0 + left_tokens = self._token_set(left) + right_tokens = self._token_set(right) + if left_tokens or right_tokens: + overlap = len(left_tokens & right_tokens) / max(1, len(left_tokens | right_tokens)) + return max(0.0, min(1.0, overlap)) + + def _try_tunneling(self, current_node: MazeNode, visited: Set[str]) -> Optional[Tuple[MazeNode, MazeEdge]]: + """尝试隧穿:跳跃到远距离节点 + :return: (目标节点, 隧穿边) 隧穿失败返回 None + """ + if not self.tunneling_enabled or random.random() > self.tunneling_probability: + return None + + # 找到所有未访问的远距离节点 + all_nodes = list(self.nodes.values()) + candidate_nodes = [] + for n in all_nodes: + if n.concept not in visited and n != current_node: + # 计算概念距离(简单实现:路径长度) + try: + path_len = nx.shortest_path_length(self.graph, current_node.concept, n.concept) + if path_len >= 2: + candidate_nodes.append(n) + except nx.NetworkXNoPath: + # 没有路径,视为远距离节点 + candidate_nodes.append(n) + + if not candidate_nodes: + return None + + # 按语义相似度排序,优先选择语义相关节点 + scored = [] + for node in candidate_nodes: + score = self._semantic_similarity(current_node.concept, node.concept) + scored.append((score, node)) + scored.sort(key=lambda item: item[0], reverse=True) + top_candidates = scored[: min(6, len(scored))] + if not top_candidates: + return None + weights = [max(0.05, score) for score, _ in top_candidates] + target_node = random.choices([node for _, node in top_candidates], weights=weights, k=1)[0] + + # 生成隧穿边 + tunneling_edge = MazeEdge( + from_node=current_node, + to_node=target_node, + relation=f"隧穿连接[{current_node.concept}→{target_node.concept}]", + resistance=random.uniform(self.tunneling_min_resistance, 0.7) + ) + tunneling_edge.is_tunneling = True + + logger.info(f"🔌 隧穿触发:{current_node.concept} → {target_node.concept} (阻力: {tunneling_edge.resistance:.2f})") + return target_node, tunneling_edge + + + def _path_visited_concepts(self, path: MazePath | None) -> Set[str]: + """Return concepts already used in the current path.""" + if not path: + return set() + return { + node.concept + for node in getattr(path, "nodes", []) + if getattr(node, "concept", None) + } + + def _grind_node_native(self, node: MazeNode, count: int = 4) -> List[Dict]: + """Native grinding based on local co-occurrence profile.""" + if not self.grinding_enabled: + return [] + if node.expand_level >= self.reasoning_monitor.max_grind_level: + logger.warning(f"??? ?? {node.concept} ???????? {node.expand_level}") + return [] + if node.expanded: + logger.warning(f"??? ?? {node.concept} ???????") + return [] + + profile = node.context_profile or {} + if not profile: + logger.debug(f"skip grinding without context profile: {node.concept}") + return [] + + candidates = sorted(profile.items(), key=lambda item: -item[1]) + if not candidates: + return [] + + max_count = max(1, candidates[0][1]) + sub_concepts = [] + for concept, cnt in candidates[:count]: + if concept == node.concept: + continue + weight = max(0.2, min(0.9, cnt / max_count)) + sub_concepts.append({ + "concept": concept, + "relation": "refines", + "weight": weight, + }) + + return self._apply_grind(node, sub_concepts) + + def _apply_grind(self, node: MazeNode, sub_concepts: List[Dict]) -> List[Dict]: + if not sub_concepts: + return [] + + # ???????? + new_nodes = [] + for sub in sub_concepts: + sub_concept = sub["concept"] + relation = sub["relation"] + weight = sub.get("weight", 0.5) + + if sub_concept not in self.nodes: + self.graph.add_node(sub_concept, type=node.type) + new_node = MazeNode(sub_concept, node.type) + new_node.expand_level = node.expand_level + 1 + self.nodes[sub_concept] = new_node + new_nodes.append(new_node) + + self.memory.add_concept( + sub_concept, + node.type, + "grinding", + importance_score=0.6 + node.expand_level * 0.1, + ) + else: + new_node = self.nodes[sub_concept] + + self.graph.add_edge(node.concept, sub_concept, relation=relation, weight=weight) + new_edge = MazeEdge( + from_node=node, + to_node=new_node, + relation=relation, + resistance=max(0.1, 1 - weight * 0.8), + ) + new_edge.is_expanded = True + self.edges.append(new_edge) + node.connections.append(new_edge) + + node.expanded = True + node.expand_level += 1 + + self.memory.add_concept( + node.concept, + node.type, + "grinding", + importance_score=0.7, + ) + + logger.info(f"? ????: {node.concept} -> {[s['concept'] for s in sub_concepts]}") + return sub_concepts + + def _validate_tunneling_path(self, path: MazePath) -> bool: + """验证隧穿路径:双重验证机制""" + if not self.tunneling_validation_enabled or not path.has_tunneling: + return True + + logger.info(f"🔍 验证隧穿路径: {path}") + + # 正向验证:路径是否能形成合理解释 + if path.score(self.length_penalty) > self.resistance_threshold * 1.2: + logger.warning(f"❌ 隧穿路径阻力过高,验证失败") + return False + + # 反向验证:是否存在明显矛盾 + concepts = [n.concept for n in path.nodes] + contradiction_pairs = [ + ("水", "电"), ("火", "水"), ("高温", "塑料"), + ("高压", "低压"), ("开", "关"), ("真", "假") + ] + + for a, b in contradiction_pairs: + if a in concepts and b in concepts: + logger.warning(f"❌ 隧穿路径存在矛盾:{a} 和 {b} 共存") + return False + + logger.info(f"✅ 隧穿路径验证通过") + return True + + async def forward_maze_explore(self, start_concept: str, target_concept: Optional[str] = None) -> List[MazePath]: + """ + 正向迷宫:探索低阻力路径(最合理的解释) + 支持路径失败回溯研磨机制:路径走不通时回溯研磨节点,重新探索 + """ + logger.info(f"🔍 正向迷宫探索:从 {start_concept} 出发") + + if start_concept not in self.nodes: + logger.error(f"起点概念 {start_concept} 不存在") + return [] + + self.reset_visits() + start_node = self.nodes[start_concept] + paths: List[MazePath] = [] + queue = deque() + + # 初始化路径 + initial_path = MazePath([start_node], []) + queue.append(initial_path) + start_node.visited = True + + explored = 0 + best_resistance = float('inf') + grinded_nodes = 0 + max_grinds = self.reasoning_monitor.max_expansions_per_round + + while queue and (not self.max_paths or self.max_paths <= 0 or len(paths) < self.max_paths) and explored < self.max_exploration_steps: + current_path = queue.popleft() + current_node = current_path.nodes[-1] + + # 更新监控器 + if current_path.score(self.length_penalty) < best_resistance: + best_resistance = current_path.score(self.length_penalty) + self.reasoning_monitor.update(best_resistance) + + # 检查路径是否走不通,需要回溯研磨 + if self.grinding_enabled and grinded_nodes < max_grinds: + should_grind, grind_node, reason = self.reasoning_monitor.should_grind_path(current_path) + if should_grind and grind_node: + logger.info(f"🔙 路径走不通,触发回溯研磨") + logger.info(f"节点: {grind_node.concept}") + logger.info(f"原因: {reason}") + + # 研磨节点 + new_concepts = self._grind_node_native(grind_node) + if new_concepts: + logger.info(f"新概念: {[c['concept'] for c in new_concepts]}") + grinded_nodes += 1 + # 研磨后重新初始化队列,从起点开始探索新路径 + queue = deque([initial_path]) + self.reset_visits() + continue + + # 找到目标(如果有)或路径足够长且阻力合理 + if (target_concept and current_node.concept == target_concept) or (not target_concept and current_path.length >= 2 and current_path.score(self.length_penalty) < self.resistance_threshold): + # 验证隧穿路径 + if self._validate_tunneling_path(current_path): + paths.append(current_path) + continue + + # 尝试隧穿 + current_visited = self._path_visited_concepts(current_path) + tunnel_result = self._try_tunneling(current_node, current_visited) + if tunnel_result: + tunnel_node, tunnel_edge = tunnel_result + if tunnel_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(tunnel_node, tunnel_edge) + queue.append(new_path) + + # 探索所有连接 + if self.policy_enabled: + candidate_edges = current_node.connections + if candidate_edges: + k = min(self.policy_branch_factor, len(candidate_edges)) + selected_edges = self.policy.select_edges( + engine=self, + current_node=current_node, + candidate_edges=candidate_edges, + path=current_path, + visited=current_visited, + mode="forward", + k=k, + deterministic=False, + ) + for edge in selected_edges: + next_node = edge.to_node + if next_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(next_node, edge) + queue.append(new_path) + else: + for edge in current_node.connections: + next_node = edge.to_node + + # 低阻力优先 + 一定概率探索未知 + if edge.resistance < 0.6 or random.random() < self.exploration_rate: + if next_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(next_node, edge) + queue.append(new_path) + + explored += 1 + + # 优先保留显式、低阻力、非隧穿路径,避免“捷径”压过主干因果链 + paths.sort( + key=lambda p: ( + p.score(self.length_penalty), + 1 if p.has_tunneling else 0, + 1 if p.has_memory else 0, + p.length, + ) + ) + + # 记忆钩子:保存成功路径 + for path in paths: + path_score = 1.0 - path.score(self.length_penalty) # 阻力越低分数越高 + self.memory.save_successful_path(path.get_concept_list(), path_score) + + # 更新路径上概念的重要性 + for node in path.nodes: + self.memory.update_concept_importance(node.concept, 0.1) + + # Online policy update (optional) + if self.policy_enabled: + self.policy.update_from_path(self, path, mode="forward") + + tunnel_count = sum(1 for p in paths if p.has_tunneling) + expanded_count = sum(1 for p in paths if p.has_expanded) + memory_count = sum(1 for p in paths if p.has_memory) + + logger.info(f"✅ 正向迷宫找到 {len(paths)} 条路径,其中 {tunnel_count} 条包含隧穿,{expanded_count} 条包含研磨节点,{memory_count} 条包含记忆边") + return paths + + async def reverse_maze_explore(self, start_concept: str, target_concept: Optional[str] = None) -> List[MazePath]: + """ + 反向迷宫:探索高阻力路径(找矛盾和反例) + 专门找难走的路,验证是否存在反例,支持隧穿 + """ + logger.info(f"🔍 反向迷宫探索:从 {start_concept} 出发找反例") + + if start_concept not in self.nodes: + logger.error(f"起点概念 {start_concept} 不存在") + return [] + + self.reset_visits() + start_node = self.nodes[start_concept] + paths: List[MazePath] = [] + stack = [] # DFS 优先探索深路径 + + initial_path = MazePath([start_node], []) + stack.append(initial_path) + + explored = 0 + while stack and (not self.max_paths or self.max_paths <= 0 or len(paths) < self.max_paths) and explored < self.max_exploration_steps: + current_path = stack.pop() + current_node = current_path.nodes[-1] + current_visited = self._path_visited_concepts(current_path) + + # 找到矛盾路径或高阻力路径 + if current_path.score(self.length_penalty) > self.resistance_threshold and current_path.length >= 2: + # 验证隧穿路径 + if self._validate_tunneling_path(current_path): + paths.append(current_path) + continue + + # 尝试隧穿(反向迷宫隧穿概率更高) + original_tunnel_prob = self.tunneling_probability + self.tunneling_probability = 0.3 + tunnel_result = self._try_tunneling(current_node, current_visited) + self.tunneling_probability = original_tunnel_prob + + if tunnel_result: + tunnel_node, tunnel_edge = tunnel_result + if tunnel_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(tunnel_node, tunnel_edge) + stack.append(new_path) + + # 优先探索高阻力边 + candidate_edges = [e for e in current_node.connections if e.resistance > self.resistance_threshold * 0.7] + if self.policy_enabled and candidate_edges: + k = min(self.policy_branch_factor, len(candidate_edges)) + selected_edges = self.policy.select_edges( + engine=self, + current_node=current_node, + candidate_edges=candidate_edges, + path=current_path, + visited=current_visited, + mode="reverse", + k=k, + deterministic=True, + ) + for edge in selected_edges: + next_node = edge.to_node + if next_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(next_node, edge) + stack.append(new_path) + else: + for edge in sorted(current_node.connections, key=lambda e: -e.resistance): + next_node = edge.to_node + # 高阻力优先,尽量找矛盾 + if edge.resistance > self.resistance_threshold * 0.7: + if next_node.concept not in current_visited: + new_path = current_path.copy() + new_path.add_step(next_node, edge) + stack.append(new_path) + + explored += 1 + + # 按阻力排序,阻力越大越可能是矛盾 + paths.sort(key=lambda p: -p.score(self.length_penalty)) + tunnel_count = sum(1 for p in paths if p.has_tunneling) + logger.info(f"✅ 反向迷宫找到 {len(paths)} 条高阻力路径(潜在矛盾),其中 {tunnel_count} 条包含隧穿") + return paths + + async def boundary_maze_explore(self, start_concept: str) -> List[MazePath]: + """ + 边界迷宫:探索未知/低概率区域(创新探索) + 探索迷宫边界,发现新连接,隧穿和概念研磨主要发生在这里 + """ + logger.info(f"🔍 边界迷宫探索:从 {start_concept} 出发找创新连接") + + if start_concept not in self.nodes: + logger.error(f"起点概念 {start_concept} 不存在") + return [] + + self.reset_visits() + start_node = self.nodes[start_concept] + paths: List[MazePath] = [] + + # 边界迷宫隧穿概率和研磨概率更高 + original_tunnel_prob = self.tunneling_probability + self.tunneling_probability = 0.4 # 40% 隧穿概率,鼓励创新 + self.tunneling_validation_enabled = False # 边界探索暂时不严格验证,后续再验证 + original_grind_prob = self.reasoning_monitor.max_stagnation_rounds + self.reasoning_monitor.max_stagnation_rounds = 2 # 更容易触发研磨 + + # 随机游走探索边界 + for _ in range(8): # 尝试8次随机游走 + current_node = start_node + path = MazePath([current_node], []) + visited = set([current_node.concept]) + + for _ in range(6): # 最多走6步 + # 优先尝试研磨低连接度节点 + if self.grinding_enabled and len(current_node.connections) < 2 and current_node.expand_level < 2 and (current_node.context_profile or {}): + self._grind_node_native(current_node) + + # 优先尝试隧穿 + tunnel_result = self._try_tunneling(current_node, visited) + if tunnel_result: + next_node, edge = tunnel_result + visited.add(next_node.concept) + path.add_step(next_node, edge) + current_node = next_node + continue + + # 否则选未访问的边 + unvisited_edges = [e for e in current_node.connections if e.to_node.concept not in visited] + if not unvisited_edges: + break + + # 优先使用策略网络选择(否则随机) + if self.policy_enabled: + selected = self.policy.select_edges( + engine=self, + current_node=current_node, + candidate_edges=unvisited_edges, + path=path, + visited=visited, + mode="boundary", + k=1, + deterministic=False, + ) + if not selected: + break + edge = selected[0] + else: + # 随机选边,优先选阻力中等的(边界区域) + edge = random.choice(unvisited_edges) + next_node = edge.to_node + visited.add(next_node.concept) + path.add_step(next_node, edge) + current_node = next_node + + if path.length >= 3: + # 验证隧穿路径 + if self._validate_tunneling_path(path): + paths.append(path) + + # 记忆钩子:保存创新路径 + path_score = 0.7 # 创新路径基础分 + self.memory.save_successful_path(path.get_concept_list(), path_score) + if self.policy_enabled: + self.policy.update_from_path(self, path, mode="boundary") + + # 恢复原始配置 + self.tunneling_probability = original_tunnel_prob + self.tunneling_validation_enabled = True + self.reasoning_monitor.max_stagnation_rounds = original_grind_prob + + tunnel_count = sum(1 for p in paths if p.has_tunneling) + expanded_count = sum(1 for p in paths if p.has_expanded) + logger.info(f"✅ 边界迷宫找到 {len(paths)} 条创新路径,其中 {tunnel_count} 条包含隧穿,{expanded_count} 条包含研磨节点") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/multimodal_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/multimodal_generator.py new file mode 100644 index 0000000..e373059 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/multimodal_generator.py @@ -0,0 +1,1792 @@ +""" +多模态生成模块 +基于 Tri-Maze 推理链路(节点/关系/阻力)直接生成结构化多模态参数 +完全基于推理路径驱动,不依赖自然语言Prompt中转 +""" +import json +import asyncio +import requests +import base64 +import os +import mimetypes +from typing import Dict, List, Any, Optional +from loguru import logger +from openai import OpenAI +from io import BytesIO +from PIL import Image +from .native_generator import NativeGenerator +from .sd_sketch_generator import SDSketchGenerator +from .sketch_v2 import SketchV2Generator +from .sketch_edit_v1 import build_render_conditioning_bundle as build_editable_render_conditioning_bundle +from .semantic_scene_v2 import summarize_scene_spec +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from .maze_engine import MazePath + + +def _safe_scene_copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +class MultimodalGenerator: + """多模态生成器:基于Tri-Maze推理链路直接驱动多模态生成 + 完全基于推理路径的节点、关系、阻力生成参数,不需要自然语言Prompt中转 + """ + + def __init__(self, llm_client: OpenAI = None, config: Dict = None): + self.llm_client = llm_client + self.output_dir = "outputs" + os.makedirs(self.output_dir, exist_ok=True) + + # 生成API配置 + self.config = config or {} + self.sd_api_url = self.config.get("sd_api_url", "").strip() # Stable Diffusion API地址 + self.image_api_url = self.config.get("image_api_url", "").strip() + self.image_api_key = self.config.get("image_api_key", "").strip() + self.image_api_model = self.config.get("image_api_model", "").strip() + self.image_api_control_model = self.config.get("image_api_control_model", "").strip() + self.image_api_size = self.config.get("image_api_size", "").strip() + self.dalle_api_key = self.config.get("dalle_api_key", "").strip() or (self.image_api_key if not self.image_api_url else "") + self.pika_api_key = self.config.get("pika_api_key", "") + self.runway_api_key = self.config.get("runway_api_key", "") + + # 原生生成器:完全不依赖外部API + self.native_generator = NativeGenerator(output_dir=self.output_dir) + self.sd_sketch_generator = SDSketchGenerator(output_dir=self.output_dir, sd_api_url=self.sd_api_url) + self.sketch_v2_generator = SketchV2Generator( + output_dir=self.output_dir, + sd_api_url=self.sd_api_url, + image_api_url=self.image_api_url, + image_api_key=self.image_api_key, + image_api_model=self.image_api_model, + image_api_size=self.image_api_size, + ) + self.use_native_generation = self.config.get("use_native_generation", True) # 默认使用原生生成 + + # 概念到视觉特征的映射规则 + self.concept_feature_map = { + # 电子电路 + "电阻": {"shape": "cylindrical", "color": ["beige", "brown", "red"], "tags": ["electronic component", "resistor"]}, + "LED": {"shape": "diode", "color": ["transparent", "red", "green", "blue"], "tags": ["light-emitting diode", "electronic component"]}, + "Arduino": {"shape": "rectangular board", "color": ["blue", "green"], "tags": ["microcontroller", "development board"]}, + "电源": {"shape": "battery", "color": ["black", "red"], "tags": ["power supply", "battery"]}, + "GND": {"shape": "ground symbol", "color": ["black"], "tags": ["ground", "electrical ground"]}, + "电路": {"style": "schematic diagram", "background": "white", "tags": ["circuit diagram", "schematic"]}, + + # 物理 + "力": {"visual": "arrow", "color": ["red"], "tags": ["force vector", "physics"]}, + "速度": {"visual": "arrow", "color": ["blue"], "tags": ["velocity vector", "physics"]}, + "能量": {"visual": "glow", "color": ["yellow", "orange"], "tags": ["energy", "glowing effect"]}, + "光": {"visual": "rays", "color": ["white", "yellow"], "tags": ["light rays", "bright"]}, + + # 生物 + "猫": {"shape": "feline", "color": ["various"], "tags": ["cat", "animal", "feline"]}, + "毛皮": {"texture": "fur", "color": ["soft"], "tags": ["fur", "animal fur"]}, + "羽毛": {"texture": "soft", "color": ["light"], "tags": ["feathers", "bird"]}, + "细胞": {"shape": "circular", "color": ["transparent"], "tags": ["cell", "biology"]}, + + # 通用 + "抽象概念": {"style": "abstract", "color": ["gradient"], "tags": ["abstract art"]}, + "机械结构": {"style": "technical drawing", "color": ["gray", "metal"], "tags": ["mechanical design"]} + } + + # 阻力到视觉权重的映射:阻力越低,视觉上越突出 + self.resistance_weight_map = { + (0.0, 0.2): {"weight": 1.0, "opacity": 1.0, "size_multiplier": 1.5}, + (0.2, 0.4): {"weight": 0.8, "opacity": 0.9, "size_multiplier": 1.3}, + (0.4, 0.6): {"weight": 0.6, "opacity": 0.8, "size_multiplier": 1.1}, + (0.6, 0.8): {"weight": 0.4, "opacity": 0.7, "size_multiplier": 1.0}, + (0.8, 1.01): {"weight": 0.2, "opacity": 0.5, "size_multiplier": 0.8}, + } + + logger.info("✅ 多模态生成器初始化完成(基于推理链路直接生成)") + + def _get_weight_config(self, resistance: float) -> Dict[str, float]: + for (lower, upper), config in self.resistance_weight_map.items(): + if lower <= resistance < upper: + return config + return self.resistance_weight_map[(0.4, 0.6)] + + def _get_canvas_size(self, sketch_options: Dict[str, Any] | None = None) -> tuple[int, int]: + sketch_options = sketch_options or {} + width = int(sketch_options.get("canvas_width", 1024)) + height = int(sketch_options.get("canvas_height", 768)) + return max(512, width), max(384, height) + + def _clean_prompt_text(self, value: Any) -> str: + text = str(value or "").replace("\n", " ").replace("\r", " ").replace("|", " ").strip() + return " ".join(text.split()).strip(" ,;,;。") + + def _resolve_sketch_backend(self, sketch_options: Dict[str, Any] | None = None) -> str: + sketch_options = sketch_options or {} + backend = str(sketch_options.get("sketch_backend", self.config.get("sketch_backend", "native")) or "native").strip().lower() + return backend if backend in {"native", "sd", "sketch_v2"} else "native" + + def _find_sketch_candidate( + self, + candidates: List[Dict[str, Any]] | None = None, + candidate_id: str | None = None, + ) -> Optional[Dict[str, Any]]: + if not isinstance(candidates, list) or not candidates: + return None + if candidate_id: + marker = str(candidate_id).strip() + for item in candidates: + if isinstance(item, dict) and str(item.get("candidate_id") or "").strip() == marker: + return item + for item in candidates: + if isinstance(item, dict) and str(item.get("image_path") or "").strip(): + return item + return None + + def resolve_used_control_image_path( + self, + *, + sketch_options: Dict[str, Any] | None = None, + preview: Dict[str, Any] | None = None, + render_options: Dict[str, Any] | None = None, + control_image_path: str | None = None, + low_preview_path: str | None = None, + render_control_path: str | None = None, + ) -> str | None: + sketch_options = sketch_options or {} + preview = preview if isinstance(preview, dict) else {} + render_options = render_options if isinstance(render_options, dict) else {} + for key in ("editable_sketch_composited_path",): + candidate = str(render_options.get(key) or preview.get(key) or "").strip() + if candidate: + return candidate + backend = self._resolve_sketch_backend(sketch_options) + if backend == "sketch_v2": + candidates = render_options.get("sketch_candidates") + if not isinstance(candidates, list) or not candidates: + candidates = preview.get("sketch_candidates") + selected_id = ( + render_options.get("selected_sketch_candidate_id") + or render_options.get("active_sketch_candidate_id") + or sketch_options.get("selected_sketch_candidate_id") + or preview.get("active_sketch_candidate_id") + ) + candidate = self._find_sketch_candidate(candidates, selected_id) + if candidate: + candidate_path = str(candidate.get("image_path") or "").strip() + if candidate_path: + return candidate_path + for key in ("active_sketch_path", "image_path", "native_control_image_path"): + value = str(render_options.get(key) or preview.get(key) or "").strip() + if value: + return value + return ( + str(render_control_path or "").strip() + or str(low_preview_path or "").strip() + or str(control_image_path or "").strip() + or None + ) + + def _conditioning_summary(self, conditioning_bundle: Dict[str, Any] | None = None) -> str: + bundle = conditioning_bundle if isinstance(conditioning_bundle, dict) else {} + counts = bundle.get("counts") if isinstance(bundle.get("counts"), dict) else {} + edited_regions = int(counts.get("edited_regions", 0) or 0) + patches = int(counts.get("patches", 0) or 0) + if not edited_regions and not patches: + return "" + parts = [] + if edited_regions: + parts.append(f"edited_regions={edited_regions}") + if patches: + parts.append(f"patches={patches}") + return " | ".join(parts) + + def _persist_conditioning_bundle(self, conditioning_bundle: Dict[str, Any] | None = None) -> str: + bundle = conditioning_bundle if isinstance(conditioning_bundle, dict) else {} + if not bundle: + return "" + revision_id = str(bundle.get("revision_id") or "").strip() + digest = abs(hash(json.dumps(bundle, ensure_ascii=False, sort_keys=True))) + filename = f"render_conditioning_{revision_id or digest}.json" + output_path = os.path.join(self.output_dir, filename) + with open(output_path, "w", encoding="utf-8") as handle: + json.dump(bundle, handle, ensure_ascii=False, indent=2) + return output_path + + def _build_render_conditioning_bundle( + self, + *, + render_options: Dict[str, Any] | None = None, + scene_spec: Dict[str, Any] | None = None, + used_control_image_path: str | None = None, + ) -> Dict[str, Any]: + render_options = render_options if isinstance(render_options, dict) else {} + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + editable_doc = render_options.get("editable_sketch_doc") if isinstance(render_options.get("editable_sketch_doc"), dict) else None + if editable_doc: + bundle = build_editable_render_conditioning_bundle(editable_doc) + else: + render_hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec.get("render_hints"), dict) else {} + region_constraints = _safe_scene_copy(render_hints.get("region_edit_constraints") or []) + patch_constraints = _safe_scene_copy(render_hints.get("render_patch_constraints") or []) + if not region_constraints and not patch_constraints: + return {} + bundle = { + "version": 1, + "source": "scene_spec_render_hints", + "revision_id": "", + "session_id": "", + "sketch_backend": str(render_options.get("sketch_backend") or ""), + "source_candidate_id": str(render_options.get("active_sketch_candidate_id") or ""), + "base_image_path": "", + "background_plate_path": "", + "composited_image_path": str(render_hints.get("editable_sketch_composited_path") or ""), + "canvas_size": _safe_scene_copy(scene_spec.get("canvas_size") or {}), + "camera_state": {}, + "depth_model": {}, + "edit_summary": str(render_hints.get("edit_summary") or ""), + "region_edit_summary": str(render_hints.get("region_edit_summary") or ""), + "region_edit_constraints": region_constraints, + "render_patch_constraints": patch_constraints, + "object_layers": [], + "region_layers": [], + "patch_layers": [], + "counts": { + "objects": 0, + "regions": len(region_constraints), + "edited_regions": len(region_constraints), + "patches": len(patch_constraints), + }, + } + if not bundle: + return {} + bundle["used_control_image_path"] = str(used_control_image_path or bundle.get("composited_image_path") or "") + bundle["conditioning_summary"] = self._conditioning_summary(bundle) + bundle["conditioning_bundle_path"] = self._persist_conditioning_bundle(bundle) + return bundle + + def render_scene_spec_preview( + self, + scene_spec: Dict[str, Any], + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + ) -> Dict[str, Any]: + sketch_options = sketch_options or {} + backend = self._resolve_sketch_backend(sketch_options) + if backend == "sketch_v2" and self.sketch_v2_generator._use_direct_scene_mode(sketch_options): + return self.sketch_v2_generator.render_from_scene_spec(scene_spec, sketch_options=sketch_options, title=title) + preview = self.native_generator.render_scene_spec_preview(scene_spec, sketch_options=sketch_options, title=title) + sketch_bundle = dict(preview.get("sketch_bundle") or {}) + native_structural = sketch_bundle.get("structural_sketch") or preview.get("image_path") + if native_structural: + sketch_bundle.setdefault("native_structural_sketch", native_structural) + sketch_bundle["active_sketch_backend"] = "native" + preview["sketch_bundle"] = sketch_bundle + preview.setdefault("backend", "native_scene_spec_preview") + preview["sketch_backend"] = "native" + if backend == "sd": + return self.sd_sketch_generator.render_from_preview(preview, sketch_options=sketch_options, title=title) + if backend == "sketch_v2": + return self.sketch_v2_generator.render_from_preview(preview, sketch_options=sketch_options, title=title) + if backend != "sd": + return preview + return self.sd_sketch_generator.render_from_preview(preview, sketch_options=sketch_options, title=title) + + def _dedupe_prompt_items(self, items: List[str]) -> List[str]: + seen = set() + output: List[str] = [] + for item in items: + cleaned = self._clean_prompt_text(item) + if not cleaned: + continue + marker = cleaned.casefold() + if marker in seen: + continue + seen.add(marker) + output.append(cleaned) + return output + + def _scene_type_caption(self, scene_type: str) -> str: + mapping = { + "scene": "具象场景图像", + "process": "过程图解画面", + "schematic": "技术结构示意图", + } + return mapping.get(str(scene_type or "scene"), "完整图像") + + def _position_phrase(self, bbox: Dict[str, Any], depth_band: str = "") -> str: + x_center = float(bbox.get("x_norm", 0.0)) + float(bbox.get("width_norm", 0.0)) / 2.0 + y_center = float(bbox.get("y_norm", 0.0)) + float(bbox.get("height_norm", 0.0)) / 2.0 + if depth_band == "foreground" or y_center >= 0.68: + depth = "前景" + elif depth_band == "background" or y_center <= 0.34: + depth = "背景" + else: + depth = "中景" + if x_center <= 0.28: + horizontal = "偏左" + elif x_center >= 0.72: + horizontal = "偏右" + else: + horizontal = "居中" + return f"{depth}{horizontal}" + + def _size_phrase(self, bbox: Dict[str, Any]) -> str: + area = float(bbox.get("width_norm", 0.0)) * float(bbox.get("height_norm", 0.0)) + if area >= 0.2: + return "超大" + if area >= 0.1: + return "较大" + if area >= 0.04: + return "中等" + return "小型" + + def _layer_region_phrase(self, bbox: Dict[str, Any]) -> str: + x_norm = float(bbox.get("x_norm", 0.0)) + y_norm = float(bbox.get("y_norm", 0.0)) + width_norm = float(bbox.get("width_norm", 0.0)) + height_norm = float(bbox.get("height_norm", 0.0)) + if width_norm >= 0.9 and height_norm >= 0.45: + if y_norm <= 0.12: + return "上半部" + if y_norm >= 0.45: + return "下半部" + return "大部分区域" + if y_norm <= 0.2: + vertical = "上方" + elif y_norm >= 0.55: + vertical = "下方" + else: + vertical = "中部" + if x_norm <= 0.25: + horizontal = "偏左" + elif x_norm >= 0.55: + horizontal = "偏右" + else: + horizontal = "" + return f"{vertical}{horizontal}" + + def _describe_render_object(self, obj: Dict[str, Any]) -> str: + name = self._clean_prompt_text(obj.get("concept") or obj.get("asset_key") or "对象") + bbox = obj.get("bbox") or {} + role = str(obj.get("role") or "") + source = str(obj.get("source") or "") + prefix: List[str] = [] + if role in {"subject", "focus", "core_subject"}: + prefix.append("主体") + elif role in {"detail", "support"}: + prefix.append("辅助元素") + if source == "user": + prefix.append("用户补充") + qualifier = "".join(prefix) + return f"{qualifier}{self._position_phrase(bbox, str(obj.get('depth_band') or ''))}的{self._size_phrase(bbox)}{name}" + + def _scene_query_clause(self, scene_context: Dict[str, Any] | None = None) -> str: + if not isinstance(scene_context, dict): + return "" + query = self._clean_prompt_text(scene_context.get("query") or "") + if not query: + return "" + if len(query) > 96: + query = query[:96].rstrip(",,;;。.!!?? ") + "…" + return query + + def _scene_style_booster(self, scene_type: str, query_clause: str = "") -> list[str]: + boosters: list[str] = [] + if scene_type == "scene": + boosters.append("严格保持用户指定的主体数量、动作姿态、相对方位与远近层次。") + boosters.append("以自然完整的真实场景方式呈现,不要把对象拼贴成素材板。") + elif scene_type == "process": + boosters.append("整体表现为浅色科普过程图解,按阶段展开,但每个阶段都必须是可识别对象,不要做成 PPT 卡片。") + boosters.append("过程箭头只作辅助,画面主体仍然是蒸发、凝结、降雨等可识别元素。") + elif scene_type == "schematic": + boosters.append("整体表现为浅色背景的二维工程示意图,使用符号化元件、清晰导线、正视角和规则排布。") + boosters.append("不要生成真实 PCB 主板照片、微距芯片特写或产品摄影。") + if query_clause: + boosters.append(f"必须忠实满足原始需求:{query_clause}。") + return boosters + + def _scene_spec_semantic_sections(self, scene_spec: Dict[str, Any] | None = None) -> Dict[str, str]: + if not isinstance(scene_spec, dict): + return {} + constraints = self._render_constraints(scene_spec) + layout_options = scene_spec.get("layout_options", {}) if isinstance(scene_spec, dict) else {} + scene_type = str(layout_options.get("scene_type", "scene") or "scene") + canvas_size = scene_spec.get("canvas_size", {}) if isinstance(scene_spec, dict) else {} + canvas_width = int(canvas_size.get("width", 1024) or 1024) + canvas_height = int(canvas_size.get("height", 768) or 768) + orientation = "横向" if canvas_width >= canvas_height else "竖向" + + background_lines = [] + for layer in constraints.get("background_layers", [])[:4]: + layer_type = str(layer.get("type") or "") + label = self._clean_prompt_text(layer.get("label") or layer_type or "背景层") + if scene_type == "schematic" and layer_type == "board": + label = "浅色技术底图" + elif scene_type == "process" and layer_type == "process_band": + label = "阶段区域" + background_lines.append(f"{label}铺在画面{self._layer_region_phrase(layer.get('bbox') or {})}") + environment = "、".join(self._dedupe_prompt_items(background_lines)) + + objects = list(constraints.get("object_instances", []) or []) + role_order = {"subject": 0, "focus": 0, "core_subject": 0, "support": 1, "detail": 2, "environment": 3} + + def _sort_key(item: Dict[str, Any]) -> tuple[float, float]: + bbox = item.get("bbox") or {} + area = float(bbox.get("width_norm", 0.0)) * float(bbox.get("height_norm", 0.0)) + return (float(role_order.get(str(item.get("role") or ""), 4)), -area) + + sorted_objects = sorted(objects, key=_sort_key) + subjects = [self._describe_render_object(item) for item in sorted_objects[:6]] + subject_text = "、".join(self._dedupe_prompt_items(subjects[:4])) + + depth_counts = constraints.get("depth_band_counts", {}) or {} + depth_chunks = [] + for depth_band in ("foreground", "midground", "background"): + count = int(depth_counts.get(depth_band, 0) or 0) + if count > 0: + depth_label = {"foreground": "前景", "midground": "中景", "background": "背景"}[depth_band] + depth_chunks.append(f"{depth_label}{count}个主要对象") + composition_bits = [f"{orientation}构图"] + if depth_chunks: + composition_bits.append("层次分布为" + "、".join(depth_chunks)) + if sorted_objects: + composition_bits.append("视觉重心放在" + self._position_phrase((sorted_objects[0].get("bbox") or {}), str(sorted_objects[0].get("depth_band") or ""))) + composition = ",".join(self._dedupe_prompt_items(composition_bits)) + + lookup = { + str(item.get("id") or ""): self._clean_prompt_text(item.get("concept") or item.get("asset_key") or "对象") + for item in objects + if item.get("id") + } + attachment_lines = [] + for item in constraints.get("attachments", [])[:6]: + child = lookup.get(str(item.get("child_id") or ""), "附着元素") + host = lookup.get(str(item.get("host_id") or ""), "宿主") + anchor = self._clean_prompt_text(item.get("anchor_name") or "对应位置") + attachment_lines.append(f"{child}附着在{host}的{anchor}") + attachments = "、".join(self._dedupe_prompt_items(attachment_lines)) + + connector_lines = [] + for item in constraints.get("connectors", [])[:4]: + from_name = lookup.get(str(item.get("from_id") or ""), "起点") + to_name = lookup.get(str(item.get("to_id") or ""), "终点") + relation = self._clean_prompt_text(item.get("label") or item.get("type") or "连接") + connector_lines.append(f"{from_name}与{to_name}通过{relation}形成联系") + connectors = "、".join(self._dedupe_prompt_items(connector_lines)) + + user_added = [] + for item in sorted_objects: + if str(item.get("source") or "") == "user": + user_added.append(self._describe_render_object(item)) + user_added_text = "、".join(self._dedupe_prompt_items(user_added[:5])) + render_hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec, dict) else {} + edit_summary = self._clean_prompt_text(render_hints.get("edit_summary") or "") + region_edit_summary = self._clean_prompt_text(render_hints.get("region_edit_summary") or "") + + return { + "scene_type": scene_type, + "scene_caption": self._scene_type_caption(scene_type), + "environment": environment, + "subjects": subject_text, + "composition": composition, + "attachments": attachments, + "connectors": connectors, + "user_added": user_added_text, + "edit_summary": edit_summary, + "region_edit_summary": region_edit_summary, + } + + def _scene_spec_to_prompt(self, scene_spec: Dict[str, Any] | None = None) -> str: + sections = self._scene_spec_semantic_sections(scene_spec) + if not sections: + return "" + prompt_parts = [f"画面类型:{sections.get('scene_caption', '完整图像')}"] + if sections.get("subjects"): + prompt_parts.append(f"主体:{sections['subjects']}") + if sections.get("environment"): + prompt_parts.append(f"环境:{sections['environment']}") + if sections.get("composition"): + prompt_parts.append(f"构图:{sections['composition']}") + if sections.get("attachments"): + prompt_parts.append(f"附着关系:{sections['attachments']}") + if sections.get("connectors") and sections.get("scene_type") in {"process", "schematic"}: + prompt_parts.append(f"结构关系:{sections['connectors']}") + if sections.get("user_added"): + prompt_parts.append(f"用户新增:{sections['user_added']}") + if sections.get("edit_summary"): + prompt_parts.append(sections["edit_summary"]) + if sections.get("region_edit_summary"): + prompt_parts.append(f"局部编辑:{sections['region_edit_summary']}") + return ";".join(self._dedupe_prompt_items(prompt_parts)) + + def _build_image_render_prompt( + self, + params: Dict[str, Any], + scene_spec: Dict[str, Any] | None = None, + style_hint: str = "", + prompt_suffix: str = "", + scene_context: Dict[str, Any] | None = None, + ) -> tuple[str, str]: + return self._structured_params_to_sd_prompt( + params, + scene_spec=scene_spec, + style_hint=style_hint, + prompt_suffix=prompt_suffix, + scene_context=scene_context, + ) + + def _scene_canvas_size(self, scene_spec: Dict[str, Any] | None = None) -> tuple[int, int]: + canvas = (scene_spec or {}).get("canvas_size", {}) if isinstance(scene_spec, dict) else {} + width = int(canvas.get("width", 1024) or 1024) + height = int(canvas.get("height", 768) or 768) + return max(1, width), max(1, height) + + def _normalized_bbox(self, item: Dict[str, Any], canvas_width: int, canvas_height: int) -> Dict[str, float]: + x = float(item.get("x", 0) or 0) + y = float(item.get("y", 0) or 0) + width = float(item.get("width", 0) or 0) + height = float(item.get("height", 0) or 0) + return { + "x": round(x, 2), + "y": round(y, 2), + "width": round(width, 2), + "height": round(height, 2), + "x_norm": round(x / canvas_width, 4), + "y_norm": round(y / canvas_height, 4), + "width_norm": round(width / canvas_width, 4), + "height_norm": round(height / canvas_height, 4), + } + + def _render_constraints(self, scene_spec: Dict[str, Any] | None = None) -> Dict[str, Any]: + if not isinstance(scene_spec, dict): + return { + "background_layers": [], + "object_instances": [], + "attachments": [], + "connectors": [], + "depth_band_counts": {}, + } + canvas_width, canvas_height = self._scene_canvas_size(scene_spec) + backgrounds = [] + for layer in scene_spec.get("background_layers", []) or []: + if not isinstance(layer, dict): + continue + backgrounds.append({ + "id": str(layer.get("id", "")), + "type": str(layer.get("type", "")), + "label": str(layer.get("label", "")), + "bbox": self._normalized_bbox(layer, canvas_width, canvas_height), + "z_index": int(layer.get("z_index", 0) or 0), + "source": str(layer.get("source", "")), + }) + + objects = [] + depth_band_counts: Dict[str, int] = {} + for obj in scene_spec.get("object_instances", []) or []: + if not isinstance(obj, dict): + continue + depth_band = str(obj.get("depth_band", "") or "") + if depth_band: + depth_band_counts[depth_band] = depth_band_counts.get(depth_band, 0) + 1 + objects.append({ + "id": str(obj.get("id", "")), + "concept": str(obj.get("concept", "")), + "asset_key": str(obj.get("asset_key", "")), + "prototype_id": str(obj.get("prototype_id", obj.get("asset_key", ""))), + "role": str(obj.get("role", "")), + "depth_band": depth_band, + "depth_z": float(obj.get("depth_z", 0.0) or 0.0), + "source": str(obj.get("source", "")), + "bbox": self._normalized_bbox(obj, canvas_width, canvas_height), + "rotation": float(obj.get("rotation", 0.0) or 0.0), + "scale": float(obj.get("scale", 1.0) or 1.0), + "visible": bool(obj.get("visible", True)), + "z_index": int(obj.get("z_index", 0) or 0), + "editable": bool(obj.get("editable", True)), + }) + + attachments = [] + for item in scene_spec.get("attachments", []) or []: + if not isinstance(item, dict): + continue + attachments.append({ + "id": str(item.get("id", "")), + "host_id": str(item.get("host_id", "")), + "child_id": str(item.get("child_id", "")), + "anchor_name": str(item.get("anchor_name", "")), + "mode": str(item.get("mode", "")), + }) + + connectors = [] + for item in scene_spec.get("connectors", []) or []: + if not isinstance(item, dict): + continue + connectors.append({ + "id": str(item.get("id", "")), + "type": str(item.get("type", "")), + "from_id": str(item.get("from_id", "")), + "to_id": str(item.get("to_id", "")), + "label": str(item.get("label", "")), + "visible": bool(item.get("visible", True)), + }) + + return { + "background_layers": backgrounds, + "object_instances": objects, + "attachments": attachments, + "connectors": connectors, + "depth_band_counts": depth_band_counts, + } + + def build_render_bundle( + self, + *, + prompt: str, + negative_prompt: str, + scene_spec: Dict[str, Any] | None = None, + structured_params: Dict[str, Any] | None = None, + control_image_path: str | None = None, + low_preview_path: str | None = None, + render_control_path: str | None = None, + used_control_image_path: str | None = None, + sketch_bundle: Dict[str, Any] | None = None, + conditioning_bundle: Dict[str, Any] | None = None, + backend: str = "", + final_image_path: str | None = None, + workflow_state: str = "previewed", + ) -> Dict[str, Any]: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + sketch_bundle = sketch_bundle if isinstance(sketch_bundle, dict) else {} + conditioning_bundle = conditioning_bundle if isinstance(conditioning_bundle, dict) else {} + layout_options = scene_spec.get("layout_options", {}) if isinstance(scene_spec, dict) else {} + render_hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec.get("render_hints"), dict) else {} + render_strategy = "text_only" + if conditioning_bundle and ( + int(((conditioning_bundle.get("counts") or {}).get("edited_regions", 0) or 0)) > 0 + or int(((conditioning_bundle.get("counts") or {}).get("patches", 0) or 0)) > 0 + ): + render_strategy = "full_state_conditioned_img2img" + elif render_control_path: + render_strategy = "render_control_v2" + elif low_preview_path and used_control_image_path and os.path.normpath(str(used_control_image_path)) == os.path.normpath(str(low_preview_path)): + render_strategy = "low_preview_bridge" + elif control_image_path and used_control_image_path and os.path.normpath(str(used_control_image_path)) == os.path.normpath(str(control_image_path)): + render_strategy = "semantic_sketch_bridge" + elif used_control_image_path: + render_strategy = "external_control_image" + return { + "version": 2, + "pipeline": "render_bridge_v2", + "workflow_state": workflow_state, + "text_prompt": str(prompt or ""), + "negative_prompt": str(negative_prompt or ""), + "scene_spec_version": int(scene_spec.get("version", 2) or 2) if isinstance(scene_spec, dict) else 2, + "composition_mode": str(layout_options.get("composition_mode", layout_options.get("scene_type", "scene"))), + "scene_type": str(layout_options.get("scene_type", "scene")), + "sketch_style": str(layout_options.get("sketch_style", "scribble_line")), + "scene_summary": summarize_scene_spec(scene_spec) if scene_spec else "", + "edit_summary": str(render_hints.get("edit_summary", "")), + "region_edit_summary": str(render_hints.get("region_edit_summary", "")), + "depth_summary": str(render_hints.get("depth_summary", "")), + "camera_summary": str(render_hints.get("camera_summary", "")), + "region_edit_constraints": _safe_scene_copy(render_hints.get("region_edit_constraints") or []), + "conditioning_summary": str(conditioning_bundle.get("conditioning_summary", "")), + "dual_conditioning": { + "text": True, + "sketch": bool(used_control_image_path or sketch_bundle), + "mode": "text+sketch", + }, + "visible_outputs": { + "semantic_sketch_path": str(control_image_path or ""), + "base_sketch_path": str(sketch_bundle.get("base_sketch") or ""), + "structural_sketch_path": str(sketch_bundle.get("structural_sketch") or control_image_path or ""), + "annotated_sketch_path": str(sketch_bundle.get("annotated_sketch") or ""), + "region_overlay_path": str(sketch_bundle.get("region_overlay") or ""), + "low_preview_path": str(low_preview_path or ""), + "hit_map_path": str(sketch_bundle.get("hit_map") or ""), + "annotation_bundle_path": str(sketch_bundle.get("annotation_bundle") or ""), + "final_image_path": str(final_image_path or ""), + "editable_sketch_composited_path": str(render_hints.get("editable_sketch_composited_path", "")), + }, + "model_inputs": { + "render_control_path": str(render_control_path or ""), + "used_control_image_path": str(used_control_image_path or ""), + "control_strategy": render_strategy, + "backend": str(backend or ""), + "conditioning_bundle_path": str(conditioning_bundle.get("conditioning_bundle_path", "")), + }, + "text_constraints": { + "scene_summary": str((scene_spec.get("render_hints", {}) or {}).get("scene_summary", "")), + "subject_summary": str((scene_spec.get("render_hints", {}) or {}).get("subject_summary", "")), + "edit_summary": str(render_hints.get("edit_summary", "")), + "region_edit_summary": str(render_hints.get("region_edit_summary", "")), + "depth_summary": str(render_hints.get("depth_summary", "")), + "camera_summary": str(render_hints.get("camera_summary", "")), + "conditioning_summary": str(conditioning_bundle.get("conditioning_summary", "")), + }, + "sketch_constraints": { + "structural_sketch_path": str(sketch_bundle.get("structural_sketch") or control_image_path or ""), + "annotated_sketch_path": str(sketch_bundle.get("annotated_sketch") or ""), + "region_overlay_path": str(sketch_bundle.get("region_overlay") or ""), + "annotation_bundle_path": str(sketch_bundle.get("annotation_bundle") or ""), + "low_preview_path": str(low_preview_path or ""), + "render_control_path": str(render_control_path or ""), + "render_patch_constraints": _safe_scene_copy(render_hints.get("render_patch_constraints") or []), + "region_edit_constraints": _safe_scene_copy(render_hints.get("region_edit_constraints") or []), + "editable_sketch_composited_path": str(render_hints.get("editable_sketch_composited_path", "")), + "conditioning_bundle_path": str(conditioning_bundle.get("conditioning_bundle_path", "")), + }, + "conditioning": { + "source": str(conditioning_bundle.get("source", "")), + "summary": str(conditioning_bundle.get("conditioning_summary", "")), + "bundle_path": str(conditioning_bundle.get("conditioning_bundle_path", "")), + "counts": _safe_scene_copy(conditioning_bundle.get("counts") or {}), + }, + "annotation_bundle": _safe_scene_copy((scene_spec.get("render_hints", {}) or {}).get("annotation_bundle") or {}), + "structured_params": structured_params or {}, + "constraints": self._render_constraints(scene_spec), + } + + def _encode_image_to_base64(self, image_path: str) -> str: + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8") + + def _encode_image_to_data_url(self, image_path: str) -> str: + mime_type, _ = mimetypes.guess_type(image_path) + mime_type = mime_type or "image/png" + return f"data:{mime_type};base64,{self._encode_image_to_base64(image_path)}" + + def _get_image_api_endpoint(self) -> str: + base_url = (self.image_api_url or "").strip().rstrip("/") + if not base_url: + return "" + if base_url.endswith("/images/generations"): + return base_url + return f"{base_url}/images/generations" + + def _is_volc_ark_image_api(self) -> bool: + url = (self.image_api_url or "").lower() + return any(keyword in url for keyword in ["ark.", "volces.com", "volcengine"]) + + def _default_ark_image_model(self) -> str: + return "doubao-seedream-5-0-260128" + + def _default_ark_control_fallback_model(self) -> str: + return "doubao-seededit-3-0-i2i-250628" + + def _infer_image_model(self, use_control_image: bool = False) -> Optional[str]: + if not self.image_api_url: + return None + if self.image_api_model: + return self.image_api_model + if use_control_image and self.image_api_control_model: + return self.image_api_control_model + if self._is_volc_ark_image_api(): + return self._default_ark_image_model() + return None + + def _infer_image_size(self, render_options: Dict[str, Any] | None = None) -> Optional[str]: + render_options = render_options or {} + explicit_size = str(render_options.get("image_size", "") or "").strip() + if explicit_size: + return explicit_size + if self.image_api_size: + return self.image_api_size + if self._is_volc_ark_image_api(): + return "2K" + return None + + def _save_generated_image(self, response_payload: Dict[str, Any], filename_prefix: str) -> str: + data = response_payload.get("data") or [] + if not data: + raise ValueError("图片接口未返回 data 字段") + first_item = data[0] or {} + image_path = os.path.join(self.output_dir, f"{filename_prefix}_{abs(hash(json.dumps(first_item, ensure_ascii=False, sort_keys=True)))}.png") + + b64_json = first_item.get("b64_json") + if b64_json: + with open(image_path, "wb") as output_file: + output_file.write(base64.b64decode(b64_json)) + return image_path + + image_url = first_item.get("url") + if image_url: + image_response = requests.get(image_url, timeout=180) + image_response.raise_for_status() + with open(image_path, "wb") as output_file: + output_file.write(image_response.content) + return image_path + + raise ValueError("图片接口返回中既没有 url 也没有 b64_json") + + def _call_generic_image_api(self, payload: Dict[str, Any], filename_prefix: str) -> str: + endpoint = self._get_image_api_endpoint() + if not endpoint or not self.image_api_key: + raise ValueError("未配置图片 API URL 或 API Key") + headers = { + "Authorization": f"Bearer {self.image_api_key}", + "Content-Type": "application/json", + } + response = requests.post(endpoint, json=payload, headers=headers, timeout=180) + if not response.ok: + error_body = response.text.strip() + raise ValueError(f"图片接口调用失败(HTTP {response.status_code}):{error_body[:800]}") + return self._save_generated_image(response.json(), filename_prefix) + + def _build_generic_image_payload( + self, + prompt: str, + control_image_path: str | None = None, + render_options: Dict[str, Any] | None = None, + model_override: str | None = None, + ) -> Dict[str, Any]: + render_options = render_options or {} + payload: Dict[str, Any] = { + "prompt": prompt, + "response_format": "url", + } + if not self._is_volc_ark_image_api(): + payload["n"] = 1 + model = (model_override or "").strip() or self._infer_image_model(use_control_image=bool(control_image_path)) + if model: + payload["model"] = model + + image_size = self._infer_image_size(render_options) + if image_size: + payload["size"] = image_size + + if self._is_volc_ark_image_api(): + payload["stream"] = bool(render_options.get("stream", False)) + payload["watermark"] = bool(render_options.get("watermark", True)) + payload["sequential_image_generation"] = str( + render_options.get("sequential_image_generation", "disabled") + ).strip() or "disabled" + + if control_image_path: + payload["image"] = self._encode_image_to_data_url(control_image_path) + + return payload + + def _path_to_structured_params(self, path: 'MazePath', generation_type: str) -> Dict[str, Any]: + """ + 直接将Tri-Maze推理路径转化为多模态生成的结构化参数 + 完全基于节点、关系、阻力生成,不需要自然语言中转 + :param path: Tri-Maze推理路径 + :param generation_type: 生成类型 + :return: 结构化生成参数 + """ + params = { + "concepts": [], + "relations": [], + "core_elements": [], + "secondary_elements": [], + "style": "", + "weights": {} + } + + # 提取路径中的概念和关系,按阻力分配权重 + for i, (node, edge) in enumerate(zip(path.nodes, path.edges + [None])): + concept = node.concept + resistance = edge.resistance if edge else 0.0 + + # 获取概念的视觉特征 + features = self.concept_feature_map.get(concept, { + "shape": "object", + "color": ["natural"], + "tags": [concept.lower().replace(" ", "_")] + }) + + # 获取阻力对应的权重 + weight_config = self._get_weight_config(resistance) + + concept_info = { + "name": concept, + "features": features, + "resistance": resistance, + "weight": weight_config["weight"], + "opacity": weight_config["opacity"], + "size_multiplier": weight_config["size_multiplier"], + "position": "core" if resistance < 0.4 else "secondary" + } + + params["concepts"].append(concept_info) + + if concept_info["position"] == "core": + params["core_elements"].append(concept) + else: + params["secondary_elements"].append(concept) + + if edge: + params["relations"].append({ + "from": path.nodes[i].concept, + "to": path.nodes[i+1].concept, + "relation": edge.relation, + "resistance": edge.resistance + }) + + # 根据生成类型设置风格 + if generation_type == "image": + if len([c for c in params["core_elements"] if c in ["电路", "电阻", "LED", "Arduino"]]) > 0: + params["style"] = "professional electronic schematic diagram, white background, clear lines, technical illustration" + elif len([c for c in params["core_elements"] if c in ["猫", "动物", "生物"]]) > 0: + params["style"] = "photorealistic, natural lighting, high detail" + elif len([c for c in params["core_elements"] if c in ["机械结构", "机器", "工程"]]) > 0: + params["style"] = "technical drawing, blueprint style, precise lines" + else: + params["style"] = "photorealistic, high quality, 8k" + + elif generation_type == "video": + params["style"] = "smooth motion, natural transitions, high quality video" + params["duration"] = "5 seconds" + params["motion"] = "slow pan over the core concepts, showing the relations between them" + + elif generation_type == "3d_model": + params["style"] = "3D model, PBR materials, high polygon, realistic rendering" + + return params + + def _structured_params_to_sd_prompt( + self, + params: Dict, + scene_spec: Dict[str, Any] | None = None, + style_hint: str = "", + prompt_suffix: str = "", + scene_context: Dict[str, Any] | None = None, + ) -> tuple[str, str]: + """将结构化参数和 SceneSpec 组织成更适合最终渲染的语义提示词。""" + sections = self._scene_spec_semantic_sections(scene_spec) + scene_type = sections.get("scene_type", "scene") + scene_caption = sections.get("scene_caption", self._scene_type_caption(scene_type)) + query_clause = self._scene_query_clause(scene_context) + + core_elements = self._dedupe_prompt_items(list(params.get("core_elements") or [])) + secondary_elements = self._dedupe_prompt_items(list(params.get("secondary_elements") or [])) + relations = self._dedupe_prompt_items([rel.get("relation", "") for rel in params.get("relations", [])]) + style_value = self._clean_prompt_text(params.get("style") or "") + scene_prompt = self._scene_spec_to_prompt(scene_spec) + + prompt_sections = [f"请生成一张最终可用的高质量{scene_caption}。"] + if scene_prompt: + prompt_sections.append(scene_prompt + "。") + elif core_elements: + prompt_sections.append(f"核心内容围绕{ '、'.join(core_elements[:4]) }展开。") + + if secondary_elements: + prompt_sections.append(f"补充元素可以包含{ '、'.join(secondary_elements[:5]) }。") + if relations and scene_type in {"process", "schematic"}: + prompt_sections.append(f"重点表达的关系包括{ '、'.join(relations[:4]) }。") + if style_value: + prompt_sections.append(f"整体风格:{style_value}。") + + extra_style = self._clean_prompt_text(style_hint) + if extra_style: + prompt_sections.append(f"额外风格要求:{extra_style}。") + extra_suffix = self._clean_prompt_text(prompt_suffix) + if extra_suffix: + prompt_sections.append(f"补充要求:{extra_suffix}。") + + prompt_sections.extend(self._scene_style_booster(scene_type, query_clause=query_clause)) + + prompt_sections.append( + "上传的控制图只用于约束构图、位置、大小占比、前后层级与附着关系,不要把控制图里的草图线条、遮罩色块、几何图标、标签文字、箭头、边框、面板或涂鸦直接渲染进最终画面。" + ) + if scene_type == "scene": + prompt_sections.append("画面要自然完整,主体清晰,避免示意图感、流程图感和拼贴感。") + elif scene_type == "process": + prompt_sections.append("请把机制过程转成清晰的阶段式图解,用可识别对象和空间层次来表达,不要退回脑图式方框。") + else: + prompt_sections.append("请保持技术结构清楚,用元件与空间布局表达结构,不要生成文字节点图。") + + prompt = " ".join(self._dedupe_prompt_items(prompt_sections)) + + negative_items = [ + "sketch lines", + "doodle overlay", + "wireframe", + "blueprint", + "diagram", + "mind map", + "labels", + "text", + "arrows", + "boxes", + "panels", + "colored masks", + "watermark", + "low quality", + "blurry", + "distorted", + "duplicate objects", + "messy composition", + "草图线稿", + "节点框", + "关系箭头", + "文字标签", + "面板框", + "遮罩色块入镜", + ] + if scene_type == "scene": + negative_items.extend(["flat collage", "sticker style", "UI screenshot"]) + elif scene_type == "process": + negative_items.extend(["flowchart boxes", "presentation slide", "ppt slide", "ui cards", "large rounded cards"]) + elif scene_type == "schematic": + negative_items.extend( + [ + "mind map layout", + "cartoon poster", + "pcb board photo", + "green motherboard", + "microchip macro", + "electronic product photography", + "realistic PCB", + "芯片微距", + "主板照片", + "绿色电路板实拍", + ] + ) + negative_prompt = ", ".join(self._dedupe_prompt_items(negative_items)) + return prompt, negative_prompt + + async def _call_stable_diffusion(self, params: Dict) -> Optional[str]: + """调用Stable Diffusion API生成图片,基于结构化参数""" + try: + prompt, negative_prompt = self._structured_params_to_sd_prompt(params) + logger.info(f"🎨 基于推理路径生成SD Prompt: {prompt[:150]}...") + + image_path = self.sd_sketch_generator.render_txt2img( + prompt=prompt, + negative_prompt=negative_prompt, + width=1024, + height=1024, + steps=25, + cfg_scale=7.0, + sampler_name="DPM++ 2M Karras", + filename_prefix="image", + ) + logger.info(f"✅ 图片生成成功,保存到: {image_path}") + return image_path, prompt + except Exception as e: + logger.error(f"❌ Stable Diffusion调用失败: {str(e)}") + return None, None + + async def _call_stable_diffusion_img2img(self, prompt: str, negative_prompt: str, control_image_path: str, render_options: Dict[str, Any] | None = None): + """调用 Stable Diffusion img2img,将控制草图转成最终图片""" + render_options = render_options or {} + scene_spec = render_options.get("scene_spec") if isinstance(render_options.get("scene_spec"), dict) else {} + layout_options = scene_spec.get("layout_options", {}) if isinstance(scene_spec, dict) else {} + scene_type = str(layout_options.get("scene_type") or layout_options.get("composition_mode") or "scene").strip().lower() or "scene" + default_strength = {"scene": 0.42, "process": 0.34, "schematic": 0.3}.get(scene_type, 0.35) + default_steps = {"scene": 30, "process": 28, "schematic": 26}.get(scene_type, 28) + default_cfg = {"scene": 7.0, "process": 6.4, "schematic": 6.0}.get(scene_type, 7.0) + controlnet_bundle = self.sd_sketch_generator.build_controlnet_bundle( + control_image_path=control_image_path, + scene_spec=scene_spec, + filename_prefix="controlled_image", + purpose="final_render", + ) + image_path = self.sd_sketch_generator.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_image_path, + denoising_strength=float(render_options.get("control_strength", default_strength)), + steps=int(render_options.get("steps", default_steps)), + cfg_scale=float(render_options.get("cfg_scale", default_cfg)), + sampler_name=str(render_options.get("sampler_name", "DPM++ 2M Karras")), + filename_prefix="controlled_image", + conditioning_bundle=render_options.get("conditioning_bundle") if isinstance(render_options.get("conditioning_bundle"), dict) else None, + controlnet_bundle=controlnet_bundle, + ) + logger.info(f"✅ 草图约束图片生成成功,保存到: {image_path}") + return image_path + + async def preview_controlled_image( + self, + reasoning_path: 'MazePath | None', + sketch_options: Dict[str, Any] | None = None, + scene_context: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + """生成前置控制草图与结构化场景说明""" + sketch_options = sketch_options or {} + canvas_size = self._get_canvas_size(sketch_options) + params = self._path_to_structured_params(reasoning_path, "image") if reasoning_path else {} + scene_spec = self.native_generator.build_scene_spec( + reasoning_path, + canvas_size=canvas_size, + sketch_options=sketch_options, + scene_context=scene_context, + ) + hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec, dict) else {} + title_core = hints.get("scene_summary") or " · ".join(scene_spec.get("concept_order", [])[:4]) + title = f"Tri-Maze 语义草图 · {title_core}" if title_core else "Tri-Maze 语义草图" + preview = self.render_scene_spec_preview( + scene_spec, + sketch_options=sketch_options, + title=title, + ) + prompt, negative_prompt = self._build_image_render_prompt( + params, + preview.get("scene_spec"), + style_hint=sketch_options.get("style_hint", ""), + prompt_suffix=sketch_options.get("prompt_suffix", ""), + scene_context=scene_context, + ) + preview["structured_params"] = params + preview["generated_prompt"] = prompt + preview["negative_prompt"] = negative_prompt + preview.setdefault("backend", "tri_maze_control_preview") + used_control_image_path = self.resolve_used_control_image_path( + sketch_options=sketch_options, + preview=preview, + control_image_path=preview.get("image_path"), + low_preview_path=preview.get("low_preview_path"), + render_control_path=preview.get("render_control_path"), + ) + preview["render_bundle"] = self.build_render_bundle( + prompt=prompt, + negative_prompt=negative_prompt, + scene_spec=preview.get("scene_spec"), + structured_params=params, + control_image_path=preview.get("image_path"), + low_preview_path=preview.get("low_preview_path"), + render_control_path=preview.get("render_control_path"), + used_control_image_path=used_control_image_path, + sketch_bundle=preview.get("sketch_bundle"), + backend="tri_maze_control_preview", + workflow_state="composed", + ) + return preview + + async def render_image_from_preview( + self, + reasoning_path: 'MazePath | None', + sketch_options: Dict[str, Any] | None = None, + render_options: Dict[str, Any] | None = None, + scene_context: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + """基于控制草图调用外部图片 API 生成最终图片""" + sketch_options = sketch_options or {} + render_options = render_options or {} + preview_result = None + control_image_path = render_options.get("control_image_path") + scene_spec = render_options.get("scene_spec") + low_preview_path = render_options.get("low_preview_path") + render_control_path = render_options.get("render_control_path") + sketch_bundle = render_options.get("sketch_bundle") if isinstance(render_options.get("sketch_bundle"), dict) else None + external_control_image_path = self.resolve_used_control_image_path( + sketch_options=sketch_options, + render_options=render_options, + control_image_path=control_image_path, + low_preview_path=low_preview_path, + render_control_path=render_control_path, + ) + if self._resolve_sketch_backend(sketch_options) == "sketch_v2" and external_control_image_path: + control_image_path = external_control_image_path + if not control_image_path: + preview_result = await self.preview_controlled_image( + reasoning_path, + sketch_options, + scene_context=scene_context, + ) + control_image_path = preview_result.get("image_path") + scene_spec = preview_result.get("scene_spec") + low_preview_path = preview_result.get("low_preview_path") + render_control_path = preview_result.get("render_control_path") + sketch_bundle = preview_result.get("sketch_bundle") + external_control_image_path = self.resolve_used_control_image_path( + sketch_options=sketch_options, + preview=preview_result, + render_options=render_options, + control_image_path=control_image_path, + low_preview_path=low_preview_path, + render_control_path=render_control_path, + ) + if self._resolve_sketch_backend(sketch_options) == "sketch_v2" and external_control_image_path: + control_image_path = external_control_image_path + params = self._path_to_structured_params(reasoning_path, "image") if reasoning_path else {} + prompt, default_negative = self._build_image_render_prompt( + params, + scene_spec, + style_hint=render_options.get("style_hint", sketch_options.get("style_hint", "")), + prompt_suffix=render_options.get("prompt_suffix", sketch_options.get("prompt_suffix", "")), + scene_context=scene_context, + ) + negative_prompt = render_options.get("negative_prompt") or default_negative + conditioning_bundle = self._build_render_conditioning_bundle( + render_options=render_options, + scene_spec=scene_spec, + used_control_image_path=external_control_image_path or control_image_path, + ) + if conditioning_bundle: + render_options["conditioning_bundle"] = conditioning_bundle + image_path = None + backend = None + note = "" + + try: + if self.sd_api_url and "http" in self.sd_api_url and control_image_path: + image_path = await self._call_stable_diffusion_img2img(prompt, negative_prompt, control_image_path, render_options) + backend = "comfyui_img2img" if self.sd_sketch_generator.comfy_client.is_comfyui_server() else "stable_diffusion_img2img" + conditioning_report = self.sd_sketch_generator.last_conditioning_report if isinstance(self.sd_sketch_generator.last_conditioning_report, dict) else {} + applied_ops = [ + item for item in (conditioning_report.get("operations") or []) + if isinstance(item, dict) and item.get("status") == "applied" + ] + if applied_ops: + note = f"已应用 {len(applied_ops)} 个局部 conditioning pass(region/patch 级)到最终渲染。" + except Exception as e: + logger.error(f"草图约束渲染失败: {str(e)}") + note = f"Stable Diffusion img2img 调用失败:{str(e)}" + + if not image_path and self.image_api_url and self.image_api_key: + try: + primary_model = self._infer_image_model(use_control_image=bool(external_control_image_path)) + payload = self._build_generic_image_payload( + prompt, + external_control_image_path, + render_options, + model_override=primary_model, + ) + image_path = self._call_generic_image_api(payload, "generic_controlled") + backend = "volc_ark_image_api" if self._is_volc_ark_image_api() else "generic_image_api" + if external_control_image_path and self._is_volc_ark_image_api(): + if note: + note += " | " + note += f"已使用火山方舟图片接口进行构图约束渲染(model={payload.get('model', '')})。" + except Exception as e: + logger.error(f"通用图片接口草图约束渲染失败: {str(e)}") + if note: + note += " | " + note += f"通用图片接口渲染失败:{str(e)}" + + if ( + not image_path + and external_control_image_path + and self.image_api_url + and self.image_api_key + and self._is_volc_ark_image_api() + ): + fallback_model = self.image_api_control_model.strip() or self._default_ark_control_fallback_model() + primary_model = self._infer_image_model(use_control_image=True) + if fallback_model and fallback_model != primary_model: + try: + payload = self._build_generic_image_payload( + prompt, + external_control_image_path, + render_options, + model_override=fallback_model, + ) + image_path = self._call_generic_image_api(payload, "ark_control_fallback") + backend = "volc_ark_image_api_control_fallback" + if note: + note += " | " + note += f"主模型不接受当前草图约束时,已回退到控制图模型(model={fallback_model})。" + except Exception as e: + logger.error(f"火山方舟控制图回退模型渲染失败: {str(e)}") + if note: + note += " | " + note += f"火山方舟控制图回退模型失败:{str(e)}" + + if not image_path and self.image_api_url and self.image_api_key: + try: + payload = self._build_generic_image_payload(prompt, None, render_options) + image_path = self._call_generic_image_api(payload, "generic_prompt_only") + backend = "volc_ark_text_fallback" if self._is_volc_ark_image_api() else "generic_image_api_text_fallback" + if note: + note += " | " + note += "外部图片接口未使用控制草图,仅复用结构化场景提示。" + except Exception as e: + logger.error(f"通用图片接口文本渲染失败: {str(e)}") + if note: + note += " | " + note += f"通用图片接口文本渲染失败:{str(e)}" + + if not image_path and self.dalle_api_key: + client = OpenAI(api_key=self.dalle_api_key) + response = client.images.generate( + model="dall-e-3", + prompt=prompt, + size="1024x1024", + quality="standard", + n=1, + ) + image_url = response.data[0].url + image_response = requests.get(image_url, timeout=180) + image_path = f"{self.output_dir}/dalle_controlled_{hash(prompt)}.png" + with open(image_path, "wb") as output_file: + output_file.write(image_response.content) + backend = "dall_e_text_fallback" + if note: + note += " | " + note += "DALL-E 兜底不直接读取草图,仅复用结构化场景提示。" + + if not image_path and scene_spec: + try: + native_result = self.native_generator.render_scene_spec_preview( + scene_spec, + sketch_options=sketch_options, + title="Tri-Maze 本地结构化渲染", + ) + image_path = native_result.get("low_preview_path") or native_result.get("image_path") + control_image_path = control_image_path or native_result.get("image_path") + low_preview_path = native_result.get("low_preview_path") or low_preview_path + scene_spec = native_result.get("scene_spec", scene_spec) + sketch_bundle = native_result.get("sketch_bundle") or sketch_bundle + backend = "native_scene_spec_fallback" + if note: + note += " | " + note += "当前未配置外部生图 API,已回退为本地结构化渲染图,可继续编辑 SceneSpec 后再重渲染。" + except Exception as e: + logger.error(f"本地结构化兜底渲染失败: {str(e)}") + if note: + note += " | " + note += f"本地结构化兜底渲染失败:{str(e)}" + + if not image_path: + return { + "success": False, + "error": note or "未配置可用的外部图片渲染 API", + "control_image_path": control_image_path, + "used_control_image_path": external_control_image_path, + "low_preview_path": low_preview_path, + "render_control_path": render_control_path, + "scene_spec": scene_spec, + "generated_prompt": prompt, + "negative_prompt": negative_prompt, + "render_bundle": self.build_render_bundle( + prompt=prompt, + negative_prompt=negative_prompt, + scene_spec=scene_spec, + structured_params=params, + control_image_path=control_image_path, + low_preview_path=low_preview_path, + render_control_path=render_control_path, + used_control_image_path=external_control_image_path, + sketch_bundle=sketch_bundle or (preview_result or {}).get("sketch_bundle"), + conditioning_bundle=conditioning_bundle, + backend=backend or "", + workflow_state="render_failed", + ), + } + + result = { + "success": True, + "type": "controlled_image", + "backend": backend, + "image_path": image_path, + "save_path": image_path, + "control_image_path": control_image_path, + "used_control_image_path": external_control_image_path, + "low_preview_path": low_preview_path, + "render_control_path": render_control_path, + "scene_spec": scene_spec, + "structured_params": params, + "generated_prompt": prompt, + "negative_prompt": negative_prompt, + "sketch_bundle": sketch_bundle, + "description": "先生成 Tri-Maze 控制草图,再交给外部图片 API 或本地结构化渲染生成最终图片", + "render_bundle": self.build_render_bundle( + prompt=prompt, + negative_prompt=negative_prompt, + scene_spec=scene_spec, + structured_params=params, + control_image_path=control_image_path, + low_preview_path=low_preview_path, + render_control_path=render_control_path, + used_control_image_path=external_control_image_path, + sketch_bundle=sketch_bundle or (preview_result or {}).get("sketch_bundle"), + conditioning_bundle=conditioning_bundle, + backend=backend or "", + final_image_path=image_path, + workflow_state="rendered", + ), + } + if note: + result["note"] = note + if preview_result: + result["control_preview"] = preview_result + return result + async def _generate_image(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成图片:完全基于Tri-Maze推理路径的结构化参数生成,不需要自然语言Prompt""" + try: + # 直接将推理路径转化为结构化参数 + params = self._path_to_structured_params(reasoning_path, "image") + + # 尝试调用SD生成真实图片 + image_path = None + generated_prompt = None + if self.sd_api_url and "http" in self.sd_api_url: + image_path, generated_prompt = await self._call_stable_diffusion(params) + + if not image_path and self.image_api_url and self.image_api_key: + prompt_desc = f"Generate a high quality image of: {', '.join(params['core_elements'])}. The image should show the relations: {', '.join([r['relation'] for r in params['relations']])}. Style: {params['style']}" + payload = self._build_generic_image_payload(prompt_desc) + image_path = self._call_generic_image_api(payload, "generic_image") + generated_prompt = prompt_desc + logger.info(f"✅ 通用图片接口生成成功,保存到: {image_path}") + + # 尝试DALL-E + if not image_path and self.dalle_api_key: + # 将结构化参数转化为DALL-E Prompt + prompt_desc = f"Generate a high quality image of: {', '.join(params['core_elements'])}. The image should show the relations: {', '.join([r['relation'] for r in params['relations']])}. Style: {params['style']}" + + client = OpenAI(api_key=self.dalle_api_key) + response = client.images.generate( + model="dall-e-3", + prompt=prompt_desc, + size="1024x1024", + quality="standard", + n=1, + ) + + image_url = response.data[0].url + image_response = requests.get(image_url) + image_path = f"{self.output_dir}/image_{hash(str(params))}.png" + with open(image_path, "wb") as f: + f.write(image_response.content) + generated_prompt = prompt_desc + logger.info(f"✅ DALL-E图片生成成功,保存到: {image_path}") + + result = { + "success": True, + "type": "image", + "structured_params": params, + "generated_prompt": generated_prompt, + "description": "基于Tri-Maze推理链路直接生成的图片" + } + + if image_path: + result["image_path"] = image_path + result["save_path"] = image_path + else: + result["note"] = "未配置图片生成API,已生成结构化参数和Prompt,可直接用于生成" + + return result + + except Exception as e: + logger.error(f"生成图片失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_video(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成视频:基于Tri-Maze推理路径生成结构化参数""" + try: + # 直接将推理路径转化为结构化参数 + params = self._path_to_structured_params(reasoning_path, "video") + + # 生成视频Prompt + prompt = f"Video showing: {', '.join(params['core_elements'])}. Motion: {params['motion']}. Style: {params['style']}. Duration: {params['duration']}." + + # 这里可以对接Pika/Runway API + video_path = None + # if self.pika_api_key: + # video_path = await self._call_pika(params) + + result = { + "success": True, + "type": "video", + "structured_params": params, + "generated_prompt": prompt, + "description": "基于Tri-Maze推理链路直接生成的视频" + } + + if video_path: + result["video_path"] = video_path + result["save_path"] = video_path + else: + result["note"] = "未配置视频生成API,已生成结构化参数和Prompt,可直接用于Pika/Runway生成" + + return result + + except Exception as e: + logger.error(f"生成视频失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_code(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成代码:基于Tri-Maze推理路径的逻辑生成""" + if not self.llm_client: + return {"success": False, "error": "缺少LLM客户端"} + + try: + # 提取路径中的逻辑关系 + path_concepts = [n.concept for n in reasoning_path.nodes] + path_relations = [e.relation for e in reasoning_path.edges] + + # 构建代码生成逻辑提示,基于推理路径 + logic_desc = "Implement code based on the following logical path:\n" + for i in range(len(path_relations)): + logic_desc += f"- {path_concepts[i]} → {path_relations[i]} → {path_concepts[i+1]}\n" + + prompt = f""" +{logic_desc} + +Generate complete, runnable code that implements this logic. Add necessary comments. The code should directly reflect the logical relationships in the path. +""" + + code_resp = self.llm_client.chat.completions.create( + model="deepseek-chat", + messages=[{"role": "user", "content": prompt}], + temperature=0.3, + max_tokens=2000 + ) + code_content = code_resp.choices[0].message.content.strip() + + # 保存代码到文件 + code_path = f"{self.output_dir}/code_{hash(str(reasoning_path.get_concept_list()))}.py" + with open(code_path, "w", encoding="utf-8") as f: + f.write(code_content) + + return { + "success": True, + "type": "code", + "content": code_content, + "save_path": code_path, + "logic_path": path_concepts, + "description": "基于Tri-Maze推理链路逻辑生成的可运行代码" + } + + except Exception as e: + logger.error(f"生成代码失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_document(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成文档:基于Tri-Maze推理路径的结构生成""" + if not self.llm_client: + return {"success": False, "error": "缺少LLM客户端"} + + try: + # 提取路径中的逻辑结构 + path_concepts = [n.concept for n in reasoning_path.nodes] + path_relations = [e.relation for e in reasoning_path.edges] + + # 构建文档结构,基于推理路径 + structure = f"Document structure based on reasoning path:\n" + for i, concept in enumerate(path_concepts): + structure += f"## {i+1}. {concept}\n" + if i < len(path_relations): + structure += f" 关系:{path_relations[i]}\n" + + prompt = f""" +{structure} + +Generate a complete, well-structured Markdown document based on this structure. The document should follow the logical flow of the reasoning path. +""" + + doc_resp = self.llm_client.chat.completions.create( + model="deepseek-chat", + messages=[{"role": "user", "content": prompt}], + temperature=0.5, + max_tokens=3000 + ) + doc_content = doc_resp.choices[0].message.content.strip() + + # 保存文档到文件 + doc_path = f"{self.output_dir}/doc_{hash(str(reasoning_path.get_concept_list()))}.md" + with open(doc_path, "w", encoding="utf-8") as f: + f.write(doc_content) + + return { + "success": True, + "type": "document", + "content": doc_content, + "save_path": doc_path, + "structure": path_concepts, + "description": "基于Tri-Maze推理链路结构生成的文档" + } + + except Exception as e: + logger.error(f"生成文档失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_design(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成设计:基于Tri-Maze推理路径生成设计说明""" + try: + params = self._path_to_structured_params(reasoning_path, "design") + + design_desc = f""" +Design Description: +Core Elements: {', '.join(params['core_elements'])} +Relations: {', '.join([r['relation'] for r in params['relations']])} +Style: {params['style']} +Element Weights: { {c['name']: c['weight'] for c in params['concepts']} } +""" + + design_path = f"{self.output_dir}/design_{hash(str(reasoning_path.get_concept_list()))}.md" + with open(design_path, "w", encoding="utf-8") as f: + f.write(design_desc) + + return { + "success": True, + "type": "design", + "content": design_desc, + "save_path": design_path, + "structured_params": params, + "description": "基于Tri-Maze推理链路生成的设计说明" + } + + except Exception as e: + logger.error(f"生成设计失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_audio(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成音频:基于Tri-Maze推理路径生成音频参数""" + try: + # 将推理路径转化为音频参数 + path_concepts = [n.concept for n in reasoning_path.nodes] + total_resistance = reasoning_path.total_resistance + + # 阻力映射到音频参数 + tempo = max(60, min(180, 120 + (0.5 - total_resistance) * 60)) # 阻力越低节奏越快 + pitch = 440 + (0.5 - total_resistance) * 220 # 阻力越低音调越高 + + prompt = f"Audio representing: {', '.join(path_concepts)}. Tempo: {tempo} BPM. Pitch: {pitch} Hz. Style: ambient sound effects." + + result = { + "success": True, + "type": "audio", + "structured_params": { + "tempo": tempo, + "pitch": pitch, + "concepts": path_concepts + }, + "generated_prompt": prompt, + "description": "基于Tri-Maze推理链路生成的音频参数" + } + + return result + + except Exception as e: + logger.error(f"生成音频失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def _generate_3d_model(self, reasoning_path: 'MazePath') -> Dict[str, Any]: + """生成3D模型:基于Tri-Maze推理路径生成3D参数""" + try: + params = self._path_to_structured_params(reasoning_path, "3d_model") + + model_desc = f""" +3D Model Description: +Core Elements: {', '.join(params['core_elements'])} +Relations: {', '.join([r['relation'] for r in params['relations']])} +Style: {params['style']} +Element Sizes: { {c['name']: c['size_multiplier'] for c in params['concepts']} } +""" + + model_path = f"{self.output_dir}/3d_{hash(str(reasoning_path.get_concept_list()))}.md" + with open(model_path, "w", encoding="utf-8") as f: + f.write(model_desc) + + return { + "success": True, + "type": "3d_model", + "content": model_desc, + "save_path": model_path, + "structured_params": params, + "description": "基于Tri-Maze推理链路生成的3D模型说明" + } + + except Exception as e: + logger.error(f"生成3D模型失败:{str(e)}") + return {"success": False, "error": str(e)} + + async def generate(self, reasoning_path: 'MazePath', generation_type: str = "auto") -> Dict[str, Any]: + """ + 生成多模态产物 + :param reasoning_path: Tri-Maze推理路径对象(包含节点、关系、阻力) + :param generation_type: 生成类型:auto/image/video/code/document/design/audio/3d_model + :return: 生成结果 + """ + # 自动判断生成类型 + if generation_type == "auto": + generation_type = self._detect_generation_type(str(reasoning_path)) + logger.info(f"自动识别生成类型:{generation_type}") + + # 优先使用原生生成(不需要外部API) + if self.use_native_generation and generation_type in ["image", "video"]: + logger.info(f"使用Tri-Maze原生生成器生成{generation_type},无外部API依赖") + return await self.native_generator.generate(reasoning_path, generation_type) + + # 否则使用外部API生成 + generators = { + "image": self._generate_image, + "video": self._generate_video, + "code": self._generate_code, + "document": self._generate_document, + "design": self._generate_design, + "audio": self._generate_audio, + "3d_model": self._generate_3d_model + } + + if generation_type not in generators: + return {"success": False, "error": f"不支持的生成类型:{generation_type}"} + + generator = generators[generation_type] + return await generator(reasoning_path) + + def _detect_generation_type(self, query: str) -> str: + """自动识别用户需要的生成类型""" + query_lower = query.lower() + + if any(keyword in query_lower for keyword in ["画", "图片", "图像", "绘画", "生成图", "插图", "海报", "设计图"]): + return "image" + elif any(keyword in query_lower for keyword in ["视频", "动画", "短片", "mv", "video"]): + return "video" + elif any(keyword in query_lower for keyword in ["代码", "程序", "脚本", "python", "java", "c++", "编程"]): + return "code" + elif any(keyword in query_lower for keyword in ["文档", "报告", "方案", "说明书", "markdown", "文章", "论文"]): + return "document" + elif any(keyword in query_lower for keyword in ["设计", "ui", "界面", "原型", "平面设计", "视觉设计"]): + return "design" + elif any(keyword in query_lower for keyword in ["音频", "声音", "音乐", "配音", "音效", "audio"]): + return "audio" + elif any(keyword in query_lower for keyword in ["3d", "模型", "三维", "建模", "blender", "maya"]): + return "3d_model" + else: + return "document" # 默认生成文档 + + def get_supported_types(self) -> List[str]: + """获取支持的生成类型""" + return ["image", "video", "code", "document", "design", "audio", "3d_model", "auto"] + + def set_sd_api(self, api_url: str): + """设置Stable Diffusion API地址""" + self.sd_api_url = api_url + self.sd_sketch_generator.set_sd_api_url(api_url) + self.sketch_v2_generator.set_sd_api_url(api_url) + logger.info(f"✅ Stable Diffusion API已设置: {api_url}") + + def set_image_api_url(self, api_url: str): + """设置通用图片 API 地址""" + self.image_api_url = api_url.strip() + self.sketch_v2_generator.set_image_api_url(self.image_api_url) + logger.info(f"✅ 通用图片 API URL已设置: {self.image_api_url}") + + def set_image_api_key(self, api_key: str): + """设置通用图片 API Key""" + self.image_api_key = api_key.strip() + self.sketch_v2_generator.set_image_api_key(self.image_api_key) + logger.info("✅ 通用图片 API Key已设置") + + def set_image_api_model(self, model_name: str): + """设置通用图片 API 主模型""" + self.image_api_model = model_name.strip() + self.sketch_v2_generator.set_image_api_model(self.image_api_model) + logger.info(f"✅ 通用图片 API 主模型已设置: {self.image_api_model}") + + def set_image_api_control_model(self, model_name: str): + """设置通用图片 API 控制图回退模型""" + self.image_api_control_model = model_name.strip() + logger.info(f"✅ 通用图片 API 控制图回退模型已设置: {self.image_api_control_model}") + + def set_image_api_size(self, image_size: str): + """设置通用图片 API 目标尺寸""" + self.image_api_size = image_size.strip() + self.sketch_v2_generator.set_image_api_size(self.image_api_size) + logger.info(f"✅ 通用图片 API 图片尺寸已设置: {self.image_api_size}") + + def set_dalle_api_key(self, api_key: str): + """设置DALL-E API Key""" + self.dalle_api_key = api_key + logger.info(f"✅ DALL-E API Key已设置") + + def set_pika_api_key(self, api_key: str): + """设置Pika API Key""" + self.pika_api_key = api_key + logger.info(f"✅ Pika API Key已设置") + + diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_concept_extractor.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_concept_extractor.py new file mode 100644 index 0000000..582ec79 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_concept_extractor.py @@ -0,0 +1,187 @@ +""" +Native concept extraction based on character n-grams and co-occurrence. +No rules/KB/embeddings/LLM are used. +""" +from __future__ import annotations + +import math +from collections import Counter, defaultdict +from dataclasses import dataclass +from typing import Dict, List, Tuple + + +@dataclass +class NativeExtractorConfig: + ngram_min: int = 2 + ngram_max: int = 4 + window_size: int = 10 + min_freq: int = 2 + top_k: int = 80 + entropy_threshold: float = 0.8 + alpha: float = 0.5 # PMI weight + beta: float = 0.3 # Jaccard weight + gamma: float = 0.2 # Frequency ratio weight + + +class NativeConceptExtractor: + """Extracts concept nodes and directed relations using only statistics.""" + + def __init__(self, config: NativeExtractorConfig | None = None) -> None: + self.config = config or NativeExtractorConfig() + + def _normalize_text(self, text: str) -> str: + # Keep characters but remove whitespace for stable n-gram extraction. + return "".join(ch for ch in text if not ch.isspace()) + + def _entropy(self, counter: Counter) -> float: + total = sum(counter.values()) + if total <= 0: + return 0.0 + ent = 0.0 + for count in counter.values(): + p = count / total + ent -= p * math.log(p + 1e-12) + return ent + + def _collect_ngrams(self, text: str) -> Tuple[Counter, Dict[str, Counter], Dict[str, Counter]]: + counts: Counter = Counter() + left_ctx: Dict[str, Counter] = defaultdict(Counter) + right_ctx: Dict[str, Counter] = defaultdict(Counter) + length = len(text) + for i in range(length): + for n in range(self.config.ngram_min, self.config.ngram_max + 1): + j = i + n + if j > length: + break + gram = text[i:j] + counts[gram] += 1 + if i > 0: + left_ctx[gram][text[i - 1]] += 1 + if j < length: + right_ctx[gram][text[j]] += 1 + return counts, left_ctx, right_ctx + + def _select_concepts( + self, + counts: Counter, + left_ctx: Dict[str, Counter], + right_ctx: Dict[str, Counter], + ) -> List[str]: + scored = [] + for gram, freq in counts.items(): + if freq < self.config.min_freq: + continue + l_ent = self._entropy(left_ctx.get(gram, Counter())) + r_ent = self._entropy(right_ctx.get(gram, Counter())) + ent = (l_ent + r_ent) / 2.0 + if ent < self.config.entropy_threshold: + continue + score = freq * (1.0 + ent) + scored.append((score, gram)) + scored.sort(key=lambda item: item[0], reverse=True) + return [gram for _, gram in scored[: self.config.top_k]] + + def _scan_positions(self, text: str, concepts: set[str]) -> Tuple[Dict[int, List[str]], Counter]: + positions: Dict[int, List[str]] = defaultdict(list) + occ_counts: Counter = Counter() + length = len(text) + for i in range(length): + for n in range(self.config.ngram_min, self.config.ngram_max + 1): + j = i + n + if j > length: + break + gram = text[i:j] + if gram in concepts: + positions[i].append(gram) + occ_counts[gram] += 1 + return positions, occ_counts + + def _build_cooccurrence( + self, positions: Dict[int, List[str]], occ_counts: Counter + ) -> Tuple[Dict[Tuple[str, str], int], Dict[str, Dict[str, int]]]: + pair_counts: Dict[Tuple[str, str], int] = defaultdict(int) + context_profile: Dict[str, Dict[str, int]] = defaultdict(lambda: defaultdict(int)) + indices = sorted(positions.keys()) + idx_set = set(indices) + for i in indices: + current = positions[i] + if not current: + continue + for j in range(i + 1, i + self.config.window_size + 1): + if j not in idx_set: + continue + future = positions[j] + if not future: + continue + for src in current: + for dst in future: + if src == dst: + continue + pair_counts[(src, dst)] += 1 + context_profile[src][dst] += 1 + return pair_counts, context_profile + + def _normalize_scores(self, values: List[float]) -> List[float]: + if not values: + return [] + v_min = min(values) + v_max = max(values) + if abs(v_max - v_min) < 1e-12: + return [0.0 for _ in values] + return [(v - v_min) / (v_max - v_min) for v in values] + + def _compute_weights( + self, + pair_counts: Dict[Tuple[str, str], int], + occ_counts: Counter, + ) -> Dict[Tuple[str, str], float]: + total_pairs = sum(pair_counts.values()) or 1 + pmi_vals: Dict[Tuple[str, str], float] = {} + for (src, dst), count in pair_counts.items(): + pmi = math.log((count * total_pairs) / ((occ_counts[src] * occ_counts[dst]) + 1e-9) + 1e-9) + pmi_vals[(src, dst)] = max(0.0, pmi) + + max_pmi = max(pmi_vals.values()) if pmi_vals else 1.0 + weights: Dict[Tuple[str, str], float] = {} + for (src, dst), count in pair_counts.items(): + pmi_norm = (pmi_vals.get((src, dst), 0.0) / max_pmi) if max_pmi > 0 else 0.0 + jaccard = count / (occ_counts[src] + occ_counts[dst] - count + 1e-9) + ratio = count / (min(occ_counts[src], occ_counts[dst]) + 1e-9) + weight = ( + self.config.alpha * pmi_norm + + self.config.beta * jaccard + + self.config.gamma * ratio + ) + weights[(src, dst)] = max(0.0, min(1.0, weight)) + return weights + + def extract(self, text: str) -> Dict: + cleaned = self._normalize_text(text) + if not cleaned: + return {"concepts": [], "relations": [], "contexts": {}} + + counts, left_ctx, right_ctx = self._collect_ngrams(cleaned) + concepts = self._select_concepts(counts, left_ctx, right_ctx) + if not concepts: + return {"concepts": [], "relations": [], "contexts": {}} + + concept_set = set(concepts) + positions, occ_counts = self._scan_positions(cleaned, concept_set) + pair_counts, context_profile = self._build_cooccurrence(positions, occ_counts) + weights = self._compute_weights(pair_counts, occ_counts) + + relations = [] + for (src, dst), weight in weights.items(): + relations.append({ + "from": src, + "to": dst, + "relation": "co_occurs", + "weight": float(weight), + }) + + concept_records = [{"concept": c, "type": "ngram"} for c in concepts] + return { + "concepts": concept_records, + "relations": relations, + "contexts": {k: dict(v) for k, v in context_profile.items()}, + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_generator.py new file mode 100644 index 0000000..54b7241 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/native_generator.py @@ -0,0 +1,2586 @@ +""" +Tri-Maze 原生多模态生成器 +完全基于三迷宫架构的推理链路原生生成多模态数据,不依赖任何外部生成 API +实现全新的生成思维:推理路径 → 生成单元 → 组合渲染 → 最终产物 +""" +import numpy as np +try: + import cv2 +except Exception: # pragma: no cover - optional dependency for video export only + cv2 = None +from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps +import os +import json +import math +from typing import Dict, List, Any, Tuple, TYPE_CHECKING +from loguru import logger +from .object_sketch_backend import scene_shape_variant_payload, summarize_scene_backend +from .semantic_scene_v2 import ( + build_editor_asset_library, + compose_semantic_scene_spec, + get_asset_definition, + normalize_scene_spec_v2, +) +from .sketch_style_spec import normalize_annotation_level, normalize_view_mode +from .unified_scene_generator import UnifiedSceneGenerator +from .whole_scene_sketch_generator import WholeSceneSketchGenerator + +if TYPE_CHECKING: + from .maze_engine import MazePath, MazeNode + + +class NativeGenerator: + """ + Tri-Maze原生生成器 + 完全基于推理路径的节点、关系、阻力直接生成多模态数据 + 不需要任何外部生成API,原生实现生成逻辑 + """ + + def __init__(self, output_dir: str = "outputs"): + self.output_dir = output_dir + os.makedirs(output_dir, exist_ok=True) + self.whole_scene_sketch_generator = WholeSceneSketchGenerator(self) + self.unified_scene_generator = UnifiedSceneGenerator(self) + + # 概念原生渲染库 + self.concept_renderers = { + # 电子元件 + "电阻": self._render_resistor, + "LED": self._render_led, + "Arduino": self._render_arduino, + "电源": self._render_battery, + "GND": self._render_ground, + "电容": self._render_capacitor, + "二极管": self._render_diode, + "三极管": self._render_transistor, + + # 基础形状 + "矩形": self._render_rectangle, + "圆形": self._render_circle, + "三角形": self._render_triangle, + "箭头": self._render_arrow, + + # 生物 + "猫": self._render_cat, + "树": self._render_tree, + "房子": self._render_house, + } + + # 关系布局规则 + self.relation_layout = { + "串联": self._layout_horizontal_series, + "并联": self._layout_horizontal_parallel, + "连接": self._layout_connect, + "控制": self._layout_top_to_bottom, + "包含": self._layout_inside, + "产生": self._layout_left_to_right, + "导致": self._layout_left_to_right, + } + + # 颜色映射 + self.color_map = { + "红色": (255, 0, 0), + "绿色": (0, 255, 0), + "蓝色": (0, 0, 255), + "黄色": (255, 255, 0), + "黑色": (0, 0, 0), + "白色": (255, 255, 255), + "灰色": (128, 128, 128), + "棕色": (165, 42, 42), + "橙色": (255, 165, 0), + "紫色": (128, 0, 128), + } + + # 字体 + font_candidates = [ + "C:\\Windows\\Fonts\\msyh.ttc", + "C:\\Windows\\Fonts\\simhei.ttf", + "C:\\Windows\\Fonts\\simsun.ttc", + "SimHei.ttf", + "NotoSansCJK-Regular.ttc", + ] + self.font = None + for font_path in font_candidates: + try: + self.font = ImageFont.truetype(font_path, 20) + break + except Exception: + continue + if self.font is None: + self.font = ImageFont.load_default() + + logger.info("✅ Tri-Maze 原生生成器初始化完成,完全不依赖外部 API") + + def _draw_circle(self, draw: ImageDraw, center: Tuple[float, float], radius: float, fill=None, outline=None, width: int = 1): + """兼容 Pillow 版本的圆形绘制""" + cx, cy = center + draw.ellipse([cx - radius, cy - radius, cx + radius, cy + radius], fill=fill, outline=outline, width=width) + + def _draw_arrow_line(self, draw: ImageDraw, start: Tuple[float, float], end: Tuple[float, float], fill, width: int = 2, arrow_size: int = 12): + """兼容 Pillow 的箭头绘制""" + draw.line([start, end], fill=fill, width=width) + dx = end[0] - start[0] + dy = end[1] - start[1] + length = math.hypot(dx, dy) + if length == 0: + return + ux = dx / length + uy = dy / length + base_x = end[0] - ux * arrow_size + base_y = end[1] - uy * arrow_size + perp_x = -uy + perp_y = ux + left = (base_x + perp_x * arrow_size * 0.5, base_y + perp_y * arrow_size * 0.5) + right = (base_x - perp_x * arrow_size * 0.5, base_y - perp_y * arrow_size * 0.5) + draw.polygon([end, left, right], fill=fill) + + def _draw_dashed_line(self, draw: ImageDraw, start: Tuple[float, float], end: Tuple[float, float], fill, width: int = 1, dash_length: int = 6): + """兼容 Pillow 的虚线绘制""" + dx = end[0] - start[0] + dy = end[1] - start[1] + length = math.hypot(dx, dy) + if length == 0: + return + dash_count = max(1, int(length / dash_length)) + for index in range(dash_count): + start_ratio = index / dash_count + end_ratio = min((index + 0.5) / dash_count, 1.0) + sx = start[0] + dx * start_ratio + sy = start[1] + dy * start_ratio + ex = start[0] + dx * end_ratio + ey = start[1] + dy * end_ratio + draw.line([(sx, sy), (ex, ey)], fill=fill, width=width) + + def _draw_dashed_rectangle(self, draw: ImageDraw, box: Tuple[float, float, float, float], outline, width: int = 1, dash_length: int = 6): + """兼容 Pillow 的虚线矩形绘制""" + x0, y0, x1, y1 = box + edges = [ + ((x0, y0), (x1, y0)), + ((x1, y0), (x1, y1)), + ((x1, y1), (x0, y1)), + ((x0, y1), (x0, y0)), + ] + for start, end in edges: + self._draw_dashed_line(draw, start, end, outline, width=width, dash_length=dash_length) + + def _build_preview_palette(self, sketch_style: str) -> Dict[str, Tuple[int, int, int]]: + sketch_style = { + "line_art": "scribble_line", + "minimal": "clean_line", + "wireframe": "wireframe", + "blueprint": "blueprint", + }.get(sketch_style, sketch_style) + palettes = { + "scribble_line": { + "background": (250, 247, 240), + "grid": (226, 220, 208), + "line": (46, 50, 56), + "accent": (73, 110, 168), + "text": (34, 37, 41), + "node_fill": (255, 255, 255), + "guide": (170, 170, 170), + "region_fill": (236, 232, 222), + "region_alt": (224, 232, 240), + }, + "clean_line": { + "background": (255, 255, 255), + "grid": (236, 238, 242), + "line": (48, 54, 61), + "accent": (53, 104, 214), + "text": (17, 24, 39), + "node_fill": (251, 252, 254), + "guide": (188, 195, 207), + "region_fill": (244, 246, 249), + "region_alt": (233, 239, 248), + }, + "blueprint": { + "background": (8, 24, 48), + "grid": (32, 72, 110), + "line": (132, 220, 255), + "accent": (121, 255, 198), + "text": (224, 245, 255), + "node_fill": (17, 58, 90), + "guide": (74, 126, 160), + "region_fill": (14, 48, 76), + "region_alt": (20, 66, 92), + }, + "wireframe": { + "background": (248, 250, 252), + "grid": (226, 232, 240), + "line": (51, 65, 85), + "accent": (14, 165, 233), + "text": (15, 23, 42), + "node_fill": (241, 245, 249), + "guide": (148, 163, 184), + "region_fill": (241, 245, 249), + "region_alt": (226, 232, 240), + }, + } + return palettes.get(sketch_style, palettes["scribble_line"]) + + def _build_low_preview_palette(self, sketch_style: str) -> Dict[str, Tuple[int, int, int]]: + sketch_style = { + "line_art": "scribble_line", + "minimal": "clean_line", + "wireframe": "wireframe", + "blueprint": "blueprint", + }.get(sketch_style, sketch_style) + palettes = { + "scribble_line": { + "background": (245, 241, 232), + "grid": (229, 222, 210), + "line": (84, 88, 94), + "accent": (218, 154, 84), + "text": (43, 46, 51), + "node_fill": (255, 252, 246), + "guide": (188, 180, 166), + "region_fill": (214, 227, 244), + "region_alt": (208, 228, 203), + }, + "clean_line": { + "background": (252, 253, 255), + "grid": (235, 239, 245), + "line": (82, 92, 105), + "accent": (238, 132, 60), + "text": (31, 41, 55), + "node_fill": (255, 255, 255), + "guide": (190, 199, 211), + "region_fill": (228, 236, 247), + "region_alt": (226, 242, 232), + }, + "blueprint": { + "background": (14, 32, 60), + "grid": (32, 72, 110), + "line": (167, 228, 255), + "accent": (255, 196, 105), + "text": (232, 246, 255), + "node_fill": (47, 88, 122), + "guide": (87, 126, 154), + "region_fill": (24, 62, 92), + "region_alt": (40, 86, 112), + }, + "wireframe": { + "background": (243, 246, 251), + "grid": (227, 234, 241), + "line": (75, 85, 99), + "accent": (14, 165, 233), + "text": (15, 23, 42), + "node_fill": (255, 255, 255), + "guide": (148, 163, 184), + "region_fill": (225, 236, 249), + "region_alt": (230, 243, 233), + }, + } + return palettes.get(sketch_style, palettes["scribble_line"]) + + def _build_rich_preview_palette(self, sketch_style: str) -> Dict[str, Tuple[int, int, int]]: + base = dict(self._build_preview_palette(sketch_style)) + if sketch_style == "clean_line": + base.update( + { + "background": (252, 252, 249), + "accent": (120, 124, 130), + "guide": (198, 202, 206), + "region_fill": (246, 244, 238), + "region_alt": (236, 234, 229), + } + ) + else: + base.update( + { + "accent": (128, 118, 102), + "guide": (186, 178, 168), + } + ) + return base + + def _draw_preview_grid(self, draw: ImageDraw, canvas_size: Tuple[int, int], palette: Dict[str, Tuple[int, int, int]], step: int = 40): + width, height = canvas_size + for x in range(0, width + 1, step): + draw.line([(x, 0), (x, height)], fill=palette["grid"], width=1) + for y in range(0, height + 1, step): + draw.line([(0, y), (width, y)], fill=palette["grid"], width=1) + + def _with_alpha(self, color: Tuple[int, int, int], opacity: float = 1.0) -> Tuple[int, int, int, int]: + alpha = max(0, min(255, int(round(255 * opacity)))) + return color[0], color[1], color[2], alpha + + def _recipe_fill(self, palette: Dict[str, Tuple[int, int, int]], fill_role: str, filled: bool = False) -> Tuple[int, int, int, int] | None: + role = str(fill_role or "fill") + if role in {"none", "transparent"}: + return None + base = palette["node_fill"] if role == "fill" else palette["region_fill"] + if role == "region_alt": + base = palette["region_alt"] + elif role == "accent_fill": + base = palette["accent"] + elif role == "background": + base = palette["background"] + opacity = 0.96 if filled else 0.18 + if role in {"region_fill", "region_alt"}: + opacity = 0.36 if filled else 0.16 + if role == "accent_fill": + opacity = 0.3 if not filled else 0.8 + return self._with_alpha(base, opacity) + + def _recipe_stroke(self, palette: Dict[str, Tuple[int, int, int]], stroke_role: str, opacity: float = 1.0) -> Tuple[int, int, int, int] | None: + role = str(stroke_role or "line") + if role in {"none", "transparent"}: + return None + color = palette["line"] if role == "line" else palette["accent"] if role == "accent" else palette["guide"] + return self._with_alpha(color, opacity) + + def _scaled_points(self, points: List[List[float]], box: Tuple[int, int, int, int]) -> List[Tuple[float, float]]: + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + return [(x0 + width * float(px), y0 + height * float(py)) for px, py in points] + + def _draw_shape_recipe( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + shape_recipe: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + filled: bool = False, + style_variant: str = "", + ) -> bool: + parts = list((shape_recipe or {}).get("parts") or []) + if not parts: + return False + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + rough = "scribble" in str(style_variant or "") + + for part in parts: + kind = str(part.get("kind") or "").lower() + opacity = float(part.get("opacity", 1.0) or 1.0) + fill = self._recipe_fill(palette, str(part.get("fill_role", "fill")), filled=filled) + outline = self._recipe_stroke(palette, str(part.get("stroke_role", "line")), opacity=opacity) + stroke_width = max(1, int(round(max(width, height) * float(part.get("stroke_width", 0.02) or 0.02)))) + dash = part.get("dash") or [] + + if kind == "rect": + rx = float(part.get("rx", 0.0) or 0.0) + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + draw.rounded_rectangle(rect, radius=max(0, int(min(width, height) * rx)), fill=fill, outline=outline, width=stroke_width) + if rough and outline: + offset = max(1, stroke_width // 3) + shifted = [rect[0] + offset, rect[1] + offset, rect[2] + offset, rect[3] + offset] + draw.rounded_rectangle(shifted, radius=max(0, int(min(width, height) * rx)), fill=None, outline=outline, width=max(1, stroke_width - 1)) + continue + + if kind == "ellipse": + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + draw.ellipse(rect, fill=fill, outline=outline, width=stroke_width) + if rough and outline: + offset = max(1, stroke_width // 3) + shifted = [rect[0] + offset, rect[1] + offset, rect[2] + offset, rect[3] + offset] + draw.ellipse(shifted, fill=None, outline=outline, width=max(1, stroke_width - 1)) + continue + + if kind == "line": + start = ( + x0 + width * float(part.get("x1", 0.0)), + y0 + height * float(part.get("y1", 0.0)), + ) + end = ( + x0 + width * float(part.get("x2", 0.0)), + y0 + height * float(part.get("y2", 0.0)), + ) + if dash: + dash_len = max(6, int(max(width, height) * float(dash[0]))) + self._draw_dashed_line(draw, start, end, outline or palette["line"], width=stroke_width, dash_length=dash_len) + else: + draw.line([start, end], fill=outline or palette["line"], width=stroke_width) + if rough and outline: + draw.line([(start[0] + 1, start[1] + 1), (end[0] + 1, end[1] + 1)], fill=outline, width=max(1, stroke_width - 1)) + continue + + if kind == "polygon": + points = self._scaled_points(part.get("points") or [], box) + if points: + draw.polygon(points, fill=fill, outline=outline) + if outline and stroke_width > 1: + draw.line(points + [points[0]], fill=outline, width=stroke_width) + if rough: + shifted = [(px + 1, py + 1) for px, py in points] + draw.line(shifted + [shifted[0]], fill=outline, width=max(1, stroke_width - 1)) + continue + + if kind == "polyline": + points = self._scaled_points(part.get("points") or [], box) + if points: + draw.line(points, fill=outline or palette["line"], width=stroke_width) + if rough and outline: + shifted = [(px + 1, py + 1) for px, py in points] + draw.line(shifted, fill=outline, width=max(1, stroke_width - 1)) + continue + + return True + + def _draw_stroke_payload( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + stroke_payload: List[List[List[float]]] | None, + palette: Dict[str, Tuple[int, int, int]], + *, + style_variant: str = "", + stroke_render_profile: Dict[str, Any] | None = None, + ) -> bool: + strokes = [stroke for stroke in list(stroke_payload or []) if len(stroke) >= 2] + if not strokes: + return False + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + rough = "scribble" in str(style_variant or "") + profile = stroke_render_profile if isinstance(stroke_render_profile, dict) else {} + min_width = float(profile.get("line_width_min", profile.get("min_width", 0.014)) or 0.014) + max_width = float(profile.get("line_width_max", profile.get("max_width", 0.034)) or 0.034) + opacity = float(profile.get("opacity", 0.96) or 0.96) + accent_ratio = float(profile.get("accent_ratio", 0.2) or 0.2) + for index, stroke in enumerate(strokes): + points = [(x0 + width * float(px), y0 + height * float(py)) for px, py in stroke] + if len(points) < 2: + continue + ratio = index / max(1, len(strokes) - 1) if len(strokes) > 1 else 0.0 + line_width = max(1, int(round(max(width, height) * (min_width + (max_width - min_width) * ratio)))) + line_role = "accent" if ratio <= accent_ratio else "line" + color = self._recipe_stroke(palette, line_role, opacity=opacity) or self._with_alpha(palette["line"], opacity) + draw.line(points, fill=color, width=line_width) + if rough: + shifted = [(px + 1.0, py + 1.0) for px, py in points] + draw.line(shifted, fill=self._recipe_stroke(palette, line_role, opacity=max(0.18, opacity * 0.55)) or color, width=max(1, line_width - 1)) + return True + + def _scene_bbox(self, item: Dict[str, Any]) -> Tuple[int, int, int, int]: + x0 = int(item.get("x", 0)) + y0 = int(item.get("y", 0)) + x1 = x0 + int(item.get("width", 0)) + y1 = y0 + int(item.get("height", 0)) + return x0, y0, x1, y1 + + def _scene_center(self, item: Dict[str, Any]) -> Tuple[float, float]: + x0, y0, x1, y1 = self._scene_bbox(item) + return (x0 + x1) / 2.0, (y0 + y1) / 2.0 + + def _connector_points_for_scene(self, from_item: Dict[str, Any], to_item: Dict[str, Any]) -> Tuple[Tuple[float, float], Tuple[float, float]]: + from_center = self._scene_center(from_item) + to_center = self._scene_center(to_item) + if from_center[0] <= to_center[0]: + start = (from_item["x"] + from_item["width"], from_center[1]) + end = (to_item["x"], to_center[1]) + else: + start = (from_item["x"], from_center[1]) + end = (to_item["x"] + to_item["width"], to_center[1]) + return start, end + + def _draw_scene_background_layer(self, draw: ImageDraw, layer: Dict[str, Any], palette: Dict[str, Tuple[int, int, int]], filled: bool = False): + x0, y0, x1, y1 = self._scene_bbox(layer) + layer_type = str(layer.get("type", "panel")) + fill = palette["region_alt"] if layer_type in {"ground", "road", "board", "water"} else palette["region_fill"] + outline = palette["guide"] if filled else palette["line"] + fill_alpha = self._with_alpha(fill, 0.45 if filled else 0.16) + outline_alpha = self._with_alpha(outline, 0.5 if filled else 0.3) + if layer_type == "road": + draw.rounded_rectangle([x0, y0, x1, y1], radius=18, fill=fill_alpha, outline=outline_alpha, width=2) + lane_y = int((y0 + y1) / 2) + self._draw_dashed_line(draw, (x0 + 24, lane_y), (x1 - 24, lane_y), palette["accent"], width=2, dash_length=18) + return + if layer_type == "sky": + draw.rectangle([x0, y0, x1, y1], fill=self._with_alpha(fill, 0.18 if not filled else 0.42)) + draw.line([(x0, y1), (x1, y1)], fill=outline_alpha, width=2) + return + if layer_type == "process_band": + draw.rounded_rectangle( + [x0 + 8, y0 + 10, x1 - 8, y1 - 10], + radius=28, + fill=self._with_alpha(fill, 0.06 if not filled else 0.14), + outline=self._with_alpha(outline, 0.14 if not filled else 0.2), + width=1, + ) + return + draw.rounded_rectangle([x0, y0, x1, y1], radius=20, fill=fill_alpha, outline=outline_alpha, width=2) + + def _draw_asset_symbol( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + silhouette_key: str, + palette: Dict[str, Tuple[int, int, int]], + filled: bool = False, + ): + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + line = palette["line"] + accent = palette["accent"] + fill = palette["node_fill"] if filled else palette["background"] + if silhouette_key in {"generic_panel", "generic_object"}: + draw.rounded_rectangle([x0, y0, x1, y1], radius=18, fill=fill, outline=line, width=3) + if silhouette_key == "generic_panel": + draw.line([(x0 + 18, y0 + 24), (x1 - 18, y0 + 24)], fill=accent, width=2) + return + if silhouette_key == "generic_circle": + draw.ellipse([x0, y0, x1, y1], fill=fill, outline=line, width=3) + return + if silhouette_key == "building": + draw.rectangle([x0 + width * 0.1, y0 + height * 0.08, x1 - width * 0.1, y1], fill=fill, outline=line, width=3) + for row in range(3): + for col in range(3): + wx = x0 + width * (0.18 + col * 0.22) + wy = y0 + height * (0.16 + row * 0.22) + ww = width * 0.12 + wh = height * 0.12 + draw.rectangle([wx, wy, wx + ww, wy + wh], outline=accent, width=2) + return + if silhouette_key == "house": + draw.polygon([(x0 + width * 0.5, y0), (x0, y0 + height * 0.34), (x1, y0 + height * 0.34)], fill=fill, outline=line, width=3) + draw.rectangle([x0 + width * 0.14, y0 + height * 0.34, x1 - width * 0.14, y1], fill=fill, outline=line, width=3) + draw.rectangle([x0 + width * 0.42, y0 + height * 0.56, x0 + width * 0.58, y1], outline=accent, width=2) + return + if silhouette_key == "window": + draw.rectangle([x0, y0, x1, y1], fill=fill, outline=line, width=3) + draw.line([(x0 + width / 2, y0), (x0 + width / 2, y1)], fill=accent, width=2) + draw.line([(x0, y0 + height / 2), (x1, y0 + height / 2)], fill=accent, width=2) + return + if silhouette_key == "door": + draw.rounded_rectangle([x0, y0, x1, y1], radius=14, fill=fill, outline=line, width=3) + knob = (x1 - width * 0.18, y0 + height * 0.56) + self._draw_circle(draw, knob, max(3, width * 0.04), fill=accent, outline=accent, width=1) + return + if silhouette_key == "tree": + trunk_w = width * 0.18 + draw.rectangle([x0 + width * 0.41, y0 + height * 0.56, x0 + width * 0.41 + trunk_w, y1], fill=accent if filled else fill, outline=line, width=3) + draw.ellipse([x0 + width * 0.12, y0, x0 + width * 0.88, y0 + height * 0.66], fill=fill, outline=line, width=3) + draw.ellipse([x0, y0 + height * 0.12, x0 + width * 0.56, y0 + height * 0.66], fill=fill, outline=line, width=2) + draw.ellipse([x0 + width * 0.44, y0 + height * 0.12, x1, y0 + height * 0.66], fill=fill, outline=line, width=2) + return + if silhouette_key == "cloud": + draw.ellipse([x0 + width * 0.08, y0 + height * 0.28, x0 + width * 0.46, y1], fill=fill, outline=line, width=3) + draw.ellipse([x0 + width * 0.26, y0, x0 + width * 0.7, y0 + height * 0.9], fill=fill, outline=line, width=3) + draw.ellipse([x0 + width * 0.54, y0 + height * 0.22, x1, y1], fill=fill, outline=line, width=3) + return + if silhouette_key == "sun": + cx = x0 + width / 2 + cy = y0 + height / 2 + radius = min(width, height) * 0.28 + self._draw_circle(draw, (cx, cy), radius, fill=fill, outline=line, width=3) + for ray in range(8): + angle = math.radians(ray * 45) + sx = cx + math.cos(angle) * radius * 1.3 + sy = cy + math.sin(angle) * radius * 1.3 + ex = cx + math.cos(angle) * radius * 1.85 + ey = cy + math.sin(angle) * radius * 1.85 + draw.line([(sx, sy), (ex, ey)], fill=accent, width=2) + return + if silhouette_key == "car": + draw.rounded_rectangle([x0 + width * 0.08, y0 + height * 0.34, x1 - width * 0.08, y1 - height * 0.12], radius=14, fill=fill, outline=line, width=3) + draw.polygon( + [(x0 + width * 0.24, y0 + height * 0.34), (x0 + width * 0.38, y0 + height * 0.1), (x0 + width * 0.72, y0 + height * 0.1), (x0 + width * 0.84, y0 + height * 0.34)], + fill=fill, + outline=line, + width=3, + ) + self._draw_circle(draw, (x0 + width * 0.3, y1 - height * 0.1), min(width, height) * 0.11, fill=palette["background"], outline=line, width=3) + self._draw_circle(draw, (x0 + width * 0.72, y1 - height * 0.1), min(width, height) * 0.11, fill=palette["background"], outline=line, width=3) + return + if silhouette_key == "road": + draw.rounded_rectangle([x0, y0 + height * 0.2, x1, y1], radius=18, fill=fill, outline=line, width=3) + self._draw_dashed_line(draw, (x0 + width * 0.08, y0 + height * 0.62), (x1 - width * 0.08, y0 + height * 0.62), accent, width=2, dash_length=18) + return + if silhouette_key == "person": + cx = x0 + width / 2 + head_r = min(width, height) * 0.16 + self._draw_circle(draw, (cx, y0 + head_r * 1.25), head_r, fill=fill, outline=line, width=3) + draw.line([(cx, y0 + head_r * 2.5), (cx, y0 + height * 0.72)], fill=line, width=3) + draw.line([(cx, y0 + height * 0.36), (x0 + width * 0.22, y0 + height * 0.5)], fill=line, width=3) + draw.line([(cx, y0 + height * 0.36), (x1 - width * 0.22, y0 + height * 0.5)], fill=line, width=3) + draw.line([(cx, y0 + height * 0.72), (x0 + width * 0.24, y1)], fill=line, width=3) + draw.line([(cx, y0 + height * 0.72), (x1 - width * 0.24, y1)], fill=line, width=3) + return + if silhouette_key == "street_lamp": + draw.line([(x0 + width * 0.5, y1), (x0 + width * 0.5, y0 + height * 0.18)], fill=line, width=4) + draw.line([(x0 + width * 0.5, y0 + height * 0.2), (x1, y0 + height * 0.2)], fill=line, width=3) + draw.arc([x1 - width * 0.36, y0 + height * 0.12, x1, y0 + height * 0.44], 200, 360, fill=line, width=3) + self._draw_circle(draw, (x1 - width * 0.06, y0 + height * 0.4), max(4, width * 0.05), fill=accent, outline=accent, width=2) + return + if silhouette_key == "table": + draw.rectangle([x0 + width * 0.08, y0 + height * 0.24, x1 - width * 0.08, y0 + height * 0.38], fill=fill, outline=line, width=3) + for ratio in (0.18, 0.82): + draw.line([(x0 + width * ratio, y0 + height * 0.38), (x0 + width * ratio, y1)], fill=line, width=3) + return + if silhouette_key == "chair": + draw.line([(x0 + width * 0.24, y1), (x0 + width * 0.24, y0 + height * 0.44)], fill=line, width=3) + draw.line([(x0 + width * 0.76, y1), (x0 + width * 0.76, y0 + height * 0.44)], fill=line, width=3) + draw.line([(x0 + width * 0.24, y0 + height * 0.62), (x0 + width * 0.76, y0 + height * 0.62)], fill=line, width=3) + draw.line([(x0 + width * 0.24, y0 + height * 0.44), (x0 + width * 0.24, y0 + height * 0.1)], fill=line, width=3) + draw.line([(x0 + width * 0.24, y0 + height * 0.1), (x0 + width * 0.76, y0 + height * 0.1)], fill=line, width=3) + return + if silhouette_key == "battery": + draw.rounded_rectangle([x0, y0 + height * 0.12, x1, y1], radius=10, fill=fill, outline=line, width=3) + draw.rectangle([x0 + width * 0.4, y0, x0 + width * 0.6, y0 + height * 0.14], fill=fill, outline=line, width=2) + draw.line([(x0 + width * 0.25, y0 + height * 0.5), (x0 + width * 0.42, y0 + height * 0.5)], fill=accent, width=2) + draw.line([(x0 + width * 0.66, y0 + height * 0.5), (x0 + width * 0.82, y0 + height * 0.5)], fill=accent, width=2) + draw.line([(x0 + width * 0.74, y0 + height * 0.42), (x0 + width * 0.74, y0 + height * 0.58)], fill=accent, width=2) + return + if silhouette_key == "led": + draw.ellipse([x0 + width * 0.24, y0, x0 + width * 0.76, y0 + height * 0.58], fill=fill, outline=line, width=3) + draw.line([(x0 + width * 0.4, y0 + height * 0.56), (x0 + width * 0.36, y1)], fill=line, width=3) + draw.line([(x0 + width * 0.6, y0 + height * 0.56), (x0 + width * 0.66, y1)], fill=line, width=3) + self._draw_arrow_line(draw, (x0 + width * 0.76, y0 + height * 0.18), (x1, y0), accent, width=2, arrow_size=10) + self._draw_arrow_line(draw, (x0 + width * 0.78, y0 + height * 0.34), (x1, y0 + height * 0.16), accent, width=2, arrow_size=10) + return + if silhouette_key == "resistor": + points = [ + (x0, y0 + height * 0.5), + (x0 + width * 0.14, y0 + height * 0.5), + (x0 + width * 0.24, y0 + height * 0.24), + (x0 + width * 0.38, y0 + height * 0.76), + (x0 + width * 0.52, y0 + height * 0.24), + (x0 + width * 0.66, y0 + height * 0.76), + (x0 + width * 0.78, y0 + height * 0.5), + (x1, y0 + height * 0.5), + ] + draw.line(points, fill=line, width=3) + return + if silhouette_key == "capacitor": + draw.line([(x0 + width * 0.22, y0 + height * 0.16), (x0 + width * 0.22, y1)], fill=line, width=3) + draw.line([(x0 + width * 0.46, y0 + height * 0.16), (x0 + width * 0.46, y1)], fill=line, width=3) + draw.line([(x0, y0 + height * 0.58), (x0 + width * 0.22, y0 + height * 0.58)], fill=accent, width=2) + draw.line([(x0 + width * 0.46, y0 + height * 0.58), (x1, y0 + height * 0.58)], fill=accent, width=2) + return + if silhouette_key == "diode": + draw.line([(x0, y0 + height * 0.5), (x0 + width * 0.18, y0 + height * 0.5)], fill=line, width=3) + draw.polygon([(x0 + width * 0.18, y0 + height * 0.16), (x0 + width * 0.18, y1 - height * 0.16), (x0 + width * 0.64, y0 + height * 0.5)], fill=fill, outline=line, width=3) + draw.line([(x0 + width * 0.74, y0 + height * 0.16), (x0 + width * 0.74, y1 - height * 0.16)], fill=line, width=3) + draw.line([(x0 + width * 0.74, y0 + height * 0.5), (x1, y0 + height * 0.5)], fill=line, width=3) + return + if silhouette_key == "board": + draw.rounded_rectangle([x0, y0, x1, y1], radius=16, fill=fill, outline=line, width=3) + for row in range(2): + for col in range(4): + px = x0 + width * (0.12 + col * 0.18) + py = y0 + height * (0.18 + row * 0.28) + draw.rectangle([px, py, px + width * 0.1, py + height * 0.12], outline=accent, width=2) + return + if silhouette_key == "airplane": + draw.line([(x0 + width * 0.08, y0 + height * 0.52), (x1, y0 + height * 0.52)], fill=line, width=4) + draw.polygon([(x0 + width * 0.3, y0 + height * 0.52), (x0 + width * 0.56, y0 + height * 0.14), (x0 + width * 0.52, y0 + height * 0.52)], fill=fill, outline=line, width=3) + draw.polygon([(x0 + width * 0.38, y0 + height * 0.52), (x0 + width * 0.62, y1 - height * 0.12), (x0 + width * 0.54, y0 + height * 0.52)], fill=fill, outline=line, width=3) + draw.polygon([(x0 + width * 0.12, y0 + height * 0.52), (x0 + width * 0.22, y0 + height * 0.24), (x0 + width * 0.24, y0 + height * 0.52)], fill=fill, outline=line, width=3) + return + if silhouette_key == "leaf": + draw.ellipse([x0, y0 + height * 0.16, x1, y1], fill=fill, outline=line, width=3) + draw.line([(x0 + width * 0.12, y0 + height * 0.84), (x1 - width * 0.12, y0 + height * 0.24)], fill=accent, width=2) + return + if silhouette_key == "raindrop": + draw.polygon([(x0 + width * 0.5, y0), (x1, y0 + height * 0.54), (x0 + width * 0.78, y1), (x0 + width * 0.22, y1), (x0, y0 + height * 0.54)], fill=fill, outline=line, width=3) + return + if silhouette_key == "cell": + draw.ellipse([x0, y0, x1, y1], fill=fill, outline=line, width=3) + draw.ellipse([x0 + width * 0.28, y0 + height * 0.28, x0 + width * 0.72, y0 + height * 0.72], fill=palette["region_alt"], outline=accent, width=2) + return + draw.rounded_rectangle([x0, y0, x1, y1], radius=18, fill=fill, outline=line, width=3) + + def _build_object_sprite(self, obj: Dict[str, Any], palette: Dict[str, Tuple[int, int, int]], filled: bool = False) -> Image.Image: + width = max(40, int(obj.get("width", 80))) + height = max(40, int(obj.get("height", 80))) + padding = 18 + sprite = Image.new("RGBA", (width + padding * 2, height + padding * 2), (0, 0, 0, 0)) + draw = ImageDraw.Draw(sprite) + style_variant = str(obj.get("style_variant") or obj.get("layout_style") or "") + stroke_render_profile = obj.get("stroke_render_profile") if isinstance(obj.get("stroke_render_profile"), dict) else obj.get("stroke_style_profile") + rendered = False + if str(obj.get("render_representation") or "") == "stroke_native" or obj.get("stroke_payload"): + rendered = self._draw_stroke_payload( + draw, + (padding, padding, padding + width, padding + height), + obj.get("stroke_payload") if isinstance(obj.get("stroke_payload"), list) else [], + palette, + style_variant=style_variant, + stroke_render_profile=stroke_render_profile if isinstance(stroke_render_profile, dict) else {}, + ) + if not rendered: + shape_recipe = obj.get("shape_recipe") if isinstance(obj.get("shape_recipe"), dict) else {} + rendered = self._draw_shape_recipe( + draw, + (padding, padding, padding + width, padding + height), + shape_recipe, + palette, + filled=filled, + style_variant=style_variant, + ) + if not rendered: + self._draw_asset_symbol( + draw, + (padding, padding, padding + width, padding + height), + str(obj.get("silhouette_key") or obj.get("asset_key") or "generic_object"), + palette, + filled=filled, + ) + rotation = float(obj.get("rotation", 0.0) or 0.0) + if abs(rotation) > 0.1: + sprite = sprite.rotate(-rotation, expand=True, resample=Image.BICUBIC) + return sprite + + def _draw_scene_connector( + self, + draw: ImageDraw, + connector: Dict[str, Any], + objects: Dict[str, Dict[str, Any]], + palette: Dict[str, Tuple[int, int, int]], + show_labels: bool = True, + ): + from_obj = objects.get(connector.get("from_id")) + to_obj = objects.get(connector.get("to_id")) + if not from_obj or not to_obj or not connector.get("visible", True): + return + start, end = self._connector_points_for_scene(from_obj, to_obj) + connector_type = str(connector.get("type", "relation")) + label = str(connector.get("label", "连接")) + line_color = palette["accent"] if connector_type in {"beam", "arrow"} else palette["line"] + if connector_type == "beam": + self._draw_dashed_line(draw, start, end, line_color, width=3, dash_length=12) + elif connector_type == "arrow": + self._draw_arrow_line(draw, start, end, line_color, width=3, arrow_size=12) + elif connector_type == "wire": + draw.line([start, end], fill=line_color, width=3) + else: + self._draw_dashed_line(draw, start, end, line_color, width=2, dash_length=10) + if show_labels and label: + mid_x = int((start[0] + end[0]) / 2) + mid_y = int((start[1] + end[1]) / 2 - 16) + draw.text((mid_x, mid_y), label, fill=palette["text"], font=self.font, anchor="mm") + + def _resolve_scene_view_flags( + self, + layout_options: Dict[str, Any], + *, + view_mode: str | None = None, + force_show_labels: bool | None = None, + force_show_grid: bool | None = None, + force_show_guides: bool | None = None, + ) -> Dict[str, Any]: + resolved_view = normalize_view_mode(view_mode or layout_options.get("sketch_view_mode")) + annotation_level = normalize_annotation_level(layout_options.get("annotation_level")) + show_grid = bool(layout_options.get("show_grid", True)) + show_labels = bool(layout_options.get("show_labels", False)) + show_guides = bool(layout_options.get("show_guides", False)) + + if resolved_view == "rough": + show_labels = False + show_guides = False + elif resolved_view == "structure": + show_labels = show_labels and annotation_level != "off" + show_guides = False + elif resolved_view == "annotated": + show_labels = annotation_level != "off" + show_guides = True + elif resolved_view == "region": + show_labels = annotation_level != "off" + show_guides = True + + if force_show_labels is not None: + show_labels = bool(force_show_labels) + if force_show_grid is not None: + show_grid = bool(force_show_grid) + if force_show_guides is not None: + show_guides = bool(force_show_guides) + + return { + "view_mode": resolved_view, + "annotation_level": annotation_level, + "show_grid": show_grid, + "show_labels": show_labels, + "show_guides": show_guides, + "show_regions": resolved_view == "region", + "show_override_regions": resolved_view in {"annotated", "region"}, + } + + def _region_box_for_object(self, obj: Dict[str, Any], region: Dict[str, Any]) -> Tuple[int, int, int, int]: + x0 = int(obj.get("x", 0) + obj.get("width", 0) * float(region.get("x", 0.0))) + y0 = int(obj.get("y", 0) + obj.get("height", 0) * float(region.get("y", 0.0))) + x1 = int(x0 + obj.get("width", 0) * float(region.get("width", 0.0))) + y1 = int(y0 + obj.get("height", 0) * float(region.get("height", 0.0))) + return x0, y0, x1, y1 + + def _draw_region_shape( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + region: Dict[str, Any], + *, + outline: Tuple[int, int, int] | Tuple[int, int, int, int], + width: int = 2, + fill: Tuple[int, int, int, int] | None = None, + dash_length: int = 8, + ) -> None: + shape = str(region.get("shape") or "rect") + if shape == "ellipse": + draw.ellipse(box, outline=outline, fill=fill, width=width) + return + if dash_length > 0 and fill is None: + self._draw_dashed_rectangle(draw, box, outline, width=width, dash_length=dash_length) + return + draw.rounded_rectangle(box, radius=max(4, int(min(box[2] - box[0], box[3] - box[1]) * 0.12)), outline=outline, fill=fill, width=width) + + def _region_style(self, action: str, palette: Dict[str, Tuple[int, int, int]]) -> Dict[str, Any]: + normalized = str(action or "").strip().lower() + if normalized == "hide": + return { + "outline": (244, 63, 94), + "fill": self._with_alpha((244, 63, 94), 0.1), + "text": (251, 113, 133), + "dash": 7, + } + if normalized == "weaken": + return { + "outline": (56, 189, 248), + "fill": self._with_alpha((56, 189, 248), 0.12), + "text": (125, 211, 252), + "dash": 8, + } + if normalized == "emphasize": + return { + "outline": (245, 158, 11), + "fill": self._with_alpha((245, 158, 11), 0.1), + "text": (253, 224, 71), + "dash": 0, + } + if normalized == "replace": + return { + "outline": (168, 85, 247), + "fill": self._with_alpha((168, 85, 247), 0.12), + "text": (196, 181, 253), + "dash": 6, + } + return { + "outline": palette["accent"], + "fill": self._with_alpha(palette["region_fill"], 0.12), + "text": palette["accent"], + "dash": 8, + } + + def _draw_region_overlays( + self, + draw: ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + labels: bool = True, + only_overrides: bool = False, + ) -> None: + for obj in scene.get("object_instances", []) or []: + regions = [item for item in obj.get("region_masks", []) or [] if isinstance(item, dict)] + overrides = obj.get("region_overrides") if isinstance(obj.get("region_overrides"), dict) else {} + if only_overrides: + regions = [item for item in regions if overrides.get(str(item.get("id") or ""))] + if not regions: + continue + for region in regions: + region_id = str(region.get("id") or "") + override = overrides.get(region_id) if isinstance(overrides, dict) else None + action = str((override or {}).get("action") or "").strip().lower() + style = self._region_style(action, palette) + box = self._region_box_for_object(obj, region) + self._draw_region_shape( + draw, + box, + region, + outline=style["outline"], + width=3 if action else 2, + fill=style["fill"] if action else None, + dash_length=style["dash"], + ) + if labels: + label = str(region.get("label") or region_id or "region") + action_label = {"hide": "隐藏", "weaken": "弱化", "emphasize": "强调", "replace": "替换"}.get(action, "") + if action: + label = f"{label} · {action_label or action}" + draw.text((box[0] + 6, max(10, box[1] - 12)), label, fill=style["text"], font=self.font) + + def _render_semantic_scene_image( + self, + scene_spec: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + title: str, + filled: bool = False, + *, + include_title: bool = True, + view_mode: str | None = None, + force_show_labels: bool | None = None, + force_show_grid: bool | None = None, + force_show_guides: bool | None = None, + ) -> Image.Image: + scene = normalize_scene_spec_v2(scene_spec) + canvas_size = (scene["canvas_size"]["width"], scene["canvas_size"]["height"]) + base = Image.new("RGBA", canvas_size, (*palette["background"], 255)) + draw = ImageDraw.Draw(base) + layout_options = scene.get("layout_options", {}) + view_flags = self._resolve_scene_view_flags( + layout_options, + view_mode=view_mode, + force_show_labels=force_show_labels, + force_show_grid=force_show_grid, + force_show_guides=force_show_guides, + ) + if view_flags["show_grid"]: + self._draw_preview_grid(draw, canvas_size, palette) + for layer in sorted(scene.get("background_layers", []), key=lambda item: item.get("z_index", 0)): + self._draw_scene_background_layer(draw, layer, palette, filled=filled) + if view_flags["show_labels"] and view_flags["view_mode"] in {"annotated", "region"}: + draw.text((layer["x"] + 16, layer["y"] + 20), str(layer.get("label", "")), fill=palette["text"], font=self.font) + if include_title and title: + draw.text((24, 20), title, fill=palette["text"], font=self.font) + style_desc = f"{layout_options.get('scene_type', 'scene')} | {layout_options.get('sketch_style', 'line_art')} | {view_flags['view_mode']}" + draw.text((24, 52), style_desc, fill=palette["text"], font=self.font) + objects_by_id = {item["id"]: item for item in scene.get("object_instances", [])} + for connector in scene.get("connectors", []): + self._draw_scene_connector(draw, connector, objects_by_id, palette, show_labels=view_flags["show_labels"]) + for obj in sorted(scene.get("object_instances", []), key=lambda item: item.get("z_index", 0)): + if obj.get("visible", True) is False: + continue + if view_flags["show_guides"]: + x0, y0, x1, y1 = self._scene_bbox(obj) + self._draw_dashed_rectangle(draw, (x0, y0, x1, y1), palette["guide"], width=1, dash_length=8) + sprite = self._build_object_sprite(obj, palette, filled=filled) + left = int(obj["x"] + obj["width"] / 2 - sprite.width / 2) + top = int(obj["y"] + obj["height"] / 2 - sprite.height / 2) + base.alpha_composite(sprite, (left, top)) + if view_flags["show_labels"]: + draw.text((obj["x"] + obj["width"] / 2, obj["y"] - 18), str(obj.get("concept", "")), fill=palette["text"], font=self.font, anchor="mm") + if view_flags["show_regions"]: + self._draw_region_overlays(draw, scene, palette, labels=True, only_overrides=False) + elif view_flags["show_override_regions"]: + self._draw_region_overlays(draw, scene, palette, labels=view_flags["show_labels"], only_overrides=True) + return base.convert("RGB") + + def _render_control_palette(self) -> Dict[str, Tuple[int, int, int]]: + return { + "background": (242, 241, 237), + "sky": (224, 229, 236), + "ground": (223, 226, 216), + "road": (214, 216, 219), + "water": (214, 223, 228), + "wall": (229, 226, 221), + "board": (226, 222, 214), + "process_band": (223, 219, 231), + "scene_object": (150, 158, 169), + "process_motif": (160, 151, 176), + "schematic_symbol": (144, 159, 148), + "subject": (128, 141, 158), + "user": (163, 146, 126), + "connector": (132, 137, 144), + } + + def _compose_rich_preview_image( + self, + structural_sketch_image: Image.Image, + low_preview_image: Image.Image, + *, + sketch_style: str, + ) -> Image.Image: + structural = structural_sketch_image.convert("RGBA") + low_preview = low_preview_image.convert("RGBA") + base = Image.blend(low_preview, structural, 0.42 if sketch_style == "clean_line" else 0.5) + overlay = structural.copy() + overlay.putalpha(216 if sketch_style == "clean_line" else 192) + merged = Image.alpha_composite(base, overlay) + return merged.convert("RGB") + + def _line_alpha_mask( + self, + image: Image.Image, + *, + gain: float = 1.0, + bias: int = 0, + ) -> Image.Image: + inverted = ImageOps.invert(image.convert("L")) + if gain != 1.0 or bias != 0: + inverted = inverted.point(lambda px: max(0, min(255, int(px * gain) + bias))) + return inverted + + def _soft_mass_outline_mask(self, mask: Image.Image) -> Image.Image: + inner = mask.filter(ImageFilter.GaussianBlur(radius=1.6)) + outer = mask.filter(ImageFilter.GaussianBlur(radius=7.5)) + outline = ImageChops.difference(inner, outer) + return outline.point(lambda px: 0 if px < 8 else min(255, int(px * 1.18))) + + def _balanced_upstream_box( + self, + box: Tuple[int, int, int, int], + *, + canvas_size: Tuple[int, int], + asset_key: str, + multi_anchor_scene: bool, + ) -> Tuple[int, int, int, int]: + if not multi_anchor_scene: + return box + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + short_side = min(width, height) + long_side = max(width, height) + key = str(asset_key or "").strip().lower() + min_short = 140 + max_long = 280 + if key in {"house", "home", "building"}: + min_short = 168 + elif key in {"tree", "leaf", "plant", "bush"}: + min_short = 156 + max_long = 260 + elif key in {"person", "human", "figure", "character"}: + min_short = 148 + max_long = 292 + scale = 1.0 + if short_side < min_short: + scale = max(scale, min(1.55, float(min_short) / max(1.0, float(short_side)))) + if long_side > max_long: + scale = min(scale, max(0.78, float(max_long) / max(1.0, float(long_side)))) + if abs(scale - 1.0) < 0.02: + return box + center_x = (x0 + x1) / 2.0 + center_y = (y0 + y1) / 2.0 + new_width = max(24, int(round(width * scale))) + new_height = max(24, int(round(height * scale))) + if key in {"person", "human", "figure", "character"} and new_height > new_width: + aspect = float(new_height) / max(1.0, float(new_width)) + if aspect > 1.46: + target_width = int(round(new_height / 1.46)) + new_width = max(new_width, min(canvas_size[0], target_width)) + new_height = max(24, int(round(new_height * 0.94))) + new_x0 = max(0, int(round(center_x - new_width / 2.0))) + new_y0 = max(0, int(round(center_y - new_height / 2.0))) + new_x1 = min(canvas_size[0], new_x0 + new_width) + new_y1 = min(canvas_size[1], new_y0 + new_height) + if new_x1 - new_x0 < 24: + new_x0 = max(0, new_x1 - 24) + if new_y1 - new_y0 < 24: + new_y0 = max(0, new_y1 - 24) + return (new_x0, new_y0, new_x1, new_y1) + + def _sd_upstream_background_color(self, layer_type: str) -> Tuple[Tuple[int, int, int], int, int]: + key = str(layer_type or "").strip().lower() + if key in {"ground", "road", "board"}: + return (212, 217, 223), 36, 10 + if key in {"water"}: + return (206, 216, 224), 34, 10 + if key in {"sky", "cloud_band"}: + return (238, 236, 232), 18, 16 + if key in {"process_band"}: + return (220, 221, 226), 26, 8 + return (234, 232, 228), 16, 12 + + def _sd_upstream_object_style(self, obj: Dict[str, Any], scene_type: str = "scene") -> Tuple[Tuple[int, int, int], int, int]: + depth_band = str(obj.get("depth_band") or "").strip().lower() + role = str(obj.get("role") or "").strip().lower() + tone = (162, 164, 170) + alpha = 96 + blur = 14 + if depth_band == "foreground": + tone = (136, 138, 146) + alpha = 126 + blur = 9 + elif depth_band == "background": + tone = (184, 186, 192) + alpha = 72 + blur = 18 + if role in {"subject", "focus", "core_subject"}: + tone = (118, 121, 130) + alpha = max(alpha, 134) + blur = max(7, blur - 2) + if scene_type == "process": + alpha = min(168, alpha + 8) + blur = max(6, blur - 4) + elif scene_type == "schematic": + tone = tuple(max(96, min(188, channel - 8)) for channel in tone) + alpha = min(164, alpha + 10) + blur = max(5, blur - 5) + return tone, alpha, blur + + def _render_sd_upstream_control_image( + self, + scene_spec: Dict[str, Any], + *, + structural_sketch_image: Image.Image, + ) -> Image.Image: + scene = normalize_scene_spec_v2(scene_spec) + canvas_size = (scene["canvas_size"]["width"], scene["canvas_size"]["height"]) + base = Image.new("RGBA", canvas_size, (245, 242, 236, 255)) + layout_options = scene.get("layout_options", {}) or {} + scene_type = str(layout_options.get("scene_type") or "scene") + + background_layer = Image.new("RGBA", canvas_size, (0, 0, 0, 0)) + background_draw = ImageDraw.Draw(background_layer, "RGBA") + for layer in sorted(scene.get("background_layers", []), key=lambda item: item.get("z_index", 0)): + color, alpha, radius = self._sd_upstream_background_color(str(layer.get("type") or "")) + background_draw.rounded_rectangle( + [layer["x"], layer["y"], layer["x"] + layer["width"], layer["y"] + layer["height"]], + radius=radius, + fill=(*color, alpha), + outline=None, + ) + background_layer = background_layer.filter(ImageFilter.GaussianBlur(radius=8 if scene_type == "scene" else 5)) + base.alpha_composite(background_layer) + + visible_objects = [obj for obj in scene.get("object_instances", []) if obj.get("visible", True) is not False] + multi_anchor_scene = len(visible_objects) > 1 + object_support_mask = Image.new("L", canvas_size, 0) + for obj in sorted(visible_objects, key=lambda item: item.get("z_index", 0)): + if obj.get("visible", True) is False: + continue + x0, y0, x1, y1 = self._scene_bbox(obj) + width = max(24, x1 - x0) + height = max(24, y1 - y0) + key = str(obj.get("asset_key") or obj.get("silhouette_key") or obj.get("concept") or "").strip().lower() + padding_ratio = 0.1 if scene_type == "scene" else 0.06 + if key in {"person", "human", "figure", "character"}: + padding_ratio = 0.045 if scene_type == "scene" else 0.035 + padding = max(6 if key in {"person", "human", "figure", "character"} else 8, int(min(width, height) * padding_ratio)) + raw_box = ( + max(0, x0 - padding), + max(0, y0 - padding), + min(canvas_size[0], x1 + padding), + min(canvas_size[1], y1 + padding), + ) + box = self._balanced_upstream_box( + raw_box, + canvas_size=canvas_size, + asset_key=str(obj.get("asset_key") or obj.get("silhouette_key") or obj.get("concept") or ""), + multi_anchor_scene=multi_anchor_scene, + ) + mask = Image.new("L", canvas_size, 0) + mask_draw = ImageDraw.Draw(mask) + self._draw_upstream_object_mass_mask(mask_draw, box, obj) + mask = self._apply_region_overrides_to_mask(mask, obj) + object_support_mask = ImageChops.lighter( + object_support_mask, + mask.filter(ImageFilter.MaxFilter(size=9)), + ) + tone, alpha, blur_radius = self._sd_upstream_object_style(obj, scene_type=scene_type) + if multi_anchor_scene: + alpha = max(alpha, 116) + blur_radius = max(6, blur_radius - 2) + if key in {"house", "home", "building"}: + tone = (128, 130, 138) + alpha = max(alpha, 144) + blur_radius = max(5, blur_radius - 2) + elif key in {"person", "human", "figure", "character"}: + tone = (126, 128, 136) + alpha = max(alpha, 130) + blur_radius = max(5, blur_radius - 3) + elif key in {"tree", "leaf", "plant", "bush"}: + alpha = max(alpha, 132) + self._apply_soft_mask(base, mask, tone, alpha, blur_radius) + + object_support_mask = object_support_mask.filter(ImageFilter.GaussianBlur(radius=4)) + outline_alpha = self._soft_mass_outline_mask(object_support_mask) + outline_layer = Image.new("RGBA", canvas_size, (104, 101, 96, 0)) + outline_layer.putalpha(outline_alpha.point(lambda px: min(255, int(px * 0.55)))) + base.alpha_composite(outline_layer) + + preserve_structural_lines = bool(layout_options.get("sd_upstream_preserve_structural_lines", False)) + if preserve_structural_lines: + guide_alpha = ImageChops.multiply( + self._line_alpha_mask(structural_sketch_image, gain=0.58, bias=-96), + object_support_mask, + ).filter(ImageFilter.GaussianBlur(radius=2.2)) + warm_guide = Image.new("RGBA", canvas_size, (116, 112, 108, 0)) + warm_guide.putalpha(guide_alpha) + base.alpha_composite(warm_guide) + return base.convert("RGB") + + def _draw_shape_recipe_mask( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + shape_recipe: Dict[str, Any], + value: int = 255, + ) -> bool: + parts = list((shape_recipe or {}).get("parts") or []) + if not parts: + return False + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + drawn = False + + for part in parts: + kind = str(part.get("kind") or "").lower() + fill_role = str(part.get("fill_role", "fill") or "fill").lower() + stroke_width = max(2, int(round(max(width, height) * float(part.get("stroke_width", 0.03) or 0.03)))) + + if kind == "rect" and fill_role not in {"none", "transparent"}: + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + rx = max(0, int(min(width, height) * float(part.get("rx", 0.0) or 0.0))) + draw.rounded_rectangle(rect, radius=rx, fill=value) + drawn = True + continue + + if kind == "ellipse" and fill_role not in {"none", "transparent"}: + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + draw.ellipse(rect, fill=value) + drawn = True + continue + + if kind == "polygon" and fill_role not in {"none", "transparent"}: + points = self._scaled_points(list(part.get("points") or []), box) + if points: + draw.polygon(points, fill=value) + drawn = True + continue + + if kind == "line": + start = ( + x0 + width * float(part.get("x1", 0.0)), + y0 + height * float(part.get("y1", 0.0)), + ) + end = ( + x0 + width * float(part.get("x2", 0.0)), + y0 + height * float(part.get("y2", 0.0)), + ) + draw.line([start, end], fill=value, width=stroke_width) + drawn = True + continue + + if kind in {"polyline", "path"}: + points = self._scaled_points(list(part.get("points") or []), box) + if len(points) >= 2: + draw.line(points, fill=value, width=stroke_width) + drawn = True + + return drawn + + def _draw_stroke_payload_mask( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + stroke_payload: List[List[List[float]]] | None, + value: int = 255, + stroke_render_profile: Dict[str, Any] | None = None, + ) -> bool: + strokes = [stroke for stroke in list(stroke_payload or []) if len(stroke) >= 2] + if not strokes: + return False + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + profile = stroke_render_profile if isinstance(stroke_render_profile, dict) else {} + min_width = float(profile.get("line_width_min", profile.get("min_width", 0.018)) or 0.018) + max_width = float(profile.get("line_width_max", profile.get("max_width", 0.04)) or 0.04) + for index, stroke in enumerate(strokes): + ratio = index / max(1, len(strokes) - 1) if len(strokes) > 1 else 0.0 + line_width = max(2, int(round(max(width, height) * (min_width + (max_width - min_width) * ratio)))) + points = [(x0 + width * float(px), y0 + height * float(py)) for px, py in stroke] + if len(points) >= 2: + draw.line(points, fill=value, width=line_width) + return True + + def _draw_object_mask(self, draw: ImageDraw, box: Tuple[int, int, int, int], obj: Dict[str, Any], value: int = 255) -> bool: + stroke_render_profile = obj.get("stroke_render_profile") if isinstance(obj.get("stroke_render_profile"), dict) else obj.get("stroke_style_profile") + if str(obj.get("render_representation") or "") == "stroke_native" or obj.get("stroke_payload"): + drew = self._draw_stroke_payload_mask( + draw, + box, + obj.get("stroke_payload") if isinstance(obj.get("stroke_payload"), list) else [], + value=value, + stroke_render_profile=stroke_render_profile if isinstance(stroke_render_profile, dict) else {}, + ) + if drew: + return True + return self._draw_shape_recipe_mask(draw, box, obj.get("shape_recipe") or {}, value=value) + + def _draw_upstream_object_mass_mask( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + obj: Dict[str, Any], + value: int = 255, + ) -> None: + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + key = str(obj.get("asset_key") or obj.get("silhouette_key") or obj.get("concept") or "generic_object").strip().lower() + + if key in {"person", "human", "figure", "character"}: + shoulder_y = y0 + height * 0.22 + hip_y = y0 + height * 0.58 + center_x = x0 + width * 0.5 + draw.ellipse([x0 + width * 0.38, y0 + height * 0.02, x0 + width * 0.62, y0 + height * 0.18], fill=value) + draw.rounded_rectangle( + [x0 + width * 0.43, y0 + height * 0.16, x0 + width * 0.57, y0 + height * 0.24], + radius=max(3, int(min(width, height) * 0.03)), + fill=value, + ) + draw.ellipse([x0 + width * 0.25, shoulder_y, x0 + width * 0.75, y0 + height * 0.48], fill=value) + draw.rounded_rectangle( + [x0 + width * 0.34, y0 + height * 0.24, x0 + width * 0.66, hip_y], + radius=max(6, int(min(width, height) * 0.08)), + fill=value, + ) + draw.polygon( + [ + (x0 + width * 0.28, y0 + height * 0.26), + (x0 + width * 0.18, y0 + height * 0.52), + (x0 + width * 0.24, y0 + height * 0.58), + (x0 + width * 0.38, y0 + height * 0.36), + ], + fill=value, + ) + draw.polygon( + [ + (x0 + width * 0.72, y0 + height * 0.26), + (x0 + width * 0.82, y0 + height * 0.52), + (x0 + width * 0.76, y0 + height * 0.58), + (x0 + width * 0.62, y0 + height * 0.36), + ], + fill=value, + ) + draw.polygon( + [ + (x0 + width * 0.38, hip_y), + (center_x - width * 0.04, y1), + (center_x, y1), + (center_x - width * 0.01, y0 + height * 0.72), + ], + fill=value, + ) + draw.polygon( + [ + (x0 + width * 0.62, hip_y), + (center_x + width * 0.04, y1), + (center_x, y1), + (center_x + width * 0.01, y0 + height * 0.72), + ], + fill=value, + ) + return + + if key in {"house", "home"}: + draw.polygon( + [ + (x0 + width * 0.5, y0 + height * 0.02), + (x0 + width * 0.16, y0 + height * 0.34), + (x1 - width * 0.16, y0 + height * 0.34), + ], + fill=value, + ) + draw.rounded_rectangle( + [x0 + width * 0.18, y0 + height * 0.28, x1 - width * 0.18, y1], + radius=max(8, int(min(width, height) * 0.1)), + fill=value, + ) + return + + if key in {"building", "tower"}: + draw.rounded_rectangle( + [x0 + width * 0.08, y0 + height * 0.04, x1 - width * 0.08, y1], + radius=max(8, int(min(width, height) * 0.08)), + fill=value, + ) + return + + if key in {"tree", "leaf", "plant", "bush"}: + draw.rounded_rectangle( + [x0 + width * 0.42, y0 + height * 0.54, x0 + width * 0.58, y1], + radius=max(4, int(min(width, height) * 0.05)), + fill=value, + ) + draw.ellipse([x0 + width * 0.06, y0 + height * 0.18, x0 + width * 0.54, y0 + height * 0.76], fill=value) + draw.ellipse([x0 + width * 0.28, y0, x1 - width * 0.12, y0 + height * 0.68], fill=value) + draw.ellipse([x0 + width * 0.48, y0 + height * 0.2, x1, y0 + height * 0.82], fill=value) + return + + if width >= height * 1.25: + draw.rounded_rectangle( + [x0, y0 + height * 0.12, x1, y1 - height * 0.12], + radius=max(8, int(min(width, height) * 0.12)), + fill=value, + ) + return + + draw.rounded_rectangle( + [x0 + width * 0.08, y0 + height * 0.04, x1 - width * 0.08, y1 - height * 0.04], + radius=max(10, int(min(width, height) * 0.18)), + fill=value, + ) + + def _draw_asset_symbol_mask( + self, + draw: ImageDraw, + box: Tuple[int, int, int, int], + asset_key: str, + value: int = 255, + ) -> None: + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + key = str(asset_key or "generic_object") + + if key == "sun": + draw.ellipse([x0, y0, x1, y1], fill=value) + return + if key == "cloud": + draw.ellipse([x0, y0 + height * 0.2, x0 + width * 0.38, y1], fill=value) + draw.ellipse([x0 + width * 0.18, y0, x0 + width * 0.72, y0 + height * 0.78], fill=value) + draw.ellipse([x0 + width * 0.5, y0 + height * 0.16, x1, y0 + height * 0.9], fill=value) + return + if key in {"building", "tower"}: + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(8, int(min(width, height) * 0.06)), fill=value) + return + if key == "house": + draw.polygon([(x0 + width * 0.5, y0), (x0, y0 + height * 0.34), (x1, y0 + height * 0.34)], fill=value) + draw.rounded_rectangle([x0 + width * 0.12, y0 + height * 0.3, x1 - width * 0.12, y1], radius=max(8, int(min(width, height) * 0.06)), fill=value) + return + if key in {"tree", "leaf"}: + draw.rectangle([x0 + width * 0.42, y0 + height * 0.56, x0 + width * 0.58, y1], fill=value) + draw.ellipse([x0 + width * 0.08, y0, x1 - width * 0.08, y0 + height * 0.72], fill=value) + return + if key == "person": + draw.ellipse([x0 + width * 0.32, y0, x0 + width * 0.68, y0 + height * 0.28], fill=value) + draw.rounded_rectangle([x0 + width * 0.34, y0 + height * 0.22, x0 + width * 0.66, y1], radius=max(6, int(min(width, height) * 0.08)), fill=value) + return + if key == "car": + draw.rounded_rectangle([x0 + width * 0.08, y0 + height * 0.36, x1 - width * 0.08, y0 + height * 0.78], radius=max(8, int(min(width, height) * 0.08)), fill=value) + draw.polygon([(x0 + width * 0.24, y0 + height * 0.36), (x0 + width * 0.42, y0 + height * 0.12), (x0 + width * 0.72, y0 + height * 0.12), (x0 + width * 0.84, y0 + height * 0.36)], fill=value) + return + if key in {"window", "door", "generic_panel", "module"}: + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(6, int(min(width, height) * 0.08)), fill=value) + return + draw.rounded_rectangle( + [x0, y0, x1, y1], + radius=max(10, int(min(width, height) * 0.16)), + fill=value, + ) + + def _draw_object_region_mask( + self, + draw: ImageDraw, + obj: Dict[str, Any], + region: Dict[str, Any], + value: int = 255, + ) -> None: + box = self._region_box_for_object(obj, region) + shape = str(region.get("shape") or "rect") + if shape == "ellipse": + draw.ellipse(box, fill=value) + return + draw.rounded_rectangle( + box, + radius=max(4, int(min(box[2] - box[0], box[3] - box[1]) * 0.12)), + fill=value, + ) + + def _apply_region_overrides_to_mask(self, mask: Image.Image, obj: Dict[str, Any]) -> Image.Image: + overrides = obj.get("region_overrides") if isinstance(obj.get("region_overrides"), dict) else {} + if not overrides: + return mask + adjusted = mask.copy() + for region in obj.get("region_masks", []) or []: + if not isinstance(region, dict): + continue + region_id = str(region.get("id") or "") + action = str((overrides.get(region_id) or {}).get("action") or "").strip().lower() + if not action: + continue + region_mask = Image.new("L", adjusted.size, 0) + region_draw = ImageDraw.Draw(region_mask) + self._draw_object_region_mask(region_draw, obj, region, value=255) + if action == "hide": + adjusted.paste(0, mask=region_mask) + continue + if action == "replace": + subtract = Image.new("L", adjusted.size, 0) + subtract.paste(120, mask=region_mask) + adjusted = ImageChops.subtract(adjusted, subtract) + continue + if action == "weaken": + subtract = Image.new("L", adjusted.size, 0) + subtract.paste(96, mask=region_mask) + adjusted = ImageChops.subtract(adjusted, subtract) + continue + if action == "emphasize": + boost = Image.new("L", adjusted.size, 0) + boost.paste(84, mask=region_mask) + adjusted = ImageChops.add(adjusted, boost) + return adjusted + + def _color_from_index(self, index: int) -> Tuple[int, int, int]: + return ( + 32 + (index * 73) % 192, + 36 + (index * 91) % 184, + 44 + (index * 57) % 176, + ) + + def _render_hit_map_image(self, scene_spec: Dict[str, Any]) -> Tuple[Image.Image, List[Dict[str, Any]]]: + scene = normalize_scene_spec_v2(scene_spec) + canvas_size = (scene["canvas_size"]["width"], scene["canvas_size"]["height"]) + image = Image.new("RGB", canvas_size, (0, 0, 0)) + draw = ImageDraw.Draw(image) + legend: List[Dict[str, Any]] = [] + color_index = 1 + + for obj in sorted(scene.get("object_instances", []), key=lambda item: item.get("z_index", 0)): + if obj.get("visible", True) is False: + continue + box = self._scene_bbox(obj) + color = self._color_from_index(color_index) + color_index += 1 + if not self._draw_object_mask(draw, box, obj, value=color): + self._draw_asset_symbol_mask(draw, box, str(obj.get("asset_key") or obj.get("silhouette_key") or "generic_object"), value=color) + legend.append( + { + "object_id": obj.get("id"), + "region_id": "", + "concept": obj.get("concept", ""), + "rgb": color, + } + ) + for region in obj.get("region_masks", []) or []: + if not isinstance(region, dict): + continue + region_color = self._color_from_index(color_index) + color_index += 1 + self._draw_object_region_mask(draw, obj, region, value=region_color) + legend.append( + { + "object_id": obj.get("id"), + "region_id": region.get("id", ""), + "concept": obj.get("concept", ""), + "label": region.get("label", ""), + "rgb": region_color, + } + ) + return image, legend + + def _control_layer_color(self, layer: Dict[str, Any], control_palette: Dict[str, Tuple[int, int, int]]) -> Tuple[int, int, int]: + layer_type = str(layer.get("type") or "layer") + return control_palette.get(layer_type, control_palette.get("wall", (226, 224, 220))) + + def _control_object_style( + self, + obj: Dict[str, Any], + control_palette: Dict[str, Tuple[int, int, int]], + scene_type: str = "scene", + ) -> Tuple[Tuple[int, int, int], int, int]: + visual_family = str(obj.get("visual_family") or "scene_object") + role = str(obj.get("role") or "") + depth_band = str(obj.get("depth_band") or "") + source = str(obj.get("source") or "") + color = control_palette.get(visual_family, control_palette["scene_object"]) + if role in {"subject", "focus", "core_subject"}: + color = control_palette["subject"] + elif source == "user": + color = control_palette["user"] + + alpha = 82 + if depth_band == "foreground": + alpha = 118 + elif depth_band == "midground": + alpha = 98 + elif depth_band == "background": + alpha = 74 + if role in {"subject", "focus", "core_subject"}: + alpha += 24 + if source == "user": + alpha += 10 + blur = 18 + if depth_band == "foreground": + blur = 14 + elif depth_band == "background": + blur = 22 + if scene_type == "process": + blur = max(6, blur - 8) + alpha = min(196, alpha + 8) + elif scene_type == "schematic": + blur = max(4, blur - 10) + alpha = min(184, alpha + 4) + return color, max(40, min(182, alpha)), blur + + def _apply_soft_mask( + self, + base: Image.Image, + mask: Image.Image, + color: Tuple[int, int, int], + alpha: int, + blur_radius: int, + ) -> None: + if blur_radius > 0: + soft_mask = mask.filter(ImageFilter.GaussianBlur(radius=blur_radius)) + else: + soft_mask = mask + soft_alpha = soft_mask.point(lambda px: min(255, int(px * alpha / 255))) + soft_layer = Image.new("RGBA", base.size, (*color, 0)) + soft_layer.putalpha(soft_alpha) + base.alpha_composite(soft_layer) + + inner_alpha = max(0, int(alpha * 0.42)) + if inner_alpha > 0: + inner_mask = mask.point(lambda px: min(255, int(px * inner_alpha / 255))) + inner_layer = Image.new("RGBA", base.size, (*color, 0)) + inner_layer.putalpha(inner_mask) + base.alpha_composite(inner_layer) + + def _draw_control_connectors( + self, + base: Image.Image, + scene: Dict[str, Any], + control_palette: Dict[str, Tuple[int, int, int]], + ) -> None: + layout_options = scene.get("layout_options", {}) or {} + scene_type = str(layout_options.get("scene_type") or "scene") + if scene_type == "scene": + return + connector_layer = Image.new("RGBA", base.size, (0, 0, 0, 0)) + draw = ImageDraw.Draw(connector_layer, "RGBA") + objects_by_id = {item["id"]: item for item in scene.get("object_instances", []) if item.get("id")} + alpha = 56 if scene_type == "process" else 72 + line_width = 8 + blur_radius = 5 + if scene_type == "process": + alpha = 64 + line_width = 6 + blur_radius = 3 + elif scene_type == "schematic": + alpha = 78 + line_width = 6 + blur_radius = 2 + line_color = (*control_palette["connector"], alpha) + for connector in scene.get("connectors", []): + if not connector.get("visible", True): + continue + from_obj = objects_by_id.get(connector.get("from_id")) + to_obj = objects_by_id.get(connector.get("to_id")) + if not from_obj or not to_obj: + continue + start, end = self._connector_points_for_scene(from_obj, to_obj) + draw.line([start, end], fill=line_color, width=line_width) + connector_layer = connector_layer.filter(ImageFilter.GaussianBlur(radius=blur_radius)) + base.alpha_composite(connector_layer) + + def _render_external_control_image( + self, + scene_spec: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> Image.Image: + scene = normalize_scene_spec_v2(scene_spec) + canvas_size = (scene["canvas_size"]["width"], scene["canvas_size"]["height"]) + control_palette = self._render_control_palette() + base = Image.new("RGBA", canvas_size, (*control_palette["background"], 255)) + layout_options = scene.get("layout_options", {}) or {} + scene_type = str(layout_options.get("scene_type") or "scene") + + background_layer = Image.new("RGBA", canvas_size, (0, 0, 0, 0)) + background_draw = ImageDraw.Draw(background_layer, "RGBA") + for layer in sorted(scene.get("background_layers", []), key=lambda item: item.get("z_index", 0)): + fill = self._control_layer_color(layer, control_palette) + layer_type = str(layer.get("type") or "") + alpha = 98 if layer_type in {"ground", "road", "board", "water"} else 82 + radius = 28 + if scene_type == "process": + if layer_type == "process_band": + alpha = 26 + else: + alpha = min(alpha, 34) + radius = 18 + elif scene_type == "schematic": + alpha = 18 if layer_type == "board" else 14 + radius = 12 + background_draw.rounded_rectangle( + [layer["x"], layer["y"], layer["x"] + layer["width"], layer["y"] + layer["height"]], + radius=radius, + fill=(*fill, alpha), + outline=None, + ) + background_blur = 18 + if scene_type == "process": + background_blur = 8 + elif scene_type == "schematic": + background_blur = 4 + background_layer = background_layer.filter(ImageFilter.GaussianBlur(radius=background_blur)) + base.alpha_composite(background_layer) + + for obj in sorted(scene.get("object_instances", []), key=lambda item: item.get("z_index", 0)): + if obj.get("visible", True) is False: + continue + x0, y0, x1, y1 = self._scene_bbox(obj) + width = max(24, x1 - x0) + height = max(24, y1 - y0) + padding_scale = 0.16 + if scene_type == "process": + padding_scale = 0.12 + elif scene_type == "schematic": + padding_scale = 0.08 + padding = max(12, int(min(width, height) * padding_scale)) + box = ( + max(0, x0 - padding), + max(0, y0 - padding), + min(canvas_size[0], x1 + padding), + min(canvas_size[1], y1 + padding), + ) + mask = Image.new("L", canvas_size, 0) + mask_draw = ImageDraw.Draw(mask) + drew = self._draw_object_mask(mask_draw, box, obj) + if not drew: + self._draw_asset_symbol_mask( + mask_draw, + box, + str(obj.get("asset_key") or obj.get("silhouette_key") or "generic_object"), + ) + mask = self._apply_region_overrides_to_mask(mask, obj) + color, alpha, blur_radius = self._control_object_style(obj, control_palette, scene_type=scene_type) + self._apply_soft_mask(base, mask, color, alpha, blur_radius) + + role = str(obj.get("role") or "") + if role in {"subject", "focus", "core_subject"}: + halo = Image.new("L", canvas_size, 0) + halo_draw = ImageDraw.Draw(halo) + halo_pad_x = max(18, int(width * 0.22)) + halo_pad_y = max(18, int(height * 0.22)) + halo_draw.ellipse( + [ + max(0, x0 - halo_pad_x), + max(0, y0 - halo_pad_y), + min(canvas_size[0], x1 + halo_pad_x), + min(canvas_size[1], y1 + halo_pad_y), + ], + fill=255, + ) + self._apply_soft_mask(base, halo, control_palette["subject"], min(74, alpha // 2), 26) + + self._draw_control_connectors(base, scene, control_palette) + return base.convert("RGB") + + def _get_connection_points(self, from_pos: Dict, to_pos: Dict) -> Tuple[Tuple[float, float], Tuple[float, float]]: + start = (from_pos["x"] + from_pos["width"], from_pos["y"] + from_pos["height"] // 2) + end = (to_pos["x"], to_pos["y"] + to_pos["height"] // 2) + return start, end + def _calculate_layout(self, path: 'MazePath', canvas_size: Tuple[int, int] = (1024, 768), layout_options: Dict[str, Any] | None = None) -> Dict: + """ + 基于推理路径的节点和关系自动计算布局 + :param path: Tri-Maze 推理路径 + :param canvas_size: 画布大小 + :return: 布局信息,包含每个节点的位置、大小、权重 + """ + layout_options = layout_options or {} + width, height = canvas_size + node_count = len(path.nodes) + if node_count == 0: + return { + "canvas_size": canvas_size, + "positions": [], + "connections": [], + "path": path, + "layout_options": layout_options, + } + + node_scale = max(0.4, float(layout_options.get("node_scale", 1.0))) + spacing_scale = max(0.6, float(layout_options.get("spacing_scale", 1.0))) + vertical_offset = int(layout_options.get("vertical_offset", 0)) + + weights = [] + for i, node in enumerate(path.nodes): + if i < len(path.edges): + resistance = path.edges[i].resistance + else: + resistance = 0.0 + weight = 1.0 - resistance + weights.append(max(0.3, weight)) + + total_weight = sum(weights) + normalized_weights = [w / total_weight for w in weights] + + positions = [] + margin_x = 100 + available_width = max(200, width - 2 * margin_x) + step_count = max(1, node_count - 1) + base_spacing = available_width / step_count if node_count > 1 else 0 + spacing = base_spacing * spacing_scale + total_span = spacing * (node_count - 1) + start_x = (width - total_span) / 2 if node_count > 1 else width / 2 + + for i in range(node_count): + node_width = max(72, min(240, 100 * normalized_weights[i] * 2 * node_scale)) + x = start_x + (spacing * i) - node_width / 2 if node_count > 1 else (width - node_width) / 2 + y = height // 2 - (node_width * 0.8) / 2 + vertical_offset + positions.append({ + "x": int(x), + "y": int(y), + "width": int(node_width), + "height": int(node_width * 0.8), + "weight": normalized_weights[i], + "node": path.nodes[i] + }) + + connections = [] + for i in range(len(path.edges)): + from_pos = positions[i] + to_pos = positions[i + 1] + start_point, end_point = self._get_connection_points(from_pos, to_pos) + connections.append({ + "from": from_pos, + "to": to_pos, + "edge": path.edges[i], + "start_point": start_point, + "end_point": end_point + }) + + return { + "canvas_size": canvas_size, + "positions": positions, + "connections": connections, + "path": path, + "layout_options": layout_options, + } + + def build_scene_spec( + self, + path: 'MazePath | None', + canvas_size: Tuple[int, int] = (1024, 768), + sketch_options: Dict[str, Any] | None = None, + scene_context: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + """将推理路径转换为可编辑的 SceneSpec。""" + sketch_options = sketch_options or {} + scene_context = scene_context or {} + if scene_context: + best_path_concepts = scene_context.get("best_path_concepts") or [ + node.concept for node in getattr(path, "nodes", []) if getattr(node, "concept", "") + ] + return compose_semantic_scene_spec( + query=str(scene_context.get("query", "") or ""), + understanding_result=scene_context.get("understanding_result"), + extraction_result=scene_context.get("extraction_result"), + answer_bundle=scene_context.get("answer_bundle"), + best_path_concepts=best_path_concepts, + canvas_size=canvas_size, + sketch_options=sketch_options, + ) + + if path is None: + return normalize_scene_spec_v2( + { + "version": 2, + "canvas_size": {"width": canvas_size[0], "height": canvas_size[1]}, + "layout_options": { + "scene_type": "scene", + "composition_mode": "scene", + "sketch_style": sketch_options.get("sketch_style", "scribble_line"), + "show_grid": bool(sketch_options.get("show_grid", True)), + "show_labels": bool(sketch_options.get("show_labels", False)), + "show_guides": bool(sketch_options.get("show_guides", False)), + }, + "background_layers": [], + "object_instances": [], + "attachments": [], + "connectors": [], + "render_hints": {}, + "concept_order": [], + }, + sketch_options, + ) + + layout = self._calculate_layout(path, canvas_size, sketch_options) + positions = layout["positions"] + nodes = [] + relations = [] + for index, pos in enumerate(positions): + node_id = f"node_{index + 1}" + nodes.append({ + "id": node_id, + "concept": pos["node"].concept, + "x": pos["x"], + "y": pos["y"], + "width": pos["width"], + "height": pos["height"], + "weight": round(pos["weight"], 4), + "role": "core" if pos["weight"] >= 0.2 else "secondary", + }) + for index, edge in enumerate(path.edges): + relations.append({ + "id": f"edge_{index + 1}", + "from_id": nodes[index]["id"], + "to_id": nodes[index + 1]["id"], + "from": nodes[index]["concept"], + "to": nodes[index + 1]["concept"], + "relation": edge.relation, + "resistance": edge.resistance, + }) + legacy_scene = { + "canvas_size": {"width": canvas_size[0], "height": canvas_size[1]}, + "layout_options": { + "node_scale": float(sketch_options.get("node_scale", 1.0)), + "spacing_scale": float(sketch_options.get("spacing_scale", 1.0)), + "sketch_style": sketch_options.get("sketch_style", "line_art"), + "show_grid": bool(sketch_options.get("show_grid", True)), + "show_labels": bool(sketch_options.get("show_labels", True)), + "show_guides": bool(sketch_options.get("show_guides", True)), + }, + "concept_order": [node["concept"] for node in nodes], + "nodes": nodes, + "relations": relations, + } + return normalize_scene_spec_v2(legacy_scene, sketch_options) + + def _normalize_scene_spec(self, scene_spec: Dict[str, Any], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + return normalize_scene_spec_v2(scene_spec, sketch_options) + + def _scene_node_shape(self, concept: str) -> str: + text = str(concept or "") + if any(keyword in text for keyword in {"圆形", "LED", "细胞"}): + return "ellipse" + if any(keyword in text for keyword in {"三角形", "箭头", "二极管"}): + return "triangle" + return "rect" + + def _render_scene_spec_relation(self, draw: ImageDraw, scene_spec: Dict[str, Any], relation: Dict[str, Any], palette: Dict[str, Tuple[int, int, int]], show_labels: bool = True): + nodes = {node["id"]: node for node in scene_spec.get("nodes", [])} + from_node = nodes.get(relation.get("from_id")) + to_node = nodes.get(relation.get("to_id")) + if not from_node or not to_node: + return + start, end = self._get_connection_points(from_node, to_node) + relation_text = str(relation.get("relation", "连接")) + if relation_text == "并联": + draw.line([start, (start[0], start[1] - 28), (end[0], end[1] - 28), end], fill=palette["line"], width=2) + draw.line([start, (start[0], start[1] + 28), (end[0], end[1] + 28), end], fill=palette["line"], width=2) + elif relation_text == "包含": + self._draw_dashed_rectangle( + draw, + ( + from_node["x"] - 6, + from_node["y"] - 6, + from_node["x"] + from_node["width"] + 6, + from_node["y"] + from_node["height"] + 6, + ), + palette["line"], + width=1, + ) + elif relation_text in {"控制", "产生", "导致", "指向", "驱动"}: + self._draw_arrow_line(draw, start, end, fill=palette["accent"], width=2) + else: + draw.line([start, end], fill=palette["line"], width=2) + if show_labels: + mid_x = int((start[0] + end[0]) / 2) + mid_y = int((start[1] + end[1]) / 2 - 18) + draw.text((mid_x, mid_y), relation_text, fill=palette["text"], font=self.font) + + def render_scene_spec_preview(self, scene_spec: Dict[str, Any], sketch_options: Dict[str, Any] | None = None, title: str | None = None) -> Dict[str, Any]: + """根据 SceneSpec 渲染语义草图与低清预演。""" + scene = self._normalize_scene_spec(scene_spec, sketch_options) + layout_options = scene.get("layout_options", {}) + variant_payload = scene_shape_variant_payload(scene) + backend_status = summarize_scene_backend(scene) + sketch_style = layout_options.get("sketch_style", "line_art") + generator_style = layout_options.get("generator_style") or sketch_style + scene_generation_backend = str(layout_options.get("scene_generation_backend") or "unified_scene_v3") + concept_order = scene.get("concept_order", []) or [ + obj.get("concept", "") for obj in scene.get("object_instances", []) if obj.get("concept") + ] + title = title or ( + f"Tri-Maze 语义草图 · {' · '.join(concept_order[:4])}" if concept_order else "Tri-Maze 语义草图" + ) + palette = self._build_preview_palette(sketch_style) + low_palette = self._build_low_preview_palette(sketch_style) + rich_palette = self._build_rich_preview_palette(str(generator_style)) + base_sketch_image = self._render_semantic_scene_image( + scene, + palette, + title, + filled=False, + include_title=False, + view_mode="rough", + ) + structural_sketch_image, annotation_bundle = self.whole_scene_sketch_generator.render_scene( + scene, + palette, + title, + annotated=False, + show_regions=False, + include_title=False, + ) + annotated_sketch_image, _ = self.whole_scene_sketch_generator.render_scene( + scene, + palette, + title, + annotated=True, + show_regions=False, + include_title=False, + ) + region_overlay_image, _ = self.whole_scene_sketch_generator.render_scene( + scene, + palette, + title, + annotated=True, + show_regions=True, + include_title=False, + ) + low_preview_image = self._render_semantic_scene_image( + scene, + low_palette, + "", + filled=True, + include_title=False, + force_show_labels=False, + force_show_grid=False, + force_show_guides=False, + view_mode="structure", + ) + render_control_image = self._render_external_control_image(scene, low_palette) + sd_upstream_control_image = self._render_sd_upstream_control_image( + scene, + structural_sketch_image=structural_sketch_image, + ) + hit_map_image, hit_map_legend = self._render_hit_map_image(scene) + scene.setdefault("render_hints", {}) + scene["render_hints"]["layout_runtime"] = json.loads(json.dumps( + scene["render_hints"].get("layout_runtime") + or layout_options.get("layout_model_status") + or {}, + ensure_ascii=False, + )) + scene["render_hints"]["annotation_bundle"] = annotation_bundle + scene["render_hints"]["structural_generator"] = { + "id": str((annotation_bundle or {}).get("generator_id") or "whole_scene_structural_v2"), + "style_variant": str(generator_style), + "synchronized_annotations": True, + "second_stage": (annotation_bundle or {}).get("second_stage_generator", {}), + } + scene["layout_options"]["generator_style"] = str(generator_style) + scene["layout_options"]["scene_generation_backend"] = scene_generation_backend + + sketch_hash = hash(json.dumps({"scene": scene, "title": title}, ensure_ascii=False, sort_keys=True)) + image_path = os.path.join(self.output_dir, f"structural_sketch_{sketch_hash}.png") + base_sketch_path = os.path.join(self.output_dir, f"base_sketch_{sketch_hash}.png") + annotated_sketch_path = os.path.join(self.output_dir, f"annotated_sketch_{sketch_hash}.png") + region_overlay_path = os.path.join(self.output_dir, f"region_overlay_{sketch_hash}.png") + low_preview_path = os.path.join(self.output_dir, f"low_preview_{sketch_hash}.png") + rich_preview_path = os.path.join(self.output_dir, f"rich_preview_{sketch_hash}.png") + render_control_path = os.path.join(self.output_dir, f"render_control_{sketch_hash}.png") + sd_upstream_control_path = os.path.join(self.output_dir, f"sd_upstream_control_{sketch_hash}.png") + hit_map_path = os.path.join(self.output_dir, f"hit_map_{sketch_hash}.png") + annotation_bundle_path = os.path.join(self.output_dir, f"scene_annotation_{sketch_hash}.json") + if scene_generation_backend == "legacy_object_library_v2": + rich_preview_image, rich_preview_meta = self.whole_scene_sketch_generator.render_scene( + scene, + rich_palette, + title, + annotated=False, + show_regions=False, + include_title=False, + view_mode="rich_preview", + ) + else: + rich_preview_image, rich_preview_meta = self.unified_scene_generator.render_scene( + scene, + rich_palette, + title, + ) + scene["render_hints"]["scene_preview_generation"] = rich_preview_meta + base_sketch_image.save(base_sketch_path) + structural_sketch_image.save(image_path) + annotated_sketch_image.save(annotated_sketch_path) + region_overlay_image.save(region_overlay_path) + low_preview_image.save(low_preview_path) + rich_preview_image.save(rich_preview_path) + render_control_image.save(render_control_path) + sd_upstream_control_image.save(sd_upstream_control_path) + hit_map_image.save(hit_map_path) + with open(annotation_bundle_path, "w", encoding="utf-8") as handle: + json.dump(annotation_bundle, handle, ensure_ascii=False, indent=2) + sketch_bundle = { + "base_sketch": base_sketch_path, + "structural_sketch": image_path, + "annotated_sketch": annotated_sketch_path, + "region_overlay": region_overlay_path, + "low_preview": low_preview_path, + "rich_preview": rich_preview_path, + "sd_upstream_control": sd_upstream_control_path, + "hit_map": hit_map_path, + "annotation_bundle": annotation_bundle_path, + "scene_preview_generation": rich_preview_meta, + } + scene["render_hints"]["sd_upstream_control_path"] = sd_upstream_control_path + return { + "success": True, + "type": "control_preview", + "image_path": image_path, + "base_sketch_path": base_sketch_path, + "annotated_sketch_path": annotated_sketch_path, + "region_overlay_path": region_overlay_path, + "low_preview_path": low_preview_path, + "rich_preview_path": rich_preview_path, + "render_control_path": render_control_path, + "sd_upstream_control_path": sd_upstream_control_path, + "hit_map_path": hit_map_path, + "annotation_bundle_path": annotation_bundle_path, + "save_path": image_path, + "scene_spec": scene, + "scene_spec_version": scene.get("version", 2), + "composition_mode": layout_options.get("composition_mode", layout_options.get("scene_type", "scene")), + "editor_palette": build_editor_asset_library() if "build_editor_asset_library" in globals() else [], + "sketch_backend_status": backend_status, + "available_shape_variants": variant_payload.get("available_shape_variants", {}), + "shape_variant_id": variant_payload.get("shape_variant_id", {}), + "shape_recipe_source": variant_payload.get("shape_recipe_source", {}), + "render_representation": variant_payload.get("render_representation", {}), + "stroke_variant_id": variant_payload.get("stroke_variant_id", {}), + "stroke_payload_source": variant_payload.get("stroke_payload_source", {}), + "annotation_bundle": annotation_bundle, + "scene_preview_generation": rich_preview_meta, + "overlay_defaults": { + "show_labels": bool(layout_options.get("show_labels", False)), + "show_grid": bool(layout_options.get("show_grid", True)), + "show_guides": bool(layout_options.get("show_guides", False)), + "view_mode": layout_options.get("sketch_view_mode", "structure"), + "annotation_level": layout_options.get("annotation_level", "light"), + }, + "sketch_bundle": sketch_bundle, + "hit_map_legend": hit_map_legend, + "description": "Tri-Maze 整图结构草图(同步标注)、人类可读整图预览与低清预演,可作为后续图片渲染的统一结构约束", + "sketch_options": scene["layout_options"], + } + + async def generate_control_preview( + self, + path: 'MazePath | None', + canvas_size: Tuple[int, int] = (1024, 768), + sketch_options: Dict[str, Any] | None = None, + scene_context: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + """生成控制草图,不依赖外部图片 API。""" + scene_spec = self.build_scene_spec( + path, + canvas_size=canvas_size, + sketch_options=sketch_options, + scene_context=scene_context, + ) + hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec, dict) else {} + title_core = hints.get("scene_summary") or " · ".join(scene_spec.get("concept_order", [])[:4]) + title = f"Tri-Maze 语义草图 · {title_core}" if title_core else "Tri-Maze 语义草图" + return self.render_scene_spec_preview(scene_spec, sketch_options=sketch_options, title=title) + + def _render_resistor(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染电阻""" + color = color or self.color_map["棕色"] + # 主体 + draw.rectangle([x, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + # 引脚 + draw.line([(x - 20, y + height//2), (x, y + height//2)], fill=self.color_map["灰色"], width=3) + draw.line([(x + width, y + height//2), (x + width + 20, y + height//2)], fill=self.color_map["灰色"], width=3) + # 色环 + ring_width = width // 5 + for i in range(4): + ring_color = [self.color_map["棕色"], self.color_map["黑色"], self.color_map["红色"], self.color_map["金色"]][i] + draw.rectangle([x + i*ring_width, y, x + (i+1)*ring_width, y + height], fill=ring_color) + + def _render_led(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染LED""" + color = color or self.color_map["红色"] + # 主体 + draw.ellipse([x, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + # 正极 + draw.line([(x + width//2, y + height), (x + width//2, y + height + 20)], fill=self.color_map["灰色"], width=3) + # 负极 + draw.line([(x + width//4, y + height), (x + width//4, y + height + 15)], fill=self.color_map["灰色"], width=3) + # 发光效果 + glow_color = (min(255, color[0] + 100), min(255, color[1] + 100), min(255, color[2] + 100)) + draw.ellipse([x-10, y-10, x + width + 10, y + height + 10], outline=glow_color, width=3) + + def _render_arduino(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染Arduino开发板""" + color = color or self.color_map["蓝色"] + # 主板 + draw.rectangle([x, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + # USB口 + draw.rectangle([x + 10, y + height//2 - 10, x + 30, y + height//2 + 10], fill=self.color_map["灰色"], outline=self.color_map["黑色"]) + # 引脚 + for i in range(10): + draw.rectangle([x + width - 5, y + 10 + i*15, x + width + 5, y + 20 + i*15], fill=self.color_map["金色"]) + # 文字 + draw.text((x + width//2 - 30, y + height//2 - 10), "Arduino", fill=self.color_map["白色"], font=self.font) + + def _render_battery(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染电源/电池""" + color = color or self.color_map["黑色"] + # 主体 + draw.rectangle([x, y, x + width, y + height], fill=self.color_map["灰色"], outline=color, width=2) + # 正极 + draw.rectangle([x + width, y + height//3, x + width + 15, y + height*2//3], fill=self.color_map["红色"]) + # 负极 + draw.rectangle([x -15, y + height//3, x, y + height*2//3], fill=self.color_map["黑色"]) + # 正负极符号 + draw.text((x + width + 20, y + height//2 - 10), "+", fill=self.color_map["红色"], font=self.font) + draw.text((x - 35, y + height//2 - 10), "-", fill=self.color_map["黑色"], font=self.font) + + def _render_ground(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染接地符号""" + color = color or self.color_map["黑色"] + draw.line([(x + width//2, y), (x + width//2, y + height//2)], fill=color, width=3) + draw.line([(x, y + height//2), (x + width, y + height//2)], fill=color, width=3) + draw.line([(x + width*0.25, y + height*0.7), (x + width*0.75, y + height*0.7)], fill=color, width=3) + draw.line([(x + width*0.4, y + height*0.9), (x + width*0.6, y + height*0.9)], fill=color, width=3) + + def _render_capacitor(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染电容""" + color = color or self.color_map["灰色"] + # 两个极板 + draw.rectangle([x, y, x + width//3, y + height], fill=color, outline=self.color_map["黑色"], width=2) + draw.rectangle([x + width*2//3, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + # 引脚 + draw.line([(x + width//6, y - 20), (x + width//6, y)], fill=self.color_map["灰色"], width=3) + draw.line([(x + width*5//6, y - 20), (x + width*5//6, y)], fill=self.color_map["灰色"], width=3) + draw.line([(x + width//6, y + height), (x + width//6, y + height + 20)], fill=self.color_map["灰色"], width=3) + draw.line([(x + width*5//6, y + height), (x + width*5//6, y + height + 20)], fill=self.color_map["灰色"], width=3) + + def _render_diode(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染二极管""" + color = color or self.color_map["黑色"] + # 三角形 + points = [ + (x, y + height//2), + (x + width*0.7, y), + (x + width*0.7, y + height) + ] + draw.polygon(points, fill=self.color_map["灰色"], outline=color, width=2) + # 竖线 + draw.line([(x + width*0.7, y), (x + width*0.7, y + height)], fill=color, width=3) + # 引脚 + draw.line([(x - 20, y + height//2), (x, y + height//2)], fill=self.color_map["灰色"], width=3) + draw.line([(x + width, y + height//2), (x + width + 20, y + height//2)], fill=self.color_map["灰色"], width=3) + + def _render_transistor(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染三极管""" + color = color or self.color_map["黑色"] + # 主体 + self._draw_circle(draw, (x + width//2, y + height//2), width//2, fill=self.color_map["灰色"], outline=color, width=2) + # 三个引脚 + draw.line([(x + width//2, y - 20), (x + width//2, y)], fill=self.color_map["灰色"], width=3) # 基极 + draw.line([(x - 20, y + height*0.8), (x, y + height*0.8)], fill=self.color_map["灰色"], width=3) # 发射极 + draw.line([(x + width, y + height*0.2), (x + width + 20, y + height*0.2)], fill=self.color_map["灰色"], width=3) # 集电极 + + def _render_rectangle(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染矩形""" + color = color or self.color_map["蓝色"] + draw.rectangle([x, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + + def _render_circle(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染圆形""" + color = color or self.color_map["红色"] + draw.ellipse([x, y, x + width, y + height], fill=color, outline=self.color_map["黑色"], width=2) + + def _render_triangle(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染三角形""" + color = color or self.color_map["黄色"] + points = [(x + width//2, y), (x, y + height), (x + width, y + height)] + draw.polygon(points, fill=color, outline=self.color_map["黑色"], width=2) + + def _render_arrow(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染箭头""" + color = color or self.color_map["黑色"] + # 箭身 + draw.line([(x, y + height//2), (x + width*0.7, y + height//2)], fill=color, width=3) + # 箭头 + points = [ + (x + width*0.7, y), + (x + width, y + height//2), + (x + width*0.7, y + height) + ] + draw.polygon(points, fill=color) + + def _render_cat(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染猫""" + color = color or self.color_map["橙色"] + # 身体 + draw.ellipse([x + width*0.2, y + height*0.3, x + width*0.8, y + height*0.9], fill=color, outline=self.color_map["黑色"], width=2) + # 头 + draw.ellipse([x + width*0.3, y, x + width*0.7, y + height*0.4], fill=color, outline=self.color_map["黑色"], width=2) + # 耳朵 + draw.polygon([(x + width*0.3, y), (x + width*0.4, y + height*0.1), (x + width*0.2, y + height*0.2)], fill=color, outline=self.color_map["黑色"]) + draw.polygon([(x + width*0.7, y), (x + width*0.6, y + height*0.1), (x + width*0.8, y + height*0.2)], fill=color, outline=self.color_map["黑色"]) + # 眼睛 + self._draw_circle(draw, (x + width*0.4, y + height*0.2), height*0.05, fill=self.color_map["黄色"]) + self._draw_circle(draw, (x + width*0.6, y + height*0.2), height*0.05, fill=self.color_map["黄色"]) + self._draw_circle(draw, (x + width*0.4, y + height*0.2), height*0.02, fill=self.color_map["黑色"]) + self._draw_circle(draw, (x + width*0.6, y + height*0.2), height*0.02, fill=self.color_map["黑色"]) + # 胡子 + draw.line([(x + width*0.2, y + height*0.25), (x + width*0.3, y + height*0.27)], fill=self.color_map["黑色"], width=1) + draw.line([(x + width*0.2, y + height*0.3), (x + width*0.3, y + height*0.3)], fill=self.color_map["黑色"], width=1) + draw.line([(x + width*0.7, y + height*0.27), (x + width*0.8, y + height*0.25)], fill=self.color_map["黑色"], width=1) + draw.line([(x + width*0.7, y + height*0.3), (x + width*0.8, y + height*0.3)], fill=self.color_map["黑色"], width=1) + + def _render_tree(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染树""" + # 树干 + draw.rectangle([x + width*0.4, y + height*0.6, x + width*0.6, y + height], fill=self.color_map["棕色"], outline=self.color_map["黑色"]) + # 树叶 + self._draw_circle(draw, (x + width//2, y + height*0.2), width*0.3, fill=self.color_map["绿色"]) + self._draw_circle(draw, (x + width*0.3, y + height*0.4), width*0.25, fill=self.color_map["绿色"]) + self._draw_circle(draw, (x + width*0.7, y + height*0.4), width*0.25, fill=self.color_map["绿色"]) + + def _render_house(self, draw: ImageDraw, x: int, y: int, width: int, height: int, color: Tuple = None): + """原生渲染房子""" + # 墙 + draw.rectangle([x + width*0.2, y + height*0.4, x + width*0.8, y + height], fill=self.color_map["黄色"], outline=self.color_map["黑色"], width=2) + # 屋顶 + draw.polygon([(x, y + height*0.4), (x + width//2, y), (x + width, y + height*0.4)], fill=self.color_map["红色"], outline=self.color_map["黑色"], width=2) + # 门 + draw.rectangle([x + width*0.45, y + height*0.7, x + width*0.55, y + height], fill=self.color_map["棕色"], outline=self.color_map["黑色"]) + # 窗户 + draw.rectangle([x + width*0.3, y + height*0.5, x + width*0.4, y + height*0.6], fill=self.color_map["蓝色"], outline=self.color_map["黑色"]) + draw.rectangle([x + width*0.6, y + height*0.5, x + width*0.7, y + height*0.6], fill=self.color_map["蓝色"], outline=self.color_map["黑色"]) + + def _layout_horizontal_series(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """水平串联布局""" + start, end = self._get_connection_points(from_pos, to_pos) + draw.line([start, end], fill=self.color_map["黑色"], width=2) + mid_x = (start[0] + end[0]) // 2 + mid_y = (start[1] + end[1]) // 2 - 30 + draw.text((mid_x, mid_y), edge.relation, fill=self.color_map["黑色"], font=self.font) + + def _layout_horizontal_parallel(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """并联布局""" + start, end = self._get_connection_points(from_pos, to_pos) + draw.line([start, (start[0], start[1] - 30), (end[0], end[1] - 30), end], fill=self.color_map["黑色"], width=2) + draw.line([start, (start[0], start[1] + 30), (end[0], end[1] + 30), end], fill=self.color_map["黑色"], width=2) + mid_x = (start[0] + end[0]) // 2 + mid_y = min(start[1], end[1]) - 50 + draw.text((mid_x, mid_y), edge.relation, fill=self.color_map["黑色"], font=self.font) + + def _layout_connect(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """普通连接""" + start, end = self._get_connection_points(from_pos, to_pos) + draw.line([start, end], fill=self.color_map["黑色"], width=2) + + def _layout_top_to_bottom(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """从上到下布局(控制关系)""" + start = (from_pos["x"] + from_pos["width"]//2, from_pos["y"] + from_pos["height"]) + end = (to_pos["x"] + to_pos["width"]//2, to_pos["y"]) + self._draw_arrow_line(draw, start, end, fill=self.color_map["黑色"], width=2) + mid_x = (start[0] + end[0]) // 2 + mid_y = (start[1] + end[1]) // 2 + draw.text((mid_x, mid_y), edge.relation, fill=self.color_map["黑色"], font=self.font) + + def _layout_inside(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """包含关系:to在from内部""" + to_pos["x"] = from_pos["x"] + from_pos["width"] * 0.2 + to_pos["y"] = from_pos["y"] + from_pos["height"] * 0.2 + to_pos["width"] = from_pos["width"] * 0.6 + to_pos["height"] = from_pos["height"] * 0.6 + self._draw_dashed_rectangle( + draw, + ( + from_pos["x"] - 5, + from_pos["y"] - 5, + from_pos["x"] + from_pos["width"] + 5, + from_pos["y"] + from_pos["height"] + 5, + ), + outline=self.color_map["灰色"], + width=1, + dash_length=5, + ) + draw.text((from_pos["x"], from_pos["y"] - 20), f"包含{to_pos['node'].concept}", fill=self.color_map["黑色"], font=self.font) + + def _layout_left_to_right(self, draw: ImageDraw, from_pos: Dict, to_pos: Dict, edge): + """从左到右布局(产生/导致关系)""" + start, end = self._get_connection_points(from_pos, to_pos) + self._draw_arrow_line(draw, start, end, fill=self.color_map["黑色"], width=2) + mid_x = (start[0] + end[0]) // 2 + mid_y = (start[1] + end[1]) // 2 - 20 + draw.text((mid_x, mid_y), edge.relation, fill=self.color_map["黑色"], font=self.font) + async def generate_image(self, path: 'MazePath', canvas_size: Tuple[int, int] = (1024, 768)) -> Dict[str, Any]: + """ + 原生生成图片:完全基于推理路径,不需要任何外部API + :param path: Tri-Maze推理路径 + :param canvas_size: 画布大小 + :return: 生成结果 + """ + logger.info(f"🎨 原生生成图片,推理路径: {path.get_concept_list()}") + + try: + # 1. 计算布局 + layout = self._calculate_layout(path, canvas_size) + positions = layout["positions"] + connections = layout["connections"] + + # 2. 创建画布 + image = Image.new("RGB", canvas_size, self.color_map["白色"]) + draw = ImageDraw.Draw(image) + + # 3. 渲染连接关系 + for conn in connections: + edge = conn["edge"] + layout_func = self.relation_layout.get(edge.relation, self._layout_connect) + layout_func(draw, conn["from"], conn["to"], edge) + + # 4. 渲染每个节点 + for pos in positions: + node = pos["node"] + renderer = self.concept_renderers.get(node.concept, self._render_rectangle) + renderer( + draw, + pos["x"], + pos["y"], + pos["width"], + pos["height"] + ) + # 标注节点名称 + draw.text( + (pos["x"], pos["y"] - 25), + node.concept, + fill=self.color_map["黑色"], + font=self.font + ) + + # 5. 保存图片 + image_path = f"{self.output_dir}/native_image_{hash(str(path.get_concept_list()))}.png" + image.save(image_path) + + logger.info(f"✅ 原生图片生成成功,保存到: {image_path}") + + return { + "success": True, + "type": "native_image", + "image_path": image_path, + "save_path": image_path, + "layout": layout, + "description": "完全基于Tri-Maze推理路径原生生成的图片,无外部API依赖", + "concepts": path.get_concept_list() + } + + except Exception as e: + logger.error(f"❌ 原生图片生成失败: {str(e)}") + return {"success": False, "error": str(e)} + + async def generate_video(self, path: 'MazePath', duration: int = 5, fps: int = 24) -> Dict[str, Any]: + """ + 原生生成视频:基于推理路径生成动画视频 + :param path: Tri-Maze推理路径 + :param duration: 视频时长(秒) + :param fps: 帧率 + :return: 生成结果 + """ + logger.info(f"🎬 原生生成视频,推理路径: {path.get_concept_list()}") + + try: + if cv2 is None: + raise RuntimeError("OpenCV is not available in the current environment") + # 计算布局 + layout = self._calculate_layout(path, (1024, 768)) + total_frames = duration * fps + + # 创建视频写入器 + video_path = f"{self.output_dir}/native_video_{hash(str(path.get_concept_list()))}.mp4" + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + video = cv2.VideoWriter(video_path, fourcc, fps, (1024, 768)) + + # 生成每一帧 + for frame_idx in range(total_frames): + # 进度:0.0到1.0 + progress = frame_idx / total_frames + + # 创建帧 + image = Image.new("RGB", (1024, 768), self.color_map["白色"]) + draw = ImageDraw.Draw(image) + + # 渲染已探索的节点和连接 + explored_count = int(len(layout["connections"]) * progress) + 1 + + # 渲染连接 + for i, conn in enumerate(layout["connections"][:explored_count]): + edge = conn["edge"] + # 绘制逐步显示的动画 + if i < explored_count - 1: + alpha = 1.0 + else: + alpha = progress * len(layout["connections"]) - (explored_count - 1) + + start = conn["start_point"] + end = conn["end_point"] + current_end = ( + int(start[0] + (end[0] - start[0]) * alpha), + int(start[1] + (end[1] - start[1]) * alpha) + ) + draw.line([start, current_end], fill=self.color_map["黑色"], width=2) + + # 渲染节点 + for i, pos in enumerate(layout["positions"][:explored_count]): + node = pos["node"] + renderer = self.concept_renderers.get(node.concept, self._render_rectangle) + renderer(draw, pos["x"], pos["y"], pos["width"], pos["height"]) + draw.text((pos["x"], pos["y"] - 25), node.concept, fill=self.color_map["黑色"], font=self.font) + + # 转换为OpenCV格式 + frame = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) + video.write(frame) + + video.release() + cv2.destroyAllWindows() + + logger.info(f"✅ 原生视频生成成功,保存到: {video_path}") + + return { + "success": True, + "type": "native_video", + "video_path": video_path, + "save_path": video_path, + "duration": duration, + "fps": fps, + "description": "完全基于Tri-Maze推理路径原生生成的动画视频,无外部API依赖", + "concepts": path.get_concept_list() + } + + except Exception as e: + logger.error(f"❌ 原生视频生成失败: {str(e)}") + return {"success": False, "error": str(e)} + + async def generate(self, path: 'MazePath', generation_type: str = "image") -> Dict[str, Any]: + """ + 原生生成多模态产物 + :param path: Tri-Maze推理路径 + :param generation_type: 生成类型:image/video + :return: 生成结果 + """ + if generation_type == "image": + return await self.generate_image(path) + elif generation_type == "video": + return await self.generate_video(path) + else: + return {"success": False, "error": f"不支持的原生生成类型: {generation_type}"} + + def get_supported_types(self) -> List[str]: + """获取支持的原生生成类型""" + return ["image", "video"] + + + + + + + + diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout.py new file mode 100644 index 0000000..38affe5 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout.py @@ -0,0 +1,882 @@ +from __future__ import annotations + +import hashlib +import json +import math +import os +import random +from typing import Any, Dict, List, Tuple + +try: + import torch +except Exception: # pragma: no cover - optional dependency path + torch = None + +try: + from .natural_layout_trainer import ( + NaturalLayoutProposalNet, + NaturalLayoutRanker, + NaturalLayoutTrainerConfig, + encode_layout_row, + ) +except Exception: # pragma: no cover - optional dependency path + NaturalLayoutProposalNet = None # type: ignore[assignment] + NaturalLayoutRanker = None # type: ignore[assignment] + NaturalLayoutTrainerConfig = None # type: ignore[assignment] + encode_layout_row = None # type: ignore[assignment] + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _clean_text(value: Any) -> str: + return str(value or "").strip() + + +def _engine_value(value: Any) -> str: + raw = _clean_text(value).lower() + if raw in {"mechanical", "mechanical_v1"}: + return "mechanical_layout_v1" + if raw in {"natural", "natural_v1", "natural_layout_v1"}: + return "natural_layout_v1" + return "auto" + + +def resolve_layout_engine(scene: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> str: + env_value = _engine_value(os.getenv("TMCRA_LAYOUT_ENGINE", "")) + option_value = _engine_value((sketch_options or {}).get("layout_engine")) + scene_value = _engine_value(((scene or {}).get("layout_options") or {}).get("layout_engine")) + for candidate in (option_value, scene_value, env_value): + if candidate in {"natural_layout_v1", "mechanical_layout_v1"}: + return candidate + return "natural_layout_v1" + + +def resolve_layout_candidate_count(scene: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> int: + for raw in ( + (sketch_options or {}).get("layout_candidate_count"), + ((scene or {}).get("layout_options") or {}).get("layout_candidate_count"), + os.getenv("TMCRA_LAYOUT_CANDIDATES", ""), + ): + try: + value = int(raw) + except Exception: + continue + if value > 0: + return max(3, min(8, value)) + return 4 + + +def _stable_seed(scene: Dict[str, Any], scene_type: str, salt: str = "") -> int: + payload = { + "scene_type": scene_type, + "objects": [ + { + "id": item.get("id"), + "asset_key": item.get("asset_key"), + "role": item.get("role"), + "depth_band": item.get("depth_band"), + "concept": item.get("concept"), + } + for item in scene.get("object_instances", []) or [] + ], + "concept_order": scene.get("concept_order", []) or [], + "summary": ((scene.get("render_hints") or {}).get("scene_summary") or ""), + "salt": salt, + } + digest = hashlib.sha256(json.dumps(payload, ensure_ascii=False, sort_keys=True).encode("utf-8")).hexdigest() + return int(digest[:12], 16) + + +def _object_center(item: Dict[str, Any]) -> Tuple[float, float]: + return float(item.get("x", 0)) + float(item.get("width", 0)) / 2.0, float(item.get("y", 0)) + float(item.get("height", 0)) / 2.0 + + +def _role_priority(item: Dict[str, Any]) -> float: + role = str(item.get("role") or "") + if role in {"subject", "focus", "core_subject"}: + return 3.0 + if role in {"support", "environment"}: + return 2.0 + return 1.0 + + +def _depth_rank(depth_band: str) -> int: + return {"background": 0, "midground": 1, "foreground": 2}.get(str(depth_band or ""), 1) + + +def _clamp(value: float, low: float, high: float) -> float: + return max(low, min(high, value)) + + +def _repo_checkpoint_path(filename: str) -> str | None: + root = os.path.dirname(os.path.dirname(__file__)) + candidate = os.path.join(root, filename) + return candidate if os.path.exists(candidate) else None + + +class NaturalLayoutModelRuntime: + def __init__(self) -> None: + self.proposal_path = ( + os.getenv("TMCRA_LAYOUT_PROPOSAL_PATH", "").strip() + or _repo_checkpoint_path("tmp_layout_proposal.pt") + or "" + ) + self.ranker_path = ( + os.getenv("TMCRA_LAYOUT_RANKER_PATH", "").strip() + or _repo_checkpoint_path("tmp_layout_ranker.pt") + or "" + ) + self._proposal = None + self._ranker = None + self._config = None + self._state: Dict[str, Any] = { + "enabled": False, + "loaded": False, + "proposal_path": self.proposal_path, + "ranker_path": self.ranker_path, + "model_id": "natural_layout_runtime_v1", + } + self._load() + + def _load(self) -> None: + if ( + torch is None + or NaturalLayoutProposalNet is None + or NaturalLayoutRanker is None + or NaturalLayoutTrainerConfig is None + or encode_layout_row is None + or not self.proposal_path + or not self.ranker_path + or not os.path.exists(self.proposal_path) + or not os.path.exists(self.ranker_path) + ): + return + try: + proposal_payload = torch.load(self.proposal_path, map_location="cpu", weights_only=False) + ranker_payload = torch.load(self.ranker_path, map_location="cpu", weights_only=False) + config_payload = proposal_payload.get("config") or ranker_payload.get("config") or {} + config = NaturalLayoutTrainerConfig(**config_payload) + proposal = NaturalLayoutProposalNet(config) + ranker = NaturalLayoutRanker(config) + proposal.load_state_dict(proposal_payload.get("state_dict") or proposal_payload, strict=False) + ranker.load_state_dict(ranker_payload.get("state_dict") or ranker_payload, strict=False) + proposal.eval() + ranker.eval() + self._proposal = proposal + self._ranker = ranker + self._config = config + self._state.update( + { + "enabled": True, + "loaded": True, + "proposal_model_id": proposal_payload.get("model_id", "natural_layout_proposal_v1"), + "ranker_model_id": ranker_payload.get("model_id", "natural_layout_ranker_v1"), + } + ) + except Exception as exc: # pragma: no cover - runtime guard + self._state["error"] = str(exc) + + def status(self) -> Dict[str, Any]: + return dict(self._state) + + def build_candidate(self, scene: Dict[str, Any], scene_type: str, locked_ids: set[str]) -> Dict[str, Any] | None: + if ( + self._proposal is None + or self._ranker is None + or self._config is None + or encode_layout_row is None + or torch is None + ): + return None + objects = list(scene.get("object_instances", []) or []) + if not objects: + return None + width = float(scene.get("canvas_size", {}).get("width", 1024) or 1024) + height = float(scene.get("canvas_size", {}).get("height", 768) or 768) + encoded = encode_layout_row( + { + "scene_type": scene_type, + "layout_quality_score": float(scene.get("layout_score", 0.8) or 0.8), + "layout_condition": { + "scene_type": scene_type, + "canvas_size": {"width": width, "height": height}, + "objects": [ + { + "id": str(item.get("id") or f"obj_{index}"), + "role": str(item.get("role") or ""), + "depth_band": str(item.get("depth_band") or "midground"), + "importance": float(item.get("importance", 1.0) or 1.0), + } + for index, item in enumerate(objects) + ], + }, + "object_boxes": [ + { + "id": str(item.get("id") or f"obj_{index}"), + "x": float(item.get("x", 0.0) or 0.0), + "y": float(item.get("y", 0.0) or 0.0), + "width": float(item.get("width", 0.0) or 0.0), + "height": float(item.get("height", 0.0) or 0.0), + "rotation": float(item.get("rotation", 0.0) or 0.0), + "depth_band": str(item.get("depth_band") or "midground"), + } + for index, item in enumerate(objects) + ], + "relation_graph": list(scene.get("connectors", []) or []), + }, + max_objects=int(self._config.max_objects), + ) + feature_tensor = torch.tensor(encoded["features"], dtype=torch.float32).unsqueeze(0) + box_tensor = torch.tensor(encoded["target_boxes"], dtype=torch.float32).unsqueeze(0) + proposal_input = feature_tensor.clone() + proposal_input[..., :5] = box_tensor + with torch.no_grad(): + predicted = self._proposal(proposal_input) + rank_logit = self._ranker(feature_tensor, predicted) + rank_score = float(torch.sigmoid(rank_logit)[0].item()) + updates: Dict[str, Dict[str, Any]] = {} + active_count = min(len(objects), int(self._config.max_objects)) + subject_centers: List[Tuple[float, float]] = [] + for index, item in enumerate(objects[:active_count]): + object_id = _clean_text(item.get("id")) + if not object_id: + continue + if object_id in locked_ids: + updates[object_id] = { + "x": int(item.get("x", 0)), + "y": int(item.get("y", 0)), + "width": int(item.get("width", 120)), + "height": int(item.get("height", 100)), + "rotation": float(item.get("rotation", 0.0) or 0.0), + "depth_band": str(item.get("depth_band") or "midground"), + "z_index": int(item.get("z_index", 20 + index)), + } + continue + px, py, pw, ph, prot = [float(value) for value in predicted[0, index].tolist()] + px = _clamp(px, 0.04, 0.92) + py = _clamp(py, 0.06, 0.90) + pw = _clamp(pw, 0.05, 0.8) + ph = _clamp(ph, 0.05, 0.8) + x = int(round(px * width)) + y = int(round(py * height)) + w = max(36, int(round(pw * width))) + h = max(36, int(round(ph * height))) + x = max(12, min(int(width) - w - 12, x)) + y = max(40, min(int(height) - h - 12, y)) + center_y = y + h / 2.0 + depth_band = "foreground" if center_y > height * 0.62 else "background" if center_y < height * 0.30 else "midground" + z_index = 20 + _depth_rank(depth_band) * 20 + index + if str(item.get("role") or "") in {"subject", "focus", "core_subject"}: + z_index += 12 + subject_centers.append((x + w / 2.0, y + h / 2.0)) + updates[object_id] = { + "x": x, + "y": y, + "width": w, + "height": h, + "rotation": round(_clamp(prot * 45.0, -18.0, 18.0), 2), + "depth_band": depth_band, + "z_index": z_index, + } + focus_x = 0.5 + focus_y = 0.46 + if subject_centers: + focus_x = round(sum(item[0] for item in subject_centers) / len(subject_centers) / width, 3) + focus_y = round(sum(item[1] for item in subject_centers) / len(subject_centers) / height, 3) + return { + "id": "layout_model_1", + "object_updates": updates, + "camera_bias": { + "focus_x": focus_x, + "focus_y": focus_y, + "perspective_strength": 0.58, + }, + "model_score": round(rank_score, 4), + "score_source": "proposal_ranker", + } + + +_LAYOUT_MODEL_RUNTIME: NaturalLayoutModelRuntime | None = None + + +def _layout_model_runtime() -> NaturalLayoutModelRuntime: + global _LAYOUT_MODEL_RUNTIME + if _LAYOUT_MODEL_RUNTIME is None: + _LAYOUT_MODEL_RUNTIME = NaturalLayoutModelRuntime() + return _LAYOUT_MODEL_RUNTIME + + +def _negative_space_mask(scene: Dict[str, Any], objects: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + occupancy = [0.0, 0.0, 0.0, 0.0] + quadrants = [ + {"x": 0, "y": 0, "width": width * 0.5, "height": height * 0.5}, + {"x": width * 0.5, "y": 0, "width": width * 0.5, "height": height * 0.5}, + {"x": 0, "y": height * 0.5, "width": width * 0.5, "height": height * 0.5}, + {"x": width * 0.5, "y": height * 0.5, "width": width * 0.5, "height": height * 0.5}, + ] + for item in objects: + x0 = float(item.get("x", 0)) + y0 = float(item.get("y", 0)) + x1 = x0 + float(item.get("width", 0)) + y1 = y0 + float(item.get("height", 0)) + for index, quad in enumerate(quadrants): + qx0 = quad["x"] + qy0 = quad["y"] + qx1 = qx0 + quad["width"] + qy1 = qy0 + quad["height"] + overlap_w = max(0.0, min(x1, qx1) - max(x0, qx0)) + overlap_h = max(0.0, min(y1, qy1) - max(y0, qy0)) + occupancy[index] += overlap_w * overlap_h + ranked = sorted(range(len(quadrants)), key=lambda index: occupancy[index]) + return [ + { + "id": f"negative_space_{slot + 1}", + "x": int(quadrants[index]["x"]), + "y": int(quadrants[index]["y"]), + "width": int(quadrants[index]["width"]), + "height": int(quadrants[index]["height"]), + "weight": round(1.0 - (occupancy[index] / max(1.0, quadrants[index]["width"] * quadrants[index]["height"])), 3), + } + for slot, index in enumerate(ranked[:2], start=1) + ] + + +def _candidate_object_updates( + scene: Dict[str, Any], + scene_type: str, + locked_ids: set[str], + *, + candidate_index: int, +) -> Dict[str, Dict[str, Any]]: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + objects = sorted( + [_copy(item) for item in scene.get("object_instances", []) or []], + key=lambda item: (-_role_priority(item), _clean_text(item.get("id"))), + ) + rng = random.Random(_stable_seed(scene, scene_type, salt=f"candidate:{candidate_index}")) + updates: Dict[str, Dict[str, Any]] = {} + total = max(1, len(objects)) + scene_focus_slots = [(0.34, 0.43), (0.62, 0.41), (0.42, 0.54), (0.58, 0.52)] + horizon_y = height * 0.56 + + for index, item in enumerate(objects): + object_id = _clean_text(item.get("id")) + if not object_id: + continue + if object_id in locked_ids: + updates[object_id] = { + "x": int(item.get("x", 0)), + "y": int(item.get("y", 0)), + "width": int(item.get("width", 120)), + "height": int(item.get("height", 100)), + "rotation": float(item.get("rotation", 0.0) or 0.0), + "depth_band": str(item.get("depth_band") or "midground"), + "z_index": int(item.get("z_index", 20 + index)), + } + continue + + base_width = max(36, int(item.get("width", 120))) + base_height = max(36, int(item.get("height", 100))) + role = str(item.get("role") or "") + asset_key = str(item.get("asset_key") or "") + scale_jitter = 1.0 + rng.uniform(-0.14, 0.18) + forced_depth_band = "" + + if role in {"subject", "focus", "core_subject"}: + scale_jitter += 0.08 + elif role in {"detail"}: + scale_jitter -= 0.05 + + object_width = max(36, int(base_width * scale_jitter)) + object_height = max(36, int(base_height * scale_jitter)) + + if scene_type == "process": + process_slots = { + "sun": (0.16, 0.16, "background"), + "cloud": (0.58, 0.22, "background"), + "vapor": (0.34, 0.48, "midground"), + "raindrop": (0.64, 0.50, "midground"), + "leaf": (0.54, 0.74, "foreground"), + "cell": (0.50, 0.58, "midground"), + "airplane": (0.48, 0.26, "background"), + "energy_wave": (0.28, 0.34, "background"), + } + default_slot = (0.22 + 0.5 * (index / max(1, total - 1)), 0.54, "midground") + base_x, base_y, forced_depth_band = process_slots.get(asset_key, default_slot) + x_ratio = base_x + rng.uniform(-0.04, 0.04) + y_ratio = base_y + rng.uniform(-0.04, 0.04) + if forced_depth_band == "background": + object_width = max(36, int(object_width * (0.88 + rng.uniform(-0.04, 0.04)))) + object_height = max(36, int(object_height * (0.88 + rng.uniform(-0.04, 0.04)))) + elif forced_depth_band == "foreground": + object_width = max(36, int(object_width * (1.12 + rng.uniform(-0.04, 0.06)))) + object_height = max(36, int(object_height * (1.12 + rng.uniform(-0.04, 0.06)))) + rotation = rng.uniform(-8, 8) + elif scene_type == "schematic": + schematic_slots = { + "battery": (0.18, 0.54, "midground"), + "switch": (0.42, 0.34, "foreground"), + "resistor": (0.50, 0.54, "midground"), + "led": (0.78, 0.54, "midground"), + "capacitor": (0.48, 0.76, "midground"), + "diode": (0.66, 0.34, "midground"), + "board": (0.50, 0.54, "background"), + } + default_slot = (0.22 + 0.5 * (index / max(1, total - 1)), 0.54, "midground") + base_x, base_y, forced_depth_band = schematic_slots.get(asset_key, default_slot) + x_ratio = base_x + rng.uniform(-0.035, 0.04) + y_ratio = base_y + rng.uniform(-0.04, 0.04) + if asset_key == "board": + object_width = max(object_width, int(width * 0.44)) + object_height = max(object_height, int(height * 0.30)) + rotation = rng.uniform(-3, 3) + else: + focus_x, focus_y = scene_focus_slots[candidate_index % len(scene_focus_slots)] + lane_bias = -1 if (index + candidate_index) % 2 == 0 else 1 + side_lane = 0.18 if lane_bias < 0 else 0.82 + depth_hint = str(item.get("depth_band") or "") + if asset_key in {"sun"}: + depth_hint = "background" + elif asset_key in {"cloud"}: + depth_hint = "background" + elif asset_key in {"road", "car", "street_lamp", "person"}: + depth_hint = "midground" if asset_key != "road" else "foreground" + elif role in {"subject", "focus", "core_subject"}: + depth_hint = depth_hint or "midground" + elif not depth_hint: + depth_hint = "background" if asset_key in {"building", "tree", "house"} else "midground" + + if depth_hint == "foreground": + y_ratio = 0.74 + rng.uniform(-0.03, 0.04) + depth_scale = 1.18 + rng.uniform(-0.04, 0.08) + elif depth_hint == "background": + y_ratio = 0.34 + rng.uniform(-0.05, 0.04) + depth_scale = 0.86 + rng.uniform(-0.08, 0.04) + else: + y_ratio = 0.54 + rng.uniform(-0.05, 0.05) + depth_scale = 1.0 + rng.uniform(-0.08, 0.06) + + object_width = max(36, int(object_width * depth_scale)) + object_height = max(36, int(object_height * depth_scale)) + + x_ratio = focus_x + rng.uniform(-0.18, 0.18) + if asset_key in {"building", "house"}: + x_ratio = side_lane + rng.uniform(-0.08, 0.08) + y_ratio = min(y_ratio, 0.5 + rng.uniform(-0.03, 0.03)) + elif asset_key == "tree": + x_ratio = (0.22 if lane_bias < 0 else 0.76) + rng.uniform(-0.07, 0.07) + y_ratio += 0.02 + elif asset_key == "street_lamp": + x_ratio = (0.14 if lane_bias < 0 else 0.86) + rng.uniform(-0.03, 0.03) + y_ratio = max(y_ratio, 0.58 + rng.uniform(-0.04, 0.04)) + elif asset_key == "car": + x_ratio = 0.5 + rng.uniform(-0.12, 0.12) + y_ratio = max(y_ratio, 0.7 + rng.uniform(-0.02, 0.03)) + elif role in {"subject", "focus", "core_subject"}: + x_ratio = focus_x + rng.uniform(-0.08, 0.08) + y_ratio = 0.5 + rng.uniform(-0.04, 0.05) + if asset_key == "sun": + x_ratio = 0.18 + 0.18 * (candidate_index % 3) + y_ratio = 0.12 + rng.uniform(-0.02, 0.02) + elif asset_key == "cloud": + x_ratio = 0.24 + 0.18 * ((index + candidate_index) % 3) + y_ratio = 0.18 + rng.uniform(-0.04, 0.03) + elif asset_key == "road": + x_ratio = 0.5 + y_ratio = 0.76 + object_width = max(object_width, int(width * 0.62)) + object_height = max(object_height, int(height * 0.16)) + if role not in {"subject", "focus", "core_subject"}: + x_ratio = x_ratio + (0.06 if x_ratio < focus_x else -0.06) * rng.uniform(0.4, 1.0) + y_ratio = max(y_ratio, (horizon_y / height) + 0.02 if depth_hint != "background" else 0.12) + rotation = rng.uniform(-10, 10) + + x = int(width * _clamp(x_ratio, 0.12, 0.88) - object_width / 2) + y = int(height * _clamp(y_ratio, 0.14, 0.84) - object_height / 2) + x = max(12, min(width - object_width - 12, x)) + y = max(40, min(height - object_height - 12, y)) + + if scene_type == "scene": + depth_band = "foreground" if y > height * 0.58 else "background" if y < height * 0.32 else "midground" + else: + depth_band = forced_depth_band or ("midground" if role not in {"subject", "focus", "core_subject"} else "foreground") + z_index = 20 + _depth_rank(depth_band) * 20 + index + if role in {"subject", "focus", "core_subject"}: + z_index += 12 + + updates[object_id] = { + "x": x, + "y": y, + "width": object_width, + "height": object_height, + "rotation": round(rotation, 2), + "depth_band": depth_band, + "z_index": z_index, + } + if scene_type == "scene": + updates = _refine_scene_object_updates(scene, updates, candidate_index=candidate_index) + return updates + + +def _refine_scene_object_updates( + scene: Dict[str, Any], + updates: Dict[str, Dict[str, Any]], + *, + candidate_index: int, +) -> Dict[str, Dict[str, Any]]: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + objects_by_id = {str(item.get("id") or ""): item for item in scene.get("object_instances", []) or []} + refined = _copy(updates) + subject_boxes: List[Tuple[int, int, int, int]] = [] + + for object_id, payload in refined.items(): + item = objects_by_id.get(object_id) or {} + role = str(item.get("role") or "") + asset_key = str(item.get("asset_key") or "") + if role in {"subject", "focus", "core_subject"}: + subject_boxes.append( + ( + int(payload.get("x", 0)), + int(payload.get("y", 0)), + int(payload.get("x", 0)) + int(payload.get("width", 0)), + int(payload.get("y", 0)) + int(payload.get("height", 0)), + ) + ) + if asset_key in {"building", "house"}: + payload["rotation"] = 0.0 + elif asset_key in {"road"}: + payload["rotation"] = 0.0 + payload["x"] = max(0, min(width - int(payload["width"]), int(width * 0.5 - int(payload["width"]) / 2))) + elif asset_key in {"street_lamp"}: + payload["rotation"] = round(-2 + candidate_index * 0.8, 2) + + for object_id, payload in refined.items(): + item = objects_by_id.get(object_id) or {} + role = str(item.get("role") or "") + asset_key = str(item.get("asset_key") or "") + if role in {"subject", "focus", "core_subject"} or asset_key in {"road", "sun", "cloud"}: + continue + x0 = int(payload.get("x", 0)) + y0 = int(payload.get("y", 0)) + x1 = x0 + int(payload.get("width", 0)) + y1 = y0 + int(payload.get("height", 0)) + for sx0, sy0, sx1, sy1 in subject_boxes: + overlap_w = max(0, min(x1, sx1) - max(x0, sx0)) + overlap_h = max(0, min(y1, sy1) - max(y0, sy0)) + if overlap_w * overlap_h <= 0: + continue + shift = max(18, overlap_w + 12) + if x0 < sx0: + x0 = max(12, x0 - shift) + else: + x0 = min(width - int(payload["width"]) - 12, x0 + shift) + y0 = min(height - int(payload["height"]) - 12, max(40, y0 + max(0, overlap_h // 2))) + x1 = x0 + int(payload["width"]) + y1 = y0 + int(payload["height"]) + payload["x"] = x0 + payload["y"] = y0 + return refined + + +def _score_layout(scene: Dict[str, Any], objects: List[Dict[str, Any]]) -> Tuple[float, Dict[str, Any]]: + width = float(scene.get("canvas_size", {}).get("width", 1024) or 1024) + height = float(scene.get("canvas_size", {}).get("height", 768) or 768) + if not objects: + return 0.0, {"focus_score": 0.0, "layering_score": 0.0, "negative_space_score": 0.0, "symmetry_penalty": 0.0, "connector_penalty": 0.0, "uniformity_penalty": 0.0} + + subject_objects = [item for item in objects if str(item.get("role") or "") in {"subject", "focus", "core_subject"}] + focus_targets = [(width * 0.36, height * 0.42), (width * 0.62, height * 0.42)] + focus_score = 0.0 + for subject in subject_objects or objects[:1]: + center = _object_center(subject) + nearest = min(math.dist(center, target) for target in focus_targets) + focus_score += 1.0 - _clamp(nearest / max(width, height), 0.0, 1.0) + focus_score /= max(1, len(subject_objects or objects[:1])) + + centers_x = sorted(_object_center(item)[0] for item in objects) + x_gaps = [centers_x[index + 1] - centers_x[index] for index in range(len(centers_x) - 1)] + if x_gaps: + avg_gap = sum(x_gaps) / len(x_gaps) + gap_variance = sum((gap - avg_gap) ** 2 for gap in x_gaps) / len(x_gaps) + uniformity_penalty = 1.0 - _clamp(math.sqrt(gap_variance) / max(24.0, avg_gap), 0.0, 1.0) + else: + uniformity_penalty = 0.0 + + left_weight = 0.0 + right_weight = 0.0 + for item in objects: + area = float(item.get("width", 0)) * float(item.get("height", 0)) + if _object_center(item)[0] <= width / 2: + left_weight += area + else: + right_weight += area + symmetry_penalty = 1.0 - _clamp(abs(left_weight - right_weight) / max(1.0, left_weight + right_weight), 0.0, 1.0) + + y_centers = [_object_center(item)[1] for item in objects] + y_span = max(y_centers) - min(y_centers) if len(y_centers) > 1 else 0.0 + depth_bands = {str(item.get("depth_band") or "midground") for item in objects} + layering_score = 0.5 * _clamp(y_span / max(1.0, height * 0.42), 0.0, 1.0) + 0.5 * (len(depth_bands) / 3.0) + + occupancy = sum(float(item.get("width", 0)) * float(item.get("height", 0)) for item in objects) / max(1.0, width * height) + negative_space_score = _clamp(1.0 - occupancy, 0.0, 1.0) + + objects_by_id = {str(item.get("id") or ""): item for item in objects} + connector_vectors: List[float] = [] + for connector in scene.get("connectors", []) or []: + if not connector.get("visible", True): + continue + from_obj = objects_by_id.get(str(connector.get("from_id") or "")) + to_obj = objects_by_id.get(str(connector.get("to_id") or "")) + if not from_obj or not to_obj: + continue + start = _object_center(from_obj) + end = _object_center(to_obj) + connector_vectors.append(abs(start[1] - end[1]) / max(24.0, abs(start[0] - end[0]) + abs(start[1] - end[1]))) + connector_penalty = sum(connector_vectors) / len(connector_vectors) if connector_vectors else 0.35 + + semantic_score = 0.7 + scene_type = _clean_text(((scene.get("layout_options") or {}).get("scene_type")) or "scene") + if scene_type == "scene": + semantic_checks: List[float] = [] + for item in objects: + asset_key = str(item.get("asset_key") or "").strip().lower() + center_x, center_y = _object_center(item) + x_ratio = center_x / max(1.0, width) + y_ratio = center_y / max(1.0, height) + visible_area = (float(item.get("width", 0) or 0) * float(item.get("height", 0) or 0)) / max(1.0, width * height) + if asset_key in {"person", "dog"}: + y_target = 1.0 - _clamp(abs(y_ratio - 0.68) / 0.24, 0.0, 1.0) + x_target = 1.0 - _clamp(abs(x_ratio - 0.5) / 0.34, 0.0, 1.0) + semantic_checks.append(0.65 * y_target + 0.35 * x_target) + elif asset_key in {"house", "building"}: + y_target = 1.0 - _clamp(abs(y_ratio - 0.52) / 0.22, 0.0, 1.0) + side_target = _clamp(abs(x_ratio - 0.5) / 0.24, 0.0, 1.0) + semantic_checks.append(0.68 * y_target + 0.32 * side_target) + elif asset_key in {"tree", "street_lamp"}: + y_target = 1.0 - _clamp(abs(y_ratio - 0.6) / 0.28, 0.0, 1.0) + side_target = _clamp(abs(x_ratio - 0.5) / 0.28, 0.0, 1.0) + semantic_checks.append(0.56 * y_target + 0.44 * side_target) + elif asset_key in {"car", "road"}: + y_target = 1.0 - _clamp(abs(y_ratio - 0.74) / 0.18, 0.0, 1.0) + semantic_checks.append(y_target) + elif asset_key == "sun": + semantic_checks.append(1.0 - _clamp(abs(y_ratio - 0.14) / 0.12, 0.0, 1.0)) + elif asset_key == "cloud": + semantic_checks.append(1.0 - _clamp(abs(y_ratio - 0.18) / 0.14, 0.0, 1.0)) + elif asset_key: + semantic_checks.append(0.84 if visible_area <= 0.24 else 0.62) + + if semantic_checks: + semantic_score = sum(semantic_checks) / len(semantic_checks) + depth_kinds = {str(item.get("depth_band") or "") for item in objects if str(item.get("depth_band") or "")} + if len(objects) >= 3 and len(depth_kinds) <= 1: + semantic_score *= 0.72 + if subject_objects: + subject_box = subject_objects[0] + sx0 = float(subject_box.get("x", 0) or 0) + sy0 = float(subject_box.get("y", 0) or 0) + sx1 = sx0 + float(subject_box.get("width", 0) or 0) + sy1 = sy0 + float(subject_box.get("height", 0) or 0) + support_overlap_penalty = 0.0 + support_count = 0 + for item in objects: + if item is subject_box: + continue + ix0 = float(item.get("x", 0) or 0) + iy0 = float(item.get("y", 0) or 0) + ix1 = ix0 + float(item.get("width", 0) or 0) + iy1 = iy0 + float(item.get("height", 0) or 0) + overlap_w = max(0.0, min(ix1, sx1) - max(ix0, sx0)) + overlap_h = max(0.0, min(iy1, sy1) - max(iy0, sy0)) + if overlap_w * overlap_h <= 0: + continue + support_count += 1 + overlap_ratio = (overlap_w * overlap_h) / max(1.0, (sx1 - sx0) * (sy1 - sy0)) + support_overlap_penalty += overlap_ratio + if support_count: + semantic_score *= max(0.55, 1.0 - (support_overlap_penalty / support_count) * 0.9) + + naturalness = ( + focus_score * 0.26 + + layering_score * 0.18 + + negative_space_score * 0.14 + + (1.0 - symmetry_penalty) * 0.08 + + connector_penalty * 0.06 + + (1.0 - uniformity_penalty) * 0.06 + + semantic_score * 0.22 + ) + features = { + "focus_score": round(focus_score, 3), + "layering_score": round(layering_score, 3), + "negative_space_score": round(negative_space_score, 3), + "symmetry_penalty": round(symmetry_penalty, 3), + "connector_penalty": round(connector_penalty, 3), + "uniformity_penalty": round(uniformity_penalty, 3), + "semantic_score": round(semantic_score, 3), + } + return round(naturalness, 4), features + + +def _apply_candidate_to_objects(scene: Dict[str, Any], candidate: Dict[str, Any]) -> None: + updates = candidate.get("object_updates") if isinstance(candidate.get("object_updates"), dict) else {} + for item in scene.get("object_instances", []) or []: + object_id = _clean_text(item.get("id")) + payload = updates.get(object_id) if object_id else None + if not isinstance(payload, dict): + continue + item["x"] = int(payload.get("x", item.get("x", 0))) + item["y"] = int(payload.get("y", item.get("y", 0))) + item["width"] = int(payload.get("width", item.get("width", 120))) + item["height"] = int(payload.get("height", item.get("height", 100))) + item["rotation"] = float(payload.get("rotation", item.get("rotation", 0.0) or 0.0)) + item["depth_band"] = str(payload.get("depth_band", item.get("depth_band", "midground"))) + item["z_index"] = int(payload.get("z_index", item.get("z_index", 20))) + + +def _manual_layout_payload(scene: Dict[str, Any]) -> Dict[str, Any]: + objects = [_copy(item) for item in scene.get("object_instances", []) or []] + score, features = _score_layout(scene, objects) + return { + "id": str(scene.get("layout_candidate_id") or "manual"), + "score": score, + "features": features, + "camera_bias": _copy(scene.get("camera_bias") or {"focus_x": 0.5, "focus_y": 0.5, "perspective_strength": 0.4}), + "negative_space_mask": _copy(scene.get("negative_space_mask") or _negative_space_mask(scene, objects)), + "object_updates": { + str(item.get("id")): { + "x": int(item.get("x", 0)), + "y": int(item.get("y", 0)), + "width": int(item.get("width", 120)), + "height": int(item.get("height", 100)), + "rotation": float(item.get("rotation", 0.0) or 0.0), + "depth_band": str(item.get("depth_band", "midground")), + "z_index": int(item.get("z_index", 20)), + } + for item in objects + if item.get("id") + }, + } + + +def apply_natural_layout(scene_spec: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + scene = _copy(scene_spec or {}) + scene.setdefault("layout_options", {}) + layout_options = scene["layout_options"] + scene_type = _clean_text(layout_options.get("scene_type") or "scene") + resolved_engine = resolve_layout_engine(scene, sketch_options) + model_runtime = _layout_model_runtime() + runtime_status = _copy(model_runtime.status()) + scene.setdefault("render_hints", {}) + layout_options["layout_engine"] = resolved_engine + layout_options["layout_model_status"] = runtime_status + if resolved_engine != "natural_layout_v1" or not (scene.get("object_instances") or []): + scene["layout_engine"] = "mechanical_layout_v1" if resolved_engine == "mechanical_layout_v1" else resolved_engine + scene.setdefault("layout_candidate_id", "mechanical") + scene.setdefault("layout_score", 0.0) + scene.setdefault("layout_features", {}) + scene.setdefault("camera_bias", {"focus_x": 0.5, "focus_y": 0.5, "perspective_strength": 0.3}) + scene.setdefault("negative_space_mask", []) + scene["render_hints"]["layout_runtime"] = { + **runtime_status, + "fallback_used": True, + "selected_source": "mechanical" if resolved_engine == "mechanical_layout_v1" else "bypass", + } + return scene + + if bool(layout_options.get("layout_manual_override")): + current = _manual_layout_payload(scene) + scene["layout_engine"] = "natural_layout_v1" + scene["layout_candidate_id"] = current["id"] + scene["layout_score"] = current["score"] + scene["layout_features"] = current["features"] + scene["camera_bias"] = current["camera_bias"] + scene["negative_space_mask"] = current["negative_space_mask"] + scene["layout_candidates"] = [current] + scene["render_hints"]["layout_runtime"] = { + **runtime_status, + "fallback_used": False, + "selected_source": "manual_override", + "selected_candidate_id": current["id"], + } + return scene + + candidate_count = resolve_layout_candidate_count(scene, sketch_options) + locked_ids = { + str(item.get("id")) + for item in scene.get("object_instances", []) or [] + if item.get("layout_locked") and item.get("id") + } + candidates: List[Dict[str, Any]] = [] + for candidate_index in range(candidate_count): + candidate = { + "id": f"layout_{candidate_index + 1}", + "object_updates": _candidate_object_updates(scene, scene_type, locked_ids, candidate_index=candidate_index), + "camera_bias": { + "focus_x": round(0.36 + 0.08 * (candidate_index % 3), 3), + "focus_y": round(0.42 + 0.05 * ((candidate_index + 1) % 2), 3), + "perspective_strength": round(0.34 + 0.08 * (candidate_index % 4), 3), + }, + } + preview_scene = _copy(scene) + _apply_candidate_to_objects(preview_scene, candidate) + score, features = _score_layout(preview_scene, list(preview_scene.get("object_instances", []) or [])) + candidate["score"] = score + candidate["features"] = features + candidate["negative_space_mask"] = _negative_space_mask(preview_scene, list(preview_scene.get("object_instances", []) or [])) + candidates.append(candidate) + + model_candidate = model_runtime.build_candidate(scene, scene_type, locked_ids) + if isinstance(model_candidate, dict): + preview_scene = _copy(scene) + _apply_candidate_to_objects(preview_scene, model_candidate) + heuristic_score, heuristic_features = _score_layout(preview_scene, list(preview_scene.get("object_instances", []) or [])) + model_score = float(model_candidate.get("model_score", 0.0) or 0.0) + combined_score = round(heuristic_score * 0.58 + model_score * 0.42, 4) + model_candidate["score"] = combined_score + model_candidate["features"] = { + **heuristic_features, + "model_score": round(model_score, 3), + "heuristic_score": round(heuristic_score, 3), + "score_source": "proposal_ranker+heuristic", + } + model_candidate["negative_space_mask"] = _negative_space_mask(preview_scene, list(preview_scene.get("object_instances", []) or [])) + candidates.append(model_candidate) + + requested_id = _clean_text(scene.get("layout_candidate_id") or layout_options.get("layout_candidate_id")) + candidate_map = {candidate["id"]: candidate for candidate in candidates} + chosen = candidate_map.get(requested_id) + fallback_used = False + if chosen is None: + chosen = max(candidates, key=lambda item: float(item.get("score", 0.0) or 0.0)) + fallback_used = isinstance(model_candidate, dict) and str(chosen.get("id", "")) != str(model_candidate.get("id", "")) + _apply_candidate_to_objects(scene, chosen) + scene["layout_engine"] = "natural_layout_v1" + scene["layout_candidate_id"] = str(chosen["id"]) + scene["layout_score"] = float(chosen.get("score", 0.0) or 0.0) + scene["layout_features"] = _copy(chosen.get("features") or {}) + scene["camera_bias"] = _copy(chosen.get("camera_bias") or {}) + scene["negative_space_mask"] = _copy(chosen.get("negative_space_mask") or []) + scene["render_hints"]["layout_runtime"] = { + **runtime_status, + "fallback_used": fallback_used, + "selected_candidate_id": str(chosen["id"]), + "selected_source": "model_candidate" if "model" in str(chosen.get("id", "")).lower() else "heuristic_candidate", + } + scene["layout_candidates"] = [ + { + "id": str(candidate["id"]), + "score": float(candidate.get("score", 0.0) or 0.0), + "features": _copy(candidate.get("features") or {}), + "camera_bias": _copy(candidate.get("camera_bias") or {}), + "negative_space_mask": _copy(candidate.get("negative_space_mask") or []), + "object_updates": _copy(candidate.get("object_updates") or {}), + } + for candidate in sorted(candidates, key=lambda item: float(item.get("score", 0.0) or 0.0), reverse=True) + ] + return scene diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout_trainer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout_trainer.py new file mode 100644 index 0000000..7452c3b --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/natural_layout_trainer.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Dict, List, Sequence + +try: + import torch + from torch import nn +except Exception: # pragma: no cover + torch = None + nn = None + + +ROLE_PRIORITIES = { + "subject": 1.0, + "focus": 1.0, + "core_subject": 1.0, + "support": 0.72, + "environment": 0.62, + "detail": 0.48, +} +DEPTH_VALUES = {"background": 0.2, "midground": 0.55, "foreground": 0.9} +SCENE_VALUES = {"scene": 0.2, "process": 0.6, "schematic": 0.9} + + +@dataclass(slots=True) +class NaturalLayoutTrainerConfig: + max_objects: int = 12 + feature_dim: int = 10 + hidden_dim: int = 128 + + +if nn is not None: + class NaturalLayoutProposalNet(nn.Module): + def __init__(self, config: NaturalLayoutTrainerConfig): + super().__init__() + self.config = config + input_dim = config.max_objects * config.feature_dim + self.net = nn.Sequential( + nn.Linear(input_dim, config.hidden_dim), + nn.GELU(), + nn.Linear(config.hidden_dim, config.hidden_dim), + nn.GELU(), + nn.Linear(config.hidden_dim, config.max_objects * 5), + ) + + def forward(self, features): # type: ignore[override] + batch = features.shape[0] + output = self.net(features.reshape(batch, -1)) + return output.reshape(batch, self.config.max_objects, 5) + + + class NaturalLayoutRanker(nn.Module): + def __init__(self, config: NaturalLayoutTrainerConfig): + super().__init__() + input_dim = config.max_objects * (config.feature_dim + 5) + self.net = nn.Sequential( + nn.Linear(input_dim, config.hidden_dim), + nn.GELU(), + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 1), + ) + + def forward(self, features, boxes): # type: ignore[override] + batch = features.shape[0] + merged = torch.cat([features, boxes], dim=-1) + return self.net(merged.reshape(batch, -1)).squeeze(-1) +else: # pragma: no cover + class NaturalLayoutProposalNet: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use NaturalLayoutProposalNet") + + + class NaturalLayoutRanker: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use NaturalLayoutRanker") + + +def _role_value(value: Any) -> float: + return ROLE_PRIORITIES.get(str(value or "").strip(), 0.4) + + +def _depth_value(value: Any) -> float: + return DEPTH_VALUES.get(str(value or "").strip(), 0.55) + + +def _scene_value(value: Any) -> float: + return SCENE_VALUES.get(str(value or "").strip(), 0.2) + + +def encode_layout_row(row: Dict[str, Any], *, max_objects: int = 12) -> Dict[str, Any]: + layout_condition = row.get("layout_condition") or {} + objects = list(layout_condition.get("objects") or row.get("objects") or []) + boxes = list(row.get("object_boxes") or []) + relation_graph = list(row.get("relation_graph") or []) + canvas = layout_condition.get("canvas_size") or {"width": 1024, "height": 768} + width = max(1.0, float(canvas.get("width", 1024) or 1024)) + height = max(1.0, float(canvas.get("height", 768) or 768)) + degree_map: Dict[str, int] = {} + for edge in relation_graph: + source = str(edge.get("source") or "") + target = str(edge.get("target") or "") + if source: + degree_map[source] = degree_map.get(source, 0) + 1 + if target: + degree_map[target] = degree_map.get(target, 0) + 1 + feature_rows: List[List[float]] = [] + target_boxes: List[List[float]] = [] + mask: List[float] = [] + scene_value = _scene_value(layout_condition.get("scene_type") or row.get("scene_type")) + for index in range(max_objects): + if index < len(boxes): + box = boxes[index] + meta = objects[index] if index < len(objects) else {} + object_id = str(meta.get("id") or box.get("id") or f"obj_{index}") + x = float(box.get("x", 0.0)) / width + y = float(box.get("y", 0.0)) / height + w = float(box.get("width", 0.0)) / width + h = float(box.get("height", 0.0)) / height + rotation = float(box.get("rotation", 0.0)) / 45.0 + role = _role_value(meta.get("role")) + is_subject = 1.0 if role >= 0.95 else 0.0 + depth = _depth_value(meta.get("depth_band") or box.get("depth_band")) + degree = min(1.0, degree_map.get(object_id, 0) / 6.0) + importance = float(meta.get("importance", 1.0) or 1.0) + importance = max(0.0, min(1.0, importance / 3.0 if importance > 1.0 else importance)) + feature_rows.append([x, y, w, h, role, is_subject, depth, degree, scene_value, importance]) + target_boxes.append([x, y, w, h, rotation]) + mask.append(1.0) + else: + feature_rows.append([0.0] * 10) + target_boxes.append([0.0] * 5) + mask.append(0.0) + return { + "features": feature_rows, + "target_boxes": target_boxes, + "mask": mask, + "quality": float(row.get("layout_quality_score", row.get("naturalness_score", 0.8)) or 0.8), + "scene_type": str(layout_condition.get("scene_type") or row.get("scene_type") or "scene"), + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/__init__.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/__init__.py new file mode 100644 index 0000000..418f24f --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/__init__.py @@ -0,0 +1,6 @@ +"""NLG helpers for TMCRA.""" + +from .pattern_bank import PatternBank +from .path_realizer import realize_answer + +__all__ = ["PatternBank", "realize_answer"] diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/path_realizer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/path_realizer.py new file mode 100644 index 0000000..08e68e6 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/path_realizer.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +import random +from typing import List + +from .pattern_bank import PatternBank + + +RELATION_CATEGORY_MAP = { + "导致": "causal", + "引起": "causal", + "造成": "causal", + "使得": "causal", + "触发": "causal", + "产生": "causal", + "因为": "causal", + "由于": "causal", + "causes": "causal", + "cause": "causal", + "leads to": "causal", + "lead to": "causal", + "results in": "causal", + "result in": "causal", + "drives": "causal", + "trigger": "causal", + "组成": "structural", + "构成": "structural", + "包含": "structural", + "包括": "structural", + "属于": "structural", + "是": "structural", + "具有": "property", + "具备": "property", + "属性": "property", + "特性": "property", + "used for": "functional", + "used to": "functional", + "用于": "functional", + "用来": "functional", + "适用于": "functional", + "能够": "functional", + "限制": "limiting", + "阻止": "limiting", + "抑制": "limiting", + "阻碍": "limiting", + "相关": "generic", + "related": "generic", + "related to": "generic", +} + +FALLBACK_PATTERNS = { + "causal": "{X}会导致{Y}", + "structural": "{X}由{Y}组成", + "property": "{X}具有{Y}", + "functional": "{X}用于{Y}", + "limiting": "{X}限制{Y}", + "generic": "{X}与{Y}相关", +} + + +def _category_for_relation(relation: str) -> str: + lowered = relation.lower() + for key, category in RELATION_CATEGORY_MAP.items(): + if key.lower() in lowered: + return category + return "generic" + + +def _realize_edge(pattern_bank: PatternBank, source: str, relation: str, target: str) -> str: + category = _category_for_relation(relation) + pattern = pattern_bank.pick(category) or FALLBACK_PATTERNS.get(category) + if not pattern: + pattern = "{X}与{Y}相关" + return pattern.replace("{X}", source).replace("{Y}", target) + + +def _decorate_with_connector(pattern_bank: PatternBank, sentence: str) -> str: + if not sentence: + return sentence + if random.random() < 0.6: + connector = pattern_bank.pick_connector() + if connector: + if sentence.startswith(connector): + return sentence + return f"{connector},{sentence}" + return sentence + + +def realize_answer( + query: str, + concepts: List[str], + relations: List[str], + pattern_bank: PatternBank, + *, + intent: str = "general", +) -> str: + sentences: List[str] = [] + if concepts and relations and len(concepts) == len(relations) + 1: + for idx, relation in enumerate(relations): + sentence = _realize_edge(pattern_bank, concepts[idx], relation, concepts[idx + 1]) + sentences.append(sentence) + else: + for idx in range(len(concepts) - 1): + sentences.append(_realize_edge(pattern_bank, concepts[idx], "相关", concepts[idx + 1])) + + if not sentences: + return "暂未形成足够的概念关系,建议补充语料或知识库。" + + decorated: List[str] = [] + for idx, sentence in enumerate(sentences): + if idx == 0: + decorated.append(sentence) + else: + decorated.append(_decorate_with_connector(pattern_bank, sentence)) + + intro = pattern_bank.pick_intro(intent) + if not intro: + if intent == "necessity": + intro = "需要这样做的原因是:" + elif intent == "explanation": + intro = "其机理可以概括为:" + elif intent == "how_to": + intro = "关键步骤与原因如下:" + else: + intro = "" + + body = "。".join(decorated) + if intro: + return f"{intro}{body}。" + return f"{body}。" diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/pattern_bank.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/pattern_bank.py new file mode 100644 index 0000000..a34e6c1 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/nlg/pattern_bank.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import json +import random +from pathlib import Path +from typing import Dict, List, Optional + + +class PatternBank: + """Lightweight pattern bank for relation-to-sentence patterns.""" + + def __init__(self, patterns: Dict[str, List[Dict]], meta: Optional[Dict] = None) -> None: + self.patterns = patterns + self.meta = meta or {} + + @classmethod + def load(cls, path: str) -> "PatternBank": + file_path = Path(path) + if not file_path.exists(): + return cls({}) + with file_path.open("r", encoding="utf-8") as handle: + data = json.load(handle) + if isinstance(data, dict) and "_meta" in data: + meta = data.get("_meta") or {} + patterns = {k: v for k, v in data.items() if k != "_meta"} + return cls(patterns or {}, meta=meta) + return cls(data or {}) + + def pick(self, category: str, *, top_k: int = 6) -> Optional[str]: + items = self.patterns.get(category, []) + if not items: + return None + items = sorted(items, key=lambda item: -item.get("count", 0)) + pool = items[: max(top_k, 1)] + weights = [max(item.get("count", 1), 1) for item in pool] + return random.choices([item.get("pattern") for item in pool], weights=weights, k=1)[0] + + def pick_connector(self) -> Optional[str]: + connectors = self.meta.get("connectors", []) + if not connectors: + return None + connectors = sorted(connectors, key=lambda item: -item.get("count", 0)) + pool = connectors[:6] + weights = [max(item.get("count", 1), 1) for item in pool] + return random.choices([item.get("text") for item in pool], weights=weights, k=1)[0] + + def pick_intro(self, intent: str) -> Optional[str]: + intros = self.meta.get("intros", {}).get(intent) + if not intros: + return None + intros = sorted(intros, key=lambda item: -item.get("count", 0)) + pool = intros[:4] + weights = [max(item.get("count", 1), 1) for item in pool] + return random.choices([item.get("text") for item in pool], weights=weights, k=1)[0] diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_backend.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_backend.py new file mode 100644 index 0000000..840b8d4 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_backend.py @@ -0,0 +1,578 @@ +from __future__ import annotations + +import json +import math +import os +from collections import Counter +from functools import lru_cache +from pathlib import Path +from typing import Any, Dict, Iterable, List, Sequence + +from .sketch_style_spec import ( + build_stroke_style_profile, + default_part_graph, + default_readability_rank, + default_region_masks, + infer_sketch_family, +) +from .visual_prototypes import FAMILY_FALLBACKS, resolve_visual_prototype +from .default_model_paths import ( + LEGACY_OBJECT_STROKE_VARIANTS_PATH, + LEGACY_OBJECT_VARIANTS_PATH, + resolve_default_object_stroke_variants_path, + resolve_default_object_variants_path, +) + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +DATA_DIR = PROJECT_ROOT / "data" / "object_sketch" +DEFAULT_EXPORTED_VARIANTS_PATH = LEGACY_OBJECT_VARIANTS_PATH +DEFAULT_EXPORTED_STROKE_VARIANTS_PATH = LEGACY_OBJECT_STROKE_VARIANTS_PATH +EXPORTED_VARIANTS_PATH = DEFAULT_EXPORTED_VARIANTS_PATH +PUBLIC_SEED_PATH = DATA_DIR / "public_seed_dataset.jsonl" +MANUAL_SEED_PATH = DATA_DIR / "manual_seed_dataset.jsonl" + +DEMO_BACKEND_MODE = "hybrid_demo" +SCENE_OBJECT_CLASSES = ("building", "house", "window", "door", "tree", "cloud", "sun", "person", "car", "street_lamp", "table", "chair", "dog", "desk_lamp", "road") +PROCESS_MOTIF_CLASSES = ("cycle", "flow_node", "energy_wave", "vapor", "leaf", "raindrop", "airplane", "cell", "branch", "module") +SCHEMATIC_SYMBOL_CLASSES = ("battery", "led", "resistor", "capacitor", "diode", "board", "module", "branch", "flow_node") +TRAINED_DEMO_CLASSES = tuple(dict.fromkeys([*SCENE_OBJECT_CLASSES, *PROCESS_MOTIF_CLASSES, *SCHEMATIC_SYMBOL_CLASSES]).keys()) +CLASS_SCENE_MAP = {item: "scene" for item in SCENE_OBJECT_CLASSES} | {item: "process" for item in PROCESS_MOTIF_CLASSES} | {item: "schematic" for item in SCHEMATIC_SYMBOL_CLASSES} +STYLE_VARIANTS = ({"id": "scribble_line", "label": "Scribble line"}, {"id": "clean_line", "label": "Clean line"}) + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def resolve_exported_variants_path() -> Path: + override = os.getenv("TMCRA_OBJECT_VARIANTS_PATH", "").strip() + if override: + return Path(override).expanduser() + return resolve_default_object_variants_path() + + +def resolve_exported_stroke_variants_path() -> Path: + override = os.getenv("TMCRA_OBJECT_STROKE_VARIANTS_PATH", "").strip() + if override: + return Path(override).expanduser() + return resolve_default_object_stroke_variants_path() + + +def _normalize_stroke_payload(payload: Any) -> List[List[List[float]]]: + strokes: List[List[List[float]]] = [] + for stroke in payload if isinstance(payload, list) else []: + if not isinstance(stroke, list): + continue + cleaned: List[List[float]] = [] + for point in stroke: + if not isinstance(point, (list, tuple)) or len(point) < 2: + continue + cleaned.append([max(0.0, min(1.0, float(point[0]))), max(0.0, min(1.0, float(point[1])))]) + if len(cleaned) >= 2: + strokes.append(cleaned) + return strokes + + +def _resolve_sketch_engine() -> str: + raw = str(os.getenv("TMCRA_SKETCH_ENGINE", "auto") or "auto").strip().lower() + if raw in {"mechanical", "mechanical_v1"}: + return "mechanical_v1" + if raw in {"natural", "natural_v1"}: + return "natural_v1" + return "auto" + + +def _shape(parts: List[Dict[str, Any]]) -> Dict[str, Any]: + return {"version": 1, "viewbox": [0, 0, 1, 1], "parts": parts} + + +def _rect(x: float, y: float, w: float, h: float, *, rx: float = 0.0, fill_role: str = "fill", stroke_role: str = "line", stroke_width: float = 0.02) -> Dict[str, Any]: + return {"kind": "rect", "x": x, "y": y, "w": w, "h": h, "rx": rx, "fill_role": fill_role, "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} + + +def _ellipse(x: float, y: float, w: float, h: float, *, fill_role: str = "fill", stroke_role: str = "line", stroke_width: float = 0.02) -> Dict[str, Any]: + return {"kind": "ellipse", "x": x, "y": y, "w": w, "h": h, "fill_role": fill_role, "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} + + +def _line(x1: float, y1: float, x2: float, y2: float, *, stroke_role: str = "line", stroke_width: float = 0.02, dash: List[float] | None = None) -> Dict[str, Any]: + part = {"kind": "line", "x1": x1, "y1": y1, "x2": x2, "y2": y2, "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} + if dash: + part["dash"] = list(dash) + return part + + +def _polygon(points: Sequence[Sequence[float]], *, fill_role: str = "fill", stroke_role: str = "line", stroke_width: float = 0.02) -> Dict[str, Any]: + return {"kind": "polygon", "points": [[float(px), float(py)] for px, py in points], "fill_role": fill_role, "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} + + +def _polyline(points: Sequence[Sequence[float]], *, stroke_role: str = "line", stroke_width: float = 0.02) -> Dict[str, Any]: + return {"kind": "polyline", "points": [[float(px), float(py)] for px, py in points], "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} + + +def _variant(asset_key: str, suffix: str, label: str, parts: List[Dict[str, Any]], *, scene_type: str = "", source: str = "demo_library", confidence: float = 0.82) -> Dict[str, Any]: + resolved_scene = scene_type or CLASS_SCENE_MAP.get(asset_key, "scene") + family = infer_sketch_family(asset_key, scene_type=resolved_scene) + return { + "id": f"{asset_key}:{suffix}", + "label": label, + "asset_key": asset_key, + "shape_recipe": _shape(parts), + "source": source, + "confidence": float(confidence), + "style_variants": [item["id"] for item in STYLE_VARIANTS], + "default_style": "scribble_line", + "part_graph": default_part_graph(asset_key, scene_type=resolved_scene), + "region_masks": default_region_masks(asset_key, scene_type=resolved_scene), + "stroke_style_profile": build_stroke_style_profile(asset_key, scene_type=resolved_scene, style_variant="scribble_line", sketch_family=family), + "readability_rank": default_readability_rank(asset_key, scene_type=resolved_scene), + "sketch_family": family, + } + + +def _fallback_variant(asset_key: str, concept: str = "", scene_type: str = "scene") -> Dict[str, Any]: + prototype = resolve_visual_prototype(asset_key, concept, scene_type) + family = infer_sketch_family(asset_key, scene_type=scene_type) + return { + "id": f"{asset_key}:rule_base", + "label": f"{asset_key} base", + "asset_key": asset_key, + "shape_recipe": _copy(prototype.get("shape_recipe", {})), + "source": "rule_prototype", + "confidence": 0.64 if asset_key not in TRAINED_DEMO_CLASSES else 0.78, + "style_variants": [item["id"] for item in STYLE_VARIANTS], + "default_style": "scribble_line", + "part_graph": default_part_graph(asset_key, scene_type=scene_type), + "region_masks": default_region_masks(asset_key, scene_type=scene_type), + "stroke_style_profile": build_stroke_style_profile(asset_key, scene_type=scene_type, style_variant="scribble_line", sketch_family=family), + "readability_rank": default_readability_rank(asset_key, scene_type=scene_type), + "sketch_family": family, + } + + +@lru_cache(maxsize=1) +def _builtin_variant_library() -> Dict[str, List[Dict[str, Any]]]: + library = { + "building": [_variant("building", "city_block", "City block", [_rect(0.12, 0.1, 0.76, 0.88, rx=0.03), _rect(0.22, 0.2, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.42, 0.2, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.62, 0.2, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.44, 0.72, 0.12, 0.24, fill_role="none", stroke_role="accent", stroke_width=0.014)], confidence=0.84)], + "house": [_variant("house", "gable", "Gable house", [_polygon([[0.5, 0.02], [0.08, 0.34], [0.92, 0.34]]), _rect(0.16, 0.34, 0.68, 0.62, rx=0.03), _rect(0.42, 0.58, 0.16, 0.38, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.24, 0.46, 0.12, 0.12, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.64, 0.46, 0.12, 0.12, fill_role="none", stroke_role="accent", stroke_width=0.014)], confidence=0.84)], + "window": [_variant("window", "cross", "Window", [_rect(0.08, 0.08, 0.84, 0.84, rx=0.04), _line(0.5, 0.1, 0.5, 0.9, stroke_role="accent", stroke_width=0.018), _line(0.1, 0.5, 0.9, 0.5, stroke_role="accent", stroke_width=0.018)], confidence=0.84)], + "door": [_variant("door", "rounded", "Rounded door", [_rect(0.14, 0.06, 0.72, 0.9, rx=0.14), _ellipse(0.7, 0.5, 0.06, 0.06, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01)], confidence=0.82)], + "tree": [_variant("tree", "round_canopy", "Round canopy", [_rect(0.44, 0.58, 0.12, 0.38, fill_role="region_alt", stroke_role="line", stroke_width=0.018), _ellipse(0.22, 0.16, 0.56, 0.42), _ellipse(0.08, 0.34, 0.28, 0.24), _ellipse(0.62, 0.32, 0.22, 0.22)], confidence=0.86)], + "cloud": [_variant("cloud", "puffy", "Puffy cloud", [_ellipse(0.06, 0.42, 0.3, 0.26), _ellipse(0.28, 0.2, 0.34, 0.34), _ellipse(0.54, 0.36, 0.28, 0.24), _line(0.16, 0.72, 0.78, 0.72, stroke_width=0.016)], confidence=0.87)], + "sun": [_variant("sun", "classic", "Classic sun", [_ellipse(0.24, 0.24, 0.52, 0.52), _line(0.5, 0.0, 0.5, 0.18, stroke_role="accent", stroke_width=0.018), _line(0.5, 0.82, 0.5, 1.0, stroke_role="accent", stroke_width=0.018), _line(0.0, 0.5, 0.18, 0.5, stroke_role="accent", stroke_width=0.018), _line(0.82, 0.5, 1.0, 0.5, stroke_role="accent", stroke_width=0.018)], confidence=0.87)], + "person": [_variant("person", "standing", "Standing person", [_ellipse(0.36, 0.04, 0.28, 0.22), _line(0.5, 0.28, 0.5, 0.68, stroke_width=0.024), _line(0.5, 0.38, 0.24, 0.52, stroke_width=0.02), _line(0.5, 0.38, 0.76, 0.52, stroke_width=0.02), _line(0.5, 0.68, 0.26, 0.98, stroke_width=0.02), _line(0.5, 0.68, 0.74, 0.98, stroke_width=0.02)], confidence=0.86)], + "car": [_variant("car", "sedan", "Sedan", [_rect(0.08, 0.42, 0.84, 0.3, rx=0.12), _polygon([[0.24, 0.42], [0.36, 0.18], [0.7, 0.18], [0.82, 0.42]]), _ellipse(0.2, 0.72, 0.18, 0.18, fill_role="region_alt", stroke_width=0.018), _ellipse(0.62, 0.72, 0.18, 0.18, fill_role="region_alt", stroke_width=0.018)], confidence=0.87)], + "street_lamp": [_variant("street_lamp", "classic", "Classic lamp", [_line(0.5, 0.98, 0.5, 0.14, stroke_width=0.034), _line(0.5, 0.16, 0.86, 0.16, stroke_width=0.026), _ellipse(0.76, 0.22, 0.14, 0.14, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01)], confidence=0.84)], + "table": [_variant("table", "desk", "Desk", [_rect(0.1, 0.18, 0.8, 0.16, rx=0.04), _line(0.2, 0.34, 0.2, 0.96, stroke_width=0.028), _line(0.8, 0.34, 0.8, 0.96, stroke_width=0.028)], confidence=0.83)], + "chair": [_variant("chair", "straight", "Straight chair", [_rect(0.28, 0.12, 0.34, 0.2, rx=0.06), _line(0.3, 0.32, 0.3, 0.96, stroke_width=0.024), _line(0.62, 0.32, 0.62, 0.96, stroke_width=0.024), _line(0.62, 0.14, 0.8, 0.02, stroke_width=0.022), _line(0.8, 0.02, 0.8, 0.68, stroke_width=0.022)], confidence=0.83)], + "dog": [_variant("dog", "standing", "Standing dog", [_ellipse(0.2, 0.34, 0.54, 0.3), _ellipse(0.66, 0.24, 0.22, 0.18), _line(0.26, 0.64, 0.22, 0.98, stroke_width=0.022), _line(0.44, 0.64, 0.42, 0.98, stroke_width=0.022), _line(0.62, 0.64, 0.62, 0.98, stroke_width=0.022), _line(0.16, 0.42, 0.04, 0.24, stroke_width=0.022)], confidence=0.82)], + "desk_lamp": [_variant("desk_lamp", "task", "Task lamp", [_line(0.38, 0.98, 0.48, 0.62, stroke_width=0.028), _line(0.48, 0.62, 0.64, 0.34, stroke_width=0.024), _polygon([[0.58, 0.28], [0.8, 0.18], [0.72, 0.42]], fill_role="none", stroke_role="line", stroke_width=0.022), _ellipse(0.16, 0.9, 0.32, 0.08, fill_role="region_alt")], confidence=0.82)], + "road": [_variant("road", "perspective", "Perspective road", [_polygon([[0.32, 0.18], [0.68, 0.18], [0.94, 0.96], [0.06, 0.96]], fill_role="region_alt"), _line(0.5, 0.26, 0.5, 0.94, stroke_role="accent", stroke_width=0.016, dash=[0.06])], confidence=0.82)], + "cycle": [_variant("cycle", "loop", "Cycle loop", [_ellipse(0.16, 0.18, 0.68, 0.68, fill_role="none", stroke_role="line", stroke_width=0.028), _polygon([[0.62, 0.18], [0.88, 0.28], [0.7, 0.42]], fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), _polygon([[0.22, 0.82], [0.1, 0.58], [0.34, 0.64]], fill_role="accent_fill", stroke_role="accent", stroke_width=0.01)], scene_type="process", confidence=0.84)], + "flow_node": [_variant("flow_node", "stage_card", "Stage node", [_rect(0.12, 0.2, 0.76, 0.52, rx=0.16), _line(0.24, 0.34, 0.76, 0.34, stroke_role="accent", stroke_width=0.018), _line(0.24, 0.52, 0.62, 0.52, stroke_width=0.016), _line(0.78, 0.46, 0.9, 0.46, stroke_role="accent", stroke_width=0.016)], scene_type="process", confidence=0.82)], + "energy_wave": [_variant("energy_wave", "arc", "Energy arc", [_polyline([[0.08, 0.68], [0.24, 0.48], [0.4, 0.62], [0.56, 0.34], [0.72, 0.48], [0.9, 0.2]], stroke_role="accent", stroke_width=0.032), _polyline([[0.12, 0.84], [0.3, 0.68], [0.46, 0.82], [0.62, 0.56], [0.78, 0.68]], stroke_width=0.018)], scene_type="process", confidence=0.8)], + "vapor": [_variant("vapor", "steam", "Steam plume", [_polyline([[0.28, 0.92], [0.24, 0.72], [0.32, 0.54], [0.26, 0.34], [0.36, 0.16]], stroke_width=0.026), _polyline([[0.48, 0.92], [0.44, 0.68], [0.54, 0.5], [0.46, 0.28], [0.58, 0.08]], stroke_width=0.026), _polyline([[0.68, 0.92], [0.64, 0.72], [0.72, 0.56], [0.66, 0.36], [0.74, 0.18]], stroke_width=0.026)], scene_type="process", confidence=0.82)], + "leaf": [_variant("leaf", "simple", "Leaf", [_polygon([[0.5, 0.04], [0.82, 0.48], [0.5, 0.96], [0.18, 0.48]]), _line(0.5, 0.1, 0.5, 0.9, stroke_role="accent", stroke_width=0.016), _line(0.5, 0.44, 0.72, 0.28, stroke_role="accent", stroke_width=0.012)], scene_type="process", confidence=0.82)], + "raindrop": [_variant("raindrop", "drop", "Raindrop", [_polygon([[0.5, 0.02], [0.78, 0.42], [0.66, 0.82], [0.34, 0.82], [0.22, 0.42]])], scene_type="process", confidence=0.82)], + "airplane": [_variant("airplane", "jet", "Jet", [_polyline([[0.08, 0.5], [0.52, 0.5], [0.72, 0.3], [0.88, 0.36], [0.7, 0.5], [0.88, 0.64], [0.72, 0.7], [0.52, 0.5]], stroke_width=0.028), _line(0.42, 0.5, 0.28, 0.24, stroke_width=0.02), _line(0.42, 0.5, 0.28, 0.76, stroke_width=0.02)], scene_type="process", confidence=0.82)], + "cell": [_variant("cell", "nucleus", "Cell", [_ellipse(0.08, 0.12, 0.84, 0.76), _ellipse(0.36, 0.32, 0.28, 0.24, fill_role="region_alt"), _ellipse(0.26, 0.26, 0.12, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014)], scene_type="process", confidence=0.82)], + "battery": [_variant("battery", "cell", "Battery cell", [_line(0.08, 0.5, 0.34, 0.5, stroke_width=0.022), _line(0.42, 0.18, 0.42, 0.82, stroke_width=0.026), _line(0.58, 0.28, 0.58, 0.72, stroke_width=0.02), _line(0.66, 0.5, 0.92, 0.5, stroke_width=0.022)], scene_type="schematic", confidence=0.84)], + "led": [_variant("led", "symbol", "LED symbol", [_line(0.06, 0.5, 0.22, 0.5, stroke_width=0.022), _polygon([[0.24, 0.2], [0.24, 0.8], [0.62, 0.5]]), _line(0.68, 0.18, 0.68, 0.82, stroke_width=0.024), _line(0.68, 0.5, 0.94, 0.5, stroke_width=0.022), _line(0.66, 0.24, 0.86, 0.1, stroke_role="accent", stroke_width=0.016), _line(0.62, 0.46, 0.86, 0.26, stroke_role="accent", stroke_width=0.016)], scene_type="schematic", confidence=0.84)], + "resistor": [_variant("resistor", "zigzag", "Resistor", [_line(0.04, 0.5, 0.18, 0.5, stroke_width=0.022), _polyline([[0.18, 0.5], [0.28, 0.24], [0.4, 0.76], [0.52, 0.24], [0.64, 0.76], [0.76, 0.24], [0.86, 0.5]], stroke_width=0.024), _line(0.86, 0.5, 0.98, 0.5, stroke_width=0.022)], scene_type="schematic", confidence=0.83)], + "capacitor": [_variant("capacitor", "parallel", "Capacitor", [_line(0.08, 0.5, 0.36, 0.5, stroke_width=0.022), _line(0.42, 0.18, 0.42, 0.82, stroke_width=0.026), _line(0.58, 0.18, 0.58, 0.82, stroke_width=0.026), _line(0.64, 0.5, 0.92, 0.5, stroke_width=0.022)], scene_type="schematic", confidence=0.82)], + "diode": [_variant("diode", "standard", "Diode", [_line(0.06, 0.5, 0.22, 0.5, stroke_width=0.022), _polygon([[0.24, 0.22], [0.24, 0.78], [0.6, 0.5]]), _line(0.64, 0.18, 0.64, 0.82, stroke_width=0.024), _line(0.66, 0.5, 0.94, 0.5, stroke_width=0.022)], scene_type="schematic", confidence=0.82)], + "board": [_variant("board", "chip", "Board module", [_rect(0.12, 0.14, 0.76, 0.72, rx=0.06), _rect(0.24, 0.26, 0.28, 0.22, fill_role="none", stroke_role="accent", stroke_width=0.014), _rect(0.58, 0.28, 0.14, 0.18, fill_role="none", stroke_role="accent", stroke_width=0.014), _line(0.08, 0.22, 0.12, 0.22, stroke_width=0.016), _line(0.88, 0.28, 0.92, 0.28, stroke_width=0.016)], scene_type="schematic", confidence=0.8)], + "module": [_variant("module", "io", "I/O module", [_rect(0.1, 0.18, 0.8, 0.62, rx=0.08), _line(0.22, 0.32, 0.78, 0.32, stroke_role="accent", stroke_width=0.016), _ellipse(0.14, 0.48, 0.08, 0.08, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), _ellipse(0.78, 0.48, 0.08, 0.08, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01)], scene_type="schematic", confidence=0.8)], + "branch": [_variant("branch", "split", "Split branch", [_line(0.12, 0.5, 0.46, 0.5, stroke_width=0.026), _line(0.46, 0.5, 0.78, 0.24, stroke_width=0.022), _line(0.46, 0.5, 0.78, 0.76, stroke_width=0.022), _ellipse(0.78, 0.18, 0.1, 0.1, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), _ellipse(0.78, 0.72, 0.1, 0.1, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01)], scene_type="schematic", confidence=0.76)], + } + return library + + +def _coerce_variant(asset_key: str, raw: Dict[str, Any]) -> Dict[str, Any]: + item = _copy(raw) + scene_type = CLASS_SCENE_MAP.get(asset_key, "scene") + family = infer_sketch_family(asset_key, scene_type=scene_type) + variant_id = str(item.get("id") or f"{asset_key}:external") + stroke_payload = _normalize_stroke_payload(item.get("stroke_payload")) + shape_recipe = _copy(item.get("shape_recipe") or {}) + if not stroke_payload and shape_recipe: + stroke_payload = shape_recipe_to_strokes(shape_recipe) + if not shape_recipe and stroke_payload: + shape_recipe = strokes_to_shape_recipe(stroke_payload) + render_representation = str(item.get("render_representation") or ("stroke_native" if stroke_payload else "shape_recipe")) + stroke_variant_id = str(item.get("stroke_variant_id") or variant_id) + return { + "id": variant_id, + "label": str(item.get("label") or variant_id), + "asset_key": asset_key, + "shape_recipe": shape_recipe, + "source": str(item.get("source") or "trained_export"), + "confidence": float(item.get("confidence", 0.8) or 0.8), + "style_variants": list(item.get("style_variants") or [style["id"] for style in STYLE_VARIANTS]), + "default_style": str(item.get("default_style") or "scribble_line"), + "part_graph": _copy(item.get("part_graph") or default_part_graph(asset_key, scene_type=scene_type)), + "region_masks": _copy(item.get("region_masks") or default_region_masks(asset_key, scene_type=scene_type)), + "stroke_style_profile": _copy(item.get("stroke_style_profile") or build_stroke_style_profile(asset_key, scene_type=scene_type, style_variant=str(item.get("default_style") or "scribble_line"), sketch_family=family)), + "stroke_payload": stroke_payload, + "stroke_variant_id": stroke_variant_id, + "stroke_payload_source": str(item.get("stroke_payload_source") or item.get("source") or "trained_export"), + "stroke_render_profile": _copy(item.get("stroke_render_profile") or item.get("stroke_style_profile") or build_stroke_style_profile(asset_key, scene_type=scene_type, style_variant=str(item.get("default_style") or "scribble_line"), sketch_family=family)), + "render_representation": render_representation, + "readability_rank": int(item.get("readability_rank", default_readability_rank(asset_key, scene_type=scene_type)) or default_readability_rank(asset_key, scene_type=scene_type)), + "sketch_family": str(item.get("sketch_family") or family), + } + + +@lru_cache(maxsize=8) +def _load_exported_variant_library_cached(path_key: str) -> Dict[str, List[Dict[str, Any]]]: + export_path = Path(path_key) + if not export_path.exists(): + return {} + try: + payload = json.loads(export_path.read_text(encoding="utf-8")) + except Exception: + return {} + raw_variants = payload.get("variants") if isinstance(payload, dict) else {} + if not isinstance(raw_variants, dict): + return {} + library: Dict[str, List[Dict[str, Any]]] = {} + for asset_key, variants in raw_variants.items(): + if not isinstance(variants, list): + continue + cleaned = [_coerce_variant(str(asset_key), item) for item in variants if isinstance(item, dict)] + if cleaned: + library[str(asset_key)] = cleaned + return library + + +def load_exported_variant_library() -> Dict[str, List[Dict[str, Any]]]: + return _load_exported_variant_library_cached(str(resolve_exported_variants_path().resolve())) + + +@lru_cache(maxsize=8) +def _load_exported_stroke_variant_library_cached(path_key: str) -> Dict[str, List[Dict[str, Any]]]: + export_path = Path(path_key) + if not export_path.exists(): + return {} + try: + payload = json.loads(export_path.read_text(encoding="utf-8")) + except Exception: + return {} + raw_variants = payload.get("variants") if isinstance(payload, dict) else {} + if not isinstance(raw_variants, dict): + return {} + library: Dict[str, List[Dict[str, Any]]] = {} + for asset_key, variants in raw_variants.items(): + if not isinstance(variants, list): + continue + cleaned = [_coerce_variant(str(asset_key), item) for item in variants if isinstance(item, dict)] + if cleaned: + library[str(asset_key)] = cleaned + return library + + +def load_exported_stroke_variant_library() -> Dict[str, List[Dict[str, Any]]]: + return _load_exported_stroke_variant_library_cached(str(resolve_exported_stroke_variants_path().resolve())) + + +def _merge_variants(items: Iterable[Dict[str, Any]]) -> List[Dict[str, Any]]: + unique: Dict[str, Dict[str, Any]] = {} + for item in items: + variant_id = str(item.get("id") or "") + if variant_id: + unique[variant_id] = _copy(item) + return list(unique.values()) + + +def list_object_shape_variants(asset_key: str, concept: str = "", scene_type: str = "scene") -> List[Dict[str, Any]]: + key = str(asset_key or "").strip() or FAMILY_FALLBACKS.get(scene_type, "blob") + return _merge_variants([ + *load_exported_variant_library().get(key, []), + *_builtin_variant_library().get(key, []), + _fallback_variant(key, concept, scene_type), + *load_exported_stroke_variant_library().get(key, []), + ]) + + +def _stable_index(key: str, total: int) -> int: + if total <= 0: + return 0 + return sum((index + 1) * ord(char) for index, char in enumerate(key)) % total + + +def _normalize_style_variant_id(style_variant: str | None) -> str: + raw = str(style_variant or "").strip().lower() + if raw in {"minimal", "clean", "clean_line"}: + return "clean_line" + if raw in {"line_art", "scribble", "scribble_line"}: + return "scribble_line" + return raw or "" + + +def _resolve_default_style_variant(asset_key: str, scene_type: str, style_variant: str | None) -> str: + explicit = _normalize_style_variant_id(style_variant) + if explicit: + return explicit + env_default = _normalize_style_variant_id(os.getenv("TMCRA_GENERATION_STYLE_DEFAULT", "")) + if env_default: + return env_default + if asset_key in SCENE_OBJECT_CLASSES or scene_type == "scene": + return "clean_line" + return "scribble_line" + + +def _resolve_variant_selection_policy() -> str: + raw = str(os.getenv("TMCRA_OBJECT_VARIANT_POLICY", "current_generation_v1") or "").strip().lower() + if raw in {"stable", "legacy_stable", "legacy"}: + return "legacy_stable" + return "current_generation_v1" + + +def _source_selection_bonus( + asset_key: str, + *, + scene_type: str, + source: str, + render_representation: str, +) -> float: + if scene_type == "scene" and asset_key in SCENE_OBJECT_CLASSES: + if source == "demo_library": + return 1.0 + if source == "rule_prototype": + return 0.82 + if source.startswith("trained_export") and render_representation == "stroke_native": + return 0.35 + if source.startswith("trained_export"): + return 0.78 + if source == "demo_library": + return 0.58 + if source == "rule_prototype": + return 0.42 + return 0.0 + + +def _variant_priority_tuple( + asset_key: str, + variant: Dict[str, Any], + *, + concept: str, + scene_type: str, + preferred_style: str, + stroke_seed: int | str | None, +) -> tuple[float, ...]: + styles = {_normalize_style_variant_id(item) for item in (variant.get("style_variants") or [])} + default_style = _normalize_style_variant_id(variant.get("default_style")) + source = str(variant.get("source") or "") + confidence = float(variant.get("confidence", 0.0) or 0.0) + readability = float(variant.get("readability_rank", default_readability_rank(asset_key, scene_type=scene_type)) or 0.0) + stroke_payload = _normalize_stroke_payload(variant.get("stroke_payload")) + render_representation = str(variant.get("render_representation") or "") + sketch_engine = _resolve_sketch_engine() + style_hit = 1.0 if preferred_style and preferred_style in styles else 0.0 + style_default_hit = 1.0 if preferred_style and default_style == preferred_style else 0.0 + clean_bonus = 1.0 if "clean_line" in styles else 0.0 + source_bonus = _source_selection_bonus( + asset_key, + scene_type=scene_type, + source=source, + render_representation=render_representation, + ) + native_stroke_bonus = 1.0 if stroke_payload and render_representation == "stroke_native" else 0.0 + natural_engine_bonus = 1.0 if stroke_payload and sketch_engine != "mechanical_v1" else 0.0 + scene_clean_bonus = 1.0 if preferred_style == "clean_line" and (asset_key in SCENE_OBJECT_CLASSES or scene_type == "scene") else 0.0 + tie_break = -float(_stable_index(f"{asset_key}|{concept}|{variant.get('id') or ''}|{stroke_seed or ''}", 1_000_000)) + return ( + style_hit, + confidence, + source_bonus, + readability, + style_default_hit, + scene_clean_bonus * clean_bonus, + clean_bonus, + natural_engine_bonus, + native_stroke_bonus, + tie_break, + ) + + +def resolve_object_shape(asset_key: str, *, concept: str = "", scene_type: str = "scene", preferred_variant_id: str | None = None, style_variant: str | None = None, stroke_seed: int | str | None = None) -> Dict[str, Any]: + variants = list_object_shape_variants(asset_key, concept, scene_type) + variant_map = {item["id"]: item for item in variants} + preferred_style = _resolve_default_style_variant(asset_key, scene_type, style_variant) + explicit_variant = variant_map.get(str(preferred_variant_id or "").strip()) + if explicit_variant: + chosen = explicit_variant + selection_policy = "preferred_variant_id" + elif _resolve_variant_selection_policy() == "legacy_stable": + chosen = variants[_stable_index(f"{asset_key}|{concept}|{stroke_seed or ''}", len(variants))] + selection_policy = "legacy_stable" + else: + chosen = max( + variants, + key=lambda item: _variant_priority_tuple( + asset_key, + item, + concept=concept, + scene_type=scene_type, + preferred_style=preferred_style, + stroke_seed=stroke_seed, + ), + ) + selection_policy = "current_generation_v1" + source = str(chosen.get("source") or "rule_prototype") + sketch_engine = _resolve_sketch_engine() + stroke_payload = _normalize_stroke_payload(chosen.get("stroke_payload")) + shape_recipe = _copy(chosen.get("shape_recipe") or {}) + if not stroke_payload and shape_recipe: + stroke_payload = shape_recipe_to_strokes(shape_recipe) + render_representation = "shape_recipe" if sketch_engine == "mechanical_v1" else str(chosen.get("render_representation") or ("stroke_native" if stroke_payload else "shape_recipe")) + if render_representation == "stroke_native" and not stroke_payload: + render_representation = "shape_recipe" + sketch_backend = "trained" if source.startswith("trained_export") else "hybrid" if asset_key in TRAINED_DEMO_CLASSES else "rule" + return { + "sketch_backend": sketch_backend, + "shape_variant_id": chosen["id"], + "shape_recipe": shape_recipe, + "shape_recipe_source": source, + "shape_confidence": float(chosen.get("confidence", 0.78) or 0.78), + "stroke_seed": str(stroke_seed or ""), + "style_variant": preferred_style or str(chosen.get("default_style") or "scribble_line"), + "part_graph": _copy(chosen.get("part_graph") or []), + "region_masks": _copy(chosen.get("region_masks") or []), + "stroke_style_profile": _copy(chosen.get("stroke_style_profile") or {}), + "render_representation": render_representation, + "stroke_variant_id": str(chosen.get("stroke_variant_id") or chosen["id"]), + "stroke_payload": stroke_payload, + "stroke_payload_source": str(chosen.get("stroke_payload_source") or source), + "stroke_render_profile": _copy(chosen.get("stroke_render_profile") or chosen.get("stroke_style_profile") or {}), + "readability_rank": int(chosen.get("readability_rank", default_readability_rank(asset_key, scene_type=scene_type)) or default_readability_rank(asset_key, scene_type=scene_type)), + "sketch_family": str(chosen.get("sketch_family") or infer_sketch_family(asset_key, scene_type=scene_type)), + "variant_selection_policy": selection_policy, + "available_shape_variants": [{"id": item["id"], "label": item.get("label", item["id"]), "asset_key": item.get("asset_key", asset_key), "source": item.get("source", "rule_prototype"), "confidence": float(item.get("confidence", 0.75) or 0.75), "style_variants": list(item.get("style_variants") or [style["id"] for style in STYLE_VARIANTS]), "shape_recipe": _copy(item.get("shape_recipe") or {}), "part_graph": _copy(item.get("part_graph") or []), "region_masks": _copy(item.get("region_masks") or []), "stroke_style_profile": _copy(item.get("stroke_style_profile") or {}), "readability_rank": item.get("readability_rank"), "sketch_family": item.get("sketch_family"), "render_representation": item.get("render_representation"), "stroke_variant_id": item.get("stroke_variant_id"), "stroke_payload_source": item.get("stroke_payload_source"), "stroke_render_profile": _copy(item.get("stroke_render_profile") or {}), "stroke_payload": _normalize_stroke_payload(item.get("stroke_payload"))} for item in variants], + } + + +def summarize_scene_backend(scene_spec: Dict[str, Any] | None) -> Dict[str, Any]: + objects = list((scene_spec or {}).get("object_instances") or []) + return { + "mode": DEMO_BACKEND_MODE, + "object_count": len(objects), + "backend_counts": dict(Counter(str(item.get("sketch_backend") or "rule") for item in objects)), + "source_counts": dict(Counter(str(item.get("shape_recipe_source") or "rule_prototype") for item in objects)), + "render_representation_counts": dict(Counter(str(item.get("render_representation") or "shape_recipe") for item in objects)), + "family_counts": dict(Counter(str(item.get("sketch_family") or "") for item in objects if item.get("sketch_family"))), + "trained_class_count": len(TRAINED_DEMO_CLASSES), + "export_library_loaded": bool(load_exported_variant_library()), + "stroke_export_library_loaded": bool(load_exported_stroke_variant_library()), + } + + +def scene_shape_variant_payload(scene_spec: Dict[str, Any] | None) -> Dict[str, Any]: + objects = list((scene_spec or {}).get("object_instances") or []) + return { + "available_shape_variants": {str(item.get("id")): [{"id": variant.get("id"), "label": variant.get("label"), "source": variant.get("source"), "confidence": variant.get("confidence"), "style_variants": variant.get("style_variants"), "readability_rank": variant.get("readability_rank"), "sketch_family": variant.get("sketch_family")} for variant in list(item.get("available_shape_variants") or [])] for item in objects if item.get("id")}, + "shape_variant_id": {str(item.get("id")): str(item.get("shape_variant_id") or "") for item in objects if item.get("id")}, + "shape_recipe_source": {str(item.get("id")): str(item.get("shape_recipe_source") or "") for item in objects if item.get("id")}, + "render_representation": {str(item.get("id")): str(item.get("render_representation") or "shape_recipe") for item in objects if item.get("id")}, + "stroke_variant_id": {str(item.get("id")): str(item.get("stroke_variant_id") or "") for item in objects if item.get("id")}, + "stroke_payload_source": {str(item.get("id")): str(item.get("stroke_payload_source") or "") for item in objects if item.get("id")}, + "region_masks": {str(item.get("id")): _copy(item.get("region_masks") or []) for item in objects if item.get("id")}, + } + + +def _resample_points(points: Sequence[Sequence[float]], target_points: int) -> List[List[float]]: + cleaned = [[float(px), float(py)] for px, py in points] + if not cleaned: + return [] + if len(cleaned) == 1: + return cleaned * max(1, target_points) + distances = [0.0] + for index in range(1, len(cleaned)): + distances.append(distances[-1] + math.dist(cleaned[index - 1], cleaned[index])) + total = distances[-1] + if total <= 1e-6: + return [cleaned[0] for _ in range(max(1, target_points))] + sampled: List[List[float]] = [] + for step in range(max(1, target_points)): + target = total * step / max(1, target_points - 1) + for index in range(1, len(cleaned)): + if distances[index] >= target: + start = cleaned[index - 1] + end = cleaned[index] + span = max(1e-6, distances[index] - distances[index - 1]) + ratio = (target - distances[index - 1]) / span + sampled.append([start[0] + (end[0] - start[0]) * ratio, start[1] + (end[1] - start[1]) * ratio]) + break + else: + sampled.append(cleaned[-1]) + return sampled + + +def _shape_part_to_points(part: Dict[str, Any], sample_points: int = 24) -> List[List[float]]: + kind = str(part.get("kind") or "").lower() + if kind == "line": + return [[float(part.get("x1", 0.0)), float(part.get("y1", 0.0))], [float(part.get("x2", 0.0)), float(part.get("y2", 0.0))]] + if kind in {"polyline", "polygon"}: + points = [[float(px), float(py)] for px, py in part.get("points") or []] + return points + ([points[0]] if kind == "polygon" and points else []) + if kind == "rect": + x, y, w, h = float(part.get("x", 0.0)), float(part.get("y", 0.0)), float(part.get("w", 0.0)), float(part.get("h", 0.0)) + return [[x, y], [x + w, y], [x + w, y + h], [x, y + h], [x, y]] + if kind == "ellipse": + x, y, w, h = float(part.get("x", 0.0)), float(part.get("y", 0.0)), float(part.get("w", 0.0)), float(part.get("h", 0.0)) + cx, cy, rx, ry = x + w / 2.0, y + h / 2.0, w / 2.0, h / 2.0 + return [[cx + math.cos(2 * math.pi * step / sample_points) * rx, cy + math.sin(2 * math.pi * step / sample_points) * ry] for step in range(sample_points + 1)] + return [] + + +def shape_recipe_to_strokes(shape_recipe: Dict[str, Any], *, max_strokes: int = 8, points_per_stroke: int = 32) -> List[List[List[float]]]: + strokes: List[List[List[float]]] = [] + for part in list((shape_recipe or {}).get("parts") or []): + points = _shape_part_to_points(part, sample_points=max(12, points_per_stroke)) + if points: + strokes.append(_resample_points(points, points_per_stroke)) + if len(strokes) >= max_strokes: + break + return strokes + + +def strokes_to_shape_recipe(strokes: Sequence[Sequence[Sequence[float]]], *, stroke_width: float = 0.02, stroke_role: str = "line") -> Dict[str, Any]: + return _shape([{"kind": "polyline", "points": [[max(0.0, min(1.0, float(px))), max(0.0, min(1.0, float(py)))] for px, py in stroke], "stroke_role": stroke_role, "stroke_width": stroke_width, "opacity": 1.0} for stroke in strokes if len(stroke) >= 2]) + + +def _load_seed_rows(path: Path) -> List[Dict[str, Any]]: + if not path.exists(): + return [] + rows: List[Dict[str, Any]] = [] + for line in path.read_text(encoding="utf-8").splitlines(): + if not line.strip(): + continue + try: + item = json.loads(line) + except Exception: + continue + if isinstance(item, dict): + rows.append(item) + return rows + + +def bootstrap_training_rows() -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + seen: set[tuple[str, str, str]] = set() + for row in [*_load_seed_rows(PUBLIC_SEED_PATH), *_load_seed_rows(MANUAL_SEED_PATH)]: + key = (str(row.get("class_id") or ""), str(row.get("style_id") or ""), str(row.get("variant_id") or "seed")) + if all(key) and key not in seen: + rows.append(_copy(row)) + seen.add(key) + for asset_key in TRAINED_DEMO_CLASSES: + scene_type = CLASS_SCENE_MAP.get(asset_key, "scene") + for variant in list_object_shape_variants(asset_key, asset_key, scene_type): + if str(variant.get("source") or "") == "rule_prototype": + continue + for style in STYLE_VARIANTS: + key = (asset_key, style["id"], str(variant.get("id") or "")) + if key in seen: + continue + rows.append({"class_id": asset_key, "scene_type": scene_type, "style_id": style["id"], "variant_id": variant["id"], "strokes": shape_recipe_to_strokes(variant.get("shape_recipe") or {}), "shape_recipe": _copy(variant.get("shape_recipe") or {}), "region_masks": _copy(variant.get("region_masks") or []), "part_graph": _copy(variant.get("part_graph") or []), "stroke_style_profile": _copy(variant.get("stroke_style_profile") or {}), "sketch_family": str(variant.get("sketch_family") or infer_sketch_family(asset_key, scene_type=scene_type)), "readability_rank": int(variant.get("readability_rank", default_readability_rank(asset_key, scene_type=scene_type)) or default_readability_rank(asset_key, scene_type=scene_type)), "source": str(variant.get("source") or "demo_library")}) + seen.add(key) + return rows diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_dataset.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_dataset.py new file mode 100644 index 0000000..f8b067e --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_dataset.py @@ -0,0 +1,791 @@ +from __future__ import annotations + +import hashlib +import json +import math +import random +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any, Dict, Iterable, Iterator, List, Sequence + +import torch +from torch.utils.data import Dataset + +from .object_sketch_backend import ( + STYLE_VARIANTS, + list_object_shape_variants, + shape_recipe_to_strokes, + strokes_to_shape_recipe, +) +from .sketch_style_spec import ( + build_stroke_style_profile, + default_part_graph, + default_readability_rank, + default_region_masks, + infer_sketch_family, +) + + +TRAINING_STYLE_IDS = tuple(item["id"] for item in STYLE_VARIANTS) +DEFAULT_MAX_STROKES = 12 +DEFAULT_POINTS_PER_STROKE = 48 +REAL_PROVENANCE_TYPES = {"real_handdrawn", "cleaned_real", "retraced"} +DEFAULT_PROVENANCE_WEIGHTS = { + "real_handdrawn": 1.35, + "cleaned_real": 1.15, + "retraced": 0.95, + "bootstrap": 0.35, + "unknown": 0.8, +} + + +@dataclass(slots=True) +class SketchTrainingClassSpec: + class_id: str + scene_type: str + sketch_family: str + priority: int = 1 + min_target_samples: int = 192 + bootstrap_from_runtime: bool = True + + +TARGET_TRAINING_CLASS_SPECS: tuple[SketchTrainingClassSpec, ...] = ( + SketchTrainingClassSpec("building", "scene", "scene_subject", priority=1, min_target_samples=320), + SketchTrainingClassSpec("house", "scene", "scene_subject", priority=1, min_target_samples=280), + SketchTrainingClassSpec("window", "scene", "scene_detail", priority=1, min_target_samples=240), + SketchTrainingClassSpec("door", "scene", "scene_detail", priority=1, min_target_samples=220), + SketchTrainingClassSpec("tree", "scene", "scene_support", priority=1, min_target_samples=320), + SketchTrainingClassSpec("cloud", "scene", "scene_environment", priority=1, min_target_samples=220), + SketchTrainingClassSpec("sun", "scene", "scene_environment", priority=1, min_target_samples=220), + SketchTrainingClassSpec("person", "scene", "scene_subject", priority=1, min_target_samples=320), + SketchTrainingClassSpec("car", "scene", "scene_subject", priority=1, min_target_samples=320), + SketchTrainingClassSpec("street_lamp", "scene", "scene_support", priority=1, min_target_samples=220), + SketchTrainingClassSpec("table", "scene", "scene_support", priority=1, min_target_samples=220), + SketchTrainingClassSpec("chair", "scene", "scene_support", priority=1, min_target_samples=220), + SketchTrainingClassSpec("dog", "scene", "scene_subject", priority=1, min_target_samples=240), + SketchTrainingClassSpec("desk_lamp", "scene", "scene_support", priority=2, min_target_samples=180), + SketchTrainingClassSpec("road", "scene", "scene_environment", priority=1, min_target_samples=220), + SketchTrainingClassSpec("bicycle", "scene", "scene_subject", priority=2, min_target_samples=180), + SketchTrainingClassSpec("bus", "scene", "scene_subject", priority=2, min_target_samples=180), + SketchTrainingClassSpec("bridge", "scene", "scene_environment", priority=2, min_target_samples=160), + SketchTrainingClassSpec("river", "scene", "scene_environment", priority=2, min_target_samples=160), + SketchTrainingClassSpec("mountain", "scene", "scene_environment", priority=2, min_target_samples=160), + SketchTrainingClassSpec("bench", "scene", "scene_support", priority=2, min_target_samples=160), + SketchTrainingClassSpec("bird", "scene", "scene_support", priority=2, min_target_samples=160), + SketchTrainingClassSpec("flower", "scene", "scene_detail", priority=2, min_target_samples=160), + SketchTrainingClassSpec("boat", "scene", "scene_subject", priority=2, min_target_samples=160), + SketchTrainingClassSpec("grass", "scene", "scene_environment", priority=2, min_target_samples=160), + SketchTrainingClassSpec("cycle", "process", "process_motif", priority=1, min_target_samples=240), + SketchTrainingClassSpec("flow_node", "process", "process_motif", priority=1, min_target_samples=240), + SketchTrainingClassSpec("energy_wave", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("vapor", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("leaf", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("raindrop", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("airplane", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("cell", "process", "process_motif", priority=1, min_target_samples=220), + SketchTrainingClassSpec("photosynthesis", "process", "process_motif", priority=2, min_target_samples=180), + SketchTrainingClassSpec("heat_flow", "process", "process_motif", priority=2, min_target_samples=180), + SketchTrainingClassSpec("water_cycle", "process", "process_motif", priority=2, min_target_samples=180), + SketchTrainingClassSpec("airflow", "process", "process_motif", priority=2, min_target_samples=180), + SketchTrainingClassSpec("battery", "schematic", "schematic_symbol", priority=1, min_target_samples=220), + SketchTrainingClassSpec("led", "schematic", "schematic_symbol", priority=1, min_target_samples=220), + SketchTrainingClassSpec("resistor", "schematic", "schematic_symbol", priority=1, min_target_samples=220), + SketchTrainingClassSpec("capacitor", "schematic", "schematic_symbol", priority=1, min_target_samples=200), + SketchTrainingClassSpec("diode", "schematic", "schematic_symbol", priority=1, min_target_samples=200), + SketchTrainingClassSpec("board", "schematic", "schematic_symbol", priority=1, min_target_samples=200), + SketchTrainingClassSpec("module", "schematic", "schematic_symbol", priority=1, min_target_samples=200), + SketchTrainingClassSpec("branch", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("switch", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("wire", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("motor", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("sensor", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("ground", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("chip", "schematic", "schematic_symbol", priority=2, min_target_samples=180), + SketchTrainingClassSpec("transistor", "schematic", "schematic_symbol", priority=2, min_target_samples=180), +) + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _normalize_provenance(raw: Any) -> str: + value = str(raw or "").strip().lower() + if value in REAL_PROVENANCE_TYPES: + return value + if value in {"runtime_variant", "demo_dataset", "trained_export_v3", "bootstrap"}: + return "bootstrap" + if not value: + return "unknown" + return value + + +def _infer_provenance(row: Dict[str, Any]) -> str: + explicit = _normalize_provenance(row.get("provenance")) + if explicit != "unknown": + return explicit + source = str(row.get("source") or "").lower() + origin_path = str(row.get("origin_path") or "").lower() + merged = " ".join(part for part in (source, origin_path) if part) + if any(token in merged for token in ("bootstrap", "runtime_variant", "demo", "trained_export", "synthetic")): + return "bootstrap" + if any(token in merged for token in ("retraced", "trace", "vectorized")): + return "retraced" + if any(token in merged for token in ("handdrawn", "hand_drawn", "quickdraw", "ink", "tu_berlin", "sketchyscene")): + return "real_handdrawn" + if any(token in merged for token in ("clean", "cleaned", "curated", "manual")): + return "cleaned_real" + return "unknown" + + +def _default_sample_weight(*, provenance: str, priority: int) -> float: + base = DEFAULT_PROVENANCE_WEIGHTS.get(provenance, DEFAULT_PROVENANCE_WEIGHTS["unknown"]) + if priority <= 1: + base *= 1.12 + elif priority >= 3: + base *= 0.94 + return round(max(0.1, min(2.0, base)), 4) + + +def _default_style_cluster_id(*, style_id: str, sketch_family: str) -> str: + family = str(sketch_family or "generic").strip() or "generic" + style = str(style_id or "scribble_line").strip() or "scribble_line" + return f"{family}:{style}" + + +def _raw_stroke_lengths( + strokes: Sequence[Sequence[Sequence[float]]], + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> tuple[List[float], int]: + lengths: List[float] = [] + sequence_length = 0 + for stroke in list(strokes)[:max_strokes]: + raw_len = 0 + for point in stroke: + if isinstance(point, (list, tuple)) and len(point) >= 2: + raw_len += 1 + raw_len = max(0, raw_len) + sequence_length += min(points_per_stroke, raw_len) + lengths.append(min(1.0, raw_len / max(1, points_per_stroke))) + return lengths, sequence_length + + +def iter_target_class_specs(*, priority_at_most: int | None = None) -> List[SketchTrainingClassSpec]: + specs = list(TARGET_TRAINING_CLASS_SPECS) + if priority_at_most is not None: + specs = [item for item in specs if item.priority <= priority_at_most] + return specs + + +def target_class_manifest(*, priority_at_most: int | None = None) -> Dict[str, Any]: + specs = iter_target_class_specs(priority_at_most=priority_at_most) + by_scene: Dict[str, List[Dict[str, Any]]] = {} + for spec in specs: + by_scene.setdefault(spec.scene_type, []).append(asdict(spec)) + return { + "style_ids": list(TRAINING_STYLE_IDS), + "class_count": len(specs), + "classes": [asdict(item) for item in specs], + "by_scene_type": by_scene, + } + + +def read_jsonl(path: Path) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + if not path.exists(): + return rows + with path.open("r", encoding="utf-8") as handle: + for raw in handle: + line = raw.strip() + if not line: + continue + try: + item = json.loads(line) + except Exception: + continue + if isinstance(item, dict): + rows.append(item) + return rows + + +def write_jsonl(path: Path, rows: Sequence[Dict[str, Any]]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as handle: + for row in rows: + handle.write(json.dumps(row, ensure_ascii=False) + "\n") + + +def _resample_points(points: Sequence[Sequence[float]], target_points: int) -> List[List[float]]: + cleaned = [[float(px), float(py)] for px, py in points] + if not cleaned: + return [] + if len(cleaned) == 1: + return cleaned * max(2, target_points) + distances = [0.0] + for index in range(1, len(cleaned)): + distances.append(distances[-1] + math.dist(cleaned[index - 1], cleaned[index])) + total = distances[-1] + if total <= 1e-6: + return [cleaned[0] for _ in range(max(2, target_points))] + sampled: List[List[float]] = [] + for step in range(max(2, target_points)): + target = total * step / max(1, target_points - 1) + for index in range(1, len(cleaned)): + if distances[index] >= target: + start = cleaned[index - 1] + end = cleaned[index] + span = max(1e-6, distances[index] - distances[index - 1]) + ratio = (target - distances[index - 1]) / span + sampled.append([start[0] + (end[0] - start[0]) * ratio, start[1] + (end[1] - start[1]) * ratio]) + break + else: + sampled.append(cleaned[-1]) + return sampled + + +def canonicalize_strokes( + strokes: Sequence[Sequence[Sequence[float]]], + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> List[List[List[float]]]: + normalized: List[List[List[float]]] = [] + for stroke in strokes[:max_strokes]: + cleaned = [] + for point in stroke: + if not isinstance(point, (list, tuple)) or len(point) < 2: + continue + px = max(0.0, min(1.0, float(point[0]))) + py = max(0.0, min(1.0, float(point[1]))) + cleaned.append([px, py]) + if len(cleaned) >= 2: + normalized.append(_resample_points(cleaned, points_per_stroke)) + return normalized + + +def augment_strokes( + strokes: Sequence[Sequence[Sequence[float]]], + rng: random.Random, + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, + aggressive: bool = False, +) -> List[List[List[float]]]: + scale = rng.uniform(0.88, 1.12 if aggressive else 1.06) + shift_x = rng.uniform(-0.06 if aggressive else -0.03, 0.06 if aggressive else 0.03) + shift_y = rng.uniform(-0.06 if aggressive else -0.03, 0.06 if aggressive else 0.03) + angle = math.radians(rng.uniform(-10.0 if aggressive else -4.0, 10.0 if aggressive else 4.0)) + jitter = rng.uniform(0.004, 0.02 if aggressive else 0.012) + mirror = rng.random() < (0.12 if aggressive else 0.05) + keep_ratio = rng.uniform(0.6, 1.0) if aggressive else rng.uniform(0.78, 1.0) + cos_a = math.cos(angle) + sin_a = math.sin(angle) + augmented: List[List[List[float]]] = [] + for stroke in strokes: + if len(augmented) >= max_strokes: + break + points: List[List[float]] = [] + for px, py in stroke: + cx = float(px) - 0.5 + cy = float(py) - 0.5 + rx = cx * cos_a - cy * sin_a + ry = cx * sin_a + cy * cos_a + nx = rx * scale + 0.5 + shift_x + rng.uniform(-jitter, jitter) + ny = ry * scale + 0.5 + shift_y + rng.uniform(-jitter, jitter) + if mirror: + nx = 1.0 - nx + points.append([max(0.0, min(1.0, nx)), max(0.0, min(1.0, ny))]) + if rng.random() < 0.22 and len(points) > 8: + target_len = max(6, int(len(points) * keep_ratio)) + points = points[:target_len] + if len(points) >= 2: + augmented.append(_resample_points(points, points_per_stroke)) + if aggressive and augmented and rng.random() < 0.08: + augmented = augmented[1:] or augmented + return augmented[:max_strokes] + + +def flatten_stroke_sequence( + strokes: Sequence[Sequence[Sequence[float]]], + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> tuple[torch.Tensor, torch.Tensor]: + sequence: List[List[float]] = [] + mask: List[float] = [] + for stroke_index in range(max_strokes): + stroke = strokes[stroke_index] if stroke_index < len(strokes) else [] + for point_index in range(points_per_stroke): + if point_index < len(stroke): + px, py = stroke[point_index] + pen_break = 1.0 if point_index == len(stroke) - 1 else 0.0 + sequence.append([float(px), float(py), pen_break]) + mask.append(1.0) + else: + sequence.append([0.0, 0.0, 1.0]) + mask.append(0.0) + return torch.tensor(sequence, dtype=torch.float32), torch.tensor(mask, dtype=torch.float32) + + +def sequence_to_strokes( + sequence: torch.Tensor, + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> List[List[List[float]]]: + values = sequence.detach().cpu().tolist() + strokes: List[List[List[float]]] = [] + current: List[List[float]] = [] + for index, (px, py, pen_break) in enumerate(values[: max_strokes * points_per_stroke]): + current.append([max(0.0, min(1.0, float(px))), max(0.0, min(1.0, float(py)))]) + if pen_break >= 0.5 or (index + 1) % points_per_stroke == 0: + if len(current) >= 2: + strokes.append(current) + current = [] + if current and len(current) >= 2: + strokes.append(current) + return strokes[:max_strokes] + + +def compute_bbox(strokes: Sequence[Sequence[Sequence[float]]]) -> List[float]: + points = [(float(px), float(py)) for stroke in strokes for px, py in stroke] + if not points: + return [0.0, 0.0, 0.0, 0.0] + xs = [point[0] for point in points] + ys = [point[1] for point in points] + min_x, max_x = max(0.0, min(xs)), min(1.0, max(xs)) + min_y, max_y = max(0.0, min(ys)), min(1.0, max(ys)) + return [min_x, min_y, max(0.0, max_x - min_x), max(0.0, max_y - min_y)] + + +def _stable_hash(text: str) -> float: + digest = hashlib.md5(text.encode("utf-8", errors="ignore")).digest() + return int.from_bytes(digest[:4], "big") / 2**32 + + +def normalize_training_row( + row: Dict[str, Any], + *, + fallback_class_id: str | None = None, + fallback_scene_type: str | None = None, + fallback_style_id: str = "scribble_line", + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> Dict[str, Any] | None: + class_id = str(row.get("class_id") or fallback_class_id or "").strip() + if not class_id: + return None + scene_type = str(row.get("scene_type") or fallback_scene_type or "scene").strip() or "scene" + style_id = str(row.get("style_id") or fallback_style_id).strip() or fallback_style_id + sketch_family = str(row.get("sketch_family") or infer_sketch_family(class_id, scene_type=scene_type)).strip() + shape_recipe = _copy(row.get("shape_recipe") or {}) + stroke_payload = _copy(row.get("stroke_payload") or []) + raw_strokes = row.get("strokes") or stroke_payload or shape_recipe_to_strokes(shape_recipe) + raw_lengths, sequence_length = _raw_stroke_lengths( + raw_strokes, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + strokes = canonicalize_strokes( + raw_strokes, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + if not strokes: + return None + region_masks = _copy(row.get("region_masks") or default_region_masks(class_id, scene_type=scene_type)) + part_graph = _copy(row.get("part_graph") or default_part_graph(class_id, scene_type=scene_type)) + readability_rank = int(row.get("readability_rank", default_readability_rank(class_id, scene_type=scene_type)) or default_readability_rank(class_id, scene_type=scene_type)) + priority = int(row.get("priority", 2) or 2) + provenance = _infer_provenance(row) + style_cluster_id = str(row.get("style_cluster_id") or _default_style_cluster_id(style_id=style_id, sketch_family=sketch_family)) + stroke_style_profile = _copy( + row.get("stroke_style_profile") + or build_stroke_style_profile( + class_id, + scene_type=scene_type, + style_variant=style_id, + sketch_family=sketch_family, + ) + ) + variant_id = str(row.get("variant_id") or row.get("id") or f"{class_id}:{style_id}:{abs(hash(json.dumps(strokes, ensure_ascii=False))) % 10_000_000}") + payload = { + "class_id": class_id, + "scene_type": scene_type, + "style_id": style_id, + "variant_id": variant_id, + "strokes": strokes, + "stroke_payload": _copy(strokes), + "shape_recipe": strokes_to_shape_recipe(strokes), + "source": str(row.get("source") or "unknown"), + "region_masks": region_masks, + "part_graph": part_graph, + "stroke_style_profile": stroke_style_profile, + "stroke_render_profile": _copy(row.get("stroke_render_profile") or stroke_style_profile), + "sketch_family": sketch_family, + "readability_rank": readability_rank, + "stroke_count": len(strokes), + "bbox": compute_bbox(strokes), + "render_representation": str(row.get("render_representation") or "stroke_native"), + "stroke_variant_id": str(row.get("stroke_variant_id") or variant_id), + "stroke_payload_source": str(row.get("stroke_payload_source") or row.get("source") or "unknown"), + "naturalness_score": float(row.get("naturalness_score", row.get("quality_score", 0.6)) or 0.6), + "quality_score": float(row.get("quality_score", row.get("naturalness_score", 0.6)) or 0.6), + "provenance": provenance, + "sample_weight": float(row.get("sample_weight", _default_sample_weight(provenance=provenance, priority=priority)) or _default_sample_weight(provenance=provenance, priority=priority)), + "style_cluster_id": style_cluster_id, + "stroke_lengths": raw_lengths[:max_strokes], + "sequence_length": int(sequence_length or len(strokes) * points_per_stroke), + "priority": priority, + } + extra_keys = ("origin_path", "layout_condition", "object_boxes", "depth_order", "relation_graph", "condition_maps", "target_sketch_path", "layout_quality_score") + for key in extra_keys: + if key in row: + payload[key] = _copy(row[key]) + return payload + + +def build_bootstrap_rows( + *, + class_specs: Sequence[SketchTrainingClassSpec] | None = None, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + specs = list(class_specs or TARGET_TRAINING_CLASS_SPECS) + for spec in specs: + if not spec.bootstrap_from_runtime: + continue + variants = list_object_shape_variants(spec.class_id, spec.class_id, spec.scene_type) + if not variants: + continue + for variant in variants: + for style_id in TRAINING_STYLE_IDS: + normalized = normalize_training_row( + { + "class_id": spec.class_id, + "scene_type": spec.scene_type, + "style_id": style_id, + "variant_id": variant.get("id") or f"{spec.class_id}:{style_id}", + "render_representation": variant.get("render_representation", "stroke_native"), + "stroke_variant_id": variant.get("stroke_variant_id") or variant.get("id") or f"{spec.class_id}:{style_id}", + "stroke_payload": _copy(variant.get("stroke_payload") or []), + "stroke_payload_source": variant.get("stroke_payload_source") or variant.get("source") or "runtime_variant", + "stroke_render_profile": _copy(variant.get("stroke_render_profile") or variant.get("stroke_style_profile") or {}), + "shape_recipe": _copy(variant.get("shape_recipe") or {}), + "region_masks": _copy(variant.get("region_masks") or []), + "part_graph": _copy(variant.get("part_graph") or []), + "stroke_style_profile": _copy(variant.get("stroke_style_profile") or {}), + "sketch_family": spec.sketch_family, + "readability_rank": variant.get("readability_rank", default_readability_rank(spec.class_id, scene_type=spec.scene_type)), + "source": str(variant.get("source") or "runtime_variant"), + "priority": spec.priority, + "provenance": "bootstrap", + }, + fallback_class_id=spec.class_id, + fallback_scene_type=spec.scene_type, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + if normalized: + rows.append(normalized) + return rows + + +def expand_rows_to_targets( + rows: Sequence[Dict[str, Any]], + *, + class_specs: Sequence[SketchTrainingClassSpec] | None = None, + seed: int = 42, + max_multiplier: float = 1.0, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, +) -> List[Dict[str, Any]]: + rng = random.Random(seed) + specs = list(class_specs or TARGET_TRAINING_CLASS_SPECS) + normalized_rows: List[Dict[str, Any]] = [] + for row in rows: + normalized = normalize_training_row( + row, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + if normalized: + normalized_rows.append(normalized) + grouped: Dict[tuple[str, str], List[Dict[str, Any]]] = {} + for row in normalized_rows: + grouped.setdefault((row["class_id"], row["style_id"]), []).append(row) + spec_lookup = {item.class_id: item for item in specs} + result = list(normalized_rows) + for spec in specs: + per_style_target = max(24, math.ceil(spec.min_target_samples * max_multiplier / max(1, len(TRAINING_STYLE_IDS)))) + for style_id in TRAINING_STYLE_IDS: + key = (spec.class_id, style_id) + candidates = list(grouped.get(key, [])) + if not candidates: + fallback_rows = [ + row + for row in normalized_rows + if row["class_id"] == spec.class_id + ] + candidates = [] + for item in fallback_rows: + cloned = _copy(item) + cloned["style_id"] = style_id + cloned["stroke_style_profile"] = build_stroke_style_profile( + spec.class_id, + scene_type=spec.scene_type, + style_variant=style_id, + sketch_family=spec.sketch_family, + ) + normalized = normalize_training_row( + cloned, + fallback_class_id=spec.class_id, + fallback_scene_type=spec.scene_type, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + if normalized: + candidates.append(normalized) + if not candidates: + continue + grouped[key] = list(candidates) + result.extend(candidates) + while len(grouped.get(key, [])) < per_style_target: + base = _copy(rng.choice(candidates)) + base["variant_id"] = f'{base["variant_id"]}::auto_aug_{len(grouped.get(key, [])) + 1}' + base["source"] = f'{base.get("source", "unknown")}:scale_augmented' + base["style_id"] = style_id + base["strokes"] = augment_strokes( + base.get("strokes", []), + rng, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + aggressive=len(grouped.get(key, [])) > per_style_target * 0.6, + ) + base["stroke_payload"] = _copy(base["strokes"]) + base["render_representation"] = "stroke_native" + base["stroke_payload_source"] = str(base.get("source") or "scale_augmented") + base["stroke_variant_id"] = str(base.get("stroke_variant_id") or base.get("variant_id") or "") + base["stroke_style_profile"] = build_stroke_style_profile( + spec.class_id, + scene_type=spec.scene_type, + style_variant=style_id, + sketch_family=spec.sketch_family, + ) + normalized = normalize_training_row( + base, + fallback_class_id=spec.class_id, + fallback_scene_type=spec.scene_type, + max_strokes=max_strokes, + points_per_stroke=points_per_stroke, + ) + if not normalized: + break + grouped.setdefault(key, []).append(normalized) + result.append(normalized) + return result + + +def split_rows( + rows: Sequence[Dict[str, Any]], + *, + train_ratio: float = 0.9, + val_ratio: float = 0.07, +) -> Dict[str, List[Dict[str, Any]]]: + train: List[Dict[str, Any]] = [] + val: List[Dict[str, Any]] = [] + test: List[Dict[str, Any]] = [] + boundary_train = max(0.0, min(1.0, train_ratio)) + boundary_val = max(boundary_train, min(1.0, train_ratio + val_ratio)) + for row in rows: + key = f'{row.get("class_id", "")}|{row.get("style_id", "")}|{row.get("variant_id", "")}' + score = _stable_hash(key) + if score < boundary_train: + train.append(_copy(row)) + elif score < boundary_val: + val.append(_copy(row)) + else: + test.append(_copy(row)) + return {"train": train, "val": val, "test": test} + + +def build_index_maps(rows: Sequence[Dict[str, Any]]) -> Dict[str, Dict[str, int]]: + class_ids = sorted({str(row.get("class_id") or "") for row in rows if row.get("class_id")}) + style_ids = sorted({str(row.get("style_id") or "") for row in rows if row.get("style_id")}) + scene_ids = sorted({str(row.get("scene_type") or "scene") for row in rows}) + family_ids = sorted({str(row.get("sketch_family") or "") for row in rows if row.get("sketch_family")}) + provenance_ids = sorted({_normalize_provenance(row.get("provenance")) for row in rows} | {"unknown"}) + style_cluster_ids = sorted({str(row.get("style_cluster_id") or _default_style_cluster_id(style_id=row.get("style_id"), sketch_family=row.get("sketch_family"))) for row in rows}) + return { + "class_to_idx": {item: index for index, item in enumerate(class_ids)}, + "style_to_idx": {item: index for index, item in enumerate(style_ids)}, + "scene_to_idx": {item: index for index, item in enumerate(scene_ids)}, + "family_to_idx": {item: index for index, item in enumerate(family_ids)}, + "provenance_to_idx": {item: index for index, item in enumerate(provenance_ids)}, + "style_cluster_to_idx": {item: index for index, item in enumerate(style_cluster_ids)}, + } + + +def build_dataset_manifest( + split_rows_map: Dict[str, Sequence[Dict[str, Any]]], + *, + class_specs: Sequence[SketchTrainingClassSpec] | None = None, +) -> Dict[str, Any]: + specs = list(class_specs or TARGET_TRAINING_CLASS_SPECS) + spec_lookup = {item.class_id: item for item in specs} + all_rows = [row for rows in split_rows_map.values() for row in rows] + mappings = build_index_maps(all_rows) + split_summary: Dict[str, Any] = {} + for split_name, rows in split_rows_map.items(): + class_counts: Dict[str, int] = {} + style_counts: Dict[str, int] = {} + scene_counts: Dict[str, int] = {} + source_counts: Dict[str, int] = {} + provenance_counts: Dict[str, int] = {} + readability = [] + stroke_counts = [] + naturalness = [] + for row in rows: + class_counts[row["class_id"]] = class_counts.get(row["class_id"], 0) + 1 + style_counts[row["style_id"]] = style_counts.get(row["style_id"], 0) + 1 + scene_counts[row["scene_type"]] = scene_counts.get(row["scene_type"], 0) + 1 + source = str(row.get("source") or "unknown") + source_counts[source] = source_counts.get(source, 0) + 1 + provenance = _normalize_provenance(row.get("provenance")) + provenance_counts[provenance] = provenance_counts.get(provenance, 0) + 1 + readability.append(int(row.get("readability_rank", 0) or 0)) + stroke_counts.append(int(row.get("stroke_count", 0) or 0)) + naturalness.append(float(row.get("naturalness_score", row.get("quality_score", 0.0)) or 0.0)) + real_rows = sum(count for key, count in provenance_counts.items() if key in REAL_PROVENANCE_TYPES) + split_summary[split_name] = { + "row_count": len(rows), + "class_counts": class_counts, + "style_counts": style_counts, + "scene_counts": scene_counts, + "source_counts": source_counts, + "provenance_counts": provenance_counts, + "avg_readability_rank": round(sum(readability) / max(1, len(readability)), 3), + "avg_stroke_count": round(sum(stroke_counts) / max(1, len(stroke_counts)), 3), + "avg_naturalness_score": round(sum(naturalness) / max(1, len(naturalness)), 4), + "real_data_ratio": round(real_rows / max(1, len(rows)), 4), + "bootstrap_ratio": round(provenance_counts.get("bootstrap", 0) / max(1, len(rows)), 4), + } + coverage = [] + for spec in specs: + class_rows = [row for row in all_rows if row.get("class_id") == spec.class_id] + total = len(class_rows) + real_rows = sum(1 for row in class_rows if _normalize_provenance(row.get("provenance")) in REAL_PROVENANCE_TYPES) + bootstrap_rows = sum(1 for row in class_rows if _normalize_provenance(row.get("provenance")) == "bootstrap") + real_ratio = real_rows / max(1, total) + target_real_ratio = 0.7 if spec.priority == 1 else 0.55 if spec.priority == 2 else 0.45 + coverage.append( + { + "class_id": spec.class_id, + "scene_type": spec.scene_type, + "sketch_family": spec.sketch_family, + "priority": spec.priority, + "min_target_samples": spec.min_target_samples, + "actual_samples": total, + "coverage_ratio": round(total / max(1, spec.min_target_samples), 3), + "real_samples": real_rows, + "real_ratio": round(real_ratio, 4), + "bootstrap_ratio": round(bootstrap_rows / max(1, total), 4), + "target_real_ratio": target_real_ratio, + } + ) + return { + "target_taxonomy": target_class_manifest(), + "mappings": mappings, + "splits": split_summary, + "coverage": coverage, + "row_count": len(all_rows), + "class_count": len({row["class_id"] for row in all_rows}), + "style_count": len({row["style_id"] for row in all_rows}), + "scene_type_count": len({row["scene_type"] for row in all_rows}), + "priority_gaps": [ + item + for item in coverage + if item["priority"] == 1 + and ( + item["actual_samples"] < spec_lookup[item["class_id"]].min_target_samples + or item["real_ratio"] < item["target_real_ratio"] + ) + ], + } + + +class PreparedObjectSketchDataset(Dataset): + def __init__( + self, + rows: Sequence[Dict[str, Any]], + mappings: Dict[str, Dict[str, int]], + *, + max_strokes: int = DEFAULT_MAX_STROKES, + points_per_stroke: int = DEFAULT_POINTS_PER_STROKE, + ): + self.rows = list(rows) + self.mappings = mappings + self.max_strokes = max_strokes + self.points_per_stroke = points_per_stroke + + def __len__(self) -> int: + return len(self.rows) + + def __getitem__(self, index: int) -> Dict[str, Any]: + row = self.rows[index] + sequence, mask = flatten_stroke_sequence( + row.get("strokes", []), + max_strokes=self.max_strokes, + points_per_stroke=self.points_per_stroke, + ) + class_to_idx = self.mappings["class_to_idx"] + style_to_idx = self.mappings["style_to_idx"] + scene_to_idx = self.mappings["scene_to_idx"] + family_to_idx = self.mappings["family_to_idx"] + provenance_to_idx = self.mappings.get("provenance_to_idx", {"unknown": 0}) + style_cluster_to_idx = self.mappings.get("style_cluster_to_idx", {}) + stroke_lengths = [float(value) for value in (row.get("stroke_lengths") or [])[: self.max_strokes]] + if len(stroke_lengths) < self.max_strokes: + stroke_lengths.extend([0.0] * (self.max_strokes - len(stroke_lengths))) + provenance = _normalize_provenance(row.get("provenance")) + style_cluster_id = str(row.get("style_cluster_id") or _default_style_cluster_id(style_id=row.get("style_id"), sketch_family=row.get("sketch_family"))) + return { + "sequence": sequence, + "mask": mask, + "class_id": torch.tensor(class_to_idx[row["class_id"]], dtype=torch.long), + "style_id": torch.tensor(style_to_idx[row["style_id"]], dtype=torch.long), + "scene_id": torch.tensor(scene_to_idx[row["scene_type"]], dtype=torch.long), + "family_id": torch.tensor(family_to_idx[row["sketch_family"]], dtype=torch.long), + "stroke_count": torch.tensor(min(self.max_strokes, int(row.get("stroke_count", len(row.get("strokes", []))) or 0)), dtype=torch.long), + "bbox": torch.tensor(row.get("bbox") or compute_bbox(row.get("strokes", [])), dtype=torch.float32), + "readability_rank": torch.tensor(float(row.get("readability_rank", 0) or 0.0), dtype=torch.float32), + "naturalness_score": torch.tensor(float(row.get("naturalness_score", row.get("quality_score", 0.0)) or 0.0), dtype=torch.float32), + "sample_weight": torch.tensor(float(row.get("sample_weight", 1.0) or 1.0), dtype=torch.float32), + "provenance_id": torch.tensor(provenance_to_idx.get(provenance, provenance_to_idx.get("unknown", 0)), dtype=torch.long), + "style_cluster_id": torch.tensor(style_cluster_to_idx.get(style_cluster_id, 0), dtype=torch.long), + "stroke_lengths": torch.tensor(stroke_lengths, dtype=torch.float32), + "sequence_length": torch.tensor(int(row.get("sequence_length", int(mask.sum().item())) or 0), dtype=torch.long), + } + + +def collate_object_sketch_batch(items: Sequence[Dict[str, Any]]) -> Dict[str, Any]: + return { + "sequence": torch.stack([item["sequence"] for item in items], dim=0), + "mask": torch.stack([item["mask"] for item in items], dim=0), + "class_id": torch.stack([item["class_id"] for item in items], dim=0), + "style_id": torch.stack([item["style_id"] for item in items], dim=0), + "scene_id": torch.stack([item["scene_id"] for item in items], dim=0), + "family_id": torch.stack([item["family_id"] for item in items], dim=0), + "stroke_count": torch.stack([item["stroke_count"] for item in items], dim=0), + "bbox": torch.stack([item["bbox"] for item in items], dim=0), + "readability_rank": torch.stack([item["readability_rank"] for item in items], dim=0), + "naturalness_score": torch.stack([item["naturalness_score"] for item in items], dim=0), + "sample_weight": torch.stack([item["sample_weight"] for item in items], dim=0), + "provenance_id": torch.stack([item["provenance_id"] for item in items], dim=0), + "style_cluster_id": torch.stack([item["style_cluster_id"] for item in items], dim=0), + "stroke_lengths": torch.stack([item["stroke_lengths"] for item in items], dim=0), + "sequence_length": torch.stack([item["sequence_length"] for item in items], dim=0), + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_model.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_model.py new file mode 100644 index 0000000..b53627a --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/object_sketch_model.py @@ -0,0 +1,517 @@ +from __future__ import annotations + +from dataclasses import dataclass + +try: + import torch + from torch import nn +except Exception: # pragma: no cover + torch = None + nn = None + + +@dataclass(slots=True) +class ObjectSketchConfig: + class_count: int + style_count: int + max_strokes: int = 8 + points_per_stroke: int = 32 + class_embed_dim: int = 24 + style_embed_dim: int = 12 + hidden_dim: int = 128 + latent_dim: int = 32 + + @property + def seq_len(self) -> int: + return self.max_strokes * self.points_per_stroke + + @property + def point_dim(self) -> int: + return 3 + + @property + def flat_dim(self) -> int: + return self.seq_len * self.point_dim + + +@dataclass(slots=True) +class ObjectSketchV2Config: + class_count: int + style_count: int + scene_count: int + family_count: int + max_strokes: int = 12 + points_per_stroke: int = 48 + class_embed_dim: int = 48 + style_embed_dim: int = 24 + scene_embed_dim: int = 16 + family_embed_dim: int = 16 + hidden_dim: int = 256 + latent_dim: int = 96 + encoder_layers: int = 2 + decoder_layers: int = 2 + dropout: float = 0.1 + + @property + def seq_len(self) -> int: + return self.max_strokes * self.points_per_stroke + + @property + def point_dim(self) -> int: + return 3 + + +@dataclass(slots=True) +class ObjectSketchV3Config: + class_count: int + style_count: int + scene_count: int + family_count: int + provenance_count: int = 1 + style_cluster_count: int = 1 + max_strokes: int = 12 + points_per_stroke: int = 48 + class_embed_dim: int = 56 + style_embed_dim: int = 24 + scene_embed_dim: int = 16 + family_embed_dim: int = 16 + provenance_embed_dim: int = 8 + style_cluster_embed_dim: int = 12 + hidden_dim: int = 320 + latent_dim: int = 128 + encoder_layers: int = 2 + dropout: float = 0.1 + + @property + def seq_len(self) -> int: + return self.max_strokes * self.points_per_stroke + + @property + def point_dim(self) -> int: + return 3 + + +if nn is not None: + class ObjectSketchCVAE(nn.Module): + def __init__(self, config: ObjectSketchConfig): + super().__init__() + self.config = config + self.class_embed = nn.Embedding(config.class_count, config.class_embed_dim) + self.style_embed = nn.Embedding(config.style_count, config.style_embed_dim) + cond_dim = config.class_embed_dim + config.style_embed_dim + self.encoder = nn.Sequential( + nn.Linear(config.flat_dim + cond_dim, config.hidden_dim), + nn.ReLU(), + nn.Linear(config.hidden_dim, config.hidden_dim), + nn.ReLU(), + ) + self.mu_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.logvar_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.decoder_input = nn.Linear(config.latent_dim + cond_dim, config.hidden_dim) + self.decoder = nn.GRU(input_size=config.hidden_dim, hidden_size=config.hidden_dim, batch_first=True) + self.output_head = nn.Linear(config.hidden_dim, config.point_dim) + + def _cond(self, class_ids, style_ids): + return torch.cat([self.class_embed(class_ids), self.style_embed(style_ids)], dim=-1) + + def encode(self, sequences, class_ids, style_ids): + batch = sequences.shape[0] + flattened = sequences.reshape(batch, -1) + hidden = self.encoder(torch.cat([flattened, self._cond(class_ids, style_ids)], dim=-1)) + return self.mu_head(hidden), self.logvar_head(hidden) + + def reparameterize(self, mu, logvar): + std = torch.exp(0.5 * logvar) + return mu + torch.randn_like(std) * std + + def decode(self, latent, class_ids, style_ids): + cond = self._cond(class_ids, style_ids) + repeated = self.decoder_input(torch.cat([latent, cond], dim=-1)).unsqueeze(1).repeat(1, self.config.seq_len, 1) + decoded, _ = self.decoder(repeated) + return self.output_head(decoded) + + def forward(self, sequences, class_ids, style_ids): + mu, logvar = self.encode(sequences, class_ids, style_ids) + latent = self.reparameterize(mu, logvar) + recon = self.decode(latent, class_ids, style_ids) + return recon, mu, logvar + + def sample(self, class_ids, style_ids, *, latent=None): + if latent is None: + latent = torch.randn((class_ids.shape[0], self.config.latent_dim), device=class_ids.device) + return self.decode(latent, class_ids, style_ids) + + + class ObjectSketchV2(nn.Module): + def __init__(self, config: ObjectSketchV2Config): + super().__init__() + self.config = config + cond_dim = config.class_embed_dim + config.style_embed_dim + config.scene_embed_dim + config.family_embed_dim + self.class_embed = nn.Embedding(config.class_count, config.class_embed_dim) + self.style_embed = nn.Embedding(config.style_count, config.style_embed_dim) + self.scene_embed = nn.Embedding(config.scene_count, config.scene_embed_dim) + self.family_embed = nn.Embedding(config.family_count, config.family_embed_dim) + self.input_proj = nn.Linear(config.point_dim, config.hidden_dim) + self.encoder = nn.GRU( + input_size=config.hidden_dim + cond_dim, + hidden_size=config.hidden_dim, + num_layers=config.encoder_layers, + batch_first=True, + dropout=config.dropout if config.encoder_layers > 1 else 0.0, + bidirectional=True, + ) + self.context_proj = nn.Sequential( + nn.Linear(config.hidden_dim * 2 + cond_dim, config.hidden_dim), + nn.GELU(), + nn.Dropout(config.dropout), + nn.Linear(config.hidden_dim, config.hidden_dim), + nn.GELU(), + ) + self.mu_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.logvar_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.position_embed = nn.Embedding(config.seq_len, config.hidden_dim) + self.decoder_token = nn.Parameter(torch.randn(1, 1, config.hidden_dim) * 0.02) + self.decoder_input = nn.Linear(config.latent_dim + cond_dim, config.hidden_dim) + self.decoder_hidden = nn.Linear(config.latent_dim + cond_dim, config.hidden_dim * config.decoder_layers) + self.decoder = nn.GRU( + input_size=config.hidden_dim, + hidden_size=config.hidden_dim, + num_layers=config.decoder_layers, + batch_first=True, + dropout=config.dropout if config.decoder_layers > 1 else 0.0, + ) + self.output_head = nn.Linear(config.hidden_dim, config.point_dim) + self.readability_head = nn.Sequential( + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 1), + ) + self.stroke_count_head = nn.Linear(config.hidden_dim, config.max_strokes + 1) + self.bbox_head = nn.Sequential( + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 4), + nn.Sigmoid(), + ) + + def _cond(self, class_ids, style_ids, scene_ids, family_ids): + return torch.cat( + [ + self.class_embed(class_ids), + self.style_embed(style_ids), + self.scene_embed(scene_ids), + self.family_embed(family_ids), + ], + dim=-1, + ) + + def encode(self, sequences, class_ids, style_ids, scene_ids, family_ids, *, mask=None): + cond = self._cond(class_ids, style_ids, scene_ids, family_ids) + token = self.input_proj(sequences) + cond_tokens = cond.unsqueeze(1).expand(-1, sequences.shape[1], -1) + encoded, _ = self.encoder(torch.cat([token, cond_tokens], dim=-1)) + if mask is None: + pooled = encoded.mean(dim=1) + else: + weights = mask.unsqueeze(-1).clamp(0.0, 1.0) + pooled = (encoded * weights).sum(dim=1) / weights.sum(dim=1).clamp_min(1.0) + hidden = self.context_proj(torch.cat([pooled, cond], dim=-1)) + return hidden, self.mu_head(hidden), self.logvar_head(hidden) + + def reparameterize(self, mu, logvar): + std = torch.exp(0.5 * logvar) + return mu + torch.randn_like(std) * std + + def decode(self, latent, class_ids, style_ids, scene_ids, family_ids): + cond = self._cond(class_ids, style_ids, scene_ids, family_ids) + cond_latent = torch.cat([latent, cond], dim=-1) + batch_size = class_ids.shape[0] + positions = self.position_embed( + torch.arange(self.config.seq_len, device=class_ids.device, dtype=torch.long) + ).unsqueeze(0) + base = self.decoder_input(cond_latent).unsqueeze(1).expand(batch_size, self.config.seq_len, -1) + tokens = base + positions + self.decoder_token.expand(batch_size, self.config.seq_len, -1) + hidden0 = self.decoder_hidden(cond_latent).view( + self.config.decoder_layers, + batch_size, + self.config.hidden_dim, + ).contiguous() + decoded, _ = self.decoder(tokens, hidden0) + raw = self.output_head(decoded) + points = torch.cat([torch.sigmoid(raw[..., :2]), raw[..., 2:3]], dim=-1) + summary = decoded.mean(dim=1) + aux = { + "readability": self.readability_head(summary).squeeze(-1), + "stroke_count_logits": self.stroke_count_head(summary), + "bbox": self.bbox_head(summary), + } + return points, aux + + def forward(self, sequences, class_ids, style_ids, scene_ids, family_ids, *, mask=None, **_): + hidden, mu, logvar = self.encode( + sequences, + class_ids, + style_ids, + scene_ids, + family_ids, + mask=mask, + ) + latent = self.reparameterize(mu, logvar) + recon, aux = self.decode(latent, class_ids, style_ids, scene_ids, family_ids) + aux["context"] = hidden + aux["latent"] = latent + return recon, mu, logvar, aux + + def sample(self, class_ids, style_ids, scene_ids, family_ids, *, latent=None, **_): + if latent is None: + latent = torch.randn((class_ids.shape[0], self.config.latent_dim), device=class_ids.device) + recon, aux = self.decode(latent, class_ids, style_ids, scene_ids, family_ids) + aux["latent"] = latent + return recon, aux + + + class ObjectSketchV3(nn.Module): + def __init__(self, config: ObjectSketchV3Config): + super().__init__() + self.config = config + cond_dim = ( + config.class_embed_dim + + config.style_embed_dim + + config.scene_embed_dim + + config.family_embed_dim + + config.provenance_embed_dim + + config.style_cluster_embed_dim + ) + self.class_embed = nn.Embedding(config.class_count, config.class_embed_dim) + self.style_embed = nn.Embedding(config.style_count, config.style_embed_dim) + self.scene_embed = nn.Embedding(config.scene_count, config.scene_embed_dim) + self.family_embed = nn.Embedding(config.family_count, config.family_embed_dim) + self.provenance_embed = nn.Embedding(max(1, config.provenance_count), config.provenance_embed_dim) + self.style_cluster_embed = nn.Embedding(max(1, config.style_cluster_count), config.style_cluster_embed_dim) + self.input_proj = nn.Sequential( + nn.Linear(config.point_dim, config.hidden_dim), + nn.LayerNorm(config.hidden_dim), + nn.GELU(), + ) + self.encoder = nn.GRU( + input_size=config.hidden_dim + cond_dim, + hidden_size=config.hidden_dim, + num_layers=config.encoder_layers, + batch_first=True, + dropout=config.dropout if config.encoder_layers > 1 else 0.0, + bidirectional=True, + ) + self.context_proj = nn.Sequential( + nn.Linear(config.hidden_dim * 2 + cond_dim, config.hidden_dim), + nn.GELU(), + nn.Dropout(config.dropout), + nn.Linear(config.hidden_dim, config.hidden_dim), + nn.GELU(), + ) + self.mu_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.logvar_head = nn.Linear(config.hidden_dim, config.latent_dim) + self.planner = nn.Sequential( + nn.Linear(config.hidden_dim + cond_dim, config.hidden_dim), + nn.GELU(), + nn.Dropout(config.dropout), + ) + self.stroke_count_head = nn.Linear(config.hidden_dim, config.max_strokes + 1) + self.stroke_length_head = nn.Linear(config.hidden_dim, config.max_strokes) + self.readability_head = nn.Sequential( + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 1), + ) + self.naturalness_head = nn.Sequential( + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 1), + ) + self.style_cluster_head = nn.Linear(config.hidden_dim, max(1, config.style_cluster_count)) + self.bbox_head = nn.Sequential( + nn.Linear(config.hidden_dim, config.hidden_dim // 2), + nn.GELU(), + nn.Linear(config.hidden_dim // 2, 4), + nn.Sigmoid(), + ) + self.position_embed = nn.Embedding(config.seq_len, config.hidden_dim) + self.decoder_input = nn.Sequential( + nn.Linear(config.point_dim + config.latent_dim + cond_dim + config.hidden_dim, config.hidden_dim), + nn.LayerNorm(config.hidden_dim), + nn.GELU(), + ) + self.decoder_cell = nn.GRUCell(config.hidden_dim, config.hidden_dim) + self.decoder_hidden = nn.Linear(config.latent_dim + cond_dim + config.hidden_dim, config.hidden_dim) + self.output_head = nn.Linear(config.hidden_dim, config.point_dim) + self.sample_context = nn.Sequential( + nn.Linear(config.latent_dim + cond_dim, config.hidden_dim), + nn.GELU(), + nn.Linear(config.hidden_dim, config.hidden_dim), + nn.GELU(), + ) + + def _cond(self, class_ids, style_ids, scene_ids, family_ids, provenance_ids, style_cluster_ids): + return torch.cat( + [ + self.class_embed(class_ids), + self.style_embed(style_ids), + self.scene_embed(scene_ids), + self.family_embed(family_ids), + self.provenance_embed(provenance_ids.clamp_min(0)), + self.style_cluster_embed(style_cluster_ids.clamp_min(0)), + ], + dim=-1, + ) + + def encode( + self, + sequences, + class_ids, + style_ids, + scene_ids, + family_ids, + provenance_ids, + style_cluster_ids, + *, + mask=None, + ): + cond = self._cond(class_ids, style_ids, scene_ids, family_ids, provenance_ids, style_cluster_ids) + token = self.input_proj(sequences) + cond_tokens = cond.unsqueeze(1).expand(-1, sequences.shape[1], -1) + encoded, _ = self.encoder(torch.cat([token, cond_tokens], dim=-1)) + if mask is None: + pooled = encoded.mean(dim=1) + else: + weights = mask.unsqueeze(-1).clamp(0.0, 1.0) + pooled = (encoded * weights).sum(dim=1) / weights.sum(dim=1).clamp_min(1.0) + hidden = self.context_proj(torch.cat([pooled, cond], dim=-1)) + planner_summary = self.planner(torch.cat([hidden, cond], dim=-1)) + return hidden, planner_summary, self.mu_head(hidden), self.logvar_head(hidden), cond + + def reparameterize(self, mu, logvar): + std = torch.exp(0.5 * logvar) + return mu + torch.randn_like(std) * std + + def decode( + self, + latent, + context, + cond, + *, + teacher_sequence=None, + teacher_forcing_ratio: float = 1.0, + ): + batch_size = latent.shape[0] + hidden = self.decoder_hidden(torch.cat([latent, cond, context], dim=-1)) + prev_point = torch.zeros((batch_size, self.config.point_dim), device=latent.device, dtype=latent.dtype) + outputs = [] + for step in range(self.config.seq_len): + position = self.position_embed( + torch.full((batch_size,), step, device=latent.device, dtype=torch.long) + ) + token = self.decoder_input(torch.cat([prev_point, latent, cond, context], dim=-1)) + position + hidden = self.decoder_cell(token, hidden) + raw = self.output_head(hidden) + point = torch.cat([torch.sigmoid(raw[..., :2]), raw[..., 2:3]], dim=-1) + outputs.append(point.unsqueeze(1)) + if teacher_sequence is None: + prev_point = point.detach() + continue + if teacher_forcing_ratio >= 1.0: + prev_point = teacher_sequence[:, step, :] + continue + use_teacher = ( + torch.rand((batch_size, 1), device=latent.device) < max(0.0, teacher_forcing_ratio) + ).to(point.dtype) + prev_point = teacher_sequence[:, step, :] * use_teacher + point.detach() * (1.0 - use_teacher) + return torch.cat(outputs, dim=1) + + def _build_aux(self, planner_summary, context): + return { + "readability": self.readability_head(context).squeeze(-1), + "stroke_count_logits": self.stroke_count_head(planner_summary), + "stroke_length_logits": self.stroke_length_head(planner_summary), + "bbox": self.bbox_head(context), + "naturalness": self.naturalness_head(context).squeeze(-1), + "style_cluster_logits": self.style_cluster_head(context), + "style_embedding": context, + } + + def forward( + self, + sequences, + class_ids, + style_ids, + scene_ids, + family_ids, + *, + provenance_ids=None, + style_cluster_ids=None, + mask=None, + teacher_forcing_ratio: float = 1.0, + ): + if provenance_ids is None: + provenance_ids = torch.zeros_like(class_ids) + if style_cluster_ids is None: + style_cluster_ids = torch.zeros_like(class_ids) + context, planner_summary, mu, logvar, cond = self.encode( + sequences, + class_ids, + style_ids, + scene_ids, + family_ids, + provenance_ids, + style_cluster_ids, + mask=mask, + ) + latent = self.reparameterize(mu, logvar) + recon = self.decode( + latent, + context, + cond, + teacher_sequence=sequences, + teacher_forcing_ratio=teacher_forcing_ratio, + ) + aux = self._build_aux(planner_summary, context) + aux["context"] = context + aux["latent"] = latent + return recon, mu, logvar, aux + + def sample( + self, + class_ids, + style_ids, + scene_ids, + family_ids, + *, + provenance_ids=None, + style_cluster_ids=None, + latent=None, + ): + if provenance_ids is None: + provenance_ids = torch.zeros_like(class_ids) + if style_cluster_ids is None: + style_cluster_ids = torch.zeros_like(class_ids) + if latent is None: + latent = torch.randn((class_ids.shape[0], self.config.latent_dim), device=class_ids.device) + cond = self._cond(class_ids, style_ids, scene_ids, family_ids, provenance_ids, style_cluster_ids) + context = self.sample_context(torch.cat([latent, cond], dim=-1)) + recon = self.decode(latent, context, cond, teacher_sequence=None, teacher_forcing_ratio=0.0) + aux = self._build_aux(context, context) + aux["context"] = context + aux["latent"] = latent + return recon, aux +else: # pragma: no cover + class ObjectSketchCVAE: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use ObjectSketchCVAE") + + + class ObjectSketchV2: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use ObjectSketchV2") + + + class ObjectSketchV3: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use ObjectSketchV3") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_dataset.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_dataset.py new file mode 100644 index 0000000..51e2d8c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_dataset.py @@ -0,0 +1,804 @@ +from __future__ import annotations + +import hashlib +import json +import math +from dataclasses import asdict, dataclass, field +from pathlib import Path +from types import SimpleNamespace +from typing import Any, Iterator, Sequence + +try: + import torch + from torch.utils.data import Dataset, Sampler +except Exception as exc: # pragma: no cover - torch is required for trainer usage + raise RuntimeError(f"torch is required for Tri-Maze policy datasets: {exc}") + + +BASE_FEATURE_DIM = 13 +PATH_CONTEXT_DIM = 6 +CANDIDATE_FLAG_DIM = 4 +DEFAULT_HISTORY_SIZE = 4 +FEATURE_SCHEMA_VERSION = "tri_maze_policy_v2.0" +PAD_ID = 0 +UNK_ID = 1 + + +def _normalize_text(value: Any) -> str: + if value is None: + return "" + return " ".join(str(value).replace("\u00a0", " ").strip().split()) + + +def _stable_hash(text: str) -> int: + digest = hashlib.md5(text.encode("utf-8", errors="ignore")).digest() + return int.from_bytes(digest[:8], "big") + + +def _hash_bucket(text: str, bucket_count: int) -> int: + if bucket_count <= 0: + return 0 + normalized = _normalize_text(text) + if not normalized: + return 0 + return 1 + (_stable_hash(normalized.casefold()) % bucket_count) + + +def _clamp01(value: Any, default: float = 0.0) -> float: + try: + return max(0.0, min(1.0, float(value))) + except Exception: + return float(default) + + +def _mode_one_hot(mode: str) -> list[float]: + normalized = (_normalize_text(mode) or "forward").lower() + if normalized == "reverse": + return [0.0, 1.0, 0.0] + if normalized == "boundary": + return [0.0, 0.0, 1.0] + return [1.0, 0.0, 0.0] + + +def compute_candidate_base_features( + engine: Any, + current_node: Any, + edge: Any, + *, + path: Any = None, + visited: set[str] | None = None, + mode: str = "forward", + max_degree: int | None = None, +) -> list[float]: + visited = visited or set() + next_node = edge.to_node + degree_cur = len(getattr(current_node, "connections", []) or []) + degree_next = len(getattr(next_node, "connections", []) or []) + max_degree = max(1, int(max_degree or getattr(engine, "_max_degree", 1) or 1)) + + resistance = float(getattr(edge, "resistance", 0.5) or 0.5) + memory_reinf = 0.0 + if getattr(engine, "memory", None): + try: + memory_reinf = float( + engine.memory.get_edge_reinforcement(current_node.concept, next_node.concept) + ) + except Exception: + memory_reinf = 0.0 + + semantic = 0.0 + if hasattr(engine, "_semantic_similarity"): + try: + semantic = float(engine._semantic_similarity(current_node.concept, next_node.concept)) + except Exception: + semantic = 0.0 + + visited_flag = 1.0 if next_node.concept in visited else 0.0 + path_len = float(getattr(path, "length", 0) or 0) + max_steps = float(getattr(engine, "max_exploration_steps", 1) or 1) + + features = [ + resistance, + memory_reinf, + semantic, + min(1.0, degree_cur / max_degree), + min(1.0, degree_next / max_degree), + min(1.0, path_len / max_steps), + visited_flag, + 1.0 if getattr(edge, "is_memory", False) else 0.0, + 1.0 if getattr(edge, "is_expanded", False) else 0.0, + 1.0 if getattr(edge, "is_tunneling", False) else 0.0, + ] + features.extend(_mode_one_hot(mode)) + return features + + +def build_path_context_features( + *, + path_length: int, + visited_count: int, + candidate_count: int, + max_degree: int, + history_count: int, + revisit_ratio: float, + max_steps: int | None = None, +) -> list[float]: + max_degree = max(1, int(max_degree or 1)) + max_steps = max(1, int(max_steps or 80)) + path_length_norm = min(1.0, max(0, path_length) / max_steps) + candidate_density = min(1.0, max(0, candidate_count) / max_degree) + visited_density = min(1.0, max(0, visited_count) / max(1, path_length + candidate_count + 1)) + branch_density = min(1.0, max(0, candidate_count) / max(1, visited_count + candidate_count)) + history_fill = min(1.0, max(0, history_count) / max(1, DEFAULT_HISTORY_SIZE)) + revisit_ratio = _clamp01(revisit_ratio) + return [ + path_length_norm, + candidate_density, + visited_density, + branch_density, + history_fill, + revisit_ratio, + ] + + +def _path_length_bucket(path_length: int) -> int: + if path_length <= 1: + return 0 + if path_length <= 3: + return 1 + if path_length <= 5: + return 2 + return 3 + + +@dataclass(slots=True) +class CurriculumConfig: + enabled: bool = False + min_fraction: float = 0.35 + max_fraction: float = 1.0 + include_tunneling_after: float = 0.45 + include_hard_after: float = 0.55 + + def fraction_for_epoch(self, epoch: int, total_epochs: int) -> float: + if not self.enabled: + return self.max_fraction + total_epochs = max(1, int(total_epochs)) + progress = min(1.0, max(0.0, float(epoch) / max(1, total_epochs - 1))) + return self.min_fraction + (self.max_fraction - self.min_fraction) * progress + + +@dataclass(slots=True) +class PolicyStepRecord: + sample_id: str + source_kind: str + source_dataset: str + query_type: str + mode: str + task_key: str + current_concept: str + recent_concepts: tuple[str, ...] + visited_concepts: tuple[str, ...] + candidate_concepts: tuple[str, ...] + candidate_relations: tuple[str, ...] + candidate_base_features: tuple[tuple[float, ...], ...] + candidate_is_memory: tuple[int, ...] + candidate_is_expanded: tuple[int, ...] + candidate_is_tunneling: tuple[int, ...] + target_index: int + weight: float + path_length: int + path_length_bucket: int + difficulty: float + high_value_target: int + has_tunneling_path: int + source_score: float = 0.0 + metadata: dict[str, Any] = field(default_factory=dict) + + def to_dict(self) -> dict[str, Any]: + payload = asdict(self) + for key in ( + "recent_concepts", + "visited_concepts", + "candidate_concepts", + "candidate_relations", + "candidate_is_memory", + "candidate_is_expanded", + "candidate_is_tunneling", + ): + payload[key] = list(payload[key]) + payload["candidate_base_features"] = [list(item) for item in self.candidate_base_features] + return payload + + @classmethod + def from_dict(cls, payload: dict[str, Any]) -> "PolicyStepRecord": + return cls( + sample_id=_normalize_text(payload.get("sample_id") or ""), + source_kind=_normalize_text(payload.get("source_kind") or "unknown"), + source_dataset=_normalize_text(payload.get("source_dataset") or "unknown"), + query_type=_normalize_text(payload.get("query_type") or "query"), + mode=_normalize_text(payload.get("mode") or "forward"), + task_key=_normalize_text(payload.get("task_key") or "default"), + current_concept=_normalize_text(payload.get("current_concept") or ""), + recent_concepts=tuple(_normalize_text(item) for item in payload.get("recent_concepts") or [] if _normalize_text(item)), + visited_concepts=tuple(_normalize_text(item) for item in payload.get("visited_concepts") or [] if _normalize_text(item)), + candidate_concepts=tuple(_normalize_text(item) for item in payload.get("candidate_concepts") or [] if _normalize_text(item)), + candidate_relations=tuple(_normalize_text(item) for item in payload.get("candidate_relations") or [] if _normalize_text(item)), + candidate_base_features=tuple( + tuple(float(value) for value in feature_row) + for feature_row in payload.get("candidate_base_features") or [] + ), + candidate_is_memory=tuple(int(value) for value in payload.get("candidate_is_memory") or []), + candidate_is_expanded=tuple(int(value) for value in payload.get("candidate_is_expanded") or []), + candidate_is_tunneling=tuple(int(value) for value in payload.get("candidate_is_tunneling") or []), + target_index=int(payload.get("target_index", -1)), + weight=float(payload.get("weight", 1.0) or 1.0), + path_length=int(payload.get("path_length", 0) or 0), + path_length_bucket=int(payload.get("path_length_bucket", _path_length_bucket(int(payload.get("path_length", 0) or 0)))), + difficulty=float(payload.get("difficulty", 0.0) or 0.0), + high_value_target=int(payload.get("high_value_target", 0) or 0), + has_tunneling_path=int(payload.get("has_tunneling_path", 0) or 0), + source_score=float(payload.get("source_score", 0.0) or 0.0), + metadata=dict(payload.get("metadata") or {}), + ) + + def all_concepts(self) -> set[str]: + concepts = {self.current_concept} + concepts.update(self.recent_concepts) + concepts.update(self.visited_concepts) + concepts.update(self.candidate_concepts) + return {item for item in concepts if item} + + +@dataclass(slots=True) +class PolicyVocabulary: + concept_to_id: dict[str, int] + relation_to_id: dict[str, int] + source_to_id: dict[str, int] + query_type_to_id: dict[str, int] + mode_to_id: dict[str, int] + task_to_id: dict[str, int] + hash_bucket_size: int = 8192 + + @classmethod + def empty(cls, *, hash_bucket_size: int = 8192) -> "PolicyVocabulary": + return cls( + concept_to_id={"": PAD_ID, "": UNK_ID}, + relation_to_id={"": PAD_ID, "": UNK_ID}, + source_to_id={"": PAD_ID, "": UNK_ID}, + query_type_to_id={"": PAD_ID, "": UNK_ID}, + mode_to_id={"": PAD_ID, "": UNK_ID, "forward": 2, "reverse": 3, "boundary": 4, "runtime": 5}, + task_to_id={"": PAD_ID, "": UNK_ID}, + hash_bucket_size=max(32, int(hash_bucket_size)), + ) + + @classmethod + def build( + cls, + records: Sequence[PolicyStepRecord], + *, + hash_bucket_size: int = 8192, + ) -> "PolicyVocabulary": + vocab = cls.empty(hash_bucket_size=hash_bucket_size) + for record in records: + vocab._add(vocab.concept_to_id, record.current_concept) + for concept in record.recent_concepts: + vocab._add(vocab.concept_to_id, concept) + for concept in record.visited_concepts: + vocab._add(vocab.concept_to_id, concept) + for concept in record.candidate_concepts: + vocab._add(vocab.concept_to_id, concept) + for relation in record.candidate_relations: + vocab._add(vocab.relation_to_id, relation) + vocab._add(vocab.source_to_id, record.source_dataset) + vocab._add(vocab.query_type_to_id, record.query_type) + vocab._add(vocab.mode_to_id, record.mode) + vocab._add(vocab.task_to_id, record.task_key) + return vocab + + @staticmethod + def _key(value: str) -> str: + normalized = _normalize_text(value) + return normalized.casefold() if normalized else "" + + def _add(self, mapping: dict[str, int], value: str) -> None: + key = self._key(value) + if not key or key in mapping: + return + mapping[key] = len(mapping) + + def encode_token(self, mapping: dict[str, int], value: str) -> int: + key = self._key(value) + if not key: + return PAD_ID + return int(mapping.get(key, UNK_ID)) + + def encode_concept(self, value: str) -> tuple[int, int]: + return ( + self.encode_token(self.concept_to_id, value), + _hash_bucket(value, self.hash_bucket_size), + ) + + def encode_relation(self, value: str) -> int: + return self.encode_token(self.relation_to_id, value) + + def encode_source(self, value: str) -> int: + return self.encode_token(self.source_to_id, value) + + def encode_query_type(self, value: str) -> int: + return self.encode_token(self.query_type_to_id, value) + + def encode_mode(self, value: str) -> int: + return self.encode_token(self.mode_to_id, value) + + def encode_task(self, value: str) -> int: + return self.encode_token(self.task_to_id, value) + + @property + def concept_vocab_size(self) -> int: + return len(self.concept_to_id) + + @property + def relation_vocab_size(self) -> int: + return len(self.relation_to_id) + + @property + def source_vocab_size(self) -> int: + return len(self.source_to_id) + + @property + def query_type_vocab_size(self) -> int: + return len(self.query_type_to_id) + + @property + def mode_vocab_size(self) -> int: + return len(self.mode_to_id) + + @property + def task_vocab_size(self) -> int: + return len(self.task_to_id) + + def to_metadata(self) -> dict[str, Any]: + return { + "concept_to_id": self.concept_to_id, + "relation_to_id": self.relation_to_id, + "source_to_id": self.source_to_id, + "query_type_to_id": self.query_type_to_id, + "mode_to_id": self.mode_to_id, + "task_to_id": self.task_to_id, + "hash_bucket_size": self.hash_bucket_size, + } + + @classmethod + def from_metadata(cls, payload: dict[str, Any] | None) -> "PolicyVocabulary": + if not payload: + return cls.empty() + return cls( + concept_to_id={str(k): int(v) for k, v in dict(payload.get("concept_to_id") or {}).items()}, + relation_to_id={str(k): int(v) for k, v in dict(payload.get("relation_to_id") or {}).items()}, + source_to_id={str(k): int(v) for k, v in dict(payload.get("source_to_id") or {}).items()}, + query_type_to_id={str(k): int(v) for k, v in dict(payload.get("query_type_to_id") or {}).items()}, + mode_to_id={str(k): int(v) for k, v in dict(payload.get("mode_to_id") or {}).items()}, + task_to_id={str(k): int(v) for k, v in dict(payload.get("task_to_id") or {}).items()}, + hash_bucket_size=max(32, int(payload.get("hash_bucket_size", 8192) or 8192)), + ) + + +@dataclass(slots=True) +class PolicyBatch: + sample_ids: list[str] + source_kinds: list[str] + current_concept_ids: torch.Tensor + current_hash_ids: torch.Tensor + history_concept_ids: torch.Tensor + history_hash_ids: torch.Tensor + candidate_concept_ids: torch.Tensor + candidate_hash_ids: torch.Tensor + relation_ids: torch.Tensor + source_ids: torch.Tensor + query_type_ids: torch.Tensor + mode_ids: torch.Tensor + task_ids: torch.Tensor + base_features: torch.Tensor + path_context: torch.Tensor + candidate_flags: torch.Tensor + candidate_mask: torch.Tensor + target_index: torch.Tensor + weights: torch.Tensor + path_length_bucket: torch.Tensor + tunnel_label: torch.Tensor + high_value_label: torch.Tensor + difficulty: torch.Tensor + candidate_count: torch.Tensor + + def to(self, device: torch.device | str) -> "PolicyBatch": + for field_name in self.__dataclass_fields__: + value = getattr(self, field_name) + if torch.is_tensor(value): + setattr(self, field_name, value.to(device)) + return self + + @property + def batch_size(self) -> int: + return int(self.current_concept_ids.shape[0]) + + +class PolicyStepDataset(Dataset): + def __init__( + self, + records: Sequence[PolicyStepRecord], + *, + vocabulary: PolicyVocabulary | None = None, + history_size: int = DEFAULT_HISTORY_SIZE, + feature_schema_version: str = FEATURE_SCHEMA_VERSION, + ) -> None: + self.records = list(records) + self.history_size = max(1, int(history_size)) + self.feature_schema_version = feature_schema_version + self.vocabulary = vocabulary or PolicyVocabulary.build(self.records) + self._encoded = [self._encode_record(record) for record in self.records] + + def __len__(self) -> int: + return len(self.records) + + def __getitem__(self, index: int) -> dict[str, Any]: + return self._encoded[index] + + def _encode_record(self, record: PolicyStepRecord) -> dict[str, Any]: + vocab = self.vocabulary + history = list(record.recent_concepts[-self.history_size :]) + while len(history) < self.history_size: + history.insert(0, "") + + current_id, current_hash = vocab.encode_concept(record.current_concept) + history_ids: list[int] = [] + history_hash_ids: list[int] = [] + for concept in history: + concept_id, hash_id = vocab.encode_concept(concept) + history_ids.append(concept_id) + history_hash_ids.append(hash_id) + + candidate_ids: list[int] = [] + candidate_hash_ids: list[int] = [] + relation_ids: list[int] = [] + candidate_flags: list[list[float]] = [] + candidate_features: list[list[float]] = [] + candidate_count = len(record.candidate_concepts) + visited_set = {item.casefold() for item in record.visited_concepts} + revisit_hits = 0 + for index, concept in enumerate(record.candidate_concepts): + concept_id, hash_id = vocab.encode_concept(concept) + candidate_ids.append(concept_id) + candidate_hash_ids.append(hash_id) + relation_ids.append(vocab.encode_relation(record.candidate_relations[index] if index < len(record.candidate_relations) else "related_to")) + visited_flag = 1.0 if concept.casefold() in visited_set else 0.0 + revisit_hits += int(visited_flag > 0.0) + candidate_flags.append( + [ + float(record.candidate_is_memory[index] if index < len(record.candidate_is_memory) else 0), + float(record.candidate_is_expanded[index] if index < len(record.candidate_is_expanded) else 0), + float(record.candidate_is_tunneling[index] if index < len(record.candidate_is_tunneling) else 0), + visited_flag, + ] + ) + feature_row = list(record.candidate_base_features[index] if index < len(record.candidate_base_features) else ()) + if len(feature_row) < BASE_FEATURE_DIM: + feature_row.extend([0.0] * (BASE_FEATURE_DIM - len(feature_row))) + candidate_features.append(feature_row[:BASE_FEATURE_DIM]) + + path_context = build_path_context_features( + path_length=record.path_length, + visited_count=len(record.visited_concepts), + candidate_count=candidate_count, + max_degree=max(candidate_count, 1), + history_count=len(record.recent_concepts), + revisit_ratio=float(revisit_hits / max(1, candidate_count)), + ) + + return { + "sample_id": record.sample_id, + "source_kind": record.source_kind, + "current_concept_id": current_id, + "current_hash_id": current_hash, + "history_concept_ids": history_ids, + "history_hash_ids": history_hash_ids, + "candidate_concept_ids": candidate_ids, + "candidate_hash_ids": candidate_hash_ids, + "relation_ids": relation_ids, + "source_id": vocab.encode_source(record.source_dataset), + "query_type_id": vocab.encode_query_type(record.query_type), + "mode_id": vocab.encode_mode(record.mode), + "task_id": vocab.encode_task(record.task_key), + "base_features": candidate_features, + "path_context": path_context, + "candidate_flags": candidate_flags, + "target_index": int(record.target_index), + "weight": float(record.weight), + "path_length_bucket": int(record.path_length_bucket), + "tunnel_label": int(record.has_tunneling_path), + "high_value_label": int(record.high_value_target), + "difficulty": float(record.difficulty), + "candidate_count": int(candidate_count), + } + + +def policy_collate_fn(batch: Sequence[dict[str, Any]]) -> PolicyBatch: + if not batch: + raise ValueError("cannot collate empty policy batch") + + batch_size = len(batch) + max_candidates = max(1, max(int(item["candidate_count"]) for item in batch)) + history_size = max(1, len(batch[0]["history_concept_ids"])) + + current_concept_ids = torch.zeros(batch_size, dtype=torch.long) + current_hash_ids = torch.zeros(batch_size, dtype=torch.long) + history_concept_ids = torch.zeros(batch_size, history_size, dtype=torch.long) + history_hash_ids = torch.zeros(batch_size, history_size, dtype=torch.long) + candidate_concept_ids = torch.zeros(batch_size, max_candidates, dtype=torch.long) + candidate_hash_ids = torch.zeros(batch_size, max_candidates, dtype=torch.long) + relation_ids = torch.zeros(batch_size, max_candidates, dtype=torch.long) + source_ids = torch.zeros(batch_size, dtype=torch.long) + query_type_ids = torch.zeros(batch_size, dtype=torch.long) + mode_ids = torch.zeros(batch_size, dtype=torch.long) + task_ids = torch.zeros(batch_size, dtype=torch.long) + base_features = torch.zeros(batch_size, max_candidates, BASE_FEATURE_DIM, dtype=torch.float32) + path_context = torch.zeros(batch_size, PATH_CONTEXT_DIM, dtype=torch.float32) + candidate_flags = torch.zeros(batch_size, max_candidates, CANDIDATE_FLAG_DIM, dtype=torch.float32) + candidate_mask = torch.zeros(batch_size, max_candidates, dtype=torch.bool) + target_index = torch.full((batch_size,), -1, dtype=torch.long) + weights = torch.ones(batch_size, dtype=torch.float32) + path_length_bucket = torch.zeros(batch_size, dtype=torch.long) + tunnel_label = torch.zeros(batch_size, dtype=torch.float32) + high_value_label = torch.zeros(batch_size, dtype=torch.float32) + difficulty = torch.zeros(batch_size, dtype=torch.float32) + candidate_count = torch.zeros(batch_size, dtype=torch.long) + + sample_ids: list[str] = [] + source_kinds: list[str] = [] + + for row_index, row in enumerate(batch): + count = int(row["candidate_count"]) + sample_ids.append(str(row["sample_id"])) + source_kinds.append(str(row["source_kind"])) + current_concept_ids[row_index] = int(row["current_concept_id"]) + current_hash_ids[row_index] = int(row["current_hash_id"]) + history_concept_ids[row_index] = torch.tensor(row["history_concept_ids"], dtype=torch.long) + history_hash_ids[row_index] = torch.tensor(row["history_hash_ids"], dtype=torch.long) + if count > 0: + candidate_concept_ids[row_index, :count] = torch.tensor(row["candidate_concept_ids"], dtype=torch.long) + candidate_hash_ids[row_index, :count] = torch.tensor(row["candidate_hash_ids"], dtype=torch.long) + relation_ids[row_index, :count] = torch.tensor(row["relation_ids"], dtype=torch.long) + base_features[row_index, :count] = torch.tensor(row["base_features"], dtype=torch.float32) + candidate_flags[row_index, :count] = torch.tensor(row["candidate_flags"], dtype=torch.float32) + candidate_mask[row_index, :count] = True + source_ids[row_index] = int(row["source_id"]) + query_type_ids[row_index] = int(row["query_type_id"]) + mode_ids[row_index] = int(row["mode_id"]) + task_ids[row_index] = int(row["task_id"]) + path_context[row_index] = torch.tensor(row["path_context"], dtype=torch.float32) + target_index[row_index] = int(row["target_index"]) + weights[row_index] = float(row["weight"]) + path_length_bucket[row_index] = int(row["path_length_bucket"]) + tunnel_label[row_index] = float(row["tunnel_label"]) + high_value_label[row_index] = float(row["high_value_label"]) + difficulty[row_index] = float(row["difficulty"]) + candidate_count[row_index] = int(count) + + return PolicyBatch( + sample_ids=sample_ids, + source_kinds=source_kinds, + current_concept_ids=current_concept_ids, + current_hash_ids=current_hash_ids, + history_concept_ids=history_concept_ids, + history_hash_ids=history_hash_ids, + candidate_concept_ids=candidate_concept_ids, + candidate_hash_ids=candidate_hash_ids, + relation_ids=relation_ids, + source_ids=source_ids, + query_type_ids=query_type_ids, + mode_ids=mode_ids, + task_ids=task_ids, + base_features=base_features, + path_context=path_context, + candidate_flags=candidate_flags, + candidate_mask=candidate_mask, + target_index=target_index, + weights=weights, + path_length_bucket=path_length_bucket, + tunnel_label=tunnel_label, + high_value_label=high_value_label, + difficulty=difficulty, + candidate_count=candidate_count, + ) + + +class EpisodicBatchSampler(Sampler[list[int]]): + def __init__(self, records: Sequence[PolicyStepRecord], *, batch_size: int, seed: int = 42) -> None: + self.batch_size = max(1, int(batch_size)) + self.seed = int(seed) + task_groups: dict[str, list[int]] = {} + for index, record in enumerate(records): + task_groups.setdefault(record.task_key or "default", []).append(index) + self.task_groups = {key: value for key, value in task_groups.items() if value} + self.task_keys = list(self.task_groups.keys()) + + def __iter__(self) -> Iterator[list[int]]: + if not self.task_keys: + return iter(()) + generator = torch.Generator().manual_seed(self.seed) + task_order = torch.randperm(len(self.task_keys), generator=generator).tolist() + batches: list[list[int]] = [] + for task_index in task_order: + indices = self.task_groups[self.task_keys[task_index]].copy() + if len(indices) > 1: + perm = torch.randperm(len(indices), generator=generator).tolist() + indices = [indices[item] for item in perm] + for start in range(0, len(indices), self.batch_size): + batches.append(indices[start : start + self.batch_size]) + return iter(batches) + + def __len__(self) -> int: + total = 0 + for indices in self.task_groups.values(): + total += math.ceil(len(indices) / self.batch_size) + return total + + +def build_domain_sampling_weights(records: Sequence[PolicyStepRecord]) -> list[float]: + if not records: + return [] + counts: dict[tuple[str, str], int] = {} + for record in records: + key = ( + _normalize_text(record.source_dataset).casefold() or "unknown", + _normalize_text(record.query_type).casefold() or "query", + ) + counts[key] = counts.get(key, 0) + 1 + weights: list[float] = [] + for record in records: + key = ( + _normalize_text(record.source_dataset).casefold() or "unknown", + _normalize_text(record.query_type).casefold() or "query", + ) + weights.append(1.0 / max(1, counts.get(key, 1))) + return weights + + +def filter_curriculum_records( + records: Sequence[PolicyStepRecord], + *, + epoch: int, + total_epochs: int, + curriculum: CurriculumConfig, +) -> list[PolicyStepRecord]: + if not curriculum.enabled or not records: + return list(records) + ordered = sorted(records, key=lambda item: (item.difficulty, item.path_length, item.sample_id)) + cutoff = max(1, int(math.ceil(len(ordered) * curriculum.fraction_for_epoch(epoch, total_epochs)))) + allowed = ordered[:cutoff] + progress = min(1.0, max(0.0, float(epoch) / max(1, total_epochs - 1))) + if progress >= curriculum.include_tunneling_after: + tunneling_records = [record for record in records if record.has_tunneling_path and record not in allowed] + allowed.extend(tunneling_records) + if progress >= curriculum.include_hard_after: + hard_records = [record for record in records if len(record.candidate_concepts) > 3 and record not in allowed] + allowed.extend(hard_records) + seen = set() + deduped: list[PolicyStepRecord] = [] + for record in allowed: + if record.sample_id in seen: + continue + seen.add(record.sample_id) + deduped.append(record) + return deduped + + +def serialize_policy_records(path: str | Path, records: Sequence[PolicyStepRecord]) -> None: + target = Path(path) + target.parent.mkdir(parents=True, exist_ok=True) + with target.open("w", encoding="utf-8") as handle: + for record in records: + handle.write(json.dumps(record.to_dict(), ensure_ascii=False) + "\n") + + +def load_policy_records(path: str | Path) -> list[PolicyStepRecord]: + records: list[PolicyStepRecord] = [] + with Path(path).open("r", encoding="utf-8-sig") as handle: + for raw in handle: + line = raw.strip() + if not line: + continue + payload = json.loads(line) + if isinstance(payload, dict): + records.append(PolicyStepRecord.from_dict(payload)) + return records + + +def build_runtime_step_record( + engine: Any, + current_node: Any, + candidate_edges: Sequence[Any], + *, + path: Any = None, + visited: set[str] | None = None, + mode: str = "forward", + target_index: int = -1, + sample_id: str | None = None, + source_kind: str = "runtime", + source_dataset: str = "runtime", + query_type: str = "runtime", + task_key: str = "runtime|runtime|forward", + weight: float = 1.0, + source_score: float = 0.0, +) -> PolicyStepRecord: + visited = visited or set() + candidate_edges = list(candidate_edges) + candidate_concepts = tuple(getattr(edge.to_node, "concept", "") for edge in candidate_edges) + candidate_relations = tuple(_normalize_text(getattr(edge, "relation", "") or "related_to") for edge in candidate_edges) + base_features = tuple( + tuple( + compute_candidate_base_features( + engine, + current_node, + edge, + path=path, + visited=visited, + mode=mode, + max_degree=getattr(engine, "_max_degree", 1), + ) + ) + for edge in candidate_edges + ) + candidate_is_memory = tuple(1 if getattr(edge, "is_memory", False) else 0 for edge in candidate_edges) + candidate_is_expanded = tuple(1 if getattr(edge, "is_expanded", False) else 0 for edge in candidate_edges) + candidate_is_tunneling = tuple(1 if getattr(edge, "is_tunneling", False) else 0 for edge in candidate_edges) + + path_nodes = [getattr(node, "concept", "") for node in getattr(path, "nodes", []) if getattr(node, "concept", "")] + recent_concepts = tuple(path_nodes[-DEFAULT_HISTORY_SIZE:]) + visited_concepts = tuple(sorted(_normalize_text(item) for item in visited if _normalize_text(item))) + candidate_count = len(candidate_edges) + target_index = int(target_index) + selected_edge = candidate_edges[target_index] if 0 <= target_index < len(candidate_edges) else None + high_value_target = 0 + if selected_edge is not None: + heuristic_score = 1.0 - float(getattr(selected_edge, "resistance", 0.5) or 0.5) + heuristic_score += 0.25 * float(getattr(selected_edge, "is_memory", False)) + heuristic_score += 0.15 * float(getattr(selected_edge, "is_expanded", False)) + high_value_target = int(heuristic_score >= 0.75) + has_tunneling_path = int(any(getattr(edge, "is_tunneling", False) for edge in getattr(path, "edges", []) or [])) + difficulty = ( + float(getattr(path, "length", 0) or 0) + + 0.5 * max(0, candidate_count - 1) + + 1.25 * float(has_tunneling_path) + + 0.5 * float(target_index >= 0 and candidate_count > 3) + ) + return PolicyStepRecord( + sample_id=sample_id or f"runtime::{current_node.concept}::{mode}::{_stable_hash('|'.join(candidate_concepts))}", + source_kind=source_kind, + source_dataset=source_dataset or "runtime", + query_type=query_type or "runtime", + mode=mode or "forward", + task_key=task_key or f"{source_dataset}|{query_type}|{mode}", + current_concept=_normalize_text(getattr(current_node, "concept", "")), + recent_concepts=recent_concepts, + visited_concepts=visited_concepts, + candidate_concepts=candidate_concepts, + candidate_relations=candidate_relations, + candidate_base_features=base_features, + candidate_is_memory=candidate_is_memory, + candidate_is_expanded=candidate_is_expanded, + candidate_is_tunneling=candidate_is_tunneling, + target_index=target_index, + weight=float(weight), + path_length=int(getattr(path, "length", 0) or 0), + path_length_bucket=_path_length_bucket(int(getattr(path, "length", 0) or 0)), + difficulty=float(difficulty), + high_value_target=high_value_target, + has_tunneling_path=has_tunneling_path, + source_score=float(source_score), + metadata={"candidate_count": candidate_count}, + ) + + +def build_path_stub(engine: Any, concepts: Sequence[str]) -> Any: + nodes = [engine.nodes[concept] for concept in concepts if concept in engine.nodes] + return SimpleNamespace(length=max(0, len(concepts) - 1), nodes=nodes, edges=[]) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_network.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_network.py new file mode 100644 index 0000000..0bea907 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/policy_network.py @@ -0,0 +1,880 @@ +""" +Neural policy for Tri-Maze exploration (non-LLM). +Provides a backward-compatible EdgePolicy wrapper that can load the original +v1 shallow MLP checkpoints or the new v2 structured ranking model. +""" +from __future__ import annotations + +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any, Optional, Sequence +import random + +try: + import torch + from torch import nn + import torch.nn.functional as F +except Exception: # pragma: no cover - optional dependency + torch = None + nn = None + F = None + +from .policy_dataset import ( + BASE_FEATURE_DIM, + CANDIDATE_FLAG_DIM, + FEATURE_SCHEMA_VERSION, + PATH_CONTEXT_DIM, + PolicyStepDataset, + PolicyVocabulary, + build_runtime_step_record, + policy_collate_fn, +) + + +CHECKPOINT_VERSION_V2 = "tmcra_tri_maze_policy_v2" + + +def _mask_fill_value(tensor: torch.Tensor) -> float: + if torch is None: + return -1e4 + try: + return float(torch.finfo(tensor.dtype).min) + except Exception: + return -1e4 + + +@dataclass(slots=True) +class PolicyModelConfig: + model_version: str = "v2" + base_feature_dim: int = BASE_FEATURE_DIM + path_context_dim: int = PATH_CONTEXT_DIM + candidate_flag_dim: int = CANDIDATE_FLAG_DIM + history_size: int = 4 + concept_embedding_dim: int = 64 + relation_embedding_dim: int = 16 + domain_embedding_dim: int = 8 + hash_bucket_size: int = 8192 + trunk_dims: tuple[int, ...] = (128, 256, 128) + dropout: float = 0.1 + feature_attention: bool = True + multitask: bool = True + domain_adapt: bool = False + contrastive_dim: int = 128 + path_length_buckets: int = 4 + concept_vocab_size: int = 2 + relation_vocab_size: int = 2 + source_vocab_size: int = 2 + query_type_vocab_size: int = 2 + mode_vocab_size: int = 6 + task_vocab_size: int = 2 + + def to_dict(self) -> dict[str, Any]: + payload = asdict(self) + payload["trunk_dims"] = list(self.trunk_dims) + return payload + + @classmethod + def from_dict(cls, payload: dict[str, Any] | None) -> "PolicyModelConfig": + if not payload: + return cls() + data = dict(payload) + if "trunk_dims" in data: + data["trunk_dims"] = tuple(int(item) for item in data.get("trunk_dims") or ()) + return cls(**data) + + def apply_vocabulary(self, vocabulary: PolicyVocabulary | None) -> "PolicyModelConfig": + if vocabulary is None: + return self + updated = self.to_dict() + updated.update( + { + "hash_bucket_size": int(vocabulary.hash_bucket_size), + "concept_vocab_size": int(vocabulary.concept_vocab_size), + "relation_vocab_size": int(vocabulary.relation_vocab_size), + "source_vocab_size": int(vocabulary.source_vocab_size), + "query_type_vocab_size": int(vocabulary.query_type_vocab_size), + "mode_vocab_size": int(vocabulary.mode_vocab_size), + "task_vocab_size": int(vocabulary.task_vocab_size), + } + ) + return PolicyModelConfig.from_dict(updated) + + +if nn is not None: + class PolicyNet(nn.Module): + def __init__(self, input_dim: int, hidden_dim: int = 32): + super().__init__() + self.net = nn.Sequential( + nn.Linear(input_dim, hidden_dim), + nn.ReLU(), + nn.Linear(hidden_dim, 1), + ) + + def forward(self, x): # x: [N, D] + return self.net(x).squeeze(-1) +else: # pragma: no cover + class PolicyNet: + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use PolicyNet") + + +if nn is not None: + class _GradReverse(torch.autograd.Function): + @staticmethod + def forward(ctx, x, coeff): + ctx.coeff = coeff + return x.view_as(x) + + @staticmethod + def backward(ctx, grad_output): + return grad_output.neg() * ctx.coeff, None + + + def grad_reverse(x: torch.Tensor, coeff: float) -> torch.Tensor: + return _GradReverse.apply(x, coeff) + + + def _masked_mean(values: torch.Tensor, mask: torch.Tensor, dim: int) -> torch.Tensor: + weights = mask.float() + total = (values * weights.unsqueeze(-1)).sum(dim=dim) + denom = weights.sum(dim=dim, keepdim=True).clamp_min(1.0) + return total / denom + + + class PolicyNetV2(nn.Module): + def __init__(self, config: PolicyModelConfig): + super().__init__() + self.config = config + self.concept_embedding = nn.Embedding( + config.concept_vocab_size, + config.concept_embedding_dim, + padding_idx=0, + ) + self.hash_embedding = nn.Embedding( + config.hash_bucket_size + 1, + config.concept_embedding_dim, + padding_idx=0, + ) + self.relation_embedding = nn.Embedding( + config.relation_vocab_size, + config.relation_embedding_dim, + padding_idx=0, + ) + self.source_embedding = nn.Embedding( + config.source_vocab_size, + config.domain_embedding_dim, + padding_idx=0, + ) + self.query_type_embedding = nn.Embedding( + config.query_type_vocab_size, + config.domain_embedding_dim, + padding_idx=0, + ) + self.mode_embedding = nn.Embedding( + config.mode_vocab_size, + config.domain_embedding_dim, + padding_idx=0, + ) + self.task_embedding = nn.Embedding( + config.task_vocab_size, + config.domain_embedding_dim, + padding_idx=0, + ) + + self.sample_context_dim = ( + config.concept_embedding_dim * 2 + + config.path_context_dim + + config.domain_embedding_dim * 4 + ) + self.candidate_input_dim = ( + config.base_feature_dim + + config.path_context_dim + + config.candidate_flag_dim + + config.relation_embedding_dim + + config.concept_embedding_dim * 4 + + config.domain_embedding_dim * 4 + + config.trunk_dims[0] + ) + self.sample_context_proj = nn.Sequential( + nn.Linear(self.sample_context_dim, config.trunk_dims[0]), + nn.LayerNorm(config.trunk_dims[0]), + nn.SiLU(), + ) + if config.feature_attention: + self.feature_gate = nn.Sequential( + nn.Linear(self.candidate_input_dim, self.candidate_input_dim), + nn.LayerNorm(self.candidate_input_dim), + nn.Sigmoid(), + ) + else: + self.feature_gate = None + + layers: list[nn.Module] = [] + prev_dim = self.candidate_input_dim + for hidden_dim in config.trunk_dims: + layers.extend( + [ + nn.Linear(prev_dim, hidden_dim), + nn.LayerNorm(hidden_dim), + nn.SiLU(), + nn.Dropout(config.dropout), + ] + ) + prev_dim = hidden_dim + self.trunk = nn.Sequential(*layers) + self.score_head = nn.Linear(prev_dim, 1) + self.path_length_head = nn.Linear(prev_dim, config.path_length_buckets) + self.tunnel_head = nn.Linear(prev_dim, 1) + self.high_value_head = nn.Linear(prev_dim, 1) + self.context_projection = nn.Linear(prev_dim, config.contrastive_dim) + self.candidate_projection = nn.Linear(prev_dim, config.contrastive_dim) + self.domain_head = nn.Linear(prev_dim, config.source_vocab_size) if config.domain_adapt else None + + def _concept_repr(self, token_ids: torch.Tensor, hash_ids: torch.Tensor) -> torch.Tensor: + return self.concept_embedding(token_ids) + self.hash_embedding(hash_ids) + + def forward(self, batch: PolicyBatch | dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: + if isinstance(batch, dict): + batch = PolicyBatch(**batch) + + current_embed = self._concept_repr(batch.current_concept_ids, batch.current_hash_ids) + history_embed = self._concept_repr(batch.history_concept_ids, batch.history_hash_ids) + history_mask = (batch.history_concept_ids != 0) | (batch.history_hash_ids != 0) + history_summary = _masked_mean(history_embed, history_mask, dim=1) + + candidate_embed = self._concept_repr(batch.candidate_concept_ids, batch.candidate_hash_ids) + relation_embed = self.relation_embedding(batch.relation_ids) + source_embed = self.source_embedding(batch.source_ids) + query_embed = self.query_type_embedding(batch.query_type_ids) + mode_embed = self.mode_embedding(batch.mode_ids) + task_embed = self.task_embedding(batch.task_ids) + + sample_context = torch.cat( + [ + current_embed, + history_summary, + batch.path_context, + source_embed, + query_embed, + mode_embed, + task_embed, + ], + dim=-1, + ) + sample_context = self.sample_context_proj(sample_context) + sample_context_expanded = sample_context.unsqueeze(1).expand(-1, batch.base_features.shape[1], -1) + path_context_expanded = batch.path_context.unsqueeze(1).expand(-1, batch.base_features.shape[1], -1) + domain_context = torch.cat([source_embed, query_embed, mode_embed, task_embed], dim=-1) + domain_context = domain_context.unsqueeze(1).expand(-1, batch.base_features.shape[1], -1) + + candidate_input = torch.cat( + [ + batch.base_features, + path_context_expanded, + batch.candidate_flags, + relation_embed, + sample_context_expanded, + candidate_embed, + current_embed.unsqueeze(1).expand_as(candidate_embed), + candidate_embed - current_embed.unsqueeze(1), + candidate_embed * current_embed.unsqueeze(1), + domain_context, + ], + dim=-1, + ) + if self.feature_gate is not None: + candidate_input = candidate_input * self.feature_gate(candidate_input) + + hidden = self.trunk(candidate_input) + logits = self.score_head(hidden).squeeze(-1) + logits = logits.masked_fill(~batch.candidate_mask, _mask_fill_value(logits)) + pooled = _masked_mean(hidden, batch.candidate_mask, dim=1) + + outputs = { + "logits": logits, + "hidden": hidden, + "pooled": pooled, + "path_length_logits": self.path_length_head(pooled), + "tunnel_logits": self.tunnel_head(pooled).squeeze(-1), + "high_value_logits": self.high_value_head(pooled).squeeze(-1), + "contrastive_context": F.normalize(self.context_projection(pooled), dim=-1), + "contrastive_candidates": F.normalize(self.candidate_projection(hidden), dim=-1), + } + if self.domain_head is not None: + outputs["domain_logits"] = self.domain_head(grad_reverse(pooled, 1.0)) + return outputs + + +def masked_cross_entropy( + logits: torch.Tensor, + target_index: torch.Tensor, + candidate_mask: torch.Tensor, + *, + sample_weights: torch.Tensor | None = None, +) -> torch.Tensor: + if F is None: + raise RuntimeError("torch not available") + masked_logits = logits.masked_fill(~candidate_mask, _mask_fill_value(logits)) + loss = F.cross_entropy(masked_logits, target_index, reduction="none") + if sample_weights is not None: + loss = loss * sample_weights + return loss.mean() + + +def hard_negative_margin_loss( + logits: torch.Tensor, + target_index: torch.Tensor, + candidate_mask: torch.Tensor, + *, + margin: float = 0.2, +) -> torch.Tensor: + if F is None: + raise RuntimeError("torch not available") + batch_index = torch.arange(logits.shape[0], device=logits.device) + positive = logits[batch_index, target_index] + negative_mask = candidate_mask.clone() + negative_mask[batch_index, target_index] = False + hardest_negative = logits.masked_fill(~negative_mask, _mask_fill_value(logits)).max(dim=-1).values + loss = F.relu(margin - (positive - hardest_negative)) + valid = negative_mask.any(dim=-1) + if valid.any(): + return loss[valid].mean() + return loss.new_tensor(0.0) + + +def candidate_contrastive_loss( + context_repr: torch.Tensor, + candidate_repr: torch.Tensor, + target_index: torch.Tensor, + candidate_mask: torch.Tensor, + *, + temperature: float = 0.1, +) -> torch.Tensor: + if F is None: + raise RuntimeError("torch not available") + logits = torch.einsum("bd,bcd->bc", context_repr, candidate_repr) / max(temperature, 1e-4) + logits = logits.masked_fill(~candidate_mask, _mask_fill_value(logits)) + return F.cross_entropy(logits, target_index) + + +def _copy_embedding_rows_by_token( + target_tensor: torch.Tensor, + source_tensor: torch.Tensor | None, + target_mapping: dict[str, int], + source_mapping: dict[str, int], +) -> None: + if source_tensor is None: + return + rows = int(target_tensor.shape[0]) + source_rows = int(source_tensor.shape[0]) + cols = min(int(target_tensor.shape[1]), int(source_tensor.shape[1])) if target_tensor.ndim == 2 and source_tensor.ndim == 2 else 0 + if cols <= 0: + return + with torch.no_grad(): + for token, target_index in target_mapping.items(): + source_index = source_mapping.get(token) + if source_index is None: + continue + if not (0 <= int(target_index) < rows and 0 <= int(source_index) < source_rows): + continue + target_tensor[int(target_index), :cols].copy_(source_tensor[int(source_index), :cols]) + + +def _copy_prefix_tensor(target_tensor: torch.Tensor, source_tensor: torch.Tensor | None) -> None: + if source_tensor is None or target_tensor.ndim != source_tensor.ndim: + return + common_shape = tuple(min(int(a), int(b)) for a, b in zip(target_tensor.shape, source_tensor.shape)) + if not common_shape: + return + target_slices = tuple(slice(0, size) for size in common_shape) + source_slices = tuple(slice(0, size) for size in common_shape) + with torch.no_grad(): + target_tensor[target_slices].copy_(source_tensor[source_slices]) + + +class EdgePolicy: + def __init__( + self, + input_dim: int = 13, + hidden_dim: int = 32, + lr: float = 1e-3, + temperature: float = 1.0, + branch_factor: int = 2, + revisit_probability: float = 0.2, + seed: int = 42, + *, + model_version: str = "v2", + model_config: PolicyModelConfig | None = None, + vocabulary: PolicyVocabulary | None = None, + weight_decay: float = 1e-4, + ): + self.enabled = torch is not None + self.input_dim = int(input_dim) + self.hidden_dim = int(hidden_dim) + self.lr = float(lr) + self.weight_decay = float(weight_decay) + self.temperature = max(0.1, float(temperature)) + self.branch_factor = max(1, int(branch_factor)) + self.revisit_probability = max(0.0, min(1.0, float(revisit_probability))) + self.max_degree = 1 + self.seed = int(seed) + self.rng = random.Random(seed) + self.model_version = str(model_version or "v2").lower() + self.feature_schema = {"version": FEATURE_SCHEMA_VERSION} + self.vocabulary = vocabulary or PolicyVocabulary.empty() + self.model_config = (model_config or PolicyModelConfig()).apply_vocabulary(self.vocabulary) + + if not self.enabled: + self.model = None + self.optimizer = None + return + + torch.manual_seed(seed) + self.model = None + self.optimizer = None + self._build_model() + + def _build_model(self) -> None: + if not self.enabled: + return + if self.model_version == "v1": + self.model = PolicyNet(input_dim=self.input_dim, hidden_dim=self.hidden_dim) + self.optimizer = torch.optim.Adam(self.model.parameters(), lr=self.lr) + else: + self.model_version = "v2" + self.model_config = self.model_config.apply_vocabulary(self.vocabulary) + self.model = PolicyNetV2(self.model_config) + self.optimizer = torch.optim.AdamW( + self.model.parameters(), + lr=self.lr, + weight_decay=self.weight_decay, + ) + + def _model_device(self) -> torch.device: + if self.model is None: + return torch.device("cpu") + try: + return next(self.model.parameters()).device + except StopIteration: + return torch.device("cpu") + + def set_max_degree(self, max_degree: int) -> None: + self.max_degree = max(1, int(max_degree)) + + def allow_revisit(self) -> bool: + return self.rng.random() < self.revisit_probability + + def config_dict(self) -> dict[str, Any]: + base = { + "input_dim": self.input_dim, + "hidden_dim": self.hidden_dim, + "lr": self.lr, + "weight_decay": self.weight_decay, + "temperature": self.temperature, + "branch_factor": self.branch_factor, + "revisit_probability": self.revisit_probability, + "seed": self.seed, + "max_degree": self.max_degree, + "model_version": self.model_version, + } + if self.model_version == "v2": + base["model_config"] = self.model_config.to_dict() + return base + + def set_vocabulary(self, vocabulary: PolicyVocabulary | None) -> None: + if vocabulary is None: + return + self.vocabulary = vocabulary + if self.model_version == "v2": + self.model_config = self.model_config.apply_vocabulary(vocabulary) + self._build_model() + + def save_checkpoint( + self, + path: str | Path, + *, + metadata: dict[str, Any] | None = None, + scheduler_state: dict[str, Any] | None = None, + extra_state: dict[str, Any] | None = None, + ) -> None: + if not self.enabled: + raise RuntimeError("torch not available; cannot save EdgePolicy checkpoint") + payload = { + "format_version": CHECKPOINT_VERSION_V2 if self.model_version == "v2" else "tmcra_tri_maze_policy_v1", + "config": self.config_dict(), + "model_state": self.model.state_dict(), + "optimizer_state": self.optimizer.state_dict() if self.optimizer is not None else None, + "metadata": metadata or {}, + "scheduler_state": scheduler_state, + "extra_state": extra_state or {}, + } + if self.model_version == "v2": + payload["vocabulary"] = self.vocabulary.to_metadata() + payload["feature_schema"] = self.feature_schema + target = Path(path) + target.parent.mkdir(parents=True, exist_ok=True) + torch.save(payload, target) + + def _load_v1_checkpoint( + self, + payload: dict[str, Any], + *, + load_optimizer: bool, + strict: bool, + ) -> dict[str, Any]: + config = payload.get("config") or {} + required = {"input_dim", "hidden_dim", "lr", "temperature", "branch_factor", "revisit_probability", "seed"} + if not required.issubset(config): + raise ValueError("invalid EdgePolicy checkpoint: missing config keys") + self.model_version = "v1" + self.input_dim = int(config["input_dim"]) + self.hidden_dim = int(config["hidden_dim"]) + self.lr = float(config["lr"]) + self.temperature = float(config["temperature"]) + self.branch_factor = int(config["branch_factor"]) + self.revisit_probability = float(config["revisit_probability"]) + self.seed = int(config["seed"]) + self.max_degree = int(config.get("max_degree", self.max_degree)) + self.rng = random.Random(self.seed) + self._build_model() + self.model.load_state_dict(payload["model_state"], strict=strict) + if load_optimizer and payload.get("optimizer_state") is not None and self.optimizer is not None: + self.optimizer.load_state_dict(payload["optimizer_state"]) + return payload.get("metadata") or {} + + def load_checkpoint( + self, + path: str | Path, + *, + load_optimizer: bool = False, + strict: bool = True, + preserve_vocabulary: bool = False, + ) -> dict[str, Any]: + if not self.enabled: + raise RuntimeError("torch not available; cannot load EdgePolicy checkpoint") + payload = torch.load(path, map_location="cpu", weights_only=False) + config = payload.get("config") or {} + if payload.get("format_version") == CHECKPOINT_VERSION_V2 or config.get("model_version") == "v2": + self.model_version = "v2" + if not preserve_vocabulary: + self.lr = float(config.get("lr", self.lr)) + self.weight_decay = float(config.get("weight_decay", self.weight_decay)) + self.temperature = float(config.get("temperature", self.temperature)) + self.branch_factor = int(config.get("branch_factor", self.branch_factor)) + self.revisit_probability = float(config.get("revisit_probability", self.revisit_probability)) + self.seed = int(config.get("seed", self.seed)) + self.max_degree = int(config.get("max_degree", self.max_degree)) + self.rng = random.Random(self.seed) + checkpoint_vocabulary = PolicyVocabulary.from_metadata(payload.get("vocabulary")) + if preserve_vocabulary: + current_vocabulary = self.vocabulary or PolicyVocabulary.empty() + self.vocabulary = current_vocabulary + else: + self.vocabulary = checkpoint_vocabulary + self.feature_schema = dict(payload.get("feature_schema") or {"version": FEATURE_SCHEMA_VERSION}) + self.model_config = PolicyModelConfig.from_dict(config.get("model_config")).apply_vocabulary(self.vocabulary) + self._build_model() + if preserve_vocabulary: + target_state = self.model.state_dict() + source_state = payload["model_state"] + for name, source_tensor in source_state.items(): + target_tensor = target_state.get(name) + if target_tensor is None: + continue + if target_tensor.shape == source_tensor.shape: + target_state[name] = source_tensor + _copy_embedding_rows_by_token( + target_state["concept_embedding.weight"], + source_state.get("concept_embedding.weight"), + self.vocabulary.concept_to_id, + checkpoint_vocabulary.concept_to_id, + ) + _copy_embedding_rows_by_token( + target_state["relation_embedding.weight"], + source_state.get("relation_embedding.weight"), + self.vocabulary.relation_to_id, + checkpoint_vocabulary.relation_to_id, + ) + _copy_embedding_rows_by_token( + target_state["source_embedding.weight"], + source_state.get("source_embedding.weight"), + self.vocabulary.source_to_id, + checkpoint_vocabulary.source_to_id, + ) + _copy_embedding_rows_by_token( + target_state["query_type_embedding.weight"], + source_state.get("query_type_embedding.weight"), + self.vocabulary.query_type_to_id, + checkpoint_vocabulary.query_type_to_id, + ) + _copy_embedding_rows_by_token( + target_state["mode_embedding.weight"], + source_state.get("mode_embedding.weight"), + self.vocabulary.mode_to_id, + checkpoint_vocabulary.mode_to_id, + ) + _copy_embedding_rows_by_token( + target_state["task_embedding.weight"], + source_state.get("task_embedding.weight"), + self.vocabulary.task_to_id, + checkpoint_vocabulary.task_to_id, + ) + _copy_prefix_tensor( + target_state["hash_embedding.weight"], + source_state.get("hash_embedding.weight"), + ) + self.model.load_state_dict(target_state, strict=False) + else: + self.model.load_state_dict(payload["model_state"], strict=strict) + if load_optimizer and not preserve_vocabulary and payload.get("optimizer_state") is not None and self.optimizer is not None: + self.optimizer.load_state_dict(payload["optimizer_state"]) + return payload.get("metadata") or {} + return self._load_v1_checkpoint(payload, load_optimizer=load_optimizer, strict=strict) + + def _encode_runtime_batch( + self, + engine, + current_node, + candidate_edges, + path, + visited: set[str], + mode: str, + *, + target_index: int = -1, + sample_id: str | None = None, + weight: float = 1.0, + ) -> PolicyBatch: + record = build_runtime_step_record( + engine=engine, + current_node=current_node, + candidate_edges=candidate_edges, + path=path, + visited=visited, + mode=mode, + target_index=target_index, + sample_id=sample_id, + weight=weight, + source_kind="runtime_update" if target_index >= 0 else "runtime", + source_dataset="runtime", + query_type="runtime", + task_key=f"runtime|runtime|{mode}", + ) + dataset = PolicyStepDataset( + [record], + vocabulary=self.vocabulary, + history_size=self.model_config.history_size, + ) + batch = policy_collate_fn([dataset[0]]) + return batch.to(self._model_device()) + + def evaluate_candidates(self, engine, current_node, candidate_edges, path, visited: set, mode: str = "forward"): + if not self.enabled or not candidate_edges: + return None + self.model.eval() + with torch.no_grad(): + if self.model_version == "v1": + features = torch.tensor( + [ + row + for row in [ + build_runtime_step_record( + engine, + current_node, + [edge], + path=path, + visited=visited, + mode=mode, + sample_id=f"single::{index}", + ).candidate_base_features[0] + for index, edge in enumerate(candidate_edges) + ] + ], + dtype=torch.float32, + device=self._model_device(), + ) + logits = self.model(features) + probs = torch.softmax(logits / self.temperature, dim=0) + return {"features": features, "logits": logits, "probs": probs} + + batch = self._encode_runtime_batch( + engine=engine, + current_node=current_node, + candidate_edges=candidate_edges, + path=path, + visited=visited, + mode=mode, + ) + outputs = self.model(batch) + logits = outputs["logits"][0, : len(candidate_edges)] + probs = torch.softmax(logits / self.temperature, dim=0) + return {"batch": batch, "outputs": outputs, "logits": logits, "probs": probs} + + def score_edges(self, engine, current_node, edges, path, visited: set, mode: str): + if not self.enabled or not edges: + return None + evaluated = self.evaluate_candidates(engine, current_node, edges, path, visited, mode) + if evaluated is None: + return None + return evaluated["logits"] + + def select_edges( + self, + engine, + current_node, + candidate_edges, + path, + visited: set, + mode: str = "forward", + k: Optional[int] = None, + deterministic: bool = False, + ): + if not self.enabled or not candidate_edges: + return [] + + evaluated = self.evaluate_candidates(engine, current_node, candidate_edges, path, visited, mode) + if evaluated is None: + return [] + probs = evaluated["probs"] + + k = k or self.branch_factor + k = max(1, min(int(k), len(candidate_edges))) + + if deterministic: + top_idx = torch.topk(probs, k=k).indices.tolist() + return [candidate_edges[i] for i in top_idx] + + if k == 1: + idx = torch.multinomial(probs, num_samples=1).item() + return [candidate_edges[idx]] + + idxs = torch.multinomial(probs, num_samples=k, replacement=False).tolist() + return [candidate_edges[i] for i in idxs] + + def _online_supervised_step(self, batch: PolicyBatch) -> float: + if self.optimizer is None: + return 0.0 + self.model.train() + outputs = self.model(batch) + loss = masked_cross_entropy( + outputs["logits"], + batch.target_index, + batch.candidate_mask, + sample_weights=batch.weights, + ) + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + return float(loss.item()) + + def warm_start_from_memory( + self, + engine, + max_paths: int = 200, + max_steps: int = 800, + ) -> int: + if not self.enabled: + return 0 + memory = getattr(engine, "memory", None) + if not memory: + return 0 + paths = memory.get_all_paths() + if not paths: + return 0 + + steps = 0 + self.rng.shuffle(paths) + for path_item in paths[:max_paths]: + concept_list = [str(item).strip() for item in (path_item.get("path") or []) if str(item).strip()] + if len(concept_list) < 2: + continue + weight = max(0.1, min(1.0, float(path_item.get("score", 0.5) or 0.5))) + visited: set[str] = set() + for index in range(len(concept_list) - 1): + if steps >= max_steps: + return steps + current = concept_list[index] + target = concept_list[index + 1] + current_node = engine.nodes.get(current) + if not current_node: + continue + edges = list(current_node.connections) + target_idx = next((item for item, edge in enumerate(edges) if edge.to_node.concept == target), None) + if target_idx is None: + continue + visited.add(current) + path_stub = type("PathStub", (), {"length": index, "nodes": [engine.nodes[c] for c in concept_list[: index + 1] if c in engine.nodes], "edges": []})() + if self.model_version == "v1": + features = torch.tensor( + [build_runtime_step_record(engine, current_node, [edge], path=path_stub, visited=visited, mode="forward").candidate_base_features[0] for edge in edges], + dtype=torch.float32, + device=self._model_device(), + ) + logits = self.model(features).unsqueeze(0) + target_tensor = torch.tensor([target_idx], dtype=torch.long, device=self._model_device()) + loss = F.cross_entropy(logits, target_tensor) * weight + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + else: + batch = self._encode_runtime_batch( + engine=engine, + current_node=current_node, + candidate_edges=edges, + path=path_stub, + visited=visited, + mode="forward", + target_index=target_idx, + sample_id=f"warm::{current}::{target}::{index}", + weight=weight, + ) + self._online_supervised_step(batch) + steps += 1 + return steps + + def update_from_path(self, engine, path, mode: str = "forward") -> int: + if not self.enabled or not path or not getattr(path, "edges", None): + return 0 + + reward = 1.0 + if hasattr(path, "score") and hasattr(engine, "length_penalty"): + reward = max(0.05, 1.0 - float(path.score(engine.length_penalty))) + + visited: set[str] = set() + steps = 0 + for index, edge in enumerate(path.edges): + current_node = path.nodes[index] + visited.add(current_node.concept) + candidate_edges = list(current_node.connections) + if not candidate_edges: + continue + try: + target_idx = candidate_edges.index(edge) + except ValueError: + continue + if self.model_version == "v1": + features = torch.tensor( + [build_runtime_step_record(engine, current_node, [candidate], path=path, visited=visited, mode=mode).candidate_base_features[0] for candidate in candidate_edges], + dtype=torch.float32, + device=self._model_device(), + ) + logits = self.model(features).unsqueeze(0) + target_tensor = torch.tensor([target_idx], dtype=torch.long, device=self._model_device()) + loss = F.cross_entropy(logits, target_tensor) * reward + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + else: + batch = self._encode_runtime_batch( + engine=engine, + current_node=current_node, + candidate_edges=candidate_edges, + path=path, + visited=visited, + mode=mode, + target_index=target_idx, + sample_id=f"update::{current_node.concept}::{index}", + weight=reward, + ) + self._online_supervised_step(batch) + steps += 1 + return steps diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/query_understanding.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/query_understanding.py new file mode 100644 index 0000000..6b87604 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/query_understanding.py @@ -0,0 +1,197 @@ +""" +LLM front-layer query understanding. +Normalizes user queries into structured seeds before graph extraction/search. +""" +from __future__ import annotations + +import json +import os +from typing import Dict, List + +from loguru import logger +from openai import OpenAI + + +class QueryUnderstandingLayer: + """LLM-based front-layer understanding for TMCRA.""" + + def __init__(self, api_key: str | None = None, base_url: str | None = None, model: str | None = None): + self.api_key = (api_key if api_key is not None else os.getenv("API_KEY", "")).strip() + self.base_url = (base_url if base_url is not None else os.getenv("API_BASE_URL", "https://api.deepseek.com/v1")).strip() + self.model = (model if model is not None else os.getenv("TMCRA_QUERY_MODEL", os.getenv("TMCRA_LLM_MODEL", "deepseek-chat"))).strip() or "deepseek-chat" + self.max_concepts = None + self.max_relations = 18 + self.client = self._build_client() + self.system_prompt = """ +你是 TMCRA 的前置理解层。你的任务不是直接回答问题,而是把用户自然语言整理成适合后续图推理系统处理的结构化输入。 + +目标: +1. 判断问题意图(general / explanation / necessity / how_to / design / code) +2. 把原问题改写成更适合机制推理的规范化问题 +3. 提取核心概念、候选关系、关注焦点 +4. 尽量避免抽象空泛概念,优先保留可进入知识图谱的实体、结构、过程、属性、材料、能量 +5. 输出严格 JSON,不要额外解释 + +输出格式: +{ + "intent": "explanation", + "normalized_query": "解释 LED 串联电阻限制电流的机制", + "focus_concept": "LED", + "concepts": [ + {"concept": "LED", "type": "entity"}, + {"concept": "电阻", "type": "component"} + ], + "relations": [ + {"from": "电阻", "to": "电流", "relation": "限制", "weight": 0.78} + ], + "constraints": ["优先机制链", "避免抽象概念"], + "confidence": 0.86 +} + +要求: +- concepts 不设固定上限,尽量完整保留关键概念 +- relations 最多 18 个 +- weight 在 0 到 1 之间 +- normalized_query 必须保留用户原始意图,但改写得更适合图推理 +- 如果用户问题本身很清楚,也可以基本保持原句 +- 如果无法判断,就保守输出,confidence 降低 +""" + + def _build_client(self): + if not self.api_key: + return None + return OpenAI(api_key=self.api_key, base_url=self.base_url) + + @property + def available(self) -> bool: + return self.client is not None and bool(self.api_key) + + def set_api_config(self, api_key: str, base_url: str | None = None, model: str | None = None) -> None: + self.api_key = (api_key or "").strip() + if base_url is not None and base_url.strip(): + self.base_url = base_url.strip() + if model is not None and model.strip(): + self.model = model.strip() + self.client = self._build_client() + if self.client: + logger.info("✅ 前置理解层 API 配置已更新") + else: + logger.info("ℹ️ 前置理解层 API 配置已清空") + + def _clamp_weight(self, value) -> float: + try: + return max(0.0, min(1.0, float(value))) + except Exception: + return 0.5 + + def _normalize_concepts(self, concepts: List[Dict]) -> List[Dict]: + seen = set() + normalized: List[Dict] = [] + for item in concepts or []: + if not isinstance(item, dict): + continue + concept = str(item.get("concept", "")).strip() + if not concept or concept in seen: + continue + seen.add(concept) + normalized.append({ + "concept": concept, + "type": str(item.get("type", "general") or "general").strip() or "general", + }) + if self.max_concepts and self.max_concepts > 0 and len(normalized) >= self.max_concepts: + break + return normalized + + def _normalize_relations(self, relations: List[Dict], concept_names: set[str]) -> List[Dict]: + seen = set() + normalized: List[Dict] = [] + for item in relations or []: + if not isinstance(item, dict): + continue + src = str(item.get("from", "")).strip() + dst = str(item.get("to", "")).strip() + relation = str(item.get("relation", "")).strip() + if not src or not dst or not relation or src == dst: + continue + key = (src, dst, relation) + if key in seen: + continue + seen.add(key) + if concept_names and (src not in concept_names or dst not in concept_names): + continue + normalized.append({ + "from": src, + "to": dst, + "relation": relation, + "weight": self._clamp_weight(item.get("weight", 0.6)), + }) + if len(normalized) >= self.max_relations: + break + return normalized + + def _normalize_result(self, result: Dict, query: str) -> Dict: + concepts = self._normalize_concepts(result.get("concepts", [])) + concept_names = {item["concept"] for item in concepts} + relations = self._normalize_relations(result.get("relations", []), concept_names) + focus = str(result.get("focus_concept", "")).strip() + if focus and focus not in concept_names: + focus = "" + if not focus and concepts: + focus = concepts[0]["concept"] + + intent = str(result.get("intent", "general") or "general").strip().lower() + if intent not in {"general", "explanation", "necessity", "how_to", "design", "code"}: + intent = "general" + + constraints = [] + for item in result.get("constraints", []): + text = str(item).strip() + if text: + constraints.append(text) + constraints = constraints[:6] + + normalized_query = str(result.get("normalized_query", "")).strip() or query.strip() + confidence = self._clamp_weight(result.get("confidence", 0.5)) + + return { + "intent": intent, + "normalized_query": normalized_query, + "focus_concept": focus, + "concepts": concepts, + "relations": relations, + "constraints": constraints, + "confidence": confidence, + } + + def preprocess(self, query: str) -> Dict | None: + text = query.strip() + if not text: + return None + if not self.available: + return None + + try: + response = self.client.chat.completions.create( + model=self.model, + messages=[ + {"role": "system", "content": self.system_prompt}, + {"role": "user", "content": text}, + ], + temperature=0.1, + max_tokens=1200, + response_format={"type": "json_object"}, + ) + raw = response.choices[0].message.content + result = json.loads(raw) + normalized = self._normalize_result(result, text) + logger.info( + "✅ 前置理解完成:intent={} concepts={} relations={} confidence={}", + normalized["intent"], + len(normalized["concepts"]), + len(normalized["relations"]), + normalized["confidence"], + ) + return normalized + except Exception as exc: + logger.warning("前置理解层调用失败: {}", exc) + return None diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_harmonizer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_harmonizer.py new file mode 100644 index 0000000..3d99251 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_harmonizer.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +import os +from dataclasses import dataclass +from typing import Any, Dict + +import numpy as np +from PIL import Image, ImageFilter + +from .scene_line_generator import SceneLineGeneratorRuntime + + +@dataclass +class SceneSketchHarmonizerRuntime: + checkpoint_path: str | None = None + + def __post_init__(self) -> None: + harmonizer_path = self.checkpoint_path or os.getenv("TMCRA_SCENE_HARMONIZER_PATH", "").strip() or None + self._runtime = SceneLineGeneratorRuntime(checkpoint_path=harmonizer_path) if harmonizer_path else SceneLineGeneratorRuntime() + self._state: Dict[str, Any] = { + "enabled": bool(self._runtime.status().get("enabled")), + "model_id": "scene_sketch_harmonizer_v1", + "checkpoint_path": harmonizer_path or self._runtime.status().get("checkpoint_path", ""), + "fallback_model_id": self._runtime.status().get("model_id", "scene_line_generator_v1"), + "loaded": bool(self._runtime.status().get("loaded")), + } + if self._runtime.status().get("error"): + self._state["error"] = self._runtime.status()["error"] + + def status(self) -> Dict[str, Any]: + payload = dict(self._state) + payload["fallback_status"] = self._runtime.status() + return payload + + def harmonize(self, *, base_image: Image.Image, condition_maps: np.ndarray) -> Image.Image | None: + refined = self._runtime.refine(base_image=base_image, condition_maps=condition_maps) + if refined is None: + return None + softened = refined.filter(ImageFilter.GaussianBlur(radius=0.35)) + lines = refined.convert("L").point(lambda value: 255 - value) + lines = lines.filter(ImageFilter.GaussianBlur(radius=0.6)) + overlay = Image.merge("RGB", (lines, lines, lines)) + blended = Image.blend(softened.convert("RGB"), overlay, alpha=0.08) + return blended diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_line_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_line_generator.py new file mode 100644 index 0000000..ae58931 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_line_generator.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +import os +from dataclasses import dataclass +from typing import Any, Dict + +import numpy as np +from PIL import Image + +try: + import torch + from torch import nn +except Exception: # pragma: no cover - optional dependency path + torch = None + nn = None + + +if nn is not None: + class _ConvBlock(nn.Module): + def __init__(self, in_channels: int, out_channels: int): + super().__init__() + self.net = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), + nn.BatchNorm2d(out_channels), + nn.SiLU(), + nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), + nn.BatchNorm2d(out_channels), + nn.SiLU(), + ) + + def forward(self, x): # type: ignore[override] + return self.net(x) + + + class SceneLineGenerator(nn.Module): + """Trainable second-stage whole-scene line sketch refiner.""" + + def __init__(self, in_channels: int = 6, base_channels: int = 32): + super().__init__() + self.enc1 = _ConvBlock(in_channels, base_channels) + self.pool1 = nn.MaxPool2d(2) + self.enc2 = _ConvBlock(base_channels, base_channels * 2) + self.pool2 = nn.MaxPool2d(2) + self.enc3 = _ConvBlock(base_channels * 2, base_channels * 4) + self.up2 = nn.ConvTranspose2d(base_channels * 4, base_channels * 2, kernel_size=2, stride=2) + self.dec2 = _ConvBlock(base_channels * 4, base_channels * 2) + self.up1 = nn.ConvTranspose2d(base_channels * 2, base_channels, kernel_size=2, stride=2) + self.dec1 = _ConvBlock(base_channels * 2, base_channels) + self.head = nn.Conv2d(base_channels, 1, kernel_size=1) + + def forward(self, x): # type: ignore[override] + e1 = self.enc1(x) + e2 = self.enc2(self.pool1(e1)) + e3 = self.enc3(self.pool2(e2)) + d2 = self.up2(e3) + d2 = self.dec2(torch.cat([d2, e2], dim=1)) + d1 = self.up1(d2) + d1 = self.dec1(torch.cat([d1, e1], dim=1)) + return torch.sigmoid(self.head(d1)) + + +@dataclass +class SceneLineGeneratorRuntime: + checkpoint_path: str | None = None + + def __post_init__(self) -> None: + self.checkpoint_path = self.checkpoint_path or os.getenv("TMCRA_SCENE_LINE_GENERATOR_PATH", "").strip() or None + self._model = None + self._state: Dict[str, Any] = { + "enabled": False, + "model_id": "scene_line_generator_v1", + "checkpoint_path": self.checkpoint_path or "", + "loaded": False, + } + if torch is None or nn is None or not self.checkpoint_path or not os.path.exists(self.checkpoint_path): + return + try: + model = SceneLineGenerator() + payload = torch.load(self.checkpoint_path, map_location="cpu") + state_dict = payload.get("state_dict") if isinstance(payload, dict) and "state_dict" in payload else payload + model.load_state_dict(state_dict, strict=False) + model.eval() + self._model = model + self._state.update({"enabled": True, "loaded": True}) + except Exception as exc: # pragma: no cover - runtime guard + self._state["error"] = str(exc) + + def status(self) -> Dict[str, Any]: + return dict(self._state) + + def refine(self, *, base_image: Image.Image, condition_maps: np.ndarray) -> Image.Image | None: + if self._model is None or torch is None: + return None + height, width = condition_maps.shape[:2] + tensor = torch.from_numpy(condition_maps.transpose(2, 0, 1)).unsqueeze(0).float() + with torch.no_grad(): + prediction = self._model(tensor)[0, 0].cpu().numpy() + prediction = np.clip(prediction, 0.0, 1.0) + refined = base_image.convert("RGB").resize((width, height)) + arr = np.asarray(refined, dtype=np.uint8).copy() + line_mask = prediction > 0.42 + arr[line_mask] = np.minimum(arr[line_mask], np.array([44, 52, 64], dtype=np.uint8)) + return Image.fromarray(arr, mode="RGB") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_dataset.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_dataset.py new file mode 100644 index 0000000..8c6000e --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_dataset.py @@ -0,0 +1,299 @@ +from __future__ import annotations + +import json +import math +import random +from collections import Counter +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any, Dict, Iterable, List, Sequence + +import numpy as np +import torch +from PIL import Image +from torch.utils.data import Dataset + + +DEFAULT_IMAGE_SIZE = 256 + + +@dataclass(slots=True) +class SceneTrainingRecord: + dataset_id: str + scene_type: str + style_id: str + source_family: str + recommended_use: str + split: str + image_path: str + component_count: int + mapped_component_count: int + mapped_internal_classes: List[str] + metadata: Dict[str, Any] + + +def read_json(path: Path) -> Dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def write_json(path: Path, payload: Dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") + + +def read_jsonl(path: Path) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + if not path.exists(): + return rows + with path.open("r", encoding="utf-8") as handle: + for raw in handle: + line = raw.strip() + if not line: + continue + try: + item = json.loads(line) + except Exception: + continue + if isinstance(item, dict): + rows.append(item) + return rows + + +def write_jsonl(path: Path, rows: Sequence[Dict[str, Any]]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as handle: + for row in rows: + handle.write(json.dumps(row, ensure_ascii=False) + "\n") + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _split_from_bucket(bucket: str, fallback: str = "train") -> str: + text = str(bucket or "").strip().lower() + if text in {"primary_val", "style_val"}: + return "val" + if text in {"primary_test", "style_test", "holdout_eval"}: + return "test" + if text: + return "train" + return fallback + + +def _infer_image_path(row: Dict[str, Any]) -> str: + drawing_png = str(row.get("drawing_png") or "").strip() + if drawing_png: + return drawing_png + drawing_svg = str(row.get("drawing_svg") or "").strip() + return drawing_svg + + +def registry_rows_to_scene_records( + rows: Sequence[Dict[str, Any]], + *, + min_mapped_components: int = 1, +) -> List[Dict[str, Any]]: + records: List[Dict[str, Any]] = [] + for row in rows: + if str(row.get("record_type") or "") != "scene_sample": + continue + if str(row.get("readiness") or "") != "ready": + continue + image_path = _infer_image_path(row) + if not image_path or not Path(image_path).exists(): + continue + mapped_component_count = int(row.get("mapped_component_count", 0) or 0) + allow_unmapped_training = bool(row.get("allow_unmapped_training")) + if mapped_component_count < min_mapped_components and not allow_unmapped_training: + continue + recommended_bucket = str(row.get("recommended_bucket") or "") + records.append( + asdict( + SceneTrainingRecord( + dataset_id=str(row.get("dataset_id") or "unknown"), + scene_type=str(row.get("scene_type") or "scene"), + style_id=str(row.get("style_variant") or "unknown"), + source_family=str(row.get("source_family") or "unknown"), + recommended_use=str(row.get("recommended_use") or "scene_sketch_pretrain"), + split=_split_from_bucket(recommended_bucket), + image_path=image_path, + component_count=int(row.get("component_count", 0) or 0), + mapped_component_count=mapped_component_count, + mapped_internal_classes=[ + str(item) + for item in (row.get("mapped_internal_classes") or []) + if str(item).strip() + ], + metadata={ + "dataset_id": row.get("dataset_id"), + "archive_name": row.get("archive_name"), + "scene_id": row.get("scene_id"), + "recommended_bucket": recommended_bucket, + "recommended_extract_dir": row.get("recommended_extract_dir"), + "component_labels": _copy(row.get("component_labels") or []), + "allow_unmapped_training": allow_unmapped_training, + }, + ) + ) + ) + return records + + +def build_scene_index_maps(rows: Sequence[Dict[str, Any]]) -> Dict[str, Dict[str, int]]: + scene_types = sorted({str(row.get("scene_type") or "scene") for row in rows}) + style_ids = sorted({str(row.get("style_id") or "unknown") for row in rows}) + source_families = sorted({str(row.get("source_family") or "unknown") for row in rows}) + recommended_uses = sorted({str(row.get("recommended_use") or "scene_sketch_pretrain") for row in rows}) + internal_classes = sorted( + { + str(class_id) + for row in rows + for class_id in (row.get("mapped_internal_classes") or []) + if str(class_id).strip() + } + ) + return { + "scene_to_idx": {value: idx for idx, value in enumerate(scene_types)}, + "style_to_idx": {value: idx for idx, value in enumerate(style_ids)}, + "source_family_to_idx": {value: idx for idx, value in enumerate(source_families)}, + "use_to_idx": {value: idx for idx, value in enumerate(recommended_uses)}, + "class_to_idx": {value: idx for idx, value in enumerate(internal_classes)}, + } + + +def split_scene_rows(rows: Sequence[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]: + payload = {"train": [], "val": [], "test": []} + for row in rows: + split = str(row.get("split") or "train") + payload.setdefault(split, []).append(_copy(row)) + return payload + + +def build_scene_manifest(split_rows_payload: Dict[str, List[Dict[str, Any]]]) -> Dict[str, Any]: + all_rows = [row for rows in split_rows_payload.values() for row in rows] + by_dataset = Counter(str(row.get("dataset_id") or "") for row in all_rows) + by_scene = Counter(str(row.get("scene_type") or "scene") for row in all_rows) + by_style = Counter(str(row.get("style_id") or "unknown") for row in all_rows) + return { + "row_count": len(all_rows), + "dataset_count": len(by_dataset), + "scene_type_count": len(by_scene), + "style_count": len(by_style), + "splits": { + split_name: {"row_count": len(rows)} + for split_name, rows in split_rows_payload.items() + }, + "by_dataset": dict(sorted(by_dataset.items())), + "by_scene_type": dict(sorted(by_scene.items())), + "by_style": dict(sorted(by_style.items())), + } + + +def prepare_scene_dataset_from_registry( + *, + registry_path: Path, + output_dir: Path, + min_mapped_components: int = 1, +) -> Dict[str, Any]: + registry_rows = read_jsonl(registry_path) + scene_rows = registry_rows_to_scene_records( + registry_rows, + min_mapped_components=min_mapped_components, + ) + split_map = split_scene_rows(scene_rows) + mappings = build_scene_index_maps(scene_rows) + manifest = build_scene_manifest(split_map) + output_dir.mkdir(parents=True, exist_ok=True) + for split_name, rows in split_map.items(): + write_jsonl(output_dir / f"{split_name}.jsonl", rows) + write_json(output_dir / "manifest.json", manifest) + write_json(output_dir / "mappings.json", mappings) + return { + "output_dir": str(output_dir), + "row_count": len(scene_rows), + "manifest": manifest, + } + + +def _load_image_grayscale(path: Path, image_size: int) -> torch.Tensor: + with Image.open(path) as image: + image = image.convert("L") + image = image.resize((image_size, image_size), Image.BILINEAR) + array = np.asarray(image, dtype=np.float32) / 255.0 + tensor = torch.from_numpy(array).unsqueeze(0) + return tensor + + +def _augment_image(image: torch.Tensor, rng: random.Random) -> torch.Tensor: + output = image.clone() + if rng.random() < 0.5: + output = torch.flip(output, dims=[2]) + if rng.random() < 0.25: + output = torch.flip(output, dims=[1]) + if rng.random() < 0.3: + output = torch.clamp(output + rng.uniform(-0.08, 0.08), 0.0, 1.0) + if rng.random() < 0.25: + noise = torch.randn_like(output) * rng.uniform(0.01, 0.04) + output = torch.clamp(output + noise, 0.0, 1.0) + return output + + +class PreparedSceneTrainingDataset(Dataset): + def __init__( + self, + rows: Sequence[Dict[str, Any]], + mappings: Dict[str, Dict[str, int]], + *, + image_size: int = DEFAULT_IMAGE_SIZE, + augment: bool = False, + seed: int = 42, + ): + self.rows = list(rows) + self.mappings = mappings + self.image_size = int(image_size) + self.augment = bool(augment) + self.seed = int(seed) + self.class_count = len(mappings.get("class_to_idx") or {}) + + def __len__(self) -> int: + return len(self.rows) + + def __getitem__(self, index: int) -> Dict[str, Any]: + row = self.rows[index] + path = Path(str(row.get("image_path") or "")) + image = _load_image_grayscale(path, self.image_size) + if self.augment: + image = _augment_image(image, random.Random(self.seed + index)) + class_target = torch.zeros(self.class_count, dtype=torch.float32) + for class_id in row.get("mapped_internal_classes") or []: + class_index = self.mappings["class_to_idx"].get(str(class_id)) + if class_index is not None: + class_target[class_index] = 1.0 + return { + "image": image, + "scene_id": torch.tensor(self.mappings["scene_to_idx"][str(row.get("scene_type") or "scene")], dtype=torch.long), + "style_id": torch.tensor(self.mappings["style_to_idx"][str(row.get("style_id") or "unknown")], dtype=torch.long), + "source_family_id": torch.tensor(self.mappings["source_family_to_idx"][str(row.get("source_family") or "unknown")], dtype=torch.long), + "use_id": torch.tensor(self.mappings["use_to_idx"][str(row.get("recommended_use") or "scene_sketch_pretrain")], dtype=torch.long), + "component_count": torch.tensor(math.log1p(float(row.get("component_count", 0) or 0)), dtype=torch.float32), + "mapped_component_count": torch.tensor(math.log1p(float(row.get("mapped_component_count", 0) or 0)), dtype=torch.float32), + "class_target": class_target, + "image_path": str(path), + "raw_row": row, + } + + +def collate_scene_training_batch(batch: Sequence[Dict[str, Any]]) -> Dict[str, Any]: + return { + "image": torch.stack([item["image"] for item in batch], dim=0), + "scene_id": torch.stack([item["scene_id"] for item in batch], dim=0), + "style_id": torch.stack([item["style_id"] for item in batch], dim=0), + "source_family_id": torch.stack([item["source_family_id"] for item in batch], dim=0), + "use_id": torch.stack([item["use_id"] for item in batch], dim=0), + "component_count": torch.stack([item["component_count"] for item in batch], dim=0), + "mapped_component_count": torch.stack([item["mapped_component_count"] for item in batch], dim=0), + "class_target": torch.stack([item["class_target"] for item in batch], dim=0), + "image_path": [item["image_path"] for item in batch], + "raw_row": [item["raw_row"] for item in batch], + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_model.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_model.py new file mode 100644 index 0000000..d279366 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/scene_training_model.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +from dataclasses import dataclass + +try: + import torch + from torch import nn +except Exception: # pragma: no cover + torch = None + nn = None + + +@dataclass(slots=True) +class SceneRepresentationConfig: + scene_count: int + style_count: int + source_family_count: int + use_count: int + class_count: int + image_size: int = 256 + width: int = 48 + embed_dim: int = 160 + dropout: float = 0.1 + + +if nn is not None: + class ConvBlock(nn.Module): + def __init__(self, in_channels: int, out_channels: int, *, stride: int = 1): + super().__init__() + self.block = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.GELU(), + nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.GELU(), + ) + + def forward(self, x): + return self.block(x) + + + class SceneRepresentationNet(nn.Module): + def __init__(self, config: SceneRepresentationConfig): + super().__init__() + self.config = config + width = config.width + self.stem = nn.Sequential( + nn.Conv2d(1, width, kernel_size=5, stride=2, padding=2, bias=False), + nn.BatchNorm2d(width), + nn.GELU(), + ) + self.encoder = nn.Sequential( + ConvBlock(width, width), + ConvBlock(width, width * 2, stride=2), + ConvBlock(width * 2, width * 2), + ConvBlock(width * 2, width * 4, stride=2), + ConvBlock(width * 4, width * 4), + ) + self.pool = nn.AdaptiveAvgPool2d((1, 1)) + self.backbone_head = nn.Sequential( + nn.Linear(width * 4, config.embed_dim), + nn.GELU(), + nn.Dropout(config.dropout), + ) + self.scene_head = nn.Linear(config.embed_dim, config.scene_count) + self.style_head = nn.Linear(config.embed_dim, config.style_count) + self.source_family_head = nn.Linear(config.embed_dim, config.source_family_count) + self.use_head = nn.Linear(config.embed_dim, config.use_count) + self.class_presence_head = nn.Linear(config.embed_dim, config.class_count) + self.component_count_head = nn.Linear(config.embed_dim, 1) + self.mapped_component_count_head = nn.Linear(config.embed_dim, 1) + + def encode(self, image): + features = self.stem(image) + features = self.encoder(features) + pooled = self.pool(features).flatten(1) + return self.backbone_head(pooled) + + def forward(self, image): + embedding = self.encode(image) + return { + "embedding": embedding, + "scene_logits": self.scene_head(embedding), + "style_logits": self.style_head(embedding), + "source_family_logits": self.source_family_head(embedding), + "use_logits": self.use_head(embedding), + "class_presence_logits": self.class_presence_head(embedding), + "component_count": self.component_count_head(embedding).squeeze(-1), + "mapped_component_count": self.mapped_component_count_head(embedding).squeeze(-1), + } +else: # pragma: no cover + class SceneRepresentationNet: # type: ignore[override] + def __init__(self, *args, **kwargs): + raise RuntimeError("torch not available; install torch to use SceneRepresentationNet") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sd_sketch_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sd_sketch_generator.py new file mode 100644 index 0000000..fdc478b --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sd_sketch_generator.py @@ -0,0 +1,1716 @@ +from __future__ import annotations + +import base64 +import os +from pathlib import Path +from typing import Any, Dict, List, Tuple + +import requests +from loguru import logger +from PIL import Image, ImageChops, ImageDraw, ImageFilter, ImageOps + +from .comfyui_client import ComfyUIClient +from .semantic_scene_v2 import summarize_scene_spec + + +class SDSketchGenerator: + def __init__(self, output_dir: str = "outputs", sd_api_url: str = "") -> None: + self.output_dir = output_dir + self.sd_api_url = str(sd_api_url or "").strip().rstrip("/") + self.comfy_client = ComfyUIClient(api_url=self.sd_api_url, output_dir=output_dir) + self.last_conditioning_report: Dict[str, Any] = {} + Path(self.output_dir).mkdir(parents=True, exist_ok=True) + + @property + def available(self) -> bool: + return self.sd_api_url.startswith("http") + + def set_sd_api_url(self, api_url: str) -> None: + self.sd_api_url = str(api_url or "").strip().rstrip("/") + self.comfy_client.set_api_url(self.sd_api_url) + + def _encode_image_to_base64(self, image_path: str) -> str: + with open(image_path, "rb") as handle: + return base64.b64encode(handle.read()).decode("utf-8") + + def _control_image_path(self, preview: Dict[str, Any]) -> str: + sketch_bundle = preview.get("sketch_bundle", {}) if isinstance(preview.get("sketch_bundle"), dict) else {} + for candidate in ( + sketch_bundle.get("sd_upstream_control"), + sketch_bundle.get("rich_preview"), + preview.get("sd_upstream_control_path"), + preview.get("rich_preview_path"), + preview.get("render_control_path"), + preview.get("low_preview_path"), + preview.get("image_path"), + ): + value = str(candidate or "").strip() + if value and os.path.exists(value): + return value + return "" + + def _style_prompt(self, sketch_style: str) -> str: + style = str(sketch_style or "").strip().lower() + mapping = { + "scribble_line": "expressive monochrome concept sketch, loose but readable contour lines", + "line_art": "clean monochrome line art sketch, readable contour lines, minimal shading", + "clean_line": "clean monochrome line art sketch, readable contour lines, minimal shading", + "wireframe": "technical wireframe sketch, structural contour drawing, monochrome", + "blueprint": "blueprint-style technical sketch, clean construction lines, minimal fill", + "minimal": "minimal line drawing, sparse contour lines, clean white background", + } + return mapping.get(style, "clean monochrome line art sketch, readable contour lines") + + def _build_prompt( + self, + scene_spec: Dict[str, Any] | None, + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + ) -> str: + sketch_options = sketch_options or {} + style_prompt = self._style_prompt(str(sketch_options.get("sketch_style", "line_art"))) + scene_summary = summarize_scene_spec(scene_spec or {}) if isinstance(scene_spec, dict) else "" + style_hint = str(sketch_options.get("style_hint", "") or "").strip() + prompt_suffix = str(sketch_options.get("prompt_suffix", "") or "").strip() + parts = [ + style_prompt, + "preserve composition, object placement, scale, and layering from the input control image", + "white or light paper background", + "high readability", + "no photorealistic shading", + ] + if title: + parts.append(str(title).strip()) + if scene_summary: + parts.append(scene_summary) + if style_hint: + parts.append(style_hint) + if prompt_suffix: + parts.append(prompt_suffix) + return ", ".join(part for part in parts if part) + + def _build_negative_prompt(self, sketch_style: str) -> str: + negative = [ + "photorealistic", + "full color rendering", + "oil painting", + "watercolor", + "3d render", + "ui screenshot", + "text", + "labels", + "arrows", + "boxes", + "watermark", + "blurry", + "messy composition", + "heavy shadows", + "thick paint texture", + ] + if str(sketch_style or "").strip().lower() == "blueprint": + negative.extend(["black paper", "dark background"]) + return ", ".join(negative) + + def _fallback_preview(self, preview: Dict[str, Any], reason: str) -> Dict[str, Any]: + payload = dict(preview or {}) + sketch_bundle = dict(payload.get("sketch_bundle") or {}) + if payload.get("image_path") and not sketch_bundle.get("native_structural_sketch"): + sketch_bundle["native_structural_sketch"] = payload.get("image_path") + sketch_bundle["active_sketch_backend"] = "native" + payload["sketch_bundle"] = sketch_bundle + payload["backend"] = payload.get("backend", "native_scene_spec_preview") + payload["sketch_backend"] = "native" + payload["note"] = reason + return payload + + def _conditioning_action_rank(self, action: str) -> int: + mapping = { + "hide": 0, + "replace": 1, + "inpaint": 2, + "emphasize": 3, + "weaken": 4, + "show": 5, + "transform": 8, + "idle": 9, + } + return mapping.get(str(action or "idle").strip().lower(), 9) + + def _region_conditioning_prompt(self, base_prompt: str, region: Dict[str, Any]) -> str: + label = str(region.get("label") or region.get("region_id") or "region").strip() + action = str(region.get("action") or region.get("edit_state") or "idle").strip().lower() + render_intent = region.get("render_intent") if isinstance(region.get("render_intent"), dict) else {} + prompt_hint = str(render_intent.get("prompt") or region.get("prompt") or "").strip() + if action in {"idle", "transform"} and not prompt_hint: + return "" + instruction = "" + if action == "hide": + instruction = f"remove the masked {label} and blend the surrounding structure naturally" + elif action == "replace": + instruction = f"replace the masked {label} with {prompt_hint or f'a clearer {label} matching the scene'}" + elif action == "inpaint": + instruction = f"redraw only the masked {label} region as {prompt_hint or f'a clearer {label}'}" + elif action == "emphasize": + instruction = f"make the masked {label} more prominent, clearer, and easier to read" + elif action == "weaken": + instruction = f"make the masked {label} subtler, lighter, and less dominant" + elif action == "show": + instruction = f"restore a readable {label} in the masked region consistent with the scene" + elif prompt_hint: + instruction = f"refine the masked {label} region as {prompt_hint}" + if not instruction: + return "" + return f"{base_prompt}. Apply only inside the masked region: {instruction}. Keep everything outside the mask stable." + + def _patch_conditioning_prompt(self, base_prompt: str, patch: Dict[str, Any]) -> str: + kind = str(patch.get("kind") or "").strip().lower() + prompt_hint = str(patch.get("prompt") or "").strip() + if kind == "erase_region": + instruction = prompt_hint or "remove the masked content and blend it naturally" + elif kind == "brush_mask": + instruction = prompt_hint or "clean and simplify the masked area while keeping the composition stable" + elif kind == "inpaint_region": + instruction = prompt_hint or "repaint the masked area so it is clean and readable" + else: + instruction = prompt_hint + if not instruction: + return "" + return f"{base_prompt}. Apply only inside the masked region: {instruction}. Keep everything outside the mask stable." + + def _region_mask_canvas(self, region: Dict[str, Any], canvas_size: tuple[int, int]) -> Image.Image: + canvas = Image.new("L", canvas_size, 0) + rect = region.get("current_rect") if isinstance(region.get("current_rect"), dict) else {} + if not rect: + return canvas + x = int(round(float(rect.get("x", 0) or 0))) + y = int(round(float(rect.get("y", 0) or 0))) + width = max(1, int(round(float(rect.get("width", 1) or 1)))) + height = max(1, int(round(float(rect.get("height", 1) or 1)))) + mask_path = str(region.get("mask_image_path") or "").strip() + if mask_path and os.path.exists(mask_path): + region_mask = Image.open(mask_path).convert("L").resize((width, height), Image.Resampling.LANCZOS) + else: + region_mask = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(region_mask) + shape = str(region.get("shape") or "rect").strip().lower() + if shape == "ellipse": + draw.ellipse([0, 0, max(0, width - 1), max(0, height - 1)], fill=255) + else: + draw.rounded_rectangle([0, 0, max(0, width - 1), max(0, height - 1)], radius=max(4, int(min(width, height) * 0.08)), fill=255) + layer = Image.new("L", canvas_size, 0) + layer.paste(region_mask, (x, y)) + rotation = float(region.get("rotation", 0.0) or 0.0) + if abs(rotation) > 0.01: + center = (x + width / 2.0, y + height / 2.0) + layer = layer.rotate(rotation, resample=Image.Resampling.BICUBIC, center=center) + return layer.filter(ImageFilter.GaussianBlur(radius=1.6)) + + def _patch_mask_canvas(self, patch: Dict[str, Any], canvas_size: tuple[int, int]) -> Image.Image: + canvas = Image.new("L", canvas_size, 0) + rect = patch.get("rect") if isinstance(patch.get("rect"), dict) else {} + if not rect: + return canvas + x = int(round(float(rect.get("x", 0) or 0))) + y = int(round(float(rect.get("y", 0) or 0))) + width = max(1, int(round(float(rect.get("width", 1) or 1)))) + height = max(1, int(round(float(rect.get("height", 1) or 1)))) + draw = ImageDraw.Draw(canvas) + draw.rounded_rectangle( + [x, y, x + width, y + height], + radius=max(6, int(min(width, height) * 0.12)), + fill=255, + ) + blur_radius = 8 if str(patch.get("kind") or "").strip().lower() == "brush_mask" else 4 + return canvas.filter(ImageFilter.GaussianBlur(radius=blur_radius)) + + def _save_mask_canvas(self, mask: Image.Image, filename_prefix: str) -> str: + rgba = Image.new("RGBA", mask.size, (255, 255, 255, 0)) + rgba.putalpha(mask) + output_path = os.path.join(self.output_dir, f"{filename_prefix}_{abs(hash(mask.tobytes()))}.png") + rgba.save(output_path) + return output_path + + def _save_luma_canvas(self, image: Image.Image, filename_prefix: str, suffix: str) -> str: + output_path = os.path.join(self.output_dir, f"{filename_prefix}_{suffix}_{abs(hash(image.tobytes()))}.png") + image.convert("L").save(output_path) + return output_path + + def _scene_canvas_size(self, scene_spec: Dict[str, Any] | None, fallback_size: tuple[int, int]) -> tuple[int, int]: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + canvas = scene_spec.get("canvas_size") if isinstance(scene_spec.get("canvas_size"), dict) else {} + width = max(1, int(canvas.get("width", fallback_size[0]) or fallback_size[0])) + height = max(1, int(canvas.get("height", fallback_size[1]) or fallback_size[1])) + return width, height + + def _scene_bbox(self, item: Dict[str, Any], canvas_size: tuple[int, int]) -> tuple[int, int, int, int]: + width_limit, height_limit = canvas_size + x0 = max(0, min(width_limit - 1, int(round(float(item.get("x", 0) or 0))))) + y0 = max(0, min(height_limit - 1, int(round(float(item.get("y", 0) or 0))))) + width = max(2, int(round(float(item.get("width", 1) or 1)))) + height = max(2, int(round(float(item.get("height", 1) or 1)))) + x1 = max(x0 + 2, min(width_limit, x0 + width)) + y1 = max(y0 + 2, min(height_limit, y0 + height)) + return x0, y0, x1, y1 + + def _scaled_points(self, points: List[List[float]], box: tuple[int, int, int, int]) -> List[Tuple[float, float]]: + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + return [(x0 + width * float(px), y0 + height * float(py)) for px, py in points if len([px, py]) == 2] + + def _draw_dashed_line(self, draw: ImageDraw.ImageDraw, start: Tuple[float, float], end: Tuple[float, float], *, fill: int, width: int = 1, dash_length: int = 10) -> None: + dx = end[0] - start[0] + dy = end[1] - start[1] + length = max(1.0, (dx * dx + dy * dy) ** 0.5) + steps = max(1, int(length / max(2, dash_length))) + for index in range(steps): + start_ratio = index / steps + end_ratio = min(1.0, (index + 0.55) / steps) + sx = start[0] + dx * start_ratio + sy = start[1] + dy * start_ratio + ex = start[0] + dx * end_ratio + ey = start[1] + dy * end_ratio + draw.line([(sx, sy), (ex, ey)], fill=fill, width=width) + + def _draw_shape_recipe_control( + self, + draw: ImageDraw.ImageDraw, + box: tuple[int, int, int, int], + shape_recipe: Dict[str, Any], + *, + fill_value: int, + outline_value: int, + accent_value: int, + ) -> bool: + parts = list((shape_recipe or {}).get("parts") or []) + if not parts: + return False + x0, y0, x1, y1 = box + width = max(1, x1 - x0) + height = max(1, y1 - y0) + drew = False + + for part in parts: + kind = str(part.get("kind") or "").strip().lower() + fill_role = str(part.get("fill_role", "fill") or "fill").strip().lower() + stroke_role = str(part.get("stroke_role", "line") or "line").strip().lower() + stroke_value = accent_value if stroke_role == "accent" else outline_value + stroke_width = max(1, int(round(max(width, height) * float(part.get("stroke_width", 0.02) or 0.02)))) + fill = None if fill_role in {"none", "transparent"} else fill_value + + if kind == "rect": + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + rx = max(0, int(min(width, height) * float(part.get("rx", 0.0) or 0.0))) + draw.rounded_rectangle(rect, radius=rx, fill=fill, outline=stroke_value, width=stroke_width) + drew = True + continue + if kind == "ellipse": + rect = [ + x0 + width * float(part.get("x", 0.0)), + y0 + height * float(part.get("y", 0.0)), + x0 + width * (float(part.get("x", 0.0)) + float(part.get("w", 0.0))), + y0 + height * (float(part.get("y", 0.0)) + float(part.get("h", 0.0))), + ] + draw.ellipse(rect, fill=fill, outline=stroke_value, width=stroke_width) + drew = True + continue + if kind == "line": + start = (x0 + width * float(part.get("x1", 0.0)), y0 + height * float(part.get("y1", 0.0))) + end = (x0 + width * float(part.get("x2", 0.0)), y0 + height * float(part.get("y2", 0.0))) + dash = list(part.get("dash") or []) + if dash: + dash_len = max(6, int(max(width, height) * float(dash[0] or 0.08))) + self._draw_dashed_line(draw, start, end, fill=stroke_value, width=stroke_width, dash_length=dash_len) + else: + draw.line([start, end], fill=stroke_value, width=stroke_width) + drew = True + continue + if kind == "polygon": + points = self._scaled_points(list(part.get("points") or []), box) + if points: + draw.polygon(points, fill=fill, outline=stroke_value) + if len(points) >= 2 and stroke_width > 1: + draw.line(points + [points[0]], fill=stroke_value, width=stroke_width) + drew = True + continue + if kind in {"polyline", "path"}: + points = self._scaled_points(list(part.get("points") or []), box) + if len(points) >= 2: + draw.line(points, fill=stroke_value, width=stroke_width) + drew = True + return drew + + def _draw_structure_asset_prior( + self, + draw: ImageDraw.ImageDraw, + box: tuple[int, int, int, int], + asset_key: str, + *, + fill_value: int, + outline_value: int, + accent_value: int, + ) -> None: + x0, y0, x1, y1 = box + width = max(2, x1 - x0) + height = max(2, y1 - y0) + key = str(asset_key or "").strip().lower() + line_w = max(2, int(round(min(width, height) * 0.03))) + accent_w = max(1, line_w - 1) + + if key in {"house", "home"}: + body = [x0 + width * 0.16, y0 + height * 0.30, x1 - width * 0.16, y1 - height * 0.02] + roof = [(x0 + width * 0.5, y0 + height * 0.03), (x0 + width * 0.10, y0 + height * 0.34), (x1 - width * 0.10, y0 + height * 0.34)] + draw.polygon(roof, fill=fill_value, outline=outline_value) + draw.line(roof + [roof[0]], fill=outline_value, width=line_w) + draw.rounded_rectangle(body, radius=max(6, int(min(width, height) * 0.06)), fill=fill_value, outline=outline_value, width=line_w) + door = [x0 + width * 0.43, y0 + height * 0.58, x0 + width * 0.57, y1 - height * 0.02] + left_window = [x0 + width * 0.24, y0 + height * 0.46, x0 + width * 0.36, y0 + height * 0.58] + right_window = [x0 + width * 0.64, y0 + height * 0.46, x0 + width * 0.76, y0 + height * 0.58] + for rect in (door, left_window, right_window): + draw.rectangle(rect, outline=accent_value, width=accent_w) + return + + if key in {"tree", "leaf", "plant", "bush"}: + trunk = [x0 + width * 0.44, y0 + height * 0.56, x0 + width * 0.56, y1] + draw.rounded_rectangle(trunk, radius=max(3, int(min(width, height) * 0.04)), fill=max(0, fill_value - 14), outline=outline_value, width=line_w) + canopy_boxes = [ + [x0 + width * 0.08, y0 + height * 0.18, x0 + width * 0.56, y0 + height * 0.74], + [x0 + width * 0.26, y0 + height * 0.02, x0 + width * 0.78, y0 + height * 0.66], + [x0 + width * 0.48, y0 + height * 0.16, x1, y0 + height * 0.80], + ] + for canopy in canopy_boxes: + draw.ellipse(canopy, fill=fill_value, outline=outline_value, width=line_w) + return + + if key in {"person", "human", "figure", "character"}: + head = [x0 + width * 0.37, y0 + height * 0.02, x0 + width * 0.63, y0 + height * 0.18] + torso = [x0 + width * 0.37, y0 + height * 0.20, x0 + width * 0.63, y0 + height * 0.60] + draw.ellipse(head, fill=fill_value, outline=outline_value, width=line_w) + draw.rounded_rectangle(torso, radius=max(4, int(min(width, height) * 0.06)), fill=fill_value, outline=outline_value, width=line_w) + draw.line([(x0 + width * 0.37, y0 + height * 0.30), (x0 + width * 0.22, y0 + height * 0.52)], fill=outline_value, width=line_w) + draw.line([(x0 + width * 0.63, y0 + height * 0.30), (x0 + width * 0.78, y0 + height * 0.52)], fill=outline_value, width=line_w) + draw.line([(x0 + width * 0.46, y0 + height * 0.60), (x0 + width * 0.38, y1)], fill=outline_value, width=line_w) + draw.line([(x0 + width * 0.54, y0 + height * 0.60), (x0 + width * 0.62, y1)], fill=outline_value, width=line_w) + return + + if key in {"building", "tower"}: + draw.rounded_rectangle([x0 + width * 0.12, y0 + height * 0.04, x1 - width * 0.12, y1], radius=max(6, int(min(width, height) * 0.04)), fill=fill_value, outline=outline_value, width=line_w) + for row in range(3): + for col in range(3): + wx = x0 + width * (0.24 + col * 0.18) + wy = y0 + height * (0.18 + row * 0.18) + ww = width * 0.08 + wh = height * 0.08 + draw.rectangle([wx, wy, wx + ww, wy + wh], outline=accent_value, width=accent_w) + return + + draw.rounded_rectangle( + [x0 + width * 0.08, y0 + height * 0.06, x1 - width * 0.08, y1 - height * 0.04], + radius=max(8, int(min(width, height) * 0.12)), + fill=fill_value, + outline=outline_value, + width=line_w, + ) + + def _structure_values(self, obj: Dict[str, Any], *, purpose: str) -> tuple[int, int, int]: + depth_band = str(obj.get("depth_band") or "").strip().lower() + role = str(obj.get("role") or "").strip().lower() + fill = {"background": 226, "midground": 208, "foreground": 190}.get(depth_band, 206) + outline = {"background": 108, "midground": 88, "foreground": 72}.get(depth_band, 84) + accent = {"background": 138, "midground": 116, "foreground": 96}.get(depth_band, 112) + if role in {"subject", "focus", "core_subject", "primary"}: + fill = max(150, fill - 10) + outline = max(46, outline - 10) + accent = max(62, accent - 8) + if purpose == "final_render": + fill = max(142, fill - 8) + outline = max(42, outline - 6) + accent = max(58, accent - 6) + return fill, outline, accent + + def _draw_structure_background_layer(self, draw: ImageDraw.ImageDraw, layer: Dict[str, Any], *, canvas_size: tuple[int, int]) -> None: + x0, y0, x1, y1 = self._scene_bbox(layer, canvas_size) + layer_type = str(layer.get("type") or "").strip().lower() + if layer_type == "process_band": + return + if layer_type == "sky": + draw.rectangle([x0, y0, x1, y1], fill=246) + draw.line([(x0, y1), (x1, y1)], fill=198, width=2) + return + if layer_type == "ground": + draw.rectangle([x0, y0, x1, y1], fill=238) + draw.line([(x0, y0), (x1, y0)], fill=184, width=2) + return + if layer_type == "road": + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(8, int(min(x1 - x0, y1 - y0) * 0.08)), fill=232, outline=182, width=2) + center_y = (y0 + y1) / 2.0 + self._draw_dashed_line(draw, (x0 + 22, center_y), (x1 - 22, center_y), fill=170, width=2, dash_length=22) + return + if layer_type == "water": + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(8, int(min(x1 - x0, y1 - y0) * 0.08)), fill=240, outline=188, width=2) + wave_y = y0 + (y1 - y0) * 0.35 + self._draw_dashed_line(draw, (x0 + 18, wave_y), (x1 - 18, wave_y), fill=180, width=2, dash_length=18) + return + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(8, int(min(x1 - x0, y1 - y0) * 0.08)), fill=242, outline=196, width=2) + + def _draw_structure_connectors(self, draw: ImageDraw.ImageDraw, scene_spec: Dict[str, Any], *, canvas_size: tuple[int, int]) -> None: + scene_type = str(((scene_spec.get("layout_options") or {}).get("scene_type")) or "scene").strip().lower() + if scene_type == "scene": + return + objects_by_id = { + str(item.get("id")): item + for item in (scene_spec.get("object_instances") or []) + if isinstance(item, dict) and item.get("id") and item.get("visible", True) is not False + } + for connector in scene_spec.get("connectors", []) or []: + if not isinstance(connector, dict): + continue + from_id = str(connector.get("from_id") or connector.get("source_id") or "") + to_id = str(connector.get("to_id") or connector.get("target_id") or "") + if not from_id or not to_id or from_id not in objects_by_id or to_id not in objects_by_id: + continue + fx0, fy0, fx1, fy1 = self._scene_bbox(objects_by_id[from_id], canvas_size) + tx0, ty0, tx1, ty1 = self._scene_bbox(objects_by_id[to_id], canvas_size) + start = ((fx0 + fx1) / 2.0, (fy0 + fy1) / 2.0) + end = ((tx0 + tx1) / 2.0, (ty0 + ty1) / 2.0) + self._draw_dashed_line(draw, start, end, fill=156, width=2, dash_length=14) + + def _draw_structure_region_constraints( + self, + draw: ImageDraw.ImageDraw, + scene_spec: Dict[str, Any] | None, + *, + purpose: str, + ) -> None: + if purpose != "final_render": + return + render_hints = (scene_spec or {}).get("render_hints") if isinstance((scene_spec or {}).get("render_hints"), dict) else {} + constraints = list(render_hints.get("region_edit_constraints") or []) + for item in constraints: + if not isinstance(item, dict): + continue + rect = item.get("current_rect") if isinstance(item.get("current_rect"), dict) else item.get("source_rect") if isinstance(item.get("source_rect"), dict) else {} + if not rect: + continue + x = int(round(float(rect.get("x", 0) or 0))) + y = int(round(float(rect.get("y", 0) or 0))) + width = max(2, int(round(float(rect.get("width", 1) or 1)))) + height = max(2, int(round(float(rect.get("height", 1) or 1)))) + box = [x, y, x + width, y + height] + action = str(item.get("action") or "").strip().lower() + visible = bool(item.get("visible", True)) + if action == "hide" or not visible: + draw.rounded_rectangle(box, radius=max(4, int(min(width, height) * 0.12)), fill=248, outline=214, width=2) + continue + emphasis = 84 if action in {"replace", "show", "inpaint"} else 98 if action == "emphasize" else 116 + draw.rounded_rectangle(box, radius=max(4, int(min(width, height) * 0.12)), fill=None, outline=emphasis, width=3) + + def _explicit_structure_canvas( + self, + scene_spec: Dict[str, Any] | None, + *, + control_image_path: str, + filename_prefix: str, + purpose: str, + ) -> str: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + with Image.open(control_image_path) as control_image: + canvas_size = self._scene_canvas_size(scene_spec, control_image.size) + image = Image.new("L", canvas_size, 248) + draw = ImageDraw.Draw(image) + scene_type = str(((scene_spec.get("layout_options") or {}).get("scene_type")) or "scene").strip().lower() + + for layer in sorted(scene_spec.get("background_layers", []) or [], key=lambda item: item.get("z_index", 0) if isinstance(item, dict) else 0): + if isinstance(layer, dict): + self._draw_structure_background_layer(draw, layer, canvas_size=canvas_size) + + objects = [obj for obj in (scene_spec.get("object_instances") or []) if isinstance(obj, dict) and obj.get("visible", True) is not False] + if scene_type in {"process", "schematic"}: + objects = [obj for obj in objects if not self._should_skip_direct_object(scene_type, obj)] + objects.sort(key=lambda item: (float(item.get("depth_z", 0.5) or 0.5), int(item.get("z_index", 0) or 0))) + prior_overlay_keys = { + "house", + "home", + "tree", + "leaf", + "plant", + "bush", + "person", + "human", + "figure", + "character", + "building", + "tower", + "sun", + "cloud", + "vapor", + "raindrop", + "battery", + "resistor", + "led", + "switch", + "diode", + "board", + } + for obj in objects: + box = self._scene_bbox(obj, canvas_size) + fill_value, outline_value, accent_value = self._structure_values(obj, purpose=purpose) + asset_key = str(obj.get("asset_key") or obj.get("silhouette_key") or obj.get("concept") or "") + shape_recipe = obj.get("shape_recipe") if isinstance(obj.get("shape_recipe"), dict) else {} + drew = self._draw_shape_recipe_control( + draw, + box, + shape_recipe, + fill_value=fill_value, + outline_value=outline_value, + accent_value=accent_value, + ) + should_overlay_prior = asset_key.strip().lower() in prior_overlay_keys + if not drew or should_overlay_prior: + if should_overlay_prior: + self._draw_direct_scene_object_mass(draw, obj, scene_type=scene_type, canvas_size=canvas_size) + else: + self._draw_structure_asset_prior( + draw, + box, + asset_key, + fill_value=fill_value, + outline_value=outline_value, + accent_value=accent_value, + ) + + self._draw_structure_connectors(draw, scene_spec, canvas_size=canvas_size) + self._draw_structure_region_constraints(draw, scene_spec, purpose=purpose) + + image = ImageOps.autocontrast(image) + if purpose == "sketch_upstream": + image = image.filter(ImageFilter.GaussianBlur(radius=0.2)) + return self._save_luma_canvas(image, filename_prefix, "structure_control") + + def _edge_control_canvas(self, control_image_path: str, filename_prefix: str) -> str: + with Image.open(control_image_path) as image: + gray = ImageOps.autocontrast(image.convert("L")) + smoothed = gray.filter(ImageFilter.GaussianBlur(radius=0.8)) + edges = smoothed.filter(ImageFilter.FIND_EDGES).point(lambda px: 255 if px > 18 else 0) + line_seed = gray.point(lambda px: 255 if px < 214 else 0).filter(ImageFilter.MaxFilter(size=3)) + merged = ImageChops.lighter(edges, line_seed).filter(ImageFilter.MaxFilter(size=3)) + merged = merged.filter(ImageFilter.GaussianBlur(radius=0.6)).point(lambda px: 255 if px > 18 else 0) + return self._save_luma_canvas(merged, filename_prefix, "edge_control") + + def _direct_scene_type(self, scene_spec: Dict[str, Any] | None) -> str: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + layout_options = scene_spec.get("layout_options") if isinstance(scene_spec.get("layout_options"), dict) else {} + return str(layout_options.get("scene_type") or layout_options.get("composition_mode") or "scene").strip().lower() or "scene" + + def _direct_scene_asset_allowlist(self, scene_type: str) -> set[str]: + if scene_type == "process": + return {"sun", "vapor", "cloud", "raindrop", "leaf", "energy_wave", "airplane", "cell"} + if scene_type == "schematic": + return {"battery", "resistor", "led", "switch", "capacitor", "diode", "board"} + return {"person", "house", "home", "building", "tree", "leaf", "plant", "bush", "road", "car", "street_lamp", "cloud", "sun", "dog", "table", "chair", "desk_lamp"} + + def _should_skip_direct_object(self, scene_type: str, obj: Dict[str, Any]) -> bool: + asset_key = str(obj.get("asset_key") or obj.get("silhouette_key") or "").strip().lower() + concept = str(obj.get("concept") or obj.get("label") or "").strip().lower() + allowlist = self._direct_scene_asset_allowlist(scene_type) + if asset_key and allowlist and asset_key not in allowlist: + return True + noise_terms = ("tri-maze", "scene sketch", "semantic sketch", "readable", "editable", "direct edit", "后续", "可编辑", "直接编辑", "包含", "contains", "结构", "说明", "描述") + if concept and any(token in concept for token in noise_terms): + return True + if scene_type == "schematic" and asset_key == "road": + return True + return False + + def _depth_value(self, obj: Dict[str, Any]) -> float: + depth_z = obj.get("depth_z") + if depth_z is not None: + try: + return max(0.0, min(1.0, float(depth_z))) + except Exception: + pass + return {"background": 0.28, "midground": 0.56, "foreground": 0.86}.get(str(obj.get("depth_band") or "").strip().lower(), 0.48) + + def _depth_control_canvas( + self, + scene_spec: Dict[str, Any] | None, + *, + canvas_size: tuple[int, int], + filename_prefix: str, + ) -> str: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + scene_type = self._direct_scene_type(scene_spec) + image = Image.new("L", canvas_size, 40) + draw = ImageDraw.Draw(image) + objects = [ + obj + for obj in (scene_spec.get("object_instances") or []) + if isinstance(obj, dict) and obj.get("visible", True) is not False and not self._should_skip_direct_object(scene_type, obj) + ] + for obj in sorted(objects, key=lambda item: float(item.get("depth_z", 0.5) or 0.5)): + x0 = int(round(float(obj.get("x", 0) or 0))) + y0 = int(round(float(obj.get("y", 0) or 0))) + width = max(1, int(round(float(obj.get("width", 1) or 1)))) + height = max(1, int(round(float(obj.get("height", 1) or 1)))) + pad = max(8, int(min(width, height) * 0.08)) + rect = [ + max(0, x0 - pad), + max(0, y0 - pad), + min(canvas_size[0], x0 + width + pad), + min(canvas_size[1], y0 + height + pad), + ] + depth_value = int(round(self._depth_value(obj) * 255)) + draw.rounded_rectangle(rect, radius=max(10, int(min(width, height) * 0.14)), fill=depth_value) + image = image.filter(ImageFilter.GaussianBlur(radius=10)) + return self._save_luma_canvas(image, filename_prefix, "depth_control") + + def _draw_direct_scene_background( + self, + draw: ImageDraw.ImageDraw, + scene_spec: Dict[str, Any] | None, + *, + canvas_size: tuple[int, int], + ) -> None: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + scene_type = self._direct_scene_type(scene_spec) + width, height = canvas_size + if scene_type == "schematic": + return + for layer in sorted(scene_spec.get("background_layers", []) or [], key=lambda item: item.get("z_index", 0) if isinstance(item, dict) else 0): + if not isinstance(layer, dict): + continue + x0, y0, x1, y1 = self._scene_bbox(layer, canvas_size) + layer_type = str(layer.get("type") or "").strip().lower() + if scene_type == "process" and layer_type not in {"sky", "ground", "water"}: + continue + if layer_type == "sky": + draw.rectangle([x0, y0, x1, y1], fill=246) + continue + if layer_type == "ground": + draw.rectangle([x0, y0, x1, y1], fill=232) + draw.line([(0, y0), (width, y0)], fill=220, width=max(2, height // 256)) + continue + if layer_type == "road": + if scene_type != "scene": + continue + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(14, int(min(x1 - x0, y1 - y0) * 0.08)), fill=226) + continue + if layer_type == "water": + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(14, int(min(x1 - x0, y1 - y0) * 0.08)), fill=236) + continue + if scene_type == "process": + continue + draw.rounded_rectangle([x0, y0, x1, y1], radius=max(12, int(min(x1 - x0, y1 - y0) * 0.08)), fill=240) + + def _scene_region_box( + self, + obj: Dict[str, Any], + region: Dict[str, Any], + canvas_size: tuple[int, int], + ) -> tuple[int, int, int, int]: + x0, y0, x1, y1 = self._scene_bbox(obj, canvas_size) + width = max(1, x1 - x0) + height = max(1, y1 - y0) + rx0 = x0 + width * float(region.get("x", 0.0) or 0.0) + ry0 = y0 + height * float(region.get("y", 0.0) or 0.0) + rx1 = rx0 + width * float(region.get("width", 0.0) or 0.0) + ry1 = ry0 + height * float(region.get("height", 0.0) or 0.0) + return ( + int(round(rx0)), + int(round(ry0)), + max(int(round(rx0)) + 2, int(round(rx1))), + max(int(round(ry0)) + 2, int(round(ry1))), + ) + + def _mass_fill_value(self, obj: Dict[str, Any], *, delta: int = 0) -> int: + depth_band = str(obj.get("depth_band") or "").strip().lower() + base = {"background": 206, "midground": 160, "foreground": 116}.get(depth_band, 150) + role = str(obj.get("role") or "").strip().lower() + if role in {"subject", "focus", "core_subject", "primary"}: + base = max(88, base - 12) + return max(56, min(228, base + delta)) + + def _draw_direct_scene_object_mass( + self, + draw: ImageDraw.ImageDraw, + obj: Dict[str, Any], + *, + scene_type: str, + canvas_size: tuple[int, int], + ) -> None: + asset_key = str(obj.get("asset_key") or obj.get("concept") or "").strip().lower() + concept = str(obj.get("concept") or obj.get("label") or "").strip().lower() + x0, y0, x1, y1 = self._scene_bbox(obj, canvas_size) + width = max(2, x1 - x0) + height = max(2, y1 - y0) + primary_fill = self._mass_fill_value(obj) + secondary_fill = self._mass_fill_value(obj, delta=18) + accent_fill = self._mass_fill_value(obj, delta=-12) + regions = [item for item in (obj.get("region_masks") or []) if isinstance(item, dict)] + if self._should_skip_direct_object(scene_type, obj): + return + + if regions: + for index, region in enumerate(regions): + rx0, ry0, rx1, ry1 = self._scene_region_box(obj, region, canvas_size) + fill_value = max(48, min(236, primary_fill + index * 8)) + shape = str(region.get("shape") or "rect").strip().lower() + if shape == "ellipse": + draw.ellipse([rx0, ry0, rx1, ry1], fill=fill_value) + else: + draw.rounded_rectangle( + [rx0, ry0, rx1, ry1], + radius=max(8, int(min(rx1 - rx0, ry1 - ry0) * 0.16)), + fill=fill_value, + ) + return + + if asset_key in {"person", "human", "figure", "character"}: + head = [x0 + width * 0.34, y0 + height * 0.04, x0 + width * 0.66, y0 + height * 0.24] + torso = [x0 + width * 0.30, y0 + height * 0.22, x0 + width * 0.70, y0 + height * 0.62] + leg_left = [x0 + width * 0.34, y0 + height * 0.58, x0 + width * 0.48, y1] + leg_right = [x0 + width * 0.52, y0 + height * 0.58, x0 + width * 0.66, y1] + draw.ellipse(head, fill=primary_fill) + draw.rounded_rectangle(torso, radius=max(10, int(min(width, height) * 0.12)), fill=accent_fill) + draw.rounded_rectangle(leg_left, radius=max(6, int(min(width, height) * 0.08)), fill=secondary_fill) + draw.rounded_rectangle(leg_right, radius=max(6, int(min(width, height) * 0.08)), fill=secondary_fill) + return + + if asset_key in {"house", "home"}: + roof = [(x0 + width * 0.50, y0 + height * 0.02), (x0 + width * 0.08, y0 + height * 0.34), (x1 - width * 0.08, y0 + height * 0.34)] + body = [x0 + width * 0.14, y0 + height * 0.28, x1 - width * 0.14, y1] + draw.polygon(roof, fill=accent_fill) + draw.rounded_rectangle(body, radius=max(10, int(min(width, height) * 0.08)), fill=primary_fill) + return + + if asset_key in {"tree", "leaf", "plant", "bush"}: + canopy_a = [x0 + width * 0.06, y0 + height * 0.10, x0 + width * 0.60, y0 + height * 0.72] + canopy_b = [x0 + width * 0.30, y0 + height * 0.02, x1 - width * 0.02, y0 + height * 0.68] + trunk = [x0 + width * 0.42, y0 + height * 0.56, x0 + width * 0.58, y1] + draw.ellipse(canopy_a, fill=primary_fill) + draw.ellipse(canopy_b, fill=secondary_fill) + draw.rounded_rectangle(trunk, radius=max(6, int(min(width, height) * 0.06)), fill=accent_fill) + return + + if asset_key in {"building", "tower"}: + draw.rounded_rectangle([x0 + width * 0.10, y0 + height * 0.04, x1 - width * 0.10, y1], radius=max(10, int(min(width, height) * 0.06)), fill=primary_fill) + return + + if asset_key == "sun": + halo = [x0 + width * 0.08, y0 + height * 0.08, x1 - width * 0.08, y1 - height * 0.08] + core = [x0 + width * 0.22, y0 + height * 0.22, x1 - width * 0.22, y1 - height * 0.22] + draw.ellipse(halo, fill=secondary_fill) + draw.ellipse(core, fill=accent_fill) + return + + if asset_key == "cloud": + draw.ellipse([x0 + width * 0.06, y0 + height * 0.28, x0 + width * 0.46, y1 - height * 0.08], fill=secondary_fill) + draw.ellipse([x0 + width * 0.28, y0 + height * 0.08, x0 + width * 0.72, y1 - height * 0.16], fill=primary_fill) + draw.ellipse([x0 + width * 0.52, y0 + height * 0.22, x1 - width * 0.04, y1 - height * 0.06], fill=secondary_fill) + return + + if asset_key == "vapor": + for index in range(3): + left = x0 + width * (0.18 + index * 0.18) + top = y0 + height * (0.16 + (index % 2) * 0.08) + right = left + width * 0.16 + bottom = y1 - height * 0.08 + draw.ellipse([left, top, right, bottom], fill=primary_fill if index == 1 else secondary_fill) + return + + if asset_key == "raindrop": + drop = [ + (x0 + width * 0.50, y0 + height * 0.06), + (x0 + width * 0.24, y0 + height * 0.42), + (x0 + width * 0.30, y1 - height * 0.10), + (x0 + width * 0.70, y1 - height * 0.10), + (x0 + width * 0.76, y0 + height * 0.42), + ] + draw.polygon(drop, fill=primary_fill) + return + + if asset_key in {"cycle", "flow_node"}: + outer = [x0 + width * 0.12, y0 + height * 0.16, x1 - width * 0.12, y1 - height * 0.16] + inner = [x0 + width * 0.30, y0 + height * 0.34, x1 - width * 0.30, y1 - height * 0.34] + draw.ellipse(outer, fill=secondary_fill) + draw.ellipse(inner, fill=248) + return + + if asset_key == "battery": + body = [x0 + width * 0.14, y0 + height * 0.28, x1 - width * 0.12, y1 - height * 0.18] + nub = [x1 - width * 0.16, y0 + height * 0.38, x1 - width * 0.04, y0 + height * 0.58] + draw.rounded_rectangle(body, radius=max(8, int(min(width, height) * 0.12)), fill=primary_fill) + draw.rounded_rectangle(nub, radius=max(4, int(min(width, height) * 0.06)), fill=accent_fill) + return + + if asset_key == "resistor": + left_lead = [x0 + width * 0.04, y0 + height * 0.46, x0 + width * 0.20, y0 + height * 0.54] + core = [x0 + width * 0.18, y0 + height * 0.30, x1 - width * 0.18, y1 - height * 0.30] + right_lead = [x1 - width * 0.20, y0 + height * 0.46, x1 - width * 0.04, y0 + height * 0.54] + draw.rounded_rectangle(left_lead, radius=max(4, int(min(width, height) * 0.05)), fill=secondary_fill) + draw.rounded_rectangle(core, radius=max(8, int(min(width, height) * 0.10)), fill=primary_fill) + draw.rounded_rectangle(right_lead, radius=max(4, int(min(width, height) * 0.05)), fill=secondary_fill) + return + + if asset_key in {"led", "diode"}: + left_lead = [x0 + width * 0.06, y0 + height * 0.46, x0 + width * 0.24, y0 + height * 0.54] + bulb = [x0 + width * 0.22, y0 + height * 0.22, x0 + width * 0.72, y1 - height * 0.18] + base = [x0 + width * 0.56, y0 + height * 0.36, x1 - width * 0.08, y0 + height * 0.62] + draw.rounded_rectangle(left_lead, radius=max(4, int(min(width, height) * 0.05)), fill=secondary_fill) + draw.ellipse(bulb, fill=primary_fill) + draw.rounded_rectangle(base, radius=max(6, int(min(width, height) * 0.08)), fill=accent_fill) + return + + if asset_key == "switch" or (asset_key in {"module", "board"} and any(token in concept for token in ("开关", "switch", "toggle", "button"))): + left_contact = [x0 + width * 0.14, y0 + height * 0.42, x0 + width * 0.28, y0 + height * 0.58] + right_contact = [x1 - width * 0.28, y0 + height * 0.42, x1 - width * 0.14, y0 + height * 0.58] + draw.ellipse(left_contact, fill=secondary_fill) + draw.ellipse(right_contact, fill=secondary_fill) + draw.line( + [(x0 + width * 0.28, y0 + height * 0.50), (x1 - width * 0.18, y0 + height * 0.26)], + fill=accent_fill, + width=max(4, int(min(width, height) * 0.08)), + ) + draw.rounded_rectangle( + [x0 + width * 0.08, y0 + height * 0.26, x1 - width * 0.08, y1 - height * 0.20], + radius=max(8, int(min(width, height) * 0.10)), + outline=primary_fill, + width=max(3, int(min(width, height) * 0.05)), + ) + return + + if asset_key in {"module", "board"}: + body = [x0 + width * 0.10, y0 + height * 0.16, x1 - width * 0.10, y1 - height * 0.16] + draw.rounded_rectangle(body, radius=max(8, int(min(width, height) * 0.10)), fill=primary_fill) + notch_size = max(6, int(min(width, height) * 0.12)) + draw.rounded_rectangle([x0 + width * 0.18, y0 + height * 0.28, x0 + width * 0.34, y0 + height * 0.44], radius=notch_size // 3, fill=secondary_fill) + draw.rounded_rectangle([x0 + width * 0.58, y0 + height * 0.56, x0 + width * 0.76, y0 + height * 0.72], radius=notch_size // 3, fill=secondary_fill) + return + + if asset_key == "branch": + node = [x0 + width * 0.34, y0 + height * 0.30, x0 + width * 0.66, y0 + height * 0.62] + draw.ellipse(node, fill=primary_fill) + draw.rounded_rectangle([x0 + width * 0.08, y0 + height * 0.44, x0 + width * 0.34, y0 + height * 0.52], radius=max(4, int(min(width, height) * 0.05)), fill=secondary_fill) + draw.rounded_rectangle([x0 + width * 0.66, y0 + height * 0.44, x1 - width * 0.08, y0 + height * 0.52], radius=max(4, int(min(width, height) * 0.05)), fill=secondary_fill) + return + + if asset_key == "road" and scene_type == "schematic": + center_y = y0 + height * 0.50 + draw.rounded_rectangle([x0 + width * 0.04, center_y - height * 0.08, x1 - width * 0.04, center_y + height * 0.08], radius=max(6, int(min(width, height) * 0.06)), fill=secondary_fill) + return + + if asset_key == "road" and scene_type == "scene": + draw.rounded_rectangle([x0 + width * 0.04, y0 + height * 0.28, x1 - width * 0.04, y1 - height * 0.10], radius=max(10, int(min(width, height) * 0.08)), fill=secondary_fill) + return + + if asset_key == "car": + body = [x0 + width * 0.12, y0 + height * 0.34, x1 - width * 0.10, y1 - height * 0.10] + roof = [x0 + width * 0.28, y0 + height * 0.12, x0 + width * 0.72, y0 + height * 0.40] + wheel_a = [x0 + width * 0.18, y1 - height * 0.24, x0 + width * 0.38, y1 - height * 0.02] + wheel_b = [x0 + width * 0.62, y1 - height * 0.24, x0 + width * 0.82, y1 - height * 0.02] + draw.rounded_rectangle(body, radius=max(10, int(min(width, height) * 0.10)), fill=primary_fill) + draw.rounded_rectangle(roof, radius=max(8, int(min(width, height) * 0.08)), fill=secondary_fill) + draw.ellipse(wheel_a, fill=accent_fill) + draw.ellipse(wheel_b, fill=accent_fill) + return + + draw.rounded_rectangle( + [x0 + width * 0.06, y0 + height * 0.06, x1 - width * 0.06, y1 - height * 0.04], + radius=max(12, int(min(width, height) * 0.14)), + fill=primary_fill, + ) + + def _draw_direct_scene_connectors( + self, + draw: ImageDraw.ImageDraw, + scene_spec: Dict[str, Any] | None, + *, + canvas_size: tuple[int, int], + scene_type: str, + ) -> None: + if scene_type == "scene": + return + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + objects_by_id = { + str(item.get("id")): item + for item in (scene_spec.get("object_instances") or []) + if isinstance(item, dict) and item.get("id") and item.get("visible", True) is not False and not self._should_skip_direct_object(scene_type, item) + } + for connector in scene_spec.get("connectors", []) or []: + if not isinstance(connector, dict): + continue + from_id = str(connector.get("from_id") or connector.get("source_id") or "") + to_id = str(connector.get("to_id") or connector.get("target_id") or "") + if not from_id or not to_id or from_id not in objects_by_id or to_id not in objects_by_id: + continue + fx0, fy0, fx1, fy1 = self._scene_bbox(objects_by_id[from_id], canvas_size) + tx0, ty0, tx1, ty1 = self._scene_bbox(objects_by_id[to_id], canvas_size) + start = ((fx0 + fx1) / 2.0, (fy0 + fy1) / 2.0) + end = ((tx0 + tx1) / 2.0, (ty0 + ty1) / 2.0) + if scene_type == "schematic": + mid_x = (start[0] + end[0]) / 2.0 + draw.line([start, (mid_x, start[1]), (mid_x, end[1]), end], fill=170, width=3) + else: + self._draw_dashed_line(draw, start, end, fill=176, width=2, dash_length=16) + + def _direct_scene_background_plate( + self, + scene_spec: Dict[str, Any] | None, + *, + canvas_size: tuple[int, int], + filename_prefix: str, + ) -> str: + image = Image.new("RGB", canvas_size, (248, 246, 241)) + gray = image.convert("L") + draw = ImageDraw.Draw(gray) + self._draw_direct_scene_background(draw, scene_spec, canvas_size=canvas_size) + output_path = os.path.join(self.output_dir, f"{filename_prefix}_direct_base.png") + gray.convert("RGB").save(output_path) + return output_path + + def _direct_scene_layout_canvas( + self, + scene_spec: Dict[str, Any] | None, + *, + canvas_size: tuple[int, int], + filename_prefix: str, + ) -> str: + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + scene_type = self._direct_scene_type(scene_spec) + image = Image.new("L", canvas_size, 248) + draw = ImageDraw.Draw(image) + self._draw_direct_scene_background(draw, scene_spec, canvas_size=canvas_size) + objects = [ + obj + for obj in (scene_spec.get("object_instances") or []) + if isinstance(obj, dict) and obj.get("visible", True) is not False and not self._should_skip_direct_object(scene_type, obj) + ] + objects.sort(key=lambda item: (float(item.get("depth_z", 0.5) or 0.5), int(item.get("z_index", 0) or 0))) + for obj in objects: + self._draw_direct_scene_object_mass(draw, obj, scene_type=scene_type, canvas_size=canvas_size) + self._draw_direct_scene_connectors(draw, scene_spec, canvas_size=canvas_size, scene_type=scene_type) + blur_radius = 8.0 if scene_type == "scene" else 5.2 if scene_type == "process" else 4.4 + image = image.filter(ImageFilter.GaussianBlur(radius=blur_radius)) + image = ImageOps.autocontrast(image, cutoff=1) + return self._save_luma_canvas(image, filename_prefix, "direct_scene_layout") + + def build_direct_scene_prior( + self, + *, + scene_spec: Dict[str, Any] | None = None, + filename_prefix: str = "direct_scene", + fallback_size: tuple[int, int] = (1024, 768), + ) -> Dict[str, Any]: + canvas_size = self._scene_canvas_size(scene_spec, fallback_size) + base_plate_path = self._direct_scene_background_plate( + scene_spec, + canvas_size=canvas_size, + filename_prefix=filename_prefix, + ) + layout_control_path = self._direct_scene_layout_canvas( + scene_spec, + canvas_size=canvas_size, + filename_prefix=filename_prefix, + ) + depth_control_path = self._depth_control_canvas( + scene_spec, + canvas_size=canvas_size, + filename_prefix=filename_prefix, + ) + return { + "canvas_size": {"width": canvas_size[0], "height": canvas_size[1]}, + "base_plate_path": base_plate_path, + "layout_control_path": layout_control_path, + "depth_control_path": depth_control_path, + } + + def build_direct_scene_controlnet_bundle( + self, + *, + scene_spec: Dict[str, Any] | None = None, + prior_bundle: Dict[str, Any] | None = None, + filename_prefix: str = "direct_scene", + ) -> Dict[str, Any]: + if not self.comfy_client.is_comfyui_server(): + return {} + prior_bundle = prior_bundle if isinstance(prior_bundle, dict) else {} + available = self.comfy_client.get_available_controlnets() + if not available: + return {} + available_markers = [name.casefold() for name in available] + layout_path = str(prior_bundle.get("layout_control_path") or "").strip() + depth_path = str(prior_bundle.get("depth_control_path") or "").strip() + base_plate_path = str(prior_bundle.get("base_plate_path") or layout_path or "").strip() + inputs: list[Dict[str, Any]] = [] + + scene_type = self._direct_scene_type(scene_spec) + structure_path = "" + if scene_spec and base_plate_path: + try: + structure_path = self._explicit_structure_canvas( + scene_spec, + control_image_path=base_plate_path, + filename_prefix=f"{filename_prefix}_direct", + purpose="sketch_candidate", + ) + except Exception as exc: + logger.warning(f"failed to build direct scene structure control: {exc}") + structure_path = "" + if structure_path: + inputs.append( + { + "image_path": structure_path, + "control_net_name": self.comfy_client.pick_controlnet(["lineart", "sketch", "scribble", "canny"]), + "strength": 0.54 if scene_type == "schematic" else 0.48 if scene_type == "process" else 0.40, + "start_percent": 0.0, + "end_percent": 0.90 if scene_type == "schematic" else 0.86 if scene_type == "process" else 0.78, + "kind": "scene_structure", + } + ) + if layout_path: + control_name = self.comfy_client.pick_controlnet(["scribble", "sketch", "lineart", "canny"]) + control_path = layout_path + if "canny" in str(control_name).casefold(): + control_path = self._edge_control_canvas(layout_path, filename_prefix) + inputs.append( + { + "image_path": control_path, + "control_net_name": control_name, + "strength": 0.66 if scene_type in {"process", "schematic"} else 0.58, + "start_percent": 0.0, + "end_percent": 0.90 if scene_type in {"process", "schematic"} else 0.84, + "kind": "scene_layout", + } + ) + if depth_path and any("depth" in marker for marker in available_markers): + inputs.append( + { + "image_path": depth_path, + "control_net_name": self.comfy_client.pick_controlnet(["depth"]), + "strength": 0.24 if scene_type in {"process", "schematic"} else 0.42, + "start_percent": 0.0, + "end_percent": 0.82 if scene_type in {"process", "schematic"} else 0.88, + "kind": "scene_depth", + } + ) + if not inputs or not base_plate_path: + return {} + init_image_path = base_plate_path or layout_path + return { + "purpose": "direct_scene", + "comfy_mode": "img2img_controlnet" if scene_type in {"process", "schematic"} else "txt2img_controlnet", + "init_image_path": init_image_path, + "inputs": inputs, + "layout_control_path": layout_path, + "depth_control_path": depth_path, + "structure_control_path": structure_path, + } + + def build_controlnet_bundle( + self, + *, + control_image_path: str, + scene_spec: Dict[str, Any] | None = None, + filename_prefix: str = "controlnet", + purpose: str = "sketch_candidate", + ) -> Dict[str, Any]: + if not self.comfy_client.is_comfyui_server(): + return {} + available = self.comfy_client.get_available_controlnets() + if not available: + return {} + + available_markers = [name.casefold() for name in available] + with Image.open(control_image_path) as image: + canvas_size = self._scene_canvas_size(scene_spec, image.size) + + structure_path = "" + if scene_spec: + try: + structure_path = self._explicit_structure_canvas( + scene_spec, + control_image_path=control_image_path, + filename_prefix=filename_prefix, + purpose=purpose, + ) + except Exception as exc: + logger.warning(f"failed to build explicit structure control: {exc}") + structure_path = "" + + inputs: list[Dict[str, Any]] = [] + init_image_path = control_image_path + + if purpose in {"sketch_upstream", "sketch_candidate"} and structure_path: + sketch_model = self.comfy_client.pick_controlnet(["sketch", "scribble", "lineart", "canny"]) + inputs.append( + { + "image_path": structure_path, + "control_net_name": sketch_model, + "strength": 0.86 if purpose == "sketch_upstream" else 0.78, + "start_percent": 0.0, + "end_percent": 1.0, + "kind": "structure_sketch", + } + ) + canny_model = self.comfy_client.pick_controlnet(["canny", "lineart", "sketch"]) + if "canny" in str(canny_model).casefold(): + structure_edge_path = self._edge_control_canvas(structure_path, filename_prefix) + inputs.append( + { + "image_path": structure_edge_path, + "control_net_name": canny_model, + "strength": 0.48 if purpose == "sketch_upstream" else 0.42, + "start_percent": 0.0, + "end_percent": 0.88, + "kind": "structure_canny", + } + ) + else: + if any(marker for marker in available_markers if any(tag in marker for tag in ("canny", "lineart", "sketch", "scribble"))): + edge_path = self._edge_control_canvas(control_image_path, filename_prefix) + if purpose == "final_render": + strength = 0.9 + elif purpose == "sketch_upstream": + strength = 1.0 + else: + strength = 0.96 + inputs.append( + { + "image_path": edge_path, + "control_net_name": self.comfy_client.pick_controlnet( + ["canny", "lineart", "sketch", "scribble"] if purpose != "final_render" else ["sketch", "lineart", "scribble", "canny"] + ), + "strength": strength, + "start_percent": 0.0, + "end_percent": 1.0, + "kind": "edge", + } + ) + + if purpose == "final_render": + sketch_model = "" + try: + sketch_model = self.comfy_client.pick_controlnet(["sketch", "scribble", "lineart"]) + except Exception: + sketch_model = "" + if sketch_model: + inputs.insert( + 0, + { + "image_path": control_image_path, + "control_net_name": sketch_model, + "strength": 0.88, + "start_percent": 0.0, + "end_percent": 1.0, + "kind": "edited_sketch", + }, + ) + if structure_path: + inputs.append( + { + "image_path": structure_path, + "control_net_name": self.comfy_client.pick_controlnet(["sketch", "scribble", "lineart", "canny"]), + "strength": 0.42, + "start_percent": 0.0, + "end_percent": 0.82, + "kind": "scene_structure", + } + ) + + if scene_spec and any("depth" in marker for marker in available_markers): + depth_path = self._depth_control_canvas(scene_spec, canvas_size=canvas_size, filename_prefix=filename_prefix) + inputs.append( + { + "image_path": depth_path, + "control_net_name": self.comfy_client.pick_controlnet(["depth"]), + "strength": 0.58 if purpose != "final_render" else 0.46, + "start_percent": 0.0, + "end_percent": 0.86, + "kind": "depth", + } + ) + + if not inputs: + return {} + return { + "purpose": purpose, + "comfy_mode": "img2img_controlnet", + "init_image_path": init_image_path, + "structure_image_path": structure_path, + "inputs": inputs, + } + + def _iter_conditioning_ops(self, conditioning_bundle: Dict[str, Any] | None = None) -> list[Dict[str, Any]]: + bundle = conditioning_bundle if isinstance(conditioning_bundle, dict) else {} + ops: list[Dict[str, Any]] = [] + for region in bundle.get("region_layers", []) or []: + if not isinstance(region, dict): + continue + action = str(region.get("action") or region.get("edit_state") or "idle").strip().lower() + if action in {"idle", "transform"} and not str(((region.get("render_intent") or {}).get("prompt") or "")).strip(): + continue + if action == "show" and not str(((region.get("render_intent") or {}).get("prompt") or "")).strip(): + continue + ops.append({"kind": "region", "action": action, "payload": region}) + for patch in bundle.get("patch_layers", []) or []: + if not isinstance(patch, dict): + continue + kind = str(patch.get("kind") or "").strip().lower() + if kind not in {"erase_region", "brush_mask", "inpaint_region"}: + continue + ops.append({"kind": "patch", "action": kind, "payload": patch}) + ops.sort(key=lambda item: (self._conditioning_action_rank(item.get("action", "")), item.get("kind", ""))) + return ops[:6] + + def render_inpaint( + self, + *, + prompt: str, + negative_prompt: str, + init_image_path: str, + mask_image_path: str, + denoising_strength: float, + steps: int, + cfg_scale: float, + sampler_name: str, + filename_prefix: str, + ) -> str: + with Image.open(init_image_path) as image: + width, height = image.size + + if self.comfy_client.is_comfyui_server(): + return self.comfy_client.render_inpaint( + prompt=prompt, + negative_prompt=negative_prompt, + init_image_path=init_image_path, + mask_image_path=mask_image_path, + steps=steps, + cfg_scale=cfg_scale, + denoising_strength=denoising_strength, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + ) + + payload = { + "init_images": [self._encode_image_to_base64(init_image_path)], + "mask": self._encode_image_to_base64(mask_image_path), + "prompt": prompt, + "negative_prompt": negative_prompt, + "denoising_strength": float(denoising_strength), + "steps": int(steps), + "cfg_scale": float(cfg_scale), + "width": width, + "height": height, + "sampler_name": str(sampler_name or "DPM++ 2M Karras"), + "resize_mode": 0, + "mask_blur": 4, + "inpainting_fill": 1, + "inpaint_full_res": True, + "inpaint_full_res_padding": 32, + } + response = requests.post( + url=f"{self.sd_api_url}/sdapi/v1/img2img", + json=payload, + timeout=240, + ) + response.raise_for_status() + result = response.json() + images = result.get("images") or [] + if not images: + raise RuntimeError("SD inpaint backend returned no images") + output_path = os.path.join(self.output_dir, f"{filename_prefix}_{abs(hash(prompt + init_image_path + mask_image_path))}.png") + with open(output_path, "wb") as handle: + handle.write(base64.b64decode(images[0])) + return output_path + + def _apply_conditioning_passes( + self, + *, + base_image_path: str, + prompt: str, + negative_prompt: str, + conditioning_bundle: Dict[str, Any] | None = None, + steps: int, + cfg_scale: float, + denoising_strength: float, + sampler_name: str, + filename_prefix: str, + ) -> str: + bundle = conditioning_bundle if isinstance(conditioning_bundle, dict) else {} + ops = self._iter_conditioning_ops(bundle) + self.last_conditioning_report = { + "applied": False, + "base_image_path": base_image_path, + "final_image_path": base_image_path, + "operations": [], + } + if not ops or not os.path.exists(base_image_path): + return base_image_path + canvas = bundle.get("canvas_size") if isinstance(bundle.get("canvas_size"), dict) else {} + with Image.open(base_image_path) as base_image: + canvas_size = ( + max(1, int(canvas.get("width", base_image.size[0]) or base_image.size[0])), + max(1, int(canvas.get("height", base_image.size[1]) or base_image.size[1])), + ) + current_image_path = base_image_path + for index, op in enumerate(ops, start=1): + payload = op.get("payload") if isinstance(op.get("payload"), dict) else {} + if op.get("kind") == "region": + mask = self._region_mask_canvas(payload, canvas_size) + local_prompt = self._region_conditioning_prompt(prompt, payload) + else: + mask = self._patch_mask_canvas(payload, canvas_size) + local_prompt = self._patch_conditioning_prompt(prompt, payload) + if not local_prompt or mask.getbbox() is None: + continue + mask_path = self._save_mask_canvas(mask, f"{filename_prefix}_mask_{index}") + try: + next_image_path = self.render_inpaint( + prompt=local_prompt, + negative_prompt=negative_prompt, + init_image_path=current_image_path, + mask_image_path=mask_path, + denoising_strength=max(0.18, min(0.62, float(denoising_strength) * (0.95 if op.get("kind") == "region" else 0.88))), + steps=max(10, min(int(steps), 20)), + cfg_scale=float(cfg_scale), + sampler_name=sampler_name, + filename_prefix=f"{filename_prefix}_cond_{index}", + ) + current_image_path = next_image_path + self.last_conditioning_report["operations"].append( + { + "kind": op.get("kind"), + "action": op.get("action"), + "status": "applied", + "mask_image_path": mask_path, + "output_image_path": next_image_path, + } + ) + except Exception as exc: + logger.warning(f"conditioning inpaint failed: {exc}") + self.last_conditioning_report["operations"].append( + { + "kind": op.get("kind"), + "action": op.get("action"), + "status": "failed", + "mask_image_path": mask_path, + "error": str(exc), + } + ) + self.last_conditioning_report["applied"] = any(item.get("status") == "applied" for item in self.last_conditioning_report["operations"]) + self.last_conditioning_report["final_image_path"] = current_image_path + return current_image_path + + def render_img2img( + self, + *, + prompt: str, + negative_prompt: str, + control_image_path: str, + denoising_strength: float, + steps: int, + cfg_scale: float, + sampler_name: str, + filename_prefix: str, + conditioning_bundle: Dict[str, Any] | None = None, + controlnet_bundle: Dict[str, Any] | None = None, + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + init_image_path = str((controlnet_bundle or {}).get("init_image_path") or control_image_path).strip() or control_image_path + with Image.open(init_image_path) as image: + width, height = image.size + + if self.comfy_client.is_comfyui_server(): + controlnet_inputs = list((controlnet_bundle or {}).get("inputs") or []) + comfy_mode = str((controlnet_bundle or {}).get("comfy_mode") or "img2img_controlnet").strip().lower() + if controlnet_inputs: + if comfy_mode == "txt2img_controlnet": + base_output_path = self.comfy_client.render_controlnet_txt2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_inputs=controlnet_inputs, + width=width, + height=height, + steps=max(steps, 28), + cfg_scale=cfg_scale, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + else: + base_output_path = self.comfy_client.render_controlnet_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + init_image_path=init_image_path, + control_inputs=controlnet_inputs, + width=width, + height=height, + steps=steps, + cfg_scale=cfg_scale, + denoising_strength=denoising_strength, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + else: + base_output_path = self.comfy_client.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=init_image_path, + width=width, + height=height, + steps=steps, + cfg_scale=cfg_scale, + denoising_strength=denoising_strength, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + else: + payload = { + "init_images": [self._encode_image_to_base64(init_image_path)], + "prompt": prompt, + "negative_prompt": negative_prompt, + "denoising_strength": float(denoising_strength), + "steps": int(steps), + "cfg_scale": float(cfg_scale), + "width": width, + "height": height, + "sampler_name": str(sampler_name or "DPM++ 2M Karras"), + "resize_mode": 0, + } + response = requests.post( + url=f"{self.sd_api_url}/sdapi/v1/img2img", + json=payload, + timeout=180, + ) + response.raise_for_status() + result = response.json() + images = result.get("images") or [] + if not images: + raise RuntimeError("SD sketch backend returned no images") + base_output_path = os.path.join(self.output_dir, f"{filename_prefix}_{abs(hash(prompt + init_image_path))}.png") + with open(base_output_path, "wb") as handle: + handle.write(base64.b64decode(images[0])) + + final_output_path = self._apply_conditioning_passes( + base_image_path=base_output_path, + prompt=prompt, + negative_prompt=negative_prompt, + conditioning_bundle=conditioning_bundle, + steps=steps, + cfg_scale=cfg_scale, + denoising_strength=denoising_strength, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + ) + if controlnet_bundle: + self.last_conditioning_report["controlnet_bundle"] = controlnet_bundle + self.last_conditioning_report["base_image_path"] = base_output_path + self.last_conditioning_report["final_image_path"] = final_output_path + return final_output_path + + def render_txt2img( + self, + *, + prompt: str, + negative_prompt: str, + width: int, + height: int, + steps: int, + cfg_scale: float, + sampler_name: str, + filename_prefix: str, + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> str: + if self.comfy_client.is_comfyui_server(): + return self.comfy_client.render_txt2img( + prompt=prompt, + negative_prompt=negative_prompt, + width=width, + height=height, + steps=steps, + cfg_scale=cfg_scale, + sampler_name=sampler_name, + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + + payload = { + "prompt": prompt, + "negative_prompt": negative_prompt, + "steps": int(steps), + "cfg_scale": float(cfg_scale), + "width": int(width), + "height": int(height), + "sampler_name": str(sampler_name or "DPM++ 2M Karras"), + } + response = requests.post( + url=f"{self.sd_api_url}/sdapi/v1/txt2img", + json=payload, + timeout=180, + ) + response.raise_for_status() + result = response.json() + images = result.get("images") or [] + if not images: + raise RuntimeError("SD image backend returned no images") + output_path = os.path.join(self.output_dir, f"{filename_prefix}_{abs(hash(prompt + negative_prompt))}.png") + with open(output_path, "wb") as handle: + handle.write(base64.b64decode(images[0])) + return output_path + + def render_scene_direct( + self, + *, + scene_spec: Dict[str, Any] | None, + prompt: str, + negative_prompt: str, + sketch_options: Dict[str, Any] | None = None, + filename_prefix: str = "sd_direct_scene", + prior_bundle: Dict[str, Any] | None = None, + controlnet_bundle: Dict[str, Any] | None = None, + checkpoint_name: str = "", + lora_name: str = "", + lora_strength_model: float = 1.0, + lora_strength_clip: float = 1.0, + ) -> Dict[str, Any]: + sketch_options = sketch_options or {} + prior_bundle = prior_bundle if isinstance(prior_bundle, dict) else self.build_direct_scene_prior( + scene_spec=scene_spec, + filename_prefix=filename_prefix, + ) + controlnet_bundle = controlnet_bundle if isinstance(controlnet_bundle, dict) else self.build_direct_scene_controlnet_bundle( + scene_spec=scene_spec, + prior_bundle=prior_bundle, + filename_prefix=filename_prefix, + ) + canvas = prior_bundle.get("canvas_size") if isinstance(prior_bundle.get("canvas_size"), dict) else {} + width = max(512, int(canvas.get("width", 1024) or 1024)) + height = max(384, int(canvas.get("height", 768) or 768)) + scene_type = self._direct_scene_type(scene_spec) + default_denoising = 0.82 if scene_type == "scene" else 0.78 if scene_type == "schematic" else 0.80 + default_steps = 30 if scene_type == "scene" else 36 + default_cfg = 6.2 if scene_type == "scene" else 6.5 if scene_type == "schematic" else 6.4 + + if controlnet_bundle.get("inputs"): + image_path = self.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=str(controlnet_bundle.get("init_image_path") or prior_bundle.get("base_plate_path") or prior_bundle.get("layout_control_path") or ""), + denoising_strength=float(sketch_options.get("sd_direct_denoising", default_denoising)), + steps=int(sketch_options.get("sd_direct_steps", sketch_options.get("sd_sketch_steps", default_steps))), + cfg_scale=float(sketch_options.get("sd_direct_cfg_scale", sketch_options.get("sd_sketch_cfg_scale", default_cfg))), + sampler_name=str(sketch_options.get("sd_direct_sampler_name", sketch_options.get("sd_sketch_sampler_name", "DPM++ 2M Karras"))), + filename_prefix=filename_prefix, + controlnet_bundle=controlnet_bundle, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + else: + image_path = self.render_txt2img( + prompt=prompt, + negative_prompt=negative_prompt, + width=width, + height=height, + steps=int(sketch_options.get("sd_direct_steps", sketch_options.get("sd_sketch_steps", 30))), + cfg_scale=float(sketch_options.get("sd_direct_cfg_scale", sketch_options.get("sd_sketch_cfg_scale", 6.6))), + sampler_name=str(sketch_options.get("sd_direct_sampler_name", sketch_options.get("sd_sketch_sampler_name", "DPM++ 2M Karras"))), + filename_prefix=filename_prefix, + checkpoint_name=checkpoint_name, + lora_name=lora_name, + lora_strength_model=lora_strength_model, + lora_strength_clip=lora_strength_clip, + ) + + return { + "image_path": image_path, + "prior_bundle": prior_bundle, + "controlnet_bundle": controlnet_bundle, + } + + def render_from_preview( + self, + preview: Dict[str, Any], + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + ) -> Dict[str, Any]: + preview = dict(preview or {}) + sketch_options = sketch_options or {} + + if not self.available: + return self._fallback_preview(preview, "SD sketch backend is not configured; falling back to native sketch.") + + control_image_path = self._control_image_path(preview) + if not control_image_path: + return self._fallback_preview(preview, "SD sketch backend has no usable control image; falling back to native sketch.") + + prompt = self._build_prompt(preview.get("scene_spec"), sketch_options, title=title) + negative_prompt = self._build_negative_prompt(str(sketch_options.get("sketch_style", "line_art"))) + controlnet_bundle = self.build_controlnet_bundle( + control_image_path=control_image_path, + scene_spec=preview.get("scene_spec"), + filename_prefix="sd_sketch_preview", + purpose="sketch_candidate", + ) + + try: + output_path = self.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_image_path, + denoising_strength=float(sketch_options.get("sd_sketch_denoising", 0.42)), + steps=int(sketch_options.get("sd_sketch_steps", 20)), + cfg_scale=float(sketch_options.get("sd_sketch_cfg_scale", 6.5)), + sampler_name=str(sketch_options.get("sd_sketch_sampler_name", "DPM++ 2M Karras")), + filename_prefix="sd_sketch", + controlnet_bundle=controlnet_bundle, + ) + except Exception as exc: + logger.error(f"SD sketch generation failed: {exc}") + return self._fallback_preview(preview, f"SD sketch generation failed, falling back to native sketch: {exc}") + + payload = dict(preview) + sketch_bundle = dict(payload.get("sketch_bundle") or {}) + native_structural = sketch_bundle.get("structural_sketch") or payload.get("image_path") + if native_structural: + sketch_bundle["native_structural_sketch"] = native_structural + sketch_bundle["structural_sketch"] = output_path + sketch_bundle["sd_sketch"] = output_path + sketch_bundle["active_sketch_backend"] = "sd" + + payload["image_path"] = output_path + payload["save_path"] = output_path + payload["sd_sketch_path"] = output_path + payload["backend"] = "comfyui_sketch_preview" if self.comfy_client.is_comfyui_server() else "sd_sketch_preview" + payload["sketch_backend"] = "sd" + payload["generated_prompt"] = prompt + payload["negative_prompt"] = negative_prompt + payload["sketch_bundle"] = sketch_bundle + logger.info(f"SD sketch generation succeeded: {output_path}") + return payload diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene.py new file mode 100644 index 0000000..0384f08 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene.py @@ -0,0 +1,1436 @@ +from __future__ import annotations + +import json +import re +from typing import Any, Dict, Iterable, List, Tuple + +from .visual_prototypes import fallback_prototype_id, resolve_visual_prototype + + +CANVAS_DEFAULT = (1024, 768) + + +ASSET_LIBRARY: Dict[str, Dict[str, Any]] = { + "generic_object": { + "label": "通用对象", + "category": "通用", + "silhouette_key": "generic_object", + "default_size": (152, 132), + "keywords": [], + "anchors": ["center", "top", "bottom", "left", "right"], + "editor_visible": True, + }, + "generic_panel": { + "label": "通用面板", + "category": "通用", + "silhouette_key": "generic_panel", + "default_size": (180, 120), + "keywords": [], + "anchors": ["center", "top", "bottom"], + "editor_visible": True, + }, + "generic_circle": { + "label": "通用圆形", + "category": "通用", + "silhouette_key": "generic_circle", + "default_size": (120, 120), + "keywords": [], + "anchors": ["center"], + "editor_visible": True, + }, + "blob": { + "label": "语义团块", + "category": "兜底", + "silhouette_key": "blob", + "default_size": (168, 128), + "keywords": [], + "anchors": ["center"], + "editor_visible": True, + }, + "tower": { + "label": "高塔体", + "category": "兜底", + "silhouette_key": "tower", + "default_size": (180, 260), + "keywords": [], + "anchors": ["facade", "roof", "ground", "center"], + "editor_visible": True, + }, + "capsule": { + "label": "过程胶囊", + "category": "兜底", + "silhouette_key": "capsule", + "default_size": (172, 116), + "keywords": [], + "anchors": ["center", "left", "right"], + "editor_visible": True, + }, + "branch": { + "label": "分支母题", + "category": "兜底", + "silhouette_key": "branch", + "default_size": (180, 140), + "keywords": [], + "anchors": ["center"], + "editor_visible": True, + }, + "module": { + "label": "功能模块", + "category": "兜底", + "silhouette_key": "module", + "default_size": (180, 120), + "keywords": [], + "anchors": ["left", "right", "center"], + "editor_visible": True, + }, + "building": { + "label": "楼体", + "category": "建筑", + "silhouette_key": "building", + "default_size": (240, 280), + "keywords": ["楼", "楼房", "建筑", "大楼", "高楼", "工厂", "教学楼", "公寓"], + "anchors": ["facade", "roof", "ground", "center"], + "editor_visible": True, + }, + "house": { + "label": "房子", + "category": "建筑", + "silhouette_key": "house", + "default_size": (220, 220), + "keywords": ["房子", "房屋", "小屋", "住宅", "家"], + "anchors": ["facade", "roof", "ground", "center"], + "editor_visible": True, + }, + "window": { + "label": "窗户", + "category": "建筑", + "silhouette_key": "window", + "default_size": (72, 72), + "keywords": ["窗", "窗户", "玻璃窗"], + "anchors": ["facade", "center"], + "editor_visible": True, + }, + "door": { + "label": "门", + "category": "建筑", + "silhouette_key": "door", + "default_size": (72, 124), + "keywords": ["门", "大门", "房门"], + "anchors": ["facade", "ground", "center"], + "editor_visible": True, + }, + "tree": { + "label": "树", + "category": "自然", + "silhouette_key": "tree", + "default_size": (180, 220), + "keywords": ["树", "树林", "树木"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "cloud": { + "label": "云", + "category": "自然", + "silhouette_key": "cloud", + "default_size": (150, 90), + "keywords": ["云", "云朵", "乌云"], + "anchors": ["sky", "center"], + "editor_visible": True, + }, + "sun": { + "label": "太阳", + "category": "自然", + "silhouette_key": "sun", + "default_size": (110, 110), + "keywords": ["太阳", "阳光", "日光"], + "anchors": ["sky", "center"], + "editor_visible": True, + }, + "car": { + "label": "车", + "category": "交通", + "silhouette_key": "car", + "default_size": (170, 92), + "keywords": ["车", "汽车", "轿车", "卡车"], + "anchors": ["road", "ground", "center"], + "editor_visible": True, + }, + "road": { + "label": "道路", + "category": "交通", + "silhouette_key": "road", + "default_size": (320, 96), + "keywords": ["路", "道路", "公路", "街道"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "person": { + "label": "人物", + "category": "角色", + "silhouette_key": "person", + "default_size": (96, 172), + "keywords": ["人", "人物", "学生", "工人", "孩子", "成人"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "street_lamp": { + "label": "路灯", + "category": "城市", + "silhouette_key": "street_lamp", + "default_size": (72, 220), + "keywords": ["路灯", "灯杆", "街灯"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "table": { + "label": "桌子", + "category": "室内", + "silhouette_key": "table", + "default_size": (180, 116), + "keywords": ["桌", "桌子", "课桌", "餐桌"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "chair": { + "label": "椅子", + "category": "室内", + "silhouette_key": "chair", + "default_size": (96, 138), + "keywords": ["椅", "椅子", "凳子"], + "anchors": ["ground", "center"], + "editor_visible": True, + }, + "battery": { + "label": "电池", + "category": "自动科技", + "silhouette_key": "battery", + "default_size": (120, 80), + "keywords": ["电池", "电源", "供电"], + "anchors": ["left", "right", "center"], + "editor_visible": False, + }, + "led": { + "label": "LED", + "category": "自动科技", + "silhouette_key": "led", + "default_size": (104, 92), + "keywords": ["led", "发光二极管", "灯泡"], + "anchors": ["left", "right", "center"], + "editor_visible": False, + }, + "resistor": { + "label": "电阻", + "category": "自动科技", + "silhouette_key": "resistor", + "default_size": (120, 62), + "keywords": ["电阻", "电阻器"], + "anchors": ["left", "right", "center"], + "editor_visible": False, + }, + "capacitor": { + "label": "电容", + "category": "自动科技", + "silhouette_key": "capacitor", + "default_size": (92, 88), + "keywords": ["电容", "电容器"], + "anchors": ["left", "right", "center"], + "editor_visible": False, + }, + "diode": { + "label": "二极管", + "category": "自动科技", + "silhouette_key": "diode", + "default_size": (112, 72), + "keywords": ["二极管", "整流管"], + "anchors": ["left", "right", "center"], + "editor_visible": False, + }, + "board": { + "label": "电路板", + "category": "自动科技", + "silhouette_key": "board", + "default_size": (200, 140), + "keywords": ["arduino", "电路板", "开发板", "主板"], + "anchors": ["center"], + "editor_visible": False, + }, + "airplane": { + "label": "飞机", + "category": "自动科技", + "silhouette_key": "airplane", + "default_size": (220, 140), + "keywords": ["飞机", "机翼", "飞行器"], + "anchors": ["sky", "center"], + "editor_visible": False, + }, + "leaf": { + "label": "叶片", + "category": "自动科技", + "silhouette_key": "leaf", + "default_size": (132, 92), + "keywords": ["叶片", "叶子", "树叶"], + "anchors": ["center"], + "editor_visible": False, + }, + "raindrop": { + "label": "雨滴", + "category": "自动科技", + "silhouette_key": "raindrop", + "default_size": (72, 96), + "keywords": ["雨滴", "水滴"], + "anchors": ["sky", "center"], + "editor_visible": False, + }, + "cell": { + "label": "细胞", + "category": "自动科技", + "silhouette_key": "cell", + "default_size": (140, 140), + "keywords": ["细胞"], + "anchors": ["center"], + "editor_visible": False, + }, +} + + +EDITOR_LIBRARY_ORDER = [ + "building", + "house", + "window", + "door", + "tree", + "cloud", + "sun", + "car", + "road", + "person", + "street_lamp", + "table", + "chair", + "battery", + "led", + "resistor", + "capacitor", + "diode", + "board", + "airplane", + "leaf", + "raindrop", + "cell", + "tower", + "capsule", + "branch", + "module", + "blob", + "generic_object", + "generic_panel", + "generic_circle", +] + + +SCHEMATIC_TOKENS = { + "led", + "电路", + "电阻", + "电容", + "二极管", + "三极管", + "arduino", + "电池", + "导线", + "串联", + "并联", + "电流", + "电压", +} + + +SCENE_TOKENS = { + "场景", + "图片", + "画面", + "草图", + "房子", + "楼", + "树", + "云", + "太阳", + "路", + "车", + "人物", + "街道", +} + + +PROCESS_TOKENS = {"为什么", "解释", "原理", "过程", "机制", "如何", "怎么", "因果"} + + +def _deep_copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _clean_text(value: Any) -> str: + return str(value or "").strip() + + +def _slugify(text: str) -> str: + stripped = re.sub(r"\s+", "_", _clean_text(text).lower()) + stripped = re.sub(r"[^0-9a-z_\u4e00-\u9fff]+", "", stripped) + return stripped or "item" + + +def get_asset_definition(asset_key: str) -> Dict[str, Any]: + return ASSET_LIBRARY.get(asset_key, ASSET_LIBRARY["generic_object"]) + + +ATTACHMENT_COMPATIBILITY: Dict[str, List[str]] = { + "window": ["building", "house", "tower"], + "door": ["building", "house", "tower"], + "cloud": ["bg_sky"], + "sun": ["bg_sky"], + "car": ["road"], + "chair": ["table"], + "street_lamp": ["road", "building", "house"], +} + + +def build_editor_asset_library() -> List[Dict[str, Any]]: + grouped: Dict[str, List[Dict[str, Any]]] = {} + for asset_key in EDITOR_LIBRARY_ORDER: + asset = get_asset_definition(asset_key) + category = asset.get("category", "其他") + grouped.setdefault(category, []).append( + { + "asset_key": asset_key, + "label": asset.get("label", asset_key), + "silhouette_key": asset.get("silhouette_key", asset_key), + "default_width": asset.get("default_size", (120, 120))[0], + "default_height": asset.get("default_size", (120, 120))[1], + "anchors": asset.get("anchors", []), + } + ) + return [{"category": category, "items": items} for category, items in grouped.items()] + + +def pick_asset_key(concept: str, scene_type: str = "scene") -> str: + concept_text = _clean_text(concept) + lowered = concept_text.lower() + for asset_key, asset in ASSET_LIBRARY.items(): + for keyword in asset.get("keywords", []): + if keyword and keyword.lower() in lowered: + return asset_key + if scene_type == "schematic": + if any(token in lowered for token in ("电流", "电压", "导电", "功率", "效率")): + return "generic_panel" + return "generic_object" + if scene_type == "process" and any(token in concept_text for token in ("作用", "过程", "机制", "功能", "能力")): + return "generic_panel" + return "generic_object" + + +def infer_scene_type( + query: str, + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> str: + query_text = _clean_text(query) + joined_parts = [query_text] + for source in (understanding_result or {}, extraction_result or {}, answer_bundle or {}): + joined_parts.append(json.dumps(source, ensure_ascii=False)) + haystack = " ".join(joined_parts).lower() + if any(token.lower() in haystack for token in SCHEMATIC_TOKENS): + return "schematic" + if any(token.lower() in haystack for token in SCENE_TOKENS) and not any(token in query_text for token in PROCESS_TOKENS): + return "scene" + if any(token in query_text for token in PROCESS_TOKENS): + return "process" + return "scene" + + +def _collect_concepts( + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, + best_path_concepts: List[str] | None, +) -> tuple[List[str], Dict[str, str], Dict[str, float]]: + ordered: List[str] = [] + concept_types: Dict[str, str] = {} + importance: Dict[str, float] = {} + + def push(concept: str, concept_type: str = "general", delta: float = 1.0) -> None: + name = _clean_text(concept) + if not name: + return + if name not in ordered: + ordered.append(name) + if concept_type and name not in concept_types: + concept_types[name] = concept_type + importance[name] = importance.get(name, 0.0) + delta + + focus = _clean_text((answer_bundle or {}).get("focus_concept") or (understanding_result or {}).get("focus_concept")) + if focus: + push(focus, "focus", 4.0) + + for concept in best_path_concepts or []: + push(concept, "path", 2.8) + + for item in (extraction_result or {}).get("concepts", []) or []: + push(item.get("concept", ""), item.get("type", "general"), 1.3) + + for item in (understanding_result or {}).get("concepts", []) or []: + push(item.get("concept", ""), item.get("type", "general"), 1.0) + + for relation in (answer_bundle or {}).get("primary_chain", []) or []: + push(relation.get("from", ""), "relation", 2.2) + push(relation.get("to", ""), "relation", 2.2) + + for relation in (answer_bundle or {}).get("supporting_relations", []) or []: + push(relation.get("from", ""), "support", 1.0) + push(relation.get("to", ""), "support", 1.0) + + return ordered, concept_types, importance + + +def _collect_relations( + answer_bundle: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, +) -> List[Dict[str, Any]]: + merged: List[Dict[str, Any]] = [] + seen = set() + for group in ( + (answer_bundle or {}).get("primary_chain", []) or [], + (answer_bundle or {}).get("supporting_relations", []) or [], + (extraction_result or {}).get("relations", []) or [], + ): + for relation in group: + src = _clean_text(relation.get("from")) + dst = _clean_text(relation.get("to")) + label = _clean_text(relation.get("relation")) + if not src or not dst or not label: + continue + key = (src, dst, label) + if key in seen: + continue + seen.add(key) + merged.append( + { + "from": src, + "to": dst, + "relation": label, + "weight": float(relation.get("weight", 0.5) or 0.5), + "source": relation.get("source", "evidence"), + } + ) + return merged + + +def _make_id(prefix: str, label: str, index: int) -> str: + return f"{prefix}_{index}_{_slugify(label)}" + + +def _build_background_layer( + layer_id: str, + layer_type: str, + label: str, + x: int, + y: int, + width: int, + height: int, + z_index: int, + source: str = "auto", +) -> Dict[str, Any]: + return { + "id": layer_id, + "type": layer_type, + "label": label, + "x": int(x), + "y": int(y), + "width": int(width), + "height": int(height), + "z_index": int(z_index), + "source": source, + } + + +def _build_object_instance( + object_id: str, + concept: str, + asset_key: str, + role: str, + depth_band: str, + x: float, + y: float, + width: float, + height: float, + z_index: int, + source: str = "auto", + rotation: float = 0.0, + scale: float = 1.0, + editable: bool = True, + visible: bool = True, + depth_z: float | None = None, +) -> Dict[str, Any]: + asset = get_asset_definition(asset_key) + return { + "id": object_id, + "concept": _clean_text(concept), + "asset_key": asset_key, + "source": source, + "role": role, + "depth_band": depth_band, + "x": int(round(x)), + "y": int(round(y)), + "width": int(round(width)), + "height": int(round(height)), + "rotation": float(rotation), + "scale": float(scale), + "silhouette_key": asset.get("silhouette_key", asset_key), + "z_index": int(z_index), + "editable": bool(editable), + "visible": bool(visible), + "depth_z": float(depth_z) if depth_z is not None else { + "background": 0.18, + "midground": 0.52, + "foreground": 0.84, + }.get(depth_band, 0.52), + } + + +def _connector_type(label: str, scene_type: str) -> str: + text = _clean_text(label) + if any(keyword in text for keyword in ("光", "照射", "发射", "辐射")): + return "beam" + if scene_type == "schematic" or any(keyword in text for keyword in ("连接", "串联", "并联", "导通", "供电")): + return "wire" + if any(keyword in text for keyword in ("导致", "推动", "产生", "影响", "驱动", "引发", "减少", "增加", "支持")): + return "arrow" + return "relation" + + +def _build_connector( + connector_id: str, + from_id: str, + to_id: str, + label: str, + scene_type: str, + visible: bool = True, +) -> Dict[str, Any]: + return { + "id": connector_id, + "type": _connector_type(label, scene_type), + "from_id": from_id, + "to_id": to_id, + "label": _clean_text(label), + "visible": bool(visible), + } + + +def _build_attachment(attachment_id: str, host_id: str, child_id: str, anchor_name: str, mode: str = "attach") -> Dict[str, Any]: + return { + "id": attachment_id, + "host_id": host_id, + "child_id": child_id, + "anchor_name": anchor_name, + "mode": mode, + } + + +def _build_scene_shell(canvas_size: Tuple[int, int], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + sketch_options = sketch_options or {} + width = max(512, int(canvas_size[0])) + height = max(384, int(canvas_size[1])) + return { + "version": 2, + "canvas_size": {"width": width, "height": height}, + "layout_options": { + "mode": "semantic_composition", + "sketch_style": sketch_options.get("sketch_style", "line_art"), + "show_grid": bool(sketch_options.get("show_grid", True)), + "show_labels": bool(sketch_options.get("show_labels", True)), + "show_guides": bool(sketch_options.get("show_guides", True)), + "node_scale": float(sketch_options.get("node_scale", 1.0)), + "spacing_scale": float(sketch_options.get("spacing_scale", 1.0)), + }, + "background_layers": [], + "object_instances": [], + "attachments": [], + "connectors": [], + "render_hints": {}, + "concept_order": [], + } + + +def _render_hints_for_scene(scene: Dict[str, Any], scene_type: str) -> Dict[str, str]: + objects = scene.get("object_instances", []) or [] + backgrounds = scene.get("background_layers", []) or [] + subjects = [item["concept"] for item in objects if item.get("role") in {"subject", "focus", "core_subject"}][:3] + user_items = [item["concept"] for item in objects if item.get("source") == "user"][:6] + bg_labels = [item["label"] for item in backgrounds][:4] + connectors = [item["label"] for item in scene.get("connectors", []) if item.get("visible")][:4] + style_name = scene.get("layout_options", {}).get("sketch_style", "line_art") + return { + "scene_summary": "、".join(subjects) + (" 场景草图" if subjects else "语义构图草图"), + "subject_summary": "主体: " + ("、".join(subjects) if subjects else "未显式主体"), + "style_summary": f"风格: {style_name} | 类型: {scene_type}", + "preview_summary": "背景: " + ("、".join(bg_labels) if bg_labels else "无") + " | 关系: " + ("、".join(connectors) if connectors else "弱化显示"), + "user_added_summary": "用户新增: " + ("、".join(user_items) if user_items else "无"), + } + + +def _outdoor_backgrounds(width: int, height: int, include_road: bool = False, include_water: bool = False) -> List[Dict[str, Any]]: + layers = [ + _build_background_layer("bg_sky", "sky", "天空", 0, 0, width, int(height * 0.58), -30), + ] + ground_label = "水面" if include_water else "地面" + ground_type = "water" if include_water else "ground" + layers.append(_build_background_layer("bg_ground", ground_type, ground_label, 0, int(height * 0.58), width, int(height * 0.42), -20)) + if include_road: + road_height = max(72, int(height * 0.16)) + layers.append(_build_background_layer("bg_road", "road", "道路", 0, height - road_height, width, road_height, -10)) + return layers + + +def _compose_scene_layout( + query: str, + concept_names: List[str], + concept_types: Dict[str, str], + importance: Dict[str, float], + relations: List[Dict[str, Any]], + focus_concept: str, + canvas_size: Tuple[int, int], + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + scene = _build_scene_shell(canvas_size, sketch_options) + width = scene["canvas_size"]["width"] + height = scene["canvas_size"]["height"] + indoor_mode = any(token in query for token in ("室内", "房间")) or any( + pick_asset_key(name, "scene") in {"table", "chair", "desk_lamp"} for name in concept_names + ) + include_road = any(pick_asset_key(name) == "car" or "路" in name for name in concept_names) + include_water = any("水" in name for name in concept_names) + if indoor_mode: + scene["background_layers"] = [ + _build_background_layer("bg_wall", "wall", "墙面", 0, 0, width, int(height * 0.64), -30), + _build_background_layer("bg_floor", "ground", "地面", 0, int(height * 0.64), width, int(height * 0.36), -20), + ] + else: + scene["background_layers"] = _outdoor_backgrounds(width, height, include_road=include_road, include_water=include_water) + + ranked = sorted(concept_names, key=lambda name: (-importance.get(name, 0.0), concept_names.index(name))) + subject = focus_concept if focus_concept in concept_names else (ranked[0] if ranked else "") + if indoor_mode: + table_subject = next((name for name in ranked if pick_asset_key(name, "scene") == "table"), "") + if table_subject: + subject = table_subject + if pick_asset_key(subject) in {"window", "door", "cloud", "sun"} and len(ranked) > 1: + subject = ranked[1] + + subject_id = "" + if subject: + asset_key = pick_asset_key(subject, "scene") + default_w, default_h = get_asset_definition(asset_key).get("default_size", (180, 180)) + subject_x = width * 0.37 + subject_y = height * 0.34 + subject_w = default_w * 1.15 + subject_h = default_h * 1.15 + if indoor_mode and asset_key == "table": + subject_x = width * 0.28 + subject_y = height * 0.5 + subject_w = min(width * 0.42, default_w * 1.35) + subject_h = min(height * 0.26, default_h * 1.15) + scene["object_instances"].append( + _build_object_instance( + "obj_subject", + subject, + asset_key, + "subject", + "midground", + subject_x, + subject_y, + subject_w, + subject_h, + 30, + ) + ) + subject_id = "obj_subject" + + side_toggle = 0 + detail_index = 0 + for concept in ranked: + if concept == subject: + continue + asset_key = pick_asset_key(concept, "scene") + default_w, default_h = get_asset_definition(asset_key).get("default_size", (120, 120)) + if indoor_mode and asset_key in {"chair", "desk_lamp"} and subject_id and pick_asset_key(subject, "scene") == "table": + host = next((item for item in scene["object_instances"] if item["id"] == subject_id), None) + if host: + child_id = _make_id("obj", concept, detail_index + 1) + if asset_key == "chair": + child_w = min(default_w, host["width"] * 0.34) + child_h = min(default_h, host["height"] * 1.26) + child_x = host["x"] - child_w * (0.58 if detail_index % 2 == 0 else -1.08) + child_y = host["y"] - host["height"] * 0.1 + anchor = "center" + role_name = "support" + else: + child_w = min(default_w, host["width"] * 0.24) + child_h = min(default_h, max(84, host["height"] * 0.96)) + child_x = host["x"] + host["width"] * 0.58 + child_y = host["y"] - child_h * 0.42 + anchor = "center" + role_name = "detail" + scene["object_instances"].append( + _build_object_instance(child_id, concept, asset_key, role_name, "midground", child_x, child_y, child_w, child_h, 36) + ) + scene["attachments"].append(_build_attachment(_make_id("att", concept, detail_index + 1), host["id"], child_id, anchor)) + detail_index += 1 + continue + if asset_key in {"window", "door"} and subject_id and pick_asset_key(subject, "scene") in {"building", "house"}: + host = next((item for item in scene["object_instances"] if item["id"] == subject_id), None) + if not host: + continue + child_id = _make_id("obj", concept, detail_index + 1) + child_w = min(default_w, host["width"] * 0.22) + child_h = min(default_h, host["height"] * (0.26 if asset_key == "door" else 0.18)) + child_x = host["x"] + host["width"] * (0.2 + 0.22 * (detail_index % 3)) + child_y = host["y"] + host["height"] * (0.2 + 0.2 * (detail_index // 3)) + anchor = "facade" + if asset_key == "door": + child_y = host["y"] + host["height"] - child_h - 6 + anchor = "ground" + scene["object_instances"].append( + _build_object_instance(child_id, concept, asset_key, "detail", "midground", child_x, child_y, child_w, child_h, 36) + ) + scene["attachments"].append(_build_attachment(_make_id("att", concept, detail_index + 1), host["id"], child_id, anchor)) + detail_index += 1 + continue + + depth_band = "background" + role = "environment" + z_index = 12 + x = width * (0.08 if side_toggle % 2 == 0 else 0.68) + y = height * (0.4 if side_toggle % 2 == 0 else 0.46) + scale = 0.84 + if asset_key in {"cloud", "sun"}: + depth_band = "background" + role = "effect" + z_index = 4 + y = height * 0.1 + x = width * (0.12 + 0.2 * (side_toggle % 4)) + scale = 0.8 + elif asset_key in {"tree", "person", "street_lamp", "car"}: + depth_band = "foreground" + role = "support" + z_index = 42 + y = height * 0.56 + scale = 0.95 + elif asset_key == "dog": + depth_band = "foreground" + role = "support" + z_index = 40 + y = height * 0.62 + scale = 0.96 + elif asset_key in {"building", "house"}: + depth_band = "background" + role = "support" + z_index = 18 + y = height * 0.24 + scale = 0.9 + elif asset_key == "road": + depth_band = "foreground" + role = "support" + z_index = 8 + y = height * 0.8 + scale = 1.0 + elif indoor_mode and asset_key == "table": + depth_band = "midground" + role = "support" + z_index = 28 + x = width * 0.58 + y = height * 0.52 + scale = 1.05 + + object_id = _make_id("obj", concept, side_toggle + 1) + object_width = default_w * scale + object_height = default_h * scale + scene["object_instances"].append( + _build_object_instance(object_id, concept, asset_key, role, depth_band, x, y, object_width, object_height, z_index) + ) + side_toggle += 1 + + object_by_concept = {item["concept"]: item for item in scene["object_instances"]} + for index, relation in enumerate(relations[:8], start=1): + from_obj = object_by_concept.get(relation["from"]) + to_obj = object_by_concept.get(relation["to"]) + if not from_obj or not to_obj: + continue + connector = _build_connector( + _make_id("conn", relation["relation"], index), + from_obj["id"], + to_obj["id"], + relation["relation"], + "scene", + visible=_connector_type(relation["relation"], "scene") in {"beam", "arrow"}, + ) + if connector["visible"]: + scene["connectors"].append(connector) + + scene["concept_order"] = [item["concept"] for item in scene["object_instances"]] + scene["render_hints"] = _render_hints_for_scene(scene, "scene") + scene["layout_options"]["scene_type"] = "scene" + return scene + + +def _compose_process_layout( + concept_names: List[str], + importance: Dict[str, float], + relations: List[Dict[str, Any]], + focus_concept: str, + canvas_size: Tuple[int, int], + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + scene = _build_scene_shell(canvas_size, sketch_options) + width = scene["canvas_size"]["width"] + height = scene["canvas_size"]["height"] + panel_width = width // 3 + scene["background_layers"] = [ + _build_background_layer("panel_input", "panel", "输入", 0, 92, panel_width, height - 132, -20), + _build_background_layer("panel_process", "panel", "过程", panel_width, 92, panel_width, height - 132, -19), + _build_background_layer("panel_output", "panel", "结果", panel_width * 2, 92, width - panel_width * 2, height - 132, -18), + ] + + ordered = concept_names[:6] + if focus_concept and focus_concept in ordered: + ordered = [focus_concept] + [item for item in ordered if item != focus_concept] + if not ordered and relations: + ordered = [relations[0]["from"], relations[0]["to"]] + + x_positions = [width * 0.12, width * 0.4, width * 0.72] + y_base = [height * 0.32, height * 0.5] + + object_by_concept: Dict[str, Dict[str, Any]] = {} + for index, concept in enumerate(ordered): + asset_key = pick_asset_key(concept, "process") + if asset_key == "generic_object": + asset_key = "generic_panel" + default_w, default_h = get_asset_definition(asset_key).get("default_size", (180, 120)) + importance_scale = 0.9 + min(0.45, importance.get(concept, 1.0) * 0.05) + column = min(2, index // 2) + row = index % 2 + role = "subject" if concept == focus_concept else ("stage" if column == 1 else "support") + object_id = _make_id("obj", concept, index + 1) + obj = _build_object_instance( + object_id, + concept, + asset_key, + role, + "midground", + x_positions[column] - (default_w * importance_scale) / 2, + y_base[row] - (default_h * importance_scale) / 2, + default_w * importance_scale, + default_h * importance_scale, + 25 + column, + ) + scene["object_instances"].append(obj) + object_by_concept[concept] = obj + + for index, relation in enumerate(relations[:10], start=1): + from_obj = object_by_concept.get(relation["from"]) + to_obj = object_by_concept.get(relation["to"]) + if not from_obj or not to_obj: + continue + scene["connectors"].append( + _build_connector(_make_id("conn", relation["relation"], index), from_obj["id"], to_obj["id"], relation["relation"], "process", visible=True) + ) + + scene["concept_order"] = [item["concept"] for item in scene["object_instances"]] + scene["render_hints"] = _render_hints_for_scene(scene, "process") + scene["layout_options"]["scene_type"] = "process" + return scene + + +def _compose_schematic_layout( + concept_names: List[str], + importance: Dict[str, float], + relations: List[Dict[str, Any]], + focus_concept: str, + canvas_size: Tuple[int, int], + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + scene = _build_scene_shell(canvas_size, sketch_options) + width = scene["canvas_size"]["width"] + height = scene["canvas_size"]["height"] + scene["background_layers"] = [ + _build_background_layer("board_layer", "board", "电路画板", 18, 72, width - 36, height - 110, -18), + ] + + ordered = concept_names[:8] + if focus_concept and focus_concept in ordered: + ordered = [focus_concept] + [item for item in ordered if item != focus_concept] + if not ordered and relations: + ordered = [relations[0]["from"], relations[0]["to"]] + if not ordered: + ordered = ["电路", "信号", "输出"] + + cell_concept = next((name for name in ordered if pick_asset_key(name, "schematic") == "cell"), "") + if cell_concept: + object_by_concept: Dict[str, Dict[str, Any]] = {} + cell_w = width * 0.42 + cell_h = height * 0.46 + cell_x = width * 0.29 + cell_y = height * 0.24 + cell_obj = _build_object_instance("obj_cell", cell_concept, "cell", "subject", "midground", cell_x, cell_y, cell_w, cell_h, 30) + scene["object_instances"].append(cell_obj) + object_by_concept[cell_concept] = cell_obj + + ring_added = False + for index, concept in enumerate(ordered, start=1): + if concept == cell_concept: + continue + asset_key = pick_asset_key(concept, "schematic") + object_id = _make_id("obj", concept, index) + if "膜" in concept: + membrane = _build_object_instance( + object_id, + concept, + "generic_circle", + "detail", + "midground", + cell_x + cell_w * 0.05, + cell_y + cell_h * 0.06, + cell_w * 0.9, + cell_h * 0.86, + 31, + ) + scene["object_instances"].append(membrane) + scene["attachments"].append(_build_attachment(_make_id("att", concept, index), cell_obj["id"], object_id, "center")) + object_by_concept[concept] = membrane + ring_added = True + continue + if "核" in concept: + nucleus = _build_object_instance( + object_id, + concept, + "generic_circle", + "detail", + "midground", + cell_x + cell_w * 0.4, + cell_y + cell_h * 0.34, + cell_w * 0.18, + cell_h * 0.18, + 34, + ) + scene["object_instances"].append(nucleus) + scene["attachments"].append(_build_attachment(_make_id("att", concept, index), cell_obj["id"], object_id, "center")) + object_by_concept[concept] = nucleus + continue + if "质" in concept: + cytoplasm = _build_object_instance( + object_id, + concept, + "generic_circle", + "support", + "midground", + cell_x + cell_w * 0.22, + cell_y + cell_h * 0.25, + cell_w * 0.56, + cell_h * 0.4, + 32, + ) + scene["object_instances"].append(cytoplasm) + scene["attachments"].append(_build_attachment(_make_id("att", concept, index), cell_obj["id"], object_id, "center")) + object_by_concept[concept] = cytoplasm + continue + + default_w, default_h = get_asset_definition(asset_key).get("default_size", (140, 90)) + side = -1 if index % 2 == 0 else 1 + x = width * (0.08 if side < 0 else 0.7) + y = height * (0.22 + 0.18 * ((index - 1) % 3)) + obj = _build_object_instance( + object_id, + concept, + asset_key, + "component", + "midground", + x, + y, + default_w * 0.95, + default_h * 0.95, + 25, + ) + scene["object_instances"].append(obj) + object_by_concept[concept] = obj + scene["connectors"].append( + _build_connector(_make_id("conn", concept, index), obj["id"], cell_obj["id"], "关联", "schematic", visible=True) + ) + + if not ring_added: + membrane = _build_object_instance( + "obj_cell_membrane", + "细胞膜", + "generic_circle", + "detail", + "midground", + cell_x + cell_w * 0.05, + cell_y + cell_h * 0.06, + cell_w * 0.9, + cell_h * 0.86, + 31, + ) + scene["object_instances"].append(membrane) + scene["attachments"].append(_build_attachment("att_cell_membrane", cell_obj["id"], membrane["id"], "center")) + object_by_concept["细胞膜"] = membrane + + for index, relation in enumerate(relations[:12], start=1): + from_obj = object_by_concept.get(relation["from"]) + to_obj = object_by_concept.get(relation["to"]) + if not from_obj or not to_obj: + continue + scene["connectors"].append( + _build_connector(_make_id("conn", relation["relation"], index), from_obj["id"], to_obj["id"], relation["relation"], "schematic", visible=True) + ) + + scene["concept_order"] = [item["concept"] for item in scene["object_instances"]] + scene["render_hints"] = _render_hints_for_scene(scene, "schematic") + scene["layout_options"]["scene_type"] = "schematic" + return scene + + gap = max(110, int((width - 160) / max(1, len(ordered) - 1))) + object_by_concept: Dict[str, Dict[str, Any]] = {} + y = height * 0.5 + for index, concept in enumerate(ordered): + asset_key = pick_asset_key(concept, "schematic") + default_w, default_h = get_asset_definition(asset_key).get("default_size", (140, 90)) + importance_scale = 0.85 + min(0.4, importance.get(concept, 1.0) * 0.04) + x = 80 + gap * index + role = "subject" if concept == focus_concept else "component" + object_id = _make_id("obj", concept, index + 1) + obj = _build_object_instance( + object_id, + concept, + asset_key, + role, + "midground", + x - (default_w * importance_scale) / 2, + y - (default_h * importance_scale) / 2, + default_w * importance_scale, + default_h * importance_scale, + 28 + index, + ) + scene["object_instances"].append(obj) + object_by_concept[concept] = obj + + for index, relation in enumerate(relations[:12], start=1): + from_obj = object_by_concept.get(relation["from"]) + to_obj = object_by_concept.get(relation["to"]) + if not from_obj or not to_obj: + continue + scene["connectors"].append( + _build_connector(_make_id("conn", relation["relation"], index), from_obj["id"], to_obj["id"], relation["relation"], "schematic", visible=True) + ) + + scene["concept_order"] = [item["concept"] for item in scene["object_instances"]] + scene["render_hints"] = _render_hints_for_scene(scene, "schematic") + scene["layout_options"]["scene_type"] = "schematic" + return scene + + +def compose_semantic_scene_spec( + query: str, + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, + best_path_concepts: List[str] | None = None, + canvas_size: Tuple[int, int] = CANVAS_DEFAULT, + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + scene_type = infer_scene_type(query, understanding_result, extraction_result, answer_bundle) + concept_names, concept_types, importance = _collect_concepts( + understanding_result, + extraction_result, + answer_bundle, + best_path_concepts, + ) + relations = _collect_relations(answer_bundle, extraction_result) + focus_concept = _clean_text((answer_bundle or {}).get("focus_concept") or (understanding_result or {}).get("focus_concept")) + + if scene_type == "schematic": + scene = _compose_schematic_layout(concept_names, importance, relations, focus_concept, canvas_size, sketch_options) + elif scene_type == "process": + scene = _compose_process_layout(concept_names, importance, relations, focus_concept, canvas_size, sketch_options) + else: + scene = _compose_scene_layout(query, concept_names, concept_types, importance, relations, focus_concept, canvas_size, sketch_options) + + scene["render_hints"]["concept_type_summary"] = "、".join( + f"{concept}:{concept_types.get(concept, 'general')}" for concept in concept_names[:6] + ) + scene["render_hints"]["query_summary"] = _clean_text(query) + scene["debug_legacy"] = { + "concept_order": concept_names, + "relations": relations[:12], + } + return scene + + +def _normalize_background_layers(scene: Dict[str, Any]) -> List[Dict[str, Any]]: + layers = [] + for index, layer in enumerate(scene.get("background_layers", []) or [], start=1): + width = max(1, int(layer.get("width", 1))) + height = max(1, int(layer.get("height", 1))) + layers.append( + _build_background_layer( + layer.get("id") or f"bg_{index}", + layer.get("type") or "panel", + layer.get("label") or f"区域{index}", + int(layer.get("x", 0)), + int(layer.get("y", 0)), + width, + height, + int(layer.get("z_index", -10)), + _clean_text(layer.get("source") or "auto"), + ) + ) + return layers + + +def _normalize_objects(scene: Dict[str, Any]) -> List[Dict[str, Any]]: + objects = [] + for index, obj in enumerate(scene.get("object_instances", []) or [], start=1): + concept = _clean_text(obj.get("concept") or f"对象{index}") + asset_key = obj.get("asset_key") or pick_asset_key(concept, scene.get("layout_options", {}).get("scene_type", "scene")) + default_w, default_h = get_asset_definition(asset_key).get("default_size", (140, 100)) + width = max(36, int(obj.get("width", default_w))) + height = max(36, int(obj.get("height", default_h))) + objects.append( + _build_object_instance( + obj.get("id") or f"obj_{index}", + concept, + asset_key, + _clean_text(obj.get("role") or "support"), + _clean_text(obj.get("depth_band") or "midground"), + float(obj.get("x", 80 + index * 40)), + float(obj.get("y", 120 + index * 24)), + width, + height, + int(obj.get("z_index", 20 + index)), + _clean_text(obj.get("source") or "auto"), + float(obj.get("rotation", 0.0) or 0.0), + float(obj.get("scale", 1.0) or 1.0), + bool(obj.get("editable", True)), + bool(obj.get("visible", True)), + obj.get("depth_z"), + ) + ) + return objects + + +def _normalize_connectors(scene: Dict[str, Any], object_ids: Iterable[str]) -> List[Dict[str, Any]]: + valid_ids = set(object_ids) + connectors = [] + for index, connector in enumerate(scene.get("connectors", []) or [], start=1): + from_id = _clean_text(connector.get("from_id")) + to_id = _clean_text(connector.get("to_id")) + if from_id not in valid_ids or to_id not in valid_ids: + continue + connectors.append( + { + "id": connector.get("id") or f"conn_{index}", + "type": _clean_text(connector.get("type") or "arrow"), + "from_id": from_id, + "to_id": to_id, + "label": _clean_text(connector.get("label") or "连接"), + "visible": bool(connector.get("visible", True)), + } + ) + return connectors + + +def _normalize_attachments(scene: Dict[str, Any], object_ids: Iterable[str]) -> List[Dict[str, Any]]: + valid_ids = set(object_ids) + attachments = [] + for index, attachment in enumerate(scene.get("attachments", []) or [], start=1): + host_id = _clean_text(attachment.get("host_id")) + child_id = _clean_text(attachment.get("child_id")) + if host_id not in valid_ids or child_id not in valid_ids or host_id == child_id: + continue + attachments.append( + _build_attachment( + attachment.get("id") or f"att_{index}", + host_id, + child_id, + _clean_text(attachment.get("anchor_name") or "center"), + _clean_text(attachment.get("mode") or "attach"), + ) + ) + return attachments + + +def legacy_scene_spec_to_v2(scene_spec: Dict[str, Any], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + sketch_options = sketch_options or {} + canvas = scene_spec.get("canvas_size") or {} + canvas_size = ( + max(512, int(canvas.get("width", sketch_options.get("canvas_width", CANVAS_DEFAULT[0])))), + max(384, int(canvas.get("height", sketch_options.get("canvas_height", CANVAS_DEFAULT[1])))), + ) + scene = _build_scene_shell(canvas_size, sketch_options) + legacy_nodes = scene_spec.get("nodes", []) or [] + legacy_relations = scene_spec.get("relations", []) or [] + inferred_type = "schematic" if legacy_relations else "scene" + scene["layout_options"]["scene_type"] = inferred_type + + object_instances = [] + concept_order = [] + for index, node in enumerate(legacy_nodes, start=1): + concept = _clean_text(node.get("concept") or f"节点{index}") + concept_order.append(concept) + asset_key = pick_asset_key(concept, inferred_type) + object_instances.append( + _build_object_instance( + node.get("id") or f"obj_{index}", + concept, + asset_key, + _clean_text(node.get("role") or "support"), + "midground", + float(node.get("x", 80 + index * 120)), + float(node.get("y", 240)), + float(node.get("width", get_asset_definition(asset_key).get("default_size", (140, 100))[0])), + float(node.get("height", get_asset_definition(asset_key).get("default_size", (140, 100))[1])), + int(node.get("z_index", 20 + index)), + _clean_text(node.get("source") or "auto"), + float(node.get("rotation", 0.0) or 0.0), + float(node.get("scale", 1.0) or 1.0), + bool(node.get("editable", True)), + ) + ) + + scene["object_instances"] = object_instances + scene["connectors"] = [ + _build_connector( + relation.get("id") or f"conn_{index}", + _clean_text(relation.get("from_id")), + _clean_text(relation.get("to_id")), + relation.get("relation") or relation.get("label") or "连接", + inferred_type, + visible=True, + ) + for index, relation in enumerate(legacy_relations, start=1) + if _clean_text(relation.get("from_id")) and _clean_text(relation.get("to_id")) + ] + scene["concept_order"] = concept_order + scene["render_hints"] = _render_hints_for_scene(scene, inferred_type) + scene["debug_legacy"] = { + "concept_order": scene_spec.get("concept_order", concept_order), + "nodes": legacy_nodes, + "relations": legacy_relations, + } + return scene + + +def normalize_scene_spec_v2(scene_spec: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + sketch_options = sketch_options or {} + raw = _deep_copy(scene_spec or {}) + if not raw: + return _build_scene_shell(CANVAS_DEFAULT, sketch_options) + if int(raw.get("version", 0) or 0) != 2 and ("object_instances" not in raw and "background_layers" not in raw): + raw = legacy_scene_spec_to_v2(raw, sketch_options) + + canvas = raw.get("canvas_size") or {} + width = max(512, int(canvas.get("width", sketch_options.get("canvas_width", CANVAS_DEFAULT[0])))) + height = max(384, int(canvas.get("height", sketch_options.get("canvas_height", CANVAS_DEFAULT[1])))) + normalized = _build_scene_shell((width, height), sketch_options) + normalized["version"] = 2 + normalized["layout_options"].update(raw.get("layout_options") or {}) + normalized["layout_options"]["mode"] = "semantic_composition" + normalized["layout_options"]["sketch_style"] = sketch_options.get( + "sketch_style", + normalized["layout_options"].get("sketch_style", "line_art"), + ) + normalized["layout_options"]["show_grid"] = bool( + sketch_options.get("show_grid", normalized["layout_options"].get("show_grid", True)) + ) + normalized["layout_options"]["show_labels"] = bool( + sketch_options.get("show_labels", normalized["layout_options"].get("show_labels", True)) + ) + normalized["layout_options"]["show_guides"] = bool( + sketch_options.get("show_guides", normalized["layout_options"].get("show_guides", True)) + ) + normalized["layout_options"]["node_scale"] = float( + sketch_options.get("node_scale", normalized["layout_options"].get("node_scale", 1.0)) + ) + normalized["layout_options"]["spacing_scale"] = float( + sketch_options.get("spacing_scale", normalized["layout_options"].get("spacing_scale", 1.0)) + ) + + normalized["background_layers"] = _normalize_background_layers(raw) + normalized["object_instances"] = _normalize_objects(raw) + object_ids = [item["id"] for item in normalized["object_instances"]] + normalized["attachments"] = _normalize_attachments(raw, object_ids) + normalized["connectors"] = _normalize_connectors(raw, object_ids) + normalized["concept_order"] = [ + _clean_text(item.get("concept")) + for item in normalized["object_instances"] + if _clean_text(item.get("concept")) + ] + normalized["render_hints"] = { + **_render_hints_for_scene( + { + "background_layers": normalized["background_layers"], + "object_instances": normalized["object_instances"], + "connectors": normalized["connectors"], + "layout_options": normalized["layout_options"], + }, + normalized["layout_options"].get("scene_type", "scene"), + ), + **(raw.get("render_hints") or {}), + } + if raw.get("debug_legacy"): + normalized["debug_legacy"] = raw["debug_legacy"] + return normalized + + +def summarize_scene_spec(scene_spec: Dict[str, Any] | None) -> str: + if not scene_spec: + return "" + scene = normalize_scene_spec_v2(scene_spec) + backgrounds = scene.get("background_layers", []) or [] + objects = scene.get("object_instances", []) or [] + attachments = scene.get("attachments", []) or [] + connectors = [item for item in scene.get("connectors", []) or [] if item.get("visible")] + + bg_summary = ", ".join( + f"{item['label']}@({item['x']},{item['y']},{item['width']}x{item['height']})" + for item in backgrounds[:5] + ) + object_summary = ", ".join( + f"{item['concept']}[{item['asset_key']}]@({item['x']},{item['y']},{item['width']}x{item['height']})/{item['depth_band']}" + for item in objects[:8] + ) + attachment_summary = ", ".join( + f"{item['child_id']}->{item['host_id']}:{item['anchor_name']}" + for item in attachments[:6] + ) + connector_summary = ", ".join( + f"{item['type']}:{item['label']} {item['from_id']}->{item['to_id']}" + for item in connectors[:6] + ) + hints = scene.get("render_hints", {}) or {} + parts = [ + f"scene_type={scene.get('layout_options', {}).get('scene_type', 'scene')}", + f"style={scene.get('layout_options', {}).get('sketch_style', 'line_art')}", + f"backgrounds={bg_summary}" if bg_summary else "", + f"objects={object_summary}" if object_summary else "", + f"attachments={attachment_summary}" if attachment_summary else "", + f"connectors={connector_summary}" if connector_summary else "", + hints.get("scene_summary", ""), + hints.get("subject_summary", ""), + hints.get("user_added_summary", ""), + ] + return " | ".join(part for part in parts if part) + + +def scene_spec_counts(scene_spec: Dict[str, Any] | None) -> Tuple[int, int]: + if not scene_spec: + return 0, 0 + scene = normalize_scene_spec_v2(scene_spec) + return len(scene.get("object_instances", []) or []), len(scene.get("connectors", []) or []) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene_v2.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene_v2.py new file mode 100644 index 0000000..300e6d6 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/semantic_scene_v2.py @@ -0,0 +1,1377 @@ +from __future__ import annotations + +import json +import re +from typing import Any, Dict, List, Tuple + +from . import semantic_scene as legacy +from .natural_layout import apply_natural_layout +from .object_sketch_backend import resolve_object_shape +from .sketch_style_spec import ( + build_stroke_style_profile, + default_part_graph, + default_readability_rank, + default_region_masks, + infer_sketch_family, + normalize_layout_options, + normalize_style_variant, + summarize_region_overrides, +) +from .visual_prototypes import fallback_prototype_id, resolve_visual_prototype + + +CANVAS_DEFAULT = legacy.CANVAS_DEFAULT + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _clean_text(value: Any) -> str: + return str(value or "").strip() + + +FALLBACK_ASSETS: Dict[str, Dict[str, Any]] = { + "blob": { + "label": "语义团块", + "category": "兜底", + "silhouette_key": "blob", + "default_size": (168, 128), + "keywords": [], + "anchors": ["center"], + "editor_visible": True, + }, + "tower": { + "label": "高塔母题", + "category": "兜底", + "silhouette_key": "tower", + "default_size": (180, 260), + "keywords": [], + "anchors": ["facade", "roof", "ground", "center"], + "editor_visible": True, + }, + "capsule": { + "label": "过程胶囊", + "category": "兜底", + "silhouette_key": "capsule", + "default_size": (172, 116), + "keywords": [], + "anchors": ["center", "left", "right"], + "editor_visible": True, + }, + "branch": { + "label": "分支母题", + "category": "兜底", + "silhouette_key": "branch", + "default_size": (180, 140), + "keywords": [], + "anchors": ["center"], + "editor_visible": True, + }, + "module": { + "label": "功能模块", + "category": "兜底", + "silhouette_key": "module", + "default_size": (180, 120), + "keywords": [], + "anchors": ["left", "right", "center"], + "editor_visible": True, + }, +} + + +EXTRA_ASSETS: Dict[str, Dict[str, Any]] = { + "dog": { + "label": "狗", + "category": "角色", + "silhouette_key": "dog", + "default_size": (180, 128), + "keywords": ["狗", "小狗", "犬", "dog"], + "anchors": ["center", "ground"], + "editor_visible": True, + }, + "desk_lamp": { + "label": "台灯", + "category": "室内", + "silhouette_key": "desk_lamp", + "default_size": (120, 180), + "keywords": ["台灯", "桌灯", "desk lamp"], + "anchors": ["base", "center"], + "editor_visible": True, + }, + "cycle": { + "label": "循环母题", + "category": "过程", + "silhouette_key": "cycle", + "default_size": (180, 180), + "keywords": ["循环", "周期", "回路", "cycle"], + "anchors": ["center"], + "editor_visible": True, + }, + "flow_node": { + "label": "流程节点", + "category": "过程", + "silhouette_key": "flow_node", + "default_size": (180, 120), + "keywords": ["阶段", "步骤", "过程", "机制", "flow"], + "anchors": ["center", "left", "right"], + "editor_visible": True, + }, + "energy_wave": { + "label": "能量波", + "category": "过程", + "silhouette_key": "energy_wave", + "default_size": (180, 100), + "keywords": ["能量", "热", "光", "传播", "波"], + "anchors": ["center", "left", "right"], + "editor_visible": True, + }, + "vapor": { + "label": "蒸汽母题", + "category": "过程", + "silhouette_key": "vapor", + "default_size": (160, 180), + "keywords": ["蒸发", "蒸汽", "水汽", "vapor"], + "anchors": ["center", "sky"], + "editor_visible": True, + }, + "switch": { + "label": "开关", + "category": "电路", + "silhouette_key": "switch", + "default_size": (170, 110), + "keywords": ["开关", "按钮", "按键", "拨动", "toggle", "switch"], + "anchors": ["left", "right", "center"], + "editor_visible": True, + }, +} + + +ASSET_LIBRARY: Dict[str, Dict[str, Any]] = _copy(legacy.ASSET_LIBRARY) +ASSET_LIBRARY.update(FALLBACK_ASSETS) +ASSET_LIBRARY.update(EXTRA_ASSETS) + + +EDITOR_LIBRARY_ORDER = [ + *[item for item in legacy.EDITOR_LIBRARY_ORDER if item not in {"tower", "capsule", "branch", "module", "blob"}], + "dog", + "desk_lamp", + "cycle", + "flow_node", + "energy_wave", + "vapor", + "switch", + "tower", + "branch", + "module", + "blob", +] + + +ATTACHMENT_COMPATIBILITY: Dict[str, List[str]] = { + "window": ["building", "house", "tower"], + "door": ["building", "house", "tower"], + "cloud": ["bg_sky"], + "sun": ["bg_sky"], + "car": ["road"], + "chair": ["table"], + "desk_lamp": ["table"], + "street_lamp": ["road", "building", "house"], +} + + +NOISE_EXACT = { + "一个", + "一种", + "一些", + "东西", + "内容", + "图片", + "图像", + "画面", + "场景", + "草图", + "示意图", + "问题", + "答案", + "原因", + "结果", + "条件", + "关系", + "结构", + "对象", + "主体", + "元素", +} + + +NOISE_CONTAINS = { + "这张图", + "该图片", + "这个场景", + "这个东西", + "一张图", + "某个东西", + "visualized intent", +} + + +def _sync_legacy() -> None: + legacy.ASSET_LIBRARY = ASSET_LIBRARY + legacy.EDITOR_LIBRARY_ORDER = EDITOR_LIBRARY_ORDER + legacy.pick_asset_key = pick_asset_key + + +def _normalized_text(text: Any) -> str: + value = _clean_text(text).lower() + value = re.sub(r"[\s\-_·•,.;:!?!?、,。;:“”\"'()()【】\[\]<>《》/\\]+", "", value) + return value + + +def _contains_any(text: str, tokens: tuple[str, ...] | list[str]) -> bool: + return any(token and token in text for token in tokens) + + +_QUERY_NEGATION_PATTERNS = ( + re.compile(r"(不要|别|避免|勿|去掉|移除|不是|并非|非)\s*$"), + re.compile(r"(?:^|[\s,;:()\[\]{}'\"/_-])(no|not|avoid|avoiding|without|exclude|excluding|remove|minus)\s*$"), +) + + +def _iter_query_token_hits(text: str, lowered: str, marker: str): + cleaned = _clean_text(marker) + if not cleaned: + return + ascii_phrase = all(ord(ch) < 128 for ch in cleaned) + if ascii_phrase: + pattern = re.compile(rf"(? bool: + prefix = source[max(0, start - 28):start].strip() + if not prefix: + return False + return any(pattern.search(prefix) for pattern in _QUERY_NEGATION_PATTERNS) + + +def _contains_query_token(text: str, lowered: str, tokens: tuple[str, ...] | list[str]) -> bool: + for token in tokens: + marker = _clean_text(token) + if not marker: + continue + for source, start, _ in _iter_query_token_hits(text, lowered, marker): + if not _is_negated_query_hit(source, start): + return True + return False + + +def _is_switch_like_concept(text: str) -> bool: + raw = _clean_text(text) + lowered = raw.lower() + return _contains_any(raw, ("开关", "按钮", "按键", "拨动", "切换")) or any( + token in lowered for token in ("switch", "toggle", "button") + ) + + +def _is_explicit_board_concept(text: str) -> bool: + raw = _clean_text(text) + lowered = raw.lower() + return _contains_any(raw, ("电路板", "开发板", "主板", "面包板", "板子", "控制板")) or any( + token in lowered for token in ("board", "breadboard", "arduino", "pcb", "controller board", "control board") + ) + + +def _normalize_schematic_connector_label(label: Any) -> str: + raw = _clean_text(label) + if not raw: + return "连接" + return "连接" + + +def _is_generic_process_stage(text: str) -> bool: + raw = _clean_text(text) + return _contains_any(raw, ("过程", "机制", "阶段", "步骤", "输入", "输出", "结果", "原因", "条件", "变化", "转化")) + + +def _is_noise_concept(text: Any) -> bool: + raw = _clean_text(text) + if not raw: + return True + normalized = _normalized_text(raw) + if normalized in NOISE_EXACT: + return True + if any(token in raw for token in NOISE_CONTAINS): + return True + if len(normalized) <= 2 and normalized in {"它", "他", "她", "其", "该", "此", "某"}: + return True + return False + + +def get_asset_definition(asset_key: str) -> Dict[str, Any]: + return ASSET_LIBRARY.get(asset_key, ASSET_LIBRARY["generic_object"]) + + +def _asset_scene_type(asset_key: str, fallback_scene_type: str) -> str: + key = _clean_text(asset_key) + if key in {"cycle", "flow_node", "energy_wave", "vapor", "leaf", "raindrop", "airplane", "cell"}: + return "process" + if key in {"battery", "led", "resistor", "capacitor", "diode", "board", "module", "branch", "switch"}: + return "schematic" + return fallback_scene_type + + +def _preferred_scene_style(scene_type: str) -> str: + return "clean_line" if _clean_text(scene_type) == "scene" else "scribble_line" + + +def _preferred_variant_id_for_style(variants: List[Dict[str, Any]], style_variant: str) -> str: + normalized_style = normalize_style_variant(style_variant or "") + if not normalized_style: + return "" + for variant in variants: + styles = {normalize_style_variant(item) for item in (variant.get("style_variants") or [])} + if normalized_style in styles and normalize_style_variant(variant.get("default_style")) == normalized_style: + return str(variant.get("id") or "") + for variant in variants: + styles = {normalize_style_variant(item) for item in (variant.get("style_variants") or [])} + if normalized_style in styles: + return str(variant.get("id") or "") + return "" + + +def build_editor_asset_library() -> List[Dict[str, Any]]: + grouped: Dict[str, List[Dict[str, Any]]] = {} + for asset_key in EDITOR_LIBRARY_ORDER: + asset = get_asset_definition(asset_key) + scene_type = _asset_scene_type(asset_key, "scene") + prototype = resolve_visual_prototype(asset_key, asset.get("label", asset_key), scene_type) + requested_style = normalize_style_variant(_preferred_scene_style(scene_type) if scene_type == "scene" else (prototype.get("style_variant") or _preferred_scene_style(scene_type))) + sketch_variant = resolve_object_shape( + asset_key, + concept=asset.get("label", asset_key), + scene_type=scene_type, + style_variant=requested_style, + stroke_seed=asset_key, + ) + category = asset.get("category", "其他") + grouped.setdefault(category, []).append( + { + "asset_key": asset_key, + "label": asset.get("label", asset_key), + "silhouette_key": asset.get("silhouette_key", asset_key), + "default_width": asset.get("default_size", (120, 120))[0], + "default_height": asset.get("default_size", (120, 120))[1], + "anchors": asset.get("anchors", []), + "prototype_id": prototype.get("prototype_id", asset_key), + "visual_family": prototype.get("visual_family", "scene_object"), + "style_variant": sketch_variant.get("style_variant", requested_style), + "part_slots": prototype.get("part_slots", []), + "shape_recipe": sketch_variant.get("shape_recipe") or prototype.get("shape_recipe", {}), + "shape_variant_id": sketch_variant.get("shape_variant_id", f"{asset_key}:rule_base"), + "shape_recipe_source": sketch_variant.get("shape_recipe_source", "rule_prototype"), + "sketch_backend": sketch_variant.get("sketch_backend", "rule"), + "shape_confidence": float(sketch_variant.get("shape_confidence", 0.7) or 0.7), + "available_shape_variants": sketch_variant.get("available_shape_variants", []), + "render_representation": sketch_variant.get("render_representation", "shape_recipe"), + "stroke_variant_id": sketch_variant.get("stroke_variant_id", sketch_variant.get("shape_variant_id", f"{asset_key}:rule_base")), + "stroke_payload": sketch_variant.get("stroke_payload", []), + "stroke_payload_source": sketch_variant.get("stroke_payload_source", sketch_variant.get("shape_recipe_source", "rule_prototype")), + "stroke_render_profile": sketch_variant.get("stroke_render_profile", sketch_variant.get("stroke_style_profile", {})), + "part_graph": sketch_variant.get("part_graph") or default_part_graph(asset_key, scene_type=scene_type), + "region_masks": sketch_variant.get("region_masks") or default_region_masks(asset_key, scene_type=scene_type), + "stroke_style_profile": sketch_variant.get("stroke_style_profile") + or build_stroke_style_profile( + asset_key, + scene_type=scene_type, + style_variant=sketch_variant.get("style_variant", requested_style), + sketch_family=sketch_variant.get("sketch_family", infer_sketch_family(asset_key, scene_type=scene_type)), + ), + "readability_rank": int(sketch_variant.get("readability_rank", default_readability_rank(asset_key, scene_type=scene_type)) or default_readability_rank(asset_key, scene_type=scene_type)), + "sketch_family": sketch_variant.get("sketch_family", infer_sketch_family(asset_key, scene_type=scene_type)), + "attach_to": ATTACHMENT_COMPATIBILITY.get(asset_key, []), + } + ) + return [{"category": category, "items": items} for category, items in grouped.items()] + + +def _process_asset_from_concept(text: str) -> str: + if _contains_any(text, ("蒸发", "蒸汽", "水汽", "雾气", "气化")): + return "vapor" + if _contains_any(text, ("雨", "降水", "降雨", "水滴")): + return "raindrop" + if _contains_any(text, ("云", "凝结")): + return "cloud" + if _contains_any(text, ("太阳", "日照", "光合作用", "叶", "叶片", "植物")): + return "leaf" if _contains_any(text, ("光合作用", "叶", "叶片", "植物")) else "sun" + if _contains_any(text, ("能量", "热量", "热", "光照", "光", "辐射")): + return "sun" + if _contains_any(text, ("飞机", "机翼", "升力", "飞行")): + return "airplane" + if _contains_any(text, ("细胞", "线粒体", "叶绿体")): + return "cell" + return "" + + +def _schematic_asset_from_concept(text: str) -> str: + if _contains_any(text, ("电池", "电源", "供电", "battery", "power")): + return "battery" + if _contains_any(text, ("led", "发光二极管", "灯泡")): + return "led" + if _contains_any(text, ("电阻", "resistor")): + return "resistor" + if _contains_any(text, ("电容", "capacitor")): + return "capacitor" + if _contains_any(text, ("二极管", "diode")): + return "diode" + if _is_switch_like_concept(text): + return "switch" + if _contains_any(text, ("电路板", "开发板", "主板", "board", "arduino")): + return "board" + return "" + + +def pick_asset_key(concept: str, scene_type: str = "scene") -> str: + concept_text = _clean_text(concept) + lowered = concept_text.lower() + normalized = _normalized_text(concept_text) + + english_map = ( + "dog", + "desk_lamp", + "window", + "door", + "building", + "house", + "tree", + "cloud", + "sun", + "car", + "road", + "person", + "chair", + "table", + "cycle", + "flow_node", + "energy_wave", + "vapor", + "battery", + "led", + "switch", + "resistor", + "capacitor", + "diode", + "board", + "airplane", + "leaf", + "raindrop", + "cell", + ) + for asset_key in english_map: + if asset_key in lowered: + return asset_key + + chinese_token_map = [ + ("dog", ("狗", "小狗", "柯基", "犬")), + ("desk_lamp", ("台灯", "桌灯")), + ("street_lamp", ("路灯", "街灯", "灯杆")), + ("building", ("楼房", "大楼", "建筑", "高楼")), + ("house", ("房子", "房屋", "住宅")), + ("window", ("窗户", "窗", "玻璃窗")), + ("door", ("门", "大门", "房门")), + ("tree", ("树", "树木", "树林")), + ("cloud", ("云", "云朵")), + ("sun", ("太阳", "阳光", "日光")), + ("car", ("汽车", "轿车", "车辆")), + ("road", ("道路", "路面", "街道", "公路")), + ("person", ("人物", "人", "行人", "学生", "孩子")), + ("table", ("桌子", "桌")), + ("chair", ("椅子", "椅")), + ("cycle", ("循环", "周期", "回路")), + ("flow_node", ("步骤", "阶段", "流程节点")), + ("energy_wave", ("能量", "热量", "波", "辐射", "传播")), + ("vapor", ("蒸发", "蒸汽", "水汽", "雾气")), + ("battery", ("电池", "电源")), + ("led", ("LED", "发光二极管", "灯泡")), + ("switch", ("开关", "按钮", "按键", "拨动")), + ("resistor", ("电阻",)), + ("capacitor", ("电容",)), + ("diode", ("二极管",)), + ("board", ("电路板", "开发板", "主板", "面包板", "板子", "控制板")), + ("airplane", ("飞机", "机翼", "飞行器")), + ("leaf", ("叶子", "树叶", "叶片")), + ("raindrop", ("雨滴", "水滴")), + ("cell", ("细胞",)), + ] + for asset_key, tokens in chinese_token_map: + if any(token in concept_text for token in tokens): + return asset_key + + if any(token in concept_text for token in ("细胞核", "细胞质", "细胞膜")): + return "generic_circle" + + for asset_key, asset in ASSET_LIBRARY.items(): + for keyword in asset.get("keywords", []): + if keyword and keyword.lower() in lowered: + return asset_key + + if scene_type == "process": + process_asset = _process_asset_from_concept(concept_text) + if process_asset: + return process_asset + + if scene_type == "schematic": + schematic_asset = _schematic_asset_from_concept(concept_text) + if schematic_asset: + return schematic_asset + + if scene_type == "scene" and _contains_any(normalized, ("塔", "楼", "大厦", "烟囱", "柱")): + return "tower" + + prototype_id = fallback_prototype_id(concept_text, scene_type) + if prototype_id in ASSET_LIBRARY: + return prototype_id + if scene_type == "process": + return "flow_node" + if scene_type == "schematic": + return "module" + return "blob" + + +def _sanitize_scene(scene: Dict[str, Any]) -> Dict[str, Any]: + objects = [] + removed_ids: set[str] = set() + for obj in scene.get("object_instances", []) or []: + item = _copy(obj) + concept = _clean_text(item.get("concept")) + source = _clean_text(item.get("source")) + if not concept and source != "user": + removed_ids.add(str(item.get("id") or "")) + continue + if source != "user" and _is_noise_concept(concept): + removed_ids.add(str(item.get("id") or "")) + continue + objects.append(item) + scene["object_instances"] = objects + if removed_ids: + scene["attachments"] = [ + item + for item in scene.get("attachments", []) or [] + if str(item.get("host_id") or "") not in removed_ids and str(item.get("child_id") or "") not in removed_ids + ] + scene["connectors"] = [ + item + for item in scene.get("connectors", []) or [] + if str(item.get("from_id") or "") not in removed_ids and str(item.get("to_id") or "") not in removed_ids + ] + concept_order = [_clean_text(item) for item in scene.get("concept_order", []) or []] + scene["concept_order"] = [item for item in concept_order if item and not _is_noise_concept(item)] + if not scene["concept_order"]: + scene["concept_order"] = [item.get("concept", "") for item in objects if _clean_text(item.get("concept"))] + return scene + + +def _repair_asset_key(asset_key: str, concept: str, scene_type: str) -> str: + current = _clean_text(asset_key) + if scene_type == "process" and current in {"capsule", "generic_panel", "generic_object", "blob"}: + current = "" + if scene_type == "schematic" and current in {"generic_panel", "generic_object", "blob"}: + current = "" + if scene_type == "scene" and current in {"generic_panel"}: + current = "" + return current or pick_asset_key(concept, scene_type) + + +def _rebalance_generic_objects(scene: Dict[str, Any]) -> Dict[str, Any]: + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or "scene") + for obj in scene.get("object_instances", []) or []: + concept = _clean_text(obj.get("concept")) + repaired = _repair_asset_key(_clean_text(obj.get("asset_key")), concept, scene_type) + obj["asset_key"] = repaired + obj["silhouette_key"] = get_asset_definition(repaired).get("silhouette_key", repaired) + return scene + + +def _apply_visual_metadata(scene: Dict[str, Any]) -> Dict[str, Any]: + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or "scene") + objects: List[Dict[str, Any]] = [] + for obj in scene.get("object_instances", []) or []: + item = _copy(obj) + concept = _clean_text(item.get("concept")) + asset_key = _repair_asset_key(_clean_text(item.get("asset_key")), concept, scene_type) + prototype = resolve_visual_prototype( + _clean_text(item.get("prototype_id") or asset_key), + concept, + scene_type, + ) + raw_item_style = normalize_style_variant(_clean_text(item.get("style_variant"))) + if scene_type == "scene" and raw_item_style == "scribble_line" and _clean_text(item.get("source")) != "user": + raw_item_style = "" + style_variant = normalize_style_variant(raw_item_style or (_preferred_scene_style(scene_type) if scene_type == "scene" else (prototype.get("style_variant") or _preferred_scene_style(scene_type)))) + preferred_variant_id = _clean_text(item.get("shape_variant_id")) + if style_variant == "clean_line" and "clean_line" not in preferred_variant_id: + preferred_variant_id = "" + sketch_variant = resolve_object_shape( + asset_key, + concept=concept, + scene_type=scene_type, + preferred_variant_id=preferred_variant_id, + style_variant=style_variant, + stroke_seed=item.get("stroke_seed") or item.get("id") or concept or asset_key, + ) + sketch_family = item.get("sketch_family") or sketch_variant.get("sketch_family") or infer_sketch_family(asset_key, scene_type=scene_type) + resolved_style = normalize_style_variant(sketch_variant.get("style_variant") or style_variant or _preferred_scene_style(scene_type)) + preferred_style_variant_id = _preferred_variant_id_for_style( + sketch_variant.get("available_shape_variants") or [], + resolved_style, + ) + item["asset_key"] = asset_key + item["silhouette_key"] = item.get("silhouette_key") or get_asset_definition(asset_key).get("silhouette_key", asset_key) + item["prototype_id"] = prototype.get("prototype_id", asset_key) + item["visual_family"] = item.get("visual_family") or prototype.get("visual_family", "scene_object") + item["shape_recipe"] = item.get("shape_recipe") or sketch_variant.get("shape_recipe") or prototype.get("shape_recipe", {}) + item["part_slots"] = item.get("part_slots") or prototype.get("part_slots", []) + item["style_variant"] = resolved_style + item["shape_variant_id"] = preferred_style_variant_id or sketch_variant.get("shape_variant_id", f"{asset_key}:rule_base") + item["shape_recipe_source"] = item.get("shape_recipe_source") or sketch_variant.get("shape_recipe_source", "rule_prototype") + item["sketch_backend"] = item.get("sketch_backend") or sketch_variant.get("sketch_backend", "rule") + item["stroke_seed"] = str(item.get("stroke_seed") or sketch_variant.get("stroke_seed") or item.get("id") or concept or asset_key) + item["shape_confidence"] = float(item.get("shape_confidence") or sketch_variant.get("shape_confidence") or 0.7) + item["available_shape_variants"] = item.get("available_shape_variants") or sketch_variant.get("available_shape_variants", []) + item["render_representation"] = item.get("render_representation") or sketch_variant.get("render_representation", "shape_recipe") + item["stroke_variant_id"] = item.get("stroke_variant_id") or sketch_variant.get("stroke_variant_id") or item["shape_variant_id"] + item["stroke_payload"] = item.get("stroke_payload") or sketch_variant.get("stroke_payload") or [] + item["stroke_payload_source"] = item.get("stroke_payload_source") or sketch_variant.get("stroke_payload_source") or item["shape_recipe_source"] + item["stroke_render_profile"] = item.get("stroke_render_profile") or sketch_variant.get("stroke_render_profile") or sketch_variant.get("stroke_style_profile") or {} + item["part_graph"] = item.get("part_graph") or sketch_variant.get("part_graph") or default_part_graph(asset_key, scene_type=scene_type) + item["region_masks"] = item.get("region_masks") or sketch_variant.get("region_masks") or default_region_masks(asset_key, scene_type=scene_type) + item["stroke_style_profile"] = item.get("stroke_style_profile") or sketch_variant.get("stroke_style_profile") or build_stroke_style_profile( + asset_key, + scene_type=scene_type, + style_variant=resolved_style, + sketch_family=sketch_family, + ) + item["readability_rank"] = int(item.get("readability_rank") or sketch_variant.get("readability_rank") or default_readability_rank(asset_key, scene_type=scene_type)) + item["sketch_family"] = sketch_family + item["region_overrides"] = item.get("region_overrides") if isinstance(item.get("region_overrides"), dict) else {} + objects.append(item) + scene["object_instances"] = objects + return scene + + +def _soften_backgrounds(scene: Dict[str, Any]) -> Dict[str, Any]: + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or "scene") + updated: List[Dict[str, Any]] = [] + for index, layer in enumerate(scene.get("background_layers", []) or [], start=1): + item = _copy(layer) + if scene_type == "process" and item.get("type") == "panel": + item["type"] = "process_band" + item["source"] = item.get("source", "auto") + item["z_index"] = -22 + index + elif scene_type == "schematic" and item.get("type") == "board": + item["type"] = "board" + item["z_index"] = -18 + updated.append(item) + scene["background_layers"] = updated + return scene + + +def _upgrade_layout_defaults(scene: Dict[str, Any], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + sketch_options = sketch_options or {} + layout = scene.setdefault("layout_options", {}) + layout["mode"] = "semantic_composition" + layout["sketch_style"] = normalize_style_variant(_clean_text(sketch_options.get("sketch_style") or layout.get("sketch_style") or _preferred_scene_style(_clean_text(layout.get("scene_type") or "scene")))) + layout["show_labels"] = bool(sketch_options.get("show_labels", layout.get("show_labels", False))) + layout["show_grid"] = bool(sketch_options.get("show_grid", layout.get("show_grid", True))) + layout["show_guides"] = bool(sketch_options.get("show_guides", layout.get("show_guides", False))) + layout["node_scale"] = float(sketch_options.get("node_scale", layout.get("node_scale", 1.0))) + layout["spacing_scale"] = float(sketch_options.get("spacing_scale", layout.get("spacing_scale", 1.0))) + layout["composition_mode"] = layout.get("scene_type", "scene") + layout["layout_engine"] = _clean_text(sketch_options.get("layout_engine") or layout.get("layout_engine") or "auto") or "auto" + layout["layout_candidate_count"] = int(sketch_options.get("layout_candidate_count", layout.get("layout_candidate_count", 4)) or 4) + layout["layout_manual_override"] = bool(layout.get("layout_manual_override", False)) + layout.update(normalize_layout_options(layout, sketch_options)) + return scene + + +def _upgrade_render_hints(scene: Dict[str, Any]) -> Dict[str, Any]: + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or "scene") + hints = dict(scene.get("render_hints") or {}) + objects = scene.get("object_instances", []) or [] + subjects = [item.get("concept", "") for item in objects if item.get("role") in {"subject", "focus", "core_subject"}][:3] + user_items = [item.get("concept", "") for item in objects if item.get("source") == "user"][:6] + families = [item.get("prototype_id", item.get("asset_key", "")) for item in objects[:8]] + edit_summary = summarize_region_overrides(scene) + hints["scene_summary"] = hints.get("scene_summary") or ("、".join(filter(None, subjects)) if subjects else "语义构图") + hints["subject_summary"] = "主体: " + ("、".join(filter(None, subjects)) if subjects else "未显式主体") + hints["style_summary"] = f"风格: {scene.get('layout_options', {}).get('sketch_style', 'scribble_line')} | 类型: {scene_type}" + hints["prototype_summary"] = "原型: " + ("、".join(filter(None, families)) if families else "无") + hints["user_added_summary"] = "用户新增: " + ("、".join(filter(None, user_items)) if user_items else "无") + hints["edit_summary"] = "局部编辑: " + (edit_summary if edit_summary else "无") + hints["sketch_view_mode"] = scene.get("layout_options", {}).get("sketch_view_mode", "structure") + hints["annotation_level"] = scene.get("layout_options", {}).get("annotation_level", "light") + scene["render_hints"] = hints + return scene + + +def _infer_scene_type_from_query(query: str) -> str: + text = _clean_text(query) + lowered = text.lower() + + def score(*groups: tuple[tuple[str, ...], int]) -> int: + total = 0 + for tokens, weight in groups: + if _contains_query_token(text, lowered, tokens): + total += weight + return total + + scene_score = score( + (("场景", "整图", "街景", "室内", "户外", "房间", "街道", "城市", "自然场景", "scene", "whole-scene", "street-view", "indoor", "outdoor", "room", "city", "landscape"), 2), + (("房子", "建筑", "桌子", "椅子", "台灯", "树", "人", "汽车", "house", "building", "table", "chair", "desk lamp", "tree", "person", "car"), 1), + ) + schematic_score = score( + (("电路", "原理图", "线路图", "串联", "并联", "示意图", "circuit", "schematic", "wiring"), 4), + (("LED", "电阻", "电容", "二极管", "发光二极管", "led", "resistor", "capacitor", "diode"), 3), + (("电池", "电源", "battery"), 2), + (("开发板", "电路板", "主板", "arduino", "board"), 2), + (("开关", "按钮", "按键", "拨动", "switch", "toggle"), 1), + ) + process_score = score( + (("为什么", "形成", "原理", "机制", "过程", "循环", "如何产生", "怎么产生", "作用", "机理"), 3), + (("process", "workflow", "cycle", "mechanism", "explanation", "how it works"), 3), + (("evaporation", "condensation", "rain", "rainfall", "photosynthesis", "water cycle", "plant-energy"), 4), + (("升力", "气流", "空气流动", "空气动力", "lift", "airflow", "aerodynamic"), 4), + ) + if _contains_query_token(text, lowered, ("飞机", "飞行", "airplane", "aircraft", "flight")) and _contains_query_token( + text, + lowered, + ("原理", "机制", "解释", "升力", "气流", "空气流动", "mechanism", "explanation", "lift", "airflow"), + ): + process_score += 3 + if _contains_query_token(text, lowered, ("叶", "叶子", "leaf")) and _contains_query_token( + text, + lowered, + ("太阳", "阳光", "sun", "sunlight"), + ) and _contains_query_token( + text, + lowered, + ("能量", "光合作用", "光照", "energy", "plant-energy", "photosynthesis"), + ): + process_score += 3 + + if schematic_score >= max(process_score + 2, scene_score + 2, 4): + return "schematic" + if process_score >= max(schematic_score + 1, scene_score + 1, 3): + return "process" + return "scene" + + +def _collect_query_assets(query: str, scene_type: str) -> List[str]: + text = _clean_text(query) + lowered = text.lower() + keys: List[str] = [] + def add(key: str) -> None: + if key and key not in keys: + keys.append(key) + + reliable_scene_tokens = [ + ("building", ("\u697c", "\u5927\u697c", "\u697c\u623f", "\u5efa\u7b51", "building", "architecture")), + ("house", ("\u623f\u5b50", "\u5c0f\u623f\u5b50", "\u623f\u5c4b", "\u4f4f\u5b85", "house", "home", "cottage")), + ("road", ("\u8def", "\u8857\u9053", "\u9053\u8def", "\u516c\u8def", "\u9a6c\u8def", "\u8857\u666f", "road", "street", "avenue")), + ("car", ("\u6c7d\u8f66", "\u8f66", "\u8f66\u8f86", "car", "vehicle")), + ("street_lamp", ("\u8def\u706f", "\u8857\u706f", "\u706f\u6746", "street lamp", "streetlight", "lamp post")), + ("person", ("\u4eba", "\u4eba\u7269", "\u884c\u4eba", "\u5b66\u751f", "\u5b69\u5b50", "\u4e00\u4e2a\u4eba", "person", "people", "human", "pedestrian")), + ("tree", ("\u6811", "\u6811\u6728", "\u6811\u6797", "\u4e00\u68f5\u6811", "tree", "trees")), + ("cloud", ("\u4e91", "\u4e91\u6735", "cloud")), + ("sun", ("\u592a\u9633", "\u9633\u5149", "sun")), + ("dog", ("\u72d7", "\u5c0f\u72d7", "\u72ac", "dog")), + ("table", ("\u684c", "\u684c\u5b50", "table")), + ("chair", ("\u6905", "\u6905\u5b50", "chair")), + ("desk_lamp", ("\u53f0\u706f", "\u684c\u706f", "desk lamp")), + ] + reliable_process_tokens = [ + ("sun", ("\u592a\u9633", "\u9633\u5149", "sun")), + ("vapor", ("\u84b8\u53d1", "\u84b8\u6c7d", "\u6c34\u84b8\u6c14", "vapor")), + ("cloud", ("\u4e91", "\u4e91\u6735", "\u51dd\u7ed3", "cloud")), + ("raindrop", ("\u96e8", "\u96e8\u6c34", "\u964d\u96e8", "\u96e8\u6ef4", "\u6c34\u6ef4", "rain", "raindrop")), + ("leaf", ("\u53f6", "\u53f6\u5b50", "\u690d\u7269", "leaf")), + ("energy_wave", ("\u80fd\u91cf", "\u4f20\u64ad", "\u8f90\u5c04", "energy")), + ("airplane", ("\u98de\u673a", "\u98de\u884c", "airplane")), + ("cell", ("\u7ec6\u80de", "cell")), + ] + reliable_schematic_tokens = [ + ("battery", ("\u7535\u6c60", "\u7535\u6e90", "\u4f9b\u7535", "battery", "power")), + ("resistor", ("\u7535\u963b", "resistor")), + ("led", ("led", "\u53d1\u5149\u4e8c\u6781\u7ba1", "\u706f\u6ce1")), + ("switch", ("\u5f00\u5173", "\u6309\u94ae", "\u6309\u952e", "\u62e8\u52a8", "switch", "toggle", "button")), + ("capacitor", ("\u7535\u5bb9", "capacitor")), + ("diode", ("\u4e8c\u6781\u7ba1", "diode")), + ("board", ("\u5f00\u53d1\u677f", "\u7535\u8def\u677f", "\u4e3b\u677f", "\u9762\u5305\u677f", "\u677f\u5b50", "\u63a7\u5236\u677f", "arduino", "breadboard", "board")), + ] + if scene_type == "scene": + for key, tokens in reliable_scene_tokens: + if _contains_query_token(text, lowered, tokens): + add(key) + elif scene_type == "process": + for key, tokens in reliable_process_tokens: + if _contains_query_token(text, lowered, tokens): + add(key) + elif scene_type == "schematic": + for key, tokens in reliable_schematic_tokens: + if _contains_query_token(text, lowered, tokens): + add(key) + + if scene_type == "schematic": + for key, tokens in [ + ("battery", ("电池", "电源", "供电", "battery")), + ("resistor", ("电阻", "resistor")), + ("led", ("LED", "发光二极管", "灯泡", "led")), + ("switch", ("开关", "按钮", "按键", "拨动", "switch", "toggle", "button")), + ("capacitor", ("电容", "capacitor")), + ("diode", ("二极管", "diode")), + ("board", ("开发板", "电路板", "主板", "面包板", "板子", "控制板", "arduino", "breadboard", "board")), + ]: + if _contains_any(text, tokens) or _contains_any(lowered, tokens): + add(key) + if not keys and (_contains_any(text, ("电路", "结构", "信号")) or _contains_any(lowered, ("circuit", "schematic", "wiring"))): + keys = ["battery", "switch", "resistor", "led"] + return keys[:6] + + if scene_type == "process": + if _contains_any(text, ("下雨", "降雨", "降水", "雨水")) or _contains_any(lowered, ("rain", "rainfall", "water cycle")): + return ["sun", "vapor", "cloud", "raindrop"] + if _contains_any(text, ("光合作用",)) or _contains_any(lowered, ("photosynthesis",)): + return ["sun", "leaf", "cloud"] + if _contains_any(text, ("飞机", "升力", "飞行")) or _contains_any(lowered, ("airplane", "flight", "lift")): + return ["airplane", "cloud"] + for key, tokens in [ + ("vapor", ("蒸发", "蒸汽", "水汽", "vapor")), + ("cloud", ("云", "凝结", "cloud")), + ("raindrop", ("雨", "降雨", "水滴", "raindrop")), + ("sun", ("太阳", "光", "热", "sun")), + ("leaf", ("叶", "植物", "leaf")), + ("energy_wave", ("能量", "传播", "辐射", "energy")), + ("airplane", ("飞机", "机翼", "airplane")), + ("cell", ("细胞", "cell")), + ]: + if _contains_any(text, tokens) or _contains_any(lowered, tokens): + add(key) + if not keys: + keys = ["sun", "cloud"] + return keys[:6] + + for key, tokens in [ + ("building", ("楼", "大楼", "楼房", "建筑", "building", "architecture")), + ("house", ("房子", "小房子", "房屋", "住宅", "house", "home", "cottage")), + ("road", ("路", "街道", "道路", "公路", "马路", "街景", "road", "street", "avenue")), + ("car", ("汽车", "轿车", "车辆", "车", "car", "vehicle")), + ("street_lamp", ("路灯", "街灯", "灯杆", "street lamp", "streetlight", "lamp post")), + ("person", ("人", "人物", "行人", "学生", "孩子", "一个人", "两个人", "person", "people", "human", "pedestrian")), + ("tree", ("树", "树林", "树木", "一棵树", "tree", "trees")), + ("cloud", ("云", "云朵", "cloud")), + ("sun", ("太阳", "阳光", "sun")), + ("dog", ("狗", "小狗", "犬", "dog")), + ("table", ("桌", "桌子", "table")), + ("chair", ("椅", "椅子", "chair")), + ("desk_lamp", ("台灯", "桌灯", "desk lamp")), + ]: + if _contains_any(text, tokens) or _contains_any(lowered, tokens): + add(key) + return keys[:8] + + +def _simple_background_layers(scene_type: str, width: int, height: int, assets: List[str]) -> List[Dict[str, Any]]: + if scene_type == "process": + return [ + {"id": "bg_process_sky", "type": "sky", "label": "天空", "x": 0, "y": 0, "width": width, "height": int(height * 0.58), "z_index": -20, "source": "auto"}, + {"id": "bg_process_ground", "type": "ground", "label": "地面", "x": 0, "y": int(height * 0.58), "width": width, "height": int(height * 0.42), "z_index": -19, "source": "auto"}, + ] + if scene_type == "schematic": + return [] + layers = [ + {"id": "bg_sky", "type": "sky", "label": "天空", "x": 0, "y": 0, "width": width, "height": int(height * 0.54), "z_index": -20, "source": "auto"}, + {"id": "bg_ground", "type": "ground", "label": "地面", "x": 0, "y": int(height * 0.56), "width": width, "height": int(height * 0.44), "z_index": -19, "source": "auto"}, + ] + if "road" in assets: + layers.append({"id": "bg_road", "type": "road", "label": "道路", "x": int(width * 0.1), "y": int(height * 0.62), "width": int(width * 0.8), "height": int(height * 0.2), "z_index": -18, "source": "auto"}) + return layers + + +def _query_scene_object_seed( + asset_key: str, + *, + scene_assets: List[str], + index: int, +) -> Tuple[float, float, str, str]: + has_person = "person" in scene_assets + has_house = any(item in {"house", "building"} for item in scene_assets) + house_on_right = True + if has_house: + house_index = next((pos for pos, item in enumerate(scene_assets) if item in {"house", "building"}), 0) + house_on_right = (house_index % 2) == 0 + if asset_key == "road": + return 0.5, 0.78, "environment", "foreground" + if asset_key == "sun": + return 0.16 + 0.18 * (index % 3), 0.12, "detail", "background" + if asset_key == "cloud": + return 0.28 + 0.18 * (index % 3), 0.18, "detail", "background" + if asset_key in {"person", "dog"}: + return 0.48, 0.66, "subject", "foreground" + if asset_key == "car": + return 0.58, 0.72, "support", "foreground" + if asset_key in {"house", "building"}: + return (0.72 if house_on_right else 0.28), 0.5, ("support" if has_person else "subject"), "midground" + if asset_key == "tree": + if has_house: + return (0.22 if house_on_right else 0.78), 0.58, "support", "midground" + return (0.26 if (index % 2 == 0) else 0.74), 0.58, "support", "midground" + if asset_key == "street_lamp": + return (0.12 if house_on_right else 0.88), 0.62, "detail", "foreground" + if asset_key in {"table", "chair", "desk_lamp"}: + return 0.5 + (0.08 if index % 2 else -0.08), 0.6, ("subject" if not has_person else "detail"), "midground" + fallback_slots = [ + (0.32, 0.56, "subject", "midground"), + (0.68, 0.52, "support", "midground"), + (0.22, 0.62, "detail", "foreground"), + (0.78, 0.26, "detail", "background"), + (0.18, 0.24, "detail", "background"), + ] + return fallback_slots[min(index, len(fallback_slots) - 1)] + + +def _query_process_object_seed(asset_key: str, index: int) -> Tuple[float, float, str, str]: + slots = { + "sun": (0.16, 0.16, "support", "background"), + "cloud": (0.58, 0.22, "subject", "background"), + "vapor": (0.34, 0.48, "detail", "midground"), + "raindrop": (0.64, 0.48, "detail", "midground"), + "leaf": (0.54, 0.74, "subject", "foreground"), + "airplane": (0.48, 0.26, "subject", "background"), + "cell": (0.50, 0.58, "subject", "midground"), + "energy_wave": (0.28, 0.34, "detail", "background"), + } + fallback_slots = [ + (0.22, 0.58, "subject", "midground"), + (0.50, 0.34, "support", "background"), + (0.72, 0.58, "detail", "midground"), + (0.38, 0.74, "detail", "foreground"), + ] + return slots.get(asset_key, fallback_slots[min(index, len(fallback_slots) - 1)]) + + +def _query_schematic_object_seed(asset_key: str, index: int) -> Tuple[float, float, str, str]: + slots = { + "battery": (0.18, 0.54, "subject", "midground"), + "switch": (0.42, 0.34, "subject", "foreground"), + "resistor": (0.50, 0.54, "subject", "midground"), + "led": (0.78, 0.54, "subject", "midground"), + "capacitor": (0.48, 0.76, "detail", "midground"), + "diode": (0.66, 0.34, "detail", "midground"), + "board": (0.50, 0.54, "support", "background"), + } + fallback_slots = [ + (0.24, 0.54, "subject", "midground"), + (0.50, 0.34, "subject", "foreground"), + (0.76, 0.54, "subject", "midground"), + (0.50, 0.76, "detail", "midground"), + ] + return slots.get(asset_key, fallback_slots[min(index, len(fallback_slots) - 1)]) + + +def _compose_query_only_scene(query: str, canvas_size: Tuple[int, int], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any] | None: + scene_type = _infer_scene_type_from_query(query) + assets = _collect_query_assets(query, scene_type) + if not assets: + return None + width, height = canvas_size + objects: List[Dict[str, Any]] = [] + connectors: List[Dict[str, Any]] = [] + backgrounds = _simple_background_layers(scene_type, width, height, assets) + + object_assets = [item for item in assets if not (scene_type == "scene" and item == "road")] + for index, asset_key in enumerate(object_assets): + asset = get_asset_definition(asset_key) + default_width, default_height = asset.get("default_size", (160, 120)) + if scene_type == "scene": + px, py, role, depth = _query_scene_object_seed( + asset_key, + scene_assets=object_assets, + index=index, + ) + if asset_key == "road": + default_width = int(width * 0.72) + default_height = int(height * 0.18) + elif scene_type == "process": + px, py, role, depth = _query_process_object_seed(asset_key, index) + else: + px, py, role, depth = _query_schematic_object_seed(asset_key, index) + if asset_key == "board": + default_width = int(width * 0.58) + default_height = int(height * 0.44) + + obj_width = int(default_width if scene_type != "schematic" else default_width * 0.92) + obj_height = int(default_height if scene_type != "schematic" else default_height * 0.92) + objects.append( + { + "id": f"obj_{index + 1}", + "concept": asset.get("label", asset_key), + "asset_key": asset_key, + "source": "auto", + "role": role, + "depth_band": depth, + "x": int(width * px - obj_width / 2), + "y": int(height * py - obj_height / 2), + "width": obj_width, + "height": obj_height, + "rotation": 0, + "scale": 1, + "z_index": 20 + index, + "editable": True, + } + ) + + if scene_type == "process": + connectors = [] + elif scene_type == "schematic": + for index in range(len(objects) - 1): + connectors.append( + { + "id": f"conn_{index + 1}", + "type": "wire", + "from_id": objects[index]["id"], + "to_id": objects[index + 1]["id"], + "label": "连接", + "visible": True, + } + ) + + scene = { + "version": 2, + "canvas_size": {"width": width, "height": height}, + "layout_options": { + "scene_type": scene_type, + "composition_mode": scene_type, + "sketch_style": _clean_text((sketch_options or {}).get("sketch_style") or _preferred_scene_style(scene_type)), + "show_grid": bool((sketch_options or {}).get("show_grid", True)), + "show_labels": bool((sketch_options or {}).get("show_labels", False)), + "show_guides": bool((sketch_options or {}).get("show_guides", False)), + "layout_engine": _clean_text((sketch_options or {}).get("layout_engine") or "auto") or "auto", + "layout_candidate_count": int((sketch_options or {}).get("layout_candidate_count", 4) or 4), + }, + "background_layers": backgrounds, + "object_instances": objects, + "attachments": [], + "connectors": connectors, + "render_hints": { + "scene_summary": query[:48], + }, + "concept_order": [item["concept"] for item in objects], + } + return apply_natural_layout(scene, sketch_options) + + +def _prefer_sd_semantic_upstream(sketch_options: Dict[str, Any] | None = None) -> bool: + backend = _clean_text((sketch_options or {}).get("sketch_backend")).lower() + return backend in {"sd", "sketch_v2"} + + +def _scene_query_asset_gap(scene: Dict[str, Any], query: str) -> Tuple[str, List[str], List[str], List[str], int]: + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or _infer_scene_type_from_query(query)) + query_assets = _collect_query_assets(query, scene_type) + current_assets = [str(item.get("asset_key") or "") for item in scene.get("object_instances", []) or []] + missing_query_assets = [item for item in query_assets if item not in current_assets] + generic_assets = {"module", "branch", "road", "blob", "generic_object", "generic_panel", "flow_node", "capsule"} + generic_count = sum(1 for item in current_assets if item in generic_assets) + return scene_type, query_assets, current_assets, missing_query_assets, generic_count + + +def _scene_needs_query_boost( + scene: Dict[str, Any], + query: str, + sketch_options: Dict[str, Any] | None = None, +) -> bool: + scene_type, query_assets, current_assets, missing_query_assets, generic_count = _scene_query_asset_gap(scene, query) + if not query_assets: + return False + if not current_assets: + return True + if _prefer_sd_semantic_upstream(sketch_options): + strong_scene_assets = { + "building", + "house", + "road", + "car", + "street_lamp", + "person", + "tree", + "dog", + "table", + "chair", + "desk_lamp", + } + if len(current_assets) <= 1 and len(query_assets) >= 2 and bool(missing_query_assets): + return True + if scene_type == "scene" and generic_count > 0 and len(query_assets) >= 2: + return True + if scene_type == "process": + explicit_process_assets = {"sun", "vapor", "cloud", "raindrop", "leaf", "airplane", "cell"} + if any(item in {"cycle", "flow_node", "branch"} for item in current_assets): + return True + if explicit_process_assets.intersection(query_assets) and len(explicit_process_assets.intersection(current_assets)) < len(explicit_process_assets.intersection(query_assets)): + return True + if scene_type == "schematic": + explicit_schematic_assets = {"battery", "resistor", "led", "capacitor", "diode", "board", "switch"} + if any(item in {"module", "branch", "road"} for item in current_assets): + return True + if explicit_schematic_assets.intersection(query_assets) and len(explicit_schematic_assets.intersection(current_assets)) < len(explicit_schematic_assets.intersection(query_assets)): + return True + if generic_count >= max(1, len(current_assets) - 1) and bool(missing_query_assets): + return True + if strong_scene_assets.intersection(missing_query_assets) and len(missing_query_assets) >= max(1, len(query_assets) // 2): + return True + if scene_type == "schematic": + specific_assets = {"battery", "resistor", "led", "capacitor", "diode", "board", "switch"} + return bool(specific_assets.intersection(query_assets)) and bool(missing_query_assets) + if scene_type == "process": + return generic_count >= max(1, len(current_assets) // 2) and bool(missing_query_assets) + return generic_count == len(current_assets) and bool(missing_query_assets) + + +def _strip_sd_symbolic_objects(scene: Dict[str, Any], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + if not _prefer_sd_semantic_upstream(sketch_options): + return scene + + scene_type = _clean_text(scene.get("layout_options", {}).get("scene_type") or "scene") + width = int(scene.get("canvas_size", {}).get("width", CANVAS_DEFAULT[0]) or CANVAS_DEFAULT[0]) + height = int(scene.get("canvas_size", {}).get("height", CANVAS_DEFAULT[1]) or CANVAS_DEFAULT[1]) + kept_objects: List[Dict[str, Any]] = [] + kept_ids: set[str] = set() + removed_ids: set[str] = set() + + for obj in scene.get("object_instances", []) or []: + item = _copy(obj) + object_id = _clean_text(item.get("id")) + concept = _clean_text(item.get("concept") or item.get("label")) + asset_key = _clean_text(item.get("asset_key") or item.get("silhouette_key")).lower() + + if scene_type == "process": + if asset_key in {"cycle", "flow_node", "branch", "capsule", "generic_panel", "generic_object", "blob"}: + if object_id: + removed_ids.add(object_id) + continue + if _is_generic_process_stage(concept) and asset_key in {"energy_wave", "cycle", "flow_node", "branch"}: + if object_id: + removed_ids.add(object_id) + continue + elif scene_type == "schematic": + if _is_switch_like_concept(concept): + item["asset_key"] = "switch" + item["silhouette_key"] = "switch" + elif asset_key in {"branch", "road", "generic_panel", "generic_object", "blob"}: + if object_id: + removed_ids.add(object_id) + continue + elif asset_key == "module": + if object_id: + removed_ids.add(object_id) + continue + elif asset_key == "board" and not _is_explicit_board_concept(concept): + if object_id: + removed_ids.add(object_id) + continue + if concept and _contains_any(concept, ("电路结构", "可编辑", "结构说明", "直接编辑")): + if object_id: + removed_ids.add(object_id) + continue + + kept_objects.append(item) + if object_id: + kept_ids.add(object_id) + + scene["object_instances"] = kept_objects + scene["concept_order"] = [_clean_text(item.get("concept")) for item in kept_objects if _clean_text(item.get("concept"))] + scene["attachments"] = [ + item + for item in scene.get("attachments", []) or [] + if str(item.get("host_id") or "") in kept_ids and str(item.get("child_id") or "") in kept_ids + ] + if scene_type == "process": + scene["connectors"] = [] + scene["background_layers"] = _simple_background_layers("process", width, height, []) + elif scene_type == "schematic": + normalized_connectors: List[Dict[str, Any]] = [] + seen_pairs: set[Tuple[str, str]] = set() + for item in scene.get("connectors", []) or []: + from_id = str(item.get("from_id") or "") + to_id = str(item.get("to_id") or "") + if str(item.get("type") or "").strip().lower() != "wire" or from_id not in kept_ids or to_id not in kept_ids: + continue + pair_key = (from_id, to_id) + if pair_key in seen_pairs: + continue + cleaned = _copy(item) + cleaned["type"] = "wire" + cleaned["label"] = _normalize_schematic_connector_label(cleaned.get("label")) + cleaned["visible"] = True + normalized_connectors.append(cleaned) + seen_pairs.add(pair_key) + scene["connectors"] = normalized_connectors + scene["background_layers"] = [ + item for item in scene.get("background_layers", []) or [] if str(item.get("type") or "").strip().lower() not in {"board", "process_band"} + ] + else: + scene["connectors"] = [ + item + for item in scene.get("connectors", []) or [] + if str(item.get("from_id") or "") in kept_ids and str(item.get("to_id") or "") in kept_ids + ] + scene["background_layers"] = [ + item for item in scene.get("background_layers", []) or [] if str(item.get("type") or "").strip().lower() != "process_band" + ] + + hints = dict(scene.get("render_hints") or {}) + hints["sd_upstream_cleanup"] = { + "applied": True, + "scene_type": scene_type, + "removed_ids": sorted(item for item in removed_ids if item), + } + scene["render_hints"] = hints + return scene + + +def _merge_query_boost_scene( + base_scene: Dict[str, Any], + fallback_scene: Dict[str, Any], + query: str, + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + merged = _copy(fallback_scene) + base_scene = base_scene if isinstance(base_scene, dict) else {} + base_hints = _copy(base_scene.get("render_hints") or {}) + merged_hints = _copy(merged.get("render_hints") or {}) + merged["canvas_size"] = _copy(base_scene.get("canvas_size") or merged.get("canvas_size") or {}) + merged["render_hints"] = { + **base_hints, + **merged_hints, + "scene_summary": _clean_text(merged_hints.get("scene_summary") or base_hints.get("scene_summary") or query[:48]), + "query_boost_applied": True, + "query_boost_reason": "sd_upstream_scene_rebuild" if _prefer_sd_semantic_upstream(sketch_options) else "query_scene_rebuild", + "query_boost_query": _clean_text(query), + "query_boost_assets": _collect_query_assets(query, _clean_text((merged.get("layout_options") or {}).get("scene_type") or "scene")), + } + merged["layout_options"] = { + **_copy(base_scene.get("layout_options") or {}), + **_copy(merged.get("layout_options") or {}), + } + if _prefer_sd_semantic_upstream(sketch_options): + merged["layout_options"]["semantic_source"] = "query_boost_sd_upstream" + merged["concept_order"] = [item.get("concept") for item in merged.get("object_instances", []) or [] if item.get("concept")] + return merged + + +def normalize_scene_spec_v2(scene_spec: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + _sync_legacy() + scene = legacy.normalize_scene_spec_v2(scene_spec, sketch_options) + scene = _sanitize_scene(scene) + scene = _rebalance_generic_objects(scene) + scene = _strip_sd_symbolic_objects(scene, sketch_options) + scene = _apply_visual_metadata(scene) + scene = _soften_backgrounds(scene) + scene = _upgrade_layout_defaults(scene, sketch_options) + scene = apply_natural_layout(scene, sketch_options) + scene = _upgrade_render_hints(scene) + return scene + + +def legacy_scene_spec_to_v2(scene_spec: Dict[str, Any], sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + _sync_legacy() + legacy_scene = legacy.legacy_scene_spec_to_v2(scene_spec, sketch_options) + return normalize_scene_spec_v2(legacy_scene, sketch_options) + + +def compose_semantic_scene_spec( + query: str, + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, + best_path_concepts: List[str] | None = None, + canvas_size: Tuple[int, int] = CANVAS_DEFAULT, + sketch_options: Dict[str, Any] | None = None, +) -> Dict[str, Any]: + _sync_legacy() + base_scene = legacy.compose_semantic_scene_spec( + query=query, + understanding_result=understanding_result, + extraction_result=extraction_result, + answer_bundle=answer_bundle, + best_path_concepts=best_path_concepts, + canvas_size=canvas_size, + sketch_options=sketch_options, + ) + scene = normalize_scene_spec_v2(base_scene, sketch_options) + boost_needed = _scene_needs_query_boost(scene, query, sketch_options) + if scene.get("object_instances") and not boost_needed: + return scene + fallback_scene = _compose_query_only_scene(query, canvas_size, sketch_options) + if fallback_scene: + boosted_scene = _merge_query_boost_scene(scene, fallback_scene, query, sketch_options) + return normalize_scene_spec_v2(boosted_scene, sketch_options) + return scene + + +def summarize_scene_spec(scene_spec: Dict[str, Any] | None) -> str: + if not scene_spec: + return "" + scene = normalize_scene_spec_v2(scene_spec) + backgrounds = scene.get("background_layers", []) or [] + objects = scene.get("object_instances", []) or [] + attachments = scene.get("attachments", []) or [] + connectors = [item for item in scene.get("connectors", []) or [] if item.get("visible")] + hints = scene.get("render_hints", {}) or {} + bg_summary = ", ".join( + f"{item.get('label', item.get('type', 'layer'))}@({item.get('x', 0)},{item.get('y', 0)},{item.get('width', 0)}x{item.get('height', 0)})" + for item in backgrounds[:4] + ) + object_summary = ", ".join( + f"{item.get('concept', '')}[{item.get('prototype_id', item.get('asset_key', ''))}]@({item.get('x', 0)},{item.get('y', 0)},{item.get('width', 0)}x{item.get('height', 0)})/{item.get('depth_band', '')}" + for item in objects[:8] + ) + attachment_summary = ", ".join( + f"{item.get('child_id', '')}->{item.get('host_id', '')}:{item.get('anchor_name', '')}" + for item in attachments[:6] + ) + connector_summary = ", ".join( + f"{item.get('type', '')}:{item.get('label', '')} {item.get('from_id', '')}->{item.get('to_id', '')}" + for item in connectors[:6] + ) + parts = [ + f"scene_type={scene.get('layout_options', {}).get('scene_type', 'scene')}", + f"style={scene.get('layout_options', {}).get('sketch_style', 'scribble_line')}", + f"view={scene.get('layout_options', {}).get('sketch_view_mode', 'structure')}", + f"backgrounds={bg_summary}" if bg_summary else "", + f"objects={object_summary}" if object_summary else "", + f"attachments={attachment_summary}" if attachment_summary else "", + f"connectors={connector_summary}" if connector_summary else "", + hints.get("scene_summary", ""), + hints.get("subject_summary", ""), + hints.get("prototype_summary", ""), + hints.get("user_added_summary", ""), + hints.get("edit_summary", ""), + ] + return " | ".join(part for part in parts if part) + + +def scene_spec_counts(scene_spec: Dict[str, Any] | None) -> Tuple[int, int]: + if not scene_spec: + return 0, 0 + scene = normalize_scene_spec_v2(scene_spec) + return len(scene.get("object_instances", []) or []), len(scene.get("connectors", []) or []) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/session_memory.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/session_memory.py new file mode 100644 index 0000000..23c8489 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/session_memory.py @@ -0,0 +1,620 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +import re +from typing import Any, Dict, Iterable, List + + +_GOAL_MARKERS = ( + "目标", + "想要", + "希望", + "实现", + "做成", + "达成", + "验证", + "评估", + "提升", + "重构", + "升级", + "训练", + "支持", + "切换", +) +_PREFERENCE_MARKERS = ( + "默认", + "优先", + "保留", + "保持", + "透明", + "自然", + "可解释", + "开源", + "本地", +) +_CONSTRAINT_MARKERS = ( + "不要", + "必须", + "不能", + "仅", + "只做", + "只用", + "禁止", +) +_VAGUE_QUERY_MARKERS = ( + "继续", + "接着", + "然后", + "当前计划", + "这个体系", + "这个系统", + "方案", + "当前", +) +_RELATION_BY_CATEGORY = { + "goal": "session_goal", + "preference": "prefers", + "terminology": "uses_term", + "constraint": "constrained_by", + "stage_state": "stage_state", +} +_TYPE_BY_CATEGORY = { + "goal": "session_goal", + "preference": "session_preference", + "terminology": "session_term", + "constraint": "session_constraint", + "stage_state": "session_stage", +} + + +def _clean_text(value: Any) -> str: + text = str(value or "").strip() + text = re.sub(r"\s+", " ", text) + return text + + +def _normalize_key(value: Any) -> str: + return _clean_text(value).lower() + + +def _clip_text(value: Any, max_len: int = 72) -> str: + text = _clean_text(value) + if len(text) <= max_len: + return text + return text[: max_len - 3].rstrip() + "..." + + +def _dedupe_texts(values: Iterable[Any], max_items: int | None = None) -> List[str]: + items: List[str] = [] + seen = set() + for value in values: + text = _clean_text(value) + if not text: + continue + key = _normalize_key(text) + if key in seen: + continue + seen.add(key) + items.append(text) + if max_items is not None and len(items) >= max_items: + break + return items + + +def _split_fragments(text: str) -> List[str]: + text = _clean_text(text) + if not text: + return [] + fragments = re.split(r"[,,。;;!!??\n]+", text) + return _dedupe_texts(fragments) + + +def _contains_any(text: str, markers: Iterable[str]) -> bool: + return any(marker in text for marker in markers) + + +def _match_fragments(text: str, markers: Iterable[str], max_items: int = 2) -> List[str]: + matched = [fragment for fragment in _split_fragments(text) if _contains_any(fragment, markers)] + return _dedupe_texts(matched, max_items=max_items) + + +def _concept_order( + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> List[str]: + concepts: List[str] = [] + if isinstance(answer_bundle, dict): + concepts.extend(answer_bundle.get("core_concepts", []) or []) + focus = answer_bundle.get("focus_concept") + if focus: + concepts.insert(0, focus) + if isinstance(understanding_result, dict): + focus = understanding_result.get("focus_concept") + if focus: + concepts.insert(0, focus) + if isinstance(extraction_result, dict): + for item in extraction_result.get("concepts", []) or []: + if isinstance(item, dict): + concepts.append(item.get("concept", "")) + return _dedupe_texts(concepts, max_items=12) + + +_TOKEN_RE = re.compile(r"[a-z0-9_]+|[\u4e00-\u9fff]", re.IGNORECASE) + + +def _token_set(value: Any) -> set[str]: + text = _normalize_key(value) + if not text: + return set() + return {token for token in _TOKEN_RE.findall(text) if token} + + +def _category_slot_key(category: str, value: str) -> str: + normalized_category = _normalize_key(category) + if normalized_category == "goal": + return "goal.primary" + if normalized_category == "preference": + return "preference.active" + if normalized_category == "constraint": + return "constraint.active" + if normalized_category == "stage_state": + return "stage.current" + if normalized_category == "terminology": + return f"terminology.{_normalize_key(value)[:24]}" + return f"{normalized_category}.{_normalize_key(value)[:24]}" + + +def _anchor_signature(anchors: Iterable[Any]) -> str: + normalized = sorted({_normalize_key(anchor) for anchor in anchors if _clean_text(anchor)}) + return "|".join(normalized) + + +def _state_signature(*, category: str, slot_key: str, anchors: Iterable[Any]) -> str: + components = [_normalize_key(category), _normalize_key(slot_key), _anchor_signature(anchors)] + return "|".join(component for component in components if component) + + +def _memory_signature(*, category: str, value: str, slot_key: str, anchors: Iterable[Any]) -> str: + components = [ + _state_signature(category=category, slot_key=slot_key, anchors=anchors), + _normalize_key(value), + ] + return "|".join(component for component in components if component) + + +def _event_signature(*, category: str, value: str, slot_key: str, anchors: Iterable[Any]) -> str: + category_label = _normalize_key(category).replace("_", " ") + slot_label = _normalize_key(slot_key).replace(".", " ").replace("_", " ") + parts = [category_label, slot_label] + parts.extend(_clean_text(anchor) for anchor in anchors if _clean_text(anchor)) + parts.append(_clean_text(value)) + return " ".join(_dedupe_texts(parts, max_items=8)) + + +@dataclass(slots=True) +class SessionMemoryRecord: + memory_id: str + category: str + value: str + relation: str + anchor_concepts: List[str] = field(default_factory=list) + salience: float = 0.6 + confidence: float = 0.6 + source_kind: str = "session_memory" + turn_index: int = 0 + metadata: Dict[str, Any] = field(default_factory=dict) + + def key(self) -> tuple[str, str, str]: + anchor_key = "|".join(sorted(_normalize_key(item) for item in self.anchor_concepts)) + return (_normalize_key(self.category), _normalize_key(self.value), anchor_key) + + def to_dict(self) -> Dict[str, Any]: + return { + "memory_id": self.memory_id, + "category": self.category, + "value": self.value, + "relation": self.relation, + "anchor_concepts": list(self.anchor_concepts), + "salience": round(float(self.salience), 4), + "confidence": round(float(self.confidence), 4), + "source_kind": self.source_kind, + "turn_index": int(self.turn_index), + "metadata": dict(self.metadata), + } + + def to_hit(self, relevance: float) -> Dict[str, Any]: + return { + "memory_id": self.memory_id, + "category": self.category, + "value": self.value, + "relation": self.relation, + "anchors": list(self.anchor_concepts), + "salience": round(float(self.salience), 4), + "confidence": round(float(self.confidence), 4), + "relevance": round(float(relevance), 4), + "source_kind": self.source_kind, + "turn_index": int(self.turn_index), + "metadata": dict(self.metadata), + } + + +class SessionMemoryExtractor: + def extract( + self, + query: str, + understanding_result: Dict[str, Any] | None = None, + extraction_result: Dict[str, Any] | None = None, + answer_bundle: Dict[str, Any] | None = None, + *, + answer_mode: str = "natural", + turn_index: int = 0, + ) -> List[SessionMemoryRecord]: + query_text = _clean_text(query) + if not query_text: + return [] + + anchors = _concept_order(understanding_result, extraction_result, answer_bundle) + records: List[SessionMemoryRecord] = [] + + for constraint in self._extract_constraints(query_text, understanding_result): + records.append( + self._make_record( + category="constraint", + value=constraint, + anchors=anchors, + salience=0.88, + confidence=0.82, + turn_index=turn_index, + ) + ) + + for preference in self._extract_preferences(query_text, answer_mode): + records.append( + self._make_record( + category="preference", + value=preference, + anchors=anchors, + salience=0.82, + confidence=0.8, + turn_index=turn_index, + ) + ) + + for goal in self._extract_goals(query_text, anchors): + records.append( + self._make_record( + category="goal", + value=goal, + anchors=anchors, + salience=0.9, + confidence=0.78, + turn_index=turn_index, + ) + ) + + for stage_state in self._extract_stage_states(query_text): + records.append( + self._make_record( + category="stage_state", + value=stage_state, + anchors=anchors, + salience=0.74, + confidence=0.72, + turn_index=turn_index, + ) + ) + + for term in self._extract_terms(query_text, anchors): + records.append( + self._make_record( + category="terminology", + value=term, + anchors=[term], + salience=0.64, + confidence=0.68, + turn_index=turn_index, + ) + ) + + merged: Dict[tuple[str, str, str], SessionMemoryRecord] = {} + for record in records: + key = record.key() + existing = merged.get(key) + if existing is None: + merged[key] = record + continue + existing.salience = max(existing.salience, record.salience) + existing.confidence = max(existing.confidence, record.confidence) + existing.turn_index = max(existing.turn_index, record.turn_index) + existing.anchor_concepts = _dedupe_texts([*existing.anchor_concepts, *record.anchor_concepts], max_items=8) + return list(merged.values()) + + def _make_record( + self, + *, + category: str, + value: str, + anchors: List[str], + salience: float, + confidence: float, + turn_index: int, + ) -> SessionMemoryRecord: + clean_value = _clip_text(value) + clean_anchors = _dedupe_texts(anchors, max_items=6) + slot_key = _category_slot_key(category, clean_value) + state_signature = _state_signature(category=category, slot_key=slot_key, anchors=clean_anchors) + memory_signature = _memory_signature(category=category, value=clean_value, slot_key=slot_key, anchors=clean_anchors) + event_signature = _event_signature(category=category, value=clean_value, slot_key=slot_key, anchors=clean_anchors) + memory_id = f"{category}:{_normalize_key(clean_value)}" + return SessionMemoryRecord( + memory_id=memory_id, + category=category, + value=clean_value, + relation=_RELATION_BY_CATEGORY.get(category, "related_to"), + anchor_concepts=clean_anchors, + salience=max(0.0, min(1.0, float(salience))), + confidence=max(0.0, min(1.0, float(confidence))), + turn_index=int(turn_index), + metadata={ + "slot_key": slot_key, + "state_signature": state_signature, + "memory_signature": memory_signature, + "event_signature": event_signature, + "anchor_signature": _anchor_signature(clean_anchors), + }, + ) + + def _extract_goals(self, query_text: str, anchors: List[str]) -> List[str]: + goals = _match_fragments(query_text, _GOAL_MARKERS, max_items=2) + if goals: + return goals + if _contains_any(query_text, ("继续", "接着")) and anchors: + return [f"围绕 {anchors[0]} 持续推进"] + return [] + + def _extract_preferences(self, query_text: str, answer_mode: str) -> List[str]: + preferences: List[str] = [] + lowered = query_text.lower() + if "transparent" in lowered or "透明" in query_text or "可解释" in query_text or answer_mode == "transparent": + preferences.append("transparent_mode") + if "natural" in lowered or "自然" in query_text or answer_mode == "natural": + preferences.append("natural_mode") + if "开源" in query_text: + preferences.append("prefer_open_models") + if any(marker in query_text for marker in ("本地", "离线", "私有部署")): + preferences.append("prefer_local_modules") + if _contains_any(query_text, _PREFERENCE_MARKERS): + preferences.extend(_match_fragments(query_text, _PREFERENCE_MARKERS, max_items=2)) + return _dedupe_texts(preferences, max_items=4) + + def _extract_constraints(self, query_text: str, understanding_result: Dict[str, Any] | None) -> List[str]: + constraints: List[str] = [] + if isinstance(understanding_result, dict): + constraints.extend(understanding_result.get("constraints", []) or []) + constraints.extend(_match_fragments(query_text, _CONSTRAINT_MARKERS, max_items=3)) + return [_clip_text(item, max_len=64) for item in _dedupe_texts(constraints, max_items=4)] + + def _extract_terms(self, query_text: str, anchors: List[str]) -> List[str]: + terms: List[str] = [] + for anchor in anchors[:6]: + if len(anchor) >= 2 and anchor in query_text: + terms.append(anchor) + english_terms = re.findall(r"[A-Za-z][A-Za-z0-9_-]{1,}", query_text) + terms.extend(english_terms[:4]) + return _dedupe_texts(terms, max_items=6) + + def _extract_stage_states(self, query_text: str) -> List[str]: + states: List[str] = [] + if "继续" in query_text or "接着" in query_text: + states.append("continue_current_plan") + if "开始" in query_text or "启动" in query_text: + states.append("execution_started") + if "验证" in query_text or "测试" in query_text or "smoke" in query_text.lower(): + states.append("validation_phase") + if "训练" in query_text: + states.append("training_phase") + if "实施" in query_text or "落地" in query_text or "重构" in query_text: + states.append("implementation_phase") + return _dedupe_texts(states, max_items=3) + + +class SessionMemoryGraph: + def __init__(self, records: Iterable[SessionMemoryRecord] | None = None, turn_index: int = 0): + self.turn_index = int(turn_index) + self._records: Dict[tuple[str, str, str], SessionMemoryRecord] = {} + for record in records or []: + self.add_records([record]) + + @classmethod + def from_dict(cls, payload: Dict[str, Any] | None) -> "SessionMemoryGraph": + if not isinstance(payload, dict): + return cls() + records = [] + for item in payload.get("records", []) or []: + if not isinstance(item, dict): + continue + records.append( + SessionMemoryRecord( + memory_id=_clean_text(item.get("memory_id")), + category=_clean_text(item.get("category")), + value=_clean_text(item.get("value")), + relation=_clean_text(item.get("relation")) or "related_to", + anchor_concepts=_dedupe_texts(item.get("anchor_concepts", []) or [], max_items=8), + salience=float(item.get("salience", 0.6) or 0.6), + confidence=float(item.get("confidence", 0.6) or 0.6), + source_kind=_clean_text(item.get("source_kind")) or "session_memory", + turn_index=int(item.get("turn_index", 0) or 0), + metadata=dict(item.get("metadata") or {}), + ) + ) + return cls(records=records, turn_index=int(payload.get("turn_index", 0) or 0)) + + def to_dict(self) -> Dict[str, Any]: + return { + "turn_index": int(self.turn_index), + "records": [record.to_dict() for record in self.records()], + } + + def next_turn(self) -> int: + self.turn_index += 1 + return self.turn_index + + def records(self) -> List[SessionMemoryRecord]: + ordered = sorted( + self._records.values(), + key=lambda item: (item.turn_index, item.salience, item.confidence), + reverse=True, + ) + return ordered + + def record_count(self) -> int: + return len(self._records) + + def add_records(self, records: Iterable[SessionMemoryRecord]) -> int: + stored = 0 + for record in records: + key = record.key() + existing = self._records.get(key) + if existing is None: + self._records[key] = record + stored += 1 + continue + existing.salience = max(existing.salience, record.salience) + existing.confidence = max(existing.confidence, record.confidence) + existing.turn_index = max(existing.turn_index, record.turn_index) + existing.anchor_concepts = _dedupe_texts([*existing.anchor_concepts, *record.anchor_concepts], max_items=8) + existing.metadata.update(record.metadata) + return stored + + def build_context( + self, + query: str, + understanding_result: Dict[str, Any] | None = None, + extraction_result: Dict[str, Any] | None = None, + answer_bundle: Dict[str, Any] | None = None, + *, + max_records: int = 8, + ) -> Dict[str, Any]: + anchors = _concept_order(understanding_result, extraction_result, answer_bundle) + query_text = _clean_text(query) + vague_query = not anchors or _contains_any(query_text, _VAGUE_QUERY_MARKERS) + ranked: List[tuple[float, SessionMemoryRecord]] = [] + for record in self.records(): + relevance = self._relevance_score(record, query=query_text, anchors=anchors, vague_query=vague_query) + if relevance <= 0.0: + continue + ranked.append((relevance, record)) + ranked.sort(key=lambda item: item[0], reverse=True) + selected = ranked[: max(0, int(max_records))] + + concepts: Dict[str, Dict[str, Any]] = {} + relations: List[Dict[str, Any]] = [] + memory_hits: List[Dict[str, Any]] = [] + relation_seen = set() + + for relevance, record in selected: + target = record.value + concepts.setdefault( + target, + { + "concept": target, + "type": _TYPE_BY_CATEGORY.get(record.category, "session_memory"), + "source_kind": "session_memory", + }, + ) + + relation_added = False + for anchor in record.anchor_concepts[:4]: + if not anchor or anchor == target: + continue + concepts.setdefault(anchor, {"concept": anchor, "type": "general"}) + relation_key = (anchor, target, record.relation) + if relation_key not in relation_seen: + relation_seen.add(relation_key) + relations.append( + { + "from": anchor, + "to": target, + "relation": record.relation, + "weight": round(max(0.35, min(0.95, 0.45 + record.salience * 0.4)), 4), + "source_kind": "session_memory", + "memory_id": record.memory_id, + } + ) + back_key = (target, anchor, "context_for") + if back_key not in relation_seen: + relation_seen.add(back_key) + relations.append( + { + "from": target, + "to": anchor, + "relation": "context_for", + "weight": round(max(0.25, min(0.85, 0.3 + record.confidence * 0.35)), 4), + "source_kind": "session_memory", + "memory_id": record.memory_id, + } + ) + relation_added = True + + if not relation_added and anchors: + anchor = anchors[0] + if anchor and anchor != target: + relation_key = (anchor, target, record.relation) + if relation_key not in relation_seen: + relation_seen.add(relation_key) + relations.append( + { + "from": anchor, + "to": target, + "relation": record.relation, + "weight": round(max(0.35, min(0.95, 0.45 + record.salience * 0.4)), 4), + "source_kind": "session_memory", + "memory_id": record.memory_id, + } + ) + + memory_hits.append(record.to_hit(relevance)) + + return { + "concepts": list(concepts.values()), + "relations": relations, + "memory_hits": memory_hits, + } + + def _relevance_score(self, record: SessionMemoryRecord, *, query: str, anchors: List[str], vague_query: bool) -> float: + query_tokens = _token_set(query) + anchor_set = {_normalize_key(item) for item in anchors} + record_anchor_set = {_normalize_key(item) for item in record.anchor_concepts} + overlap = len(anchor_set & record_anchor_set) + value_overlap = len(query_tokens & _token_set(record.value)) + metadata = dict(record.metadata or {}) + slot_key_tokens = _token_set(metadata.get("slot_key", "")) + state_signature_tokens = _token_set(metadata.get("state_signature", "")) + memory_signature_tokens = _token_set(metadata.get("memory_signature", "")) + event_signature_tokens = _token_set(metadata.get("event_signature", "")) + recency = 1.0 if self.turn_index <= 0 else max(0.0, 1.0 - ((self.turn_index - record.turn_index) / max(1.0, float(self.turn_index)))) + score = record.salience * 0.5 + record.confidence * 0.25 + recency * 0.15 + if overlap > 0: + score += min(0.4, overlap * 0.15) + if value_overlap > 0: + score += min(0.22, value_overlap * 0.08) + if query_tokens and event_signature_tokens: + score += min(0.22, (len(query_tokens & event_signature_tokens) / max(1, len(query_tokens))) * 0.22) + if query_tokens and slot_key_tokens: + score += min(0.16, (len(query_tokens & slot_key_tokens) / max(1, len(query_tokens))) * 0.16) + if query_tokens and state_signature_tokens: + score += min(0.18, (len(query_tokens & state_signature_tokens) / max(1, len(query_tokens))) * 0.18) + if query_tokens and memory_signature_tokens: + score += min(0.24, (len(query_tokens & memory_signature_tokens) / max(1, len(query_tokens))) * 0.24) + elif not vague_query and overlap <= 0 and value_overlap <= 0: + score -= 0.18 + if vague_query and record.category in {"goal", "preference", "stage_state"}: + score += 0.12 + return max(0.0, min(1.5, score)) + + +def create_tmcra_reasoning_adapter(*, flags: Any | None = None) -> Any: + from core.tmcra_reasoning_runtime import create_reasoning_v2_shadow_adapter + + return create_reasoning_v2_shadow_adapter(flags=flags) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_edit_v1.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_edit_v1.py new file mode 100644 index 0000000..5f72051 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_edit_v1.py @@ -0,0 +1,1738 @@ +from __future__ import annotations + +import json +import math +import uuid +from pathlib import Path +from typing import Any, Dict, List + +from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter + + +DEPTH_BAND_Z = { + "background": 0.18, + "midground": 0.52, + "foreground": 0.84, +} + +DEFAULT_REGION_TRANSFORM = { + "tx": 0.0, + "ty": 0.0, + "scale_x": 1.0, + "scale_y": 1.0, + "rotation": 0.0, +} + +SUPPORTED_OPS = [ + "transform_object", + "set_depth", + "hide_object", + "show_object", + "reorder_layer", + "transform_region", + "hide_region", + "show_region", + "replace_region", + "emphasize_region", + "weaken_region", + "restore_region", + "erase_region", + "brush_mask", + "inpaint_region", +] + +REGION_ONLY_OPS = [ + "transform_region", + "hide_region", + "show_region", + "replace_region", + "emphasize_region", + "weaken_region", + "restore_region", + "inpaint_region", +] + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _slug(value: Any) -> str: + raw = "".join(ch if str(ch).isalnum() else "_" for ch in str(value or "").strip()) + raw = raw.strip("_") + return raw[:64] or "item" + + +def _int(value: Any, default: int = 0) -> int: + try: + return int(round(float(value))) + except Exception: + return int(default) + + +def _float(value: Any, default: float = 0.0) -> float: + try: + return float(value) + except Exception: + return float(default) + + +def _clamp_rect(rect: Dict[str, Any], width: int, height: int) -> Dict[str, int]: + x = max(0, min(width - 1, _int(rect.get("x"), 0))) + y = max(0, min(height - 1, _int(rect.get("y"), 0))) + w = max(1, _int(rect.get("width"), 1)) + h = max(1, _int(rect.get("height"), 1)) + if x + w > width: + w = max(1, width - x) + if y + h > height: + h = max(1, height - y) + return {"x": x, "y": y, "width": w, "height": h} + + +def _band_depth(depth_band: str, depth_z: Any = None) -> float: + if depth_z is not None: + try: + return max(0.0, min(1.0, float(depth_z))) + except Exception: + pass + return float(DEPTH_BAND_Z.get(str(depth_band or "midground"), DEPTH_BAND_Z["midground"])) + + +def _new_revision_id() -> str: + return f"esk_{uuid.uuid4().hex[:12]}" + + +def _default_region_transform() -> Dict[str, float]: + return dict(DEFAULT_REGION_TRANSFORM) + + +def _candidate_from_preview(preview: Dict[str, Any], candidate_id: str | None = None) -> Dict[str, Any] | None: + candidates = preview.get("sketch_candidates") + if not isinstance(candidates, list): + candidates = [] + marker = str(candidate_id or preview.get("active_sketch_candidate_id") or "").strip() + if marker: + for item in candidates: + if isinstance(item, dict) and str(item.get("candidate_id") or "").strip() == marker: + return _copy(item) + active_path = str(preview.get("active_sketch_path") or preview.get("image_path") or "").strip() + active_provider = str(preview.get("active_sketch_provider") or "").strip() + if active_path: + for item in candidates: + if isinstance(item, dict) and str(item.get("image_path") or "").strip() == active_path: + return _copy(item) + if active_path: + return { + "candidate_id": marker or "active", + "provider": active_provider or "unknown", + "image_path": active_path, + } + for item in candidates: + if isinstance(item, dict) and str(item.get("image_path") or "").strip(): + return _copy(item) + return None + + +def _estimate_background_rgb(image: Image.Image, *, stride: int = 4) -> tuple[int, int, int]: + rgb = image.convert("RGB") + width, height = rgb.size + border = max(1, min(width, height) // 18) + samples: List[tuple[int, int, int, int]] = [] + + def _push_pixel(px: int, py: int) -> None: + r, g, b = rgb.getpixel((px, py)) + luminance = int((r + g + b) / 3) + samples.append((luminance, r, g, b)) + + for x in range(0, width, max(1, stride)): + for y in range(0, min(height, border), max(1, stride)): + _push_pixel(x, y) + for y in range(max(0, height - border), height, max(1, stride)): + _push_pixel(x, y) + for y in range(border, max(border, height - border), max(1, stride)): + for x in range(0, min(width, border), max(1, stride)): + _push_pixel(x, y) + for x in range(max(0, width - border), width, max(1, stride)): + _push_pixel(x, y) + + if not samples: + return (248, 246, 241) + samples.sort(key=lambda item: item[0], reverse=True) + keep = samples[: max(1, len(samples) // 3)] + count = max(1, len(keep)) + return ( + int(round(sum(item[1] for item in keep) / count)), + int(round(sum(item[2] for item in keep) / count)), + int(round(sum(item[3] for item in keep) / count)), + ) + + +def _white_alpha_from_crop(crop: Image.Image) -> Image.Image: + rgb = crop.convert("RGB") + bg_r, bg_g, bg_b = _estimate_background_rgb(rgb, stride=3) + background_luma = int((bg_r + bg_g + bg_b) / 3) + alpha = Image.new("L", crop.size, 0) + src = rgb.load() + dst = alpha.load() + width, height = crop.size + for x in range(width): + for y in range(height): + r, g, b = src[x, y] + luminance = int((r + g + b) / 3) + contrast = max( + 0, + background_luma - luminance, + abs(r - bg_r), + abs(g - bg_g), + abs(b - bg_b), + ) + if contrast <= 12: + value = 0 + elif contrast >= 60: + value = 255 + else: + value = int((contrast - 12) * 255 / 48) + dst[x, y] = value + alpha = alpha.filter(ImageFilter.GaussianBlur(radius=0.8)) + alpha = alpha.point(lambda px: 0 if px < 14 else min(255, int(px * 1.08))) + return alpha + + +def _expand_box(box: Dict[str, int], canvas_width: int, canvas_height: int, padding: int) -> Dict[str, int]: + return _clamp_rect( + { + "x": box["x"] - padding, + "y": box["y"] - padding, + "width": box["width"] + padding * 2, + "height": box["height"] + padding * 2, + }, + canvas_width, + canvas_height, + ) + + +def _shape_mask(width: int, height: int, shape: str) -> Image.Image: + mask = Image.new("L", (max(1, width), max(1, height)), 0) + draw = ImageDraw.Draw(mask) + shape_name = str(shape or "rect").strip().lower() + if shape_name == "ellipse": + draw.ellipse([0, 0, max(0, width - 1), max(0, height - 1)], fill=255) + else: + draw.rounded_rectangle([0, 0, max(0, width - 1), max(0, height - 1)], radius=max(2, int(min(width, height) * 0.08)), fill=255) + return mask.filter(ImageFilter.GaussianBlur(radius=0.8)) + + +def _transform_is_default(transform: Dict[str, Any] | None) -> bool: + transform = transform if isinstance(transform, dict) else {} + return ( + abs(_float(transform.get("tx"), 0.0)) < 0.01 + and abs(_float(transform.get("ty"), 0.0)) < 0.01 + and abs(_float(transform.get("scale_x"), 1.0) - 1.0) < 0.01 + and abs(_float(transform.get("scale_y"), 1.0) - 1.0) < 0.01 + and abs(_float(transform.get("rotation"), 0.0)) < 0.01 + ) + + +def _normalize_region_action(value: str) -> str: + raw = str(value or "").strip().lower() + mapping = { + "transform_region": "transform", + "hide_region": "hide", + "show_region": "show", + "replace_region": "replace", + "emphasize_region": "emphasize", + "weaken_region": "weaken", + "restore_region": "restore", + "inpaint_region": "inpaint", + } + return mapping.get(raw, raw or "idle") + + +def _region_action_text(action: str) -> str: + mapping = { + "transform": "移动或变形", + "hide": "隐藏", + "show": "显示", + "replace": "替换", + "emphasize": "强调", + "weaken": "弱化", + "restore": "恢复", + "inpaint": "局部重绘", + "idle": "未编辑", + } + return mapping.get(str(action or "idle"), str(action or "未编辑")) + + +def _region_state_from_action(action: str) -> str: + mapping = { + "transform": "transformed", + "hide": "hidden", + "show": "shown", + "replace": "replaced", + "emphasize": "emphasized", + "weaken": "weakened", + "restore": "idle", + "inpaint": "inpainted", + } + return mapping.get(str(action or "transform"), "transformed") + + +def _rotate_point(x: float, y: float, center_x: float, center_y: float, angle_deg: float) -> tuple[float, float]: + if abs(angle_deg) < 0.01: + return x, y + radians = math.radians(angle_deg) + rel_x = x - center_x + rel_y = y - center_y + cos_v = math.cos(radians) + sin_v = math.sin(radians) + return ( + center_x + rel_x * cos_v - rel_y * sin_v, + center_y + rel_x * sin_v + rel_y * cos_v, + ) + + +def _resolve_object_layer(doc: Dict[str, Any], op: Dict[str, Any]) -> Dict[str, Any] | None: + wanted = str(op.get("object_id") or op.get("scene_object_id") or op.get("layer_id") or "").strip() + if not wanted: + return None + for item in doc.get("object_layers", []) or []: + if str(item.get("id") or "") == wanted or str(item.get("scene_object_id") or "") == wanted: + return item + return None + + +def _resolve_region_layer(doc: Dict[str, Any], op: Dict[str, Any]) -> Dict[str, Any] | None: + wanted = str(op.get("region_id") or op.get("region_layer_id") or "").strip() + parent_object_id = str(op.get("object_id") or "").strip() + for item in doc.get("region_layers", []) or []: + if not isinstance(item, dict): + continue + region_id = str(item.get("region_id") or item.get("id") or "").strip() + object_id = str(item.get("parent_object_id") or item.get("object_id") or "").strip() + if wanted and region_id != wanted: + continue + if parent_object_id and object_id != parent_object_id: + continue + if wanted or parent_object_id: + return item + return None + + +def _resolve_scene_object(scene_spec: Dict[str, Any], layer: Dict[str, Any]) -> Dict[str, Any] | None: + wanted = str(layer.get("scene_object_id") or layer.get("id") or "").strip() + for item in scene_spec.get("object_instances", []) or []: + if isinstance(item, dict) and str(item.get("id") or "").strip() == wanted: + return item + return None + + +def _object_rect_ratios(object_layer: Dict[str, Any], region: Dict[str, Any]) -> Dict[str, float]: + source_bbox = object_layer.get("source_bbox") if isinstance(object_layer.get("source_bbox"), dict) else {} + source_rect = region.get("source_rect") if isinstance(region.get("source_rect"), dict) else {} + source_width = max(1, _float(source_bbox.get("width"), 1.0)) + source_height = max(1, _float(source_bbox.get("height"), 1.0)) + return { + "x": (_float(source_rect.get("x"), 0.0) - _float(source_bbox.get("x"), 0.0)) / source_width, + "y": (_float(source_rect.get("y"), 0.0) - _float(source_bbox.get("y"), 0.0)) / source_height, + "width": _float(source_rect.get("width"), 0.0) / source_width, + "height": _float(source_rect.get("height"), 0.0) / source_height, + } + + +def _region_base_rect(object_layer: Dict[str, Any], region: Dict[str, Any]) -> Dict[str, float]: + ratios = region.get("source_rect_ratios") if isinstance(region.get("source_rect_ratios"), dict) else _object_rect_ratios(object_layer, region) + object_x = _float(object_layer.get("x"), 0.0) + object_y = _float(object_layer.get("y"), 0.0) + object_width = max(1.0, _float(object_layer.get("width"), 1.0)) + object_height = max(1.0, _float(object_layer.get("height"), 1.0)) + base_width = max(1.0, object_width * _float(ratios.get("width"), 0.0)) + base_height = max(1.0, object_height * _float(ratios.get("height"), 0.0)) + base_left = object_x + object_width * _float(ratios.get("x"), 0.0) + base_top = object_y + object_height * _float(ratios.get("y"), 0.0) + base_center_x = base_left + base_width / 2.0 + base_center_y = base_top + base_height / 2.0 + object_center_x = object_x + object_width / 2.0 + object_center_y = object_y + object_height / 2.0 + rotated_center_x, rotated_center_y = _rotate_point( + base_center_x, + base_center_y, + object_center_x, + object_center_y, + _float(object_layer.get("rotation"), 0.0), + ) + return { + "x": rotated_center_x - base_width / 2.0, + "y": rotated_center_y - base_height / 2.0, + "width": base_width, + "height": base_height, + "center_x": rotated_center_x, + "center_y": rotated_center_y, + } + + +def _region_display_state(doc: Dict[str, Any], region: Dict[str, Any]) -> Dict[str, Any]: + object_layer = _resolve_object_layer(doc, {"object_id": region.get("parent_object_id") or region.get("object_id")}) + if not object_layer: + current_rect = _copy(region.get("source_rect") or {"x": 0, "y": 0, "width": 1, "height": 1}) + return { + "base_rect": current_rect, + "current_rect": current_rect, + "rotation": _float((region.get("local_transform") or {}).get("rotation"), 0.0), + "depth_z": 0.52, + "z_index": 0, + } + base_rect = _region_base_rect(object_layer, region) + local_transform = region.get("local_transform") if isinstance(region.get("local_transform"), dict) else {} + current_width = max(1.0, base_rect["width"] * max(0.2, _float(local_transform.get("scale_x"), 1.0))) + current_height = max(1.0, base_rect["height"] * max(0.2, _float(local_transform.get("scale_y"), 1.0))) + center_x = base_rect["center_x"] + _float(local_transform.get("tx"), 0.0) + center_y = base_rect["center_y"] + _float(local_transform.get("ty"), 0.0) + current_rect = { + "x": int(round(center_x - current_width / 2.0)), + "y": int(round(center_y - current_height / 2.0)), + "width": max(1, int(round(current_width))), + "height": max(1, int(round(current_height))), + } + return { + "base_rect": { + "x": int(round(base_rect["x"])), + "y": int(round(base_rect["y"])), + "width": max(1, int(round(base_rect["width"]))), + "height": max(1, int(round(base_rect["height"]))), + }, + "current_rect": current_rect, + "rotation": _float(object_layer.get("rotation"), 0.0) + _float(local_transform.get("rotation"), 0.0), + "depth_z": _float(object_layer.get("depth_z"), 0.52), + "z_index": _int(object_layer.get("z_index"), 0), + } + + +def _region_is_edited(region: Dict[str, Any]) -> bool: + return ( + bool(region.get("promoted")) + or not bool(region.get("visible", True)) + or str(region.get("edit_state") or "idle") != "idle" + or not _transform_is_default(region.get("local_transform")) + or bool(str(((region.get("render_intent") or {}).get("prompt") or "")).strip()) + ) + + +def _doc_has_visual_edits(doc: Dict[str, Any]) -> bool: + if doc.get("patch_layers"): + return True + if any(isinstance(region, dict) and _region_is_edited(region) for region in doc.get("region_layers", []) or []): + return True + return any( + str(entry.get("type") or "") + in {"transform_object", "set_depth", "hide_object", "show_object", "reorder_layer"} + for entry in doc.get("edit_history", []) or [] + if isinstance(entry, dict) + ) + + +def _overlay_from_doc(doc: Dict[str, Any]) -> Dict[str, Any]: + region_layers = [] + for item in doc.get("region_layers", []) or []: + if not isinstance(item, dict): + continue + display = _region_display_state(doc, item) + region_layers.append( + { + "id": item.get("region_id") or item.get("id"), + "region_id": item.get("region_id") or item.get("id"), + "parent_object_id": item.get("parent_object_id") or item.get("object_id"), + "label": item.get("label"), + "shape": item.get("shape"), + "actions": _copy(item.get("actions") or []), + "visible": item.get("visible", True), + "promoted": bool(item.get("promoted", False)), + "edit_state": str(item.get("edit_state") or "idle"), + "render_intent": _copy(item.get("render_intent") or {}), + "local_transform": _copy(item.get("local_transform") or _default_region_transform()), + "source_rect": _copy(item.get("source_rect") or {}), + "base_rect": _copy(display.get("base_rect") or {}), + "current_rect": _copy(display.get("current_rect") or {}), + "rotation": display.get("rotation"), + "depth_z": display.get("depth_z"), + "z_index": display.get("z_index"), + "crop_image_path": item.get("crop_image_path"), + "mask_image_path": item.get("mask_image_path"), + } + ) + return { + "revision_id": doc.get("revision_id"), + "canvas_size": _copy(doc.get("canvas_size") or {}), + "camera_state": _copy(doc.get("camera_state") or {}), + "object_layers": [ + { + "id": item.get("id"), + "scene_object_id": item.get("scene_object_id"), + "concept": item.get("concept"), + "x": item.get("x"), + "y": item.get("y"), + "width": item.get("width"), + "height": item.get("height"), + "rotation": item.get("rotation"), + "scale": item.get("scale"), + "visible": item.get("visible", True), + "depth_band": item.get("depth_band"), + "depth_z": item.get("depth_z"), + "z_index": item.get("z_index"), + "crop_image_path": item.get("display_image_path") or item.get("crop_image_path"), + "base_crop_image_path": item.get("base_crop_image_path"), + "source_bbox": _copy(item.get("source_bbox") or {}), + } + for item in doc.get("object_layers", []) or [] + ], + "region_layers": region_layers, + "patch_layers": [ + { + **_copy(item), + "rect": _copy(_resolve_patch_rect(doc, item) or item.get("rect") or {}), + } + for item in doc.get("patch_layers", []) or [] + if isinstance(item, dict) + ], + } + + +def _camera_summary(doc: Dict[str, Any]) -> str: + camera = doc.get("camera_state") if isinstance(doc.get("camera_state"), dict) else {} + return ( + f"pan=({camera.get('pan_x', 0)},{camera.get('pan_y', 0)}) | " + f"zoom={float(camera.get('zoom', 1.0) or 1.0):.2f} | " + f"parallax={float(camera.get('parallax_strength', 0.12) or 0.12):.2f}" + ) + + +def _depth_summary(doc: Dict[str, Any]) -> str: + counts = {"foreground": 0, "midground": 0, "background": 0} + for item in doc.get("object_layers", []) or []: + if not item.get("visible", True): + continue + band = str(item.get("depth_band") or "midground") + counts[band] = counts.get(band, 0) + 1 + return f"foreground={counts.get('foreground', 0)} | midground={counts.get('midground', 0)} | background={counts.get('background', 0)}" + + +def _render_patch_constraints(doc: Dict[str, Any]) -> List[Dict[str, Any]]: + constraints: List[Dict[str, Any]] = [] + for patch in doc.get("patch_layers", []) or []: + constraints.append( + { + "patch_id": patch.get("id"), + "kind": patch.get("kind"), + "rect": _copy(patch.get("rect") or {}), + "prompt": str(patch.get("prompt") or ""), + "note": str(patch.get("note") or ""), + } + ) + return constraints + + +def _region_edit_constraints(doc: Dict[str, Any]) -> List[Dict[str, Any]]: + constraints: List[Dict[str, Any]] = [] + for region in doc.get("region_layers", []) or []: + if not isinstance(region, dict) or not _region_is_edited(region): + continue + display = _region_display_state(doc, region) + render_intent = region.get("render_intent") if isinstance(region.get("render_intent"), dict) else {} + constraints.append( + { + "parent_object_id": region.get("parent_object_id") or region.get("object_id"), + "region_id": region.get("region_id") or region.get("id"), + "label": str(region.get("label") or region.get("region_id") or "region"), + "action": str(render_intent.get("action") or _normalize_region_action(region.get("edit_state") or "idle")), + "visible": bool(region.get("visible", True)), + "source_rect": _copy(region.get("source_rect") or {}), + "current_rect": _copy(display.get("current_rect") or {}), + "transform": _copy(region.get("local_transform") or _default_region_transform()), + "prompt": str(render_intent.get("prompt") or ""), + } + ) + return constraints + + +def _region_edit_summary(doc: Dict[str, Any]) -> str: + parts: List[str] = [] + for region in doc.get("region_layers", []) or []: + if not isinstance(region, dict) or not _region_is_edited(region): + continue + render_intent = region.get("render_intent") if isinstance(region.get("render_intent"), dict) else {} + action = str(render_intent.get("action") or _normalize_region_action(region.get("edit_state") or "idle")) + text = f"{region.get('label') or region.get('region_id')}: {_region_action_text(action)}" + prompt = str(render_intent.get("prompt") or "").strip() + if prompt: + text += f"({prompt})" + parts.append(text) + if not parts: + return "" + return ";".join(parts[:10]) + + +def _edit_summary(doc: Dict[str, Any]) -> str: + object_changes = len( + [ + entry + for entry in doc.get("edit_history", []) or [] + if str(entry.get("type") or "") in {"transform_object", "set_depth", "hide_object", "show_object", "reorder_layer"} + ] + ) + region_changes = len([region for region in doc.get("region_layers", []) or [] if isinstance(region, dict) and _region_is_edited(region)]) + patch_changes = len(doc.get("patch_layers", []) or []) + return f"对象直改 {object_changes} 次;部件直改 {region_changes} 处;局部 patch {patch_changes} 层" + + +def _update_render_sync_state(doc: Dict[str, Any]) -> None: + render_sync = doc.setdefault("render_sync_state", {}) + render_sync["ready"] = bool(doc.get("composited_image_path")) + render_sync["used_control_image_path"] = doc.get("composited_image_path") + render_sync["edit_summary"] = _edit_summary(doc) + render_sync["region_edit_summary"] = _region_edit_summary(doc) + render_sync["depth_summary"] = _depth_summary(doc) + render_sync["camera_summary"] = _camera_summary(doc) + render_sync["render_patch_constraints"] = _render_patch_constraints(doc) + render_sync["region_edit_constraints"] = _region_edit_constraints(doc) + + +def _rect_from_points(points: List[List[float]] | None, width: int, height: int) -> Dict[str, int] | None: + valid = [item for item in (points or []) if isinstance(item, (list, tuple)) and len(item) >= 2] + if not valid: + return None + xs = [max(0, min(width, _float(item[0], 0.0))) for item in valid] + ys = [max(0, min(height, _float(item[1], 0.0))) for item in valid] + return _clamp_rect( + { + "x": min(xs), + "y": min(ys), + "width": max(1, max(xs) - min(xs)), + "height": max(1, max(ys) - min(ys)), + }, + width, + height, + ) + + +def _resolve_region_rect(doc: Dict[str, Any], object_id: str | None = None, region_id: str | None = None) -> Dict[str, int] | None: + for region in doc.get("region_layers", []) or []: + if object_id and str(region.get("parent_object_id") or region.get("object_id") or "") != str(object_id): + continue + if region_id and str(region.get("region_id") or region.get("id") or "") != str(region_id): + continue + display = _region_display_state(doc, region) + rect = display.get("current_rect") + if isinstance(rect, dict): + return _copy(rect) + return None + + +def _resolve_patch_rect(doc: Dict[str, Any], patch: Dict[str, Any]) -> Dict[str, int] | None: + canvas = doc.get("canvas_size") if isinstance(doc.get("canvas_size"), dict) else {} + width = max(1, _int(canvas.get("width"), 1)) + height = max(1, _int(canvas.get("height"), 1)) + if patch.get("follow_region") and patch.get("anchor_region_id"): + target_region = _resolve_region_layer(doc, {"region_id": patch.get("anchor_region_id"), "object_id": patch.get("anchor_object_id")}) + relative = patch.get("relative_rect") if isinstance(patch.get("relative_rect"), dict) else {} + if target_region: + target_rect = _region_display_state(doc, target_region).get("current_rect") or {} + rect = { + "x": _int(target_rect.get("x"), 0) + int(round(float(relative.get("x", 0.0) or 0.0) * _int(target_rect.get("width"), 1))), + "y": _int(target_rect.get("y"), 0) + int(round(float(relative.get("y", 0.0) or 0.0) * _int(target_rect.get("height"), 1))), + "width": int(round(float(relative.get("width", 0.0) or 0.0) * _int(target_rect.get("width"), 1))), + "height": int(round(float(relative.get("height", 0.0) or 0.0) * _int(target_rect.get("height"), 1))), + } + return _clamp_rect(rect, width, height) + if patch.get("follow_object") and patch.get("anchor_object_id"): + target = _resolve_object_layer(doc, {"object_id": patch.get("anchor_object_id")}) + relative = patch.get("relative_rect") if isinstance(patch.get("relative_rect"), dict) else {} + if target: + rect = { + "x": _int(target.get("x"), 0) + int(round(float(relative.get("x", 0.0) or 0.0) * _int(target.get("width"), 1))), + "y": _int(target.get("y"), 0) + int(round(float(relative.get("y", 0.0) or 0.0) * _int(target.get("height"), 1))), + "width": int(round(float(relative.get("width", 0.0) or 0.0) * _int(target.get("width"), 1))), + "height": int(round(float(relative.get("height", 0.0) or 0.0) * _int(target.get("height"), 1))), + } + return _clamp_rect(rect, width, height) + rect = patch.get("rect") + if isinstance(rect, dict): + return _clamp_rect(rect, width, height) + return None + + +def _asset_root(output_dir: str | Path, session_id: str, candidate_id: str) -> Path: + root = Path(output_dir) / "sketch_edit_v1" / _slug(session_id) / _slug(candidate_id) + root.mkdir(parents=True, exist_ok=True) + return root + + +def _object_promoted_regions(doc: Dict[str, Any], object_id: str) -> List[Dict[str, Any]]: + regions = [ + item + for item in doc.get("region_layers", []) or [] + if isinstance(item, dict) + and str(item.get("parent_object_id") or item.get("object_id") or "") == str(object_id) + and bool(item.get("promoted")) + ] + return sorted(regions, key=lambda item: str(item.get("region_id") or item.get("id") or "")) + + +def _build_object_residual_image(doc: Dict[str, Any], object_layer: Dict[str, Any]) -> str: + promoted_regions = _object_promoted_regions(doc, str(object_layer.get("scene_object_id") or "")) + if not promoted_regions: + object_layer["display_image_path"] = object_layer.get("base_crop_image_path") or object_layer.get("crop_image_path") + return str(object_layer.get("display_image_path") or "") + crop_path = str(object_layer.get("base_crop_image_path") or object_layer.get("crop_image_path") or "").strip() + if not crop_path or not Path(crop_path).exists(): + return "" + crop_image = Image.open(crop_path).convert("RGBA") + alpha = crop_image.getchannel("A") + crop_box = object_layer.get("crop_box") if isinstance(object_layer.get("crop_box"), dict) else {} + for region in promoted_regions: + mask_path = str(region.get("mask_image_path") or "").strip() + source_rect = region.get("source_rect") if isinstance(region.get("source_rect"), dict) else {} + if not mask_path or not Path(mask_path).exists() or not source_rect: + continue + local_x = _int(source_rect.get("x"), 0) - _int(crop_box.get("x"), 0) + local_y = _int(source_rect.get("y"), 0) - _int(crop_box.get("y"), 0) + mask = Image.open(mask_path).convert("L") + alpha.paste(0, (local_x, local_y), mask=mask) + crop_image.putalpha(alpha) + asset_root = Path(str(doc.get("asset_root") or "")).resolve() + residual_path = asset_root / f"residual_{doc.get('revision_id')}_{_slug(object_layer.get('scene_object_id'))}.png" + crop_image.save(residual_path) + object_layer["display_image_path"] = str(residual_path) + return str(residual_path) + + +def _render_object_crop(base: Image.Image, object_layer: Dict[str, Any], image_path: str) -> None: + crop_path = str(image_path or "").strip() + if not crop_path or not Path(crop_path).exists(): + return + source_bbox = object_layer.get("source_bbox") if isinstance(object_layer.get("source_bbox"), dict) else {} + crop_box = object_layer.get("crop_box") if isinstance(object_layer.get("crop_box"), dict) else {} + current_x = _int(object_layer.get("x"), 0) + current_y = _int(object_layer.get("y"), 0) + current_w = max(1, _int(object_layer.get("width"), source_bbox.get("width", 1))) + current_h = max(1, _int(object_layer.get("height"), source_bbox.get("height", 1))) + source_w = max(1, _int(source_bbox.get("width"), current_w)) + source_h = max(1, _int(source_bbox.get("height"), current_h)) + ratio_x = current_w / source_w + ratio_y = current_h / source_h + crop_w = max(1, int(round(_int(crop_box.get("width"), current_w) * ratio_x))) + crop_h = max(1, int(round(_int(crop_box.get("height"), current_h) * ratio_y))) + offset_x = int(round(_int(object_layer.get("crop_offset_x"), 0) * ratio_x)) + offset_y = int(round(_int(object_layer.get("crop_offset_y"), 0) * ratio_y)) + paste_x = current_x - offset_x + paste_y = current_y - offset_y + crop = Image.open(crop_path).convert("RGBA").resize((crop_w, crop_h), Image.Resampling.LANCZOS) + layer = Image.new("RGBA", base.size, (0, 0, 0, 0)) + layer.alpha_composite(crop, (paste_x, paste_y)) + rotation = _float(object_layer.get("rotation"), 0.0) + if abs(rotation) > 0.01: + center = (current_x + current_w / 2.0, current_y + current_h / 2.0) + layer = layer.rotate(rotation, resample=Image.Resampling.BICUBIC, center=center) + base.alpha_composite(layer) + + +def _apply_region_visual_intent(crop: Image.Image, region: Dict[str, Any]) -> Image.Image: + edit_state = str(region.get("edit_state") or "idle") + if edit_state in {"idle", "transformed", "shown"}: + return crop + result = crop.convert("RGBA") + if edit_state == "weakened": + alpha = result.getchannel("A").point(lambda px: int(px * 0.38)) + result.putalpha(alpha) + return result + if edit_state == "emphasized": + alpha = result.getchannel("A").point(lambda px: min(255, int(px * 1.25))) + result.putalpha(alpha) + return ImageEnhance.Contrast(result).enhance(1.25) + if edit_state in {"replaced", "inpainted"}: + tinted = Image.new("RGBA", result.size, (255, 255, 255, 0)) + alpha = result.getchannel("A") + if edit_state == "replaced": + tinted.putalpha(alpha.point(lambda px: min(255, int(px * 0.78)))) + return Image.alpha_composite(result.filter(ImageFilter.GaussianBlur(radius=1.2)), tinted) + tinted.putalpha(alpha.point(lambda px: min(255, int(px * 0.88)))) + return Image.alpha_composite(result.filter(ImageFilter.GaussianBlur(radius=2.0)), tinted) + return result + + +def _render_region_crop(base: Image.Image, doc: Dict[str, Any], region: Dict[str, Any]) -> None: + crop_path = str(region.get("crop_image_path") or "").strip() + if not crop_path or not Path(crop_path).exists(): + return + display = _region_display_state(doc, region) + rect = display.get("current_rect") if isinstance(display.get("current_rect"), dict) else {} + if not rect: + return + current_w = max(1, _int(rect.get("width"), 1)) + current_h = max(1, _int(rect.get("height"), 1)) + paste_x = _int(rect.get("x"), 0) + paste_y = _int(rect.get("y"), 0) + crop = Image.open(crop_path).convert("RGBA").resize((current_w, current_h), Image.Resampling.LANCZOS) + crop = _apply_region_visual_intent(crop, region) + layer = Image.new("RGBA", base.size, (0, 0, 0, 0)) + layer.alpha_composite(crop, (paste_x, paste_y)) + rotation = _float(display.get("rotation"), 0.0) + if abs(rotation) > 0.01: + center = (paste_x + current_w / 2.0, paste_y + current_h / 2.0) + layer = layer.rotate(rotation, resample=Image.Resampling.BICUBIC, center=center) + base.alpha_composite(layer) + + +def _compose_doc(doc: Dict[str, Any]) -> Dict[str, Any]: + canvas = doc.get("canvas_size") if isinstance(doc.get("canvas_size"), dict) else {} + canvas_width = max(1, _int(canvas.get("width"), 1)) + canvas_height = max(1, _int(canvas.get("height"), 1)) + revision_id = str(doc.get("revision_id") or _new_revision_id()) + doc["revision_id"] = revision_id + if not _doc_has_visual_edits(doc): + base_image_path = str(doc.get("base_image_path") or "").strip() + if base_image_path and Path(base_image_path).exists(): + doc["composited_image_path"] = base_image_path + doc["overlay"] = _overlay_from_doc(doc) + _update_render_sync_state(doc) + return doc + background_path = str(doc.get("background_plate_path") or "").strip() + if background_path and Path(background_path).exists(): + base = Image.open(background_path).convert("RGBA") + else: + base = Image.new("RGBA", (canvas_width, canvas_height), (255, 255, 255, 255)) + + object_layers = sorted( + [item for item in doc.get("object_layers", []) or [] if isinstance(item, dict) and item.get("visible", True)], + key=lambda item: (_float(item.get("depth_z"), 0.0), _int(item.get("z_index"), 0)), + ) + for item in object_layers: + display_path = _build_object_residual_image(doc, item) + _render_object_crop(base, item, display_path) + + region_layers = sorted( + [ + item + for item in doc.get("region_layers", []) or [] + if isinstance(item, dict) and item.get("promoted") and item.get("visible", True) + ], + key=lambda item: ( + _float(_region_display_state(doc, item).get("depth_z"), 0.0), + _int(_region_display_state(doc, item).get("z_index"), 0), + str(item.get("region_id") or item.get("id") or ""), + ), + ) + for item in region_layers: + _render_region_crop(base, doc, item) + + for patch in doc.get("patch_layers", []) or []: + rect = _resolve_patch_rect(doc, patch) + if not rect: + continue + patch_layer = Image.new("RGBA", base.size, (0, 0, 0, 0)) + draw = ImageDraw.Draw(patch_layer, "RGBA") + kind = str(patch.get("kind") or "erase_region") + fill = (255, 255, 255, 255) if kind in {"erase_region", "brush_mask", "inpaint_region"} else (255, 255, 255, 190) + draw.rounded_rectangle( + [rect["x"], rect["y"], rect["x"] + rect["width"], rect["y"] + rect["height"]], + radius=max(8, int(min(rect["width"], rect["height"]) * 0.12)), + fill=fill, + outline=None, + ) + if kind == "brush_mask": + patch_layer = patch_layer.filter(ImageFilter.GaussianBlur(radius=8)) + elif kind == "inpaint_region": + patch_layer = patch_layer.filter(ImageFilter.GaussianBlur(radius=4)) + base.alpha_composite(patch_layer) + + asset_root = Path(str(doc.get("asset_root") or "")).resolve() + asset_root.mkdir(parents=True, exist_ok=True) + composited_path = asset_root / f"composited_{revision_id}.png" + base.convert("RGB").save(composited_path) + doc["composited_image_path"] = str(composited_path) + doc["overlay"] = _overlay_from_doc(doc) + _update_render_sync_state(doc) + return doc + + +def _make_object_layer( + base_image: Image.Image, + scene_object: Dict[str, Any], + asset_root: Path, + index: int, + canvas_width: int, + canvas_height: int, +) -> Dict[str, Any]: + source_bbox = _clamp_rect( + { + "x": scene_object.get("x", 0), + "y": scene_object.get("y", 0), + "width": scene_object.get("width", 1), + "height": scene_object.get("height", 1), + }, + canvas_width, + canvas_height, + ) + padding = max(8, int(min(source_bbox["width"], source_bbox["height"]) * 0.16)) + crop_box = _expand_box(source_bbox, canvas_width, canvas_height, padding) + crop = base_image.crop( + ( + crop_box["x"], + crop_box["y"], + crop_box["x"] + crop_box["width"], + crop_box["y"] + crop_box["height"], + ) + ).convert("RGBA") + alpha = _white_alpha_from_crop(crop) + rgba = crop.copy() + rgba.putalpha(alpha) + crop_path = asset_root / f"layer_{index:03d}_{_slug(scene_object.get('id') or scene_object.get('concept'))}.png" + rgba.save(crop_path) + return { + "id": f"layer_{_slug(scene_object.get('id') or index)}", + "scene_object_id": str(scene_object.get("id") or f"obj_{index}"), + "concept": str(scene_object.get("concept") or scene_object.get("asset_key") or f"对象{index}"), + "base_crop_image_path": str(crop_path), + "crop_image_path": str(crop_path), + "display_image_path": str(crop_path), + "source_bbox": source_bbox, + "crop_box": crop_box, + "crop_offset_x": source_bbox["x"] - crop_box["x"], + "crop_offset_y": source_bbox["y"] - crop_box["y"], + "x": source_bbox["x"], + "y": source_bbox["y"], + "width": source_bbox["width"], + "height": source_bbox["height"], + "rotation": _float(scene_object.get("rotation"), 0.0), + "scale": _float(scene_object.get("scale"), 1.0), + "depth_band": str(scene_object.get("depth_band") or "midground"), + "depth_z": _band_depth(scene_object.get("depth_band"), scene_object.get("depth_z")), + "z_index": _int(scene_object.get("z_index"), index), + "visible": bool(scene_object.get("visible", True)), + } + + +def _build_region_layer( + scene_object: Dict[str, Any], + object_layer: Dict[str, Any], + asset_root: Path, + region_spec: Dict[str, Any], + index: int, +) -> Dict[str, Any] | None: + source_rect = _clamp_rect( + { + "x": _float(scene_object.get("x"), 0.0) + _float(region_spec.get("x"), 0.0) * _float(scene_object.get("width"), 1.0), + "y": _float(scene_object.get("y"), 0.0) + _float(region_spec.get("y"), 0.0) * _float(scene_object.get("height"), 1.0), + "width": _float(region_spec.get("width"), 0.0) * _float(scene_object.get("width"), 1.0), + "height": _float(region_spec.get("height"), 0.0) * _float(scene_object.get("height"), 1.0), + }, + max(1, _int((scene_object.get("canvas_size") or {}).get("width"), object_layer.get("width", 1) + object_layer.get("x", 0) + 1)), + max(1, _int((scene_object.get("canvas_size") or {}).get("height"), object_layer.get("height", 1) + object_layer.get("y", 0) + 1)), + ) + object_crop_path = str(object_layer.get("base_crop_image_path") or object_layer.get("crop_image_path") or "").strip() + if not object_crop_path or not Path(object_crop_path).exists(): + return None + object_crop = Image.open(object_crop_path).convert("RGBA") + crop_box = object_layer.get("crop_box") if isinstance(object_layer.get("crop_box"), dict) else {} + local_x = _int(source_rect.get("x"), 0) - _int(crop_box.get("x"), 0) + local_y = _int(source_rect.get("y"), 0) - _int(crop_box.get("y"), 0) + local_w = max(1, _int(source_rect.get("width"), 1)) + local_h = max(1, _int(source_rect.get("height"), 1)) + region_crop = object_crop.crop((local_x, local_y, local_x + local_w, local_y + local_h)).convert("RGBA") + shape = str(region_spec.get("shape") or "rect") + region_mask = _shape_mask(local_w, local_h, shape) + region_alpha = ImageChops.multiply(_white_alpha_from_crop(region_crop), region_mask) + region_crop.putalpha(region_alpha) + object_id = str(scene_object.get("id") or object_layer.get("scene_object_id") or "object") + region_id = str(region_spec.get("id") or f"{object_id}_region_{index}") + crop_path = asset_root / f"region_{_slug(object_id)}_{_slug(region_id)}.png" + mask_path = asset_root / f"region_{_slug(object_id)}_{_slug(region_id)}_mask.png" + region_crop.save(crop_path) + region_mask.save(mask_path) + ratios = _object_rect_ratios(object_layer, {"source_rect": source_rect}) + return { + "id": region_id, + "region_id": region_id, + "parent_object_id": object_id, + "label": str(region_spec.get("label") or region_id), + "shape": shape, + "source_rect": source_rect, + "source_rect_ratios": ratios, + "crop_image_path": str(crop_path), + "mask_image_path": str(mask_path), + "actions": [str(item) for item in (region_spec.get("actions") or []) if str(item).strip()], + "visible": True, + "local_transform": _default_region_transform(), + "promoted": False, + "edit_state": "idle", + "render_intent": {"action": "idle", "prompt": "", "note": ""}, + } + + +def _build_region_layers(scene_spec: Dict[str, Any], object_layers: List[Dict[str, Any]], asset_root: Path) -> List[Dict[str, Any]]: + object_map = {str(item.get("scene_object_id") or ""): item for item in object_layers if isinstance(item, dict)} + regions: List[Dict[str, Any]] = [] + for scene_object in scene_spec.get("object_instances", []) or []: + if not isinstance(scene_object, dict): + continue + object_id = str(scene_object.get("id") or "") + object_layer = object_map.get(object_id) + if not object_layer: + continue + scene_object = _copy(scene_object) + scene_object["canvas_size"] = _copy(scene_spec.get("canvas_size") or {}) + region_specs = scene_object.get("region_masks") or [] + if not region_specs: + region_specs = [ + { + "id": "core", + "label": "主体区域", + "shape": "rect", + "x": 0.14, + "y": 0.14, + "width": 0.72, + "height": 0.72, + "actions": ["replace", "weaken", "hide", "emphasize"], + } + ] + for index, region_spec in enumerate(region_specs, start=1): + if not isinstance(region_spec, dict): + continue + layer = _build_region_layer(scene_object, object_layer, asset_root, region_spec, index) + if layer: + regions.append(layer) + return regions + + +def _default_depth_model(scene_spec: Dict[str, Any]) -> Dict[str, Any]: + counts = {"foreground": 0, "midground": 0, "background": 0} + for item in scene_spec.get("object_instances", []) or []: + if not isinstance(item, dict): + continue + band = str(item.get("depth_band") or "midground") + counts[band] = counts.get(band, 0) + 1 + return {"bands": counts, "mode": "parallax_v1"} + + +def _build_background_plate(base_image: Image.Image, object_layers: List[Dict[str, Any]], asset_root: Path) -> str: + background = base_image.copy() + fill_rgb = _estimate_background_rgb(base_image, stride=6) + for layer in object_layers: + crop_path = str(layer.get("base_crop_image_path") or layer.get("crop_image_path") or "").strip() + if not crop_path or not Path(crop_path).exists(): + continue + crop = Image.open(crop_path).convert("RGBA") + alpha = crop.getchannel("A").filter(ImageFilter.GaussianBlur(radius=1.8)) + wipe = Image.new("RGBA", crop.size, (*fill_rgb, 255)) + background.paste( + wipe, + (_int(layer.get("crop_box", {}).get("x"), 0), _int(layer.get("crop_box", {}).get("y"), 0)), + mask=alpha, + ) + output_path = asset_root / "background_plate.png" + background.convert("RGB").save(output_path) + return str(output_path) + + +def create_editable_sketch_doc( + *, + preview: Dict[str, Any], + scene_spec: Dict[str, Any], + session_id: str, + output_dir: str | Path = "outputs", + sketch_backend: str = "sketch_v2", + source_candidate_id: str | None = None, +) -> Dict[str, Any] | None: + if str(sketch_backend or "").strip().lower() != "sketch_v2": + return None + active_candidate = _candidate_from_preview(preview, source_candidate_id) + if not active_candidate: + return None + if str(active_candidate.get("provider") or "").strip().lower() != "sd": + return None + image_path = str(active_candidate.get("image_path") or "").strip() + if not image_path or not Path(image_path).exists(): + return None + + base_image = Image.open(image_path).convert("RGBA") + canvas_width, canvas_height = base_image.size + asset_root = _asset_root(output_dir, session_id, str(active_candidate.get("candidate_id") or "active")) + object_layers: List[Dict[str, Any]] = [] + for index, item in enumerate(scene_spec.get("object_instances", []) or [], start=1): + if not isinstance(item, dict): + continue + object_layers.append(_make_object_layer(base_image, item, asset_root, index, canvas_width, canvas_height)) + + region_layers = _build_region_layers(scene_spec, object_layers, asset_root) + doc = { + "revision_id": _new_revision_id(), + "session_id": session_id, + "sketch_backend": "sketch_v2", + "source_candidate_id": str(active_candidate.get("candidate_id") or "active"), + "source_provider": str(active_candidate.get("provider") or "sd"), + "base_image_path": image_path, + "asset_root": str(asset_root), + "canvas_size": {"width": canvas_width, "height": canvas_height}, + "camera_state": { + "pan_x": 0, + "pan_y": 0, + "zoom": 1.0, + "parallax_strength": 0.12, + "preview_enabled": False, + }, + "depth_model": _default_depth_model(scene_spec), + "object_layers": object_layers, + "region_layers": region_layers, + "patch_layers": [], + "edit_history": [], + "scene_sync_state": { + "synced_object_ids": [item.get("scene_object_id") for item in object_layers], + "pending_region_layers": 0, + "pending_patch_layers": 0, + "last_scene_delta": {"objects": [], "regions": [], "patches": []}, + }, + "render_sync_state": { + "ready": False, + "used_control_image_path": "", + "edit_summary": "", + "region_edit_summary": "", + "depth_summary": "", + "camera_summary": "", + "render_patch_constraints": [], + "region_edit_constraints": [], + }, + } + doc["background_plate_path"] = _build_background_plate(base_image, object_layers, asset_root) + return _compose_doc(doc) + + +def _update_scene_render_hints(scene_spec: Dict[str, Any], doc: Dict[str, Any]) -> None: + render_hints = scene_spec.setdefault("render_hints", {}) + render_sync = doc.get("render_sync_state") if isinstance(doc.get("render_sync_state"), dict) else {} + render_hints["edit_summary"] = str(render_sync.get("edit_summary") or "") + render_hints["region_edit_summary"] = str(render_sync.get("region_edit_summary") or "") + render_hints["depth_summary"] = str(render_sync.get("depth_summary") or "") + render_hints["camera_summary"] = str(render_sync.get("camera_summary") or "") + render_hints["render_patch_constraints"] = _copy(render_sync.get("render_patch_constraints") or []) + render_hints["region_edit_constraints"] = _copy(render_sync.get("region_edit_constraints") or []) + render_hints["editable_sketch_composited_path"] = str(doc.get("composited_image_path") or "") + + +def build_render_conditioning_bundle(doc: Dict[str, Any] | None) -> Dict[str, Any]: + doc = doc if isinstance(doc, dict) else {} + if not doc: + return {} + object_layers = [] + for item in doc.get("object_layers", []) or []: + if not isinstance(item, dict): + continue + object_layers.append( + { + "object_id": item.get("scene_object_id") or item.get("id"), + "concept": item.get("concept"), + "x": _int(item.get("x"), 0), + "y": _int(item.get("y"), 0), + "width": _int(item.get("width"), 0), + "height": _int(item.get("height"), 0), + "rotation": _float(item.get("rotation"), 0.0), + "scale": _float(item.get("scale"), 1.0), + "visible": bool(item.get("visible", True)), + "depth_band": str(item.get("depth_band") or "midground"), + "depth_z": _float(item.get("depth_z"), 0.52), + "z_index": _int(item.get("z_index"), 0), + "display_image_path": str(item.get("display_image_path") or item.get("crop_image_path") or ""), + "base_crop_image_path": str(item.get("base_crop_image_path") or ""), + "source_bbox": _copy(item.get("source_bbox") or {}), + } + ) + region_layers = [] + for item in doc.get("region_layers", []) or []: + if not isinstance(item, dict): + continue + display = _region_display_state(doc, item) + render_intent = item.get("render_intent") if isinstance(item.get("render_intent"), dict) else {} + region_layers.append( + { + "region_id": item.get("region_id") or item.get("id"), + "parent_object_id": item.get("parent_object_id") or item.get("object_id"), + "label": str(item.get("label") or item.get("region_id") or "region"), + "shape": str(item.get("shape") or "rect"), + "visible": bool(item.get("visible", True)), + "promoted": bool(item.get("promoted", False)), + "edit_state": str(item.get("edit_state") or "idle"), + "action": str(render_intent.get("action") or _normalize_region_action(item.get("edit_state") or "idle")), + "render_intent": _copy(render_intent), + "local_transform": _copy(item.get("local_transform") or _default_region_transform()), + "source_rect": _copy(item.get("source_rect") or {}), + "base_rect": _copy(display.get("base_rect") or {}), + "current_rect": _copy(display.get("current_rect") or {}), + "rotation": _float(display.get("rotation"), 0.0), + "depth_z": _float(display.get("depth_z"), 0.52), + "z_index": _int(display.get("z_index"), 0), + "crop_image_path": str(item.get("crop_image_path") or ""), + "mask_image_path": str(item.get("mask_image_path") or ""), + "edited": bool(_region_is_edited(item)), + } + ) + patch_layers = [] + for item in doc.get("patch_layers", []) or []: + if not isinstance(item, dict): + continue + patch_layers.append( + { + "patch_id": item.get("id"), + "kind": str(item.get("kind") or ""), + "prompt": str(item.get("prompt") or ""), + "note": str(item.get("note") or ""), + "rect": _copy(_resolve_patch_rect(doc, item) or item.get("rect") or {}), + "anchor_object_id": str(item.get("anchor_object_id") or ""), + "anchor_region_id": str(item.get("anchor_region_id") or item.get("region_id") or ""), + "follow_region": bool(item.get("follow_region", False)), + "follow_object": bool(item.get("follow_object", False)), + } + ) + return { + "version": 1, + "source": "editable_sketch_doc", + "revision_id": str(doc.get("revision_id") or ""), + "session_id": str(doc.get("session_id") or ""), + "sketch_backend": str(doc.get("sketch_backend") or ""), + "source_candidate_id": str(doc.get("source_candidate_id") or ""), + "base_image_path": str(doc.get("base_image_path") or ""), + "background_plate_path": str(doc.get("background_plate_path") or ""), + "composited_image_path": str(doc.get("composited_image_path") or ""), + "canvas_size": _copy(doc.get("canvas_size") or {}), + "camera_state": _copy(doc.get("camera_state") or {}), + "depth_model": _copy(doc.get("depth_model") or {}), + "edit_summary": _edit_summary(doc), + "region_edit_summary": _region_edit_summary(doc), + "region_edit_constraints": _region_edit_constraints(doc), + "render_patch_constraints": _render_patch_constraints(doc), + "object_layers": object_layers, + "region_layers": region_layers, + "patch_layers": patch_layers, + "counts": { + "objects": len(object_layers), + "regions": len(region_layers), + "edited_regions": len([item for item in region_layers if item.get("edited")]), + "patches": len(patch_layers), + }, + } + + +def attach_doc_to_preview(preview: Dict[str, Any], scene_spec: Dict[str, Any], doc: Dict[str, Any]) -> Dict[str, Any]: + updated_preview = _copy(preview) + updated_scene = _copy(scene_spec) + _update_scene_render_hints(updated_scene, doc) + updated_preview["scene_spec"] = updated_scene + updated_preview["editable_sketch_doc"] = _copy(doc) + updated_preview["editable_sketch_enabled"] = True + updated_preview["editable_sketch_revision_id"] = doc.get("revision_id") + updated_preview["editable_sketch_base_candidate_id"] = doc.get("source_candidate_id") + updated_preview["editable_sketch_source_candidate_id"] = doc.get("source_candidate_id") + updated_preview["editable_sketch_base_image_path"] = doc.get("base_image_path") + updated_preview["editable_sketch_composited_path"] = doc.get("composited_image_path") + updated_preview["editable_sketch_overlay"] = _copy(doc.get("overlay") or _overlay_from_doc(doc)) + updated_preview["editable_sketch_scene_sync"] = _copy(doc.get("scene_sync_state") or {}) + updated_preview["editable_sketch_history"] = _copy(doc.get("edit_history") or []) + updated_preview["editable_sketch_capabilities"] = { + "supported_ops": list(SUPPORTED_OPS), + "region_ops": list(REGION_ONLY_OPS), + "modes": ["select", "erase", "inpaint", "depth"], + "parallax": True, + "direct_on_active_sd_sketch": True, + } + render_bundle = updated_preview.get("render_bundle") + if isinstance(render_bundle, dict): + render_bundle = _copy(render_bundle) + model_inputs = render_bundle.get("model_inputs") if isinstance(render_bundle.get("model_inputs"), dict) else {} + model_inputs["used_control_image_path"] = str(doc.get("composited_image_path") or "") + render_bundle["model_inputs"] = model_inputs + updated_preview["render_bundle"] = render_bundle + return updated_preview + + +def detach_doc_from_preview(preview: Dict[str, Any], note: str = "") -> Dict[str, Any]: + updated_preview = _copy(preview) + for key in [ + "editable_sketch_doc", + "editable_sketch_revision_id", + "editable_sketch_base_candidate_id", + "editable_sketch_source_candidate_id", + "editable_sketch_base_image_path", + "editable_sketch_composited_path", + "editable_sketch_overlay", + "editable_sketch_scene_sync", + "editable_sketch_history", + "editable_sketch_capabilities", + ]: + updated_preview.pop(key, None) + updated_preview["editable_sketch_enabled"] = False + if note: + updated_preview["editable_sketch_note"] = note + return updated_preview + + +def ensure_editable_preview( + *, + preview: Dict[str, Any] | None, + session_id: str, + sketch_backend: str, + output_dir: str | Path = "outputs", + force_rebuild: bool = False, + source_candidate_id: str | None = None, +) -> Dict[str, Any] | None: + if not isinstance(preview, dict): + return preview + updated_preview = _copy(preview) + if str(sketch_backend or "").strip().lower() != "sketch_v2": + return detach_doc_from_preview(updated_preview, "Direct sketch editing is available only under sketch_v2.") + active_candidate = _candidate_from_preview(updated_preview, source_candidate_id) + if not active_candidate: + return detach_doc_from_preview(updated_preview, "No editable sketch candidate is available in the current session.") + provider = str(active_candidate.get("provider") or "").strip().lower() + if provider != "sd": + return detach_doc_from_preview(updated_preview, "Direct editing currently requires an SD sketch candidate. Please switch to an SD candidate.") + existing_doc = updated_preview.get("editable_sketch_doc") if isinstance(updated_preview.get("editable_sketch_doc"), dict) else None + same_candidate = existing_doc and str(existing_doc.get("source_candidate_id") or "") == str(active_candidate.get("candidate_id") or "") + same_base = existing_doc and str(existing_doc.get("base_image_path") or "") == str(active_candidate.get("image_path") or "") + if existing_doc and same_candidate and same_base and not force_rebuild: + return attach_doc_to_preview(updated_preview, updated_preview.get("scene_spec") or {}, existing_doc) + scene_spec = updated_preview.get("scene_spec") if isinstance(updated_preview.get("scene_spec"), dict) else {} + if not scene_spec: + return detach_doc_from_preview(updated_preview, "No SceneSpec is available in the current session.") + doc = create_editable_sketch_doc( + preview=updated_preview, + scene_spec=scene_spec, + session_id=session_id, + output_dir=output_dir, + sketch_backend=sketch_backend, + source_candidate_id=str(active_candidate.get("candidate_id") or ""), + ) + if not doc: + return detach_doc_from_preview(updated_preview, "Direct editing currently requires an SD sketch candidate. Please switch to an SD candidate.") + return attach_doc_to_preview(updated_preview, scene_spec, doc) + + +def _append_history(doc: Dict[str, Any], op: Dict[str, Any], note: str = "") -> None: + history = doc.setdefault("edit_history", []) + history.append( + { + "id": f"hist_{uuid.uuid4().hex[:10]}", + "type": str(op.get("type") or op.get("op") or ""), + "note": note, + "payload": _copy(op), + } + ) + if len(history) > 120: + del history[:-120] + + +def _resolve_op_rect(doc: Dict[str, Any], op: Dict[str, Any]) -> Dict[str, int] | None: + canvas = doc.get("canvas_size") if isinstance(doc.get("canvas_size"), dict) else {} + width = max(1, _int(canvas.get("width"), 1)) + height = max(1, _int(canvas.get("height"), 1)) + rect = op.get("rect") + if isinstance(rect, dict): + return _clamp_rect(rect, width, height) + points_rect = _rect_from_points(op.get("points") if isinstance(op.get("points"), list) else None, width, height) + if points_rect: + return points_rect + region_layer = _resolve_region_layer(doc, op) + if region_layer: + region_rect = _resolve_region_rect(doc, region_layer.get("parent_object_id"), region_layer.get("region_id")) + if region_rect: + return region_rect + object_layer = _resolve_object_layer(doc, op) + if object_layer: + return _clamp_rect( + { + "x": object_layer.get("x"), + "y": object_layer.get("y"), + "width": object_layer.get("width"), + "height": object_layer.get("height"), + }, + width, + height, + ) + return None + + +def _sync_object_to_scene(scene_obj: Dict[str, Any], layer: Dict[str, Any]) -> None: + scene_obj["x"] = _int(layer.get("x"), scene_obj.get("x", 0)) + scene_obj["y"] = _int(layer.get("y"), scene_obj.get("y", 0)) + scene_obj["width"] = _int(layer.get("width"), scene_obj.get("width", 1)) + scene_obj["height"] = _int(layer.get("height"), scene_obj.get("height", 1)) + scene_obj["rotation"] = _float(layer.get("rotation"), scene_obj.get("rotation", 0.0)) + scene_obj["scale"] = _float(layer.get("scale"), scene_obj.get("scale", 1.0)) + scene_obj["depth_band"] = str(layer.get("depth_band") or scene_obj.get("depth_band") or "midground") + scene_obj["depth_z"] = _float(layer.get("depth_z"), scene_obj.get("depth_z", _band_depth(layer.get("depth_band")))) + scene_obj["z_index"] = _int(layer.get("z_index"), scene_obj.get("z_index", 0)) + scene_obj["visible"] = bool(layer.get("visible", True)) + + +def _ensure_region_promoted(region: Dict[str, Any], *, action: str, prompt: str = "", note: str = "") -> None: + region["promoted"] = True + region["edit_state"] = _region_state_from_action(action) + render_intent = region.setdefault("render_intent", {}) + render_intent["action"] = action + render_intent["prompt"] = str(prompt or "") + render_intent["note"] = str(note or "") + + +def _apply_transform_object(doc: Dict[str, Any], scene_spec: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> None: + layer = _resolve_object_layer(doc, op) + if not layer: + return + source_bbox = layer.get("source_bbox") if isinstance(layer.get("source_bbox"), dict) else {} + if "dx" in op: + layer["x"] = _int(layer.get("x"), 0) + _int(op.get("dx"), 0) + if "dy" in op: + layer["y"] = _int(layer.get("y"), 0) + _int(op.get("dy"), 0) + if "x" in op: + layer["x"] = _int(op.get("x"), layer.get("x", 0)) + if "y" in op: + layer["y"] = _int(op.get("y"), layer.get("y", 0)) + if "width" in op: + layer["width"] = max(24, _int(op.get("width"), layer.get("width", 24))) + if "height" in op: + layer["height"] = max(24, _int(op.get("height"), layer.get("height", 24))) + if "scale" in op and "width" not in op and "height" not in op: + scale = max(0.2, min(3.0, _float(op.get("scale"), layer.get("scale", 1.0)))) + layer["scale"] = scale + if source_bbox: + layer["width"] = max(24, int(round(_int(source_bbox.get("width"), layer.get("width", 24)) * scale))) + layer["height"] = max(24, int(round(_int(source_bbox.get("height"), layer.get("height", 24)) * scale))) + else: + layer["scale"] = max(0.2, min(3.0, _float(op.get("scale"), layer.get("scale", 1.0)))) + if source_bbox and _int(source_bbox.get("width"), 0) > 0: + scale_x = _int(layer.get("width"), 1) / max(1, _int(source_bbox.get("width"), 1)) + scale_y = _int(layer.get("height"), 1) / max(1, _int(source_bbox.get("height"), 1)) + layer["scale"] = round((scale_x + scale_y) / 2.0, 4) + if "rotation" in op: + layer["rotation"] = _float(op.get("rotation"), layer.get("rotation", 0.0)) + scene_obj = _resolve_scene_object(scene_spec, layer) + if scene_obj: + _sync_object_to_scene(scene_obj, layer) + scene_delta["objects"].append( + { + "object_id": layer.get("scene_object_id"), + "x": layer.get("x"), + "y": layer.get("y"), + "width": layer.get("width"), + "height": layer.get("height"), + "rotation": layer.get("rotation"), + "scale": layer.get("scale"), + } + ) + _append_history(doc, op, note=f"Updated object {layer.get('concept')}") + + +def _apply_set_depth(doc: Dict[str, Any], scene_spec: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> None: + layer = _resolve_object_layer(doc, op) + if not layer: + return + depth_band = str(op.get("depth_band") or op.get("band") or layer.get("depth_band") or "midground") + layer["depth_band"] = depth_band + layer["depth_z"] = _band_depth(depth_band, op.get("depth_z")) + if "z_index" in op: + layer["z_index"] = _int(op.get("z_index"), layer.get("z_index", 0)) + scene_obj = _resolve_scene_object(scene_spec, layer) + if scene_obj: + _sync_object_to_scene(scene_obj, layer) + scene_delta["objects"].append( + { + "object_id": layer.get("scene_object_id"), + "depth_band": layer.get("depth_band"), + "depth_z": layer.get("depth_z"), + "z_index": layer.get("z_index"), + } + ) + _append_history(doc, op, note=f"Updated depth for {layer.get('concept')}") + + +def _apply_visibility(doc: Dict[str, Any], scene_spec: Dict[str, Any], op: Dict[str, Any], visible: bool, scene_delta: Dict[str, Any]) -> None: + layer = _resolve_object_layer(doc, op) + if not layer: + return + layer["visible"] = bool(visible) + scene_obj = _resolve_scene_object(scene_spec, layer) + if scene_obj: + _sync_object_to_scene(scene_obj, layer) + scene_delta["objects"].append({"object_id": layer.get("scene_object_id"), "visible": visible}) + _append_history(doc, op, note=f"{'Showed' if visible else 'Hid'} object {layer.get('concept')}") + + +def _apply_reorder(doc: Dict[str, Any], scene_spec: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> None: + layer = _resolve_object_layer(doc, op) + if not layer: + return + z_values = [_int(item.get("z_index"), 0) for item in doc.get("object_layers", []) or []] + direction = str(op.get("direction") or "").strip().lower() + if "z_index" in op: + layer["z_index"] = _int(op.get("z_index"), layer.get("z_index", 0)) + elif direction == "front": + layer["z_index"] = (max(z_values) if z_values else 0) + 1 + elif direction == "back": + layer["z_index"] = (min(z_values) if z_values else 0) - 1 + scene_obj = _resolve_scene_object(scene_spec, layer) + if scene_obj: + _sync_object_to_scene(scene_obj, layer) + scene_delta["objects"].append({"object_id": layer.get("scene_object_id"), "z_index": layer.get("z_index")}) + _append_history(doc, op, note=f"Reordered object {layer.get('concept')}") + + +def _apply_transform_region(doc: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> None: + region = _resolve_region_layer(doc, op) + if not region: + return + base_rect = _region_display_state(doc, region).get("base_rect") or {} + transform = region.setdefault("local_transform", _default_region_transform()) + if "dx" in op: + transform["tx"] = _float(transform.get("tx"), 0.0) + _float(op.get("dx"), 0.0) + if "dy" in op: + transform["ty"] = _float(transform.get("ty"), 0.0) + _float(op.get("dy"), 0.0) + if "x" in op: + transform["tx"] = _float(op.get("x"), base_rect.get("x", 0.0)) - _float(base_rect.get("x"), 0.0) + if "y" in op: + transform["ty"] = _float(op.get("y"), base_rect.get("y", 0.0)) - _float(base_rect.get("y"), 0.0) + if "scale" in op: + scale = max(0.25, min(3.0, _float(op.get("scale"), 1.0))) + transform["scale_x"] = scale + transform["scale_y"] = scale + if "scale_x" in op: + transform["scale_x"] = max(0.25, min(3.0, _float(op.get("scale_x"), 1.0))) + if "scale_y" in op: + transform["scale_y"] = max(0.25, min(3.0, _float(op.get("scale_y"), 1.0))) + if "width" in op and _float(base_rect.get("width"), 0.0) > 0: + transform["scale_x"] = max(0.25, min(3.0, _float(op.get("width"), base_rect.get("width", 1.0)) / _float(base_rect.get("width"), 1.0))) + if "height" in op and _float(base_rect.get("height"), 0.0) > 0: + transform["scale_y"] = max(0.25, min(3.0, _float(op.get("height"), base_rect.get("height", 1.0)) / _float(base_rect.get("height"), 1.0))) + if "rotation" in op: + transform["rotation"] = _float(op.get("rotation"), transform.get("rotation", 0.0)) + _ensure_region_promoted(region, action="transform", prompt=str(op.get("prompt") or "")) + display = _region_display_state(doc, region) + scene_delta["regions"].append( + { + "region_id": region.get("region_id"), + "parent_object_id": region.get("parent_object_id"), + "action": "transform", + "current_rect": _copy(display.get("current_rect") or {}), + "transform": _copy(transform), + } + ) + _append_history(doc, op, note=f"Updated region {region.get('label')}") + + +def _apply_region_visibility(doc: Dict[str, Any], op: Dict[str, Any], visible: bool, scene_delta: Dict[str, Any]) -> None: + region = _resolve_region_layer(doc, op) + if not region: + return + region["visible"] = bool(visible) + action = "show" if visible else "hide" + _ensure_region_promoted(region, action=action, prompt=str(op.get("prompt") or "")) + scene_delta["regions"].append( + { + "region_id": region.get("region_id"), + "parent_object_id": region.get("parent_object_id"), + "action": action, + "visible": bool(visible), + } + ) + _append_history(doc, op, note=f"{'Showed' if visible else 'Hid'} region {region.get('label')}") + + +def _apply_region_semantic_op(doc: Dict[str, Any], op: Dict[str, Any], action: str, scene_delta: Dict[str, Any]) -> None: + region = _resolve_region_layer(doc, op) + if not region: + return + prompt = str(op.get("prompt") or "").strip() + _ensure_region_promoted(region, action=action, prompt=prompt, note=str(op.get("note") or "")) + region["visible"] = True + scene_delta["regions"].append( + { + "region_id": region.get("region_id"), + "parent_object_id": region.get("parent_object_id"), + "action": action, + "prompt": prompt, + "current_rect": _copy((_region_display_state(doc, region).get("current_rect") or {})), + } + ) + _append_history(doc, op, note=f"{_region_action_text(action)} region {region.get('label')}") + + +def _apply_restore_region(doc: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> bool: + region = _resolve_region_layer(doc, op) + if region: + region["visible"] = True + region["promoted"] = False + region["edit_state"] = "idle" + region["local_transform"] = _default_region_transform() + region["render_intent"] = {"action": "idle", "prompt": "", "note": ""} + scene_delta["regions"].append( + { + "region_id": region.get("region_id"), + "parent_object_id": region.get("parent_object_id"), + "action": "restore", + } + ) + _append_history(doc, op, note=f"Restored region {region.get('label')}") + return True + return False + + +def _apply_patch_layer(doc: Dict[str, Any], op: Dict[str, Any], kind: str, scene_delta: Dict[str, Any]) -> None: + rect = _resolve_op_rect(doc, op) + if not rect: + return + region_layer = _resolve_region_layer(doc, op) + object_layer = _resolve_object_layer(doc, op) + follow_region = bool(op.get("follow_region", False) and region_layer) + follow_object = bool(op.get("follow_object", False) and object_layer and not follow_region) + patch: Dict[str, Any] = { + "id": f"patch_{uuid.uuid4().hex[:10]}", + "kind": kind, + "rect": rect, + "prompt": str(op.get("prompt") or ""), + "note": str(op.get("note") or ""), + "anchor_object_id": object_layer.get("scene_object_id") if object_layer else "", + "anchor_region_id": region_layer.get("region_id") if region_layer else "", + "region_id": region_layer.get("region_id") if region_layer else "", + "follow_region": follow_region, + "follow_object": follow_object, + } + if follow_region and region_layer: + region_rect = _region_display_state(doc, region_layer).get("current_rect") or {} + region_w = max(1, _int(region_rect.get("width"), 1)) + region_h = max(1, _int(region_rect.get("height"), 1)) + patch["relative_rect"] = { + "x": (rect["x"] - _int(region_rect.get("x"), 0)) / region_w, + "y": (rect["y"] - _int(region_rect.get("y"), 0)) / region_h, + "width": rect["width"] / region_w, + "height": rect["height"] / region_h, + } + elif follow_object and object_layer: + layer_w = max(1, _int(object_layer.get("width"), 1)) + layer_h = max(1, _int(object_layer.get("height"), 1)) + patch["relative_rect"] = { + "x": (rect["x"] - _int(object_layer.get("x"), 0)) / layer_w, + "y": (rect["y"] - _int(object_layer.get("y"), 0)) / layer_h, + "width": rect["width"] / layer_w, + "height": rect["height"] / layer_h, + } + doc.setdefault("patch_layers", []).append(patch) + scene_delta["patches"].append({"patch_id": patch["id"], "kind": kind, "rect": rect}) + _append_history(doc, op, note=f"Added {kind} patch") + + +def _apply_restore_patch(doc: Dict[str, Any], op: Dict[str, Any], scene_delta: Dict[str, Any]) -> None: + patch_layers = doc.get("patch_layers") + if not isinstance(patch_layers, list) or not patch_layers: + return + target_id = str(op.get("patch_id") or "").strip() + removed = None + if target_id: + for index, item in enumerate(list(patch_layers)): + if str(item.get("id") or "") == target_id: + removed = patch_layers.pop(index) + break + if removed is None: + object_id = str(op.get("object_id") or "").strip() + region_id = str(op.get("region_id") or "").strip() + for index in range(len(patch_layers) - 1, -1, -1): + item = patch_layers[index] + if object_id and str(item.get("anchor_object_id") or "") != object_id: + continue + if region_id and str(item.get("region_id") or item.get("anchor_region_id") or "") != region_id: + continue + removed = patch_layers.pop(index) + break + if removed is None and patch_layers: + removed = patch_layers.pop() + if removed is not None: + scene_delta["patches"].append({"restored_patch_id": removed.get("id")}) + _append_history(doc, op, note=f"Restored patch {removed.get('id')}") + + +def apply_patch_ops( + *, + preview: Dict[str, Any], + session_id: str, + sketch_backend: str = "sketch_v2", + output_dir: str | Path = "outputs", + ops: List[Dict[str, Any]] | None = None, + source_candidate_id: str | None = None, +) -> Dict[str, Any]: + prepared = ensure_editable_preview( + preview=preview, + session_id=session_id, + sketch_backend=sketch_backend, + output_dir=output_dir, + force_rebuild=False, + source_candidate_id=source_candidate_id, + ) + if not isinstance(prepared, dict): + return {"preview": preview, "scene_sync_delta": {"objects": [], "regions": [], "patches": []}, "render_sync_ready": False} + if not prepared.get("editable_sketch_enabled"): + return {"preview": prepared, "scene_sync_delta": {"objects": [], "regions": [], "patches": []}, "render_sync_ready": False} + + doc = _copy(prepared.get("editable_sketch_doc") or {}) + scene_spec = _copy(prepared.get("scene_spec") or {}) + ops = [item for item in (ops or []) if isinstance(item, dict)] + scene_delta = {"objects": [], "regions": [], "patches": []} + + for op in ops: + op_type = str(op.get("type") or op.get("op") or "").strip() + if op_type == "transform_object": + _apply_transform_object(doc, scene_spec, op, scene_delta) + elif op_type == "set_depth": + _apply_set_depth(doc, scene_spec, op, scene_delta) + elif op_type == "hide_object": + _apply_visibility(doc, scene_spec, op, False, scene_delta) + elif op_type == "show_object": + _apply_visibility(doc, scene_spec, op, True, scene_delta) + elif op_type == "reorder_layer": + _apply_reorder(doc, scene_spec, op, scene_delta) + elif op_type == "transform_region": + _apply_transform_region(doc, op, scene_delta) + elif op_type == "hide_region": + _apply_region_visibility(doc, op, False, scene_delta) + elif op_type == "show_region": + _apply_region_visibility(doc, op, True, scene_delta) + elif op_type == "replace_region": + _apply_region_semantic_op(doc, op, "replace", scene_delta) + elif op_type == "emphasize_region": + _apply_region_semantic_op(doc, op, "emphasize", scene_delta) + elif op_type == "weaken_region": + _apply_region_semantic_op(doc, op, "weaken", scene_delta) + elif op_type == "restore_region": + if not _apply_restore_region(doc, op, scene_delta): + _apply_restore_patch(doc, op, scene_delta) + elif op_type == "inpaint_region": + if _resolve_region_layer(doc, op): + _apply_region_semantic_op(doc, op, "inpaint", scene_delta) + else: + _apply_patch_layer(doc, op, op_type, scene_delta) + elif op_type in {"erase_region", "brush_mask"}: + _apply_patch_layer(doc, op, op_type, scene_delta) + + doc["revision_id"] = _new_revision_id() + doc.setdefault("scene_sync_state", {}) + doc["scene_sync_state"]["synced_object_ids"] = sorted( + { + item.get("object_id") + for item in scene_delta.get("objects", []) + if isinstance(item, dict) and str(item.get("object_id") or "").strip() + } + ) + doc["scene_sync_state"]["pending_region_layers"] = len( + [item for item in doc.get("region_layers", []) or [] if isinstance(item, dict) and _region_is_edited(item)] + ) + doc["scene_sync_state"]["pending_patch_layers"] = len(doc.get("patch_layers", []) or []) + doc["scene_sync_state"]["last_scene_delta"] = _copy(scene_delta) + doc["depth_model"] = _default_depth_model({"object_instances": doc.get("object_layers", []) or []}) + doc = _compose_doc(doc) + updated_preview = attach_doc_to_preview(prepared, scene_spec, doc) + return { + "preview": updated_preview, + "scene_sync_delta": scene_delta, + "render_sync_ready": bool((doc.get("render_sync_state") or {}).get("ready")), + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_quality_schema.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_quality_schema.py new file mode 100644 index 0000000..9a36b3d --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_quality_schema.py @@ -0,0 +1,330 @@ +from __future__ import annotations + +import json +from dataclasses import dataclass +from typing import Any, Dict, Iterable, List, Sequence + + +SKETCH_QUALITY_SCHEMA_VERSION = "tmcra_sketch_quality_v1" +DISTANCE_TO_TARGET_VALUES = ("close", "medium", "far") +SCENE_COVERAGE_GROUPS = ("nature", "urban", "street", "indoor", "surreal", "general") +FOCUS_MODES = ( + "class_separation", + "silhouette_stability", + "line_cleanup", + "layout_to_scene_structure", + "depth_and_perspective", + "support_object_coverage", + "editability", + "target_style_alignment", +) + +DIMENSION_TO_FOCUS_MODES: dict[str, tuple[str, ...]] = { + "subject_readability": ("class_separation", "silhouette_stability"), + "line_cleanliness": ("line_cleanup", "target_style_alignment"), + "editable_control": ("editability", "layout_to_scene_structure"), + "scene_layering": ("layout_to_scene_structure", "support_object_coverage"), + "perspective_logic": ("depth_and_perspective",), + "scene_richness": ("support_object_coverage",), +} + + +@dataclass(frozen=True) +class SketchQualityDimension: + key: str + label: str + weight: float + description: str + scoring_focus: tuple[str, ...] + downgrade_signals: tuple[str, ...] + + +CANONICAL_SKETCH_QUALITY_DIMENSIONS: tuple[SketchQualityDimension, ...] = ( + SketchQualityDimension( + key="subject_readability", + label="Subject Readability", + weight=0.24, + description="Main subject class, silhouette, and semantic intent are obvious at a glance.", + scoring_focus=("class separation", "silhouette stability", "clear primary subject"), + downgrade_signals=("ambiguous subject", "merged classes", "missing key parts"), + ), + SketchQualityDimension( + key="line_cleanliness", + label="Line Cleanliness", + weight=0.2, + description="Contours are clean, stable, and usable as editable sketch structure.", + scoring_focus=("clean contour control", "consistent stroke quality", "low clutter"), + downgrade_signals=("scratchy lines", "double edges", "noisy decorative detail"), + ), + SketchQualityDimension( + key="editable_control", + label="Editable Control", + weight=0.18, + description="Geometry is controllable, decomposable, and easy to edit downstream.", + scoring_focus=("stable structure", "part boundaries", "layout controllability"), + downgrade_signals=("collapsed forms", "uneditable tangles", "weak part separation"), + ), + SketchQualityDimension( + key="scene_layering", + label="Scene Layering", + weight=0.15, + description="Foreground, midground, background, and support objects form a readable scene stack.", + scoring_focus=("depth grouping", "support object placement", "clear near-far layout"), + downgrade_signals=("flat layout", "missing support context", "foreground/background confusion"), + ), + SketchQualityDimension( + key="perspective_logic", + label="Perspective Logic", + weight=0.13, + description="Scale, overlap, road/bridge direction, skyline placement, and depth cues are coherent.", + scoring_focus=("correct scale falloff", "consistent vanishing logic", "physical plausibility"), + downgrade_signals=("broken depth", "conflicting scale", "perspective drift"), + ), + SketchQualityDimension( + key="scene_richness", + label="Scene Richness", + weight=0.1, + description="The scene includes enough secondary elements to support the subject without clutter.", + scoring_focus=("useful support objects", "scene completeness", "non-empty composition"), + downgrade_signals=("too empty", "support objects missing", "overcrowded clutter"), + ), +) + + +LEGACY_TMCRA_DIMENSION_CROSSWALK: dict[str, tuple[str, ...]] = { + "concept_clarity": ("subject_readability",), + "structural_integrity": ("editable_control", "scene_layering"), + "line_quality": ("line_cleanliness",), + "style_consistency": ("line_cleanliness", "editable_control"), + "creative_expression": ("scene_richness",), + "semantic_accuracy": ("subject_readability", "perspective_logic"), +} + + +TMCRA_SKETCH_PHILOSOPHY = ( + "TMCRA sketch training should favor semantic clarity, controllable structure, and useful scene support " + "over decorative detail. The goal is not photorealism. The goal is a readable, editable structural sketch " + "that can carry intent through the product chain: query -> scene plan -> scene line -> final sketch quality." +) + + +def dimension_keys() -> list[str]: + return [item.key for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS] + + +def dimension_specs() -> list[SketchQualityDimension]: + return list(CANONICAL_SKETCH_QUALITY_DIMENSIONS) + + +def build_output_template() -> dict[str, Any]: + payload: dict[str, Any] = { + "schema_version": SKETCH_QUALITY_SCHEMA_VERSION, + "overall_score": 0.0, + } + for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS: + payload[item.key] = 0.0 + payload.update( + { + "distance_to_target": "medium", + "major_gaps": ["gap"], + "retrain_focus": ["class_separation"], + "verdict": "needs_targeted_retrain", + "adaptive_training_policy": { + "generalization_strength": 0.0, + "specialization_strength": 0.0, + "synthetic_data_priority": 0.0, + "base_data_priority": 0.0, + "scene_coverage_groups": ["general"], + "focus_modes": ["layout_to_scene_structure"], + "rationale": "short reason", + }, + } + ) + return payload + + +def output_template_json() -> str: + return json.dumps(build_output_template(), ensure_ascii=False, indent=2) + + +def build_vlm_judge_prompt() -> str: + lines = [ + "You are reviewing a clean-line sketch preview generated during TMCRA training.", + TMCRA_SKETCH_PHILOSOPHY, + "", + "Score every primary dimension from 0.0 to 10.0.", + "Use harsher penalties for unreadable structure, weak class separation, bad depth logic, and messy outlines than for lack of decorative detail.", + "", + "Primary dimensions:", + ] + for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS: + focus = ", ".join(item.scoring_focus) + penalties = ", ".join(item.downgrade_signals) + lines.append( + f"- {item.key} ({item.label}, weight {item.weight:.2f}): {item.description} " + f"Focus on {focus}. Downgrade for {penalties}." + ) + lines.extend( + [ + "", + "Older TMCRA internal rubric ideas should be translated into the production-facing dimensions above using this crosswalk:", + ] + ) + for legacy_key, canonical_keys in LEGACY_TMCRA_DIMENSION_CROSSWALK.items(): + lines.append(f"- {legacy_key} -> {', '.join(canonical_keys)}") + lines.extend( + [ + "", + "Important scoring rule: favor readability, controllable structure, class separation, clean editable outlines, correct near-far logic, coherent perspective, and rich but uncluttered scene support over decorative detail.", + "If foreground/background size, overlap, road direction, skyline placement, bridge perspective, or object depth logic is weak, score scene_layering and perspective_logic aggressively lower.", + "If the scene is too empty, lacks support objects, or fails to provide useful secondary elements around the subject, score scene_richness lower even if the main subject is readable.", + "Use adaptive_training_policy to describe what the next training round should emphasize.", + "", + "Return strict JSON:", + output_template_json(), + ] + ) + return "\n".join(lines) + + +def _clamp_float(value: Any, *, lower: float, upper: float, default: float) -> float: + try: + parsed = float(value) + except Exception: + return default + return max(lower, min(upper, parsed)) + + +def _clean_string_list(values: Any) -> list[str]: + if not isinstance(values, Iterable) or isinstance(values, (str, bytes, dict)): + return [] + cleaned: list[str] = [] + for value in values: + token = str(value or "").strip() + if token: + cleaned.append(token) + return cleaned + + +def _mapped_legacy_scores(parsed: dict[str, Any]) -> dict[str, list[float]]: + mapped: dict[str, list[float]] = {item.key: [] for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS} + for legacy_key, canonical_keys in LEGACY_TMCRA_DIMENSION_CROSSWALK.items(): + if legacy_key not in parsed: + continue + value = _clamp_float(parsed.get(legacy_key), lower=0.0, upper=10.0, default=0.0) + for canonical_key in canonical_keys: + mapped.setdefault(canonical_key, []).append(value) + return mapped + + +def normalize_sketch_quality_result(parsed: dict[str, Any]) -> dict[str, Any]: + if not isinstance(parsed, dict): + return {} + normalized: dict[str, Any] = {} + mapped_legacy = _mapped_legacy_scores(parsed) + weighted_total = 0.0 + weight_sum = 0.0 + for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS: + raw_value = parsed.get(item.key) + if raw_value is None and mapped_legacy.get(item.key): + raw_value = sum(mapped_legacy[item.key]) / len(mapped_legacy[item.key]) + value = _clamp_float(raw_value, lower=0.0, upper=10.0, default=0.0) + normalized[item.key] = value + weighted_total += value * item.weight + weight_sum += item.weight + overall_default = weighted_total / weight_sum if weight_sum > 0 else 0.0 + normalized["schema_version"] = str(parsed.get("schema_version") or SKETCH_QUALITY_SCHEMA_VERSION) + normalized["overall_score"] = _clamp_float( + parsed.get("overall_score"), + lower=0.0, + upper=10.0, + default=overall_default, + ) + distance = str(parsed.get("distance_to_target") or "medium").strip().lower() + distance_aliases = { + "moderate": "medium", + "mid": "medium", + "good": "close", + "poor": "far", + } + distance = distance_aliases.get(distance, distance) + normalized["distance_to_target"] = distance if distance in DISTANCE_TO_TARGET_VALUES else "medium" + fallback_gap_dimensions = [ + item.label + for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS + if normalized[item.key] < 6.0 + ] + major_gaps = _clean_string_list(parsed.get("major_gaps")) + if not major_gaps: + major_gaps = [f"{label} is weak" for label in fallback_gap_dimensions[:3]] + normalized["major_gaps"] = major_gaps + retrain_focus = [token for token in _clean_string_list(parsed.get("retrain_focus")) if token in FOCUS_MODES] + if not retrain_focus: + weakest_dimensions = sorted( + CANONICAL_SKETCH_QUALITY_DIMENSIONS, + key=lambda item: normalized[item.key], + )[:2] + derived_focus: list[str] = [] + for item in weakest_dimensions: + for token in DIMENSION_TO_FOCUS_MODES.get(item.key, ()): + if token not in derived_focus: + derived_focus.append(token) + retrain_focus = derived_focus + normalized["retrain_focus"] = retrain_focus + verdict = str(parsed.get("verdict") or "").strip().lower() + if not verdict: + minimum_dimension = min(normalized[item.key] for item in CANONICAL_SKETCH_QUALITY_DIMENSIONS) + if normalized["overall_score"] >= 8.5 and minimum_dimension >= 8.0: + verdict = "target_close_enough" + elif normalized["overall_score"] >= 7.0: + verdict = "continue_with_targeted_cleanup" + else: + verdict = "needs_targeted_retrain" + normalized["verdict"] = verdict + adaptive_policy = parsed.get("adaptive_training_policy") + policy_payload = adaptive_policy if isinstance(adaptive_policy, dict) else {} + normalized["adaptive_training_policy"] = { + "generalization_strength": _clamp_float( + policy_payload.get("generalization_strength"), lower=0.0, upper=1.0, default=0.0 + ), + "specialization_strength": _clamp_float( + policy_payload.get("specialization_strength"), lower=0.0, upper=1.0, default=0.0 + ), + "synthetic_data_priority": _clamp_float( + policy_payload.get("synthetic_data_priority"), lower=0.0, upper=1.0, default=0.0 + ), + "base_data_priority": _clamp_float( + policy_payload.get("base_data_priority"), lower=0.0, upper=1.0, default=0.0 + ), + "scene_coverage_groups": [ + token + for token in (item.strip().lower() for item in _clean_string_list(policy_payload.get("scene_coverage_groups"))) + if token in SCENE_COVERAGE_GROUPS + ], + "focus_modes": [ + token + for token in _clean_string_list(policy_payload.get("focus_modes")) + if token in FOCUS_MODES + ], + "rationale": str(policy_payload.get("rationale") or "").strip(), + } + return normalized + + +__all__ = [ + "CANONICAL_SKETCH_QUALITY_DIMENSIONS", + "DISTANCE_TO_TARGET_VALUES", + "DIMENSION_TO_FOCUS_MODES", + "FOCUS_MODES", + "LEGACY_TMCRA_DIMENSION_CROSSWALK", + "SCENE_COVERAGE_GROUPS", + "SKETCH_QUALITY_SCHEMA_VERSION", + "SketchQualityDimension", + "TMCRA_SKETCH_PHILOSOPHY", + "build_output_template", + "build_vlm_judge_prompt", + "dimension_keys", + "dimension_specs", + "normalize_sketch_quality_result", + "output_template_json", +] diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_style_spec.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_style_spec.py new file mode 100644 index 0000000..b6ffb1a --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_style_spec.py @@ -0,0 +1,333 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +SKETCH_VIEW_MODE_ALIASES: Dict[str, str] = { + "rough": "rough", + "base": "rough", + "structure": "structure", + "structural": "structure", + "annotated": "annotated", + "annotation": "annotated", + "region": "region", + "region_overlay": "region", +} + + +DEFAULT_LAYOUT_FLAGS: Dict[str, Any] = { + "sketch_view_mode": "structure", + "annotation_level": "light", + "region_edit_enabled": True, +} + + +REGION_ACTION_LABELS: Dict[str, str] = { + "hide": "隐藏", + "weaken": "弱化", + "emphasize": "强调", + "replace": "替换", +} + + +STROKE_STYLE_PRESETS: Dict[str, Dict[str, Any]] = { + "scribble_line": { + "line_width": 1.0, + "secondary_line_width": 0.76, + "guide_opacity": 0.28, + "roughness": 0.72, + "fill_opacity": 0.1, + "annotation_color": "#f97316", + "region_color": "#38bdf8", + "region_fill": "rgba(56, 189, 248, 0.14)", + }, + "clean_line": { + "line_width": 0.94, + "secondary_line_width": 0.72, + "guide_opacity": 0.2, + "roughness": 0.18, + "fill_opacity": 0.08, + "annotation_color": "#eab308", + "region_color": "#38bdf8", + "region_fill": "rgba(56, 189, 248, 0.12)", + }, + "blueprint": { + "line_width": 0.92, + "secondary_line_width": 0.72, + "guide_opacity": 0.24, + "roughness": 0.12, + "fill_opacity": 0.06, + "annotation_color": "#fb7185", + "region_color": "#7dd3fc", + "region_fill": "rgba(125, 211, 252, 0.12)", + }, + "wireframe": { + "line_width": 0.88, + "secondary_line_width": 0.68, + "guide_opacity": 0.18, + "roughness": 0.06, + "fill_opacity": 0.03, + "annotation_color": "#0ea5e9", + "region_color": "#94a3b8", + "region_fill": "rgba(148, 163, 184, 0.08)", + }, +} + + +def normalize_view_mode(value: str | None) -> str: + token = str(value or "").strip().lower() + return SKETCH_VIEW_MODE_ALIASES.get(token, DEFAULT_LAYOUT_FLAGS["sketch_view_mode"]) + + +def normalize_annotation_level(value: str | None) -> str: + token = str(value or "").strip().lower() + if token in {"off", "light", "edit"}: + return token + return DEFAULT_LAYOUT_FLAGS["annotation_level"] + + +def normalize_style_variant(value: str | None) -> str: + token = str(value or "").strip().lower() + if token in STROKE_STYLE_PRESETS: + return token + if token == "line_art": + return "scribble_line" + if token == "minimal": + return "clean_line" + return "scribble_line" + + +def normalize_region_action(value: str | None) -> str: + token = str(value or "").strip().lower() + if token in REGION_ACTION_LABELS: + return token + return "" + + +def action_label(value: str | None) -> str: + return REGION_ACTION_LABELS.get(normalize_region_action(value), "") + + +def build_stroke_style_profile( + asset_key: str, + *, + scene_type: str = "scene", + style_variant: str = "scribble_line", + sketch_family: str = "", +) -> Dict[str, Any]: + normalized_style = normalize_style_variant(style_variant) + preset = _copy(STROKE_STYLE_PRESETS.get(normalized_style, STROKE_STYLE_PRESETS["scribble_line"])) + family = sketch_family or infer_sketch_family(asset_key, scene_type=scene_type) + if family == "scene_subject": + preset["line_width"] = round(float(preset["line_width"]) * 1.12, 3) + preset["fill_opacity"] = round(float(preset["fill_opacity"]) + 0.03, 3) + elif family == "process_motif": + preset["secondary_line_width"] = round(float(preset["secondary_line_width"]) * 0.92, 3) + elif family == "schematic_symbol": + preset["roughness"] = round(float(preset["roughness"]) * 0.4, 3) + preset["fill_opacity"] = round(float(preset["fill_opacity"]) * 0.5, 3) + preset["style_variant"] = normalized_style + preset["scene_type"] = scene_type + preset["sketch_family"] = family + return preset + + +def infer_sketch_family(asset_key: str, *, scene_type: str = "scene") -> str: + key = str(asset_key or "").strip().lower() + if key in {"building", "house", "tree", "person", "car", "dog", "street_lamp", "table", "chair", "desk_lamp"}: + return "scene_subject" if key in {"building", "house", "person", "car", "dog"} else "scene_support" + if key in {"window", "door"}: + return "scene_detail" + if key in {"cloud", "sun", "road"}: + return "scene_environment" + if key in {"cycle", "flow_node", "energy_wave", "vapor", "raindrop", "leaf", "airplane", "cell"}: + return "process_motif" + if key in {"battery", "led", "resistor", "capacitor", "diode", "board", "module", "branch"}: + return "schematic_symbol" + if scene_type == "process": + return "process_motif" + if scene_type == "schematic": + return "schematic_symbol" + return "scene_support" + + +def default_readability_rank(asset_key: str, *, scene_type: str = "scene") -> int: + key = str(asset_key or "").strip().lower() + if key in {"building", "house", "tree", "person", "car", "cloud", "sun", "street_lamp", "battery", "led", "resistor"}: + return 5 + if key in {"window", "door", "road", "leaf", "airplane", "cycle", "flow_node", "vapor", "energy_wave"}: + return 4 + if key in {"module", "branch", "cell", "board", "capacitor", "diode"}: + return 3 + if scene_type == "scene": + return 2 + return 3 + + +def _rect_region(region_id: str, label: str, x: float, y: float, width: float, height: float, **extra: Any) -> Dict[str, Any]: + payload = { + "id": region_id, + "label": label, + "shape": "rect", + "x": x, + "y": y, + "width": width, + "height": height, + "editable": True, + } + payload.update(extra) + return payload + + +def _ellipse_region(region_id: str, label: str, x: float, y: float, width: float, height: float, **extra: Any) -> Dict[str, Any]: + payload = { + "id": region_id, + "label": label, + "shape": "ellipse", + "x": x, + "y": y, + "width": width, + "height": height, + "editable": True, + } + payload.update(extra) + return payload + + +def default_region_masks(asset_key: str, *, scene_type: str = "scene") -> List[Dict[str, Any]]: + key = str(asset_key or "").strip().lower() + if key in {"building", "house"}: + return [ + _rect_region("roofline", "屋顶区域", 0.08, 0.02, 0.84, 0.22, actions=["emphasize", "weaken"]), + _rect_region("window_row", "窗户区域", 0.16, 0.16, 0.68, 0.42, actions=["replace", "weaken", "hide"]), + _rect_region("door_zone", "门区", 0.38, 0.54, 0.24, 0.42, actions=["replace", "hide"]), + _rect_region("facade", "立面", 0.1, 0.12, 0.8, 0.84, actions=["emphasize", "weaken"]), + ] + if key == "person": + return [ + _ellipse_region("head", "头部", 0.32, 0.02, 0.36, 0.26, actions=["emphasize", "weaken"]), + _ellipse_region("face", "脸部", 0.36, 0.08, 0.28, 0.18, actions=["replace", "weaken"]), + _rect_region("beard", "胡子区域", 0.38, 0.16, 0.24, 0.12, actions=["hide", "replace", "weaken"]), + _rect_region("torso", "上身", 0.28, 0.26, 0.44, 0.34, actions=["emphasize", "weaken"]), + _rect_region("legs", "下身", 0.24, 0.58, 0.52, 0.4, actions=["emphasize", "weaken"]), + ] + if key == "tree": + return [ + _ellipse_region("canopy", "树冠", 0.08, 0.04, 0.84, 0.58, actions=["hide", "replace", "weaken", "emphasize"]), + _rect_region("trunk", "树干", 0.4, 0.54, 0.2, 0.42, actions=["weaken", "emphasize"]), + ] + if key == "car": + return [ + _rect_region("cabin", "驾驶舱", 0.22, 0.18, 0.58, 0.28, actions=["replace", "weaken"]), + _rect_region("body", "车身", 0.08, 0.38, 0.84, 0.34, actions=["emphasize", "weaken"]), + _ellipse_region("front_wheel", "前轮", 0.14, 0.68, 0.22, 0.22, actions=["hide", "replace"]), + _ellipse_region("rear_wheel", "后轮", 0.6, 0.68, 0.22, 0.22, actions=["hide", "replace"]), + ] + if key == "street_lamp": + return [ + _rect_region("pole", "灯杆", 0.42, 0.18, 0.16, 0.78, actions=["weaken", "emphasize"]), + _ellipse_region("lamp_head", "灯头", 0.68, 0.18, 0.18, 0.18, actions=["replace", "hide"]), + _ellipse_region("light_cone", "光照范围", 0.5, 0.26, 0.38, 0.38, actions=["weaken", "emphasize"]), + ] + if key == "cloud": + return [_ellipse_region("cloud_mass", "云团", 0.04, 0.18, 0.88, 0.58, actions=["hide", "replace", "weaken"])] + if key == "sun": + return [ + _ellipse_region("sun_core", "太阳主体", 0.24, 0.24, 0.52, 0.52, actions=["hide", "replace", "weaken"]), + _rect_region("rays", "光线", 0.04, 0.04, 0.92, 0.92, actions=["weaken", "emphasize"]), + ] + if key in {"cycle", "flow_node", "energy_wave", "vapor"}: + return [ + _rect_region("core_flow", "主流程", 0.12, 0.16, 0.76, 0.56, actions=["replace", "weaken", "emphasize"]), + _rect_region("markers", "辅助标记", 0.08, 0.04, 0.84, 0.2, actions=["hide", "replace"]), + ] + if key in {"battery", "led", "resistor", "capacitor", "diode", "board", "module"}: + return [ + _rect_region("body", "主体区域", 0.12, 0.18, 0.76, 0.56, actions=["replace", "weaken"]), + _rect_region("terminals", "连接端", 0.02, 0.36, 0.96, 0.28, actions=["hide", "emphasize"]), + ] + return [_rect_region("core", "主体区域", 0.14, 0.14, 0.72, 0.72, actions=["replace", "weaken", "hide", "emphasize"])] + + +def default_part_graph(asset_key: str, *, scene_type: str = "scene") -> List[Dict[str, Any]]: + key = str(asset_key or "").strip().lower() + graphs: Dict[str, List[Dict[str, Any]]] = { + "building": [ + {"id": "roofline", "label": "屋顶", "kind": "part", "region_id": "roofline"}, + {"id": "window_row", "label": "窗户组", "kind": "part", "region_id": "window_row"}, + {"id": "door_zone", "label": "门区", "kind": "part", "region_id": "door_zone"}, + ], + "house": [ + {"id": "roofline", "label": "屋顶", "kind": "part", "region_id": "roofline"}, + {"id": "window_row", "label": "窗户组", "kind": "part", "region_id": "window_row"}, + {"id": "door_zone", "label": "门区", "kind": "part", "region_id": "door_zone"}, + ], + "person": [ + {"id": "head", "label": "头部", "kind": "part", "region_id": "head"}, + {"id": "face", "label": "脸部", "kind": "part", "region_id": "face"}, + {"id": "beard", "label": "胡子", "kind": "part", "region_id": "beard"}, + {"id": "torso", "label": "上身", "kind": "part", "region_id": "torso"}, + {"id": "legs", "label": "下身", "kind": "part", "region_id": "legs"}, + ], + "tree": [ + {"id": "canopy", "label": "树冠", "kind": "part", "region_id": "canopy"}, + {"id": "trunk", "label": "树干", "kind": "part", "region_id": "trunk"}, + ], + "car": [ + {"id": "cabin", "label": "驾驶舱", "kind": "part", "region_id": "cabin"}, + {"id": "body", "label": "车身", "kind": "part", "region_id": "body"}, + {"id": "front_wheel", "label": "前轮", "kind": "part", "region_id": "front_wheel"}, + {"id": "rear_wheel", "label": "后轮", "kind": "part", "region_id": "rear_wheel"}, + ], + "street_lamp": [ + {"id": "pole", "label": "灯杆", "kind": "part", "region_id": "pole"}, + {"id": "lamp_head", "label": "灯头", "kind": "part", "region_id": "lamp_head"}, + {"id": "light_cone", "label": "光照范围", "kind": "part", "region_id": "light_cone"}, + ], + } + if key in graphs: + return _copy(graphs[key]) + return [{"id": "core", "label": "主体", "kind": "part", "region_id": "core"}] + + +def normalize_layout_options(layout: Dict[str, Any] | None, sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + merged = _copy(layout or {}) + options = sketch_options or {} + merged["sketch_view_mode"] = normalize_view_mode(options.get("sketch_view_mode") or merged.get("sketch_view_mode")) + merged["annotation_level"] = normalize_annotation_level(options.get("annotation_level") or merged.get("annotation_level")) + merged["region_edit_enabled"] = bool(options.get("region_edit_enabled", merged.get("region_edit_enabled", True))) + merged["scene_generation_backend"] = str( + options.get("scene_generation_backend") + or merged.get("scene_generation_backend") + or "unified_scene_v3" + ) + return merged + + +def summarize_region_overrides(scene_spec: Dict[str, Any] | None) -> str: + if not isinstance(scene_spec, dict): + return "" + edits: List[str] = [] + for obj in scene_spec.get("object_instances", []) or []: + concept = str(obj.get("concept") or obj.get("asset_key") or "对象").strip() + region_lookup = { + str(item.get("id") or ""): str(item.get("label") or item.get("id") or "").strip() + for item in obj.get("region_masks", []) or [] + if isinstance(item, dict) + } + overrides = obj.get("region_overrides") if isinstance(obj, dict) else {} + if not isinstance(overrides, dict): + continue + for region_id, payload in overrides.items(): + if not isinstance(payload, dict): + continue + action = action_label(payload.get("action")) + label = str(payload.get("label") or region_lookup.get(str(region_id), region_id)).strip() + if action and label: + edits.append(f"{concept}的{label}{action}") + return ";".join(edits[:12]) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_v2.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_v2.py new file mode 100644 index 0000000..92e4b70 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/sketch_v2.py @@ -0,0 +1,1478 @@ +from __future__ import annotations + +import base64 +import json +import mimetypes +import os +from collections import Counter +from pathlib import Path +from typing import Any, Dict, List + +import requests +from loguru import logger +from PIL import Image + +from .default_model_paths import resolve_default_sketch_lora_alias +from .sd_sketch_generator import SDSketchGenerator +from .semantic_scene_v2 import normalize_scene_spec_v2, summarize_scene_spec + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +class SketchV2Generator: + def __init__( + self, + *, + output_dir: str = "outputs", + sd_api_url: str = "", + image_api_url: str = "", + image_api_key: str = "", + image_api_model: str = "", + image_api_size: str = "", + ) -> None: + self.output_dir = output_dir + Path(self.output_dir).mkdir(parents=True, exist_ok=True) + self.sd_generator = SDSketchGenerator(output_dir=output_dir, sd_api_url=sd_api_url) + self.image_api_url = str(image_api_url or "").strip().rstrip("/") + self.image_api_key = str(image_api_key or "").strip() + self.image_api_model = str(image_api_model or "").strip() + self.image_api_size = str(image_api_size or "").strip() + + @property + def sd_available(self) -> bool: + return self.sd_generator.available + + @property + def image_api_available(self) -> bool: + return self.image_api_url.startswith("http") and bool(self.image_api_key) + + def set_sd_api_url(self, api_url: str) -> None: + self.sd_generator.set_sd_api_url(api_url) + + def set_image_api_url(self, api_url: str) -> None: + self.image_api_url = str(api_url or "").strip().rstrip("/") + + def set_image_api_key(self, api_key: str) -> None: + self.image_api_key = str(api_key or "").strip() + + def set_image_api_model(self, model_name: str) -> None: + self.image_api_model = str(model_name or "").strip() + + def set_image_api_size(self, image_size: str) -> None: + self.image_api_size = str(image_size or "").strip() + + def _clean_text(self, value: Any) -> str: + text = str(value or "").replace("\n", " ").replace("\r", " ").replace("|", " ").strip() + return " ".join(text.split()).strip(" ,;,;。") + + def _control_image_path(self, preview: Dict[str, Any]) -> str: + sketch_bundle = preview.get("sketch_bundle", {}) if isinstance(preview.get("sketch_bundle"), dict) else {} + for candidate in ( + sketch_bundle.get("sd_upstream_control"), + sketch_bundle.get("rich_preview"), + preview.get("sd_upstream_control_path"), + preview.get("rich_preview_path"), + preview.get("render_control_path"), + preview.get("low_preview_path"), + preview.get("image_path"), + ): + value = str(candidate or "").strip() + if value and os.path.exists(value): + return value + return "" + + def _upstream_control_image_path(self, preview: Dict[str, Any]) -> str: + sketch_bundle = preview.get("sketch_bundle", {}) if isinstance(preview.get("sketch_bundle"), dict) else {} + render_bundle = preview.get("render_bundle", {}) if isinstance(preview.get("render_bundle"), dict) else {} + visible_outputs = render_bundle.get("visible_outputs", {}) if isinstance(render_bundle.get("visible_outputs"), dict) else {} + for candidate in ( + sketch_bundle.get("sd_upstream_control"), + visible_outputs.get("sd_upstream_control_path"), + preview.get("sd_upstream_control_path"), + sketch_bundle.get("rich_preview"), + visible_outputs.get("rich_preview_path"), + preview.get("rich_preview_path"), + sketch_bundle.get("structural_sketch"), + visible_outputs.get("structural_sketch_path"), + preview.get("low_preview_path"), + preview.get("render_control_path"), + preview.get("image_path"), + ): + value = str(candidate or "").strip() + if value and os.path.exists(value): + return value + return "" + + def _scene_type(self, scene_spec: Dict[str, Any] | None) -> str: + if not isinstance(scene_spec, dict): + return "scene" + layout_options = scene_spec.get("layout_options", {}) if isinstance(scene_spec.get("layout_options"), dict) else {} + return str(layout_options.get("scene_type") or layout_options.get("composition_mode") or "scene").strip().lower() or "scene" + + def _prompt_anchor_name(self, item: Dict[str, Any]) -> str: + asset_key = self._clean_text(item.get("asset_key") or "") + concept = self._clean_text(item.get("concept") or item.get("label") or "") + if asset_key and concept and concept.lower() != asset_key.lower(): + return f"{asset_key} ({concept})" + return asset_key or concept + + def _scene_asset_allowlist(self, scene_type: str) -> set[str]: + if scene_type == "process": + return {"sun", "vapor", "cloud", "raindrop", "leaf", "energy_wave", "airplane", "cell"} + if scene_type == "schematic": + return {"battery", "resistor", "led", "switch", "capacitor", "diode", "board"} + return {"person", "house", "home", "building", "tree", "leaf", "plant", "bush", "road", "car", "street_lamp", "cloud", "sun", "dog", "table", "chair", "desk_lamp"} + + def _noise_prompt_terms(self) -> tuple[str, ...]: + return ( + "tri-maze", + "scene sketch", + "semantic sketch", + "readable", + "editable", + "direct edit", + "directly edit", + "include", + "contains", + "containing", + "后续", + "可编辑", + "直接编辑", + "语义草图", + "场景草图", + "包含", + "结构", + "说明", + "描述", + "阶段一", + "阶段二", + "阶段三", + "电路结构", + ) + + def _should_skip_object_hint(self, scene_type: str, item: Dict[str, Any]) -> bool: + asset_key = self._clean_text(item.get("asset_key") or "").lower() + concept = self._clean_text(item.get("concept") or item.get("label") or "") + lowered_concept = concept.lower() + if not asset_key and not concept: + return True + allowlist = self._scene_asset_allowlist(scene_type) + if asset_key and allowlist and asset_key not in allowlist: + return True + if concept and any(token in concept or token in lowered_concept for token in self._noise_prompt_terms()): + return True + if scene_type == "schematic" and asset_key == "switch": + return False + if scene_type == "scene" and asset_key in {"road", "car", "street_lamp"} and any(token in concept for token in ("电路", "结构", "模块", "元件")): + return True + return False + + def _simple_anchor_name(self, item: Dict[str, Any]) -> str: + asset_key = self._clean_text(item.get("asset_key") or "").lower() + concept = self._clean_text(item.get("concept") or item.get("label") or "") + if asset_key == "street_lamp": + return "street lamp" + if asset_key == "desk_lamp": + return "desk lamp" + if asset_key == "energy_wave": + return "sunlight ray" + if asset_key == "raindrop": + return "rain" + if asset_key == "vapor": + return "evaporation vapor" + if asset_key == "switch": + return "switch" + if asset_key == "board": + return "circuit board" + if asset_key == "module": + if "开关" in concept: + return "switch" + if "传感" in concept: + return "sensor module" + return "module" + return asset_key or concept.lower() + + def _sd_anchor_phrases(self, scene_plan: Dict[str, Any]) -> List[str]: + scene_type = str(scene_plan.get("scene_type", "scene") or "scene") + phrases: List[str] = [] + seen_names: set[str] = set() + for item in scene_plan.get("object_hints") or []: + if not isinstance(item, dict): + continue + name = self._simple_anchor_name(item) + if not name or name in seen_names: + continue + seen_names.add(name) + position = self._clean_text(str(item.get("position") or "").replace("-", " ")) + depth_band = self._clean_text(item.get("depth_band") or "") + phrase = f"one {name}" + if scene_type == "scene" and name == "person": + phrase = "one full-body person" + if position and position not in {"middle center", "center"}: + phrase += f" at {position}" + if depth_band in {"foreground", "background"}: + phrase += f" in {depth_band}" + phrases.append(phrase) + return phrases[:6] + + def _build_sd_prompt(self, scene_plan: Dict[str, Any], variation_index: int) -> str: + scene_type = str(scene_plan.get("scene_type", "scene") or "scene") + asset_keys = { + str(item).strip().lower() + for item in (scene_plan.get("asset_keys") or []) + if str(item).strip() + } + anchors = self._sd_anchor_phrases(scene_plan) + parts: List[str] = [ + "monochrome pencil line sketch", + "plain white paper background", + "wide landscape composition", + "all requested subjects fully visible inside the frame", + "clean readable contours", + "light sketch shading only", + "no text in image", + ] + if scene_type == "process": + parts.extend( + [ + "single integrated process scene", + "natural spatial flow instead of boxed infographic panels", + "no title area, no panel borders, no ornamental frame", + ] + ) + elif scene_type == "schematic": + parts.extend( + [ + "technical hand-drawn circuit sketch", + "clear component spacing on blank paper", + "simple connection structure", + "no blueprint title block, no product design sheet", + ] + ) + else: + parts.extend( + [ + "outdoor whole-scene street view", + "natural scene composition", + "not a close-up crop", + ] + ) + if anchors: + parts.append(", ".join(anchors)) + if scene_type == "scene": + if {"house", "building"} & asset_keys: + parts.append("show roofline, windows, facade, and door clearly") + if "tree" in asset_keys: + parts.append("show tree canopy and trunk clearly") + if "person" in asset_keys: + parts.append("show head, torso, arms, and legs clearly") + if {"house", "tree", "person"} <= asset_keys: + parts.append("show one full-body person standing near the house and tree, not omitted and not replaced by another object") + parts.append("place the person in the open space between the tree and the house, clearly separated from both and not hidden behind the tree") + elif scene_type == "process": + if {"sun", "vapor", "cloud", "raindrop"} & asset_keys: + parts.append("show evaporation rising, cloud forming, and rain falling in one readable scene") + parts.append("educational water cycle illustration, sun heating water, vapor rising upward, cloud above, rain falling down, runoff flowing back across the ground") + parts.append("avoid diagram boxes and avoid decorative poster layout") + elif scene_type == "schematic": + if {"battery", "resistor", "led"} & asset_keys: + parts.append("show battery, resistor, led, and switch as simple readable components") + parts.append("single-loop hand-drawn circuit on paper, visible wires connecting battery to switch, resistor, and led in order") + parts.append("connected engineering sketch, not an industrial product concept page") + variations = [ + "balanced composition and stronger subject readability", + "clearer silhouettes and cleaner scene hierarchy", + "less clutter and more stable object identity", + "more open negative space and clearer separation between anchors", + ] + parts.append(variations[variation_index % len(variations)]) + return ", ".join(self._clean_text(part) for part in parts if self._clean_text(part)) + + def _default_background_summary(self, scene_type: str, objects: List[Dict[str, str]]) -> str: + anchors = ", ".join( + item.get("prompt_name") or item.get("concept") or "" + for item in objects[:4] + if item.get("prompt_name") or item.get("concept") + ) + if scene_type == "process": + return "plain open background with natural process flow and no boxed panels" + if scene_type == "schematic": + return "blank paper with open negative space for readable components and wire connections" + if anchors: + return f"simple street-scene environment around {anchors}" + return "simple readable scene environment with open sky and ground plane" + + def _editable_detail_summary(self, objects: List[Dict[str, str]]) -> str: + asset_keys = {str(item.get("asset_key") or "").strip().lower() for item in objects} + details: List[str] = [] + if {"house", "building"} & asset_keys: + details.append("roofline, windows, and door stay clear and editable") + if "person" in asset_keys: + details.append("human silhouette, head, torso, and legs stay readable") + if "tree" in asset_keys: + details.append("tree canopy and trunk stay readable") + return ", ".join(details[:3]) + + def _prompt_title_text(self, title: str | None = None) -> str: + cleaned = self._clean_text(title or "") + if not cleaned: + return "" + return cleaned if len(cleaned) <= 48 else "" + + def _anchor_layout_summary(self, objects: List[Dict[str, str]]) -> str: + anchors: List[str] = [] + for item in objects[:6]: + anchor = self._clean_text(item.get("asset_key") or item.get("concept") or item.get("prompt_name") or "") + position = self._clean_text(str(item.get("position") or "").replace("-", " ")) + depth = self._clean_text(item.get("depth_band") or "") + if not anchor: + continue + phrase = f"one {anchor}" + if position: + phrase += f" at {position}" + if depth: + phrase += f" in {depth}" + anchors.append(phrase) + return "; ".join(anchors) + + def _object_hint_priority(self, item: Dict[str, Any]) -> Tuple[int, int, float, float]: + role = str(item.get("role") or "").strip().lower() + depth_band = str(item.get("depth_band") or "").strip().lower() + asset_key = str(item.get("asset_key") or "").strip().lower() + role_priority = { + "subject": 0, + "focus": 0, + "core_subject": 0, + "primary": 1, + "support": 2, + "detail": 3, + }.get(role, 4) + depth_priority = { + "midground": 0, + "foreground": 1, + "background": 2, + }.get(depth_band, 3) + human_bonus = 0 if asset_key in {"person", "human", "figure", "character"} else 1 + position_bonus = abs(float(item.get("_x_center", 0.5) or 0.5) - 0.5) + abs(float(item.get("_y_center", 0.5) or 0.5) - 0.5) * 0.6 + return (role_priority, human_bonus + depth_priority * 2, position_bonus, -float(item.get("_area", 0.0) or 0.0)) + + def _anchor_presence_summary(self, scene_plan: Dict[str, Any]) -> str: + objects = list(scene_plan.get("object_hints") or []) + if not objects: + return "" + must_keep: List[str] = [] + asset_keys = { + str(item.get("asset_key") or "").strip().lower() + for item in objects + if str(item.get("asset_key") or "").strip() + } + if "person" in asset_keys: + must_keep.append("Keep one clearly visible standing person; head, torso, arms, and legs must remain readable and must not disappear.") + if "house" in asset_keys: + must_keep.append("Keep one readable house with roofline, facade, windows, and door still visible.") + if "tree" in asset_keys: + must_keep.append("Keep one readable tree with both canopy and trunk visible.") + return " ".join(must_keep[:3]) + + def _object_hints(self, scene_spec: Dict[str, Any] | None) -> List[Dict[str, str]]: + hints: List[Dict[str, str]] = [] + if not isinstance(scene_spec, dict): + return hints + scene_type = self._scene_type(scene_spec) + canvas = scene_spec.get("canvas_size", {}) if isinstance(scene_spec.get("canvas_size"), dict) else {} + width = max(1.0, float(canvas.get("width", 1024) or 1024)) + height = max(1.0, float(canvas.get("height", 768) or 768)) + for item in scene_spec.get("object_instances", []) or []: + if not isinstance(item, dict): + continue + if self._should_skip_object_hint(scene_type, item): + continue + asset_key = self._clean_text(item.get("asset_key") or "") + concept = self._clean_text(item.get("concept") or item.get("label") or asset_key or "") + prompt_name = self._prompt_anchor_name( + { + "asset_key": asset_key, + "concept": concept, + "label": self._clean_text(item.get("label") or ""), + } + ) + if not prompt_name: + continue + x_center = (float(item.get("x", 0) or 0) + float(item.get("width", 0) or 0) / 2.0) / width + y_center = (float(item.get("y", 0) or 0) + float(item.get("height", 0) or 0) / 2.0) / height + if x_center <= 0.28: + horizontal = "left" + elif x_center >= 0.72: + horizontal = "right" + else: + horizontal = "center" + if y_center <= 0.34: + vertical = "upper" + elif y_center >= 0.66: + vertical = "lower" + else: + vertical = "middle" + hints.append( + { + "concept": concept, + "asset_key": asset_key, + "prompt_name": prompt_name, + "role": str(item.get("role", "") or ""), + "depth_band": str(item.get("depth_band", "") or ""), + "position": f"{vertical}-{horizontal}", + "_x_center": x_center, + "_y_center": y_center, + "_area": float(item.get("width", 0) or 0) * float(item.get("height", 0) or 0), + "size": "large" + if float(item.get("width", 0) or 0) * float(item.get("height", 0) or 0) >= width * height * 0.1 + else "medium" + if float(item.get("width", 0) or 0) * float(item.get("height", 0) or 0) >= width * height * 0.035 + else "small", + } + ) + hints.sort(key=self._object_hint_priority) + return hints[:8] + + def build_scene_plan( + self, + scene_spec: Dict[str, Any] | None, + sketch_options: Dict[str, Any] | None = None, + *, + title: str | None = None, + ) -> Dict[str, Any]: + sketch_options = sketch_options or {} + scene_spec = scene_spec if isinstance(scene_spec, dict) else {} + scene_type = self._scene_type(scene_spec) + render_hints = scene_spec.get("render_hints", {}) if isinstance(scene_spec.get("render_hints"), dict) else {} + objects = self._object_hints(scene_spec) + subject_hints = [item.get("prompt_name") or item["concept"] for item in objects if item.get("role") in {"subject", "focus", "core_subject"}] + if not subject_hints: + subject_hints = [item.get("prompt_name") or item["concept"] for item in objects[:3]] + backgrounds = [] + for item in scene_spec.get("background_layers", []) or []: + if not isinstance(item, dict): + continue + label = self._clean_text(item.get("label") or item.get("type") or "") + if label: + backgrounds.append(label) + composition_bits = [f'{item.get("prompt_name") or item["concept"]} {item["position"]}' for item in objects[:5]] + depth_counts: Dict[str, int] = {} + for item in objects: + depth = str(item.get("depth_band") or "") + if not depth: + continue + depth_counts[depth] = depth_counts.get(depth, 0) + 1 + depth_summary = ", ".join(f"{key}:{value}" for key, value in depth_counts.items()) or "foreground, midground, background separation" + style_summary = ", ".join( + part + for part in [ + str(sketch_options.get("sketch_style", "scribble_line") or "scribble_line"), + self._clean_text(sketch_options.get("style_hint") or ""), + ] + if part + ) + if not style_summary: + style_summary = "readable whole-scene sketch" + negative_constraints = [ + "symbol collage", + "node boxes", + "arrow labels", + "flat icon layout", + "unreadable overlapping objects", + ] + if scene_type == "process": + negative_constraints.extend(["ppt slide", "flowchart boxes", "mind map"]) + elif scene_type == "schematic": + negative_constraints.extend(["pcb photo", "chip macro photo", "motherboard photo"]) + else: + negative_constraints.extend(["sticker collage", "poster layout"]) + subject_summary_hint = self._clean_text(render_hints.get("subject_summary") or "") + if len(objects) > 1: + subject_summary_hint = "" + scene_summary_hint = self._clean_text(render_hints.get("scene_summary") or "") + cleaned_title = self._clean_text(title or "") + if ( + scene_summary_hint == cleaned_title + or (cleaned_title and scene_summary_hint and (scene_summary_hint in cleaned_title or cleaned_title in scene_summary_hint)) + or len(scene_summary_hint) > 96 + ): + scene_summary_hint = "" + if scene_summary_hint and any(token in scene_summary_hint for token in ("请", "生成", "不要", "方便", "草图", "后续", "可读")): + scene_summary_hint = "" + must_include_summary = ", ".join( + item.get("prompt_name") or item.get("concept") or "" + for item in objects[:6] + if item.get("prompt_name") or item.get("concept") + ) + asset_counts: Counter[str] = Counter( + str(item.get("asset_key") or "").strip().lower() + for item in objects + if str(item.get("asset_key") or "").strip() + ) + exact_elements_summary = ", ".join( + f'{count} {asset_key}' if count > 1 else f'one {asset_key}' + for asset_key, count in asset_counts.items() + ) + anchor_layout_summary = self._anchor_layout_summary(objects) + subject_summary = self._clean_text( + subject_summary_hint + or (must_include_summary if len(asset_counts) > 1 else ", ".join(subject_hints[:4])) + or cleaned_title + or "main scene subject" + ) + background_summary = self._default_background_summary(scene_type, objects) + if scene_type == "scene" and backgrounds: + background_summary = ", ".join(backgrounds[:4]) + return { + "scene_type": scene_type, + "subject_summary": subject_summary, + "background_summary": self._clean_text(scene_summary_hint or background_summary), + "composition_summary": self._clean_text(", ".join(composition_bits) or "clear hierarchy, readable layout, coherent scene composition"), + "depth_summary": depth_summary, + "style_summary": style_summary, + "negative_constraints": negative_constraints, + "object_hints": objects, + "must_include_summary": must_include_summary, + "anchor_layout_summary": anchor_layout_summary, + "editable_detail_summary": self._editable_detail_summary(objects), + "asset_keys": list(asset_counts.keys()), + "asset_counts": dict(asset_counts), + "exact_elements_summary": exact_elements_summary, + } + + def _prompt_prefix(self, scene_type: str) -> str: + if scene_type == "process": + return "Create a highly readable whole-scene process sketch with coherent stages and spatial flow." + if scene_type == "schematic": + return "Create a highly readable technical sketch with clear structure and clean spatial organization." + return "Create a highly readable whole-scene sketch with natural composition and coherent silhouettes." + + def _variation_suffix(self, provider: str, index: int, scene_type: str) -> str: + variations = { + "sd": [ + "Favor clean silhouettes, stronger subject readability, and confident contour continuity.", + "Favor expressive but readable line rhythm, better depth layering, and less symbol-like geometry.", + ], + "image_api": [ + "Favor clearer whole-scene readability, soft hand-drawn variation, and natural scene balance.", + "Favor stronger visual storytelling, cleaner hierarchy, and less mechanical object repetition.", + ], + } + bucket = variations.get(provider) or variations["image_api"] + value = bucket[index % len(bucket)] + if scene_type == "process": + value += " Keep transitions stage-like without turning into diagram boxes." + elif scene_type == "schematic": + value += " Keep the technical structure readable without turning into PCB photography." + return value + + def build_prompt( + self, + scene_plan: Dict[str, Any], + *, + provider: str, + variation_index: int, + title: str | None = None, + ) -> str: + if provider == "sd": + return self._build_sd_prompt(scene_plan, variation_index) + scene_type = str(scene_plan.get("scene_type", "scene") or "scene") + prompt_title = self._prompt_title_text(title) + parts = [ + self._prompt_prefix(scene_type), + "Use the provided control image only as a soft layout prior for subject placement, layering, and scale.", + "Do not copy geometric helper lines, annotation labels, arrows, boxes, colored masks, or icon-like symbols into the final sketch.", + prompt_title, + f'Subject: {self._clean_text(scene_plan.get("subject_summary") or "")}', + f'Background: {self._clean_text(scene_plan.get("background_summary") or "")}', + f'Composition: {self._clean_text(scene_plan.get("composition_summary") or "")}', + f'Depth: {self._clean_text(scene_plan.get("depth_summary") or "")}', + f'Style: {self._clean_text(scene_plan.get("style_summary") or "")}', + self._variation_suffix(provider, variation_index, scene_type), + ] + must_include_summary = self._clean_text(scene_plan.get("must_include_summary") or "") + if must_include_summary: + parts.append(f"Must clearly include all anchors: {must_include_summary}.") + exact_elements_summary = self._clean_text(scene_plan.get("exact_elements_summary") or "") + if exact_elements_summary: + parts.append(f"Exact visible elements only: {exact_elements_summary}. Do not add extra major objects or substitute object types.") + anchor_layout_summary = self._clean_text(scene_plan.get("anchor_layout_summary") or "") + if anchor_layout_summary: + parts.append(f"Exact anchor layout: {anchor_layout_summary}.") + editable_detail_summary = self._clean_text(scene_plan.get("editable_detail_summary") or "") + if editable_detail_summary: + parts.append(f"Keep editable details clear: {editable_detail_summary}.") + anchor_presence_summary = self._clean_text(self._anchor_presence_summary(scene_plan)) + if anchor_presence_summary: + parts.append(anchor_presence_summary) + object_hint_text = ", ".join( + f'{item.get("prompt_name") or item.get("concept", "")} {item.get("position", "")} {item.get("depth_band", "")}'.strip() + for item in (scene_plan.get("object_hints") or [])[:6] + if item.get("prompt_name") or item.get("concept") + ) + if object_hint_text: + parts.append(f"Object hints: {object_hint_text}.") + return ", ".join(part for part in parts if part) + + def build_negative_prompt(self, scene_plan: Dict[str, Any], sketch_style: str) -> str: + scene_type = str(scene_plan.get("scene_type", "scene") or "scene") + asset_keys = { + str(item).strip().lower() + for item in (scene_plan.get("asset_keys") or []) + if str(item).strip() + } + asset_counts = { + str(key).strip().lower(): int(value) + for key, value in dict(scene_plan.get("asset_counts") or {}).items() + if str(key).strip() + } + negatives = [ + "photorealistic", + "full color rendering", + "text", + "letters", + "chinese characters", + "caption", + "title block", + "labels", + "arrows", + "boxes", + "symbol collage", + "flat icon composition", + "decorative border", + "ornate frame", + "calligraphy", + "mechanical repeated geometry", + "unreadable overlapping objects", + "watermark", + "messy composition", + "blurry", + ] + negatives.extend(str(item) for item in (scene_plan.get("negative_constraints") or [])) + style_token = str(sketch_style or "").strip().lower() + if style_token == "blueprint": + negatives.extend(["dark paper", "blueprint UI overlay"]) + if scene_type == "process": + negatives.extend(["ppt slide", "flowchart", "poster frame", "certificate border", "storybook frame", "mountain painting", "split panels", "comic panel", "forest landscape only", "empty field", "trees only", "plain countryside"]) + elif scene_type == "schematic": + negatives.extend(["pcb photo", "motherboard", "chip macro", "car", "vehicle", "wheel", "industrial design sheet", "product concept sheet", "annotated blueprint", "pen", "marker", "stationery", "writing tool"]) + else: + negatives.extend(["sphere", "orb", "balloon", "wire", "cable", "abstract sculpture", "close-up portrait", "interior room", "cropped subject", "single facade close-up"]) + if "car" not in asset_keys: + negatives.extend(["car", "vehicle", "garage focus"]) + if "person" in asset_keys and not (asset_keys & {"dog", "bird"}): + negatives.extend(["animal", "deer", "antlers", "horns", "multiple people", "crowd", "group portrait", "missing person", "person omitted", "person replaced by house", "person replaced by tree", "person hidden behind tree", "tiny distant person"]) + if "house" in asset_keys and "bird" not in asset_keys: + negatives.extend(["bird", "wings", "winged object", "flying ornament", "facade omitted", "house replaced by person"]) + if asset_counts.get("house", 0) <= 1 and asset_counts.get("building", 0) <= 1: + negatives.extend(["multiple houses", "pagoda", "temple", "pavilion", "gazebo"]) + if "tree" in asset_keys: + negatives.extend(["tree replaced by person", "tree replaced by rock"]) + if asset_counts.get("tree", 0) <= 1: + negatives.extend(["multiple trees", "forest", "grove", "woodland"]) + return ", ".join(self._clean_text(item) for item in negatives if self._clean_text(item)) + + def _encode_image_to_base64(self, image_path: str) -> str: + with open(image_path, "rb") as handle: + return base64.b64encode(handle.read()).decode("utf-8") + + def _encode_image_to_data_url(self, image_path: str) -> str: + mime_type, _ = mimetypes.guess_type(image_path) + mime_type = mime_type or "image/png" + return f"data:{mime_type};base64,{self._encode_image_to_base64(image_path)}" + + def _fingerprint(self, provider: str, prompt: str, negative_prompt: str, control_image_path: str, variation_index: int) -> str: + return json.dumps( + { + "provider": provider, + "prompt": prompt, + "negative_prompt": negative_prompt, + "control_image_path": control_image_path, + "variation_index": variation_index, + }, + ensure_ascii=False, + sort_keys=True, + ) + + def _render_sd_candidate( + self, + *, + provider: str, + variation_index: int, + prompt: str, + negative_prompt: str, + control_image_path: str, + sketch_options: Dict[str, Any], + control_kind: str = "default", + scene_spec: Dict[str, Any] | None = None, + ) -> str: + if not self.sd_available: + raise RuntimeError("SD sketch backend unavailable") + if control_kind == "raw_anchor_control": + denoising_values = [0.56, 0.62, 0.68, 0.72] + cfg_values = [6.0, 6.4, 6.8, 7.2] + step_values = [26, 28, 30, 34] + elif control_kind == "fused_anchor_scene": + denoising_values = [0.42, 0.48, 0.54, 0.58] + cfg_values = [5.8, 6.2, 6.6, 7.0] + step_values = [24, 26, 28, 30] + else: + denoising_values = [0.3, 0.36, 0.42, 0.48] + cfg_values = [5.8, 6.4, 7.0, 7.6] + step_values = [20, 22, 24, 28] + output_name = f"sketch_v2_{provider}_{abs(hash(self._fingerprint(provider, prompt, negative_prompt, control_image_path, variation_index)))}" + controlnet_bundle = self.sd_generator.build_controlnet_bundle( + control_image_path=control_image_path, + scene_spec=scene_spec, + filename_prefix=output_name, + purpose="sketch_candidate", + ) + return self.sd_generator.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_image_path, + denoising_strength=float(sketch_options.get("sd_sketch_denoising", denoising_values[variation_index % len(denoising_values)])), + steps=int(sketch_options.get("sd_sketch_steps", step_values[variation_index % len(step_values)])), + cfg_scale=float(sketch_options.get("sd_sketch_cfg_scale", cfg_values[variation_index % len(cfg_values)])), + sampler_name=str(sketch_options.get("sd_sketch_sampler_name", "DPM++ 2M Karras")), + filename_prefix=output_name, + controlnet_bundle=controlnet_bundle, + **self._sd_lora_kwargs(sketch_options), + ) + + def _get_image_api_endpoint(self) -> str: + if not self.image_api_url: + return "" + if self.image_api_url.endswith("/images/generations"): + return self.image_api_url + return f"{self.image_api_url}/images/generations" + + def _is_volc_ark_image_api(self) -> bool: + url = self.image_api_url.lower() + return any(keyword in url for keyword in ["ark.", "volces.com", "volcengine"]) + + def _build_generic_image_payload(self, prompt: str, control_image_path: str, variation_index: int) -> Dict[str, Any]: + payload: Dict[str, Any] = { + "prompt": prompt, + "response_format": "url", + } + if not self._is_volc_ark_image_api(): + payload["n"] = 1 + if self.image_api_model: + payload["model"] = self.image_api_model + if self.image_api_size: + payload["size"] = self.image_api_size + elif self._is_volc_ark_image_api(): + payload["size"] = "2K" + if control_image_path: + payload["image"] = self._encode_image_to_data_url(control_image_path) + if self._is_volc_ark_image_api(): + payload["stream"] = False + payload["watermark"] = False + payload["sequential_image_generation"] = "disabled" + payload["metadata"] = {"candidate_index": variation_index} + return payload + + def _save_generated_image(self, response_payload: Dict[str, Any], provider: str, fingerprint: str) -> str: + data = response_payload.get("data") or [] + if not data: + raise RuntimeError("Image API returned no data") + first_item = data[0] or {} + output_path = os.path.join(self.output_dir, f"sketch_v2_{provider}_{abs(hash(fingerprint))}.png") + b64_json = first_item.get("b64_json") + if b64_json: + with open(output_path, "wb") as handle: + handle.write(base64.b64decode(b64_json)) + return output_path + image_url = first_item.get("url") + if not image_url: + raise RuntimeError("Image API returned neither b64_json nor url") + image_response = requests.get(image_url, timeout=180) + image_response.raise_for_status() + with open(output_path, "wb") as handle: + handle.write(image_response.content) + return output_path + + def _render_image_api_candidate( + self, + *, + provider: str, + variation_index: int, + prompt: str, + negative_prompt: str, + control_image_path: str, + ) -> str: + if not self.image_api_available: + raise RuntimeError("Image API sketch backend unavailable") + payload = self._build_generic_image_payload(prompt, control_image_path, variation_index) + if negative_prompt: + payload["negative_prompt"] = negative_prompt + response = requests.post( + self._get_image_api_endpoint(), + json=payload, + headers={ + "Authorization": f"Bearer {self.image_api_key}", + "Content-Type": "application/json", + }, + timeout=180, + ) + response.raise_for_status() + return self._save_generated_image( + response.json(), + provider, + self._fingerprint(provider, prompt, negative_prompt, control_image_path, variation_index), + ) + + def _provider_plan(self) -> List[str]: + return self._provider_plan_for_options() + + def _provider_plan_for_options(self, sketch_options: Dict[str, Any] | None = None) -> List[str]: + sketch_options = sketch_options or {} + if self._use_direct_scene_mode(sketch_options) and self.sd_available: + return ["sd", "sd", "sd", "sd"] + if self.sd_available and self.image_api_available: + return ["sd", "sd", "image_api", "image_api"] + if self.sd_available: + return ["sd", "sd", "sd", "sd"] + if self.image_api_available: + return ["image_api", "image_api", "image_api", "image_api"] + return [] + + def _use_direct_scene_mode(self, sketch_options: Dict[str, Any] | None = None) -> bool: + sketch_options = sketch_options or {} + mode = str(sketch_options.get("sketch_v2_mode", "direct_sd") or "direct_sd").strip().lower() + if mode in {"legacy", "legacy_control", "native_control"}: + return False + if bool(sketch_options.get("sketch_v2_use_legacy_control", False)): + return False + return True + + def _sd_lora_kwargs(self, sketch_options: Dict[str, Any] | None = None) -> Dict[str, Any]: + sketch_options = sketch_options or {} + use_lora = bool(sketch_options.get("sd_sketch_use_lora", False)) + lora_name = str( + sketch_options.get("sd_sketch_lora_name") + or sketch_options.get("sd_lora_name") + or (resolve_default_sketch_lora_alias() if use_lora else "") + ).strip() + if not lora_name: + return {} + return { + "lora_name": lora_name, + "lora_strength_model": float(sketch_options.get("sd_sketch_lora_strength_model", 0.92)), + "lora_strength_clip": float(sketch_options.get("sd_sketch_lora_strength_clip", 0.86)), + } + + def _prefer_sd_upstream(self, sketch_options: Dict[str, Any] | None = None) -> bool: + sketch_options = sketch_options or {} + backend = str(sketch_options.get("sketch_backend", "native") or "native").strip().lower() + return ( + backend == "sketch_v2" + and self.sd_available + and not self._use_direct_scene_mode(sketch_options) + and not bool(sketch_options.get("disable_sd_upstream_pass", False)) + ) + + def _direct_scene_control_path(self, prior_bundle: Dict[str, Any] | None = None) -> str: + prior_bundle = prior_bundle if isinstance(prior_bundle, dict) else {} + return str( + prior_bundle.get("layout_control_path") + or prior_bundle.get("base_plate_path") + or prior_bundle.get("depth_control_path") + or "" + ).strip() + + def _clamp(self, value: Any, low: float, high: float) -> float: + return max(low, min(high, float(value or 0.0))) + + def _direct_sd_variant_recipe( + self, + scene_type: str, + variation_index: int, + sketch_options: Dict[str, Any], + ) -> Dict[str, Any]: + base_index = max(0, int(variation_index) % 4) + recipe_order = { + "scene": [3, 2, 1, 0], + "process": [2, 3, 1, 0], + "schematic": [3, 2, 1, 0], + }.get(scene_type, [0, 1, 2, 3]) + index = recipe_order[base_index % len(recipe_order)] + if scene_type in {"process", "schematic"}: + base_denoising = float(sketch_options.get("sd_direct_denoising", 0.80 if scene_type == "process" else 0.78)) + base_cfg = float(sketch_options.get("sd_direct_cfg_scale", 6.4 if scene_type == "process" else 6.5)) + base_steps = int(sketch_options.get("sd_direct_steps", sketch_options.get("sd_sketch_steps", 36))) + denoising_offsets = [0.0, 0.06, 0.12, 0.18] + cfg_offsets = [0.0, 0.05, 0.15, 0.30] + step_offsets = [0, 0, 2, 4] + layout_scales = [1.00, 0.90, 0.78, 0.66] + depth_scales = [1.00, 0.92, 0.80, 0.68] + structure_scales = [1.00, 0.96, 0.90, 0.84] + layout_end_scales = [1.00, 0.98, 0.94, 0.90] + depth_end_scales = [1.00, 0.96, 0.92, 0.88] + structure_end_scales = [1.00, 0.98, 0.94, 0.90] + else: + base_denoising = float(sketch_options.get("sd_direct_denoising", 0.82)) + base_cfg = float(sketch_options.get("sd_direct_cfg_scale", 6.2)) + base_steps = int(sketch_options.get("sd_direct_steps", sketch_options.get("sd_sketch_steps", 30))) + denoising_offsets = [0.0, 0.03, 0.08, 0.12] + cfg_offsets = [0.0, 0.05, 0.15, 0.25] + step_offsets = [0, 2, 2, 4] + layout_scales = [1.00, 0.96, 0.90, 0.84] + depth_scales = [1.00, 0.96, 0.90, 0.84] + structure_scales = [1.00, 0.98, 0.94, 0.90] + layout_end_scales = [1.00, 0.98, 0.94, 0.90] + depth_end_scales = [1.00, 0.98, 0.94, 0.90] + structure_end_scales = [1.00, 0.98, 0.94, 0.90] + denoising = self._clamp(base_denoising + denoising_offsets[index], 0.42, 1.0) + cfg_scale = self._clamp(base_cfg + cfg_offsets[index], 3.5, 12.0) + steps = max(16, base_steps + step_offsets[index]) + return { + "scene_type": scene_type, + "variation_index": index, + "sd_direct_denoising": round(denoising, 4), + "sd_direct_cfg_scale": round(cfg_scale, 4), + "sd_direct_steps": steps, + "layout_strength_scale": layout_scales[index], + "depth_strength_scale": depth_scales[index], + "structure_strength_scale": structure_scales[index], + "layout_end_scale": layout_end_scales[index], + "depth_end_scale": depth_end_scales[index], + "structure_end_scale": structure_end_scales[index], + "note": ( + f"direct_scene_prior recipe={scene_type}:{index}" + f" denoise={denoising:.2f} cfg={cfg_scale:.2f} steps={steps}" + f" layout_scale={layout_scales[index]:.2f} depth_scale={depth_scales[index]:.2f}" + f" structure_scale={structure_scales[index]:.2f}" + ), + } + + def _direct_sd_variant_controlnet( + self, + controlnet_bundle: Dict[str, Any] | None, + recipe: Dict[str, Any], + ) -> Dict[str, Any]: + bundle = _copy(controlnet_bundle or {}) + inputs = bundle.get("inputs") if isinstance(bundle.get("inputs"), list) else [] + adjusted_inputs: List[Dict[str, Any]] = [] + for item in inputs: + if not isinstance(item, dict): + continue + entry = dict(item) + kind = str(entry.get("kind") or "").strip().lower() + if kind == "scene_layout": + entry["strength"] = round( + self._clamp(float(entry.get("strength", 0.0)) * float(recipe.get("layout_strength_scale", 1.0)), 0.05, 1.35), + 4, + ) + entry["end_percent"] = round( + self._clamp(float(entry.get("end_percent", 1.0)) * float(recipe.get("layout_end_scale", 1.0)), 0.12, 1.0), + 4, + ) + elif kind == "scene_depth": + entry["strength"] = round( + self._clamp(float(entry.get("strength", 0.0)) * float(recipe.get("depth_strength_scale", 1.0)), 0.05, 1.35), + 4, + ) + entry["end_percent"] = round( + self._clamp(float(entry.get("end_percent", 1.0)) * float(recipe.get("depth_end_scale", 1.0)), 0.12, 1.0), + 4, + ) + elif kind == "scene_structure": + entry["strength"] = round( + self._clamp(float(entry.get("strength", 0.0)) * float(recipe.get("structure_strength_scale", 1.0)), 0.05, 1.35), + 4, + ) + entry["end_percent"] = round( + self._clamp(float(entry.get("end_percent", 1.0)) * float(recipe.get("structure_end_scale", 1.0)), 0.12, 1.0), + 4, + ) + adjusted_inputs.append(entry) + if adjusted_inputs: + bundle["inputs"] = adjusted_inputs + return bundle + + def _render_sd_direct_candidate( + self, + *, + provider: str, + variation_index: int, + prompt: str, + negative_prompt: str, + scene_spec: Dict[str, Any] | None, + sketch_options: Dict[str, Any], + prior_bundle: Dict[str, Any] | None = None, + controlnet_bundle: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + if not self.sd_available: + raise RuntimeError("SD sketch backend unavailable") + scene_type = self._scene_type(scene_spec) + recipe = self._direct_sd_variant_recipe(scene_type, variation_index, sketch_options) + variant_sketch_options = dict(sketch_options) + variant_sketch_options["sd_direct_denoising"] = recipe["sd_direct_denoising"] + variant_sketch_options["sd_direct_cfg_scale"] = recipe["sd_direct_cfg_scale"] + variant_sketch_options["sd_direct_steps"] = recipe["sd_direct_steps"] + variant_controlnet_bundle = self._direct_sd_variant_controlnet(controlnet_bundle, recipe) + output_name = f"sketch_v2_direct_{provider}_{abs(hash(self._fingerprint(provider, prompt, negative_prompt, self._direct_scene_control_path(prior_bundle), variation_index)))}" + render_result = self.sd_generator.render_scene_direct( + scene_spec=scene_spec, + prompt=prompt, + negative_prompt=negative_prompt, + sketch_options=variant_sketch_options, + filename_prefix=output_name, + prior_bundle=prior_bundle, + controlnet_bundle=variant_controlnet_bundle, + **self._sd_lora_kwargs(sketch_options), + ) + return { + "image_path": render_result.get("image_path"), + "control_image_path": self._direct_scene_control_path(render_result.get("prior_bundle") or prior_bundle), + "prior_bundle": _copy(render_result.get("prior_bundle") or prior_bundle or {}), + "controlnet_bundle": _copy(render_result.get("controlnet_bundle") or variant_controlnet_bundle or {}), + "sd_recipe": recipe, + "note": str(recipe.get("note") or "").strip(), + } + + def _direct_preview_seed( + self, + scene_spec: Dict[str, Any], + sketch_options: Dict[str, Any], + *, + title: str | None = None, + preview_seed: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + normalized_scene = normalize_scene_spec_v2(scene_spec or {}, sketch_options) + sketch_style = str(sketch_options.get("sketch_style", "scribble_line") or "scribble_line") + scene_plan = self.build_scene_plan(normalized_scene, sketch_options=sketch_options, title=title) + prior_prefix = f"sketch_v2_direct_prior_{abs(hash(json.dumps({'scene': normalized_scene, 'title': str(title or '')}, ensure_ascii=False, sort_keys=True)))}" + prior_bundle = self.sd_generator.build_direct_scene_prior( + scene_spec=normalized_scene, + filename_prefix=prior_prefix, + ) + controlnet_bundle = self.sd_generator.build_direct_scene_controlnet_bundle( + scene_spec=normalized_scene, + prior_bundle=prior_bundle, + filename_prefix=prior_prefix, + ) + control_path = self._direct_scene_control_path(prior_bundle) + payload = dict(preview_seed or {}) + payload["success"] = True + payload["type"] = "control_preview" + payload["scene_spec"] = normalized_scene + payload["image_path"] = control_path + payload["save_path"] = control_path + payload["low_preview_path"] = str(prior_bundle.get("base_plate_path") or control_path or "").strip() + payload["render_control_path"] = control_path + payload["sd_upstream_control_path"] = "" + payload["backend"] = "sketch_v2_direct_seed" + payload["sketch_backend"] = "sketch_v2" + payload["scene_plan"] = scene_plan + payload["direct_scene_prior"] = _copy(prior_bundle) + payload["overlay_defaults"] = { + "show_labels": bool((normalized_scene.get("layout_options") or {}).get("show_labels", False)), + "show_grid": bool((normalized_scene.get("layout_options") or {}).get("show_grid", True)), + "show_guides": bool((normalized_scene.get("layout_options") or {}).get("show_guides", False)), + "view_mode": (normalized_scene.get("layout_options") or {}).get("sketch_view_mode", "structure"), + "annotation_level": (normalized_scene.get("layout_options") or {}).get("annotation_level", "light"), + } + sketch_bundle = dict(payload.get("sketch_bundle") or {}) + sketch_bundle["active_sketch_backend"] = "sketch_v2" + sketch_bundle["direct_scene_prior"] = _copy(prior_bundle) + sketch_bundle["direct_scene_controlnet"] = _copy(controlnet_bundle) + sketch_bundle["direct_scene_prompt_mode"] = "scene_spec_to_sd" + payload["sketch_bundle"] = sketch_bundle + payload["description"] = "SceneSpec direct-SD sketch seed without native structural sketch conversion." + payload["generated_prompt"] = self.build_prompt(scene_plan, provider="sd", variation_index=0, title=title) + payload["negative_prompt"] = self.build_negative_prompt(scene_plan, sketch_style) + return payload + + def _render_direct_scene( + self, + scene_spec: Dict[str, Any], + *, + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + preview_seed: Dict[str, Any] | None = None, + ) -> Dict[str, Any]: + sketch_options = sketch_options or {} + preview = self._direct_preview_seed(scene_spec, sketch_options, title=title, preview_seed=preview_seed) + scene_plan = _copy(preview.get("scene_plan") or {}) + prior_bundle = _copy(preview.get("direct_scene_prior") or {}) + controlnet_bundle = _copy(((preview.get("sketch_bundle") or {}).get("direct_scene_controlnet")) or {}) + control_path = self._direct_scene_control_path(prior_bundle) + candidates: List[Dict[str, Any]] = [] + for index, provider in enumerate(self._provider_plan_for_options(sketch_options)): + prompt = self.build_prompt(scene_plan, provider=provider, variation_index=index, title=title) + negative_prompt = self.build_negative_prompt(scene_plan, str(sketch_options.get("sketch_style", "scribble_line"))) + try: + if provider == "sd": + render_result = self._render_sd_direct_candidate( + provider=provider, + variation_index=index, + prompt=prompt, + negative_prompt=negative_prompt, + scene_spec=preview.get("scene_spec"), + sketch_options=sketch_options, + prior_bundle=prior_bundle, + controlnet_bundle=controlnet_bundle, + ) + image_path = str(render_result.get("image_path") or "").strip() + candidate_control_path = str(render_result.get("control_image_path") or control_path).strip() + else: + image_path = self._render_image_api_candidate( + provider=provider, + variation_index=index, + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_path, + ) + candidate_control_path = control_path + except Exception as exc: + logger.warning(f"sketch_v2 direct candidate failed | provider={provider} index={index} error={exc}") + continue + if not image_path: + continue + candidates.append( + { + "candidate_id": f"sketch_v2_{provider}_{len(candidates) + 1}", + "provider": provider, + "image_path": image_path, + "prompt": prompt, + "negative_prompt": negative_prompt, + "control_image_path": candidate_control_path, + "note": str(render_result.get("note") or "direct_scene_prior").strip() if provider == "sd" else "direct_scene_prior", + "sd_recipe": _copy(render_result.get("sd_recipe") or {}) if provider == "sd" else {}, + } + ) + if not candidates: + candidates = [ + self._fallback_candidate( + preview, + scene_plan, + "No direct SD sketch candidate succeeded; falling back to current preview seed.", + ) + ] + active = candidates[0] + sketch_bundle = dict(preview.get("sketch_bundle") or {}) + sketch_bundle["active_sketch_backend"] = "sketch_v2" + sketch_bundle["active_sketch_path"] = active["image_path"] + sketch_bundle["sketch_v2_candidates"] = [item["image_path"] for item in candidates] + sketch_bundle["candidate_control_sources"] = [{"kind": "scene_prior_layout", "path": control_path}] if control_path else [] + payload = dict(preview) + payload["image_path"] = active["image_path"] + payload["save_path"] = active["image_path"] + payload["backend"] = "sketch_v2_direct_preview" + payload["sketch_bundle"] = sketch_bundle + payload["sketch_candidates"] = [_copy(item) for item in candidates] + payload["active_sketch_candidate_id"] = active["candidate_id"] + payload["active_sketch_backend"] = "sketch_v2" + payload["active_sketch_provider"] = active["provider"] + payload["active_sketch_path"] = active["image_path"] + payload["generated_prompt"] = active["prompt"] + payload["negative_prompt"] = active["negative_prompt"] + payload["native_control_image_path"] = control_path + payload["upstream_control_image_path"] = "" + payload["sd_upstream_control_path"] = "" + payload["upstream_control_provider"] = "direct_scene_prior" if control_path else "" + if active.get("note"): + payload["note"] = active["note"] + return payload + + def render_from_scene_spec( + self, + scene_spec: Dict[str, Any] | None, + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + ) -> Dict[str, Any]: + sketch_options = sketch_options or {} + return self._render_direct_scene(scene_spec or {}, sketch_options=sketch_options, title=title, preview_seed={}) + + def _build_upstream_sd_prompt(self, scene_plan: Dict[str, Any], title: str | None = None) -> str: + scene_type = str(scene_plan.get("scene_type", "scene") or "scene") + prompt_title = self._prompt_title_text(title) + parts = [ + self._prompt_prefix(scene_type), + "Create an upstream whole-scene grayscale draft for later sketch refinement and editing.", + "Replace geometric placeholders with natural scene silhouettes, readable object masses, and coherent scene depth.", + "Use the control image only as a soft prior for horizon, placement, scale, and front-mid-back layering.", + "Do not preserve symbol collage, object blobs, icon stickers, helper boxes, arrows, labels, or rigid repeated geometry.", + "Prefer tonal scene masses, believable object shapes, and readable environment context over isolated contour symbols.", + "People, buildings, trees, roads, and devices must read as real scene elements instead of stick figures or pictograms.", + prompt_title, + f'Subject: {self._clean_text(scene_plan.get("subject_summary") or "")}', + f'Background: {self._clean_text(scene_plan.get("background_summary") or "")}', + f'Composition: {self._clean_text(scene_plan.get("composition_summary") or "")}', + f'Depth: {self._clean_text(scene_plan.get("depth_summary") or "")}', + f'Style: {self._clean_text(scene_plan.get("style_summary") or "")}', + "Favor natural whole-image readability over symbolic object assembly.", + ] + must_include_summary = self._clean_text(scene_plan.get("must_include_summary") or "") + if must_include_summary: + parts.append(f"Must clearly include all anchors: {must_include_summary}.") + exact_elements_summary = self._clean_text(scene_plan.get("exact_elements_summary") or "") + if exact_elements_summary: + parts.append(f"Exact visible elements only: {exact_elements_summary}. Do not add extra major objects or substitute object types.") + anchor_layout_summary = self._clean_text(scene_plan.get("anchor_layout_summary") or "") + if anchor_layout_summary: + parts.append(f"Exact anchor layout: {anchor_layout_summary}.") + editable_detail_summary = self._clean_text(scene_plan.get("editable_detail_summary") or "") + if editable_detail_summary: + parts.append(f"Keep editable details clear: {editable_detail_summary}.") + anchor_presence_summary = self._clean_text(self._anchor_presence_summary(scene_plan)) + if anchor_presence_summary: + parts.append(anchor_presence_summary) + object_hint_text = ", ".join( + f'{item.get("prompt_name") or item.get("concept", "")} {item.get("position", "")} {item.get("depth_band", "")}'.strip() + for item in (scene_plan.get("object_hints") or [])[:8] + if item.get("prompt_name") or item.get("concept") + ) + if object_hint_text: + parts.append(f"Scene anchors: {object_hint_text}.") + return ", ".join(part for part in parts if part) + + def _build_upstream_sd_negative_prompt(self, scene_plan: Dict[str, Any], sketch_style: str) -> str: + negatives = [ + self.build_negative_prompt(scene_plan, sketch_style), + "generic blob object", + "placeholder silhouette", + "stick figure", + "floating isolated icon", + "pictogram", + "clipart", + "mechanical layout diagram", + "sticker sheet composition", + "hard geometric glyph", + "empty white page", + "single object on blank background", + "missing center subject", + ] + return ", ".join(self._clean_text(item) for item in negatives if self._clean_text(item)) + + def _render_sd_upstream_guide( + self, + *, + preview: Dict[str, Any], + scene_plan: Dict[str, Any], + control_image_path: str, + sketch_options: Dict[str, Any], + title: str | None = None, + ) -> Dict[str, str]: + if not self._prefer_sd_upstream(sketch_options) or not control_image_path: + return {} + prompt = self._build_upstream_sd_prompt(scene_plan, title=title) + negative_prompt = self._build_upstream_sd_negative_prompt( + scene_plan, + str(sketch_options.get("sketch_style", "scribble_line")), + ) + control_name = os.path.basename(control_image_path).lower() + stronger_tonal_control = control_name.startswith("sd_upstream_control_") + output_name = f"sketch_v2_upstream_sd_{abs(hash(self._fingerprint('sd_upstream', prompt, negative_prompt, control_image_path, 0)))}" + controlnet_bundle = self.sd_generator.build_controlnet_bundle( + control_image_path=control_image_path, + scene_spec=preview.get("scene_spec"), + filename_prefix=output_name, + purpose="sketch_upstream", + ) + try: + image_path = self.sd_generator.render_img2img( + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_image_path, + denoising_strength=float(sketch_options.get("sd_upstream_denoising", 0.72 if stronger_tonal_control else 0.58)), + steps=int(sketch_options.get("sd_upstream_steps", 30 if stronger_tonal_control else 24)), + cfg_scale=float(sketch_options.get("sd_upstream_cfg_scale", 6.4 if stronger_tonal_control else 6.2)), + sampler_name=str(sketch_options.get("sd_upstream_sampler_name", sketch_options.get("sd_sketch_sampler_name", "DPM++ 2M Karras"))), + filename_prefix=output_name, + controlnet_bundle=controlnet_bundle, + **self._sd_lora_kwargs(sketch_options), + ) + except Exception as exc: + logger.warning(f"sketch_v2 upstream sd guide failed: {exc}") + return {} + return { + "image_path": image_path, + "prompt": prompt, + "negative_prompt": negative_prompt, + "provider": "sd_upstream", + } + + def _fallback_candidate(self, preview: Dict[str, Any], scene_plan: Dict[str, Any], reason: str) -> Dict[str, Any]: + image_path = str(preview.get("image_path") or "") + return { + "candidate_id": "sketch_v2_fallback_native_1", + "provider": "fallback_native", + "image_path": image_path, + "prompt": self.build_prompt(scene_plan, provider="image_api", variation_index=0), + "negative_prompt": self.build_negative_prompt(scene_plan, str((preview.get("scene_spec") or {}).get("layout_options", {}).get("sketch_style", "scribble_line"))), + "control_image_path": self._control_image_path(preview) or image_path, + "note": reason, + } + + def _fuse_control_image( + self, + *, + raw_control_image_path: str, + upstream_sd_guide_path: str, + ) -> str: + raw_path = str(raw_control_image_path or "").strip() + upstream_path = str(upstream_sd_guide_path or "").strip() + if not raw_path or not upstream_path or raw_path == upstream_path: + return "" + try: + upstream_image = Image.open(upstream_path).convert("RGBA") + raw_image = Image.open(raw_path).convert("RGBA").resize(upstream_image.size) + raw_alpha = raw_image.convert("L").point(lambda px: max(0, min(255, int((255 - px) * 0.72)))) + raw_overlay = raw_image.copy() + raw_overlay.putalpha(raw_alpha) + fused = Image.alpha_composite(upstream_image, raw_overlay).convert("RGB") + output_name = f"sketch_v2_fused_control_{abs(hash(self._fingerprint('fused_control', raw_path, upstream_path, '', 0)))}.png" + output_path = os.path.join(self.output_dir, output_name) + fused.save(output_path) + return output_path + except Exception as exc: + logger.warning(f"sketch_v2 fused control build failed: {exc}") + return "" + + def _candidate_control_sources( + self, + *, + raw_control_image_path: str, + upstream_sd_guide_path: str, + fused_control_image_path: str, + ) -> List[Dict[str, str]]: + sources: List[Dict[str, str]] = [] + for kind, path in [ + ("fused_anchor_scene", fused_control_image_path), + ("raw_anchor_control", raw_control_image_path), + ("sd_upstream_scene", upstream_sd_guide_path), + ]: + cleaned = str(path or "").strip() + if not cleaned: + continue + if any(item.get("path") == cleaned for item in sources): + continue + sources.append({"kind": kind, "path": cleaned}) + return sources + + def render_from_preview( + self, + preview: Dict[str, Any], + sketch_options: Dict[str, Any] | None = None, + title: str | None = None, + ) -> Dict[str, Any]: + preview = dict(preview or {}) + sketch_options = sketch_options or {} + if self._use_direct_scene_mode(sketch_options): + return self._render_direct_scene( + preview.get("scene_spec") if isinstance(preview.get("scene_spec"), dict) else {}, + sketch_options=sketch_options, + title=title, + preview_seed=preview, + ) + scene_plan = self.build_scene_plan(preview.get("scene_spec"), sketch_options=sketch_options, title=title) + control_image_path = self._upstream_control_image_path(preview) or self._control_image_path(preview) + sketch_bundle = dict(preview.get("sketch_bundle") or {}) + native_structural = sketch_bundle.get("structural_sketch") or preview.get("image_path") + upstream_sd_guide = self._render_sd_upstream_guide( + preview=preview, + scene_plan=scene_plan, + control_image_path=control_image_path, + sketch_options=sketch_options, + title=title, + ) + upstream_guide_path = str(upstream_sd_guide.get("image_path") or "").strip() + fused_control_path = self._fuse_control_image( + raw_control_image_path=control_image_path, + upstream_sd_guide_path=upstream_guide_path, + ) + control_sources = self._candidate_control_sources( + raw_control_image_path=control_image_path, + upstream_sd_guide_path=upstream_guide_path, + fused_control_image_path=fused_control_path, + ) + upstream_control_path = control_sources[0]["path"] if control_sources else str(control_image_path or upstream_guide_path or "").strip() + candidates: List[Dict[str, Any]] = [] + for index, provider in enumerate(self._provider_plan_for_options(sketch_options)): + prompt = self.build_prompt(scene_plan, provider=provider, variation_index=index, title=title) + negative_prompt = self.build_negative_prompt(scene_plan, str(sketch_options.get("sketch_style", "scribble_line"))) + control_source = control_sources[index % len(control_sources)] if control_sources else {"kind": "default", "path": upstream_control_path} + try: + if provider == "sd": + image_path = self._render_sd_candidate( + provider=provider, + variation_index=index, + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_source["path"], + sketch_options=sketch_options, + control_kind=str(control_source.get("kind") or "default"), + scene_spec=preview.get("scene_spec"), + ) + else: + image_path = self._render_image_api_candidate( + provider=provider, + variation_index=index, + prompt=prompt, + negative_prompt=negative_prompt, + control_image_path=control_source["path"], + ) + except Exception as exc: + logger.warning(f"sketch_v2 candidate failed | provider={provider} index={index} error={exc}") + continue + candidates.append( + { + "candidate_id": f"sketch_v2_{provider}_{len(candidates) + 1}", + "provider": provider, + "image_path": image_path, + "prompt": prompt, + "negative_prompt": negative_prompt, + "control_image_path": control_source["path"], + "note": control_source["kind"], + } + ) + if not candidates: + candidates = [ + self._fallback_candidate( + preview, + scene_plan, + "No sketch_v2 provider succeeded; falling back to native composition sketch.", + ) + ] + active = candidates[0] + if native_structural: + sketch_bundle.setdefault("native_structural_sketch", native_structural) + if upstream_sd_guide.get("image_path"): + sketch_bundle["sd_upstream_guide"] = upstream_sd_guide.get("image_path") + sketch_bundle["upstream_control_provider"] = upstream_sd_guide.get("provider") + sketch_bundle["upstream_control_prompt"] = upstream_sd_guide.get("prompt") + if fused_control_path: + sketch_bundle["fused_control_image"] = fused_control_path + if control_sources: + sketch_bundle["candidate_control_sources"] = _copy(control_sources) + sketch_bundle["active_sketch_backend"] = "sketch_v2" + sketch_bundle["active_sketch_path"] = active["image_path"] + sketch_bundle["sketch_v2_candidates"] = [item["image_path"] for item in candidates] + payload = dict(preview) + payload["image_path"] = active["image_path"] + payload["save_path"] = active["image_path"] + payload["backend"] = "sketch_v2_preview" + payload["sketch_backend"] = "sketch_v2" + payload["generated_prompt"] = active["prompt"] + payload["negative_prompt"] = active["negative_prompt"] + payload["sketch_bundle"] = sketch_bundle + payload["sketch_candidates"] = [_copy(item) for item in candidates] + payload["active_sketch_candidate_id"] = active["candidate_id"] + payload["active_sketch_backend"] = "sketch_v2" + payload["active_sketch_provider"] = active["provider"] + payload["active_sketch_path"] = active["image_path"] + payload["native_control_image_path"] = control_image_path + payload["upstream_control_image_path"] = upstream_control_path if upstream_control_path and upstream_control_path != control_image_path else "" + payload["sd_upstream_control_path"] = preview.get("sd_upstream_control_path") or sketch_bundle.get("sd_upstream_control") or "" + payload["upstream_control_provider"] = upstream_sd_guide.get("provider", "") + payload["scene_plan"] = scene_plan + if active.get("note"): + payload["note"] = active["note"] + return payload + diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tmcra_reasoning_runtime.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tmcra_reasoning_runtime.py new file mode 100644 index 0000000..360409c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tmcra_reasoning_runtime.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, Dict, Iterable, List, Sequence + +from experiments.replacement.adapters.base import AdapterResponse +from experiments.replacement.adapters.memory_adapters import GraphSessionMemoryAdapter +from experiments.replacement.memory_graph import guess_slot_key +from experiments.replacement_overlay.pipeline import ReasoningRequest, TMCRAReasoningPipeline + + +def _clean_text(value: object) -> str: + return str(value or "").strip() + + +def _dedupe(items: Iterable[object]) -> List[str]: + values: List[str] = [] + seen = set() + for item in items: + text = _clean_text(item) + if not text: + continue + key = text.lower() + if key in seen: + continue + seen.add(key) + values.append(text) + return values + + +@dataclass(slots=True) +class RuntimeFeatureFlags: + TMCRA_REASONING_V2_ENABLED: bool = False + TMCRA_REASONING_V2_SHADOW: bool = True + TMCRA_TEMPORAL_REASONING_ENABLED: bool = True + TMCRA_SLOT_RESOLUTION_ENABLED: bool = True + + def to_dict(self) -> Dict[str, bool]: + return { + "TMCRA_REASONING_V2_ENABLED": bool(self.TMCRA_REASONING_V2_ENABLED), + "TMCRA_REASONING_V2_SHADOW": bool(self.TMCRA_REASONING_V2_SHADOW), + "TMCRA_TEMPORAL_REASONING_ENABLED": bool(self.TMCRA_TEMPORAL_REASONING_ENABLED), + "TMCRA_SLOT_RESOLUTION_ENABLED": bool(self.TMCRA_SLOT_RESOLUTION_ENABLED), + } + + +@dataclass(slots=True) +class SessionMemoryNormalizationAdapter: + default_source_kind: str = "session_memory" + + def normalize_records(self, records: Sequence[Any]) -> List[Dict[str, Any]]: + normalized: List[Dict[str, Any]] = [] + for index, raw in enumerate(records): + if isinstance(raw, dict): + category = _clean_text(raw.get("category", "memory")) or "memory" + value = _clean_text(raw.get("value", "")) + anchors = [_clean_text(anchor) for anchor in raw.get("anchor_concepts", raw.get("anchors", [])) or [] if _clean_text(anchor)] + turn_index = int(raw.get("turn_index", 0) or 0) + source_kind = _clean_text(raw.get("source_kind", "")) or self.default_source_kind + slot_key = _clean_text(raw.get("slot_key", raw.get("slot", ""))) or guess_slot_key(category=category, value=value, anchors=anchors) + if value: + normalized.append( + { + "category": category, + "slot": slot_key, + "value": value, + "anchors": anchors[:8], + "relation": _clean_text(raw.get("relation", "")) or f"{category}_memory", + "source_kind": source_kind, + "turn_index": turn_index, + "metadata": dict(raw.get("metadata", {}) or {}), + } + ) + continue + category = _clean_text(getattr(raw, "category", "memory")) or "memory" + value = _clean_text(getattr(raw, "value", "")) + anchors = [_clean_text(anchor) for anchor in getattr(raw, "anchor_concepts", []) or [] if _clean_text(anchor)] + if not value: + continue + normalized.append( + { + "category": category, + "slot": guess_slot_key(category=category, value=value, anchors=anchors), + "value": value, + "anchors": anchors[:8], + "relation": _clean_text(getattr(raw, "relation", "")) or f"{category}_memory", + "source_kind": _clean_text(getattr(raw, "source_kind", "")) or self.default_source_kind, + "turn_index": int(getattr(raw, "turn_index", 0) or 0), + "metadata": dict(getattr(raw, "metadata", {}) or {}), + } + ) + return normalized + + def build_memory_adapter( + self, + *, + records: Sequence[Any] | None = None, + session_turns: Sequence[Dict[str, Any]] | None = None, + ) -> GraphSessionMemoryAdapter: + adapter = GraphSessionMemoryAdapter(auto_extract=False) + if session_turns: + for turn in session_turns: + adapter.ingest_turn( + _clean_text(turn.get("user_text", "")), + _clean_text(turn.get("assistant_text", "")), + answer_payload=dict(turn.get("answer_payload", {}) or {}), + extraction_result=dict(turn.get("extraction_result", {}) or {}), + ) + normalized = self.normalize_records(records or []) + grouped: Dict[int, List[Dict[str, Any]]] = {} + for item in normalized: + grouped.setdefault(int(item.get("turn_index", 0) or 0), []).append(item) + for turn_index in sorted(grouped.keys()): + adapter.ingest_turn( + f"normalized_session_memory_turn_{turn_index}", + "", + answer_payload={"replacement_memory_records": grouped[turn_index], "metadata": {"source": "main_chain_shadow"}}, + ) + return adapter + + +class MainChainReasoningAdapter: + def __init__( + self, + *, + flags: RuntimeFeatureFlags | None = None, + normalizer: SessionMemoryNormalizationAdapter | None = None, + pipeline: TMCRAReasoningPipeline | None = None, + ) -> None: + self.flags = flags or RuntimeFeatureFlags() + self.normalizer = normalizer or SessionMemoryNormalizationAdapter() + self.pipeline = pipeline or TMCRAReasoningPipeline() + + def answer( + self, + query: str, + *, + answer_mode: str = "transparent", + legacy_response: AdapterResponse | None = None, + session_records: Sequence[Any] | None = None, + session_turns: Sequence[Dict[str, Any]] | None = None, + top_k: int = 6, + memory_name: str = "session_memory", + ) -> AdapterResponse: + adapter = self.normalizer.build_memory_adapter(records=session_records, session_turns=session_turns) + shadow_bundle = self.pipeline.run( + ReasoningRequest(query=query, answer_mode=answer_mode, top_k=top_k, metadata={"source": "main_chain_shadow"}), + memory_adapter=adapter, + base_response=legacy_response, + reasoner_name="tmcra_reasoning_v2", + memory_name=memory_name, + ) + if self.flags.TMCRA_REASONING_V2_ENABLED: + response = shadow_bundle.response + else: + response = legacy_response or AdapterResponse( + answer="", + answer_mode=answer_mode, + reasoner_name="main_chain_legacy", + memory_name=memory_name, + ) + response = AdapterResponse( + answer=response.answer, + answer_mode=response.answer_mode, + reasoner_name=response.reasoner_name, + memory_name=response.memory_name, + confidence=response.confidence, + paths=list(response.paths), + facts=list(response.facts), + candidate_scores=list(response.candidate_scores), + memory_hits=list(response.memory_hits), + evidence_consistent=bool(response.evidence_consistent), + unsupported_claims=list(response.unsupported_claims), + pillar_scores=dict(response.pillar_scores or {}), + latency_seconds=response.latency_seconds, + trace={ + **dict(response.trace or {}), + "tmcra_reasoning_v2_shadow": { + "enabled": bool(self.flags.TMCRA_REASONING_V2_ENABLED), + "shadow": bool(self.flags.TMCRA_REASONING_V2_SHADOW), + "flags": self.flags.to_dict(), + "shadow_response": shadow_bundle.response.to_dict(), + }, + }, + metadata={ + **dict(response.metadata or {}), + "tmcra_reasoning_v2": { + "enabled": bool(self.flags.TMCRA_REASONING_V2_ENABLED), + "shadow": bool(self.flags.TMCRA_REASONING_V2_SHADOW), + "flags": self.flags.to_dict(), + "shadow_bundle": shadow_bundle.to_dict(), + "normalized_slots": _dedupe(view["slot_key"] for view in shadow_bundle.context.slot_resolution.to_dict().get("views", [])), + }, + }, + ) + return response + + +def create_reasoning_v2_shadow_adapter(*, flags: RuntimeFeatureFlags | None = None) -> MainChainReasoningAdapter: + return MainChainReasoningAdapter(flags=flags or RuntimeFeatureFlags()) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_neural_trainer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_neural_trainer.py new file mode 100644 index 0000000..1c16218 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_neural_trainer.py @@ -0,0 +1,1057 @@ +from __future__ import annotations + +import argparse +import hashlib +import json +import math +import time +from dataclasses import asdict, dataclass, field +from pathlib import Path +from typing import Any, Dict, Iterable, List, Sequence + +import networkx as nx + +try: + import torch + import torch.nn.functional as F + from torch.utils.data import DataLoader, WeightedRandomSampler +except Exception as exc: # pragma: no cover + raise RuntimeError(f"torch is required for Tri-Maze neural training: {exc}") + +from .concept_graph import ConceptGraph +from .concept_memory import ConceptMemory +from .maze_engine import TriMazeEngine +from .policy_dataset import ( + CurriculumConfig, + EpisodicBatchSampler, + PolicyStepDataset, + PolicyStepRecord, + PolicyVocabulary, + build_domain_sampling_weights, + build_path_stub, + build_runtime_step_record, + filter_curriculum_records, + load_policy_records, + policy_collate_fn, + serialize_policy_records, +) +from .policy_network import ( + EdgePolicy, + PolicyModelConfig, + candidate_contrastive_loss, + hard_negative_margin_loss, + masked_cross_entropy, +) +from .tri_maze_supervision import load_supervision_rows, normalize_supervision_row, summarize_supervision_rows + + +DEFAULT_MEMORY_FILE = "data/concept_memory.json" +DEFAULT_SUPERVISION_GLOBS = ("data/tri_maze_datasets/exports/*tri_maze_supervision*.jsonl",) + + +@dataclass(slots=True) +class TrainingConfig: + epochs: int = 20 + batch_size: int = 32 + num_workers: int = 0 + lr: float = 1e-3 + weight_decay: float = 1e-4 + temperature: float = 1.0 + branch_factor: int = 2 + revisit_probability: float = 0.2 + train_ratio: float = 0.9 + patience: int = 8 + grad_clip: float = 1.0 + grad_accum_steps: int = 1 + amp: bool = True + model_type: str = "v2" + embedding_dim: int = 64 + relation_embedding_dim: int = 16 + domain_embedding_dim: int = 8 + trunk_dims: tuple[int, ...] = (128, 256, 128) + dropout: float = 0.1 + history_size: int = 4 + curriculum: CurriculumConfig = field(default_factory=CurriculumConfig) + domain_balance: bool = True + episodic: bool = False + multitask: bool = True + contrastive_weight: float = 0.08 + hard_negative_weight: float = 0.12 + aux_weight: float = 0.15 + domain_adapt: bool = False + domain_adapt_weight: float = 0.03 + zero_shot_split: str = "none" + cache_dir: str = "" + resume: str = "" + + def to_dict(self) -> dict[str, Any]: + payload = asdict(self) + payload["trunk_dims"] = list(self.trunk_dims) + payload["curriculum"] = asdict(self.curriculum) + return payload + + +def _timestamp() -> str: + return time.strftime("%Y%m%d-%H%M%S") + + +def _stable_score(text: str) -> float: + digest = hashlib.md5(text.encode("utf-8", errors="ignore")).digest() + return int.from_bytes(digest[:4], "big") / 2**32 + + +def _clamp_score(value: Any, default: float = 0.8) -> float: + try: + return max(0.1, min(1.0, float(value))) + except Exception: + return default + + +def _weight_from_path(path_record: Dict[str, Any]) -> float: + base = _clamp_score(path_record.get("score", 0.8), default=0.8) + try: + uses = max(1, int(path_record.get("uses", 1) or 1)) + except Exception: + uses = 1 + return base * math.log1p(uses) + + +def _repo_root() -> Path: + return Path(__file__).resolve().parents[1] + + +def discover_supervision_files( + *, + repo_root: Path | None = None, + files: Sequence[str] | None = None, + globs: Sequence[str] | None = None, +) -> list[Path]: + root = repo_root or _repo_root() + discovered: list[Path] = [] + for item in files or []: + candidate = Path(item) + if not candidate.is_absolute(): + candidate = root / candidate + if candidate.exists(): + discovered.append(candidate) + for pattern in globs or DEFAULT_SUPERVISION_GLOBS: + for child in sorted(root.glob(pattern)): + if child.is_file(): + discovered.append(child) + ordered: list[Path] = [] + seen = set() + for path in discovered: + marker = str(path.resolve()).casefold() + if marker in seen: + continue + seen.add(marker) + ordered.append(path) + return ordered + + +def load_all_supervision_rows(paths: Sequence[Path]) -> list[dict[str, Any]]: + rows: list[dict[str, Any]] = [] + for path in paths: + rows.extend(load_supervision_rows(path)) + return rows + + +def build_training_graph( + memory: ConceptMemory, + *, + supervision_rows: Sequence[dict[str, Any]] | None = None, + graph_json_path: str | None = None, +) -> nx.DiGraph: + if graph_json_path: + payload = json.loads(Path(graph_json_path).read_text(encoding="utf-8")) + concept_graph = ConceptGraph() + concept_graph.import_json(payload) + graph = concept_graph.graph + else: + graph = nx.DiGraph() + all_concepts = memory.get_all_concepts() + for concept, data in all_concepts.items(): + graph.add_node(concept, type=data.get("type", "unknown")) + + for fact in memory.get_all_facts(): + src = str(fact.get("from") or "").strip() + dst = str(fact.get("to") or "").strip() + if not src or not dst: + continue + graph.add_node(src, type=all_concepts.get(src, {}).get("type", "unknown")) + graph.add_node(dst, type=all_concepts.get(dst, {}).get("type", "unknown")) + weight = max(0.1, min(1.0, float(fact.get("weight", 0.7) or 0.7))) + existing = graph.get_edge_data(src, dst, {}) + graph.add_edge( + src, + dst, + relation=existing.get("relation") or str(fact.get("relation") or "related_to"), + weight=max(float(existing.get("weight", 0.0) or 0.0), weight), + ) + + for path_record in memory.get_all_paths(): + concepts = [str(item).strip() for item in (path_record.get("path") or []) if str(item).strip()] + path_weight = _clamp_score(path_record.get("score", 0.8), default=0.8) + for concept in concepts: + graph.add_node(concept, type=all_concepts.get(concept, {}).get("type", "unknown")) + for index in range(len(concepts) - 1): + src = concepts[index] + dst = concepts[index + 1] + existing = graph.get_edge_data(src, dst, {}) + graph.add_edge( + src, + dst, + relation=existing.get("relation") or "memory_path", + weight=max(float(existing.get("weight", 0.0) or 0.0), path_weight), + ) + + for row in supervision_rows or []: + normalized = normalize_supervision_row(row) + for concept in normalized.get("concepts") or []: + graph.add_node(concept, type=graph.nodes.get(concept, {}).get("type", "proposition")) + for path in normalized.get("forward_paths") or []: + for concept in path: + graph.add_node(concept, type=graph.nodes.get(concept, {}).get("type", "proposition")) + for index in range(len(path) - 1): + src = path[index] + dst = path[index + 1] + existing = graph.get_edge_data(src, dst, {}) + graph.add_edge( + src, + dst, + relation=existing.get("relation") or "supports", + weight=max(float(existing.get("weight", 0.0) or 0.0), _clamp_score(normalized.get("score", 0.8))), + ) + for fact in normalized.get("facts") or []: + src = fact["from"] + dst = fact["to"] + graph.add_node(src, type=graph.nodes.get(src, {}).get("type", "proposition")) + graph.add_node(dst, type=graph.nodes.get(dst, {}).get("type", "proposition")) + existing = graph.get_edge_data(src, dst, {}) + graph.add_edge( + src, + dst, + relation=existing.get("relation") or fact.get("relation", "supports"), + weight=max(float(existing.get("weight", 0.0) or 0.0), _clamp_score(fact.get("weight", 0.8))), + ) + return graph + + +def _parse_zero_shot_spec(spec: str) -> tuple[str, str]: + normalized = (spec or "").strip().lower() + if not normalized or normalized in {"none", "off", "false"}: + return "none", "" + if ":" in normalized: + kind, value = normalized.split(":", 1) + return kind.strip(), value.strip() + return "concept", normalized + + +def split_policy_records( + records: Sequence[PolicyStepRecord], + *, + train_ratio: float, + zero_shot_split: str = "none", +) -> dict[str, list[PolicyStepRecord]]: + split_map = {"train": [], "val": [], "zero_shot": []} + kind, value = _parse_zero_shot_spec(zero_shot_split) + holdout_concepts: set[str] = set() + holdout_dataset = "" + if kind == "concept": + try: + holdout_ratio = max(0.01, min(0.9, float(value or 0.1))) + except Exception: + holdout_ratio = 0.1 + all_concepts = sorted({concept for record in records for concept in record.all_concepts()}) + holdout_concepts = { + concept.casefold() + for concept in all_concepts + if _stable_score(f"zs::{concept.casefold()}") >= (1.0 - holdout_ratio) + } + elif kind == "dataset": + holdout_dataset = value.casefold() + + regular_records: list[PolicyStepRecord] = [] + for record in records: + if holdout_dataset and record.source_dataset.casefold() == holdout_dataset: + split_map["zero_shot"].append(record) + continue + if holdout_concepts and any(concept.casefold() in holdout_concepts for concept in record.all_concepts()): + split_map["zero_shot"].append(record) + continue + regular_records.append(record) + + boundary = max(0.0, min(1.0, float(train_ratio))) + for record in regular_records: + if _stable_score(record.sample_id) < boundary: + split_map["train"].append(record) + else: + split_map["val"].append(record) + return split_map + + +class TriMazeNeuralTrainer: + def __init__(self, graph: nx.DiGraph, memory: ConceptMemory, *, device: str = "auto", seed: int = 42): + self.graph = graph + self.memory = memory + self.seed = int(seed) + self.device = self._resolve_device(device) + self.engine = TriMazeEngine( + self.graph, + concept_memory=self.memory, + multimodal_generator=object(), + policy_enabled=False, + policy_rollout="off", + ) + + def _resolve_device(self, device_arg: str) -> torch.device: + if device_arg != "auto": + return torch.device(device_arg) + if torch.cuda.is_available(): + return torch.device("cuda") + return torch.device("cpu") + + def _memory_forward_paths(self) -> list[dict[str, Any]]: + return [ + item + for item in self.memory.get_all_paths() + if str(item.get("mode") or "forward").strip().lower() == "forward" + ] + + def _record_for_step( + self, + *, + sample_id: str, + source_kind: str, + source_dataset: str, + query_type: str, + mode: str, + concepts: Sequence[str], + step_index: int, + weight: float, + source_score: float = 0.0, + ) -> PolicyStepRecord | None: + if step_index >= len(concepts) - 1: + return None + current = concepts[step_index] + target = concepts[step_index + 1] + current_node = self.engine.nodes.get(current) + if current_node is None: + return None + candidate_edges = list(current_node.connections) + if not candidate_edges: + return None + target_index = next( + (index for index, edge in enumerate(candidate_edges) if edge.to_node.concept == target), + None, + ) + if target_index is None: + return None + path_stub = build_path_stub(self.engine, concepts[: step_index + 1]) + visited = set(concepts[: step_index + 1]) + return build_runtime_step_record( + engine=self.engine, + current_node=current_node, + candidate_edges=candidate_edges, + path=path_stub, + visited=visited, + mode=mode, + target_index=target_index, + sample_id=sample_id, + source_kind=source_kind, + source_dataset=source_dataset, + query_type=query_type, + task_key=f"{source_dataset}|{query_type}|{mode}", + weight=weight, + source_score=source_score, + ) + + def iter_memory_records(self) -> Iterable[PolicyStepRecord]: + for path_index, path_record in enumerate(self._memory_forward_paths()): + concepts = [str(item).strip() for item in (path_record.get("path") or []) if str(item).strip()] + if len(concepts) < 2: + continue + weight = _weight_from_path(path_record) + score = _clamp_score(path_record.get("score", 0.8), default=0.8) + for step_index in range(len(concepts) - 1): + record = self._record_for_step( + sample_id=f"memory::{path_index}::{step_index}", + source_kind="memory_path", + source_dataset="concept_memory", + query_type="memory", + mode="forward", + concepts=concepts, + step_index=step_index, + weight=weight, + source_score=score, + ) + if record is not None: + yield record + + def iter_supervision_records(self, supervision_rows: Sequence[dict[str, Any]]) -> Iterable[PolicyStepRecord]: + for row in supervision_rows: + normalized = normalize_supervision_row(row) + paths = list(normalized.get("forward_paths") or []) + if not paths and normalized.get("facts"): + paths = [[fact["from"], fact["to"]] for fact in normalized["facts"]] + for path_index, path in enumerate(paths): + concepts = [str(item).strip() for item in path if str(item).strip()] + if len(concepts) < 2: + continue + for step_index in range(len(concepts) - 1): + record = self._record_for_step( + sample_id=f"supervision::{normalized['sample_id']}::{path_index}::{step_index}", + source_kind="tri_maze_supervision", + source_dataset=normalized["source_dataset"], + query_type=normalized["query_type"], + mode="forward", + concepts=concepts, + step_index=step_index, + weight=_clamp_score(normalized.get("score", 0.8), default=0.8), + source_score=_clamp_score(normalized.get("score", 0.8), default=0.8), + ) + if record is not None: + yield record + + def materialize_records( + self, + *, + supervision_rows: Sequence[dict[str, Any]] | None = None, + extra_record_files: Sequence[str] | None = None, + ) -> tuple[list[PolicyStepRecord], dict[str, Any]]: + records = list(self.iter_memory_records()) + memory_count = len(records) + supervision_records = list(self.iter_supervision_records(supervision_rows or [])) + records.extend(supervision_records) + direct_records: list[PolicyStepRecord] = [] + for file_path in extra_record_files or []: + direct_records.extend(load_policy_records(file_path)) + records.extend(direct_records) + + summary = { + "record_count": len(records), + "memory_record_count": memory_count, + "supervision_record_count": len(supervision_records), + "direct_record_count": len(direct_records), + "node_count": self.graph.number_of_nodes(), + "edge_count": self.graph.number_of_edges(), + "device": str(self.device), + "feature_schema": {"version": "tri_maze_policy_v2.0"}, + } + return records, summary + + def prepare_summary( + self, + *, + supervision_rows: Sequence[dict[str, Any]] | None = None, + extra_record_files: Sequence[str] | None = None, + train_ratio: float = 0.9, + zero_shot_split: str = "none", + cache_dir: str = "", + ) -> dict[str, Any]: + records, summary = self.materialize_records( + supervision_rows=supervision_rows, + extra_record_files=extra_record_files, + ) + split_map = split_policy_records(records, train_ratio=train_ratio, zero_shot_split=zero_shot_split) + vocabulary = PolicyVocabulary.build(split_map["train"] or records) + summary["splits"] = {key: len(value) for key, value in split_map.items()} + summary["vocabulary"] = { + "concepts": vocabulary.concept_vocab_size, + "relations": vocabulary.relation_vocab_size, + "sources": vocabulary.source_vocab_size, + "query_types": vocabulary.query_type_vocab_size, + "modes": vocabulary.mode_vocab_size, + "tasks": vocabulary.task_vocab_size, + "hash_bucket_size": vocabulary.hash_bucket_size, + } + if supervision_rows: + summary["supervision"] = summarize_supervision_rows(supervision_rows) + if cache_dir: + cache_path = Path(cache_dir) + cache_path.mkdir(parents=True, exist_ok=True) + serialize_policy_records(cache_path / "all.jsonl", records) + serialize_policy_records(cache_path / "train.jsonl", split_map["train"]) + serialize_policy_records(cache_path / "val.jsonl", split_map["val"]) + serialize_policy_records(cache_path / "zero_shot.jsonl", split_map["zero_shot"]) + (cache_path / "manifest.json").write_text( + json.dumps(summary, ensure_ascii=False, indent=2), + encoding="utf-8", + ) + (cache_path / "vocabulary.json").write_text( + json.dumps(vocabulary.to_metadata(), ensure_ascii=False, indent=2), + encoding="utf-8", + ) + return summary + + def _build_loader( + self, + records: Sequence[PolicyStepRecord], + *, + vocabulary: PolicyVocabulary, + config: TrainingConfig, + train: bool, + ) -> DataLoader: + dataset = PolicyStepDataset(records, vocabulary=vocabulary, history_size=config.history_size) + if train and config.episodic: + return DataLoader( + dataset, + batch_sampler=EpisodicBatchSampler(records, batch_size=config.batch_size, seed=self.seed), + num_workers=config.num_workers, + collate_fn=policy_collate_fn, + ) + sampler = None + shuffle = bool(train) + if train and config.domain_balance: + weights = build_domain_sampling_weights(records) + sampler = WeightedRandomSampler(weights=weights, num_samples=len(weights), replacement=True) + shuffle = False + return DataLoader( + dataset, + batch_size=config.batch_size, + shuffle=shuffle if sampler is None else False, + sampler=sampler, + num_workers=config.num_workers, + collate_fn=policy_collate_fn, + pin_memory=self.device.type == "cuda", + ) + + def _build_policy(self, *, vocabulary: PolicyVocabulary, config: TrainingConfig) -> EdgePolicy: + model_config = PolicyModelConfig( + model_version=config.model_type, + history_size=config.history_size, + concept_embedding_dim=config.embedding_dim, + relation_embedding_dim=config.relation_embedding_dim, + domain_embedding_dim=config.domain_embedding_dim, + trunk_dims=tuple(int(item) for item in config.trunk_dims), + dropout=config.dropout, + feature_attention=True, + multitask=config.multitask, + domain_adapt=config.domain_adapt, + ).apply_vocabulary(vocabulary) + policy = EdgePolicy( + lr=config.lr, + temperature=config.temperature, + branch_factor=config.branch_factor, + revisit_probability=config.revisit_probability, + seed=self.seed, + model_version=config.model_type, + model_config=model_config, + vocabulary=vocabulary, + weight_decay=config.weight_decay, + ) + policy.set_max_degree(self.engine._max_degree) + policy.model.to(self.device) + return policy + + def _compute_losses( + self, + policy: EdgePolicy, + batch, + outputs: dict[str, torch.Tensor], + config: TrainingConfig, + ) -> dict[str, torch.Tensor]: + ranking_loss = masked_cross_entropy( + outputs["logits"], + batch.target_index, + batch.candidate_mask, + sample_weights=batch.weights, + ) + hard_loss = hard_negative_margin_loss( + outputs["logits"], + batch.target_index, + batch.candidate_mask, + ) + contrastive_loss = candidate_contrastive_loss( + outputs["contrastive_context"], + outputs["contrastive_candidates"], + batch.target_index, + batch.candidate_mask, + ) + aux_loss = outputs["logits"].new_tensor(0.0) + if config.multitask: + aux_loss = aux_loss + F.cross_entropy(outputs["path_length_logits"], batch.path_length_bucket) + aux_loss = aux_loss + F.binary_cross_entropy_with_logits(outputs["tunnel_logits"], batch.tunnel_label) + aux_loss = aux_loss + F.binary_cross_entropy_with_logits(outputs["high_value_logits"], batch.high_value_label) + domain_loss = outputs["logits"].new_tensor(0.0) + if config.domain_adapt and "domain_logits" in outputs: + domain_loss = F.cross_entropy(outputs["domain_logits"], batch.source_ids) + total_loss = ranking_loss + total_loss = total_loss + config.hard_negative_weight * hard_loss + total_loss = total_loss + config.contrastive_weight * contrastive_loss + total_loss = total_loss + config.aux_weight * aux_loss + total_loss = total_loss + config.domain_adapt_weight * domain_loss + return { + "total": total_loss, + "ranking": ranking_loss.detach(), + "hard_negative": hard_loss.detach(), + "contrastive": contrastive_loss.detach(), + "aux": aux_loss.detach(), + "domain": domain_loss.detach(), + } + + def _metric_hits(self, logits: torch.Tensor, target_index: torch.Tensor, mask: torch.Tensor) -> tuple[int, int]: + top1 = torch.topk(logits, k=1, dim=-1).indices + topk = min(3, logits.shape[-1]) + top3 = torch.topk(logits, k=topk, dim=-1).indices + target = target_index.unsqueeze(-1) + return int((top1 == target).any(dim=-1).sum().item()), int((top3 == target).any(dim=-1).sum().item()) + + def _run_epoch( + self, + policy: EdgePolicy, + loader: DataLoader, + *, + config: TrainingConfig, + train: bool, + max_batches: int | None = None, + ) -> dict[str, float]: + use_amp = bool(config.amp and self.device.type == "cuda") + autocast = torch.autocast(device_type=self.device.type, dtype=torch.float16, enabled=use_amp) + if hasattr(torch, "amp") and hasattr(torch.amp, "GradScaler"): + scaler = torch.amp.GradScaler("cuda", enabled=use_amp) + else: # pragma: no cover - older torch fallback + scaler = torch.cuda.amp.GradScaler(enabled=use_amp) + start = time.perf_counter() + samples = 0 + steps = 0 + top1_hits = 0 + top3_hits = 0 + loss_totals = {"total": 0.0, "ranking": 0.0, "hard_negative": 0.0, "contrastive": 0.0, "aux": 0.0, "domain": 0.0} + + if train: + policy.model.train() + if policy.optimizer is not None: + policy.optimizer.zero_grad(set_to_none=True) + else: + policy.model.eval() + + for batch_index, batch in enumerate(loader): + if max_batches is not None and batch_index >= max_batches: + break + batch = batch.to(self.device) + samples += batch.batch_size + steps += 1 + if train: + with autocast: + outputs = policy.model(batch) + losses = self._compute_losses(policy, batch, outputs, config) + scaled_loss = losses["total"] / max(1, config.grad_accum_steps) + scaler.scale(scaled_loss).backward() + if (batch_index + 1) % max(1, config.grad_accum_steps) == 0: + scaler.unscale_(policy.optimizer) + torch.nn.utils.clip_grad_norm_(policy.model.parameters(), config.grad_clip) + scaler.step(policy.optimizer) + scaler.update() + policy.optimizer.zero_grad(set_to_none=True) + else: + with torch.no_grad(): + outputs = policy.model(batch) + losses = self._compute_losses(policy, batch, outputs, config) + + logits = outputs["logits"] + hit1, hit3 = self._metric_hits(logits, batch.target_index, batch.candidate_mask) + top1_hits += hit1 + top3_hits += hit3 + for key in loss_totals: + loss_totals[key] += float(losses[key].item()) + + if train and steps % max(1, config.grad_accum_steps) != 0 and policy.optimizer is not None: + scaler.unscale_(policy.optimizer) + torch.nn.utils.clip_grad_norm_(policy.model.parameters(), config.grad_clip) + scaler.step(policy.optimizer) + scaler.update() + policy.optimizer.zero_grad(set_to_none=True) + + duration = max(1e-6, time.perf_counter() - start) + return { + "loss": loss_totals["total"] / max(1, steps), + "ranking_loss": loss_totals["ranking"] / max(1, steps), + "hard_negative_loss": loss_totals["hard_negative"] / max(1, steps), + "contrastive_loss": loss_totals["contrastive"] / max(1, steps), + "aux_loss": loss_totals["aux"] / max(1, steps), + "domain_loss": loss_totals["domain"] / max(1, steps), + "top1": top1_hits / max(1, samples), + "top3": top3_hits / max(1, samples), + "samples": float(samples), + "steps": float(steps), + "epoch_time_sec": duration, + "samples_per_sec": samples / duration, + } + + def train( + self, + *, + run_dir: str | Path, + config: TrainingConfig, + supervision_rows: Sequence[dict[str, Any]] | None = None, + extra_record_files: Sequence[str] | None = None, + ) -> dict[str, Any]: + records, summary = self.materialize_records( + supervision_rows=supervision_rows, + extra_record_files=extra_record_files, + ) + split_map = split_policy_records(records, train_ratio=config.train_ratio, zero_shot_split=config.zero_shot_split) + train_records = split_map["train"] + val_records = split_map["val"] + zero_records = split_map["zero_shot"] + if not train_records: + raise RuntimeError("no train records available for Tri-Maze policy training") + + vocabulary = PolicyVocabulary.build(train_records or records) + policy = self._build_policy(vocabulary=vocabulary, config=config) + scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( + policy.optimizer, + mode="min", + factor=0.5, + patience=2, + ) + if config.resume: + payload = torch.load(config.resume, map_location="cpu", weights_only=False) + resume_vocab_matches = False + if payload.get("format_version") == "tmcra_tri_maze_policy_v2" or (payload.get("config") or {}).get("model_version") == "v2": + checkpoint_vocab = PolicyVocabulary.from_metadata(payload.get("vocabulary")) + resume_vocab_matches = checkpoint_vocab.to_metadata() == vocabulary.to_metadata() + policy.load_checkpoint( + config.resume, + load_optimizer=resume_vocab_matches, + strict=False, + preserve_vocabulary=not resume_vocab_matches, + ) + if resume_vocab_matches and payload.get("scheduler_state"): + scheduler.load_state_dict(payload["scheduler_state"]) + policy.model.to(self.device) + + run_path = Path(run_dir) + run_path.mkdir(parents=True, exist_ok=True) + history_path = run_path / "history.jsonl" + best_val = float("inf") + best_metrics: dict[str, Any] = {} + patience_count = 0 + + for epoch in range(int(config.epochs)): + epoch_records = filter_curriculum_records( + train_records, + epoch=epoch, + total_epochs=config.epochs, + curriculum=config.curriculum, + ) + train_loader = self._build_loader(epoch_records, vocabulary=vocabulary, config=config, train=True) + val_loader = self._build_loader(val_records, vocabulary=vocabulary, config=config, train=False) if val_records else None + zero_loader = self._build_loader(zero_records, vocabulary=vocabulary, config=config, train=False) if zero_records else None + + train_metrics = self._run_epoch(policy, train_loader, config=config, train=True) + val_metrics = self._run_epoch(policy, val_loader, config=config, train=False) if val_loader is not None else {"loss": 0.0, "top1": 0.0, "top3": 0.0} + zero_metrics = self._run_epoch(policy, zero_loader, config=config, train=False) if zero_loader is not None else {"loss": 0.0, "top1": 0.0, "top3": 0.0} + scheduler.step(val_metrics["loss"]) + + if self.device.type == "cuda": + peak_memory_mb = torch.cuda.max_memory_allocated(self.device) / (1024 * 1024) + torch.cuda.reset_peak_memory_stats(self.device) + else: + peak_memory_mb = 0.0 + + row = { + "epoch": epoch, + "train_loss": train_metrics["loss"], + "train_top1": train_metrics["top1"], + "train_top3": train_metrics["top3"], + "val_loss": val_metrics["loss"], + "val_top1": val_metrics["top1"], + "val_top3": val_metrics["top3"], + "zero_shot_loss": zero_metrics["loss"], + "zero_shot_top1": zero_metrics["top1"], + "zero_shot_top3": zero_metrics["top3"], + "samples_per_sec": train_metrics["samples_per_sec"], + "epoch_time_sec": train_metrics["epoch_time_sec"], + "peak_memory_mb": peak_memory_mb, + "lr": float(policy.optimizer.param_groups[0]["lr"]), + } + with history_path.open("a", encoding="utf-8") as handle: + handle.write(json.dumps(row, ensure_ascii=False) + "\n") + + metadata = { + "epoch": epoch, + "metrics": row, + "summary": summary, + "training_config": config.to_dict(), + "split_counts": {key: len(value) for key, value in split_map.items()}, + } + policy.save_checkpoint( + run_path / "last.pt", + metadata=metadata, + scheduler_state=scheduler.state_dict(), + extra_state={"patience_count": patience_count, "best_val": best_val}, + ) + if val_metrics["loss"] <= best_val: + best_val = val_metrics["loss"] + best_metrics = row + patience_count = 0 + policy.save_checkpoint( + run_path / "best.pt", + metadata=metadata, + scheduler_state=scheduler.state_dict(), + extra_state={"patience_count": patience_count, "best_val": best_val}, + ) + else: + patience_count += 1 + if patience_count >= config.patience: + break + + train_summary = { + **summary, + "epochs": int(config.epochs), + "device": str(self.device), + "best_val_loss": best_val, + "best_metrics": best_metrics, + "training_config": config.to_dict(), + } + (run_path / "train_summary.json").write_text(json.dumps(train_summary, ensure_ascii=False, indent=2), encoding="utf-8") + return {"run_dir": str(run_path), **train_summary} + + def evaluate( + self, + *, + checkpoint: str | Path, + config: TrainingConfig, + supervision_rows: Sequence[dict[str, Any]] | None = None, + extra_record_files: Sequence[str] | None = None, + split: str = "val", + ) -> dict[str, Any]: + records, summary = self.materialize_records( + supervision_rows=supervision_rows, + extra_record_files=extra_record_files, + ) + split_map = split_policy_records(records, train_ratio=config.train_ratio, zero_shot_split=config.zero_shot_split) + if split == "all": + eval_records = records + else: + eval_records = split_map.get(split, []) + policy = EdgePolicy(seed=self.seed) + metadata = policy.load_checkpoint(checkpoint, load_optimizer=False, strict=False) + policy.set_max_degree(self.engine._max_degree) + policy.model.to(self.device) + vocabulary = policy.vocabulary if policy.model_version == "v2" else PolicyVocabulary.build(eval_records or records) + loader = self._build_loader(eval_records, vocabulary=vocabulary, config=config, train=False) + metrics = self._run_epoch(policy, loader, config=config, train=False) + return { + "checkpoint": str(checkpoint), + "split": split, + "device": str(self.device), + "metrics": metrics, + "summary": summary, + "checkpoint_metadata": metadata, + } + + def benchmark( + self, + *, + config: TrainingConfig, + supervision_rows: Sequence[dict[str, Any]] | None = None, + extra_record_files: Sequence[str] | None = None, + checkpoint: str = "", + max_batches: int = 20, + ) -> dict[str, Any]: + records, summary = self.materialize_records( + supervision_rows=supervision_rows, + extra_record_files=extra_record_files, + ) + split_map = split_policy_records(records, train_ratio=config.train_ratio, zero_shot_split=config.zero_shot_split) + vocabulary = PolicyVocabulary.build(split_map["train"] or records) + policy = self._build_policy(vocabulary=vocabulary, config=config) + if checkpoint: + policy.load_checkpoint(checkpoint, load_optimizer=False, strict=False) + policy.model.to(self.device) + loader = self._build_loader(split_map["train"], vocabulary=vocabulary, config=config, train=True) + benchmark_metrics = self._run_epoch(policy, loader, config=config, train=not bool(checkpoint), max_batches=max_batches) + return {"summary": summary, "benchmark": benchmark_metrics, "max_batches": int(max_batches)} + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Train the Tri-Maze forward edge policy offline.") + subparsers = parser.add_subparsers(dest="command", required=True) + + def add_shared_data_args(subparser: argparse.ArgumentParser) -> None: + subparser.add_argument("--memory-file", default=DEFAULT_MEMORY_FILE) + subparser.add_argument("--graph-json", default="") + subparser.add_argument("--supervision-file", action="append", default=[]) + subparser.add_argument("--supervision-glob", action="append", default=[]) + subparser.add_argument("--record-file", action="append", default=[]) + subparser.add_argument("--train-ratio", type=float, default=0.9) + subparser.add_argument("--zero-shot-split", default="none") + subparser.add_argument("--cache-dir", default="") + subparser.add_argument("--device", default="auto") + subparser.add_argument("--seed", type=int, default=42) + + def add_train_args(subparser: argparse.ArgumentParser) -> None: + subparser.add_argument("--epochs", type=int, default=20) + subparser.add_argument("--batch-size", type=int, default=32) + subparser.add_argument("--num-workers", type=int, default=0) + subparser.add_argument("--lr", type=float, default=1e-3) + subparser.add_argument("--weight-decay", type=float, default=1e-4) + subparser.add_argument("--temperature", type=float, default=1.0) + subparser.add_argument("--branch-factor", type=int, default=2) + subparser.add_argument("--revisit-probability", type=float, default=0.2) + subparser.add_argument("--patience", type=int, default=8) + subparser.add_argument("--grad-clip", type=float, default=1.0) + subparser.add_argument("--grad-accum-steps", type=int, default=1) + subparser.add_argument("--amp", action="store_true") + subparser.add_argument("--model-type", default="v2") + subparser.add_argument("--embedding-dim", type=int, default=64) + subparser.add_argument("--relation-embedding-dim", type=int, default=16) + subparser.add_argument("--domain-embedding-dim", type=int, default=8) + subparser.add_argument("--trunk-dims", default="128,256,128") + subparser.add_argument("--hidden-dim", type=int, default=0) + subparser.add_argument("--dropout", type=float, default=0.1) + subparser.add_argument("--history-size", type=int, default=4) + subparser.add_argument("--curriculum", action="store_true") + subparser.add_argument("--episodic", action="store_true") + subparser.add_argument("--no-domain-balance", action="store_true") + subparser.add_argument("--no-multitask", action="store_true") + subparser.add_argument("--contrastive-weight", type=float, default=0.08) + subparser.add_argument("--hard-negative-weight", type=float, default=0.12) + subparser.add_argument("--aux-weight", type=float, default=0.15) + subparser.add_argument("--domain-adapt", action="store_true") + subparser.add_argument("--domain-adapt-weight", type=float, default=0.03) + subparser.add_argument("--resume", default="") + + prepare = subparsers.add_parser("prepare") + add_shared_data_args(prepare) + prepare.add_argument("--output", default="") + + train = subparsers.add_parser("train") + add_shared_data_args(train) + add_train_args(train) + train.add_argument("--run-dir", default="data/tri_maze_policy/runs/latest") + + evaluate = subparsers.add_parser("evaluate") + add_shared_data_args(evaluate) + add_train_args(evaluate) + evaluate.add_argument("--checkpoint", required=True) + evaluate.add_argument("--split", choices=["train", "val", "zero_shot", "all"], default="val") + evaluate.add_argument("--output", default="") + + benchmark = subparsers.add_parser("benchmark") + add_shared_data_args(benchmark) + add_train_args(benchmark) + benchmark.add_argument("--checkpoint", default="") + benchmark.add_argument("--max-batches", type=int, default=20) + benchmark.add_argument("--output", default="") + + return parser + + +def _training_config_from_args(args: argparse.Namespace) -> TrainingConfig: + trunk_dims = tuple(int(item.strip()) for item in str(args.trunk_dims).split(",") if item.strip()) + if args.hidden_dim and not trunk_dims: + trunk_dims = (args.hidden_dim, args.hidden_dim * 2, args.hidden_dim) + if not trunk_dims: + trunk_dims = (128, 256, 128) + return TrainingConfig( + epochs=args.epochs, + batch_size=args.batch_size, + num_workers=args.num_workers, + lr=args.lr, + weight_decay=args.weight_decay, + temperature=args.temperature, + branch_factor=args.branch_factor, + revisit_probability=args.revisit_probability, + train_ratio=args.train_ratio, + patience=args.patience, + grad_clip=args.grad_clip, + grad_accum_steps=args.grad_accum_steps, + amp=bool(args.amp), + model_type=args.model_type, + embedding_dim=args.embedding_dim, + relation_embedding_dim=args.relation_embedding_dim, + domain_embedding_dim=args.domain_embedding_dim, + trunk_dims=trunk_dims, + dropout=args.dropout, + history_size=args.history_size, + curriculum=CurriculumConfig(enabled=bool(args.curriculum)), + domain_balance=not bool(args.no_domain_balance), + episodic=bool(args.episodic), + multitask=not bool(args.no_multitask), + contrastive_weight=args.contrastive_weight, + hard_negative_weight=args.hard_negative_weight, + aux_weight=args.aux_weight, + domain_adapt=bool(args.domain_adapt), + domain_adapt_weight=args.domain_adapt_weight, + zero_shot_split=args.zero_shot_split, + cache_dir=args.cache_dir, + resume=args.resume, + ) + + +def run_from_args(args: argparse.Namespace) -> Dict[str, Any]: + repo_root = _repo_root() + memory_file = Path(args.memory_file) + if not memory_file.is_absolute(): + memory_file = repo_root / memory_file + memory = ConceptMemory(memory_file=str(memory_file)) + supervision_files = discover_supervision_files( + repo_root=repo_root, + files=getattr(args, "supervision_file", []), + globs=getattr(args, "supervision_glob", []), + ) + supervision_rows = load_all_supervision_rows(supervision_files) + graph_json = getattr(args, "graph_json", "") or None + if graph_json and not Path(graph_json).is_absolute(): + graph_json = str(repo_root / graph_json) + graph = build_training_graph(memory, supervision_rows=supervision_rows, graph_json_path=graph_json) + trainer = TriMazeNeuralTrainer(graph, memory, device=args.device, seed=args.seed) + + if args.command == "prepare": + result = trainer.prepare_summary( + supervision_rows=supervision_rows, + extra_record_files=args.record_file, + train_ratio=args.train_ratio, + zero_shot_split=args.zero_shot_split, + cache_dir=args.cache_dir, + ) + else: + config = _training_config_from_args(args) + if args.command == "train": + run_dir = args.run_dir + if run_dir.endswith("latest"): + run_dir = str(Path(run_dir).parent / _timestamp()) + result = trainer.train( + run_dir=run_dir, + config=config, + supervision_rows=supervision_rows, + extra_record_files=args.record_file, + ) + elif args.command == "evaluate": + result = trainer.evaluate( + checkpoint=args.checkpoint, + config=config, + supervision_rows=supervision_rows, + extra_record_files=args.record_file, + split=args.split, + ) + else: + result = trainer.benchmark( + config=config, + supervision_rows=supervision_rows, + extra_record_files=args.record_file, + checkpoint=args.checkpoint, + max_batches=args.max_batches, + ) + + if getattr(args, "output", ""): + output = Path(args.output) + if not output.is_absolute(): + output = repo_root / output + output.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8") + return result + + +def main() -> None: + parser = build_parser() + args = parser.parse_args() + result = run_from_args(args) + print(json.dumps(result, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_supervision.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_supervision.py new file mode 100644 index 0000000..5db938f --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_supervision.py @@ -0,0 +1,1136 @@ +from __future__ import annotations + +import hashlib +import json +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Dict, Iterable, Iterator, List, Sequence + +from .concept_memory import ConceptMemory + + +CANONICAL_FIELDS = [ + "source_dataset", + "sample_id", + "query", + "query_type", + "focus_concept", + "concepts", + "forward_paths", + "facts", + "score", + "source", +] + +STOPWORDS = { + "a", + "an", + "and", + "are", + "as", + "at", + "be", + "because", + "by", + "can", + "could", + "do", + "does", + "for", + "from", + "how", + "if", + "in", + "into", + "is", + "it", + "more", + "need", + "necessary", + "of", + "on", + "or", + "should", + "than", + "that", + "the", + "their", + "there", + "these", + "this", + "to", + "what", + "when", + "where", + "which", + "why", + "will", + "with", + "would", +} + +ATOMIC_RELATIONS = { + "xNeed", + "xEffect", + "xIntent", + "xWant", + "xAttr", + "oEffect", + "oWant", + "oReact", + "xReact", + "isBefore", + "isAfter", + "HasSubEvent", + "HinderedBy", +} + + +@dataclass(slots=True) +class DatasetAdapter: + dataset_id: str + supervision_role: str + convert: Callable[[Sequence[Dict[str, Any]]], List[Dict[str, Any]]] + + +def _collapse_ws(text: str) -> str: + return re.sub(r"\s+", " ", text or "").strip() + + +def _normalize_text(value: Any) -> str: + if value is None: + return "" + if isinstance(value, str): + return _collapse_ws(value.replace("\u00a0", " ").strip(" \t\r\n\"'")) + return _collapse_ws(str(value)) + + +def _truncate(text: str, *, limit: int = 220) -> str: + if len(text) <= limit: + return text + return text[: limit - 3].rstrip() + "..." + + +def _iter_strings(value: Any) -> Iterator[str]: + if value is None: + return + if isinstance(value, str): + cleaned = _normalize_text(value) + if cleaned: + yield cleaned + return + if isinstance(value, dict): + for nested in value.values(): + yield from _iter_strings(nested) + return + if isinstance(value, (list, tuple, set)): + for item in value: + yield from _iter_strings(item) + + +def _first_text(container: Any, *keys: str) -> str: + if not isinstance(container, dict): + return "" + for key in keys: + value = container.get(key) + if isinstance(value, str): + cleaned = _normalize_text(value) + if cleaned: + return cleaned + return "" + + +def _dedupe_preserve(values: Iterable[str]) -> List[str]: + seen = set() + ordered: List[str] = [] + for value in values: + cleaned = _normalize_text(value) + if not cleaned: + continue + marker = cleaned.casefold() + if marker in seen: + continue + seen.add(marker) + ordered.append(cleaned) + return ordered + + +def _clamp_score(value: Any, *, default: float = 0.8) -> float: + try: + return max(0.1, min(1.0, float(value))) + except Exception: + return default + + +def _extract_keywords(*texts: str, limit: int = 12) -> List[str]: + ordered: List[str] = [] + seen = set() + for text in texts: + for token in re.findall(r"[A-Za-z][A-Za-z0-9_-]{2,}", text or ""): + marker = token.casefold() + if marker in STOPWORDS or marker in seen: + continue + seen.add(marker) + ordered.append(token.lower()) + if len(ordered) >= limit: + return ordered + return ordered + + +def _infer_query_type(query: str) -> str: + normalized = (query or "").strip().lower() + if normalized.startswith("why ") or normalized.startswith("why?") or " why " in f" {normalized} ": + return "explanation" + if normalized.startswith("how ") or normalized.startswith("how do") or normalized.startswith("how can"): + return "how_to" + if normalized.startswith("what if") or "what would happen" in normalized: + return "counterfactual" + if normalized.startswith("is ") or normalized.startswith("are ") or normalized.startswith("does "): + return "verification" + if "need" in normalized or "necessary" in normalized or "why must" in normalized: + return "necessity" + return "query" + + +def _as_path_nodes(values: Iterable[str], *, min_length: int = 2) -> List[str]: + cleaned = _dedupe_preserve(_truncate(_normalize_text(value), limit=220) for value in values) + if len(cleaned) < min_length: + return [] + return cleaned + + +def _path_to_facts(nodes: Sequence[str], *, relation: str, weight: float) -> List[Dict[str, Any]]: + facts: List[Dict[str, Any]] = [] + for index in range(len(nodes) - 1): + facts.append( + { + "from": nodes[index], + "relation": relation, + "to": nodes[index + 1], + "weight": max(0.1, min(1.0, float(weight))), + } + ) + return facts + + +def _extract_choice_text(row: Dict[str, Any], answer_key: str) -> str: + if not answer_key: + return "" + choices_value = row.get("choices") + if not choices_value and isinstance(row.get("question"), dict): + choices_value = row["question"].get("choices") + if not isinstance(choices_value, list): + return "" + normalized_key = answer_key.strip().upper() + for choice in choices_value: + if not isinstance(choice, dict): + continue + label = str(choice.get("label") or choice.get("key") or "").strip().upper() + if label == normalized_key: + return _normalize_text(choice.get("text") or choice.get("label_text") or "") + return "" + + +def _statement_from_query_answer(query: str, answer: str) -> str: + query_clean = _normalize_text(query) + answer_clean = _normalize_text(answer) + if not query_clean: + return answer_clean + if not answer_clean: + return query_clean + if query_clean.endswith("?"): + return _collapse_ws(f"{query_clean[:-1]}: {answer_clean}") + return _collapse_ws(f"{query_clean} => {answer_clean}") + + +def _collect_clauses(text: str, *, limit: int = 6) -> List[str]: + raw = _normalize_text(text) + if not raw: + return [] + parts = re.split(r"(?:\s*;\s*|\s+\.\s+|\s*,\s+|\s+because\s+|\s+therefore\s+|\s+so\s+)", raw) + return _dedupe_preserve(_truncate(part, limit=180) for part in parts if _normalize_text(part))[:limit] + + +def _normalize_fact(raw: Any) -> Dict[str, Any] | None: + if isinstance(raw, dict): + src = _normalize_text(raw.get("from") or raw.get("src") or raw.get("head")) + relation = _normalize_text(raw.get("relation") or raw.get("predicate") or raw.get("type")) + dst = _normalize_text(raw.get("to") or raw.get("dst") or raw.get("tail")) + if not src or not relation or not dst: + return None + return { + "from": _truncate(src), + "relation": relation.lower(), + "to": _truncate(dst), + "weight": _clamp_score(raw.get("weight", 0.8), default=0.8), + } + if isinstance(raw, str): + text = _normalize_text(raw) + if "->" in text: + left, right = text.split("->", 1) + src = _normalize_text(left) + dst = _normalize_text(right) + if src and dst: + return {"from": _truncate(src), "relation": "related_to", "to": _truncate(dst), "weight": 0.7} + return None + + +def normalize_supervision_row(row: Dict[str, Any]) -> Dict[str, Any]: + source_dataset = _normalize_text(row.get("source_dataset") or row.get("source") or "unknown").lower() + sample_id = _normalize_text(row.get("sample_id") or row.get("id") or "") + query = _truncate(_normalize_text(row.get("query") or row.get("question") or sample_id), limit=260) + query_type = _normalize_text(row.get("query_type") or _infer_query_type(query)).lower() or "query" + focus_concept = _truncate(_normalize_text(row.get("focus_concept") or ""), limit=220) + concepts = _dedupe_preserve(_truncate(item, limit=120) for item in _iter_strings(row.get("concepts"))) + + forward_paths: List[List[str]] = [] + raw_paths = row.get("forward_paths") or [] + if isinstance(raw_paths, list): + for raw_path in raw_paths: + if isinstance(raw_path, str): + path = _as_path_nodes(re.split(r"\s*->\s*", raw_path)) + else: + path = _as_path_nodes(_iter_strings(raw_path)) + if path: + forward_paths.append(path) + + facts = [] + for raw_fact in row.get("facts") or []: + normalized_fact = _normalize_fact(raw_fact) + if normalized_fact: + facts.append(normalized_fact) + + if not concepts: + concept_seed = [query, focus_concept] + for path in forward_paths: + concept_seed.extend(path) + for fact in facts: + concept_seed.extend([fact["from"], fact["to"]]) + concepts = _extract_keywords(*concept_seed, limit=16) + + normalized = { + "source_dataset": source_dataset or "unknown", + "sample_id": sample_id or f"{source_dataset}-{hashlib.md5(query.encode('utf-8', errors='ignore')).hexdigest()[:12]}", + "query": query, + "query_type": query_type, + "focus_concept": focus_concept, + "concepts": concepts, + "forward_paths": forward_paths, + "facts": facts, + "score": _clamp_score(row.get("score", 0.8), default=0.8), + "source": _normalize_text(row.get("source") or source_dataset or "unknown").lower() or "unknown", + } + return normalized + + +def validate_supervision_row(row: Dict[str, Any]) -> List[str]: + issues: List[str] = [] + normalized = normalize_supervision_row(row) + if not normalized["source_dataset"]: + issues.append("missing source_dataset") + if not normalized["sample_id"]: + issues.append("missing sample_id") + if not normalized["query"]: + issues.append("missing query") + for path_index, path in enumerate(normalized["forward_paths"]): + if len(path) < 2: + issues.append(f"path[{path_index}] shorter than 2 nodes") + for idx in range(len(path) - 1): + if path[idx].casefold() == path[idx + 1].casefold(): + issues.append(f"path[{path_index}] contains self loop at step {idx}") + for fact_index, fact in enumerate(normalized["facts"]): + if not fact["from"] or not fact["relation"] or not fact["to"]: + issues.append(f"fact[{fact_index}] is incomplete") + return issues + + +def read_jsonl(path: Path) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + with path.open("r", encoding="utf-8-sig") as handle: + for raw in handle: + line = raw.strip() + if not line: + continue + payload = json.loads(line) + if isinstance(payload, dict): + rows.append(payload) + return rows + + +def write_jsonl(path: Path, rows: Sequence[Dict[str, Any]]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as handle: + for row in rows: + handle.write(json.dumps(normalize_supervision_row(row), ensure_ascii=False) + "\n") + + +def load_records(path: str | Path) -> List[Dict[str, Any]]: + target = Path(path) + if target.is_dir(): + rows: List[Dict[str, Any]] = [] + for child in sorted(target.rglob("*")): + if child.suffix.lower() not in {".json", ".jsonl"}: + continue + rows.extend(load_records(child)) + return rows + + if target.suffix.lower() == ".jsonl": + return read_jsonl(target) + + payload = json.loads(target.read_text(encoding="utf-8-sig")) + if isinstance(payload, list): + return [item for item in payload if isinstance(item, dict)] + if isinstance(payload, dict): + for key in ("rows", "data", "examples", "items", "train", "dev", "validation", "test"): + value = payload.get(key) + if isinstance(value, list): + return [item for item in value if isinstance(item, dict)] + return [payload] + return [] + + +def load_supervision_rows(path: str | Path) -> List[Dict[str, Any]]: + return [normalize_supervision_row(item) for item in load_records(path)] + + +def summarize_supervision_rows( + rows: Sequence[Dict[str, Any]], + *, + memory: ConceptMemory | None = None, +) -> Dict[str, Any]: + normalized_rows = [normalize_supervision_row(row) for row in rows] + query_type_counts: Dict[str, int] = {} + dataset_counts: Dict[str, int] = {} + forward_path_count = 0 + forward_step_count = 0 + rows_with_paths = 0 + rows_with_facts = 0 + fact_count = 0 + invalid_rows = 0 + duplicate_paths = 0 + path_markers = set() + concept_nodes = set() + + for row in normalized_rows: + dataset_counts[row["source_dataset"]] = dataset_counts.get(row["source_dataset"], 0) + 1 + query_type_counts[row["query_type"]] = query_type_counts.get(row["query_type"], 0) + 1 + issues = validate_supervision_row(row) + if issues: + invalid_rows += 1 + if row["forward_paths"]: + rows_with_paths += 1 + if row["facts"]: + rows_with_facts += 1 + for concept in row["concepts"]: + concept_nodes.add(concept) + for path in row["forward_paths"]: + forward_path_count += 1 + forward_step_count += max(0, len(path) - 1) + concept_nodes.update(path) + marker = " -> ".join(path).casefold() + if marker in path_markers: + duplicate_paths += 1 + else: + path_markers.add(marker) + for fact in row["facts"]: + fact_count += 1 + concept_nodes.add(fact["from"]) + concept_nodes.add(fact["to"]) + + overlap = {"base_concepts": 0, "matched_concepts": 0, "match_rate": 0.0} + if memory is not None: + base_concepts = {name.casefold() for name in memory.get_all_concepts().keys()} + matched = {item for item in concept_nodes if item.casefold() in base_concepts} + overlap = { + "base_concepts": len(base_concepts), + "matched_concepts": len(matched), + "match_rate": round(len(matched) / max(1, len(concept_nodes)), 4), + } + + avg_path_length = 0.0 + if forward_path_count > 0: + avg_path_length = round((forward_step_count + forward_path_count) / forward_path_count, 4) + + return { + "row_count": len(normalized_rows), + "dataset_counts": dataset_counts, + "query_type_counts": query_type_counts, + "rows_with_paths": rows_with_paths, + "rows_with_facts": rows_with_facts, + "forward_path_count": forward_path_count, + "forward_step_count": forward_step_count, + "avg_path_length": avg_path_length, + "fact_count": fact_count, + "unique_concept_count": len(concept_nodes), + "duplicate_path_count": duplicate_paths, + "invalid_row_count": invalid_rows, + "concept_overlap": overlap, + } + + +def import_supervision_rows( + rows: Sequence[Dict[str, Any]], + *, + memory: ConceptMemory, + min_path_len: int = 2, + concept_type: str = "proposition", +) -> Dict[str, Any]: + normalized_rows = [normalize_supervision_row(row) for row in rows] + concept_attempts = 0 + fact_attempts = 0 + path_attempts = 0 + incoming_fact_total = sum(len(row.get("facts") or []) for row in normalized_rows) + if getattr(memory, "max_facts", 0): + memory.max_facts = max(int(memory.max_facts), len(memory.facts) + incoming_fact_total) + + path_lookup = {} + for index, path_record in enumerate(memory.paths): + normalized_path = memory._normalize_path_record(path_record) + marker = (tuple(normalized_path.get("path") or []), normalized_path.get("mode") or "forward") + path_lookup[marker] = index + + fact_lookup = {} + for index, fact in enumerate(memory.facts): + marker = ( + _normalize_text(fact.get("from")), + _normalize_text(fact.get("relation")).lower(), + _normalize_text(fact.get("to")), + ) + fact_lookup[marker] = index + + for row in normalized_rows: + dataset_id = row["source_dataset"] + source_tag = f"offline_import:{dataset_id}" + concept_seed: List[str] = list(row["concepts"]) + for path in row["forward_paths"]: + concept_seed.extend(path) + for fact in row["facts"]: + concept_seed.extend([fact["from"], fact["to"]]) + + for concept in _dedupe_preserve(concept_seed): + existing = memory.concepts.get(concept) + if existing is not None: + existing["importance_score"] = max( + float(existing.get("importance_score", 0.0) or 0.0), + max(0.3, min(1.0, float(row["score"]))), + ) + if concept_type != "general" and existing.get("type") == "unknown": + existing["type"] = concept_type + if not existing.get("created_from"): + existing["created_from"] = dataset_id + else: + memory.concepts[concept] = { + "concept": concept, + "type": concept_type, + "importance_score": max(0.3, min(1.0, float(row["score"]))), + "created_from": dataset_id, + } + concept_attempts += 1 + + for fact in row["facts"]: + marker = ( + _normalize_text(fact["from"]), + _normalize_text(fact["relation"]).lower(), + _normalize_text(fact["to"]), + ) + existing_fact_index = fact_lookup.get(marker) + if existing_fact_index is not None: + existing_fact = memory.facts[existing_fact_index] + existing_fact["uses"] = int(existing_fact.get("uses", 1) or 1) + 1 + existing_fact["weight"] = max(float(existing_fact.get("weight", 0.7) or 0.7), float(fact["weight"])) + else: + memory.facts.append( + { + "from": fact["from"], + "relation": fact["relation"], + "to": fact["to"], + "weight": float(fact["weight"]), + "uses": 1, + } + ) + fact_lookup[marker] = len(memory.facts) - 1 + fact_attempts += 1 + + for path in row["forward_paths"]: + if len(path) < min_path_len: + continue + marker = (tuple(path), "forward") + existing_path_index = path_lookup.get(marker) + if existing_path_index is not None: + current = memory._normalize_path_record(memory.paths[existing_path_index]) + current["uses"] = current.get("uses", 1) + 1 + current["score"] = max(float(current.get("score", 0.8)), float(row["score"])) + current["mode"] = "forward" + current["source"] = source_tag + memory.paths[existing_path_index] = current + else: + memory.paths.append( + memory._normalize_path_record( + { + "path": list(path), + "score": row["score"], + "uses": 1, + "mode": "forward", + "source": source_tag, + } + ) + ) + path_lookup[marker] = len(memory.paths) - 1 + for index in range(len(path) - 1): + edge = (path[index], path[index + 1]) + memory.edge_counts[edge] += 1 + path_attempts += 1 + + memory._cleanup_memory() + + return { + "row_count": len(normalized_rows), + "concept_attempts": concept_attempts, + "fact_attempts": fact_attempts, + "path_attempts": path_attempts, + "memory_file": memory.memory_file, + } + + +def merge_supervision_rows(inputs: Sequence[Sequence[Dict[str, Any]]]) -> List[Dict[str, Any]]: + merged: List[Dict[str, Any]] = [] + seen = set() + for rows in inputs: + for row in rows: + normalized = normalize_supervision_row(row) + marker = (normalized["source_dataset"], normalized["sample_id"]) + if marker in seen: + continue + seen.add(marker) + merged.append(normalized) + return merged + + +def _clean_statement_text(text: Any) -> str: + cleaned = _normalize_text(text) + cleaned = re.sub(r"^(?:sent|statement|fact|int|hypothesis)\d*\s*[:=]\s*", "", cleaned, flags=re.IGNORECASE) + cleaned = re.sub(r"\s+", " ", cleaned).strip(" .;") + return _truncate(cleaned, limit=220) + + +def _is_placeholder_token(text: str) -> bool: + return bool(re.fullmatch(r"(?i)(?:sent|statement|fact|int|hypothesis)\d+", _normalize_text(text))) + + +def _keep_statement(text: str, *, min_words: int = 3) -> bool: + cleaned = _clean_statement_text(text) + if not cleaned: + return False + if _is_placeholder_token(cleaned): + return False + words = re.findall(r"[A-Za-z0-9_-]+", cleaned) + return len(words) >= min_words + + +def _proof_lookup(record: Dict[str, Any], key: str) -> Dict[str, str]: + value = record.get(key) + if not value and isinstance(record.get("meta"), dict): + value = record["meta"].get(key) + mapping: Dict[str, str] = {} + if isinstance(value, dict): + for raw_key, raw_value in value.items(): + cleaned = "" + if isinstance(raw_value, dict): + cleaned = _first_text(raw_value, "text", "sentence", "statement", "original_text") + if not cleaned: + cleaned = next(iter(_iter_strings(raw_value)), "") + elif isinstance(raw_value, list): + cleaned = next(iter(_iter_strings(raw_value)), "") + else: + cleaned = _normalize_text(raw_value) + cleaned = _clean_statement_text(cleaned) + if _keep_statement(cleaned, min_words=2): + normalized_key = _normalize_text(raw_key) + mapping[normalized_key] = cleaned + mapping[normalized_key.lower()] = cleaned + return mapping + + +def _resolve_proof_token(token: str, lookup: Dict[str, str]) -> str: + cleaned = _normalize_text(token) + if not cleaned: + return "" + if cleaned in lookup: + return lookup[cleaned] + if cleaned.lower() in lookup: + return lookup[cleaned.lower()] + if _is_placeholder_token(cleaned): + return "" + resolved = _clean_statement_text(cleaned) + if not _keep_statement(resolved, min_words=2): + return "" + return resolved + + +def _extract_entailment_question(record: Dict[str, Any]) -> str: + question = _first_text(record, "question", "query") + if question: + return question + meta = record.get("meta") + if isinstance(meta, dict): + question = _first_text(meta, "question", "question_text", "query") + if question: + return question + if isinstance(record.get("answer"), dict): + question = _first_text(record["answer"], "text") + if question: + return question + return "" + + +def _extract_entailment_hypothesis(record: Dict[str, Any]) -> str: + hypothesis = _first_text(record, "hypothesis", "answer") + if hypothesis: + return _clean_statement_text(hypothesis) + meta = record.get("meta") + if isinstance(meta, dict): + hypothesis = _first_text(meta, "hypothesis", "answer") + if hypothesis: + return _clean_statement_text(hypothesis) + return "" + + +def _extract_entailment_proof_steps(record: Dict[str, Any]) -> List[tuple[List[str], str]]: + proof_text = _first_text(record, "full_text_proof", "proof") + if not proof_text and isinstance(record.get("meta"), dict): + proof_text = _first_text(record["meta"], "full_text_proof", "proof") + if not proof_text: + return [] + + lookup: Dict[str, str] = {} + lookup.update(_proof_lookup(record, "triples")) + lookup.update(_proof_lookup(record, "intermediate_conclusions")) + lookup.update(_proof_lookup(record, "sentences")) + lookup.update(_proof_lookup(record, "worldtree_provenance")) + + steps: List[tuple[List[str], str]] = [] + for line in re.split(r"[;\n]+", proof_text): + cleaned_line = _normalize_text(line) + if "->" not in cleaned_line: + continue + left, right = cleaned_line.split("->", 1) + output = _resolve_proof_token(right, lookup) + if not output: + continue + inputs = [] + for token in re.split(r"\s*(?:and|&|,)\s*", left, flags=re.IGNORECASE): + resolved = _resolve_proof_token(token, lookup) + if resolved: + inputs.append(resolved) + inputs = _dedupe_preserve(inputs) + if inputs: + steps.append((inputs, output)) + return steps + + +def _extract_entailment_paths_and_facts(record: Dict[str, Any], *, max_paths: int = 4) -> tuple[List[List[str]], List[Dict[str, Any]]]: + steps = _extract_entailment_proof_steps(record) + hypothesis = _extract_entailment_hypothesis(record) + if not steps: + fallback_path = _as_path_nodes([hypothesis] if hypothesis else []) + return ([fallback_path] if fallback_path else []), _path_to_facts(fallback_path, relation="entails", weight=0.95) + + produced_by: Dict[str, List[str]] = {} + used_as_input = set() + facts: List[Dict[str, Any]] = [] + for inputs, output in steps: + produced_by.setdefault(output, []) + for item in inputs: + if item not in produced_by[output]: + produced_by[output].append(item) + used_as_input.add(item) + facts.append({"from": item, "relation": "entails", "to": output, "weight": 0.95}) + + terminal_targets: List[str] = [] + if hypothesis and hypothesis in produced_by: + terminal_targets.append(hypothesis) + elif hypothesis: + candidate = _clean_statement_text(hypothesis) + if candidate in produced_by: + terminal_targets.append(candidate) + if not terminal_targets: + terminal_targets = [node for node in produced_by.keys() if node not in used_as_input] + terminal_targets = _dedupe_preserve(terminal_targets)[:max_paths] + + def walk(node: str, trail: tuple[str, ...]) -> List[List[str]]: + if node in trail: + return [] + parents = produced_by.get(node) or [] + if not parents: + return [[node]] + paths: List[List[str]] = [] + for parent in parents: + parent_paths = walk(parent, trail + (node,)) + if not parent_paths: + paths.append([parent, node]) + continue + for parent_path in parent_paths: + candidate = parent_path + [node] + if 2 <= len(candidate) <= 6: + paths.append(candidate) + return paths + + raw_paths: List[List[str]] = [] + for target in terminal_targets: + raw_paths.extend(walk(target, tuple())) + + cleaned_paths: List[List[str]] = [] + seen = set() + for path in raw_paths: + normalized_path = _as_path_nodes(path) + if len(normalized_path) < 2: + continue + marker = tuple(node.casefold() for node in normalized_path) + if marker in seen: + continue + seen.add(marker) + cleaned_paths.append(normalized_path) + if len(cleaned_paths) >= max_paths: + break + + if not cleaned_paths and hypothesis: + fallback_nodes = _as_path_nodes(list(produced_by.keys())[:1] + [hypothesis]) + if fallback_nodes: + cleaned_paths.append(fallback_nodes) + + deduped_facts: List[Dict[str, Any]] = [] + fact_markers = set() + for fact in facts: + marker = (fact["from"].casefold(), fact["relation"], fact["to"].casefold()) + if marker in fact_markers: + continue + fact_markers.add(marker) + deduped_facts.append(fact) + return cleaned_paths, deduped_facts + + +def convert_entailmentbank(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + query = _extract_entailment_question(record) + hypothesis = _extract_entailment_hypothesis(record) + forward_paths, facts = _extract_entailment_paths_and_facts(record) + concept_strings = [query, hypothesis] + for path in forward_paths: + concept_strings.extend(path) + rows.append( + normalize_supervision_row( + { + "source_dataset": "entailmentbank", + "sample_id": _normalize_text(record.get("id") or record.get("uid") or f"entailmentbank-{index}"), + "query": query or hypothesis or f"entailmentbank sample {index}", + "query_type": _infer_query_type(query or hypothesis), + "focus_concept": hypothesis, + "concepts": _extract_keywords(*concept_strings, limit=16), + "forward_paths": forward_paths, + "facts": facts, + "score": 0.95, + "source": "entailmentbank", + } + ) + ) + return rows + + +def _extract_qasc_question(record: Dict[str, Any]) -> str: + question_value = record.get("question") + if isinstance(question_value, dict): + return _first_text(question_value, "stem", "question") + return _normalize_text(question_value or record.get("formatted_question") or record.get("question_text")) + + +def _extract_qasc_choice_context(record: Dict[str, Any], answer_key: str) -> List[str]: + if not answer_key: + return [] + question_value = record.get("question") + if isinstance(question_value, dict): + choices = question_value.get("choices") + if isinstance(choices, list): + for choice in choices: + if not isinstance(choice, dict): + continue + label = _normalize_text(choice.get("label") or choice.get("key")).upper() + if label != answer_key.upper(): + continue + support: List[str] = [] + support.extend(_iter_strings(choice.get("facts"))) + para = _normalize_text(choice.get("para") or choice.get("support")) + if para: + support.extend(_collect_clauses(para, limit=2)) + return _dedupe_preserve(_clean_statement_text(item) for item in support if _keep_statement(item, min_words=3)) + return [] + + +def _qasc_answer_statement(query: str, answer_text: str, combined: str) -> str: + candidate = _clean_statement_text(combined) + if _keep_statement(candidate, min_words=4): + return candidate + return _clean_statement_text(_statement_from_query_answer(query, answer_text)) + + +def convert_qasc(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + query = _extract_qasc_question(record) + answer_key = _normalize_text(record.get("answerKey") or record.get("answer_key")) + answer_text = _extract_choice_text(record, answer_key) or _normalize_text(record.get("answer")) + fact1 = _clean_statement_text(_first_text(record, "fact1")) + fact2 = _clean_statement_text(_first_text(record, "fact2")) + combined = _first_text(record, "combinedfact", "combined_fact", "explanation") + answer_statement = _qasc_answer_statement(query, answer_text, combined) + path_nodes = _as_path_nodes( + [ + fact1 if _keep_statement(fact1, min_words=3) else "", + fact2 if _keep_statement(fact2, min_words=3) else "", + answer_statement if _keep_statement(answer_statement, min_words=3) else "", + ] + ) + choice_context = _extract_qasc_choice_context(record, answer_key) + weak_support = _as_path_nodes(choice_context[:2] + ([answer_statement] if answer_statement else [])) + facts = _path_to_facts(path_nodes, relation="supports", weight=0.9) + if not facts and weak_support: + facts = _path_to_facts(weak_support, relation="supports", weight=0.55) + forward_paths = [path_nodes] if path_nodes else [] + rows.append( + normalize_supervision_row( + { + "source_dataset": "qasc", + "sample_id": _normalize_text(record.get("id") or f"qasc-{index}"), + "query": query or f"qasc sample {index}", + "query_type": _infer_query_type(query), + "focus_concept": answer_text, + "concepts": _extract_keywords(query, fact1, fact2, answer_text, answer_statement, *choice_context, limit=16), + "forward_paths": forward_paths, + "facts": facts, + "score": 0.92 if forward_paths else 0.45, + "source": "qasc", + } + ) + ) + return rows + + +def _wiqa_answer_text(record: Dict[str, Any]) -> str: + answer_key = _normalize_text(record.get("answer_label") or record.get("answerKey") or record.get("label")) + if answer_key in {"A", "MORE"}: + return "more likely / more" + if answer_key in {"B", "LESS"}: + return "less likely / less" + if answer_key in {"C", "NO_EFFECT", "NO EFFECT"}: + return "no effect" + answer_text = _extract_choice_text(record, answer_key) + if answer_text: + return answer_text + return _normalize_text(record.get("answer") or record.get("answer_text")) + + +def convert_wiqa(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + query = _first_text(record, "question_stem", "question", "stem") + question_value = record.get("question") + if not query and isinstance(question_value, dict): + query = _first_text(question_value, "stem", "question") + step_texts = _dedupe_preserve( + [ + _first_text(record, "question_para_step", "question_para_steps"), + *_iter_strings(record.get("steps")), + *_iter_strings(record.get("metadata")), + ] + ) + answer_text = _wiqa_answer_text(record) + outcome = _statement_from_query_answer(query or "wiqa effect", answer_text or "effect") + path_nodes = _as_path_nodes(step_texts[:2] + [outcome]) + if not path_nodes and query and outcome: + path_nodes = _as_path_nodes([query, outcome]) + facts = _path_to_facts(path_nodes, relation="causes", weight=0.8) + rows.append( + normalize_supervision_row( + { + "source_dataset": "wiqa", + "sample_id": _normalize_text(record.get("id") or record.get("qid") or f"wiqa-{index}"), + "query": query or f"wiqa sample {index}", + "query_type": "counterfactual" if "what if" in (query or "").lower() else _infer_query_type(query), + "focus_concept": answer_text, + "concepts": _extract_keywords(query, answer_text, *path_nodes, limit=16), + "forward_paths": [path_nodes] if path_nodes else [], + "facts": facts, + "score": 0.8, + "source": "wiqa", + } + ) + ) + return rows + + +def convert_quartz(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + question_value = record.get("question") + query = _normalize_text(question_value if isinstance(question_value, str) else "") + if not query and isinstance(question_value, dict): + query = _first_text(question_value, "stem", "question") + para = _first_text(record, "para", "paragraph") + annotations = _dedupe_preserve(_iter_strings(record.get("para_anno"))) + answer_key = _normalize_text(record.get("answerKey") or record.get("answer_key")) + answer_text = _extract_choice_text(record, answer_key) or _normalize_text(record.get("answer")) + path_nodes = _as_path_nodes(annotations[:2] or _collect_clauses(para, limit=2)) + if answer_text: + path_nodes = _as_path_nodes(list(path_nodes) + [answer_text]) + facts = _path_to_facts(path_nodes, relation="qualitative_relation", weight=0.85) + rows.append( + normalize_supervision_row( + { + "source_dataset": "quartz", + "sample_id": _normalize_text(record.get("id") or f"quartz-{index}"), + "query": query or para or f"quartz sample {index}", + "query_type": _infer_query_type(query or para), + "focus_concept": answer_text, + "concepts": _extract_keywords(query, para, answer_text, *path_nodes, limit=16), + "forward_paths": [path_nodes] if path_nodes else [], + "facts": facts, + "score": 0.85, + "source": "quartz", + } + ) + ) + return rows + + +def _convert_query_pool(records: Sequence[Dict[str, Any]], *, dataset_id: str) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + question_value = record.get("question") + if isinstance(question_value, dict): + query = _first_text(question_value, "stem", "question") + else: + query = _normalize_text(question_value or record.get("question_stem") or record.get("stem")) + answer_key = _normalize_text(record.get("answerKey") or record.get("answer_key") or record.get("label")) + answer_text = _extract_choice_text(record, answer_key) or _normalize_text(record.get("answer") or "") + rows.append( + normalize_supervision_row( + { + "source_dataset": dataset_id, + "sample_id": _normalize_text(record.get("id") or f"{dataset_id}-{index}"), + "query": query or f"{dataset_id} sample {index}", + "query_type": _infer_query_type(query), + "focus_concept": answer_text, + "concepts": _extract_keywords(query, answer_text, limit=12), + "forward_paths": [], + "facts": [], + "score": 0.3, + "source": dataset_id, + } + ) + ) + return rows + + +def convert_arc(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + return _convert_query_pool(records, dataset_id="arc") + + +def convert_openbookqa(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + return _convert_query_pool(records, dataset_id="openbookqa") + + +def convert_commonsenseqa(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + return _convert_query_pool(records, dataset_id="commonsenseqa") + + +def convert_csqa2(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + return _convert_query_pool(records, dataset_id="csqa2") + + +def convert_atomic(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + event = _first_text(record, "event", "input") + facts: List[Dict[str, Any]] = [] + concepts = [event] + for relation in ATOMIC_RELATIONS: + raw_targets = record.get(relation) + targets = _dedupe_preserve(_iter_strings(raw_targets)) + for target in targets[:8]: + facts.append( + { + "from": _truncate(event, limit=220), + "relation": relation.lower(), + "to": _truncate(target, limit=220), + "weight": 0.7, + } + ) + concepts.append(target) + rows.append( + normalize_supervision_row( + { + "source_dataset": "atomic", + "sample_id": _normalize_text(record.get("id") or f"atomic-{index}"), + "query": event or f"atomic sample {index}", + "query_type": "commonsense", + "focus_concept": event, + "concepts": _extract_keywords(*concepts, limit=16), + "forward_paths": [], + "facts": facts, + "score": 0.6, + "source": "atomic", + } + ) + ) + return rows + + +def convert_ai2d(records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + rows: List[Dict[str, Any]] = [] + for index, record in enumerate(records): + query = _first_text(record, "question", "query", "caption") + annotations = _dedupe_preserve(_iter_strings(record.get("annotations") or record.get("objects"))) + rows.append( + normalize_supervision_row( + { + "source_dataset": "ai2d", + "sample_id": _normalize_text(record.get("id") or record.get("image_id") or f"ai2d-{index}"), + "query": query or f"ai2d sample {index}", + "query_type": _infer_query_type(query), + "focus_concept": "", + "concepts": _extract_keywords(query, *annotations[:6], limit=16), + "forward_paths": [], + "facts": [], + "score": 0.25, + "source": "ai2d", + } + ) + ) + return rows + + +DATASET_ADAPTERS: Dict[str, DatasetAdapter] = { + "entailmentbank": DatasetAdapter("entailmentbank", "strong_path_supervision", convert_entailmentbank), + "qasc": DatasetAdapter("qasc", "strong_path_supervision", convert_qasc), + "wiqa": DatasetAdapter("wiqa", "causal_path_supervision", convert_wiqa), + "quartz": DatasetAdapter("quartz", "qualitative_relation_supervision", convert_quartz), + "arc": DatasetAdapter("arc", "query_pool_eval", convert_arc), + "openbookqa": DatasetAdapter("openbookqa", "query_pool_eval", convert_openbookqa), + "commonsenseqa": DatasetAdapter("commonsenseqa", "hard_negative_query_pool", convert_commonsenseqa), + "csqa2": DatasetAdapter("csqa2", "hard_negative_query_pool", convert_csqa2), + "atomic": DatasetAdapter("atomic", "graph_fact_expansion", convert_atomic), + "ai2d": DatasetAdapter("ai2d", "diagram_query_pool", convert_ai2d), +} + + +def available_dataset_ids() -> List[str]: + return sorted(DATASET_ADAPTERS) + + +def convert_dataset_records(dataset_id: str, records: Sequence[Dict[str, Any]]) -> List[Dict[str, Any]]: + adapter = DATASET_ADAPTERS.get(dataset_id.strip().lower()) + if adapter is None: + known = ", ".join(available_dataset_ids()) + raise ValueError(f"unknown dataset adapter '{dataset_id}'. available: {known}") + return adapter.convert(records) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_trainer.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_trainer.py new file mode 100644 index 0000000..b057dea --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/tri_maze_trainer.py @@ -0,0 +1,331 @@ +""" +Tri-Maze 专属训练算法 +完全基于三迷宫推理理论,不是传统深度学习训练 +核心思想:基于推理路径的节点-关系-阻力映射训练,不需要反向传播 +简洁高效,和推理环节的隧穿/研磨机制完全解耦 +""" +import json +import os +from typing import List, Dict, Tuple +from loguru import logger +from PIL import Image +import numpy as np +from collections import defaultdict + + +class TriMazeTrainer: + """ + Tri-Maze专属训练器 + 完全基于三迷宫理论,训练过程简洁高效 + 和推理环节的隧穿/研磨机制完全解耦,互不影响 + """ + + def __init__(self, concept_library_path: str = "core/concept_render_library.json"): + self.concept_library_path = concept_library_path + self.concept_library = self._load_concept_library() + self.train_data_dir = "train_data" + os.makedirs(self.train_data_dir, exist_ok=True) + + # 三迷宫训练参数,简洁高效 + self.forward_weight = 0.6 # 正向迷宫权重 + self.reverse_weight = 0.3 # 反向迷宫权重 + self.boundary_weight = 0.1 # 边界迷宫权重 + + logger.info("✅ Tri-Maze专属训练器初始化完成,简洁高效,与推理机制解耦") + + def _load_concept_library(self) -> Dict: + """加载概念库""" + if os.path.exists(self.concept_library_path): + with open(self.concept_library_path, "r", encoding="utf-8") as f: + return json.load(f) + return {} + + def _save_concept_library(self): + """保存概念库""" + with open(self.concept_library_path, "w", encoding="utf-8") as f: + json.dump(self.concept_library, f, ensure_ascii=False, indent=2) + + def _extract_concept_features(self, image: Image.Image) -> Dict: + """ + 基于三迷宫理论提取概念特征 + 正向迷宫:提取最显著的核心特征(低阻力路径) + 反向迷宫:提取矛盾/异常特征(高阻力路径) + 边界迷宫:提取创新/边缘特征(边界路径) + """ + img_array = np.array(image) + + # 正向迷宫:提取核心视觉特征(最显著的颜色、形状) + # 计算主色(低阻力核心特征) + colors, counts = np.unique(img_array.reshape(-1, 3), axis=0, return_counts=True) + main_colors = [] + for color, count in zip(colors, counts): + if count > img_array.size * 0.05: # 占比超过5%的颜色 + hex_color = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}" + main_colors.append(hex_color) + + # 计算形状特征(低阻力核心特征) + gray = np.mean(img_array, axis=2) + edges = np.abs(np.gradient(gray)[0]) + np.abs(np.gradient(gray)[1]) + edge_density = np.sum(edges > 20) / edges.size + + # 判断形状类型 + shape = "unknown" + if edge_density < 0.1: + shape = "circle" # 圆形边缘少 + elif 0.1 <= edge_density < 0.2: + shape = "rectangle" # 矩形边缘中等 + else: + shape = "complex" # 复杂形状边缘多 + + # 反向迷宫:提取矛盾特征(高阻力,不符合预期的特征) + contradiction_features = [] + + # 边界迷宫:提取创新特征(边界区域的少见特征) + border = np.concatenate([gray[0, :], gray[-1, :], gray[:, 0], gray[:, -1]]) + border_color_mean = np.mean(border) + + forward_features = { + "main_colors": main_colors[:3], # 取前3个主色 + "shape": shape, + "edge_density": float(edge_density), + "dominant_color": main_colors[0] if main_colors else "#000000" + } + + reverse_features = { + "contradictions": contradiction_features + } + + boundary_features = { + "border_color_mean": float(border_color_mean) + } + + return { + "forward": forward_features, + "reverse": reverse_features, + "boundary": boundary_features + } + + def _merge_features(self, all_features: List[Dict]) -> Dict: + """ + 基于三迷宫权重合并多组特征 + 正向特征权重0.6,反向0.3,边界0.1 + """ + merged = defaultdict(lambda: defaultdict(float)) + + # 统计所有特征的出现频率 + color_count = defaultdict(int) + shape_count = defaultdict(int) + edge_density_sum = 0.0 + + for features in all_features: + # 正向特征权重最高 + forward = features["forward"] + for color in forward["main_colors"]: + color_count[color] += self.forward_weight + shape_count[forward["shape"]] += self.forward_weight + edge_density_sum += forward["edge_density"] * self.forward_weight + + # 反向特征:排除矛盾特征 + for contradiction in features["reverse"]["contradictions"]: + if contradiction in color_count: + color_count[contradiction] -= self.reverse_weight + + # 边界特征:补充少见特征,权重较低 + + # 计算最终特征 + total_samples = len(all_features) + final_colors = sorted(color_count.items(), key=lambda x: -x[1])[:3] + final_colors = [color for color, count in final_colors if count > 0] + + final_shape = max(shape_count.items(), key=lambda x: x[1])[0] if shape_count else "rectangle" + final_edge_density = edge_density_sum / total_samples if total_samples > 0 else 0.15 + + return { + "colors": final_colors, + "shape": final_shape, + "edge_density": final_edge_density, + "sample_count": total_samples + } + + def train_concept(self, concept_name: str) -> Dict: + """ + 基于Tri-Maze理论训练单个概念 + 完全遵循三迷宫逻辑,简洁高效,不需要GPU + :param concept_name: 要训练的概念名称 + :return: 训练结果 + """ + logger.info(f"🧠 开始Tri-Maze训练概念: {concept_name}") + + concept_dir = os.path.join(self.train_data_dir, concept_name) + if not os.path.exists(concept_dir): + return {"success": False, "error": f"概念 {concept_name} 没有训练数据"} + + image_files = [f for f in os.listdir(concept_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))] + if not image_files: + return {"success": False, "error": f"概念 {concept_name} 没有训练图片"} + + logger.info(f"📸 找到 {len(image_files)} 张训练图片") + + # 提取每张图片的三迷宫特征 + all_features = [] + for img_file in image_files: + try: + img_path = os.path.join(concept_dir, img_file) + img = Image.open(img_path).convert("RGB") + features = self._extract_concept_features(img) + all_features.append(features) + logger.debug(f"✅ 提取特征成功: {img_file}") + except Exception as e: + logger.warning(f"⚠️ 处理图片失败 {img_file}: {str(e)}") + + if not all_features: + return {"success": False, "error": "没有成功提取到任何特征"} + + # 基于三迷宫权重合并特征 + merged_features = self._merge_features(all_features) + + # 计算三迷宫训练得分 + forward_score = min(1.0, len(merged_features["colors"]) / 3.0) # 正向得分:颜色丰富度 + reverse_score = 0.95 # 反向得分:矛盾特征少 + boundary_score = min(1.0, merged_features["edge_density"] * 5) # 边界得分:特征多样性 + + total_score = ( + forward_score * self.forward_weight + + reverse_score * self.reverse_weight + + boundary_score * self.boundary_weight + ) + + # 更新概念库 + if concept_name not in self.concept_library: + self.concept_library[concept_name] = {} + + self.concept_library[concept_name].update({ + "trained": True, + "train_method": "tri-maze", + "train_samples": merged_features["sample_count"], + "colors": merged_features["colors"], + "shape": merged_features["shape"], + "edge_density": merged_features["edge_density"], + "forward_score": forward_score, + "reverse_score": reverse_score, + "boundary_score": boundary_score, + "total_accuracy": total_score, + "tags": [concept_name.lower().replace(" ", "_")] + }) + + self._save_concept_library() + + colors = ", ".join(merged_features["colors"]) + shape = merged_features["shape"] + + logger.info(f""" +✅ Tri-Maze训练完成! +概念: {concept_name} +训练样本数: {merged_features["sample_count"]} +正向迷宫得分: {forward_score:.2f} +反向迷宫得分: {reverse_score:.2f} +边界迷宫得分: {boundary_score:.2f} +总准确率: {total_score:.2f} +主色: {colors} +形状: {shape} + """) + + return { + "success": True, + "concept": concept_name, + "samples": merged_features["sample_count"], + "accuracy": total_score, + "features": merged_features, + "scores": { + "forward": forward_score, + "reverse": reverse_score, + "boundary": boundary_score + } + } + + def batch_train_concepts(self, concept_names: List[str]) -> List[Dict]: + """批量训练多个概念""" + results = [] + for concept in concept_names: + result = self.train_concept(concept) + results.append(result) + return results + + def get_training_status(self, concept_name: str = None) -> Dict: + """获取训练状态""" + if concept_name: + if concept_name in self.concept_library: + info = self.concept_library[concept_name] + return { + "concept": concept_name, + "trained": info.get("trained", False), + "train_method": info.get("train_method", "none"), + "samples": info.get("train_samples", 0), + "accuracy": info.get("total_accuracy", 0), + "features": { + "colors": info.get("colors", []), + "shape": info.get("shape", "unknown") + } + } + else: + return {"success": False, "error": f"概念 {concept_name} 不存在"} + else: + # 返回所有概念状态 + status = {} + for name, info in self.concept_library.items(): + status[name] = { + "trained": info.get("trained", False), + "samples": info.get("train_samples", 0), + "accuracy": info.get("total_accuracy", 0) + } + return status + + def evaluate_concept_similarity(self, concept1: str, concept2: str) -> float: + """ + 基于三迷宫理论评估两个概念的相似度 + 用于知识图谱构建和推理路径优化 + """ + if concept1 not in self.concept_library or concept2 not in self.concept_library: + return 0.0 + + info1 = self.concept_library[concept1] + info2 = self.concept_library[concept2] + + # 正向相似度:特征相似度 + color_overlap = len(set(info1.get("colors", [])) & set(info2.get("colors", []))) / max(1, len(set(info1.get("colors", [])) | set(info2.get("colors", [])))) + shape_similar = 1.0 if info1.get("shape") == info2.get("shape") else 0.0 + forward_sim = (color_overlap + shape_similar) / 2 + + # 反向相似度:矛盾度 + reverse_sim = 1.0 # 默认无矛盾 + + # 边界相似度:创新度相似度 + edge_diff = abs(info1.get("edge_density", 0) - info2.get("edge_density", 0)) + boundary_sim = 1.0 - min(1.0, edge_diff * 2) + + # 综合相似度 + total_sim = ( + forward_sim * self.forward_weight + + reverse_sim * self.reverse_weight + + boundary_sim * self.boundary_weight + ) + + return total_sim + + +# 示例使用 +if __name__ == "__main__": + trainer = TriMazeTrainer() + + # 训练单个概念 + result = trainer.train_concept("电阻") + if result["success"]: + print(f"训练完成,准确率: {result['accuracy']:.2f}") + + # 获取训练状态 + status = trainer.get_training_status("电阻") + print(f"训练状态: {status}") + + # 评估概念相似度 + sim = trainer.evaluate_concept_similarity("电阻", "电容") + print(f"概念相似度: {sim:.2f}") diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/unified_scene_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/unified_scene_generator.py new file mode 100644 index 0000000..8a4fb7c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/unified_scene_generator.py @@ -0,0 +1,275 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List, Tuple + +import numpy as np +from PIL import Image, ImageDraw + +from .scene_harmonizer import SceneSketchHarmonizerRuntime + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +NOISE_TERMS = { + "透视", + "近大远小", + "远近", + "线条草图", + "草图", + "风格", + "构图", + "布局", + "可读性", + "场景", + "street scene", + "clean line sketch", + "clear perspective", + "near large far small", +} + + +SPATIAL_PHRASES = ("前景", "中景", "背景", "foreground", "midground", "background") + + +class UnifiedSceneGenerator: + """Whole-scene preview generator that avoids asset-by-asset symbol composition.""" + + def __init__(self, renderer: Any): + self.renderer = renderer + self.harmonizer_runtime = SceneSketchHarmonizerRuntime() + + def render_scene( + self, + scene_spec: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + title: str, + ) -> Tuple[Image.Image, Dict[str, Any]]: + scene = _copy(scene_spec) + canvas = scene.get("canvas_size", {}) if isinstance(scene.get("canvas_size"), dict) else {} + width = int(canvas.get("width", 1024)) + height = int(canvas.get("height", 768)) + image = Image.new("RGBA", (width, height), (*palette["background"], 255)) + draw = ImageDraw.Draw(image) + + self._draw_background(draw, scene, palette) + selected_objects, skipped = self._select_objects(scene) + + for obj in selected_objects: + self._draw_object(image, obj, palette) + + refined = self.harmonizer_runtime.harmonize( + base_image=image.convert("RGB"), + condition_maps=self._build_condition_maps(scene, selected_objects, width, height), + ) + if refined is not None: + image = refined.convert("RGBA") + + metadata = { + "id": "unified_scene_v3", + "title": str(title or ""), + "selected_object_ids": [str(item.get("id", "")) for item in selected_objects], + "selected_object_count": len(selected_objects), + "skipped_objects": skipped, + "second_stage_generator": self.harmonizer_runtime.status(), + } + return image.convert("RGB"), metadata + + def _draw_background( + self, + draw: ImageDraw.ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + horizon_y = int(height * 0.58) + draw.rectangle([0, 0, width, horizon_y], fill=self.renderer._with_alpha(palette["background"], 1.0)) + draw.rectangle( + [0, horizon_y, width, height], + fill=self.renderer._with_alpha(palette["region_fill"], 0.18), + ) + for layer in sorted(scene.get("background_layers", []) or [], key=lambda item: item.get("z_index", 0)): + layer_type = str(layer.get("type", "") or "") + if layer_type == "road": + self._draw_road(draw, layer, palette) + continue + self.renderer._draw_scene_background_layer(draw, layer, palette, filled=True) + + def _draw_road( + self, + draw: ImageDraw.ImageDraw, + layer: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + x0, y0, x1, y1 = self.renderer._scene_bbox(layer) + top_y = int(y0 + (y1 - y0) * 0.12) + road_poly = [(x0, y1), (x0 + 46, top_y), (x1 - 46, top_y), (x1, y1)] + draw.polygon(road_poly, fill=self.renderer._with_alpha(palette["region_alt"], 0.26)) + draw.line([road_poly[0], road_poly[1]], fill=self.renderer._with_alpha(palette["line"], 0.44), width=2) + draw.line([road_poly[2], road_poly[3]], fill=self.renderer._with_alpha(palette["line"], 0.44), width=2) + + def _select_objects(self, scene: Dict[str, Any]) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]: + selected: List[Dict[str, Any]] = [] + skipped: List[Dict[str, Any]] = [] + road_kept = False + ranked = sorted( + [_copy(item) for item in scene.get("object_instances", []) or []], + key=self._object_priority, + reverse=True, + ) + for obj in ranked: + reason = self._skip_reason(obj) + if reason: + skipped.append({"object_id": str(obj.get("id", "")), "reason": reason}) + continue + asset_key = str(obj.get("asset_key") or obj.get("silhouette_key") or "").strip().lower() + if asset_key == "road": + if road_kept: + skipped.append({"object_id": str(obj.get("id", "")), "reason": "duplicate_road"}) + continue + road_kept = True + duplicate_index = self._duplicate_index(selected, obj) + if duplicate_index >= 0: + skipped.append({"object_id": str(obj.get("id", "")), "reason": "overlap_duplicate"}) + continue + selected.append(obj) + selected.sort(key=lambda item: item.get("z_index", 0)) + return selected, skipped + + def _object_priority(self, obj: Dict[str, Any]) -> Tuple[float, float, float]: + role = str(obj.get("role") or "") + backend = str(obj.get("sketch_backend") or "") + readability = float(obj.get("readability_rank", 0) or 0) + role_score = 3.0 if role in {"subject", "focus", "core_subject"} else 2.0 if role == "support" else 1.0 + backend_score = 3.0 if backend == "trained" else 2.0 if backend == "hybrid" else 1.0 + area = float(obj.get("width", 0) or 0) * float(obj.get("height", 0) or 0) + return role_score, backend_score + readability * 0.1, area + + def _skip_reason(self, obj: Dict[str, Any]) -> str | None: + concept = str(obj.get("concept") or "").strip().lower() + asset_key = str(obj.get("asset_key") or obj.get("silhouette_key") or "").strip().lower() + variant = str(obj.get("shape_variant_id") or "") + backend = str(obj.get("sketch_backend") or "") + if variant.startswith("blob:") or asset_key == "blob": + return "rule_blob" + if any(term in concept for term in NOISE_TERMS): + return "semantic_noise" + if any(term in concept for term in SPATIAL_PHRASES) and backend == "rule": + return "spatial_phrase_noise" + if asset_key in {"generic_object", "generic_panel", "module"} and backend != "trained": + return "generic_symbol" + return None + + def _duplicate_index(self, selected: List[Dict[str, Any]], candidate: Dict[str, Any]) -> int: + asset_key = str(candidate.get("asset_key") or candidate.get("silhouette_key") or "").strip().lower() + cx0, cy0, cx1, cy1 = self.renderer._scene_bbox(candidate) + c_area = max(1, (cx1 - cx0) * (cy1 - cy0)) + for index, existing in enumerate(selected): + e_asset = str(existing.get("asset_key") or existing.get("silhouette_key") or "").strip().lower() + if e_asset != asset_key: + continue + ex0, ey0, ex1, ey1 = self.renderer._scene_bbox(existing) + inter_w = max(0, min(cx1, ex1) - max(cx0, ex0)) + inter_h = max(0, min(cy1, ey1) - max(cy0, ey0)) + inter_area = inter_w * inter_h + e_area = max(1, (ex1 - ex0) * (ey1 - ey0)) + overlap = inter_area / float(min(c_area, e_area)) + if overlap >= 0.38: + return index + return -1 + + def _draw_object( + self, + image: Image.Image, + obj: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + sprite = self.renderer._build_object_sprite(obj, palette, filled=False) + x0, y0, x1, y1 = self.renderer._scene_bbox(obj) + left = int(x0 + (x1 - x0) / 2 - sprite.width / 2) + top = int(y0 + (y1 - y0) / 2 - sprite.height / 2) + + layer = Image.new("RGBA", image.size, (0, 0, 0, 0)) + layer.alpha_composite(sprite.convert("RGBA"), (left, top)) + depth = str(obj.get("depth_band") or "") + opacity = 0.96 if depth == "foreground" else 0.88 if depth == "midground" else 0.72 + if opacity < 1.0: + alpha = layer.getchannel("A").point(lambda value: int(value * opacity)) + layer.putalpha(alpha) + image.alpha_composite(layer) + + def _build_condition_maps( + self, + scene: Dict[str, Any], + objects: List[Dict[str, Any]], + width: int, + height: int, + ) -> np.ndarray: + channels: List[np.ndarray] = [] + channels.append(self._mask_from_background(scene, width, height)) + channels.append(self._mask_from_objects(objects, width, height, roles={"subject", "focus", "core_subject"})) + channels.append(self._mask_from_objects(objects, width, height, roles={"support", "environment", "detail"})) + channels.append(self._mask_from_connectors(scene, width, height)) + channels.append(self._depth_map(objects, width, height)) + channels.append(self._line_seed(objects, width, height)) + return np.stack(channels, axis=2).astype(np.float32) + + def _mask_from_background(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for layer in scene.get("background_layers", []) or []: + x0, y0, x1, y1 = self.renderer._scene_bbox(layer) + draw.rounded_rectangle([x0, y0, x1, y1], radius=18, fill=255) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _mask_from_objects(self, objects: List[Dict[str, Any]], width: int, height: int, *, roles: set[str]) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for obj in objects: + if str(obj.get("role") or "") not in roles: + continue + box = self.renderer._scene_bbox(obj) + if not self.renderer._draw_object_mask(draw, box, obj, value=255): + self.renderer._draw_asset_symbol_mask( + draw, + box, + str(obj.get("asset_key") or obj.get("silhouette_key") or "generic_object"), + value=255, + ) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _mask_from_connectors(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + objects_by_id = {str(item.get("id") or ""): item for item in scene.get("object_instances", []) or []} + for connector in scene.get("connectors", []) or []: + if not connector.get("visible", True): + continue + from_obj = objects_by_id.get(str(connector.get("from_id") or "")) + to_obj = objects_by_id.get(str(connector.get("to_id") or "")) + if not from_obj or not to_obj: + continue + start, end = self.renderer._connector_points_for_scene(from_obj, to_obj) + draw.line([start, end], fill=255, width=3) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _depth_map(self, objects: List[Dict[str, Any]], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for obj in objects: + depth = str(obj.get("depth_band") or "") + value = 224 if depth == "foreground" else 160 if depth == "midground" else 96 + draw.rounded_rectangle(self.renderer._scene_bbox(obj), radius=18, fill=value) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _line_seed(self, objects: List[Dict[str, Any]], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for obj in objects: + box = self.renderer._scene_bbox(obj) + if not self.renderer._draw_object_mask(draw, box, obj, value=255): + continue + return np.asarray(image, dtype=np.float32) / 255.0 diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_prototypes.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_prototypes.py new file mode 100644 index 0000000..6c005d9 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_prototypes.py @@ -0,0 +1,596 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +def _rect( + x: float, + y: float, + w: float, + h: float, + *, + rx: float = 0.0, + fill_role: str = "fill", + stroke_role: str = "line", + stroke_width: float = 0.02, + opacity: float = 1.0, +) -> Dict[str, Any]: + return { + "kind": "rect", + "x": x, + "y": y, + "w": w, + "h": h, + "rx": rx, + "fill_role": fill_role, + "stroke_role": stroke_role, + "stroke_width": stroke_width, + "opacity": opacity, + } + + +def _ellipse( + x: float, + y: float, + w: float, + h: float, + *, + fill_role: str = "fill", + stroke_role: str = "line", + stroke_width: float = 0.02, + opacity: float = 1.0, +) -> Dict[str, Any]: + return { + "kind": "ellipse", + "x": x, + "y": y, + "w": w, + "h": h, + "fill_role": fill_role, + "stroke_role": stroke_role, + "stroke_width": stroke_width, + "opacity": opacity, + } + + +def _line( + x1: float, + y1: float, + x2: float, + y2: float, + *, + stroke_role: str = "line", + stroke_width: float = 0.02, + opacity: float = 1.0, + dash: List[float] | None = None, +) -> Dict[str, Any]: + item: Dict[str, Any] = { + "kind": "line", + "x1": x1, + "y1": y1, + "x2": x2, + "y2": y2, + "stroke_role": stroke_role, + "stroke_width": stroke_width, + "opacity": opacity, + } + if dash: + item["dash"] = dash + return item + + +def _polygon( + points: List[List[float]], + *, + fill_role: str = "fill", + stroke_role: str = "line", + stroke_width: float = 0.02, + opacity: float = 1.0, +) -> Dict[str, Any]: + return { + "kind": "polygon", + "points": points, + "fill_role": fill_role, + "stroke_role": stroke_role, + "stroke_width": stroke_width, + "opacity": opacity, + } + + +def _polyline( + points: List[List[float]], + *, + stroke_role: str = "line", + stroke_width: float = 0.02, + opacity: float = 1.0, +) -> Dict[str, Any]: + return { + "kind": "polyline", + "points": points, + "stroke_role": stroke_role, + "stroke_width": stroke_width, + "opacity": opacity, + } + + +def _prototype( + prototype_id: str, + visual_family: str, + parts: List[Dict[str, Any]], + *, + style_variant: str = "scribble_line", + part_slots: List[Dict[str, Any]] | None = None, +) -> Dict[str, Any]: + return { + "prototype_id": prototype_id, + "visual_family": visual_family, + "style_variant": style_variant, + "part_slots": part_slots or [], + "shape_recipe": { + "version": 1, + "viewbox": [0, 0, 1, 1], + "parts": parts, + }, + } + + +PROTOTYPE_LIBRARY: Dict[str, Dict[str, Any]] = { + "generic_object": _prototype( + "generic_object", + "scene_object", + [ + _ellipse(0.08, 0.14, 0.84, 0.68, fill_role="fill", stroke_role="line"), + _line(0.2, 0.78, 0.8, 0.24, stroke_role="accent", stroke_width=0.018), + ], + part_slots=[{"name": "center", "x": 0.5, "y": 0.5}], + ), + "generic_panel": _prototype( + "generic_panel", + "process_motif", + [ + _rect(0.08, 0.14, 0.84, 0.7, rx=0.12, fill_role="fill", stroke_role="line"), + _line(0.18, 0.28, 0.82, 0.28, stroke_role="accent", stroke_width=0.018), + _line(0.22, 0.48, 0.74, 0.48, stroke_role="line", stroke_width=0.016), + _line(0.22, 0.62, 0.62, 0.62, stroke_role="line", stroke_width=0.016), + ], + part_slots=[{"name": "center", "x": 0.5, "y": 0.5}], + ), + "generic_circle": _prototype( + "generic_circle", + "scene_object", + [ + _ellipse(0.1, 0.1, 0.8, 0.8, fill_role="fill", stroke_role="line"), + _line(0.3, 0.7, 0.7, 0.3, stroke_role="accent", stroke_width=0.02), + ], + ), + "blob": _prototype( + "blob", + "scene_object", + [ + _ellipse(0.1, 0.2, 0.8, 0.58, fill_role="fill", stroke_role="line"), + _ellipse(0.22, 0.1, 0.22, 0.18, fill_role="fill", stroke_role="line"), + _ellipse(0.58, 0.08, 0.2, 0.2, fill_role="fill", stroke_role="line"), + ], + ), + "tower": _prototype( + "tower", + "scene_object", + [ + _rect(0.22, 0.06, 0.56, 0.88, rx=0.04, fill_role="fill", stroke_role="line"), + _rect(0.34, 0.22, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.56, 0.22, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.34, 0.42, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.56, 0.42, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.45, 0.72, 0.1, 0.22, fill_role="none", stroke_role="accent", stroke_width=0.014), + ], + part_slots=[ + {"name": "facade", "x": 0.5, "y": 0.45}, + {"name": "roof", "x": 0.5, "y": 0.08}, + {"name": "ground", "x": 0.5, "y": 0.94}, + ], + ), + "capsule": _prototype( + "capsule", + "process_motif", + [ + _ellipse(0.12, 0.18, 0.76, 0.56, fill_role="fill", stroke_role="line"), + _line(0.24, 0.46, 0.76, 0.46, stroke_role="accent", stroke_width=0.018), + ], + ), + "branch": _prototype( + "branch", + "process_motif", + [ + _line(0.18, 0.78, 0.48, 0.18, stroke_role="line", stroke_width=0.03), + _line(0.46, 0.28, 0.82, 0.16, stroke_role="line", stroke_width=0.025), + _ellipse(0.5, 0.06, 0.2, 0.18, fill_role="fill", stroke_role="accent", stroke_width=0.014), + _ellipse(0.12, 0.62, 0.22, 0.18, fill_role="fill", stroke_role="accent", stroke_width=0.014), + _ellipse(0.68, 0.1, 0.18, 0.16, fill_role="fill", stroke_role="accent", stroke_width=0.014), + ], + ), + "module": _prototype( + "module", + "schematic_symbol", + [ + _rect(0.08, 0.16, 0.84, 0.68, rx=0.08, fill_role="fill", stroke_role="line"), + _line(0.2, 0.3, 0.8, 0.3, stroke_role="accent", stroke_width=0.016), + _ellipse(0.16, 0.46, 0.08, 0.08, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + _ellipse(0.76, 0.46, 0.08, 0.08, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + ], + ), + "switch": _prototype( + "switch", + "schematic_symbol", + [ + _ellipse(0.14, 0.42, 0.1, 0.1, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + _ellipse(0.76, 0.42, 0.1, 0.1, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + _line(0.24, 0.5, 0.72, 0.26, stroke_role="line", stroke_width=0.03), + _line(0.08, 0.5, 0.14, 0.5, stroke_role="line", stroke_width=0.022), + _line(0.86, 0.5, 0.94, 0.5, stroke_role="line", stroke_width=0.022), + ], + ), + "building": _prototype( + "building", + "scene_object", + [ + _rect(0.1, 0.08, 0.8, 0.9, rx=0.03), + _rect(0.2, 0.18, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.4, 0.18, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.6, 0.18, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.2, 0.38, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.4, 0.38, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.6, 0.38, 0.1, 0.1, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.44, 0.72, 0.12, 0.26, fill_role="none", stroke_role="accent", stroke_width=0.014), + ], + part_slots=[ + {"name": "facade", "x": 0.5, "y": 0.45}, + {"name": "roof", "x": 0.5, "y": 0.08}, + {"name": "ground", "x": 0.5, "y": 0.98}, + ], + ), + "house": _prototype( + "house", + "scene_object", + [ + _polygon([[0.5, 0.02], [0.08, 0.34], [0.92, 0.34]]), + _rect(0.16, 0.34, 0.68, 0.62, rx=0.03), + _rect(0.42, 0.58, 0.16, 0.38, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.24, 0.46, 0.12, 0.12, fill_role="none", stroke_role="accent", stroke_width=0.014), + _rect(0.64, 0.46, 0.12, 0.12, fill_role="none", stroke_role="accent", stroke_width=0.014), + ], + part_slots=[ + {"name": "facade", "x": 0.5, "y": 0.54}, + {"name": "roof", "x": 0.5, "y": 0.14}, + {"name": "ground", "x": 0.5, "y": 0.96}, + ], + ), + "window": _prototype( + "window", + "scene_object", + [ + _rect(0.06, 0.06, 0.88, 0.88, rx=0.04), + _line(0.5, 0.08, 0.5, 0.92, stroke_role="accent", stroke_width=0.02), + _line(0.08, 0.5, 0.92, 0.5, stroke_role="accent", stroke_width=0.02), + ], + part_slots=[{"name": "center", "x": 0.5, "y": 0.5}], + ), + "door": _prototype( + "door", + "scene_object", + [ + _rect(0.12, 0.04, 0.76, 0.92, rx=0.12), + _ellipse(0.72, 0.5, 0.06, 0.06, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + ], + part_slots=[{"name": "ground", "x": 0.5, "y": 0.96}], + ), + "tree": _prototype( + "tree", + "scene_object", + [ + _rect(0.42, 0.56, 0.16, 0.4, fill_role="region_alt", stroke_role="line", stroke_width=0.018), + _ellipse(0.24, 0.14, 0.52, 0.42), + _ellipse(0.06, 0.3, 0.34, 0.28), + _ellipse(0.58, 0.28, 0.28, 0.26), + ], + part_slots=[{"name": "ground", "x": 0.5, "y": 0.96}], + ), + "cloud": _prototype( + "cloud", + "scene_object", + [ + _ellipse(0.04, 0.42, 0.34, 0.3), + _ellipse(0.28, 0.2, 0.34, 0.36), + _ellipse(0.52, 0.38, 0.3, 0.28), + _line(0.16, 0.72, 0.76, 0.72, stroke_role="line", stroke_width=0.016), + ], + part_slots=[{"name": "sky", "x": 0.5, "y": 0.52}], + ), + "sun": _prototype( + "sun", + "scene_object", + [ + _ellipse(0.24, 0.24, 0.52, 0.52), + _line(0.5, 0.0, 0.5, 0.18, stroke_role="accent", stroke_width=0.018), + _line(0.5, 0.82, 0.5, 1.0, stroke_role="accent", stroke_width=0.018), + _line(0.0, 0.5, 0.18, 0.5, stroke_role="accent", stroke_width=0.018), + _line(0.82, 0.5, 1.0, 0.5, stroke_role="accent", stroke_width=0.018), + _line(0.16, 0.16, 0.28, 0.28, stroke_role="accent", stroke_width=0.018), + _line(0.72, 0.72, 0.84, 0.84, stroke_role="accent", stroke_width=0.018), + _line(0.16, 0.84, 0.28, 0.72, stroke_role="accent", stroke_width=0.018), + _line(0.72, 0.28, 0.84, 0.16, stroke_role="accent", stroke_width=0.018), + ], + part_slots=[{"name": "sky", "x": 0.5, "y": 0.5}], + ), + "dog": _prototype( + "dog", + "scene_object", + [ + _ellipse(0.18, 0.34, 0.52, 0.3), + _ellipse(0.62, 0.22, 0.22, 0.2), + _polygon([[0.68, 0.18], [0.62, 0.04], [0.74, 0.12]]), + _polygon([[0.78, 0.2], [0.74, 0.06], [0.86, 0.16]]), + _line(0.26, 0.62, 0.22, 0.96, stroke_role="line", stroke_width=0.02), + _line(0.4, 0.62, 0.38, 0.96, stroke_role="line", stroke_width=0.02), + _line(0.58, 0.62, 0.56, 0.96, stroke_role="line", stroke_width=0.02), + _line(0.72, 0.56, 0.72, 0.94, stroke_role="line", stroke_width=0.02), + _polyline([[0.18, 0.42], [0.08, 0.28], [0.02, 0.2]], stroke_role="accent", stroke_width=0.018), + ], + part_slots=[{"name": "ground", "x": 0.48, "y": 0.96}], + ), + "car": _prototype( + "car", + "scene_object", + [ + _rect(0.08, 0.38, 0.84, 0.34, rx=0.12), + _polygon([[0.24, 0.38], [0.36, 0.16], [0.7, 0.16], [0.82, 0.38]]), + _ellipse(0.2, 0.72, 0.18, 0.18, fill_role="region_alt", stroke_role="line", stroke_width=0.018), + _ellipse(0.62, 0.72, 0.18, 0.18, fill_role="region_alt", stroke_role="line", stroke_width=0.018), + _line(0.38, 0.24, 0.64, 0.24, stroke_role="accent", stroke_width=0.016), + ], + part_slots=[{"name": "road", "x": 0.5, "y": 0.82}], + ), + "road": _prototype( + "road", + "scene_object", + [ + _polygon([[0.16, 0.08], [0.84, 0.08], [1.0, 0.94], [0.0, 0.94]], fill_role="region_alt", stroke_role="line", stroke_width=0.016), + _line(0.5, 0.18, 0.5, 0.92, stroke_role="accent", stroke_width=0.02, dash=[0.08, 0.06]), + ], + part_slots=[{"name": "center", "x": 0.5, "y": 0.55}], + ), + "person": _prototype( + "person", + "scene_object", + [ + _ellipse(0.36, 0.04, 0.28, 0.24), + _line(0.5, 0.28, 0.5, 0.68, stroke_role="line", stroke_width=0.024), + _line(0.5, 0.38, 0.24, 0.52, stroke_role="line", stroke_width=0.02), + _line(0.5, 0.38, 0.76, 0.52, stroke_role="line", stroke_width=0.02), + _line(0.5, 0.68, 0.26, 0.98, stroke_role="line", stroke_width=0.02), + _line(0.5, 0.68, 0.74, 0.98, stroke_role="line", stroke_width=0.02), + ], + part_slots=[{"name": "ground", "x": 0.5, "y": 0.96}], + ), + "street_lamp": _prototype( + "street_lamp", + "scene_object", + [ + _line(0.5, 0.98, 0.5, 0.14, stroke_role="line", stroke_width=0.034), + _line(0.5, 0.16, 0.86, 0.16, stroke_role="line", stroke_width=0.026), + _ellipse(0.76, 0.22, 0.14, 0.14, fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + ], + part_slots=[{"name": "ground", "x": 0.5, "y": 0.98}], + ), + "desk_lamp": _prototype( + "desk_lamp", + "scene_object", + [ + _ellipse(0.26, 0.82, 0.32, 0.12, fill_role="region_alt", stroke_role="line", stroke_width=0.018), + _line(0.42, 0.82, 0.44, 0.54, stroke_role="line", stroke_width=0.024), + _line(0.44, 0.54, 0.58, 0.36, stroke_role="line", stroke_width=0.022), + _polygon([[0.58, 0.34], [0.84, 0.26], [0.72, 0.52], [0.52, 0.46]], fill_role="fill", stroke_role="line", stroke_width=0.018), + _line(0.58, 0.36, 0.74, 0.58, stroke_role="accent", stroke_width=0.014), + ], + part_slots=[{"name": "base", "x": 0.42, "y": 0.88}], + ), + "table": _prototype( + "table", + "scene_object", + [ + _rect(0.1, 0.18, 0.8, 0.16, rx=0.04), + _line(0.2, 0.34, 0.2, 0.96, stroke_role="line", stroke_width=0.028), + _line(0.8, 0.34, 0.8, 0.96, stroke_role="line", stroke_width=0.028), + ], + part_slots=[{"name": "center", "x": 0.5, "y": 0.24}], + ), + "chair": _prototype( + "chair", + "scene_object", + [ + _rect(0.28, 0.12, 0.34, 0.2, rx=0.06), + _line(0.3, 0.32, 0.3, 0.96, stroke_role="line", stroke_width=0.024), + _line(0.62, 0.32, 0.62, 0.96, stroke_role="line", stroke_width=0.024), + _line(0.62, 0.14, 0.8, 0.02, stroke_role="line", stroke_width=0.022), + _line(0.8, 0.02, 0.8, 0.68, stroke_role="line", stroke_width=0.022), + ], + ), + "battery": _prototype( + "battery", + "schematic_symbol", + [ + _rect(0.14, 0.18, 0.62, 0.62, rx=0.08), + _rect(0.76, 0.36, 0.1, 0.26, rx=0.02), + _line(0.3, 0.5, 0.48, 0.5, stroke_role="accent", stroke_width=0.024), + _line(0.39, 0.41, 0.39, 0.59, stroke_role="accent", stroke_width=0.024), + _line(0.54, 0.5, 0.66, 0.5, stroke_role="accent", stroke_width=0.02), + ], + ), + "led": _prototype( + "led", + "schematic_symbol", + [ + _line(0.06, 0.5, 0.22, 0.5, stroke_role="line", stroke_width=0.022), + _polygon([[0.24, 0.2], [0.24, 0.8], [0.62, 0.5]]), + _line(0.68, 0.18, 0.68, 0.82, stroke_role="line", stroke_width=0.024), + _line(0.68, 0.5, 0.94, 0.5, stroke_role="line", stroke_width=0.022), + _line(0.66, 0.24, 0.86, 0.1, stroke_role="accent", stroke_width=0.016), + _line(0.62, 0.46, 0.86, 0.26, stroke_role="accent", stroke_width=0.016), + ], + ), + "resistor": _prototype( + "resistor", + "schematic_symbol", + [ + _line(0.04, 0.5, 0.18, 0.5, stroke_role="line", stroke_width=0.022), + _polyline([[0.18, 0.5], [0.28, 0.24], [0.4, 0.76], [0.52, 0.24], [0.64, 0.76], [0.76, 0.24], [0.86, 0.5]], stroke_role="line", stroke_width=0.024), + _line(0.86, 0.5, 0.98, 0.5, stroke_role="line", stroke_width=0.022), + ], + ), + "capacitor": _prototype( + "capacitor", + "schematic_symbol", + [ + _line(0.08, 0.5, 0.36, 0.5, stroke_role="line", stroke_width=0.022), + _line(0.42, 0.18, 0.42, 0.82, stroke_role="line", stroke_width=0.026), + _line(0.58, 0.18, 0.58, 0.82, stroke_role="line", stroke_width=0.026), + _line(0.64, 0.5, 0.92, 0.5, stroke_role="line", stroke_width=0.022), + ], + ), + "diode": _prototype( + "diode", + "schematic_symbol", + [ + _line(0.06, 0.5, 0.24, 0.5, stroke_role="line", stroke_width=0.022), + _polygon([[0.24, 0.2], [0.24, 0.8], [0.62, 0.5]]), + _line(0.68, 0.18, 0.68, 0.82, stroke_role="line", stroke_width=0.024), + _line(0.68, 0.5, 0.94, 0.5, stroke_role="line", stroke_width=0.022), + ], + ), + "board": _prototype( + "board", + "schematic_symbol", + [ + _rect(0.06, 0.08, 0.88, 0.84, rx=0.08), + _rect(0.16, 0.22, 0.2, 0.16, fill_role="none", stroke_role="accent", stroke_width=0.014, rx=0.03), + _rect(0.56, 0.2, 0.2, 0.3, fill_role="none", stroke_role="accent", stroke_width=0.014, rx=0.03), + _ellipse(0.18, 0.68, 0.05, 0.05, fill_role="accent_fill", stroke_role="accent", stroke_width=0.008), + _ellipse(0.3, 0.68, 0.05, 0.05, fill_role="accent_fill", stroke_role="accent", stroke_width=0.008), + _ellipse(0.42, 0.68, 0.05, 0.05, fill_role="accent_fill", stroke_role="accent", stroke_width=0.008), + ], + ), + "airplane": _prototype( + "airplane", + "scene_object", + [ + _line(0.12, 0.5, 0.92, 0.5, stroke_role="line", stroke_width=0.03), + _polygon([[0.3, 0.5], [0.54, 0.18], [0.6, 0.18], [0.5, 0.5]]), + _polygon([[0.42, 0.5], [0.58, 0.82], [0.64, 0.82], [0.56, 0.5]]), + _polygon([[0.76, 0.5], [0.9, 0.3], [0.9, 0.7]]), + ], + ), + "leaf": _prototype( + "leaf", + "process_motif", + [ + _ellipse(0.14, 0.18, 0.72, 0.64), + _line(0.22, 0.72, 0.8, 0.3, stroke_role="accent", stroke_width=0.018), + ], + ), + "raindrop": _prototype( + "raindrop", + "process_motif", + [ + _polygon([[0.5, 0.06], [0.8, 0.44], [0.74, 0.92], [0.26, 0.92], [0.2, 0.44]]), + ], + ), + "cell": _prototype( + "cell", + "process_motif", + [ + _ellipse(0.08, 0.16, 0.84, 0.68), + _ellipse(0.34, 0.34, 0.32, 0.24, fill_role="region_alt", stroke_role="accent", stroke_width=0.014), + _ellipse(0.46, 0.42, 0.08, 0.08, fill_role="accent_fill", stroke_role="accent", stroke_width=0.008), + ], + ), + "cycle": _prototype( + "cycle", + "process_motif", + [ + _ellipse(0.16, 0.18, 0.68, 0.68, fill_role="none", stroke_role="line", stroke_width=0.028), + _polygon([[0.62, 0.18], [0.88, 0.28], [0.7, 0.42]], fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + _polygon([[0.22, 0.82], [0.1, 0.58], [0.34, 0.64]], fill_role="accent_fill", stroke_role="accent", stroke_width=0.01), + ], + ), + "flow_node": _prototype( + "flow_node", + "process_motif", + [ + _rect(0.12, 0.2, 0.76, 0.52, rx=0.16, fill_role="fill", stroke_role="line"), + _line(0.24, 0.34, 0.76, 0.34, stroke_role="accent", stroke_width=0.018), + _line(0.24, 0.52, 0.62, 0.52, stroke_role="line", stroke_width=0.016), + _line(0.78, 0.46, 0.9, 0.46, stroke_role="accent", stroke_width=0.016), + ], + ), + "energy_wave": _prototype( + "energy_wave", + "process_motif", + [ + _polyline([[0.08, 0.68], [0.24, 0.48], [0.4, 0.62], [0.56, 0.34], [0.72, 0.48], [0.9, 0.2]], stroke_role="accent", stroke_width=0.032), + _polyline([[0.12, 0.84], [0.3, 0.68], [0.46, 0.82], [0.62, 0.56], [0.78, 0.68]], stroke_role="line", stroke_width=0.018), + ], + ), + "vapor": _prototype( + "vapor", + "process_motif", + [ + _polyline([[0.28, 0.92], [0.24, 0.72], [0.32, 0.54], [0.26, 0.34], [0.36, 0.16]], stroke_role="line", stroke_width=0.026), + _polyline([[0.48, 0.92], [0.44, 0.68], [0.54, 0.5], [0.46, 0.28], [0.58, 0.08]], stroke_role="line", stroke_width=0.026), + _polyline([[0.68, 0.92], [0.64, 0.72], [0.72, 0.56], [0.66, 0.36], [0.74, 0.18]], stroke_role="line", stroke_width=0.026), + ], + ), +} + + +FAMILY_FALLBACKS = { + "scene": "blob", + "process": "flow_node", + "schematic": "module", +} + + +TOKEN_FALLBACKS = { + "tower": ("塔", "楼", "高楼", "建筑", "烟囱", "柱"), + "cycle": ("循环", "周期", "回路", "轮回", "往复"), + "vapor": ("蒸发", "蒸汽", "水汽", "雾气", "气化"), + "energy_wave": ("能量", "热量", "热", "光照", "光", "辐射", "波", "传播"), + "flow_node": ("过程", "机制", "作用", "阶段", "步骤", "输入", "输出", "结果", "原因", "条件", "变化", "转化"), + "branch": ("分支", "发散", "传播", "分化", "树枝", "网络"), + "module": ("模块", "单元", "系统", "控制", "信号", "输入", "输出", "电源"), + "switch": ("开关", "按钮", "按键", "拨动", "切换"), + "capsule": ("囊泡", "胶囊", "包裹体"), + "blob": ("物体", "东西", "目标", "主体"), +} + + +def fallback_prototype_id(concept: str, scene_type: str = "scene") -> str: + text = str(concept or "").strip().lower() + for prototype_id, tokens in TOKEN_FALLBACKS.items(): + if any(token.lower() in text for token in tokens): + if scene_type == "schematic" and prototype_id in {"tower", "blob"}: + continue + if scene_type == "process" and prototype_id == "tower": + continue + return prototype_id + return FAMILY_FALLBACKS.get(scene_type, "blob") + + +def resolve_visual_prototype(asset_key: str, concept: str = "", scene_type: str = "scene") -> Dict[str, Any]: + prototype_id = asset_key if asset_key in PROTOTYPE_LIBRARY else fallback_prototype_id(concept, scene_type) + resolved = _copy(PROTOTYPE_LIBRARY.get(prototype_id, PROTOTYPE_LIBRARY[FAMILY_FALLBACKS.get(scene_type, "blob")])) + resolved["prototype_id"] = prototype_id + return resolved diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_query_parser.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_query_parser.py new file mode 100644 index 0000000..919da77 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/visual_query_parser.py @@ -0,0 +1,780 @@ +from __future__ import annotations + +import json +import re +from typing import Any, Dict, List + +from .semantic_scene_v2 import pick_asset_key + + +VISUAL_QUERY_HINTS = [ + "生成", + "画", + "图", + "画面", + "场景", + "草图", + "渲染", + "构图", + "近景", + "远景", + "海报", + "插画", + "示意图", + "简笔", + "预演", +] + +META_CONCEPT_HINTS = { + "用户输入", + "含义", + "解释", + "内容", + "问题", + "概念", + "机制", + "原理", + "场景", + "画面", + "草图", + "控制草图", + "示意图", + "构图", + "unknown", + "ngram", +} + +SCENE_TOKENS = { + "街道", + "街景", + "路边", + "草地", + "草坪", + "树", + "云", + "天空", + "太阳", + "房子", + "楼房", + "建筑", + "汽车", + "路灯", + "室内", + "房间", + "桌子", + "椅子", + "台灯", + "窗户", + "门", +} + +PROCESS_TOKENS = { + "过程", + "机制", + "形成", + "循环", + "蒸发", + "凝结", + "降雨", + "光合作用", + "吸收", + "产生能量", + "升力", +} + +SCHEMATIC_TOKENS = { + "电路", + "电池", + "电阻", + "电容", + "二极管", + "发光二极管", + "led", + "串联", + "并联", + "电流", + "电压", + "细胞", + "细胞核", + "细胞质", + "细胞膜", +} + +NON_OBJECT_TERMS = { + "控制草图", + "草图", + "画面", + "场景", + "图片", + "图像", + "示意图", + "简笔画", + "构图", + "问题", + "内容", + "原因", + "机制", + "原理", + "室内", + "房间", + "一个", + "过程图", + "电路图", + "基础构图", + "后续", + "空间", +} + +DETAIL_ASSETS = {"window", "door", "cloud", "sun", "generic_circle"} +UNKNOWN_ASSETS = {"blob", "capsule", "module", "generic_object", "generic_panel"} + +OBJECT_SPECS: List[Dict[str, Any]] = [ + {"concept": "狗", "aliases": ["柯基", "小狗", "狗", "犬"], "type": "animal", "role": "subject", "importance": 3.8}, + {"concept": "人", "aliases": ["人物", "行人", "人", "孩子", "学生"], "type": "role", "role": "subject", "importance": 3.4}, + {"concept": "楼房", "aliases": ["楼房", "高楼", "大楼", "楼体", "楼", "建筑"], "type": "building", "role": "subject", "importance": 3.6}, + {"concept": "房子", "aliases": ["房子", "房屋", "住宅", "小屋"], "type": "building", "role": "subject", "importance": 3.4}, + {"concept": "窗户", "aliases": ["窗户", "窗"], "type": "detail", "role": "detail", "importance": 2.3, "countable": True}, + {"concept": "门", "aliases": ["房门", "大门", "门"], "type": "detail", "role": "detail", "importance": 2.2}, + {"concept": "树", "aliases": ["树木", "树", "树叶"], "type": "environment", "role": "support", "importance": 2.8}, + {"concept": "云", "aliases": ["云朵", "云"], "type": "environment", "role": "effect", "importance": 2.7}, + {"concept": "太阳", "aliases": ["太阳", "阳光", "日光"], "type": "environment", "role": "effect", "importance": 2.8}, + {"concept": "汽车", "aliases": ["轿车", "汽车", "车"], "type": "vehicle", "role": "support", "importance": 3.0}, + {"concept": "路灯", "aliases": ["路灯", "街灯", "灯杆"], "type": "detail", "role": "detail", "importance": 2.4}, + {"concept": "桌子", "aliases": ["桌子", "餐桌", "桌"], "type": "indoor", "role": "subject", "importance": 3.2}, + {"concept": "椅子", "aliases": ["椅子", "座椅", "椅"], "type": "indoor", "role": "support", "importance": 2.8}, + {"concept": "台灯", "aliases": ["台灯", "桌灯"], "type": "indoor", "role": "detail", "importance": 2.6}, + {"concept": "室内", "aliases": ["室内", "房间"], "type": "environment", "role": "environment", "importance": 1.7}, + {"concept": "街道", "aliases": ["街道", "街景", "道路", "公路", "路面"], "type": "environment", "role": "environment", "importance": 1.9}, + {"concept": "地面", "aliases": ["地面", "地上"], "type": "environment", "role": "environment", "importance": 1.4}, + {"concept": "大气", "aliases": ["大气", "空气"], "type": "environment", "role": "environment", "importance": 1.5}, + {"concept": "草地", "aliases": ["草地", "草坪"], "type": "environment", "role": "environment", "importance": 2.1}, + {"concept": "植物", "aliases": ["植物"], "type": "life", "role": "subject", "importance": 3.0}, + {"concept": "叶片", "aliases": ["叶片", "叶子", "树叶", "叶"], "type": "life", "role": "support", "importance": 2.6}, + {"concept": "蒸发", "aliases": ["蒸发"], "type": "process", "role": "stage", "importance": 3.0}, + {"concept": "凝结", "aliases": ["凝结"], "type": "process", "role": "stage", "importance": 3.0}, + {"concept": "降雨", "aliases": ["降雨", "下雨", "降水"], "type": "process", "role": "stage", "importance": 3.1}, + {"concept": "雨滴", "aliases": ["雨滴", "水滴"], "type": "process", "role": "stage", "importance": 2.8}, + {"concept": "光合作用", "aliases": ["光合作用"], "type": "process", "role": "stage", "importance": 3.1}, + {"concept": "电池", "aliases": ["电池", "电源"], "type": "schematic", "role": "component", "importance": 3.0}, + {"concept": "电阻", "aliases": ["限流电阻", "电阻"], "type": "schematic", "role": "component", "importance": 3.0}, + {"concept": "LED", "aliases": ["发光二极管", "LED", "led"], "type": "schematic", "role": "component", "importance": 3.0}, + {"concept": "电容", "aliases": ["电容"], "type": "schematic", "role": "component", "importance": 2.6}, + {"concept": "二极管", "aliases": ["二极管"], "type": "schematic", "role": "component", "importance": 2.6}, + {"concept": "电路板", "aliases": ["电路板", "开发板", "主板"], "type": "schematic", "role": "environment", "importance": 2.0}, + {"concept": "细胞", "aliases": ["细胞"], "type": "structure", "role": "subject", "importance": 3.4}, + {"concept": "细胞核", "aliases": ["细胞核"], "type": "structure", "role": "detail", "importance": 2.8}, + {"concept": "细胞质", "aliases": ["细胞质"], "type": "structure", "role": "support", "importance": 2.8}, + {"concept": "细胞膜", "aliases": ["细胞膜"], "type": "structure", "role": "detail", "importance": 2.7}, + {"concept": "氧气", "aliases": ["氧气"], "type": "process", "role": "support", "importance": 2.6}, + {"concept": "能量", "aliases": ["能量"], "type": "process", "role": "support", "importance": 2.6}, + {"concept": "消化", "aliases": ["消化", "消化吸收"], "type": "process", "role": "stage", "importance": 2.7}, + {"concept": "血液", "aliases": ["血液", "血"], "type": "process", "role": "support", "importance": 2.7}, + {"concept": "水", "aliases": ["水"], "type": "process", "role": "support", "importance": 2.6}, +] + +RELATION_HINTS = [ + (("串联", "series"), "串联"), + (("并联", "parallel"), "并联"), + (("光照", "照射", "照到", "照向", "射向"), "照射"), + (("附着", "装在", "贴在", "挂在"), "附着"), + (("放在", "摆在", "置于"), "放在"), + (("邻近", "旁边", "靠近", "周边"), "邻近"), + (("进入", "吸收", "输送"), "进入"), + (("连接", "接到", "导通"), "连接"), + (("导致", "引发", "形成", "产生", "转化", "变成"), "导致"), + (("位于", "在里面", "内部", "包含"), "位于"), +] + +COUNT_PATTERNS = [ + (re.compile(r"(两|二|2)(?:个|扇|辆|盏|朵|栋)?"), 2), + (re.compile(r"(三|3)(?:个|扇|辆|盏|朵|栋)?"), 3), +] + + +def _clean_text(value: Any) -> str: + return str(value or "").strip() + + +def _safe_json(value: Any) -> str: + try: + return json.dumps(value or {}, ensure_ascii=False) + except Exception: + return "" + + +def _normalize_text(value: Any) -> str: + text = _clean_text(value).lower() + return re.sub(r"\s+", "", text) + + +def is_meta_concept(text: Any) -> bool: + cleaned = _clean_text(text) + lowered = _normalize_text(cleaned) + if not cleaned: + return True + if cleaned in META_CONCEPT_HINTS or lowered in META_CONCEPT_HINTS: + return True + return any(token in cleaned for token in ("用户输入", "含义", "问题", "机制", "原理")) + + +def is_visual_query(query: str) -> bool: + text = _clean_text(query) + if not text: + return False + lowered = text.lower() + if any(token.lower() in lowered for token in VISUAL_QUERY_HINTS): + return True + has_domain_tokens = any(token in text for token in SCENE_TOKENS | PROCESS_TOKENS | SCHEMATIC_TOKENS) + has_visual_intent = any(token in text for token in ("图", "画", "草图", "示意", "构图", "渲染", "预演")) + return has_domain_tokens and has_visual_intent + + +def normalize_relation_label(label: Any) -> str: + text = _normalize_text(label) + if not text: + return "" + for tokens, canonical in RELATION_HINTS: + if any(token in text for token in tokens): + return canonical + return _clean_text(label) + + +def _canonicalize_concept(name: str) -> str: + text = _clean_text(name) + lowered = text.lower() + for spec in OBJECT_SPECS: + for alias in spec["aliases"]: + alias_lower = alias.lower() + if alias_lower and alias_lower in lowered: + return spec["concept"] + return text + + +def _spec_for_concept(name: str) -> Dict[str, Any] | None: + concept = _canonicalize_concept(name) + for spec in OBJECT_SPECS: + if spec["concept"] == concept: + return spec + return None + + +def _infer_scene_type( + query: str, + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> str: + query_text = _clean_text(query).lower() + if any(token.lower() in query_text for token in SCHEMATIC_TOKENS): + return "schematic" + if any(token.lower() in query_text for token in PROCESS_TOKENS): + return "process" + if any(token in _clean_text(query) for token in SCENE_TOKENS): + return "scene" + + context_terms: List[str] = [] + for item in (understanding_result or {}).get("concepts", []) or []: + if isinstance(item, dict): + context_terms.append(_clean_text(item.get("concept"))) + for item in (extraction_result or {}).get("concepts", []) or []: + if isinstance(item, dict): + context_terms.append(_clean_text(item.get("concept"))) + for item in (answer_bundle or {}).get("core_concepts", []) or []: + context_terms.append(_clean_text(item)) + haystack = " ".join(term for term in context_terms if term).lower() + if any(token.lower() in haystack for token in SCHEMATIC_TOKENS): + return "schematic" + if any(token.lower() in haystack for token in PROCESS_TOKENS): + return "process" + return "scene" + + +def _count_for_alias(query: str, alias: str, default: int = 1) -> int: + if not alias or alias not in query: + return 0 + prefix = query[: query.index(alias)] + tail = prefix[-6:] + for pattern, value in COUNT_PATTERNS: + if pattern.search(tail): + return value + return default + + +def _object_role(spec: Dict[str, Any] | None, scene_type: str) -> str: + if not spec: + return "support" + role = str(spec.get("role", "support")) + if scene_type == "process" and role not in {"stage", "support"}: + return "stage" if spec.get("type") == "process" else "support" + if scene_type == "schematic": + return "component" if role != "environment" else "environment" + return role + + +def _append_object( + objects: List[Dict[str, Any]], + object_index: Dict[str, Dict[str, Any]], + *, + concept: str, + scene_type: str, + source: str, + importance: float = 1.0, + count: int = 1, + position: int = 9999, +) -> None: + base_concept = _canonicalize_concept(concept) + if not base_concept or base_concept in NON_OBJECT_TERMS or is_meta_concept(base_concept): + return + spec = _spec_for_concept(base_concept) + role = _object_role(spec, scene_type) + total = max(1, int(count)) + for index in range(total): + concept_name = base_concept if total == 1 else f"{base_concept}{index + 1}" + item = object_index.get(concept_name) + if item: + item["importance"] = max(float(item.get("importance", 1.0) or 1.0), float(importance)) + item["position"] = min(int(item.get("position", 9999) or 9999), int(position)) + if source not in item["sources"]: + item["sources"].append(source) + continue + asset_key = pick_asset_key(base_concept, scene_type) + record = { + "concept": concept_name, + "base_concept": base_concept, + "type": spec.get("type", "general") if spec else "general", + "role": role, + "asset_key": asset_key, + "importance": float(importance), + "position": int(position), + "sources": [source], + } + object_index[concept_name] = record + objects.append(record) + + +def _extract_query_objects(query: str, scene_type: str) -> List[Dict[str, Any]]: + objects: List[Dict[str, Any]] = [] + object_index: Dict[str, Dict[str, Any]] = {} + query_text = _clean_text(query) + lowered = query_text.lower() + for spec in OBJECT_SPECS: + positions = [] + count = 0 + for alias in spec["aliases"]: + alias_text = _clean_text(alias) + idx = lowered.find(alias_text.lower()) + if idx >= 0: + positions.append(idx) + count = max(count, _count_for_alias(query_text, alias_text, 1)) + if not positions: + continue + _append_object( + objects, + object_index, + concept=spec["concept"], + scene_type=scene_type, + source="query", + importance=float(spec.get("importance", 1.0) or 1.0), + count=count or 1, + position=min(positions), + ) + objects.sort(key=lambda item: (int(item.get("position", 9999)), -float(item.get("importance", 0.0)))) + return objects + + +def _iter_context_concepts( + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> List[str]: + names: List[str] = [] + for item in (understanding_result or {}).get("concepts", []) or []: + names.append(_clean_text(item.get("concept"))) + for item in (extraction_result or {}).get("concepts", []) or []: + names.append(_clean_text(item.get("concept"))) + for item in (answer_bundle or {}).get("core_concepts", []) or []: + names.append(_clean_text(item)) + for rel in (answer_bundle or {}).get("primary_chain", []) or []: + names.extend([_clean_text(rel.get("from")), _clean_text(rel.get("to"))]) + for rel in (answer_bundle or {}).get("supporting_relations", []) or []: + names.extend([_clean_text(rel.get("from")), _clean_text(rel.get("to"))]) + return [name for name in names if name] + + +def _augment_context_objects( + objects: List[Dict[str, Any]], + scene_type: str, + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> List[Dict[str, Any]]: + object_index = {item["concept"]: item for item in objects} + for position, name in enumerate(_iter_context_concepts(understanding_result, extraction_result, answer_bundle), start=500): + if is_meta_concept(name): + continue + canonical = _canonicalize_concept(name) + if canonical in NON_OBJECT_TERMS: + continue + if any(token in canonical for token in ("画一个", "保留", "包括", "控制草图", "基础构图")): + continue + importance = 1.1 + spec = _spec_for_concept(canonical) + if spec is None: + continue + if spec: + importance = max(importance, float(spec.get("importance", 1.0) or 1.0) * 0.8) + _append_object( + objects, + object_index, + concept=canonical, + scene_type=scene_type, + source="context", + importance=importance, + position=position, + ) + objects.sort(key=lambda item: (int(item.get("position", 9999)), -float(item.get("importance", 0.0)))) + return objects + + +def _find_host(objects: List[Dict[str, Any]], *base_concepts: str) -> str | None: + base_set = set(base_concepts) + for item in objects: + if item.get("base_concept") in base_set: + return item["concept"] + return None + + +def _map_object_name(name: str, objects: List[Dict[str, Any]]) -> str: + target = _canonicalize_concept(name) + for item in objects: + if item.get("base_concept") == target or item.get("concept") == target: + return str(item["concept"]) + return target + + +def _add_relation(relations: List[Dict[str, Any]], seen: set[tuple[str, str, str]], src: str, dst: str, label: str, source: str, weight: float = 0.72) -> None: + relation = normalize_relation_label(label) + if not src or not dst or not relation or src == dst: + return + key = (src, dst, relation) + if key in seen: + return + seen.add(key) + relations.append({"from": src, "to": dst, "relation": relation, "weight": float(weight), "source": source}) + + +def _collect_context_relations( + objects: List[Dict[str, Any]], + understanding_result: Dict[str, Any] | None, + extraction_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> List[Dict[str, Any]]: + relations: List[Dict[str, Any]] = [] + seen: set[tuple[str, str, str]] = set() + object_names = {item["concept"] for item in objects} + for group_name, group in ( + ("understanding", (understanding_result or {}).get("relations", []) or []), + ("extraction", (extraction_result or {}).get("relations", []) or []), + ("answer_primary", (answer_bundle or {}).get("primary_chain", []) or []), + ("answer_support", (answer_bundle or {}).get("supporting_relations", []) or []), + ): + for relation in group: + src = _map_object_name(_clean_text(relation.get("from")), objects) + dst = _map_object_name(_clean_text(relation.get("to")), objects) + label = normalize_relation_label(relation.get("relation")) + if src not in object_names or dst not in object_names: + continue + _add_relation(relations, seen, src, dst, label, group_name, float(relation.get("weight", 0.65) or 0.65)) + return relations + + +def _apply_rule_relations(query: str, scene_type: str, objects: List[Dict[str, Any]], relations: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + text = _clean_text(query) + seen = {(item["from"], item["to"], item["relation"]) for item in relations} + building = _find_host(objects, "楼房", "房子") + cell = _find_host(objects, "细胞") + table = _find_host(objects, "桌子") + road = _find_host(objects, "街道") + plant = _find_host(objects, "植物", "叶片") + + for item in objects: + base = item.get("base_concept") + if base == "窗户" and building: + _add_relation(relations, seen, item["concept"], building, "附着", "rule_attachment", 0.82) + elif base == "门" and building: + _add_relation(relations, seen, item["concept"], building, "附着", "rule_attachment", 0.82) + elif base == "椅子" and table: + _add_relation(relations, seen, item["concept"], table, "邻近", "rule_attachment", 0.78) + elif base == "台灯" and table: + _add_relation(relations, seen, item["concept"], table, "放在", "rule_attachment", 0.8) + elif base == "汽车" and road: + _add_relation(relations, seen, item["concept"], road, "位于", "rule_layout", 0.76) + elif base == "路灯" and road: + _add_relation(relations, seen, item["concept"], road, "位于", "rule_layout", 0.74) + elif base in {"细胞核", "细胞质"} and cell: + _add_relation(relations, seen, item["concept"], cell, "位于", "rule_structure", 0.8) + elif base == "细胞膜" and cell: + _add_relation(relations, seen, item["concept"], cell, "附着", "rule_structure", 0.8) + + if scene_type == "process": + evaporation = _find_host(objects, "蒸发") + condensation = _find_host(objects, "凝结") + rainfall = _find_host(objects, "降雨", "雨滴") + if evaporation and condensation: + _add_relation(relations, seen, evaporation, condensation, "导致", "rule_process", 0.84) + if condensation and rainfall: + _add_relation(relations, seen, condensation, rainfall, "导致", "rule_process", 0.84) + sun = _find_host(objects, "太阳") + if sun and plant: + _add_relation(relations, seen, sun, plant, "照射", "rule_process", 0.84) + photosynthesis = _find_host(objects, "光合作用") + if plant and photosynthesis: + _add_relation(relations, seen, plant, photosynthesis, "导致", "rule_process", 0.78) + + if scene_type == "schematic": + battery = _find_host(objects, "电池") + resistor = _find_host(objects, "电阻") + led = _find_host(objects, "LED") + if battery and resistor: + _add_relation(relations, seen, battery, resistor, "串联", "rule_schematic", 0.88) + if resistor and led: + _add_relation(relations, seen, resistor, led, "串联", "rule_schematic", 0.88) + + if "上" in text and table and _find_host(objects, "台灯"): + _add_relation(relations, seen, _find_host(objects, "台灯"), table, "放在", "rule_text", 0.8) + return relations + + +def _constraint(label: str, target: str = "", source: str = "query") -> Dict[str, Any]: + return {"label": label, "target": target, "source": source} + + +def _collect_constraints(query: str, objects: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + text = _clean_text(query) + focus = objects[0]["concept"] if objects else "" + constraints: List[Dict[str, Any]] = [] + if "近景" in text or "前景" in text: + constraints.append(_constraint("foreground", focus)) + if "远景" in text or "背景" in text: + constraints.append(_constraint("background", focus)) + if "左" in text: + constraints.append(_constraint("left", focus)) + if "右" in text: + constraints.append(_constraint("right", focus)) + if "上方" in text or "顶部" in text: + constraints.append(_constraint("top", focus)) + if "下方" in text or "底部" in text: + constraints.append(_constraint("bottom", focus)) + if "居中" in text or "中心" in text: + constraints.append(_constraint("center", focus)) + return constraints + + +def _infer_focus( + objects: List[Dict[str, Any]], + scene_type: str, + understanding_result: Dict[str, Any] | None, + answer_bundle: Dict[str, Any] | None, +) -> str: + preferred = [_clean_text((answer_bundle or {}).get("focus_concept")), _clean_text((understanding_result or {}).get("focus_concept"))] + object_names = {item["concept"] for item in objects} + for item in preferred: + mapped = _map_object_name(item, objects) + if mapped in object_names: + selected = next((obj for obj in objects if obj.get("concept") == mapped), None) + role = str((selected or {}).get("role", "")) + if scene_type == "process" and role != "stage": + continue + if scene_type == "schematic" and role != "component": + continue + if scene_type == "scene" and role == "detail": + continue + return mapped + ranked = sorted( + objects, + key=lambda item: ( + 1 if item.get("role") in {"subject", "stage", "component"} else 0, + float(item.get("importance", 0.0)), + -int(item.get("position", 9999)), + ), + reverse=True, + ) + for item in ranked: + if item.get("asset_key") not in DETAIL_ASSETS: + return item["concept"] + return ranked[0]["concept"] if ranked else "" + + +def parse_visual_query( + query: str, + understanding_result: Dict[str, Any] | None = None, + extraction_result: Dict[str, Any] | None = None, + answer_bundle: Dict[str, Any] | None = None, +) -> Dict[str, Any] | None: + query_text = _clean_text(query) + if not is_visual_query(query_text): + return None + scene_type = _infer_scene_type(query_text, understanding_result, extraction_result, answer_bundle) + objects = _extract_query_objects(query_text, scene_type) + objects = _augment_context_objects(objects, scene_type, understanding_result, extraction_result, answer_bundle) + if not objects: + return None + relations = _collect_context_relations(objects, understanding_result, extraction_result, answer_bundle) + relations = _apply_rule_relations(query_text, scene_type, objects, relations) + constraints = _collect_constraints(query_text, objects) + focus_concept = _infer_focus(objects, scene_type, understanding_result, answer_bundle) + unknown_assets = set(UNKNOWN_ASSETS) + if scene_type == "process": + unknown_assets.discard("capsule") + unknown_object_count = sum(1 for item in objects if str(item.get("asset_key", "")) in unknown_assets) + focus_item = next((item for item in objects if item["concept"] == focus_concept), None) + unknown_primary_object = bool(focus_item and str(focus_item.get("asset_key", "")) in unknown_assets) + fallback_reason = "" + if unknown_primary_object: + fallback_reason = "focus_object_fell_back_to_generic" + elif unknown_object_count: + fallback_reason = "some_objects_require_generic_fallback" + elif not relations: + fallback_reason = "objects_found_without_explicit_relations" + return { + "scene_type": scene_type, + "focus_concept": focus_concept, + "objects": objects, + "relations": relations, + "constraints": constraints, + "best_path_concepts": [item["concept"] for item in objects], + "object_base_concepts": [item.get("base_concept", item["concept"]) for item in objects], + "parse_source": "visual_query_parser", + "fallback_reason": fallback_reason, + "unknown_object_count": int(unknown_object_count), + "unknown_primary_object": unknown_primary_object, + } + + +def build_visual_extraction(parsed: Dict[str, Any] | None) -> Dict[str, Any] | None: + if not parsed: + return None + concepts = [ + { + "concept": item.get("concept"), + "type": item.get("type", "general"), + "importance": float(item.get("importance", 1.0) or 1.0), + "source": "visual_query_parser", + } + for item in parsed.get("objects", []) or [] + ] + return { + "concepts": concepts, + "relations": list(parsed.get("relations", []) or []), + "contexts": { + "scene_type": parsed.get("scene_type"), + "constraints": parsed.get("constraints", []), + "parse_source": parsed.get("parse_source"), + "fallback_reason": parsed.get("fallback_reason"), + }, + } + + +def build_visual_understanding(parsed: Dict[str, Any] | None, base: Dict[str, Any] | None = None) -> Dict[str, Any] | None: + if not parsed: + return base + merged = dict(base or {}) + visual_extraction = build_visual_extraction(parsed) or {"concepts": [], "relations": []} + merged.setdefault("intent", "visual_composition") + merged["normalized_query"] = merged.get("normalized_query") or "" + merged["focus_concept"] = parsed.get("focus_concept") or merged.get("focus_concept") + merged["confidence"] = max(float(merged.get("confidence", 0.0) or 0.0), 0.66) + merged["concepts"] = (merged.get("concepts") or []) or visual_extraction["concepts"] + merged["relations"] = (merged.get("relations") or []) or list(parsed.get("relations", []) or []) + merged["constraints"] = list(merged.get("constraints") or []) + [str(item.get("label")) for item in parsed.get("constraints", []) or [] if str(item.get("label", "")).strip()] + return merged + + +def build_visual_answer_bundle(parsed: Dict[str, Any] | None, base: Dict[str, Any] | None = None) -> Dict[str, Any] | None: + if not parsed: + return base + merged = dict(base or {}) + relations = list(parsed.get("relations", []) or []) + merged["focus_concept"] = parsed.get("focus_concept") or merged.get("focus_concept") + merged["answer_source"] = merged.get("answer_source") or "seeded_relations" + merged["core_concepts"] = list(dict.fromkeys(list(merged.get("core_concepts") or []) + list(parsed.get("best_path_concepts") or [])))[:12] + if not merged.get("primary_chain"): + merged["primary_chain"] = relations[:4] + merged["supporting_relations"] = list(merged.get("supporting_relations") or []) + seen = { + (_clean_text(item.get("from")), _clean_text(item.get("to")), normalize_relation_label(item.get("relation"))) + for item in merged["supporting_relations"] + } + for relation in relations: + key = (_clean_text(relation.get("from")), _clean_text(relation.get("to")), normalize_relation_label(relation.get("relation"))) + if key in seen: + continue + seen.add(key) + merged["supporting_relations"].append(relation) + merged["constraints"] = list(dict.fromkeys(list(merged.get("constraints") or []) + [item.get("label") for item in parsed.get("constraints", []) or [] if item.get("label")])) + merged["confidence"] = max(float(merged.get("confidence", 0.0) or 0.0), 0.58) + merged["has_forward_path"] = bool(merged.get("has_forward_path", False)) + merged["has_boundary_path"] = bool(merged.get("has_boundary_path", False)) + merged["has_reverse_path"] = bool(merged.get("has_reverse_path", False)) + return merged + + +def build_visual_scene_context( + query: str, + understanding_result: Dict[str, Any] | None = None, + extraction_result: Dict[str, Any] | None = None, + answer_bundle: Dict[str, Any] | None = None, + best_path_concepts: List[str] | None = None, +) -> Dict[str, Any] | None: + parsed = parse_visual_query(query, understanding_result, extraction_result, answer_bundle) + if not parsed: + return None + visual_extraction = build_visual_extraction(parsed) or {"concepts": [], "relations": [], "contexts": {}} + merged_understanding = build_visual_understanding(parsed, understanding_result) + merged_extraction = dict(extraction_result or {}) + + existing_concepts = [ + _clean_text(item.get("concept")) + for item in (merged_extraction.get("concepts") or []) + if isinstance(item, dict) and _clean_text(item.get("concept")) + ] + existing_relations = merged_extraction.get("relations") or [] + if not existing_concepts or all(is_meta_concept(name) for name in existing_concepts): + merged_extraction["concepts"] = visual_extraction["concepts"] + else: + seen_concepts = set(existing_concepts) + for item in visual_extraction["concepts"]: + name = _clean_text(item.get("concept")) + if name and name not in seen_concepts: + seen_concepts.add(name) + merged_extraction.setdefault("concepts", []).append(item) + if not existing_relations: + merged_extraction["relations"] = visual_extraction["relations"] + else: + seen_relations = { + (_clean_text(item.get("from")), _clean_text(item.get("to")), normalize_relation_label(item.get("relation"))) + for item in existing_relations + if isinstance(item, dict) + } + for relation in visual_extraction["relations"]: + key = (_clean_text(relation.get("from")), _clean_text(relation.get("to")), normalize_relation_label(relation.get("relation"))) + if key in seen_relations: + continue + seen_relations.add(key) + merged_extraction.setdefault("relations", []).append(relation) + merged_extraction["contexts"] = {**(merged_extraction.get("contexts") or {}), **(visual_extraction.get("contexts") or {})} + + merged_answer_bundle = build_visual_answer_bundle(parsed, answer_bundle) + path_concepts = list(best_path_concepts or []) + if not path_concepts or all(is_meta_concept(item) for item in path_concepts): + path_concepts = list(parsed.get("best_path_concepts") or []) + + return { + "query": _clean_text(query), + "understanding_result": merged_understanding, + "extraction_result": merged_extraction, + "answer_bundle": merged_answer_bundle, + "best_path_concepts": path_concepts, + "start_concept": merged_answer_bundle.get("focus_concept") if isinstance(merged_answer_bundle, dict) else parsed.get("focus_concept"), + "visual_parse": parsed, + } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/whole_scene_sketch_generator.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/whole_scene_sketch_generator.py new file mode 100644 index 0000000..9c304e7 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/core/whole_scene_sketch_generator.py @@ -0,0 +1,771 @@ +from __future__ import annotations + +import json +from typing import Any, Dict, List, Tuple + +import numpy as np +from PIL import Image, ImageDraw + +from .scene_harmonizer import SceneSketchHarmonizerRuntime + + +def _copy(value: Any) -> Any: + return json.loads(json.dumps(value, ensure_ascii=False)) + + +DISPLAY_LABELS = { + "building": "Building", + "house": "House", + "window": "Window", + "door": "Door", + "tree": "Tree", + "cloud": "Cloud", + "sun": "Sun", + "person": "Person", + "car": "Car", + "street_lamp": "Lamp", + "table": "Table", + "chair": "Chair", + "dog": "Dog", + "desk_lamp": "Desk lamp", + "road": "Road", +} + +REGION_LABELS = { + "roofline": "Roof", + "window_row": "Windows", + "door_zone": "Door", + "facade": "Facade", + "head": "Head", + "face": "Face", + "beard": "Beard", + "torso": "Torso", + "legs": "Legs", + "canopy": "Canopy", + "trunk": "Trunk", + "body": "Body", + "windshield": "Windshield", + "wheel_front": "Front wheel", + "wheel_rear": "Rear wheel", + "front_wheel": "Front wheel", + "rear_wheel": "Rear wheel", + "cabin": "Cabin", + "body": "Body", + "lamp_head": "Lamp head", + "pole": "Pole", + "light_cone": "Light cone", +} + + +class WholeSceneSketchGenerator: + """Render a full-scene clean-line sketch and emit synchronized annotations.""" + + def __init__(self, renderer: Any): + self.renderer = renderer + self.harmonizer_runtime = SceneSketchHarmonizerRuntime() + + def render_scene( + self, + scene_spec: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + title: str, + *, + annotated: bool = False, + show_regions: bool = False, + include_title: bool = False, + view_mode: str = "structure", + ) -> Tuple[Image.Image, Dict[str, Any]]: + scene = _copy(scene_spec) + layout_options = scene.get("layout_options", {}) if isinstance(scene.get("layout_options"), dict) else {} + canvas_size = ( + int(scene.get("canvas_size", {}).get("width", 1024)), + int(scene.get("canvas_size", {}).get("height", 768)), + ) + generator_style = str(layout_options.get("generator_style") or "clean_line") + image = Image.new("RGBA", canvas_size, (*palette["background"], 255)) + draw = ImageDraw.Draw(image) + + if view_mode != "rich_preview": + self._draw_scene_skeleton(draw, scene, palette) + self._draw_background_layers(draw, scene, palette, view_mode=view_mode) + if view_mode != "rich_preview": + self._draw_connectors(draw, scene, palette) + self._draw_objects(draw, scene, palette, generator_style=generator_style, view_mode=view_mode) + + refined = self.harmonizer_runtime.harmonize( + base_image=image.convert("RGB"), + condition_maps=self._build_condition_maps(scene), + ) + if refined is not None: + image = refined.convert("RGBA") + draw = ImageDraw.Draw(image) + + annotation_bundle = self.build_annotation_bundle( + scene, + generator_style=generator_style, + title=title, + second_stage_status=self.harmonizer_runtime.status(), + ) + + if include_title and title: + draw.text((24, 20), self._safe_text(title), fill=palette["text"], font=self.renderer.font) + draw.text( + (24, 50), + f"{layout_options.get('scene_type', 'scene')} | {generator_style} | whole_scene_structural_v2 | {view_mode}", + fill=self.renderer._with_alpha(palette["text"], 0.8), + font=self.renderer.font, + ) + if annotated: + self._draw_annotation_overlay(draw, annotation_bundle, palette, show_regions=show_regions) + return image.convert("RGB"), annotation_bundle + + def build_annotation_bundle( + self, + scene_spec: Dict[str, Any], + *, + generator_style: str, + title: str, + second_stage_status: Dict[str, Any], + ) -> Dict[str, Any]: + scene = _copy(scene_spec) + layout_options = scene.get("layout_options", {}) if isinstance(scene.get("layout_options"), dict) else {} + canvas = scene.get("canvas_size", {}) if isinstance(scene.get("canvas_size"), dict) else {} + scene_type = str(layout_options.get("scene_type", "scene")) + objects = sorted(scene.get("object_instances", []) or [], key=lambda item: (item.get("z_index", 0), item.get("id", ""))) + background_layers = sorted(scene.get("background_layers", []) or [], key=lambda item: (item.get("z_index", 0), item.get("id", ""))) + connectors = [item for item in scene.get("connectors", []) or [] if item.get("visible", True)] + + object_annotations: List[Dict[str, Any]] = [] + region_annotations: List[Dict[str, Any]] = [] + for obj in objects: + object_annotations.append( + { + "object_id": str(obj.get("id", "")), + "concept": str(obj.get("concept", "")), + "display_label": self._display_label(obj), + "asset_key": str(obj.get("asset_key", "")), + "role": str(obj.get("role", "")), + "depth_band": str(obj.get("depth_band", "")), + "bbox": self._bbox_payload(self.renderer._scene_bbox(obj)), + "label_anchor": self._label_anchor_for_object(obj), + "editable": bool(obj.get("editable", True)), + "controls": self._edit_controls_for_object(obj), + "style_variant": generator_style, + "render_representation": str(obj.get("render_representation", "shape_recipe")), + "shape_variant_id": str(obj.get("shape_variant_id", "")), + "stroke_variant_id": str(obj.get("stroke_variant_id", "")), + "shape_recipe_source": str(obj.get("shape_recipe_source", "")), + "stroke_payload_source": str(obj.get("stroke_payload_source", "")), + "sketch_backend": str(obj.get("sketch_backend", "")), + "readability_rank": int(obj.get("readability_rank", 0) or 0), + } + ) + for region in obj.get("region_masks", []) or []: + if not isinstance(region, dict): + continue + region_box = self.renderer._region_box_for_object(obj, region) + region_annotations.append( + { + "object_id": str(obj.get("id", "")), + "region_id": str(region.get("id", "")), + "label": str(region.get("label", "") or region.get("id", "")), + "display_label": self._region_display_label(region), + "bbox": self._bbox_payload(region_box), + "shape": str(region.get("shape", "rect")), + "actions": list(region.get("actions") or []), + "label_anchor": {"x": int(region_box[2] + 12), "y": int(region_box[1] + 18)}, + } + ) + + connector_annotations: List[Dict[str, Any]] = [] + objects_by_id = {str(item.get("id", "")): item for item in objects} + for connector in connectors: + from_obj = objects_by_id.get(str(connector.get("from_id", ""))) + to_obj = objects_by_id.get(str(connector.get("to_id", ""))) + if not from_obj or not to_obj: + continue + start, end = self.renderer._connector_points_for_scene(from_obj, to_obj) + connector_annotations.append( + { + "connector_id": str(connector.get("id", "")), + "type": str(connector.get("type", "relation")), + "label": str(connector.get("label", "")), + "display_label": self._connector_display_label(connector), + "from_id": str(connector.get("from_id", "")), + "to_id": str(connector.get("to_id", "")), + "start": {"x": int(start[0]), "y": int(start[1])}, + "end": {"x": int(end[0]), "y": int(end[1])}, + "label_anchor": {"x": int((start[0] + end[0]) / 2), "y": int((start[1] + end[1]) / 2 - 18)}, + } + ) + + background_annotations = [ + { + "layer_id": str(layer.get("id", "")), + "type": str(layer.get("type", "panel")), + "label": str(layer.get("label", "")), + "display_label": self._layer_display_label(layer), + "bbox": self._bbox_payload(self.renderer._scene_bbox(layer)), + } + for layer in background_layers + ] + + return { + "version": 2, + "generator_id": "whole_scene_structural_v2", + "title": self._safe_text(title), + "scene_type": scene_type, + "sketch_style": generator_style, + "canvas_size": {"width": int(canvas.get("width", 1024)), "height": int(canvas.get("height", 768))}, + "quality_targets": { + "subject_coverage": "required", + "scene_layering": "required", + "editable_control": "required", + "line_cleanliness": "required", + "detail_readability": "required", + }, + "second_stage_generator": second_stage_status, + "layout_runtime": _copy(((scene.get("render_hints") or {}).get("layout_runtime") or {})), + "scene_markers": self._scene_markers(scene), + "background_annotations": background_annotations, + "object_annotations": object_annotations, + "region_annotations": region_annotations, + "connector_annotations": connector_annotations, + "edit_layers": { + "object_edit_count": sum(1 for item in object_annotations if item.get("editable")), + "region_edit_count": len(region_annotations), + "connector_edit_count": len(connector_annotations), + }, + "metrics": { + "background_count": len(background_annotations), + "object_count": len(object_annotations), + "region_count": len(region_annotations), + "connector_count": len(connector_annotations), + }, + } + + def _draw_scene_skeleton( + self, + draw: ImageDraw.ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + scene_type = str((scene.get("layout_options", {}) or {}).get("scene_type", "scene")) + if scene_type != "scene": + return + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + horizon_y = int(height * 0.56) + vanishing_x = int(width * 0.54) + guide = self.renderer._with_alpha(palette["guide"], 0.18) + draw.line([(0, horizon_y), (width, horizon_y)], fill=guide, width=1) + for offset in (-0.28, -0.1, 0.12, 0.28): + x = int(width * (0.5 + offset)) + draw.line([(x, height), (vanishing_x, horizon_y)], fill=guide, width=1) + + def _draw_background_layers( + self, + draw: ImageDraw.ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + view_mode: str, + ) -> None: + for layer in sorted(scene.get("background_layers", []) or [], key=lambda item: item.get("z_index", 0)): + layer_type = str(layer.get("type", "panel")) + x0, y0, x1, y1 = self.renderer._scene_bbox(layer) + if layer_type == "sky": + if view_mode == "rich_preview": + draw.line([(0, y1), (x1, y1)], fill=self.renderer._with_alpha(palette["guide"], 0.08), width=1) + continue + draw.line([(0, y1), (x1, y1)], fill=self.renderer._with_alpha(palette["guide"], 0.18), width=1) + continue + if layer_type == "road": + top_y = int(y0 + (y1 - y0) * 0.12) + bottom_y = int(y1) + mid_x = int((x0 + x1) / 2) + road_poly = [(x0, bottom_y), (x0 + 50, top_y), (x1 - 50, top_y), (x1, bottom_y)] + if view_mode == "rich_preview": + draw.polygon(road_poly, fill=self.renderer._with_alpha(palette["region_alt"], 0.16)) + draw.line([road_poly[0], road_poly[1]], fill=self.renderer._with_alpha(palette["line"], 0.36), width=2) + draw.line([road_poly[2], road_poly[3]], fill=self.renderer._with_alpha(palette["line"], 0.36), width=2) + else: + draw.line(road_poly + [road_poly[0]], fill=self.renderer._with_alpha(palette["line"], 0.5), width=2) + self.renderer._draw_dashed_line( + draw, + (mid_x, top_y + 10), + (mid_x, bottom_y - 14), + palette["accent"], + width=2, + dash_length=16, + ) + continue + self.renderer._draw_scene_background_layer(draw, layer, palette, filled=view_mode == "rich_preview") + + def _draw_connectors( + self, + draw: ImageDraw.ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + objects_by_id = {item["id"]: item for item in scene.get("object_instances", []) or [] if item.get("id")} + for connector in scene.get("connectors", []) or []: + if not connector.get("visible", True): + continue + from_obj = objects_by_id.get(str(connector.get("from_id", ""))) + to_obj = objects_by_id.get(str(connector.get("to_id", ""))) + if not from_obj or not to_obj: + continue + start, end = self.renderer._connector_points_for_scene(from_obj, to_obj) + if str(connector.get("type", "relation")) == "beam": + self._draw_light_beam(draw, start, end, palette) + continue + self.renderer._draw_scene_connector(draw, connector, objects_by_id, palette, show_labels=False) + + def _draw_objects( + self, + draw: ImageDraw.ImageDraw, + scene: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + generator_style: str, + view_mode: str, + ) -> None: + for obj in sorted(scene.get("object_instances", []) or [], key=lambda item: item.get("z_index", 0)): + self._render_object(draw, obj, palette, generator_style=generator_style, view_mode=view_mode) + + def _render_object( + self, + draw: ImageDraw.ImageDraw, + obj: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + generator_style: str, + view_mode: str, + ) -> None: + bbox = self.renderer._scene_bbox(obj) + asset_key = str(obj.get("asset_key", "") or obj.get("silhouette_key", "")).strip().lower() + if view_mode == "rich_preview": + rendered = False + if str(obj.get("render_representation") or "") == "stroke_native" or obj.get("stroke_payload"): + rendered = self.renderer._draw_stroke_payload( + draw, + bbox, + obj.get("stroke_payload") if isinstance(obj.get("stroke_payload"), list) else [], + palette, + style_variant=generator_style, + stroke_render_profile=obj.get("stroke_render_profile") if isinstance(obj.get("stroke_render_profile"), dict) else obj.get("stroke_style_profile"), + ) + if not rendered: + shape_recipe = obj.get("shape_recipe") if isinstance(obj.get("shape_recipe"), dict) else {} + rendered = self.renderer._draw_shape_recipe( + draw, + bbox, + shape_recipe, + palette, + filled=False, + style_variant=generator_style, + ) + if rendered: + return + if asset_key == "building": + self._draw_building(draw, bbox, palette) + return + if asset_key == "house": + self._draw_house(draw, bbox, palette) + return + if asset_key == "tree": + self._draw_tree(draw, bbox, palette) + return + if asset_key == "person": + self._draw_person(draw, bbox, palette) + return + if asset_key == "car": + self._draw_car(draw, bbox, palette) + return + if asset_key == "street_lamp": + self._draw_street_lamp(draw, bbox, palette) + return + if asset_key == "road": + self._draw_road(draw, bbox, palette) + return + if asset_key == "window": + self._draw_window(draw, bbox, palette) + return + if asset_key == "door": + self._draw_door(draw, bbox, palette) + return + rendered = False + if str(obj.get("render_representation") or "") == "stroke_native" or obj.get("stroke_payload"): + rendered = self.renderer._draw_stroke_payload( + draw, + bbox, + obj.get("stroke_payload") if isinstance(obj.get("stroke_payload"), list) else [], + palette, + style_variant=generator_style, + stroke_render_profile=obj.get("stroke_render_profile") if isinstance(obj.get("stroke_render_profile"), dict) else obj.get("stroke_style_profile"), + ) + if not rendered: + shape_recipe = obj.get("shape_recipe") if isinstance(obj.get("shape_recipe"), dict) else {} + rendered = self.renderer._draw_shape_recipe( + draw, + bbox, + shape_recipe, + palette, + filled=False, + style_variant=generator_style, + ) + if not rendered: + self.renderer._draw_asset_symbol(draw, bbox, asset_key or "generic_object", palette, filled=False) + + def _draw_annotation_overlay( + self, + draw: ImageDraw.ImageDraw, + annotation_bundle: Dict[str, Any], + palette: Dict[str, Tuple[int, int, int]], + *, + show_regions: bool, + ) -> None: + accent = palette["accent"] + text_color = palette["text"] + muted = self.renderer._with_alpha(palette["guide"], 0.86) + for marker in annotation_bundle.get("scene_markers", []) or []: + if marker.get("type") == "light_source": + draw.text( + (int(marker.get("x", 0)) + 10, int(marker.get("y", 0)) - 12), + str(marker.get("display_label", "Light")), + fill=accent, + font=self.renderer.font, + ) + + for item in annotation_bundle.get("object_annotations", []) or []: + bbox = item.get("bbox", {}) + anchor = item.get("label_anchor", {}) + center_x = int(bbox.get("x", 0) + bbox.get("width", 0) / 2) + center_y = int(bbox.get("y", 0) + bbox.get("height", 0) / 2) + label_x = int(anchor.get("x", center_x)) + label_y = int(anchor.get("y", center_y)) + draw.line([(center_x, center_y), (label_x, label_y)], fill=accent, width=2) + label = str(item.get("display_label", "Object")) + role = str(item.get("role", "")) + if role: + label = f"{label} [{role}]" + draw.text((label_x + 4, label_y - 10), label, fill=text_color, font=self.renderer.font) + + if show_regions: + label_budget: Dict[str, int] = {} + for region in annotation_bundle.get("region_annotations", []) or []: + bbox = region.get("bbox", {}) + box = ( + int(bbox.get("x", 0)), + int(bbox.get("y", 0)), + int(bbox.get("x", 0) + bbox.get("width", 0)), + int(bbox.get("y", 0) + bbox.get("height", 0)), + ) + self.renderer._draw_region_shape( + draw, + box, + region, + outline=self.renderer._with_alpha(accent, 0.68), + width=2, + dash_length=6, + ) + object_id = str(region.get("object_id", "")) + label_budget[object_id] = label_budget.get(object_id, 0) + 1 + if label_budget[object_id] > 2: + continue + anchor = region.get("label_anchor", {}) + label_x = int(anchor.get("x", box[2] + 12)) + label_y = int(anchor.get("y", box[1] + 18)) + draw.line([(box[2], int((box[1] + box[3]) / 2)), (label_x, label_y)], fill=accent, width=1) + actions = list(region.get("actions") or []) + action_text = f" [{' / '.join(actions[:2])}]" if actions else "" + draw.text( + (label_x + 4, label_y - 10), + f"{region.get('display_label', 'Region')}{action_text}", + fill=accent, + font=self.renderer.font, + ) + + for layer in annotation_bundle.get("background_annotations", []) or []: + bbox = layer.get("bbox", {}) + draw.text( + (int(bbox.get("x", 0)) + 8, int(bbox.get("y", 0)) + 8), + str(layer.get("display_label", "")), + fill=muted, + font=self.renderer.font, + ) + + def _draw_building(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + accent = palette["accent"] + draw.rectangle([x0 + w * 0.12, y0 + h * 0.04, x1 - w * 0.08, y1], outline=line, width=3) + side = [(x1 - w * 0.08, y0 + h * 0.04), (x1, y0 + h * 0.1), (x1, y1 - h * 0.02), (x1 - w * 0.08, y1)] + draw.line(side + [side[0]], fill=self.renderer._with_alpha(line, 0.72), width=2) + rows, cols = 4, 3 + for row in range(rows): + for col in range(cols): + win_w = w * 0.12 + win_h = h * 0.1 + wx = x0 + w * (0.2 + col * 0.18) + wy = y0 + h * (0.14 + row * 0.16) + draw.rectangle([wx, wy, wx + win_w, wy + win_h], outline=accent, width=2) + self._draw_door(draw, (int(x0 + w * 0.44), int(y0 + h * 0.7), int(x0 + w * 0.62), y1), palette) + for offset in (0.18, 0.34, 0.5, 0.66): + y = int(y0 + h * offset) + draw.line([(x0 + w * 0.14, y), (x1 - w * 0.1, y)], fill=self.renderer._with_alpha(line, 0.22), width=1) + + def _draw_house(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + roof = [(x0 + w * 0.5, y0), (x0 + w * 0.12, y0 + h * 0.28), (x1 - w * 0.12, y0 + h * 0.28)] + draw.line(roof + [roof[0]], fill=line, width=3) + draw.rectangle([x0 + w * 0.16, y0 + h * 0.28, x1 - w * 0.16, y1], outline=line, width=3) + self._draw_window(draw, (int(x0 + w * 0.26), int(y0 + h * 0.42), int(x0 + w * 0.4), int(y0 + h * 0.56)), palette) + self._draw_window(draw, (int(x0 + w * 0.6), int(y0 + h * 0.42), int(x0 + w * 0.74), int(y0 + h * 0.56)), palette) + self._draw_door(draw, (int(x0 + w * 0.42), int(y0 + h * 0.56), int(x0 + w * 0.58), y1), palette) + + def _draw_tree(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + draw.line([(x0 + w * 0.5, y0 + h * 0.44), (x0 + w * 0.5, y1)], fill=line, width=4) + draw.line([(x0 + w * 0.5, y0 + h * 0.56), (x0 + w * 0.36, y0 + h * 0.78)], fill=line, width=2) + draw.line([(x0 + w * 0.5, y0 + h * 0.5), (x0 + w * 0.64, y0 + h * 0.74)], fill=line, width=2) + crowns = [ + [x0 + w * 0.2, y0 + h * 0.12, x0 + w * 0.54, y0 + h * 0.5], + [x0 + w * 0.42, y0 + h * 0.02, x0 + w * 0.82, y0 + h * 0.42], + [x0 + w * 0.58, y0 + h * 0.14, x0 + w * 0.92, y0 + h * 0.48], + ] + for crown in crowns: + draw.ellipse(crown, outline=line, width=3) + draw.line([(x0 + w * 0.28, y0 + h * 0.32), (x0 + w * 0.74, y0 + h * 0.26)], fill=self.renderer._with_alpha(line, 0.22), width=1) + + def _draw_person(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + head_box = [x0 + w * 0.34, y0, x0 + w * 0.64, y0 + h * 0.24] + draw.ellipse(head_box, outline=line, width=3) + neck = (x0 + w * 0.49, y0 + h * 0.24) + chest = (x0 + w * 0.49, y0 + h * 0.48) + hip = (x0 + w * 0.5, y0 + h * 0.62) + draw.line([neck, chest, hip], fill=line, width=4) + draw.line([(x0 + w * 0.5, y0 + h * 0.32), (x0 + w * 0.3, y0 + h * 0.48)], fill=line, width=3) + draw.line([(x0 + w * 0.5, y0 + h * 0.32), (x0 + w * 0.68, y0 + h * 0.46)], fill=line, width=3) + draw.line([hip, (x0 + w * 0.34, y1)], fill=line, width=4) + draw.line([hip, (x0 + w * 0.68, y1)], fill=line, width=4) + draw.line([(x0 + w * 0.5, y0 + h * 0.4), (x0 + w * 0.44, y0 + h * 0.58)], fill=self.renderer._with_alpha(line, 0.3), width=1) + draw.line([(x0 + w * 0.5, y0 + h * 0.4), (x0 + w * 0.58, y0 + h * 0.58)], fill=self.renderer._with_alpha(line, 0.3), width=1) + + def _draw_car(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + accent = palette["accent"] + body = [x0 + w * 0.08, y0 + h * 0.38, x1 - w * 0.08, y0 + h * 0.76] + draw.rounded_rectangle(body, radius=max(10, int(w * 0.08)), outline=line, width=3) + roof = [(x0 + w * 0.24, y0 + h * 0.38), (x0 + w * 0.38, y0 + h * 0.16), (x0 + w * 0.7, y0 + h * 0.16), (x0 + w * 0.84, y0 + h * 0.38)] + draw.line(roof + [roof[0]], fill=line, width=3) + draw.line([(x0 + w * 0.42, y0 + h * 0.2), (x0 + w * 0.34, y0 + h * 0.38)], fill=accent, width=2) + draw.line([(x0 + w * 0.56, y0 + h * 0.2), (x0 + w * 0.66, y0 + h * 0.38)], fill=accent, width=2) + wheel_r = max(6, int(min(w, h) * 0.12)) + self.renderer._draw_circle(draw, (x0 + w * 0.3, y0 + h * 0.78), wheel_r, outline=line, fill=None, width=3) + self.renderer._draw_circle(draw, (x0 + w * 0.72, y0 + h * 0.78), wheel_r, outline=line, fill=None, width=3) + + def _draw_street_lamp(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + w = x1 - x0 + h = y1 - y0 + line = palette["line"] + accent = palette["accent"] + pole_x = x0 + w * 0.48 + top_y = y0 + h * 0.18 + draw.line([(pole_x, y1), (pole_x, top_y)], fill=line, width=4) + draw.line([(pole_x, top_y), (x0 + w * 0.86, top_y)], fill=line, width=3) + lamp_box = [x0 + w * 0.72, y0 + h * 0.16, x0 + w * 0.92, y0 + h * 0.26] + draw.arc(lamp_box, start=180, end=360, fill=line, width=3) + draw.line([(x0 + w * 0.82, y0 + h * 0.26), (x0 + w * 0.74, y0 + h * 0.34)], fill=line, width=2) + for ratio in (0.0, -0.08, 0.08): + draw.line( + [(x0 + w * 0.82, y0 + h * 0.28), (x0 + w * (0.62 + ratio), y0 + h * 0.62)], + fill=self.renderer._with_alpha(accent, 0.5), + width=1, + ) + + def _draw_window(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + accent = palette["accent"] + draw.rectangle([x0, y0, x1, y1], outline=accent, width=2) + draw.line([((x0 + x1) / 2, y0), ((x0 + x1) / 2, y1)], fill=accent, width=1) + + def _draw_door(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + accent = palette["accent"] + draw.rectangle([x0, y0, x1, y1], outline=accent, width=2) + self.renderer._draw_circle(draw, (x1 - 5, (y0 + y1) / 2), 2, outline=accent, fill=accent, width=1) + + def _draw_road(self, draw: ImageDraw.ImageDraw, bbox: Tuple[int, int, int, int], palette: Dict[str, Tuple[int, int, int]]) -> None: + x0, y0, x1, y1 = bbox + mid_x = int((x0 + x1) / 2) + draw.line([(x0, y1), (x0 + 30, y0 + 20)], fill=self.renderer._with_alpha(palette["line"], 0.5), width=2) + draw.line([(x1, y1), (x1 - 30, y0 + 20)], fill=self.renderer._with_alpha(palette["line"], 0.5), width=2) + self.renderer._draw_dashed_line(draw, (mid_x, y0 + 20), (mid_x, y1 - 12), palette["accent"], width=2, dash_length=16) + + def _draw_light_beam( + self, + draw: ImageDraw.ImageDraw, + start: Tuple[float, float], + end: Tuple[float, float], + palette: Dict[str, Tuple[int, int, int]], + ) -> None: + accent = self.renderer._with_alpha(palette["accent"], 0.42) + self.renderer._draw_dashed_line(draw, start, end, accent, width=1, dash_length=12) + + def _scene_markers(self, scene: Dict[str, Any]) -> List[Dict[str, Any]]: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + markers: List[Dict[str, Any]] = [] + if str((scene.get("layout_options", {}) or {}).get("scene_type", "scene")) == "scene": + markers.append({"type": "horizon_line", "x": 0, "y": int(height * 0.56), "width": width, "display_label": "Horizon"}) + for obj in scene.get("object_instances", []) or []: + asset_key = str(obj.get("asset_key", "")) + if asset_key in {"sun", "street_lamp", "desk_lamp"}: + bbox = self.renderer._scene_bbox(obj) + markers.append( + { + "type": "light_source", + "object_id": str(obj.get("id", "")), + "label": str(obj.get("concept", "") or asset_key), + "display_label": "Light", + "x": int((bbox[0] + bbox[2]) / 2), + "y": bbox[1], + } + ) + return markers + + def _label_anchor_for_object(self, obj: Dict[str, Any]) -> Dict[str, int]: + x0, y0, x1, y1 = self.renderer._scene_bbox(obj) + role = str(obj.get("role", "")) + depth = str(obj.get("depth_band", "")) + if role in {"subject", "focus", "core_subject"}: + return {"x": x1 + 18, "y": y0 + 26} + if depth == "background": + return {"x": x0 + 10, "y": max(24, y0 - 18)} + return {"x": x1 + 10, "y": y0 + 16} + + def _edit_controls_for_object(self, obj: Dict[str, Any]) -> List[str]: + controls = ["move", "scale", "delete"] + if obj.get("editable", True): + controls.extend(["swap_variant", "restyle"]) + if obj.get("region_masks"): + controls.append("edit_regions") + return controls + + def _bbox_payload(self, bbox: Tuple[int, int, int, int]) -> Dict[str, int]: + x0, y0, x1, y1 = bbox + return {"x": int(x0), "y": int(y0), "width": int(x1 - x0), "height": int(y1 - y0)} + + def _safe_text(self, value: Any) -> str: + text = str(value or "").replace("\n", " ").replace("\r", " ").strip() + return " ".join(text.split()) + + def _display_label(self, obj: Dict[str, Any]) -> str: + asset_key = str(obj.get("asset_key", "")).strip().lower() + concept = self._safe_text(obj.get("concept", "")) + if concept and concept.isascii(): + return concept + return DISPLAY_LABELS.get(asset_key, asset_key or "Object") + + def _region_display_label(self, region: Dict[str, Any]) -> str: + region_id = str(region.get("id", "")).strip().lower() + if region_id in REGION_LABELS: + return REGION_LABELS[region_id] + label = self._safe_text(region.get("label", "")) + if label and label.isascii(): + return label + if region_id and region_id.isascii(): + return region_id.replace("_", " ").title() + return "Region" + + def _layer_display_label(self, layer: Dict[str, Any]) -> str: + layer_type = str(layer.get("type", "panel")).strip().lower() + return {"sky": "Sky", "road": "Road", "ground": "Ground", "water": "Water"}.get(layer_type, layer_type.title()) + + def _connector_display_label(self, connector: Dict[str, Any]) -> str: + connector_type = str(connector.get("type", "relation")).strip().lower() + return {"beam": "Light direction", "arrow": "Relation", "wire": "Connection"}.get(connector_type, "Relation") + + def _build_condition_maps(self, scene: Dict[str, Any]) -> np.ndarray: + width = int(scene.get("canvas_size", {}).get("width", 1024)) + height = int(scene.get("canvas_size", {}).get("height", 768)) + channels: List[np.ndarray] = [] + channels.append(self._mask_from_background(scene, width, height)) + channels.append(self._mask_from_objects(scene, width, height, roles={"subject", "focus", "core_subject"})) + channels.append(self._mask_from_objects(scene, width, height, roles={"support", "detail", ""})) + channels.append(self._mask_from_connectors(scene, width, height)) + channels.append(self._mask_from_regions(scene, width, height)) + channels.append(self._depth_map(scene, width, height)) + return np.stack(channels, axis=2).astype(np.float32) + + def _mask_from_background(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for layer in scene.get("background_layers", []) or []: + x0, y0, x1, y1 = self.renderer._scene_bbox(layer) + draw.rectangle([x0, y0, x1, y1], fill=255) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _mask_from_objects(self, scene: Dict[str, Any], width: int, height: int, roles: set[str]) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for obj in scene.get("object_instances", []) or []: + if roles and str(obj.get("role", "")) not in roles: + continue + draw.rectangle(self.renderer._scene_bbox(obj), fill=255) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _mask_from_connectors(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + objects_by_id = {item["id"]: item for item in scene.get("object_instances", []) or [] if item.get("id")} + for connector in scene.get("connectors", []) or []: + if not connector.get("visible", True): + continue + from_obj = objects_by_id.get(str(connector.get("from_id", ""))) + to_obj = objects_by_id.get(str(connector.get("to_id", ""))) + if not from_obj or not to_obj: + continue + start, end = self.renderer._connector_points_for_scene(from_obj, to_obj) + draw.line([start, end], fill=255, width=3) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _mask_from_regions(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = Image.new("L", (width, height), 0) + draw = ImageDraw.Draw(image) + for obj in scene.get("object_instances", []) or []: + for region in obj.get("region_masks", []) or []: + if not isinstance(region, dict): + continue + box = self.renderer._region_box_for_object(obj, region) + if str(region.get("shape", "rect")) == "ellipse": + draw.ellipse(box, fill=255) + else: + draw.rectangle(box, fill=255) + return np.asarray(image, dtype=np.float32) / 255.0 + + def _depth_map(self, scene: Dict[str, Any], width: int, height: int) -> np.ndarray: + image = np.zeros((height, width), dtype=np.float32) + mapping = {"background": 0.25, "midground": 0.58, "foreground": 0.9} + for obj in scene.get("object_instances", []) or []: + x0, y0, x1, y1 = self.renderer._scene_bbox(obj) + image[max(0, y0):max(0, y1), max(0, x0):max(0, x1)] = mapping.get(str(obj.get("depth_band", "")), 0.46) + return image diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Install-TmcraLocal.ps1 b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Install-TmcraLocal.ps1 new file mode 100644 index 0000000..6067506 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Install-TmcraLocal.ps1 @@ -0,0 +1,68 @@ +[CmdletBinding()] +param( + [ValidateSet('lite-cpu','balanced-bge','quality-qwen')][string]$Profile = 'lite-cpu', + [string]$DataDir = (Join-Path $env:LOCALAPPDATA 'TMCRA\local'), + [ValidateSet('auto','cpu','cuda')][string]$Device = 'auto', + [switch]$PrepareOnly, + [switch]$WaitReady +) +$ErrorActionPreference = 'Stop' +$apiRoot = Split-Path -Parent $PSScriptRoot +$localData = [IO.Path]::GetFullPath($DataDir) +if ([IO.Path]::GetPathRoot($localData) -eq $localData) { throw 'Choose a dedicated TMCRA data folder.' } +foreach ($broadPath in @($env:USERPROFILE,$env:LOCALAPPDATA,$env:APPDATA)) { + if ($broadPath -and $localData.TrimEnd('\') -eq [IO.Path]::GetFullPath($broadPath).TrimEnd('\')) { throw 'Choose a dedicated TMCRA data folder.' } +} +if ($env:TMCRA_CONFIG_FILE) { throw 'An explicit TMCRA_CONFIG_FILE override is active. Clear this advanced override before choosing automatic local installation.' } +. (Join-Path $PSScriptRoot 'Local-SetupHelpers.ps1') +Protect-TmcraLocalPath $localData -Directory +$setupLock = [IO.File]::Open((Join-Path $localData 'setup.lock'),[IO.FileMode]::OpenOrCreate,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None) +try { + # The supervisor holds run.lock for its full lifetime. Do not update an active environment. + $runProbe = [IO.File]::Open((Join-Path $localData 'run.lock'),[IO.FileMode]::OpenOrCreate,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None) + $runProbe.Dispose() + Select-TmcraLocalProfile $localData $Profile + $apiRoot = Copy-TmcraManagedRuntime $apiRoot $localData + Remove-Item Env:TMCRA_DEPLOYMENT_MODE,Env:PYTHONPATH -ErrorAction SilentlyContinue + Enable-TmcraDownloadProxy + $localPython = Get-TmcraLocalPython $localData +$useCuda = $Device -eq 'cuda' +if ($Device -eq 'auto' -and (Get-Command nvidia-smi -ErrorAction SilentlyContinue)) { + & nvidia-smi --query-gpu=name --format=csv,noheader 2>$null | Out-Null + $useCuda = $LASTEXITCODE -eq 0 +} +if ($useCuda) { + & $localPython -m pip install 'torch==2.10.0' --index-url https://download.pytorch.org/whl/cu128 +} else { + & $localPython -m pip install 'torch==2.10.0' --index-url https://download.pytorch.org/whl/cpu +} +if ($LASTEXITCODE -ne 0) { throw 'PyTorch installation failed.' } +& $localPython -m pip install -r (Join-Path $apiRoot 'requirements-tmcra-service.txt') 'transformers==4.57.6' 'huggingface-hub==0.36.2' 'sentencepiece==0.2.1' 'safetensors==0.8.0' +if ($LASTEXITCODE -ne 0) { throw 'Local dependency installation failed.' } +$env:PATH = (Split-Path -Parent $localPython) + [IO.Path]::PathSeparator + $env:PATH +Push-Location $apiRoot +try { + $runtimeDevice = if ($useCuda) { 'cuda' } else { 'cpu' } + & $localPython -m tmcra_service.local_deployment prepare --root $localData --profile $Profile --device $runtimeDevice --auto-ports + if ($LASTEXITCODE -ne 0) { throw 'Local model preparation failed; retained downloads can be resumed.' } + if (-not $PrepareOnly) { + $arguments = '-m tmcra_service.local_deployment run --root "{0}"' -f $localData + $service = Start-Process -FilePath $localPython -ArgumentList $arguments -WorkingDirectory $apiRoot -WindowStyle Hidden -RedirectStandardError (Join-Path $localData 'launcher-error.log') -RedirectStandardOutput (Join-Path $localData 'launcher.log') -PassThru + Write-Output '{"event":"starting","message":"Local services are performing their full startup checks."}' + if ($WaitReady) { + $receipt = Get-Content -Raw -LiteralPath (Join-Path $localData 'installation.json') | ConvertFrom-Json + $deadline = [DateTime]::UtcNow.AddMinutes(15) + do { + $service.Refresh() + if ($service.HasExited) { throw 'Local service exited during startup; inspect launch-error.json. The local selection is retained.' } + try { + $ready = Invoke-RestMethod -Uri "http://127.0.0.1:$($receipt.api_port)/readyz" -TimeoutSec 3 + if ($ready.status -eq 'ready' -or $ready.ready -eq $true) { Write-Output '{"event":"ready","message":"Local memory is ready; no TMCRA account or server is required."}'; return } + } catch { } + Start-Sleep -Seconds 2 + } while ([DateTime]::UtcNow -lt $deadline) + throw 'Startup did not reach ready in 15 minutes; inspect the retained local logs.' + } + } +} finally { Pop-Location } +} finally { $setupLock.Dispose() } diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Local-SetupHelpers.ps1 b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Local-SetupHelpers.ps1 new file mode 100644 index 0000000..3373d4a --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Local-SetupHelpers.ps1 @@ -0,0 +1,91 @@ +function Protect-TmcraLocalPath([string]$Path, [switch]$Directory) { + if ($Directory) { New-Item -ItemType Directory -Force -Path $Path | Out-Null } + $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value + $rights = if ($Directory) { '(OI)(CI)F' } else { 'F' } + & icacls.exe $Path /inheritance:r /grant:r "*${sid}:$rights" "*S-1-5-18:$rights" | Out-Null + if ($LASTEXITCODE -ne 0) { throw 'Could not protect the local installation directory.' } +} + +function Select-TmcraLocalProfile([string]$DataRoot, [string]$Profile) { + if ($Profile -notin @('lite-cpu','balanced-bge','quality-qwen')) { throw 'Unknown local model profile.' } + $selectionFile = if ($env:TMCRA_LOCAL_BINDING_FILE) { $env:TMCRA_LOCAL_BINDING_FILE } else { Join-Path $env:USERPROFILE '.config\tmcra\local-memory.json' } + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $selectionFile) | Out-Null + $temporarySelection = "$selectionFile.$([guid]::NewGuid().ToString('N')).tmp" + $selection = @{schemaVersion=1;mode='local';dataRoot=[IO.Path]::GetFullPath($DataRoot);profile=$Profile} + [IO.File]::WriteAllText($temporarySelection, ($selection | ConvertTo-Json), [Text.UTF8Encoding]::new($false)) + Protect-TmcraLocalPath $temporarySelection + if (Test-Path -LiteralPath $selectionFile) { + # Windows PowerShell 5 converts a null backup argument to an invalid empty path. + # Retain a private, non-secret selection backup and replace the marker atomically. + $previousSelection = "$temporarySelection.previous" + [IO.File]::Replace($temporarySelection,$selectionFile,$previousSelection) + Protect-TmcraLocalPath $previousSelection + } + else { [IO.File]::Move($temporarySelection,$selectionFile) } + Protect-TmcraLocalPath $selectionFile +} + +function Copy-TmcraManagedRuntime([string]$Source, [string]$DataRoot) { + $manifestPath = Join-Path $Source 'runtime-files.json' + if (-not (Test-Path -LiteralPath $manifestPath)) { throw 'Runtime inventory is missing; use the complete local installation package.' } + $manifest = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json + $identity = (Get-FileHash -Algorithm SHA256 -LiteralPath $manifestPath).Hash.ToLowerInvariant().Substring(0,24) + $destination = Join-Path $DataRoot "service\$identity" + $sourcePrefix = [IO.Path]::GetFullPath($Source).TrimEnd('\') + '\' + $destinationPrefix = [IO.Path]::GetFullPath($destination).TrimEnd('\') + '\' + foreach ($entry in $manifest.PSObject.Properties) { + $inputPath = [IO.Path]::GetFullPath((Join-Path $Source $entry.Name)) + $outputPath = [IO.Path]::GetFullPath((Join-Path $destination $entry.Name)) + if (-not $inputPath.StartsWith($sourcePrefix,[StringComparison]::OrdinalIgnoreCase) -or + -not $outputPath.StartsWith($destinationPrefix,[StringComparison]::OrdinalIgnoreCase)) { throw 'Unsafe runtime inventory path.' } + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $inputPath).Hash.ToLowerInvariant() -ne $entry.Value) { throw "Runtime integrity check failed: $($entry.Name)" } + if (Test-Path -LiteralPath $outputPath) { + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $outputPath).Hash.ToLowerInvariant() -ne $entry.Value) { throw 'Existing managed runtime was modified; inspect it before upgrading.' } + } else { + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $outputPath) | Out-Null + Copy-Item -LiteralPath $inputPath -Destination $outputPath + } + } + Copy-Item -LiteralPath $manifestPath -Destination (Join-Path $destination 'runtime-files.json') + return $destination +} + +function Enable-TmcraDownloadProxy { + # Respect a user's Windows proxy for installation only. Runtime strips proxies. + if ($env:HTTPS_PROXY) { return } + $settings = Get-ItemProperty -LiteralPath 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -ErrorAction SilentlyContinue + if ($settings.ProxyEnable -eq 1 -and $settings.ProxyServer -match '^(?:http://)?(127\.0\.0\.1:\d{1,5})$') { + $env:HTTPS_PROXY = "http://$($Matches[1])" + $env:HTTP_PROXY = $env:HTTPS_PROXY + $env:NO_PROXY = '127.0.0.1,localhost,::1' + } +} + +function Get-TmcraLocalPython([string]$DataRoot) { + $localPython = Join-Path $DataRoot 'venv\Scripts\python.exe' + if (Test-Path -LiteralPath $localPython) { + & $localPython -c 'import sys; assert (3,11) <= sys.version_info[:2] < (3,13) and sys.maxsize > 2**32' + if ($LASTEXITCODE -ne 0) { throw 'The existing local Python is incompatible; retain its data and inspect the environment.' } + return $localPython + } + $uvRoot = Join-Path $DataRoot 'runtime\uv-0.12.10' + New-Item -ItemType Directory -Force -Path $uvRoot | Out-Null + $archive = Join-Path $uvRoot 'uv.zip' + $expected = 'f65744f94072152b1f86ba2aace4d01f1124d9a8ecb235805039e3718c36cac2' + if (-not (Test-Path -LiteralPath $archive) -or (Get-FileHash -Algorithm SHA256 -LiteralPath $archive).Hash.ToLowerInvariant() -ne $expected) { + Write-Output '{"event":"installing_python","message":"Downloading the pinned Python environment manager."}' | Write-Host + $partial = "$archive.partial" + $download = @{UseBasicParsing=$true;Uri='https://github.com/astral-sh/uv/releases/download/0.12.10/uv-x86_64-pc-windows-msvc.zip';OutFile=$partial} + if ($env:HTTPS_PROXY) { $download.Proxy = $env:HTTPS_PROXY } + Invoke-WebRequest @download + if ((Get-FileHash -Algorithm SHA256 -LiteralPath $partial).Hash.ToLowerInvariant() -ne $expected) { throw 'Python bootstrap checksum mismatch.' } + Move-Item -LiteralPath $partial -Destination $archive -Force + } + Expand-Archive -LiteralPath $archive -DestinationPath $uvRoot -Force + $uv = Join-Path $uvRoot 'uv.exe' + $env:UV_PYTHON_INSTALL_DIR = Join-Path $DataRoot 'runtime\python' + $env:UV_CACHE_DIR = Join-Path $DataRoot 'cache\uv' + & $uv venv --python 3.12 --managed-python --seed (Join-Path $DataRoot 'venv') | Out-Host + if ($LASTEXITCODE -ne 0) { throw 'Automatic Python installation failed; downloaded files are retained for retry.' } + return $localPython +} diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Start-TmcraLocal.ps1 b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Start-TmcraLocal.ps1 new file mode 100644 index 0000000..e7b00e5 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/Start-TmcraLocal.ps1 @@ -0,0 +1,11 @@ +[CmdletBinding()] +param([string]$DataDir = (Join-Path $env:LOCALAPPDATA 'TMCRA\local')) +$ErrorActionPreference = 'Stop' +$apiRoot = Split-Path -Parent $PSScriptRoot +$localData = [IO.Path]::GetFullPath($DataDir) +$localPython = Join-Path $localData 'venv\Scripts\python.exe' +if (-not (Test-Path -LiteralPath $localPython)) { throw 'Run Install-TmcraLocal.ps1 first.' } +$receipt = Get-Content -Raw -LiteralPath (Join-Path $localData 'installation.json') | ConvertFrom-Json +if ($receipt.api_root) { $apiRoot = $receipt.api_root } +$arguments = '-m tmcra_service.local_deployment run --root "{0}"' -f $localData +Start-Process -FilePath $localPython -ArgumentList $arguments -WorkingDirectory $apiRoot -WindowStyle Hidden -RedirectStandardError (Join-Path $localData 'launcher-error.log') -RedirectStandardOutput (Join-Path $localData 'launcher.log') diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-bootstrap/sitecustomize.py b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-bootstrap/sitecustomize.py new file mode 100644 index 0000000..76a9071 --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-bootstrap/sitecustomize.py @@ -0,0 +1,12 @@ +"""Loaded by every Python worker in the explicit full-local launch environment.""" +import os + +if os.environ.get("TMCRA_DEPLOYMENT_MODE") == "local": + try: + from tmcra_local_only import install_network_guard, validate_environment + validate_environment(os.environ) + install_network_guard() + except Exception: + # CPython normally ignores sitecustomize exceptions. Fail closed instead. + os.write(2, b"TMCRA local network boundary failed; refusing to start.\n") + os._exit(78) diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-model-profiles.json b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-model-profiles.json new file mode 100644 index 0000000..460605c --- /dev/null +++ b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/deploy/local-model-profiles.json @@ -0,0 +1,132 @@ +{ + "schema_version": "tmcra.local-model-profiles.1", + "verified_upstream_on": "2026-09-06", + "status": "windows_local_preview_partial_validation", + "installation_enabled": true, + "scope": "full_local_runtime_preview", + "full_memory_system_ready": false, + "hardware_requirements_are": "conservative_planning_estimates_not_benchmark_results", + "profiles": [ + { + "id": "lite-cpu", + "name_zh": "轻量版", + "recommendation_zh": "普通笔记本、无独显电脑;中英文短记忆,低并发", + "validation": "cpu_ingest_and_raw_recall_passed_complex_compile_timed_out", + "system_ram_gib_min": 8, + "system_ram_gib_recommended_for_full_memory": 16, + "retrieval_vram_gib_recommended": 0, + "weights_bytes": 941234298, + "embedding": { + "repo_id": "intfloat/multilingual-e5-small", + "revision": "614241f622f53c4eeff9890bdc4f31cfecc418b3", + "license": "MIT", + "upstream": "https://huggingface.co/intfloat/multilingual-e5-small", + "weights": [{"file": "model.safetensors", "bytes": 470641600, "sha256": "1a55775f53449dac10a2bcbc312469fac40b96d53198c407081a831f81c98477"}], + "dimensions": 384, + "model_max_tokens": 512, + "pooling": "mean", + "normalize": true, + "query_prefix": "query: ", + "document_prefix": "passage: ", + "padding_side": "right" + }, + "reranker": { + "repo_id": "cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "revision": "1427fd652930e4ba29e8149678df786c240d8825", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1", + "weights": [{"file": "model.safetensors", "bytes": 470592698, "sha256": "5daeca2481a76b5976a2bdc32f0a78532b6716da4f8cd3ff59460ef8d2f359b4"}], + "adapter": "sequence-classification", + "model_max_tokens": 512, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["memory_pressure_retest", "complex_compile_latency", "organizer_validation", "full_service_restart_validation"] + }, + { + "id": "balanced-bge", + "name_zh": "均衡版", + "recommendation_zh": "优先复现现有生产检索模型;16GB 以上内存,建议有独显", + "validation": "production_model_stack_verified_consumer_installer_pending", + "system_ram_gib_min": 16, + "system_ram_gib_recommended_for_full_memory": 32, + "retrieval_vram_gib_recommended": 6, + "weights_bytes": 4542217682, + "embedding": { + "repo_id": "BAAI/bge-m3", + "revision": "5617a9f61b028005a4858fdac845db406aefb181", + "license": "MIT", + "upstream": "https://huggingface.co/BAAI/bge-m3", + "weights": [{"file": "pytorch_model.bin", "bytes": 2271145830, "sha256": "b5e0ce3470abf5ef3831aa1bd5553b486803e83251590ab7ff35a117cf6aad38"}], + "dimensions": 1024, + "model_max_tokens": 8192, + "pooling": "cls", + "normalize": true, + "query_prefix": "", + "document_prefix": "", + "padding_side": "right" + }, + "reranker": { + "repo_id": "BAAI/bge-reranker-v2-m3", + "revision": "953dc6f6f85a1b2dbfca4c34a2796e7dde08d41e", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/BAAI/bge-reranker-v2-m3", + "weights": [{"file": "model.safetensors", "bytes": 2271071852, "sha256": "d9e3e081faff1eefb84019509b2f5558fd74c1a05a2c7db22f74174fcedb5286"}], + "adapter": "sequence-classification", + "model_max_tokens": 8192, + "production_runtime_max_tokens": 1280, + "tmcra_fusion_checkpoint_compatible": true + }, + "required_work": ["single_recall_lane", "desktop_worker_and_context_budgets", "desktop_installer", "offline_end_to_end_validation"] + }, + { + "id": "quality-qwen", + "name_zh": "增强版候选", + "recommendation_zh": "32GB 以上内存、高显存电脑;长文本和跨语言检索候选,需与均衡版实测比较", + "validation": "upstream_artifacts_verified_runtime_pending", + "system_ram_gib_min": 32, + "system_ram_gib_recommended_for_full_memory": 64, + "retrieval_vram_gib_recommended": 16, + "weights_bytes": 9235180368, + "embedding": { + "repo_id": "Qwen/Qwen3-Embedding-4B", + "revision": "5cf2132abc99cad020ac570b19d031efec650f2b", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Embedding-4B", + "weights": [ + {"file": "model-00001-of-00002.safetensors", "bytes": 4965826464, "sha256": "e70bfe3c970523fb7ef4eddffed2254ce3f1e7150c3de2af4342de129dd756f8"}, + {"file": "model-00002-of-00002.safetensors", "bytes": 3077765624, "sha256": "ed1b87c8e9eb7e535a1a155e4fd00d9f4dba80e58a6db48a4c9f82cede7079c1"} + ], + "dimensions": 2560, + "model_max_tokens": 32768, + "pooling": "last_token", + "normalize": true, + "query_prefix": "Instruct: Given a query about previous conversations, retrieve the relevant source passages.\nQuery: ", + "document_prefix": "", + "padding_side": "left" + }, + "reranker": { + "repo_id": "Qwen/Qwen3-Reranker-0.6B", + "revision": "e61197ed45024b0ed8a2d74b80b4d909f1255473", + "license": "Apache-2.0", + "upstream": "https://huggingface.co/Qwen/Qwen3-Reranker-0.6B", + "weights": [{"file": "model.safetensors", "bytes": 1191588280, "sha256": "27cd75a405b9c1b46b59abfd88aaa209e6fed2a1972cde9b70e7659537c5e65b"}], + "adapter": "causal-lm-yes-no", + "model_max_tokens": 32768, + "tmcra_fusion_checkpoint_compatible": false + }, + "required_work": ["qwen_yes_no_reranker_adapter", "service_variable_embedding_dimensions", "bounded_gpu_batches", "full_index_rebuild", "quality_and_latency_comparison"] + } + ], + "deployment_contract": { + "automatic_profile_switch_on_existing_index": false, + "cloud_fallback_in_full_local_mode": false, + "cloud_account_required_in_full_local_mode": false, + "generation_model_included_in_weights_bytes": false, + "model_cache_and_python_runtime_included_in_weights_bytes": false, + "required_index_identity": ["repo_id", "revision", "dimensions", "pooling", "query_prefix", "document_prefix", "normalization", "precision", "chunking_policy"], + "existing_sources_must_be_preserved": true, + "existing_indexes_must_be_rebuilt_before_activation": true, + "runtime_downloads_after_setup": false, + "readiness_requires_actual_inference": true + } +} diff --git a/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/models/tmcra_v3_reranker.pt b/07-tmcra-codex-plugins/tmcra-memory/runtime/memory-api/models/tmcra_v3_reranker.pt new file mode 100644 index 0000000000000000000000000000000000000000..75d77dabea8fdc9a3217a075339254a3eda851ab GIT binary patch literal 4234837 zcmb?>2Urx%(k>t%BB&sWii#*IiXvHdy4N;>iV+ntB2kdI!-9&kJBxr>#E7COikJa2 zJKbx}5p%+bIp-X1?V{g-b3eax{`+5^hn|_9>UygybxrpU@U3R3r)OfK_kaC0(KFJM z$As`ffk|$Gd>9`T8x_Vo#mhT{2FZh*;-jLyyXxx=7YtHldJX}#V0c1EL|6<^hw%xK zaj`P}fCkX1I(8ME z;gPXH(K3?&GXMZN!eT=v2FAwmF|rzRnW?TfCN2~t35kmhj~pwjnIbcD2rvcWh{#ZY z4-Acrk(vAM4KRkT=%9%(Nm(slgG3!d#mEGCkUUIQJ0v77T8j@lNHFcshlcTCq1_`x zBLFYLDx!j)i_Eq%zh+u~cE9*F*Yayo z!OvbUYw0Iz70?)D;KSniu!OK!PzmTEFrJSa=j7}(J}h!~!+@#AKwE*oZ0NTrCPJXfu0ge6$5F8nlAakz5-c9CGnZ2uyz1wg0?ppR973@9b zvW|W-uRqG~@>_mM6##b`R~Z2H*3+w|CzoNZhV}wlhD-{ruYQKCQw0u@%R2kXy8Lk( zE>5~>bghEoA?sEdrMvH5xvYl{B3=2O!(1ox;3}*;%7#>C?XP7$^q0&5 zTA7DcupKU!jqsC=45$Zee+NcYj~P{kua|6eWxj!Z1@M?L6*3!V$bx*0wK4}+Fb|Q- zLj7c60d@ax<~otXtFV^H##Uw>p%ppum&oI^B1ctljh4$|{A96JL>>#_|1T$x`-`su zAiFrr;wv+j_10^quP2xBI^KN+kT(HZt=#eoghaV4$xk-Eirl{tbaGFq%HKscu`>T; zt>BY>2|igXcuECZgXLw+cTpsHbSrNB^zoJ%E z70^|dS{ZOkZ@psegwg=BZ)XGFy&1A}-@V%TWK;l8mCL62$)*Q5{`bJTdCsT`>n597 z8Fm(6$z`)EK+|P&v@^}D0GunAW%(tMU4EK>invh?y?1yF&FmL1Kx{t z%GJ(uam75dD`1z%WlQ~JIRWkd2e7({E~^UaAzNMYFh=&cDZbapKRxUnw9JCl)S4dke95aGLZV$tVEsu05wBK zwN47&$tv(Pa@lS_*`EJ2E!T?FytgWvM7FOo+J3F64*W9JLG7dtRe&6p%Z~WTj{X@$ zTaWx@sAE+?T%BddD}$WSf}H#Xa!Lzwx&q{kTvqBQI~!p8Cj(W0=*)AjDuj#dd}W9W zT8N9kATDVkE>}QYk;|_7$*%qLJpMAx^{ODQva-q`H?$x(e}UZ6g50hExg(d|^^=wV z^E`gp<6cz=H`)El5D&Bv4}U>C(n370fOsO8J@u14`%^A-`ExFOUKP+?_M$T2%U|yH z3NW>9207w&MG(EI0Ddc%z4Md3|5GmfJ7Ar?K2(MEkbSHS`$-p0pDRGqWnZ*2{aOL| zO)mTHC;RcITv!?K-*e&5s+gX<9@LnXV0nFb)@DTB0B&?zh6(f4;6XQM-Vp9|Qt(D_ zC+Cf!_2a8U`==cFx8i6Oz?;CRs`7N?YiK!XtMZC^mp6rHusB~6t`$b-&9q(m>AX2y zD@3UUcXGZqw0?XYX#bRGT%4+=Pu>EEt4iR-TWT3plAta;SGWLg1-E~B0bdWEDwI+m z?kXg)hC4am09rr3A+&#rs((qM(?la6tty9vx6ux-Bu8U-*7^kB1a5x01>Y3zwYso{ zYlQ?*h=2rk(E9Psq5V&~_#N4N3m~o{gPSvNuVqk4hL-UBOBb!+R%Z~9DT8kfPuk$n z&)^;4wnCIPa3|;6LhHvnLi?YTQ4#-qJ0Ptphzs9dJG_!0PVlUCiwMLF zTr2Qh;ZDxGLF>o6L;Gj^%Bh<70Me@XuDqvqcqROf@T|r6g6l7QiM9*yIk;BfBe;|E z7+ODG3hke=pNrGKvN+!f2&o0Wpde@o4@d+AcsJ0@n(3f4GzLL!tHKwcpXY${ThBA^?A z%c_W8e6)5zCBztb)}{SexY0ps(|#O0RAjh#xT}Db!JVAvq4nbvp#Ar0R($XBa(Go0 zRKh1}$t!^-!LxRn(!)zTp?@hAo12+;39t z2m9ZUIyv);b;Q~K4Y3QqL`S^zzae(zb9BVZDidor607WW@XK{Xxs{1(|2q*#xk5*_ z@}J3E_&gois>)>AUBt>;75r))O@3t>?Vf058US3Qqbm4EDi?mOj%r*oUT>yT) zj%Gt;n#y<;I|ckk9o43Pq;lam>!=DVQ)#zh6T<%59^i{~B*m3UEUS|I+CkvA=qR^V zrmWa5`it3Ldky?H9qsnYv`zn(Yvp|jeur+<&dQ@&|Hn~Izw26lmu`4T<>A^L%SyBT zOTgd7AFtMp5&x?(p?q9Cfbmo}hW%G#DvC^3UZWecyYd+AX6N6^rmFz>J-QKl|LYO1 z{65`?{gp>F`4h&kxw!BLbb}85PX@X2hjfDuS03~SS8(Bv=xC2tru~B}RQfvLkLgAo zuRQ7xu25;zzg*#jZurT{!~ft4e^uZ7DczXU|J9h^u5d;-ru4rW^V=29>c*U_JmwFs z@T(Z)&+A59_^(H}@)va@E>#}!2Ul=$`pXqA>jqu7A86e9`#PEjm1q(Z zf&;XP@psK#2wH~#IC9g|9{uo-;c*oIMBC{@%6cW=h8I3$Yv<)- zbT>!OHxzU?cU|l4t+;8K4_BbMwxx>zH(>!r(CUtD_@_E%&nlR0d$_$ByzwFXZ{)!h zZc67~t?0S6Re4+2b8E+=mAaermp$RC7nZ2w78V~D62U(QKE9^E4&;)wB?YgY#tZ09 z;a_S&0-({0$ys)StHjccf3JJ>(oOeQ8O?+LP0+A~HMPrjPALt7YxMF+(v0M~@D5Z(|veLBZ1KfZU0 zWt{Hquk+G`$mB5I2;Rcsm+l-jCTK!nbXe?Ic?55)>o(GX>CR61>RR6Rz`Fw<7bowa z>rCj-wM&;?9fHS(wf}wm+&;;*eT*A#qNUbWeH90q&}_6l`( z3FFPQBeWSTJ}8ohGvmZqId2YqeQPA?&UX`nV&bF2e!Zxreeq7e;s96oB7v_BeWUm~ zS~eqrO~tf-9k;u7;1gpLI%tpGfp26?*k3+dag<$g8m_gYb4M5FKo@6cFL#d)l^vo2 zKEY{RLR@S#ZviMle{)37TWaC|>6D(YtEJE_+S=%s!-;vI9E1wd9qaN|@OE0FP7iWE z2+oUw_^}CmJ?Ks0>qA>{W*rh20}dL>TWfh~{Yyv7H_$$6jaV`Cm&klWZTH~+KPss( zvyT5SRW#CaulS8YQs8e$8*S(C|DTZBJoC$TzknP62Cif#zKOPz{290sZD4|jv-5AB zft779ahLE-wT!f}s;zQEBYECd+tKyUoORs5Hzo$gBu2vu6$as4iK&aHt49Z2r<)7k zOv_9A`4kx&DG!8v6A~347YPn;2QS8Hza}H#hY=C*YY3eu1P94OA_8^c-y8^hO?3XF zjs6Nlhk!3c!pCV?0^dUWzOybvYBg37M)umyik}4N7NP{crM9O*0JM71Jl_hgKBST7 z-KUMawbun(#i?CjDEzu)BHvo~IxYE*PodQ$T^6kbN!F|uYUjI$^Djxh8 zPC&!>Ht@>VNVhI)r_Hz3KHKWnw2=5j-Vq+BCnh=#@U3og^TTGx7tQtbwEqMC`0E*a zz0QCC>lvqTIOGYE|NfbbcUP=8{D1N1q7`Y^%QEfugP!*P&my(fYx@V0e*LPXVo8jF zUu}4IZS`MD<>{^!fQ*+t1{G=7n12wUsh;cK3lKa}9u}wlrHpr1r~eZ7x5}a;sk$>=SKv)&BpJM7IARk&Aa%n}3ohPr5>C^1ObhV;O0ke$M~isYlWGPQ~h6 z9sY$Dt!n;n@m>D|{_74((!@$2n{O*fh)PLX^-__LLjoD%qa>bkCHZ8nBzglB)1H9`r zL?Danrjon_CD{V>V>&9yXOJVGQ;`=7m1MN9KxTGR5f7N>m)=UE0UZ?PD@iDfGY9$C zUIjh$Q;~Y_1#%hWU@w*Afu)i-83J!Rfn?e!Nz6ATxm&0t(-)|SmAis8@KusWo0TL4 z^tZaZf|SQjA-*3Kr0BkaBrgN}K?<^Y!4&c!S3#yYD9Mpk0@<1`kXOT%Wc_6&S@1|n z(rg6MxuKFY2o^|OM-}PbN+8t(l%%bxlDvpelEbr?)8oSCz#7r;@C6 z5{SVeC7Esf(}4_A_%&H`ywLm-RBf*l4Z$!oCvSA7*R z7%7l6z*{g-Nm6SoNnVJOTvsZ|3GfBmqYAR#S3wppRgtf|lw`+du#a&ni2}Qu)PZ?| ztxi-|5$8cl(l=2_Ue#BU&iw?^E>1~mjsaPg3gqWeffRsV^U4(DM-zdZgYm;&DG338 zYv?Et{2KfVi3Vav* zs=-kuxdgu2G!JxBUqwt1V8Z?FZQxgD!0(K~f2Jsj%?Ks2eXAgSL08H1ROInX1@ZM) z5!>M^G6MXzH_Z7%S_;`zD3GP61Ty1*g6y89BHcbI$ZIbp881Bya=BDVo|mVR9uNcHsgm@pE0Dd%z}6W`GUtYZoLerC^IMf< zjd?0*-$zM40MD;Wlth1`NCQt8TAz8E6nfq z8wKeIwu^I8l6Z*8cZmWSHe4Wela*w|N5~VYpr>?!xJRmpW0631gWca~^|VtUp`gb% z&mfkYK%9YItF;wKoeu&D06tNDK#$(wgRPaMj8l?E6BVS^Efwi;YzoP4D3Av=!LOKt z?7szZ5A+wo4{mY-`2uq^6d^Wxf$o@!T)(IwZQWGlHQ1MpQRFh7X%X&NQ*gE-jatsqa|g0H`T+fLzmKMk?vsUP*5JR1&w3kh9h(NtU0IBtvcu zcrK8q&B3S26=Y}YDa6KKLAZ$mNjDV8$eDoOP)Pj`8%0o#lOT>;;kFlM^3iY$fPvkr1yUOxq~=mqbCl*HnU zKrFG6_&!pQ*mGfvLG*Ro~t0^H$guCDUhP30=WwF z>*{3H`d{7nUMbx@FE zhyfMET^8iBM)m@!;iw?J(v{>gGZ}(UMcuSS!)=njfoGcIWkyRcB!B>#HK?JE+JE&`(Kgf#`#6(gAxG z#J(r^OYi9dc?{V59z#A*31q}1Sl?|RcYwXWwO0}Qy^s^Ak`zOZ?zm7Ou1*T_;yd^a z%(ocwWm5}*2p1ri8bJMVMM+ZpL561nc?7k^n@}ZLkqNP22YF*A#NH~<8m zbC0owe7aFVhW7?LcTkeJElN_j1LB?mUb&JuK>YoL_iZ3wMeh^Hu~>n;S(Zxp<)AlD zs9z2#Nde4d@e+ZIg`Dhm7<3DB84t0!&2gnh4~07x*_-k$pE*WS$wU|7!#i z0=mBj{YvoN;RNai@QGbSMY=$qviqPQwlOL)7-DO88x`@p2)erj>p2g82YMeC4(sw$ z$k!mliFdFLDghhTt0zec;^PW6L0k%{cL!<}1Hcal+rnC$TLf!gOC=fm1@wFu*39Wj zvJmusZkduC06op^4L0tmAhU);JrobMU-Jq(?ocVo;usE zGt93!WriGqB#gxVc^<2Hi4 z5BX+tYp83!DM=v2VqZ~7&cj^%f!}^q94zd3h;&O^WnnJCW7_T6Y!B3jPxV|n*5L#kbnrd$-a<*jh6<#ABFF%-ybNlShA@9M1i!k5WcdMs#O?yWZlxj;sIS(2Q4o(tDiUTZke31A zzhfb<4g~)&gF4}!Kqf=odwHus_}1V9*I_+coI;u=sYqNq$ZwE~mO+f{gPN+F9n^C` zp9Zx;pM{|N41rt^Qjx7m@a+fksq#~a)d|S`VDo8!uzzQey9wCYDi>k{a;!mHfovbFB-=hgoddCy z9Hk(ez&~!tl!QV|uK_XS*6}bw!)*A+Mv{n*#s8tF0ge~yS2HSmuy5w_5 z_|B*eehhOqSHL&x4fvk%h8(tANrK}PkOv?qE(008Aa}x?*K`8;!FF??Mpuo6^#*k8 zXA9rKklUqQKu7OVh<`n(dzyovb%q=Yw#=OZ_JXyb0BQ=O7Ag`1b(qO%fpBUi`8oq~ zKiIhEHG#+kfuur=FMXmUu6N-31AL}gG1PubmE;=4?bLBl1FnY{?*(}S*3Na{i&Oi< z+V~#kJRj;Tkd2(vR^83gSGNZ zA=FV&6E)le_0M_8v9m$HkWUm>KwoL#pAgU0!WE=8=yh&=$gi-^;q&-&OT9X<$pQcW zw9nD;AND!iyt}&n(>}-V{hoinj_N!g%{g3;jyX6At!g)uTl%bzI_cVRwRQVX+}Tb} z6iukjbxYWc#ylKFk9jN<%QKSD;uAdTuWv8bsxIS-+tj9)SMHarc6CD=YOLd&i!70= zswMI}XoFfhWEkb4ypf74rf* zabL|^a5j(I(UKQMB`@>lqVDF-;?ez$>13Y|k{+XnaHVUl#2Z^xCDPHJ$gAL|#HPn` zNtE7B$^7>o+-hY3*X7Y%v8~304m8rIwobdb!+vcfk`;4kAM+!esguCD+UAHGcFf~u z+T?O~BK6UZw->nX4_Ao0IwgtqUu_XD&g@aLH>5eT3p?j!K7K7d>ob*mxho4kGd_v; z>h@FDE?Upk`q_={e0_)Oup zs)PDvgFal(NmBahdM0PnWxe`gnlpF*_Fyspx;x$8#1Tc$J0gy~c8mtL3!~EyzU02x zT@YP7B*^NaF`bliM{V2h61V%lJEhAGiQPyN^)+PTvjg)a!FFTO^Xyuv>>1)577V4% zAN=XAo^fd6uoiT+@dmDUo9klHf~IuK*U7ZjkWJjTm;vg${69^wkVJ9V1U8`XGmf?F_dgV<}tZnayXg}CvI4Xsw^0oQztCHGva;@ZSqQa`x* zMm@0CChm2EHfUTr;~b2?ik&w+EGci~O&4Ap1*Fq-St_p*m%!d@rz@oN~$ z5;lqZ&-v4thVLZZt8G%Jh@MoLo5?A*+ldbzEkM1iT@tNbn55Kx2PfKd^z^=M>fIrI zxDJ={y)xg9Mbir$Q1|z1N=_~LET*^fiel37v5zMz5Tcjw{CnI7a=C2pjpc# zbBv7X_v(6R5t)LXhfhThjccImckheuvn=VW3FAZ!o6A{UoWtqcN75R$UFes99Vpf8 zEEl?7ZP+&oj1`lg7r)|qi< zPC3%3!Y;JsP%Ckr`nC9TLn=3RF`>mv7K#@h$J5oCw_?`^r^I1S4e8X>9$ZNLG*qzm zXo-pSTd`X68mQ*37_r^zL~6cxv$!SvC}(!#kfg=>23(`F1CeCpbM9{36RvpXInHus zINFpIOJkeMxN0^5l3__7#E2e^Y2?E|(XrN5^_m&G=uEvq+)>rRl6MyhxtXo!adlt& ztGiuw5HHz(li0W|6m!PNxqIgNTw>d=+@Ly9q~BMGPMKJ>j8PSYezaTy$>o6GeoKe&ym;T7m_tmUBm`ciqMYR zO4PJz4O%=sSM0Z=Huuq`Hn%)A1D!l`p1Wtck^9mtUo7!nK<&M^P?PiJ+y=j$=y;n} z+>br|>GD(4P{L{|&TIFfr0ZZqZd`gccd~nT$&!vqXhqTj&iHwMnzc*Vc_yP4^&7O8 zPOH_2i#ytF=c3J)G*`7vG=;Kf<&AU5aW3Vy`%gmscREN=P7cjAJ|ynZtmEcw{V0A? z_7F=(O6hL>`kcA#Y4K&kSUSV{yt=koEwul_GH(6WCF+E`uS#4$H%IbEdg8rRz33D^ z9c4Y&hyz`$xr_tpw0nS=+RSqs7yr|(B;RR@*xB|PO4{Q>kDe};cz+(xeR|&*ZU3CR zt7!ct_0hXc#BgJObbAREBU(LCCq2nT?eey%zxVA%Z;XE?dgL{s&)1jHX%AGWHhQ6^ z$rI@kr^S*l=LgZL#m_kRBkx4fJ5N;Hz9FVrx8zoo+i*>mf0N{Oo`wFjiF%vMb8h+R z{s<+X6Q4JUrTdI`b9(by&~L5vxR(aa(12qK&Y<)rH}l9F@yw`H+B0=JZGNvc)z4i; z!}%suuYE2u>AMys7Is1{gjt-)(l|Q)abvYrn>IAG?hEd1mJ{`voS}~H6(crJ`@r>I zR78(I8%m8^xQmOY*PtUq>eFhwlDNU6yP!j4xp?-@1@Y8uOD_7O9#y$@L%sY1xOhVk zDrG)(DzKW!9Dfda!3B4=k z>4~d)VuNlyxQ3gG#k1_FxG7|zXrf#%wy0svNj$%l3|iWcnunU8m^mxxc3w+KD-TW-E|0^J^rG)!zC)&5~oC{d>CpQzmrZK*B5Op z>P!_=Mj-q60g)4mT9*Uuh(nUuSQL_2NZhOyevrM42jT ztjH$#Ia)I+`*cAV5~gP6NLoo-%Q zD(=ZLL@Q^TP|qVS=-tEhYU6Y3xf>I05uVgid=}dR6}O<&v8D-k9xtGm@82mImD(3s z9um;lx$S7p-iB!V^x2~R$dO|HaPU!eO|;|!RdbpXXlgY-vHW(9q+ks~L0c?Jt{rNG z^e&&=IqStlb&dNAkfu&FH;6Sv(kYv`$jr5pjl(-|^Uk;Brhe{-7Vg-IS$h=rAeWmU~ZJZEwvjfAdVdFZ2|Xl6#9iKOPk`XN001DRN|+ zev8YV*o)iK`;2<~-8zyZxmY~!KUQ+BbfXyh%^qEyVCTi^_CYc2CUPsBTA(oR?c%VM z?&7p_rd<6dGu7{3bfTxiYNH1p1R38#C~8)w*fi7#p?2fZ*n-X6tG0W@XG7kV*q+Jb zHtZ>rEU=l4<^|hR`)VGjI3=D=Z#Y71cxx2h(LYXn*Vz;esp~JU*-;-&wSCO-8#B0l zDRro+!EQ9bCIjs|@`%F=Rp_ANwmPg&OLVtUKk-spAveAADM{H688^$j9c>mR=X_fa zS2wFyoz_%@(P;@*oXp}K_uf+AmN)mK!B>8$J<}q^sQDXdK|*&i|D#%haT8R^PZdAw zU*WRK+lsfRUE*%$wNZaPzFjPEyd;iT)f!3NHMHnpTQTYGDKXgVyZCbo|dvun_s=SaQvB9aV?6G33?KkZU}^UCerFfedy(l9p+Br85ZWuiMbP5*%S@PaX| zUpA17Iz0iU<~Z*1@6%fh_B@1AGfO${MX6-xw_DtW?{g&bdxF>S>LxUAe}B{^wnY50 zZHKt!t{t~;<4q1HQq-$-IWk;oMLS-zq>JqBIgiplbmZt)qBL#=>L2z+l9|^BUAA^Y zgWP<$hXXsHsRc7>!|%Ph)%gQx+_@g=9iiaEJ{I)Q`tc~^+z{kfx4Ag+WDYkcSVPxN zvOo!X)3`bvmeJJOwQ0jcw?z4#_HCHg_;=q?K+}89OXraQCt_iZHGoLm`o?FbR<8&E%QfNva`%v!CcvsY-W{?;< zQIFfXm!pHeoGkIIKZur}+RByPTY=8J)u1U6)5T@kKhPoLrA>11^cHk_0@yv9VMUdj|J3Z>q^DosNci zG{xbm3z=P(sr2(n8GZES2kxf2$}Su4zys>Y#gv3ZG)w@yUKRtasODl=#1<7bDW}b(7op>0A@d)bRtbk5PAg(XJIbn{B3P)4~&tcu2(I z%UX%;4BoTp{wMHK$x*uM&MQ1Ssybtbmea$*Ic!S*I?}*;2ic-YVc7L^5?URh!CBLf zV)?*sntH}+_StwFp1t_6*!|s6)}ePEn{g(DP4AsV-y992ZuMs2tIMD%{eP zIcF8KF{59wtgrW3OIZ-B5%ZeOf3qDUv%y>&hmOqV!gAIust^y-EN0!4Zs2|)*)+*2 z5WkodgfI8F%i7joh#Q@3imx3Vz|vO^ruKEsr4E`x)-Bf@>&@88^jy#4d&^I;A9!9Jh+roHG{nSvpb79y17Ax#!{*Bi}I2Y%ZIy z@h)pUU>8-Mwv=wTQ6G(a)Q<(tD#j0*gtBPOXXM^#6?^p78@Ic-1{ch*k%pOAOP{K0 zXbcCI;d*=Zr3d|uH7)ziVlA!?#4oZwv(Z<}(aiDT*!S5iw(G@I>{U#uOY;Yq( z=6xttoilnhQ-tcXu9=yr_ly}hW6(Hk9^)cSNUn}o=d5B++Qnn*xku53^Ea`_pp$I- z$W@@)yo^hqP8u-Qu$sQgcXQ*f5WGCr{O0%hO*|CpM4-uD^ecHS4L5+Xfj*hvaEkX?_#zo|T6CcRh*ommWp+OIx#vE#0``CP7Ry^&};< zl=;uJ$K497*@Q9r(uu~WSc8-PIKpQ%#xu5}%r@Wf;Ai3NyZs#2?Ce2w%I_F=2rp$9 ziw@z3onD9^@{@3T%X@5l13Mgke-!I5;RJr*>4Xo2Ev0(xis@ihjlP~Yn}xY@mZ6t z^qY%U7y5J?D9Q?Q|B*b)m{|itbAXze&!?GXWjtZ^~xyqwQ(6 zYMa9Dy*$P=o5$ewDh*qo)B506!c#O$<6{#-Vy! zSnFN(^mr>{O|QCFv2UXu>{YTpK3u$&m4!J-?`~}(9hFgv1pSk2c<2#4<#skx)w|7I zjN5}J$pcvbehs9rzqSz9Hd)6`Tb;puZ=S{*$G&D!2Jh+oWPLQss}(LS+>SqQAA}ui zcNLYf9q?|qQntju5t^IZ3x~QkVjoQX@uSyCtlVG~zFl927jM7L1`9Rur)4VKch6C_ z!Tk_!FnllTuy{LF+%lJXM=ijq8dFVp%yBy36Vtm*58>zQ9r5GHuWZ74Yw71v&k?h# zt2v)#N)vp}OV)iYW7o&nGoNnT@$q>Z*^W8QHT%cz;SQLO$MM&`<0l(li7m2gijQMv zu)8kS(#SW*IQO?F@Sa=8*mhzf-8HEbTYO{zUd%hPcu!|Mx$qdv*Sy5D!|t%RuUg?o5Th<3*vu3^HAFGsRo^W%HgS| zbJ&-wS*W_|5&P*?NNdNeV1^S!_QH1{J9J|OTd}MNosXG`eM82JMysu*cIor+&7INc zz|gnsSa}haZQjaU45cXi#3R;g&|LOrW-I2d^1;;~wBnAOyv!!$KEY$(r?c6uH?f*} z&6#&c1L~%9{93P@mHC*$8;7P_esn?a{$|+o|{tAHFlour1|{pG`1UGjE^>&!wmL^sXsX{!zYy4;!XEFHljS8sb9b2j*BZ%U0Y&J&=xvJsp8pO|`*E-aB!o?J4Zr{u_>6=!3#~OY!o!j`(Bu@5rmO z26u7HWXsLI(=A7r;A#&I@v`a#xP{#@YWi*)?lS%wa=BTAmqqB~A%+ie!^kOO@{vt= z>xC?~F>pP5F~^)WFEU~Q1qbnF%Qx&`tM>Sn@-SOmU&cHx-^CvuHDYf)YT^fv7t>2S zr_zmE53(?)M0B#vTYTej9%D0`;F?Y+)GrO9xDJ{vbcm}bopWJ6?l@s53Tko~3vJBV zm(bIA;Pq|zh(#|n&3F(V@HL;7me`=k3|BVhTOKn|mtmg{o>Z_X#OE_?vG1BglFfe0 z@jdscm@hKN7M&a6xzloJ^?lRv^?)R-pAv-kOn!-q%1+>hbOm~{0QQRxR>!xZPO|xL z-{Sn$Mw+S48YYQY!rHBJ#|P|-(5IAI=*!DI)T=~a6J9@!-FQ2O&d+&G&za`3sja8t zRnL6s(|b0!yVGe};B}2T=3286O)%SVX+9qB98}VcJB%$#Aon~skbc-#P278W9WLr5 zVNLk6Xr|v(_Oa(NTwZ-Ht8p|6Z+)$1&NIJptu`0qNqffP{i*xVla&SRZRrDSlyH$9 zSd`5=jE`Zb?nL8gTUYdB+A;RjZ5IBTSrf0-ABOU+o3R$_x1#PFvc>oYzN{eqK0C}9 zig#!r5|h2S`MG;|)9g&_bKweplKvVyHG9ei{(Or}yUu3)1GnI(w=-DOrRq{I`ylK# z-vXanyb8I0ea8l+Ucy^LKXc>XzG2q$Zqhxu1?-(yJL#28&2Yf0v#f_zbsX~Cfr;~L zNvF>_%Pi6-qgU<}y(|=%ch>^ubugWM8hMTuDm|IanvM97s+LC5dpa}Q62uNaETlEx zxzHPN#%zp5DQk~%QRa1j)@Mf}O^SU!H)+&n=6Lu5ZrntV%a<)+twxoiMMLr-pIygh zAC1_s8K1a%i^i~p&wiq(DKw!K$B;UeEl<%2PaWe~%(;9VDY}pG|R2@@7Vssxh|D zXZf`#+j(ZBz6jr{eVaYa+JUlt@8I?KqF9Zajc~Sj17GzTFP0we##}orW(6|_atj}y zW9>&<;P=tz5!dD^9y_) zv6wPrjmmci>!UP~c06~EJy@}rP1t0|YJ8R9I%X-j^Ycacpw&zy^E=C~J=wziBYScz z)K2Or$;MXPCT5>IgN;r+j+dWEXLk=ouyn{d3qA^FW(r+jG z(D^XkU24MQ5er$}nISkh`5rT`8;$wlH8foUG}vy&SoM&LX|()7W4z>Edz5p@k!_xk zg{Qjo#h2UkU|i8=CW+OPcCP)91+097&+XZc-*u9)fw%WF`_Uz=B&jzGc%+9L=8R*T zm!;s_=gc)OZwpxcQIth*+{1igERf%@ooq?$KK$1110I*u3STNMWO{YV@XL{zG(EV8 zPCMNXUkfi`l9f$a##K2xbAJ_M{TpCbCz1`eo5Ci`=g>0O57;HeM5Eb!k{NzKf|oA6 z$qx38#Xc{3qK~%E*z^EToYN$SJ$}9dA3u2jKd76GTi7hbHyoGJd4q=0J2DRUZa)$q z8ec>6POQy54L7n!^IY(~W*_OR{OxQ=%M_|gsDXFai=uLi-uPwpd)U~D;Zak+u+ImQ z7|UBkKi9axMn-pKjdo3AuM9`Am3{89eSX_E?H>_p-dKIH@ zK^z>@2KW78drsIfZ_t~|)+h_=BD?Z#fgAMCYD5j)&vv*4q@uhmE_`@=D zoW2U-b|bdJ_u&H?pS4c3?+CeO=p&ZYEuLOBtTi z+>u$eI>nlf>BrWm`JzM`fc#oFV|trH@r$#c@Z)9o@zv#y+%4nvcw)~imiX8cFPY2m z^6rw4)87Ntfwh|)(M-eoJx1SYR;zd%v5^c1zq?&aG)I0?Y7)PB*!2eNtFb z$zfLPZ=~tz{+zyZsLlE%-ofIyMpBu!`j#4vef^-Bfja@>U92(9H z_O7IjM--w~kGHe38Y%RpM*$Ci0F&1Sx}p5Y&tFW}9ZU94~L6RhZ( zMpqr~%~EF_q6KFcBK^&Ekq<3kTLWU4&E8(PQ@>f*ve{+UwRQ;`K3K)Bx6z=U?q$g8 z;6nU%Z%;h7@ktz@`b0JQi&A=fvsU@I@WQreB$ z#C5WA>!{*AFY}EGxZd{*sZ2#4#cv^o4 zEc^NbkN6r)hdn-p>#Quni`&+~X96DJE;|C5>F9OnSY96fDj&d-^=7m8uPDpv@Dm3t zIm6nT&tYxH>e1#_$C)#2jW_OC#SVs_WucRb*w^YcHCJ4|m7Djm&R` zTJGJ=zKJH%Y60e&AJNC)e0rpcJs8mo zt6I9^5yLdNboV7ZAXcQtMN`nR_l@ww>T_^w%QLLm-IF+aHmv1y_F_F+uEt4W>{8JU znio=l_8Dg2;S|Gwz9Hl zi(9M^)Snt(qCMswz&1y$*o%Avsc+h09PK%cS>+aBpV}vxS&Ne>b7u&?&}#uRKQtdd z3C?FHGE6m{cCW$TqhS%gUDsGM=xl5H^9jWJO93xkVUJ!7T}`d(Y(!CeMON@^KWlhyGwy8p z2p_C>nQfGvXF>W=xslmudCXG07-Y5!-io(3 zJ<1MzgqqA;z*ovt%<0~9=6L1`Yo-1`AM|+34mk8;Z>B$@Lu-D)HRUr{vkSX$LSHGn zf%d^Vl!dQ0H^h$mMXcQ88r#;=f!%A|9KSxU!fSl&S=!KrxOhzto7Z&?8y?k%uA7vJ z8-6arHMZ2y2;Um8;P+>-$Ei(tkpi<+|4?;(3;8N&{(Kv2(YqXPyEXV#0>VE0-UnmwIQ;#+B}#3J{H%w*RGeAD4E zj%$^O4UE6iOKB;L3w(zc`JG`K^^en$&5lqs?>oJjG#8nUzJX8Q?af>#-(r@ZcjEuU z(0RvG{YG)z%9dzqAnnpZ!+p-J{3=qYw3Jn;RJ4_fkP%r~Wn|0B%H}@j+EOx8A$t}X zAtSBd_kVwQ;dP&LKJWMEsQWC9C;zFFXi)zK_$Vvmx#MV_dsb0a@yS;Co;QKI?@*yWJ8DNo#@A zySNx7-2!a=#ZdTa8GM;1= z(pk4si{RtI2$(PDfQBv{PGDab&Dc|jFN}21^L`grcFoImyIqZKT}}A;Lo4{yc%$Nq zB6ypbPu9XN`q4d!dYrzD%2GM7!+$ZQ`e7LUTo5*$2#20u zTVIA(Wyx5eZ9zm+XOr57a5x`+4f-Eu!$*rp$kL4DG|q{{$62#z=s-HYnDdy1h%dva z(f=rmzY`~)^K;b_SLf2Lak)<#N9fsib8wCBeS9La7A3bVWjQ#TlD+dEkr;&zYU3!# z)sgQ7Yn>FxloezD*VMYb+%ygY?4v>N@?|=6I344rgxE7bj-#c+O>AYg(luYdVtRHb z`1GdZUbX~Ym2ib7Um4mM^cftPznxNzhveA$&roGiMlQAf2G@%hV77=Ld%JWMrm&ai zRx8<~;La?NmYU32TJHcplkNf3r~bKGH~6yk_|qsnC6 z-xMtR9R`0lyoV^wKiKc)1lCKJ;oy};oTkbM2x>`!j}=#8BuNF#c_@6JTa6pl<$z?feyn&p3gd z+y-)YI0t@JyI@$XG0H^%rY;KyYeODxZhjM3T;Mt6eS4kkZE*CE!zl}Fbg7HJ!Gw5Uu5r6YuJYzdWKaSg?Bkz8! z2@HknQrA${=sk`Z|AZAbZNzfRi5ydzM%<@)oaEh$CYyrlVCYF7WGyPh8%IB(eux(- z49G*H1>GFO$s9N#X#)4n#_+4hS9*cJ3P0X;z=T5{cq~1O%2bt+hdvf)@NgK<>`o!A z%PVpDks-|J)xZyn=ELpl5h#@{jfS(*q519#DEqPkjh%$J11qj${QL$~V^!jCeKVw{ z@v)!W?qcSp5HQ&K3LG?if&a`9yz`&IHg=f;?aHNelKI>@EbT$NmWAT1@if~1M-$$N zc|h>VKr-)L6!@0>f<4DAuyuSZ_G${ScWj;smFI-nHcu;2YXHE)J^^fx&nLmN!Z2OA z5>AuJ9MqzTz z5_Em3h#jM=(A?@7HdZcFbw1dN0ym8D>-RxuS@{JwlLVZHV{9t5tB8P`3#8aT`VCP#S%}}{I zU(BZPL`yB*-)D%vw|=8hYY-kbSK;t}{=%x?RfHv4o!uOZ1!{pIGI_7Rq!gv3H zBF$h>xqpXMqIMKNRmQ?YgJL}WWe~bG+Nr}t2o$*Ofcd)u;P;Cd+I-FrCOtObwVWHc zTe}OZ*qiCEd-^!Av;uBKnW<)!Y=SwRnRt3K54vYrpjR~?`*(pNvm=_*c#$UDyxIo~ zdo19IMLe`#Hl^;*_tHme`Pe@{2*L{2L>T#fh?%MCk#BuFu{)9gYK_r!`+xxV7aj#%PRMfPY*OXzPVPM|E@%!UxPcD{^|f?gw zDA>NK9al&Sau>Y$2+E!RNPbF`>g4JQ+*$MwqyLt`2}Lz}c-=D;ALe84OVxyQWd*oxIJLRQZILh>8xquv~DAKo%RE{f1_|n{xMl0k%r?#M`3q- zEky6$2CS8QEP)C!uIb@o`d(uR-jF!LQhnJ6!_gxEJs)87$|fMzx-6Zi55XsWJLi-@ zHh|6t5L_yY(t%Mh#3#(Q_P0Y3sXJujV<+gGF`H|y{EbBZw1r;UNoQS2g&Dj`C~kTh z5+sVK)Ibov>CDIZm$tzd%Ws@ojY{e&+73}`YN1!7TyT})iC3wp=pU|Gm|C^|6> z!_K{^a7h9Z7e}$|zRFUqq(^`^Z{pgqeeizF4G;2(z_S()7~NQgZ%3Y>`;jkneYgOI zs2${t4y4eP+!hQhu!F1i6RKzT&*X;nIpZwn5{!M~iGO#sa;mmW(`d(cFk`G3?i_Z< zZ4$G&O+|ui|HZyUYdQ!FUvuF<#`|b{qK~l~`7t@Q7t^mS#>sMNGFP?@b=8Gb&o3>a zYoz$7ki!6cHQ9nm{awgzItF1ubr>l4UN!MXJRF`=2ltoEU>izEaUb|S#=NmNuq6zRpi+W6S)%}l=fzOwW;|r%MS;xY?T{|aWK9CkKvsP(>y_&h95V=n zAA62~SBM9>yQY;W502rJzvcM1FA{UZny3!HDYQ5EfV1Ius@oj_dJT^;eeD)V85QF8 zEOda&3>Q~vy-ly47u()6ZAcy0Ud0+ZMPv=EQEhoQDL(>)+s155@x40>EZjiRv@cqN6x>xh-GbK zcp~{X^)8=;RoPq&pWO$_$T-8MskHErAICNBE^PLZ!j>fk^m{=cZcBUsih_Yq>{|>% ze)70JP?EcU-5<_uaX$8)Dh<4C)qpGH6d~TU10);-xlLJNsJSW}qss(e555QQK<1N zn3@UsLB@`)$ltjG%YT}~c*7kOQqh4m|2(0mVgRmYWs^S%`m{OcBP#ZK!P>CX#5E@c zkN$Q-_wiKxwY?q{4JueJy7Kun2jff;T|ctD^X^#1U33j<=n&&m*wi0;Mb z9f01fA&@+>1DsSGD2vlaz6;wkvp9CKEdh+wvW&BDn=Kkny$HrynVBOdZ zZg;8}H|oDie3es)eD+DSJ82%Q=}Cdu(O%FUI70sISq496HG-Gr1c~>k!4v-0g#PTp zv7K*7iJ>Dz&CG;ArwB+M&?0hLR=N2Zet6qAiDYJY!iKSQRNQn2FCFCNzHP0gL$g#s zPvaq$G@8Il5plFsumZ28cCgsK59J0UU~$ed*56V?hUq;6>nbmrya?dJqgKMPItWob zbLes%ern{G3$o|)Vd<8q=7Qw?m??+5Xw9+0__3c7RB z0Vamwy#7NxCVCrnuJLn=Yqz1;$}SSf@&PYHUi6W-!*~0q(Eff3j*h6|^YLl0{G1EV zC7Zjg@$6se-)cXhs2{6Nj z4^Cp``9N6JEP&m2#JR1%yW!_v}KHF7iZyhf%1+e2wY&D31Ks|a8yBI{Tw_X;X`e%U4k7+ofxyN7Sswm zQ8UdG?oY(w9mz3}m`Ph8=K@f-Ell zwG__DZe$p%IEoi3&`T-`SgrpOVt56yZAmL!ZaE6Sbk>93s$i5+b|+59zCe2FX3kp9 zb+DN@Le3fpbCVZxaH(Q6=$@;kDft5sJo`T0UYLoi_fHawZUek0R13Ffs;kcWJ%j!B zOg0T%IhylscQx)Uk$^{4*4XH051D+D@G>L;S1sjb&z$E23qI@9ZFBFz)GZ3Dv|MmH z`vWRp?4bR9>0q3?6+YORlcP>G(EF+sF4|4uSmbf^PMjovG$jEJcmmVoMD>iLWWVV* zOpgcweJ4F=o!bsO>)wD^aoJ-hqho5 zb-^{;qp{zFnc;XFamC6icovG0hj`aEpZ4@JviZInAxi1%duQS)>+1d(L&_I(si^n2r%__^f4 zNEA91B;Z@xL_`miL&o%E3hefd4y_pMbue9;p2EJ=m% z2NUqGY!55pz;^sT*$QzRMu;xI4D1&aWS@L+on)ElGe7SjpqIDc)LnZ#a`gq~*UX@M zxAel-b)T^=w*d=W-$1uwIr(wAimcXa!D{P#+T-&Ude4o*E>`GVq`AR5)wLPvkZLz`MTJRhhh@?R;YYkA@QE$iXux_Z7gZRFnyshKnbEK+tz%lsP^C zx9oiJ>f=~+fAb1*4)CI_H9tFdjyisPk_qwuSY$`)Om;4(1Y3f6A?lO>{atpQ>iYIT zc8e$I4EUmzeibg&4hIXprFi09C~mcrU~d&?T+B)tG#cr}`s^CmG{S@D{Tft-jfL43 z=i@lv6g}bUHx^;LmZJNXxg>5`I)uG##8m$`v@X4XqyG8}EWh*-4_y%AzCTxw^CMzl zvbTqxw!4aZc3*)n2d%K6Z3Akm2XdT+)_~$Z1<=`g9x}9=RiRXA-82QBnJAz$g;h7>r^0078&6s z>I5t9?!u$8x@51yQnc#i|G{Ny}bzL4fmZHMiuB3#?iB;0Z^2rlP_kS_5Iys$9{bOXh>`O=TT zc19z}t@{lvWB0Jpc{zr-MiafDe{@&XJF?wm3YJSbK)81j@ZCHPi7u@;w7LTdR4#!3 zljHc~S|aHP@1ZSLnX0;`&eS671aiO<=NzK+ZIV3X#kZo!%oVB;;`!)MF%QqLs9~*N z*#V-Dk7IPN36=ak8{;ok;9P_EtcOa~@LbsfqtE8xzGQyx=GXuT+@J!vOn=4i4=-EL zC~6+)Wf@K_ieku1OTyo#@#uJbwx=kq)uYOyb7)I33# zIesAIEX-Y!{{p@$m5_5O)2zDcLHN4R8-K5VkBO{qNL`$ckNu*_Pw6^nEZPrYhaK>6 z%S^8Gcnf^E8;1KXUB>oB71*Juhl;EG@#KX&P}j%Hy>0Lj-^X78+l4#mL~0nUPRJ$t zhA&8v)-$M32*m>3br60-5VpuL*;!ems^YtUs^Nf+QT4cxCO`O|Hkn{ z#o)qxruJQ#0$I7;oWOewb8V``o$=q$;Phjdv*RH(Tp-9T6Dh{ni~>)n$Mk0EMVT|3s8GE2hQF} zRXsU-ISSuRCq{=`V1eE+yjo;M%AW|r!6)vV=Gqwe9yS+1IT_0AgXx4i!-`WdXJLPU8DewO(NmUD?iS$fy2;Q^A(d8JSOQ@}uP7#oUqQ@NPNxFCD;fri(D8w1avxZ+PxV1xm$D zQGZ7d@MH4ejmh`PXYz@bh#!Cwmp(idegiF(EW6lA?{hf6N*u+L)+95t512p$Lc zxAz3{-j-yWZg_+J!#?!K&KaC5n?=E3Y8!lbyB62VB-8nYFGv-wgD`m=G~7H7)e=v^ zC%wbj9IJS`;Fm3D2{T_VSQJDGc<$iXr4p>t$p#ynXsCPkg3iuJhW@Sn=+XKD8H=N6%KTs3eoj!2u=aQ6M_q~-h9a#p`>q4RG(LjRdET))94n)+4+RAvXjn@Jav z+PxLSMRQdRx`IGIs}0Xw&%!k!7m3lPVwfwyf{yrbC=VW@Pft5S#Mx&kqU8(kBp&0P zFgF;?(+2x|M3u&Bu!!ygkv%hs)r&gPgl}+Gqzy(V_`{!i@7(+yH7NIA0q#pZ41*It z$d-goO0(jz^ih$jWI-ocYQpS9zocRRx{q{8c{ZkXKZJ}qnXFm8!8DC_&{KyInuF(X z)4xZ7hAuO+D`i3POg$Q-{2UIgH^b^mer{CV0p=~w$3Mm;OwMiv!Yp<0y2C=>@K2k_B*ahupPPHE8v zrsF8PF%h<@`lD2H8Qw|?!D@q8)I8}-ry7K~hR^(fb+Q+}M{!{5nj|>#VHDkxO<886 z7I^xI6ISRx2b-q1xLDGK9#{dq#WBr;uV!uUd2X< z$K+6OIF_}ygW(Y`+?6qkQ9SM_Yp8%8H^n%xD;^H6TZWp;$8k9AF8<25poeeB!IHh9 zaKfS%-J-0S?!r$Zl@g5Km{~*bssR0F+X0^+Yr~hXYoN-&2pU>)$>%#hocE7?V5>za zbXGI}(j9ZO=eXH>8*w zuP09>EAfq*D&F>a36c8)!QRalgJ0G`%$hvhd$@x}Hg{6@Ng=MdlLz{xeq-rRRAQr; zKQ7qmjkD(qlO>UUg>NIsZ6Lsm6QYAqgZz z?+set;ownU##NbVO)b5BaAFJ6}v zI5ck>-UZ0fzW4mx8Cr?3X!%Nd`1nH@RaZsxf(~e0bpt1NiL;kjd18x5IwvczhMaAq z^tX*G?iVt}N{tyXol}E`-2@8%e8w4O@vs`JadFZtGV6#5ET6+iZ<+lgikb!($@m0u zn!^WhWoX?)~62j4O0XZ99Eku6E4s%h4TIju?m$kWryIj64J(zREuAxS`*{rluR z?%=9LP~tDjHl8(?t$z0anx{BWqq6z*`H8n6=N^P@6ZI&YV}K_=&Sz`2#o?!26!|!B z=n4C8U{kCP710|Zy1N&Pt^81Dkm=X3Z{e|lH7MNLPU40)f^OI-?3Nu+?P1~pSEc_@ zd%GyNTK6U)iRZyG*OCKOj(GZH4J_lE1(qTG@esgR9lceCc^aE zj%g6xwv%+E`3VfnP9%P>4B(_^1~mRQ=e#Jrj&Gd)LrZ3N8gFL&)8#H;94C#nr)F?l z?rMWytToWhR&XPrgB9p8ldBwGM>-uBfspVAd?DtBD<{{mZV!sH!+!o{-F}{kDLZCx z&a~~Ja?MXrh}#5d_Wkhk^DH)J{x16KPboYl5>RH@N<2^gz^e)yASE-LoBoFhm)n6{8B0~W9vr1tG&MOb!2lt$Ld{GionmnbkOY4i-b?i$i#U=L%6+A;{*G z^}^zHThR0Ldsrv146oO1gNmY=c>cs=B>*u5G zre`$rnI`^}H$)5LGnmLb6VE;6;!B<&%<{+~F;`1yB>#MFW5`gh)SgUiKkuB~ct8wu zGlTHBog+BS@9|-jS(1qHtt#N~G=y-a zDB6`&Ag{b9(6XOIaHS3`jrxkF8Gg_uT|n}t(&*@&U%3Cx1&B>8ViB=!^6$iBw9iW5 ztl_T*v-20A?XevZZE+-ii>^a$_c{6~A`XW8vfxUmELLZ1f!&W@!TUEexW60Y>Bgar zIB|ah_WV}~5#K#Yl~fTuxgiq2`G~Mjw^f0N^DVp}5Q{rWDLy+T3Q<>XVTTI^C(kZu z(B;70$Dd($Vk*`|Y(a66Sx~nt5Qg5V!Ox+U;9D1oUDi1$`ey>iC->7=&gx|RYcV~s zDHqE0ra*GpD_kt=i`82%;(Tis5&EPI&&Jn)d%hhwS?{M?jkQ2-$2z>2QyW;_;|sXTN33yRp9XIHz7j&?g`GsT(t@OyN-E7reYwtuo*A?OQFHhhvB*5GIl!CeUNANyF1+#MC3>@DZ8{8 zSXaVW)h0Dqzl1{e-{Y9*TSeaYoTm!g)}t`bNUjfRV9$P57gk8Q70*yj}tQTrutd7Bj!|czRI3j{LLHR@J;2 z2baY}VMW3RT-j3qdgmTvOUQa+-x>|s%btKx{1VWX`-!5nWVi-`N*Etrh?QB1q~+6h z{PeVopx059-*p6M2gp#5HF3bJ>xmt&+|Zf)#4K|g*2a)vaPC|Jvkj|Z)5<4c@bv{p zR#1#f6mwx+Lj-wy_ZhT%me3_u-K@k2P? zPL(7H>u12+^VqS&Iq-JqHT=$(AZd(~C&e2GGeX~!tGiurtXGLXAGbk%B^L5@ z2g1l08 zdcu(4KtUE{da*!wN(Tf+=W{hU--v{3C|HLCV~La{336_Sik}Qir2M32LldORM>W!*zf~jNiV_Q zma(iFU2n3x@)KSZug`s`_6)G+HQsZ6hMSrE=f$>nP;Sc0KJ`wR-R}Gag}%?{ibh$X zHskx{9h!$}Qxsx~OMt(x2p;?{MCH7ljGNJgfiWiN{huW2x_ zVv*Nh^zIR0e^q*o!@^HFLN~I>stOC>?R|_qBRME3UIEMi`DBj zNY!aYlGims)0S;#eXxN z*auA$v15xsWaAFvB7Bs7uiguXf|xr=CUYUPHxKtQh1K+#?~ya>A>1_Yhv#=Jki9;f zEQ~mS4>s|zKMYGkWqUaW*%^XZ(`s0qYlj1+U&%;PJcc|Fg~TKuXzQLJ7yg{a$A@>~ ztHfuRsbdEcsk`yLZ5Y%p(uV%n2C8kBhc3dd`17tBXfLq^mAqj5uKft@55|#opHg7e zw?%L@ZY>S{D+O8)1aYE3oxO6U3S4C}be@kFAKH_@16dS&>BS%DIRKJHL{m z4L4zJ<`FdUV&*fK&maYRVBJQBOY+`;U3&IppYmDw6_Q2|#1(K1*I%apoZT@kvtdwI zS7!3{UOc2}550nAtasnJG;_KIRd4l>ZL&>pjOQ(Vu098>+pY1TNhmqB;0-$NiGuP# zR}gHTf`UKVpg!Hr+9o%X?)@(p`-1~Xw@NO_+*(J&KI3-Ea1V?Dm_gy&m zNg(`LnhIApT_MqK>*%C;0(lVciW&uK!0jl3L&hsG@Z!V>wTU@EmOko-kO^V#nj6V*`Eo2K+|mcpH8y1A_!pQS3>q(jX6Rn)Si#FiRoB&jfbtFG6XNwH^C?7w$x1ZX()D+U^|~W ziDdstcr_6L9_`&q-Vw z)(f-#y}(M3P`q5T4?hXLfp9lBl8`ZzE!HXnHMOeS4da1(FTI8oCy zUuu4b$@pdW;%xpRz$^b@%+MK-90icCX#;<)I+QK5C;Ym(a4^pj-cP+nrCqb2C(9e# zL=*6nQ5^nIbEC$3(%c_n9e5$+0}3lYhWjHP$jk7e-OfG`lGlcVAHJc6#$w#DqYyt_ zdkK|M*=W|+gE4RS;&4JTOvFWlW?~$t`Dp{nt^7h4r=LLksbi4aHHQ2X<@7~Z3R>6~ z<8w71IyjMxBY96Se>{S0e;bK6uV&%7ywhNQUp&WibP@z2-k@N00%}*uKxalhjCzTp z)EYY+kI-Y)G35eH;85a=@JxC)oRV*Eh(uQbA~vs=)u-U!3S z9LTaK9q2yhi?w&S*z+z7f6o0$m8>3v-YaRgibpOg{`5l;wiLKkRl{NfS5mC@5l0@4 zkb@dbXZh=QYC4eyBGxO(qbEbOePjz9R}Y8HKX`G-{v|YP?S*Z|hdH_rLaD+f8%})w za@5-C14r&Z;@J9aC;I8>2BUx7gg>m?R=N-*~u+z>E@X|BaATa>-JNCe%UU}GXyc5jbhhT?tDC_d} zAo@t$g>$!h2MO*ShU}X@V4o$zPGi{3!QN2Jh%3Pxt&31T#2bBl^x;QwB4l~{gH^XP z-s5#5vUg(PU|I!uNl4KTBMVsv{3fXW$rfBbqXIt0{ltYgR&Xu+gpt4MJ8OF7Vh}MA z?8C-V!!E%7HV! zPoXy^4QG2gP*)Fc$Tp3}W!tP_UiBsP9%4Msfn@v?VaG{Ni@+fRS8&z~2luZ%#42Tw zc06dt*b#o%b^RcX$SDH%vCVjF@p;&r{u-s$E@Cg5R${)tL1cL=!?5FZY`l3ICROjC zxyv&6wxAquOWB~iiUgc+lA_w)!<-G)ws>|glMmgn!uyvp@swf*L1WFFP6^ zh@Gapj%eUFYYDb3j~ls?QH(LV3V0#?Bl1c%)AG(I_%oj$1_lNwDgK8Kts=;~6ixIv zoC~)*^WeK#2S{&yLdI^?qt?sy$VYuqq==9G+I%IgaIRvlT=f7#EX&Yn_abiG(~Ho~ zyb&t{*28L5WB8Z;5p3R@V9?-q;Ciow*Y_Sl$DU`{CAJBgifmb#=HqbqrxAX9q{r<2 zd9aD;Qnkc{WAG*>`&D`k>y)I?%eIQfza6COUe2RpO7?KF*BvCY=0kn5GxDs_hUjk- zm=an{P4+)T+tvgSG;#r}M0vC)vfT4I<|sf{;en%}7;!V6c)YB`>>|b|7T5~2_qJp2 zxhLeZNCKlE>>!*%FY%Obfg2}GFd4R7D+0agf5ELnry&H4~A zRDrCBUv#Ql6EmbD;9N9wyCJ(0LKpNv`a%hIaeXUze;LQVR9^1jUw6#nEx`vHK7m5X zG+uWXW$WBN0ymX*gX7i!cy)@61$#wsQH%!i$*jN$%XPSTn-eZ+?*Jig~d%kE6#l|u_)flVSxE1d%)BL`eqYy)eWKR~mFM$W1FGOFTk zg90ii(U<8tthCum?uq~4tPjt^_zTx?u3HxQ-SZqoq6~1f+8Z7Ia9Q4>k=UR!1M3yn zfYz=17+r6OlXcx7C)&Xhn)Ml0eB1`doBGMmPFf?=(x~GNFM3BX3*C5}u6;VB}RmJ}fGwP8*)F{0&S&=U_LMsg$CwehEyx zHh_66v!Eeo0#?-XvcEpm0j;YFFi~DZyM_eOV!sON2Ye{S@$M;>Kq@@Z@)ak?Jxs52r`AImAjAxo#3DyIJEKIV5+mg0u@>7QU zkh24PO?tuLXdK=!WYf}5eo#p4AV7q<-pcoLMlGyQ>31#oz@1)mS3 zz6qL-{wVaqb@W94MmSrQ5Mhkm6Q`A%vIC;7;V^!h6Pxeh~M9 zHduKx?skB_I72Y;b%b9*o?vU)4N>+YaOgxX6%;8%R%|Ie`Ywp_if*KE z%9Tc+=)`eb36MPh6PC2+(;~HcT$WHkrpmO@b7wY8-I3IYqBuK5A5=enCo39{qO4OMwMpc~(T|yUEB!7U-ZB$rQXy_` zX&AQNa)m{Yl*sZf7YNM>!^w9%Y?ehDP2fEXnx%kzD?_%6Mn&U#F&8}j{4R*f8la%k z7!1xA2lPA&b7$D&8y-p*A9sLv3u5r>I>w?qr4D?}Uidou2ngm6;1eHyZmZA)^qRKA zzWurw`oIHuynb?QzP|;D@1L=GZ2@N9bO&RRKM?p+B)4-xI>a4bM`S17!`0mdq6*4Bl`M=?*cP0GjbA*9|Lr~(|hVdn#(46@NL%JK0*Z&uq&j`jY z-5z@DXb_w=-i!~fA3^t+i+ISq9v{$abiS7vJhz&l-BO*%-TesF6^B6mw=k`}!nm3z z8!&B$C1+raPYw6Dm=qlJre_xVAzW2;6y3Z@7I&KP>x7tbxBP_+?54@Mb=i60(a zuA{oTc3{@2CG44WMFAJ;z&99)$gEp|39) zI?U1#k0pZrWhL-h6Nf9GO%X?(5jeEg1j{-+V84zzvy&V9{F7E&bDduiY8^g0J6CtrF96#{p zlJ#OL&>)(McV&_>_RKKk{h7h$Tg(+D@jy5VBir&K3S94-&FQin(-y8Hz% zJPWae0inNmjsFE`Wd4S+O?&X_m;p@R$s^z1zGfNEy@UG9JdgsN&~08!XYf2g`T7cI zcW;K+8Y`0N9|pEx{BZ`euY6>;qGw1TsF=NhecuM?LX9@G)~=!RcPro_&N&ReSr0QD zEnsLv1(yGL3z-Hbu%l%jxN7>4TOx4~=*rCB@=fsUbT|1t9u50TH{$xS7*LWJ$7?E! zscBaQScG?O|E$!67e|u7Qeg|OJMV^W8|Q%Q%04W-%7+I7Pv94idQ#;15?eXRbW2q@ zFT1rQydh{?huswt9wFr2ZS^s4H> zovm4_x0>uw!v6zmt#2Ur5997O|c=IJ(} z-W6;3wICk(V)vqxQxncw^A2Z>X3^dkb76D+C)}-Y2g{@^=`PnFx&4+2cyyI7`D45g zY6MF-5$~Cs9TKkis!0noXUqn5*JmiBAjGbfuZN}6i}3G0X|%}x!1Qxl$l(=@cu_qA zm2LUpv=r0fxam)XEpE}H-=6}lOM;!=bHKe)3$hcZQ8X}+NGq-=+`Z zG&jK8-9Pa1?Rq@n>q`G_7Q)%eH(_jAklr8f!d0&~fq3;(*u8o`XSVTSxZadTz8yJ_ z&AzE{nlt*Ev%FCb zE@Z~TsE0rFhZGW18F$(;mB4g)qOtsWKTfmC7+2~X`2AsSkM`b1hfRZ6Aw9YMH^Z3! z&KSi%RTZes_*v5F!H}s@1IZSi_+0rH{pu}9W@vXu_T;DVocJY*AmTe3yv`oZ@MI9_R5iYY!2eJC* zYva|X5#pjaK+v0yDnlSeMYyn2*T!HN!J2>+9uEj zHy>-kz1Do3koW~W4g%bJP64pf?GQK}=3~z}orR0Gy@WXPc)EOif=-=Wj*^Zxpefi3 z=1bmS*ve5X)q6{Bi+ZE~Bj){$>&LqI6j*I;0p*(3uxM9*?k%nO>GpS}I1P ze6K_If9LV-#caa*vv@|%>UjAfab{z*xB(9=V^VX$pycFza<e0Z((imH! zL&YNt!Jx4Ta;`na*IgSp+Sl};&b5P?Insa_blaxX5lxdG?FD5kMi@5Lgb1% zFqh?mx%C%xReS?#v(j;3avaNfl$pFw0m38?aE_$r!*VM>ST;WhM)+r-*=jE=^_)jt zoW7w-b`BAw?qq4L6_&<40af`yG}2!HQiL{JEl>1L#PTZyFQXD%OtAm@30 z06bC7qC*=tV|YV1R{3|3HVFZYs0hRAz&qHi-pC2|%c9HECJ4VkB;K>n1)bnPT4Cw2&X?T)_)UFth4099UYeiR`@_HIuKsWcRo_THWQIyAKRR%vKx2n}RJ&;9(_KVH3ZzUO=2*Y)|l z-|h>bz2YZ!ly$-B^ZT%RFpF0p@sw8DodUnYJ~DfGC&-8jbC>v2TI(SLs@^l;gJ@*T^=SAVXcu5jAdysS{H{ngo(|9+@ ziRfGu1X=xd&O86B_*M4-k-r&$FXy^v?w9e0fTTLoAbJ5qwWh$y?e}1zt1RicDNQt$ zN?@YaC%nIZHG15Lh4vtSm@1%7k56ca@7G5GkJ+Q=eKl;@=RqcTD)Bb$WlXQ4i4ZB^ zgMU?|GUmp0JZgTnrF5b1E+BgToLvO%YyGFC&zNX@1a~raAb}y-jDMlx`UOXH+jlMhc7(&$Fl3RDz0@E>J zr%e^fKO+cfK7Dvy%#T;BTu!u4_drm9A20v75j5!5agGc(gU3QuEa^#t6Q-JweKQ!( z?vlq^+xK|?6>_X&S8*R@C6K}{UK2iIjA@D7F=np$D@I9~*iq<&No!2h$8s0bZ#uGS@I=`1}OfQ9*J1uF7Z5tL! z*OIz5y|DItHJ!RUiq5u-!aG}|h{>K$;Ptx*U8`;BJ{Ku)VP^^HS${GAEJf`pb)dYk zgN!Ftai*jT)9K>2c*50!C=Idss#P}H#&yA}*ignbb--KuS@tUdNVj=ThF(uA&RpsO zYs=PxqjLecwx+bNI(d&ExF8%WsleouG>|8tE>3M`h zvcdFzL;(zYc%Z7rLtJScgGnwC^omC=zSLg@HO{3Na8eH?#HCQO`Y*IqFI4|vGJ<-E zwa|-8kS_GX%HsF*fj@*X_ z>)6bh1MIHkXyCQa&vzK&tw)c2qvw;69YM4~E4(kZvA$n6;()ry`@3k(IukRgCk*~mgU5njY0<_yFm9g>0biZrf|w23 ze#wB)Z!a-wy%6Rs&7}(W9^fU7m*nc#2kK&+OgMLU04iuO4PCVbOrz2wLrD)VX&^+s!howO8XdQj3OXJ@Hu++fUVmVdZ}@ z*z)fke*QLzGazUH%jfgp>GuJiv!oZ?4N-;U33c$cJ_V0!rQspnKbc2s4I!vJpPXVF|vxee4NO2hc;2w)ykm_B%rO1Gatm1XussxA{}sQZI1b5#tV=?A%Xmf3xi4nlW) z@pAQAT7Taf77OhLf6ePvriFZ@U%zDJYOO5ds4KgKY+REYcc){y6_kLV|p1hT!U6*Vq?g>Y9T z>>DemJN~^uky*lA@1U7f@=Gg*ZD;ddi4xQr@}v$aJ0SY|Pq@&w7}JKch_kRLH{+-) z%)JFzFuq_oTp3 z)lc0?D+TsSt;bI%tD${W0}+p7>=dD$;N+x@Qf)&>vh8R@t21b=9^-Aly9u^T9E2TZ zPtY?c2dan^E-rsgO=juA-sb54|NYgk?zZ8Tw(@W}MPIkTY&ZT5TP_xz5bTUgE4On#9sGvw zU;2q^-vX$R=E162s&LKY2d>GV$W@6-M(uGw&Ws^XJI_^k;Dm?+NyVzf7f9QnL;q{D-#dyR6cW`^hINlF+CTixzcszvt z9A@(tV%4Q-0=V`za0Y-t%{hn$BfKZX@+EFHOR<6h&J46tc#F@{hKl7 zIvc{C)z+vCVUSt4oNl|AjZylJfO3hLIN=Y(R7!BOZ%Sds-*%WrnEPaV0wnEhqV;uO zINy_>;S29}a&by89-1%7&B}-)Qz9F9e+AX>m-i_sUL%H08h>y@x-H3AFc}d;o#%y_uG~2yWk%42PuS;Lek! zXf$L*Wv*R-CqJ7}nsNWWpJ9%I{1kkk$}(tv<(RtK8*=qt^Ir38;a{8+xv%~P-V!Sa z+f#}{Zx0jck^zppQ7^}LUl1&tG>6-NkL6}pMY8+9FxO|l5H6lS4?bBBqPA@_U9s{h z=rIRX>x~EaXGtjLeR_>IbB>T(7HeSPZ*7uL&_ZQb&0+j9HE>8i1i4mjpim+~)Xu6y z$h0~L-)9Y9MAbpr_9;FtS%Fp5i@4u=i$bmq;N8BK#IpIAs!A?c(q^pJP>1l_S!C&` z8$RPd!6Z>jjvyT+^F7nSBUBUY%+3(mpRFh(CIfaVCE)Pp1^zOU1EI(1*c{WtnQ;Y> z=%hpZd_VlVAskg!W-X5V0fGg@UrG2r&SK>yNBQ%KMFoh^MvUef8d~@B|1&|4W_Ow&?~G1d%_>k#9NWH zt9L58&z%ohvIcnP$8z5Jq<-{fz1V=ae@Sp=CzWPQ24499ug@zOCmfZ+jm<64mA;VU z9d!^$??eo<9mHU{$?!&1Q5}UP$im_-%s9`_Jkl0V4u9(b^_tbFXSE2z&ni(ZJH~ca zc7%Ra1w7I=k=r-N1=IF4;qSJGls9vf7HgCfckPdC#~(rE;w>r9WiI-!WV>R4Mot9t z;bRUEnjX*Vu` ziERjJeZ3DK9%_R-;x1&SQx4aqhb#TDIkp?8*nL9TDSxQQ z*jvtu7+tv7^8{v|-vg8Q`{~OUwh+AF7*Sn<_(L^|r+Jt|#Qd{C)|XF%4v2C09=ZyP zu@9baoW$LlO7UvYRSXd+17%0%WR|Xh9l0Ce%-lAX(G|zr2mYc;R03p8E+hhL_u;hi zZnpcff%Vq*oW18G@e0eD_N}}_b>phxPhB(1cBR4&ffVA+Er9{CD0s27iHNrf@bA?} zz?#}LT5>>?tM^!e{FM|&`g)M)OSpq&yAvoB4WVq)DVF!Y`XpqXPS(BYwg-`gzBpm&ae8$w z>j;QG!O!)N(01-uZ1tYZ%@STjq8n^s-h2UWV-^>$d{Mxn4h=L3s>9I0Xx#kZCY%|2 zf&b>W;bG=q@lDu|wvU~lJw6sSt5P6@yA6+AOawctB4R97|$oUEtA zL)m^*B!P494-23o8==q_iQX!$t;5W zY+;Ph`-!jqSW!0_Psmtz5rZu@V}+DAZ*5WlouSu+_a;2c)G>C(#3uo4ZP|=jz6r4Z z)Ml8*W)4L%eAxBh9{P;+i|=S1gMy)2e7>XrS}V`MD)}k&it`Q#3S>L8$Aa+Ln$0{K z#kkR{+sLNghj8QkF`Ut9i#o@@6WtAgD8uW695Fu}*?9xrgx27rIXqsD;XeE|IE+az zoxriq6P}%PVteBulvE0Y_$jC8-M16n$%&;fC;is&vU2jkU@-ChyXy zWYlJABU!>rU6usgey&n2gOtG)Sm%Pu3La9rcVAJBym=Wi3cBKp`8y$QU>g$p?x3WYySuEc#?ZJave-dC;;B3Yb4IuZ%?CBDf z1z7k`oO^T+yyzT;{9r-;q)so`kQB^G3!4eQ9#4eUN#pe3={{KaBbS)m zw4g1M1^ALtr?7Y-1qnkj{*7KYhPYhtS?5 z!8fpLqtbWJv1i%|w`&)pQcxc(eJDouS5M^6(-VhT>%0m7k}s+*eUATX2f&QYN$owx zp(=e6_o}Qb+?1Wh7f75%PrbSTX5dJ!DgL8J74Opb??Wg*yo;#r-$dxqsSsjOh!Gn3 zkSym21^V8k(8vu}+D5_z_FdMY{1XEWYVeeOAYBudE2 zhjZfg4YDdN9UR@uaC}b@h-)J28n%JpIa&D6`!6<$27uxBH@xp!Q@H1H^;!1l0H%*F zr_H;gh`{R<;IK1$Fmq53XY&W%bg*RPtV;5#U7=Y5$_t;`jNmZOZN`2M_6^ALHBzT?lH+Iscxy)mC zDGB}NHWG{MAb7J3=z7){e~|hcw;HUVE?v!dWRf?!wrs$@WhrEh>{Ig0<{DY6GKljs z+3vv1l=3}K;k5aD@^?iHn9Nb<)T_CXKRX;rRCEfS*BHbFm5wZvJc~LseZ{f+Rk*u* z023Ph;bVFm={TGVdoPM`{me_@)bu)D?%iWhUYm%*)80WK=MlYL+J#nPkD>LiKZr-= zfG-iS$z+D;sj-Lmk$3*}xdVOy(0y|B!U}2j)nf^Ef$D3Y3+?XijfAPeK+czO= zi#EK2c(iVI!=JJO+?Kr)A#C$%j?~ULUaIy2+$;GW_jy}jrS3V9D*uXKb%eQDi9-Bq z*AP6WOhCtuKs>sk5Z_2hLu#P`el`!n>+C(+lo*NCj*B6-BL-}o7DHl99^N|{tMcTuVVMn$1BlwFNG-AZ)986IJr8T zd8h8b?KEQ_RfP{5ts1j)BEs6a3%QNeg;l&l)=U68|;ZIVeeLNwtMQu9rigW(j>@roAU{RWvxM~CKLI!%ZRB#B5#Xl zBB*HD5!Y`b`~_P?xj!)obt2;MbW|6u-uD5@W*1@o?*~}2l?%~APT;L_0MB;$V)oL> z=-Rr7zIfY=?!~sKlCT{Qelx`tPkP`T0oF$DXW7jCa^2>E7^;U?SxZi|QWt}+ZoFftbya=>XZ1HV#7pB^8 zr{!$-^2Kiq+#N+wb@l?dbFrWHbuWS~OYMl)k#|&CjqR@QS>ur$8xYjF0m~P^z+02{ zKu$#i%(*k5zCi97zWkO*9*xS9ke`02ubcu?Cw&BZ?EvZ>olQpsAK{f*bFq8>LtG)X z3D>R*V;vHAqM_psk4OagT$=}ND&pM9(ZNvm@hfP)6XEuUX|g%NX$*X|2FuRJftgYT zaT`&`TVlc3e0dpIJUI_b4kVN2v|O^OYCT3QY(p3MTd25w6#qspfb12o=y1R@j_R$` za8`#&+8Al7WRvJo=NHJzLVL*@|ph+NIfutq+Sgxr&Xc!8EojbF3r znG2OD93jX(5Tu4dQUmb$a5YRK8L-f-6fGyRuJ^%6vf*+ah)eFmYHe?@uB8}1YKct; zm%-k?$9UoHJH}|W06U4_n3#&3OG;z(Nw*{RW&I_|lNZ9)AI9KSc{o#CTNzeeKpbj6 zh8K*HTH1!;?Aporr}O}pS=WDYyam(Q=f0d5_Rb&D zz3id;$T8Gh*GD}I7NOxWJ5&tqfc)Y{+*95IQqFHkiGn#kh*p7#EZ;O=aSx0i?4%}6 zH(*dHn00NQLu_v@7-%)Y)dmgTnCd!WcQlwj%u6RaiBae-qD${vu|7k2GXAG@9t|(J zL4HsypiwIxxl+$F3Y!meduO5JCMA$J)kM`hRa9inJ&0y!u~&%?q0AgXEsAl1!#?A- zIm6^gO+NHWyh7P94{~=(CwA=ni;DBE!t7fw(1n`f#6Ra@=1?1aD6oZdS;#wXtB>ic zs!&}d32P6%h9kd<5tbKY``r|DT-y&br>%j3nL1cub$ zT~ZY|m6|fvwK$q}yvMUUH^TRc+j;9jkZ(A*6S!M%qg?JC)-4alho?Do_m}VVpW09G z8lDIRUJFpY>Mk|gbFFwEO6!hdNnAD*3)M8Es4H0Sa*{Gwclu|k*eeeo%H zQK^g8CpvIJjWJaYa>LttPw{+i5U!E-#^QoP{JcyP-F%Ot<7-8n-(gK}-fIN&r#p!d z>m)s{jm2uOkJO-BoWHBIn+`cVqDHeE(R8sZsBHN`=Vs)?#xEndwzCx@ejC#(4vuKe z7(PQSQMk$^3YP55p=lmM+%-GAuzK=yGN1YG&L{`K(m@^A@1Tl`8+U+{pBKznu?m8U zBSBdG9fYm$0o_HRaP#m?aJk?EQ#pyG+i#S2f^!Mh2#3Swjaew?eiu89*OQE~B1o(+ z!{qE^kZ@)z={t4`t7>ZK9cN9van^<;xGg84N4@b)fEl=@PGv5LlkjUvFcz^c-8{Gd z@ULbiPvf`_`b>HX)5M&yfnGu*aVz@mjyKp{55^sH%fK&Y58U|kjO~2}Q1+-bm-%nQ%>@_m0-MX3LZ||0G}TTlgqC4^xM1#%-7;a7FQcG zU#BRSHU>hL!Z>W}e2K5jSUxvTkUObcmn2jqz|79wyxNz|@P6|%R16rv2ix@VXR`o* zGu+j|IP=8#j&_iD-&`Cqd@U2z|{$x$s>boToENte-*yKbIN-la)S=8z4a3p zX33~4$h`xpfyX#{Win4_U^{bFInrv2O6W7rBEN@o;e60(&O(bhbWr32+%?WagWs-b z`{)ZwRi|Ol&9|^o{v$=H!w@Qw3kt!J_~={$Im*vO?I+jBu_e`zZ^XFc9b>#-?SlNl zyJj%a?`cNI(LkKmBTmotJO#tDFsvS%4il?1K>vviN(?{8T%#v6VnHM2sR{A3{_#Nf zZ87)+oWNiQ1zKvj4Ty;tKjz#ID3Z*FJlV;_>Az-tH%@8(a#h^N|BouS+{AC6YhcZ( zW}K>TMD}`RK)S-~Oq1w;xNEHeJ98Mq*n(=Xnpp^f`(qgA%MQBEG{NFEks!tMLlyHs zXt*W;=PG58O&1X(My_%40>5E`T{Wif{10V`KUNpSs7D6f#;J+jD9{wan|J#iyc=Ni zU*$j;So;`3Gfz4F~P?PJ93Nvm%${j^G-*y0`Cv$P$FI)2QXf}uJtwZ;P z!fj}o}&cbb;$z5@;qbBQ9$9`XjN(M%5UyMqMqDuwuy%ZxG; zuARfigK7{fJ(qa$^l`Tj>%N*!Auh$)B`be#T*eJeZn%4bCI(r&hRYi#^6R%1;&-Q2==iV$?KZNJ>E&>Er^;&QXLl z3gU2TV>24>-V6ML%%OCu0dwMH(c8)gMe_H9yuxjKu4+xkBCGK5*Qs1HYguruxDAy9 zwy-pwg1VR^l;?_Z2U{#)((gw4o^{l&T}q}R`mE=xC(L)3)K?0A-Ee1uFUC?r`!tM`~x#5>q z!?Pj*x_h4^aWTFNKW=*Az^dJzG$lY8N)A% z@cBW<=wx{t(5_uWW^9_lmz1-|O-b*;*<6JGK;t#Nds3eyrc5TOXBwgJYcH5SiASUQ zeiGbnK=wQd#5U0tFY$keLk2sOybTcbAtc=c%n^WB5*{X;g1igI5$`V_>$ewenbUTI&VR% zqYvi%N9mmjZqTp!9G7#FsM(ZNWY_H%aLI8SN^F0?I&{o2JpSwembS|6=sJ%<>VV`!1v$9 z@N;n@oUiT!&#a|b$$VdqE6vfL@!n&d>OrMD6$46Sar3o9_#btG!v{ifuJ;aNxpEdi z^2tSX%JgJ+Y708Q)C>Q)7hs6NGxAAG7=J6bz`V`M*m9#8e~w3^BIDX^@)ZW1(TDV} zXBG;%)k93A1r=W&2a_+bGv!pqx;lN8Ou|w6*?KA5mXn4HPJ%RQNgSFL=|gVCU%V>V zh?4JoIZ6BUA+Ns_w>)|TiWwSkG4dHm+}}r>bb26q%RHzVD!}C3b7|FOAB;aaj)q2I zxbuMth)-6-uZg#zJ%zcCPqn}bS6N)a+(2itPvTn#F=(AQ3QF}3nE1LDpPUM#2i7{G zR$eXfrEvAU0vZa`!Qq`e5K(yyBF8DL z%a4T1hRl<)MV|SZCuAh*Y@@PG70@9hi^p`@(9AUnZWnq|_1huX%Q}>`1CspDmk!_w z(FZtpxj)`8OJ>Z;#dyWvfqonR0QYMd120PjkL-9(T6b#mwj7Jb#0bX!%@gMuzjwrK zn+wo6@ENp}v)wai2i-RE051-NLGjQf7@5-ufrqVOK&cBBNx0xy?G{XZ<3(qz{D4w| zB`B+QEi-oF3;N>F1lEf>M!Qzkqhw|Q?_`(*lz-2G-Fd}eGi3&DulPiKhP~nbg$UfC z_z6u5Z|(?1RN#V_nG$?6mk>M_j4%?N_++OcXgm#+7FdB7Q%jO=F?E{1by}2 zcz2fvnBF;xi$>RxOHadLWa=K&obSyUDv$&@1!3;|?iRRXE<;~4sMHO`er#a#rTXqp zIz6a}K8UV_-2FkgUQe34@#uX{lXfrpxFG`CL;s*@+)Tb@YdX$qvqstc7UDK75O+01 zW)AMx;%#uZM9+#$R2&{4VjDdn!dwE*+#II|PKDuGk35_>^;Fts&KSOB8Ai9|2!G1Y z!B4?=cyD7BZ2T9Tv6k)p3Y!YaisVR$=$;Ns&Ta&?OdHHQD-4DEKSJ>IYS_kl6xS{I zc=3cAh-ak2Wj&VrxhcXmv&^LCD;%)scn-NVZwq{wCPu$%QMkSQHcWNtr(6BK$Z`u! zvYT{qRKJOG)4cw1Y8C@jnt4NmSq>WYJHp~)AFyGm732wChrOo`z&ZU7Q1hmacX?GB z$QP_Z(ws}`g}{y`@)9@J!ok=qMkG_9PVT~ zqP$2X44rw63Gvg>?#^p+=$Z`4Jo|-5A1*+b$p}$Wi(&LN>tj~sVMX!d%$30wu^4+9C6fH?s_U4Ymlp#}vUgcvv$PY`uAqZJ!R#bGO5d zc`c}X;~HFUdP!35OY_%WXoca$h|4d3K*PPV#9);W*VbY#XztnoD%V7C!&w(t;*k!O zd2h+Jvm>B8&l}aHzme{;Pe6))qG;wEx`}nOCQMHteO~pjEN%e8v((sqash6Pt%1B4 zV^DoF6BHUpaEC%M-ut5i0%_Nv^0@{)xG#wvNB_eT<(V9~Dhd_f7oiQCr~3I*a8+T> zvHy zGH*i-C^}Bzs~NbU(;RjDlD{4Op4YgarlIVvEwEds1SjpD zg41r~$oUaqj(?X-M4k21 zNzxoS+9nqWHzf6$2mT>!JtM}w`!5&7j;#gbTT}4a!UEhreuhX%hQP{z3i$VL8r``# zmHu&D4>k3TobwO;VY<~A>`NQL_!r&mjNV8uipSBLUtiL8@kAQl`UqdPRlex1)0&fioqu0->5_>=V=_e)pdmj9Aq>7o5-qV*fp{~ zjmxn0tuZ#*ln^b!b8s=W4{cK4V8wnp{F*6xfp#|x|vw$-Bt){kBSnGu%HI&%`|F71Ty3_jiQDHrZ6 z_kvLuA@1V1SDZ&)3-R@&VE8A)#n*<+4|n1b=vQ8*Dpk$U^p%hICLhC`Q?Gct!lrVx zv)AC)lxMW=N(D`K4b0f3AV`bs-oom~3$Ukqj5lm+ig!a@>4foOdOqk0a)eu;=e-d3 z%!oBi600MVx4pw(O^hSOe&>iNGZ4QNf(FsdyRMXn>FX1rMCuT1d?Lb?sbb#8qQ~gI zf^|k*hli3&}#f!}w=i0z`CST`*n4vEF!;_Y4JT_QU_kAH-&J_r2n zpAPb2)^M=!0GwPR#8q7W8B|Wpf&+Veuz2J%jST#Phy7!4RhK#}W)|Y|iR{7sp@Y0qaP#?tg$oJ0CNy zyc_GRCc~01ImEO^0R8r|-MaBVxTKj4w?(z^;*|=NULnmr>c=wjJy+RYL<|BqG{V)g zN06I02JJDdGs1m~7uILf1=oY1Q?`c|*>A!r%46K<-TQ3u=mQb%=SwFrX-zD-Cbtp~aq`Fp2@87pO#$H-GalE~S~#lt zjQNZ#c^>V*03DPzu4`z7d#C$3;r=c>>K_XB5fQj`R78DsMGnFX75Ez*i}5*xxpqYO z13Q0Ul-mH@SUQpaTA-M!n^%+44l!=y---Oxx*Xp2g)<>??|(q1rZG2UCEA`i#`$aT zmClZ+!9@G()N}qf+%3?ITF>VoS?CQ}vu8lKp9Aq^dD6Cfzp3ooX>f`4n<`&r6BB(! za7%eWZdx6K?XUb07wv|h%Ld4bQxj06u?WP{0wLX>xk7~}g4?m#EFUR{T2GDfuHX~8 z)H#nPt!c--=GFAIM-p^~Ig{k+=P+`L8LCRZg6DIZU{QZDZJ5#u9Mu&>TqF;!vUf81 zu!<^4@5LWAQLs1o1B@>JgiiPM;aa0Mm_Dtik3R*1l+~s|RV2#Y_}@ z?Sdng;pnQ=Moizkqif1~qJG95rz`IO+7J%6&i*1kVKdS4#$EbUn+GZ@8;QR|Eo?Ym zi9Ca8WXe$s-W^>vd{WvA?gOQ$I}#4h>RgbM<4Wn5)#U2_TB`oB2@M|K#C>L=IIklC z;wCwu_Et^aGdow@r=yJ1wQta#bA{+LUml}ftWX3O+*g9EudZZklRnXVF%w%<9%9}v zA6gr@2i}>Lk;LHvT(0*5118%x(WHPA6c@Ap!3eA_yatOO z=t5W46-e_?#?Ko>`Q>8Hj3qW3LOiT-NSno%w++L`&h@ahCYEgb+k^hK5~!cVhnGBe z%->(f8N4}>pVKeO_uMsr2FfZ36}}jt+(&*Z)ez~2aya#sHFmtug!ls+ImWgWV+_Oa zgCq0P4_cw~EMMGV!^Oy--te7ebJm?Tq_xA1MBKO#LXUUxzMP21MaHr8A7>_By*80Q zLvu6g3p_{1W8V1o>O}5AapsSB?FNR4KOroo2DOf`8Cu3o8b0F!Sj)_Zc0V)n=CU|f z=jH~O+u#h9+8I0-vpm>0`6RZN1=81c;n?t7h#xwt1}Dy!5yi(_aA>|LKlk4uJT2S~ zo7Eoi(mq|LSr2-_Q!oJFfi>!T?8h*JEf_WJ4hWXikv*Fe!SF~KIJ3US?VB!m!P6Dv zby|p7g*Tp4hO-xKGU$770j04fkE+I#*U`bTajs;lIYyStITm3PE-J3V+4T7nQBea8W-+vITB zZm{dm6)JAM7JId!W-VkP`mU3wU{S_3C4CfwVI;%zO|$`!I*J&e!}|q z4m3UCI(Fc4{4?l7jxRreM`spb-}nyL_udQiT)vUx87tA`SrP1GI~pNp9)`S62GN9Z zY*J!=oWca+nZpOQ(d=tDwK8-R1cn&44>G2`8~{pWxADg_tbpw z4rMuiO-fSi?txs}QJ$`1Gv4y#(y7a~!1>WNI8|#99?S^DVe<~G9hbl&jURN;1oxmoH?YZNpJiSl9)!XBL3B@E+KBse!Cr z&ANrFAJJD=`#9GoMiKm~!rbN(827b1hfzHif6pUKII_fP5cNM z%{tI}E`gTY+u`z&Z!~O%5d56#iM3&({9RuzV*Lku`0tZAdITu0=b9VRJ@;nf*y&Q< zsj4C5c0Pxz_ED_!s7&F04sV}t7I~UAhM)WY;416&Jn66bpqA%|PVRm1tEv`Hn(xQI zzgT~CZ5x!&&Oo_U>G)%fH3ZN2#W>7k_`=~M-V|@ZwS&I_BaTDS-$!(Zs~~reH*;Ie ztAhm(>gj;G3)sIq4yNT_Am#jKY+(>;3-VkNOM>xxSQjWn?t=L<;a!5IlO*x z<}B&7LV+W_^gBNfmRIbdoo6?Y;AP>sP~U-bYu_mHWj*1)ipSXgd?BpJO-CR3H>g-} zk4{N?fbZ{}C(VBxSue8y_7$-2#AWS}ZWIDt7G@AAy9~7&KI5;312FJk3f=Cli^E1j z+y_Hb_!fBstI& zD7X1vE-9H73ojWvblEd2a*pLRY_$3C;j|9Nv+J{Z{5Llo&u)U)b^ue6ex80Jp?o9->(^v`t*V znA6W8O57X8O_Xr%gmfBR*8!ZlPcbZiF1w4l!1%E-{9x#XWrHKQXU#9hM_`<*@Y#^A zd>(C7>j*!p0qx`Xcf$Yq-+Xz}FCZPMY zulVa#8aU1hLc1RkbW;`cX#1yt$^8T{c3nlk-sph?mL8l=!BQ~wYsc-n9{9{-GWYV~ zCMdEr!L9dagVDz(x#$nOXA#a$7C2xb^-y(m+;e&hb#6f(K&}yVgC9x zSR!-}`%UB^?tv6`y}XXo-e{u6Z~@~H{p5*OYJhH<2>+W~24r|%g;{LRIa;`$bAEXa ztzI|*O%$_HKZ>z;hT`F1N*Fww_!v#Eq(WS1E#6*bgC0G#7ZRg&J3IMg2;Y3QVSh_ar&#a-!JRavM&vY=ZGp zd#JxT4`Zfk;hV@-?A3dT$3C~R8ABpyUpNfjFM=6U@gQhL$3xB=L9QRC3ZD+wV{pGK zysqo#*#5Tz=Y5Ey-_Leqe_tKTHfC{Lbh88ftFxk&*3pVOvNo ze%PxG7e>VBZuVR&l*)5_R!i}{OplY(zTdF%M+Nzzw+*))^CcoWQoQDMU(rK-l&tj= z<=*lyfu@U!pn(fO&uBTWiDgocxCJO|TteFBYQyINCENs)z-^56OE%kM{&+Y{y4Vk9 zX$7$1l_tK(culk}nPbfN8DOR(z&BCvf_HoM$b*JTj8U=1!gpMF^`Q(}##R&2nq=@h z{{~2GJvxYAgo|%tvA!(@dP`sPo{49mgzY-IQ!5$j6op}fRS@=HYhgaDQpO&c%r}g_ zhPU(Cp@}*Z7!&jCPo?$C2+F*l?dOa9-)gJX1#FLS&`rA zsJdkmPyUE4J?@-DVjq5`D_s{;*=WW?3$=iQ_MfmWlfcdild)u`13WiggPnFS!MXM( zURee3^GGT>K6wgZ0b{J|=?G(TzU1#?EBdf=E4@F|Om*u$F{$PtTF>1FM_WCy=h1F5 z@BSF>zP6fN*&C0yqC;U`z-FAB-~ux8EFbnr4SyO7s+$~HirTz6%+vT6BH!GBkX{~1 z95lylnIA}3$AirMWAIURBT1;KhU|~F`2OSzj)q4c7MnC;#*ZY-l=u%$o!pJn$Yp%8 z@-9@b^M{VOZ2Z)57R+Ct0Hdq~az;#-&Ng$2d%{?TsI%Q65`+h>m6(pFT!@^960X~f-B9#!T(@6 zG}<)6C*CGJH}fw|C_6+q4Vywj)O-v)JOX3k7NoT_9B2O71cN(tsHAoaE$N5?r?Os* z5!FFw-5x9z3nQDw!|{5uH0(Y39g~_PQSWXIHLd8TmR3*kov{zpsPCu0{$7Ef1;2RP z%gpH7-AmDU-UVp5E05n+xwAc&ImBqDL4w40q7eHS-WE7P!I(Z8c9%m$#(6S#e;SSX zVgpJ^0qEB95haWMN6~pWQvJPg+@7USR4SD;R8pwi^W3O!OFKoICQ8yS4auGnp(1-^ zWF+C9=UQcNqU?l1qELy{@BID+*XQ#&=Xu`m*GmoW+$aZIqunIHCLE@=F(FG6ARMg4~}=$6>8>HcUF4K_cYW zVgIBdB2qwrO#De>#RT~~k1D_;F-Oon_zF8l(y+s=3BM_Zp~SWM(0a|Eo;TSCn*+OW z^3irOZ(<&-jcJ7Kj}q|CB}WuVC;<$z+LjwxI&FW^rQ4-M2~N9@n=0r z&?2~V-eNo%C&10RJA`6qd@=Z|B)8=hpnL3DdM=?E%+`y6!BRVRM~MaAOntZ&TZs7y z(_lwq8ak^sf4Y-aCaZ`k?FaB zLQ*=;nPLdDp8#jBfEUgBnSk080%(ff7?>GELqgHS|Nn0Tzu6jM12%AG-9JZ54!EH0 zD=iEz^dmptuL1w>rV!q73cfO4r(r4cOIeiRlGXvZwD$+yG%`f}79NK9?YZz~x-%-5 zmcoOZJ)934jbZ!O9bi9p0E!<}ukJb_N+;Fkfn4@(i2lK%h}ZlGcaAR#sC)v$N* zB}>?1$E7=ty5NNLSFqvuYbY;<%1 zV2=i0OHo-e5N6C4AYO-=Yf%0(&OP5rHYwg@-kft_yGa84%)8Nl2HUrc`Jh7NV>A$X ziIa>O`*Jt|>)kh#f(4z_U&I`Bu3Up!Avt`L9E}-A8X@(8CoFUwBEju3c=q#oOw;q{ z-TLYa&LvtXvaFhg+d`R_&<=i0x&z8Kmv~){%itRGBE=uvLxr76VX1yB)EHLcPF2RB z0d@L9_bM!SnhV`@BK(=G1b2)RA*O8hV|#I0(;wvBZyb*Hhe_(`Z(YXD7wIdFc#QX*Mr zih&W1xwv^c?=c@DbZn-m}a zv%iEIroYf`b{OiBr&tgb1uc>5P=Ng{r=Pn@CBKc})5e#03MFXst_av_WQ|1O6)dlB zgkhmB_>onMS4Vasck^acH98F^@=s9rxQ&o7ss-i3M{x6s1sFBzj!WOZ;%&W8p=k=A z)AIfbjwT2a$wNN)M&mV>b}q&b*(SuiEOXUt!BNr*ufbD)1!`TH4Q{tn(N{H(BYxW! z+E0t}jlb2P&%BlJD1J7GFT96AzYSnk-4qa8cbHxoVY85_B5+*h3(6chNuup}c#%ZV zKEZ3K`S~RX*^SbVE1%)MMafY8tP0P1?0_)KVwBrDHFM!EH!ROK0*}{a=-_7zkKYP# zr`!p~j+`DcZ+Abg+~SP>$~9z(fCs9~$)K%;HJshcj)9=u1itdwT3j4c1xJWD9T#~7 z(d84k&f7PmTw5$uoWDXXQnIlAHe#lNG*Gu7ls>`DDt_MHoKjo1SO)5>UvE=-l=}Bbav!gd0uTLX9K)^x++v!G$MRBm<-U#(wOtz9U;pN; zxYk8K-u+5~Jj>zV)K}OuJPo}UXQGsi06%yCRMHV22%HyftmnLiabuZB*0=(-pVq+< z0TGsub%9ySyrGdagR*8BYV?Y8=P#Osb{m;T@%T=-Gde)RrzL<+(?>dKND{Rb%VE2( z5ZQZb3GZTL3B;z(#3hx6pth+5Lg&SkTjmrB#>$9KKo%ZY)d%**Z~h-_#Gp^i3;TH! zyzBBst@8`vZ;>Cqb!D89{*UOy?h|dQap=3<3T92(k7Dy3vHKAh_ulX36i7eAH^R@r zGjtJVr~SsCLrp|zm3Zdm$};RcS;V2CW8l$1qp&N_1Hz$1RjnhNFsBVEI!GPSxhZv93>y<7bIAk!lbg6o=Vs zUD3lJ5%!TD>^k3yt}_^4us@ib3~$Hg?e}ydxK)->{#46a)`ojYQy zi8(J9!fbg<*!tcWUxq7F_4U=b+C2&Gq&VOLXhgAZ4|w@?eC#~o0P?A&yrpv&L)dY) zUsR}KxhOrfG>wN7+#s6QwF=7JU!!iuOmvlz2I2fPkekf~+dtaapnDDvn51L>>0{hBs#+ZxCF5jugdvgI<2J-VxN zwroDHr!5S8&#~-r;Q%$Alf^r))dg>B^Le!g&%*a!0shRF6ZpfeH{c;R3;#AH)AhcA z@FgmXqq;o-P6W3>^!-Wn(!5a`w)z2ZsXy6kYDHBNMR9}a8!~XF26|) zVCpA@2@md}#EDeYbGkv-p8gEkzs9h{Pk^5k+fBr*&EWf!dd8WK2ECTgVE)b=<~gS0 zN4J%D6VKto*fcn_l?(k*tAKxqLZfUx8eVvTb7oUKDgKOc$W_58<_Shiz9(UwWoRPT z%yMMUcq=+fP;mJnnA~@s@(T-Ve;y$;EprWoWH6gtqHksKn$IXkE(sjQj3@q=XVT z@55J|-qeS0_NbG7$5EJ4&z4!Q#9_6w6elm)8$Dm`0I|6jNJ{=Kurb*UvfutuSDP>z z?6m;iTeZW%?IrYKfGy7|um(;}Vs6(2H+Y@02~NETM@a(}R7hmpv8Dph&U41jF)?zn zyaJ!f$AM*fFa$iDjzi)hxI8@!zZ4;K640X z)*az}-Vv24+EE3A$`Y{Y{AM&+`4%JU?7_=*2yPF!g0!(1gx+t%*cRc> zuSsQHGhXvEfnE0>la5J`;i>+8T)47{F1>je+4={+XEwtOwvQOv`Vn+g*mDsSN4}4( zLaC@0YHI4pk(zZ7{;C*K>)U}m)w>&DUC1lu}5!JqH8qt-w^~AuX(Ng=jbCAlfRz{kLxiV+wm?zx!vj z-R%n@*H7W@fLfkI|0np-#5@~mPw>y=5}cVhhurPg1@GH4Xuu}cm#zCmogLrtt{f2N zM>AH6U04cgq-vt4{WvkM<$&`>9-f#xfs_By3UwVFN%f!kAk>Wwq(>_4| z3HO6#MgeMS7@)_rU1Y!3bX=M-0bLADVOq62??hBNa=8M0VOKWO3H=35!*B4QPgmxn z?PpM`yNsUhXu^qTOM_WP`iP+w9={%d%RXw+>zQAOXy9@B_Tv-yuO%DI-UhO{&sT6w ze9T#LFayG-tMcw;c;b}tarmXL&eMssh1_rR$(!~r;;?=m>R3nM?Xf0O`QSC~F1(Mt zZ+>`EqsM(Tn6YVe6?4$cr3E%roP~vc zL(pJ(9q<43#XdSQOO)(X;HJrcn)N^(MltjsA?IrbutgjH0RfFf=Ub#7-kU3_KA`V{hx>f@>n& z9F1ObH`0c)V5Kl!;bwpr&B`$Q)*^b*+Y2|jvCPVSAJQ(6h|))bFm3)-o%)x|f%v5q z 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

Y?KEej?7*KFywwWauT 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%0D%T1f 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≪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 z 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

9JE-q@*u z!W~@VG36cgu(=KT-kqdlP=Gr}kL{&BrtoKA4YI~EqGc_vEPsUd@xSrWj$a({fdpQ| z0|ovxJ2vx+6X7d--c6p{`{8r;Sy^F|3JzDD(Fg)zc+3|9vworW#v`Z^S_3a*)EUm zsIyxy@S3E!_s?vHn^jgY$2c8o3=ZH@kijBlDZDjSLN3RTp>KQ;ujYO+?VWO)cxV1$ zeujs@&%BI+|Biyxw=V575n|jW1%ljVbB1V;#RP7Kq&(hW`?6UfqSW$T0xg`Z4US(W z(Qo?-*zY9FcTtOi@A6}K`r-|^TH#HmD7c_{?n~^H>BMyhBglx+d)zJWgr@^dL1vyi zJdPYt9x<)~O#1ejk40pZvyM0iR% z%9>ELNdJUfI+gojuOu`EGRDR{C-AUe1F1D~e9bs9uEIb#9W_ovIa2{{3^ieFk0)^1 zH4xO*nyHAqGpT=C#KAt} zdVFFQg6}>@ab9Vh#3{jd(a)s`>eueXpK`^pVg7u)az+~SOE6E7G6QmDMiFnS%@nfkqmOY_2g3NdhPLs z1kAng2^--z6#r~iQ1zGLrIcCMqWG^(4qf~jpCXM0E~Ty0RoU#BN=M_yIqbxk4u=-qy7 zClnJxOA2az96)oo5%0l>6PyWggVUzUuq8wmqHig|*UE4>&o6@rHeX-bGlG7a;-D~8 z4*h!=$fnf=h9V}wHP3~du%u9&)-%Krk?rDmvkcbx$>%_#B@w?2Z9xr>mw41*GHL2a z0fz^XoJlt0@b6OxjSHAcavmAs56D8nRV>FT--Bhdd;o6S!SBWHU@+*yi|zY{LF(P; zWR%HV2?&<2i(ti{w;Z2clKB63hkJ=LI5_2y&B6(=-8dTR5;Z}1uQG=>(-Cj&D~4}| z`=LGaCnQL&0lzm7;q<+HTp=UR9o{{OYufMymh2cNiQ7cEf|_?pe`XtGpT7uyteI0d zxf2?cenI*ERLC2A0ZRmCuzS%<`t{#+B7Hay;|%tod1VdeW<^0h$X z8NJhJ3s>x*T_wNtE z)3XVCC2r&0zUgT6_aHtopFzd;iEuR^l%v1FGdSqKh_t@TMA1qam@O?q54{S8rz)A) zkuC|J6t@wZ$R?V9vjL-&i(u4G5uzt;;K&RGlik||cz(Ja;H>We1BaJT&n*Ga-<61v z8v&vwZ?)@YFQa|t$1rxfD9~6X{%nDhj9I>nRQR}}Nz5qu(Kmu0*4-jOi%;R*sr_{3 zv3A(E*bS$wT!&;o^L3ZH;L;g#I6m|Uk1c)z|MKmi-?@q^SUrK+Z~0&zpaVuyX=GO1 zOL#GV5L2p>pwdYhsOT8)?`77l*wBKf-@Y#B4@?1Vt?w8yv6y3dx*1Pwk-~TVez$*2awX!%!It2BrSlfv+gt3OEf zPUL=8vqFIjh&lrz{6ViMnEXDE`dK{$$2p%s@<}L0taO3JmG8;*Q(Mt8I|>JPP2%1X zvcLguC2X-jfX=FMP?5$s@pCiqNcTZfp7;WejDNuuekJq@0$KvpkDuA{_+LxdHe_X+Lah?ZStKso+_C5?;J^he+dNc!KfD zlsNL*2C7aNoO2QW-t&U3xBX%2ZYR3$Ko^ELCvc=%LNVH?8@*&c!uqeTP|+qB6a$wN zjrnY@CQyY-Dx|q?=I@|tQ6SVR)Dk~@NY+eR32!^az~ae0y3US6gCjnG>w|XsE^-wl zB|QSeufE#$In2#|^AhbBhy|Tb2+Ol8;oC{Z(wXxOYYrX;6QgMQQtvs0uD?i@$=yTz zWeS3$BK$>RB|x7q#5hM|FljpsOtc86%tcViY71=0I1k4@Eyjlh`7oQ^{r<~YLAl(e z&{ggNzw>V3#s&YLX^U{rt^t6D(W zycOQ(O7MMIw{`odFG}Pvq;>E%)-^nbaYFZS^V&&hzgdv4)e-}zZ8Tw6`y<}CK9N7E z%M(2~PFSJx63%hh?$hW8=lf4lJU&m5e?M&^zdd9Vp7q{_KLx*&(l5ICK4)F&Krr)^ zJEnuxEq2ZnXTst)KjB!{AVwBH!I@RsNVOWk{>^S|-Ze(VeFE{Au@6jA%c7G$RN{}J z@9=B8D<`RMI{kSkjD9wo0>ct1_(eJ!c(U!-)FjI<4t~Qkm`=z%at+&(CHW7c6^WL7 zKQVhCj)f1}VE!pPyu8R2x3OIU+Gf+>&UV_t|3GcRC-8NzE=1w)r?DdBF&J7Kpya(L z;Kg=Gi*-KJ4=v9@UU!TxEq)0DN2XwiVK$CS@IYSeCueVO4`yrkf!L5EyfyEF0qG08 zUr&ZHCN&bdstXuTwSx{=jspKhF{xkr33Q#d;HBaj7&0XQxu)B|-YpQ84bI~(UdDC= zYwX~2x({}~Z$tr)KUCxW2iWsL7$3~KLF}ei;Vy?@2#OFVUV{B_<3~9Ds<6j|^Gi|l zRx2HySqLs$ld=8!Ae@p3fnonwu;YylS~?~|z)%G8C*8&;+5K4mYZUhwjsy3dqPA*b z7G^MaY5-$Hxu_1J*unR_v)UoJXYB@vS{01jCmW-U$~SOHe}Uq=WVKiLIb(dA4-Pti z!3l2hpufaj`?tM671|nynJ-_$`3_6qd#;Sko7Hf*`Vr>;wZ^pH^|w@X6%x8X}92#VnVXMOz*j4y|RL-b{)ZLHK^1}`Y zxsrhYDnDb9<05+V*n8N%c{7e&&4jdHW{l5O!PwoxcbVg-kz0nQ z%if{C$WCzlavq%FGYpKi;Dyw)XsjlK3U{vI8{r;USFZvgsVN}V`-;qrI!bk_@8UXJ zasD`Yfg2x6^26rbg)}e5jEN|MGdJ9Ew`vJZe|7?=Uv+_%Tqo8utpq{$o%G%Dt0?04 z3OY`Gg3|N{kg3C1nDJKlz|)8ROlgIm$u=m?=4-VPh2zyFT0N!KxYYZEk|XHH@1g^cg1i$03sw02e+sxNPbne*h~?=Cm2?`@_5 zi)%n+-7=V3BF?S8a0l3 zkOu7^XTzL)3*xf16sv{8Kx4Wb#wAyh6F%6yMD&9DlV$JfE?=r`oz?9*7>E{c0@)Z^1eV{Cr?9rrG&r&28% zXi)kdn!BFB=99kobIX0gv-u6~0z63H@Q*Y%MB~0RH+r{t7=wHwuq<2}e^=(Afx<>O zY9k6cS9(Cmt_tRD4u%;!bYZ^SHFSct(4d^nS#1#jreO;~RZ^oM!8G^uA zDSpd5z`~-F8JD7wOuj|E)(pU|_oH-e z9Ahm0Duc%*h8SNI21b^>knM4S-r9biw=ruk`C)F#Ikh1fTmA2lXDoL={`Wn)EVC+T zaSx(7ARK1O{<94W-p^6SF7Bui&G;?W$5LXaSDha7iBw7jE+OON-`{}gOd^zktGoH&bX4t^jnk5uDIwLhFN+YvmxD<5M| z*~7JWid;WhO62woq3Ux-h%e2+;L{o8xuQM!IOc~YZC#){O%h!iY)C5IOm^)20$C{n z{2FyOH|c)@zKaz>_%>q{u2Y3~hXml?89S7}){ZNgd)&60k5!kKqqtZGdf80IEjP2t z%$f=O!$}vhW9Ah4`)V{t_i!n0GV^3_+x^I8^J1IQgW93Z$jSL2#*f+e94{6yW_#KN z`o8Te3cnQr|1od8@BaWD--m!bc>?WQR^p&QDJ@Z7#TzTDLSxJKxJU9im30au_Cou4 z0(T5~c`}Wt#=4?&nMAHoFHfq`fm}OUX%-!61tq;2ksbrL5x(4|KTYwbfEuj zVlK=fBWgY6CP$!T02X$$_nGl!D4g|>&fKhm?h3`I@q7dnElhETR5^66?nKkeKfwO= zJKUm{3R~(&IXf)R;lZW{_$ui;-E901a-CWCZ`&y<=#c|9gBc*?yq+csCP4SeDg3(n znfSUY2LmmYV3C0z$g}gk@$6$L*!LQ~IIhzhLdCyl)?1l>Fl1hfb3^~5v=oH*)SONdKyzsb>IDOWZ0m{sG z8-BS6G#3Zp-j*oPi9QY?TeU%Dz9;!RN0hH2y&r4ZTXEmN514q`7j9Pg@M;_5!SdKB z&)$f6SmUk9%Gw@~4;04aAEyWvVm;@aLC!K`M^Ib)9iOVr#s~cpb!~+?YaUVF*kly4yiY}gXYfoNm*5jM4X~gRP>;sQ zJrjloo|n$OwJOlOd6s0Zf4=S7-cGyz5u0C z*p9YW3y%9NCFchiZ`dyetWLMnh8jDvH@uxbb_*mQ&trM0d^OZxz1F?Wh|)*yA;b%>0vdIE3jGSFe&0Z1GhCA=%9kXBNK z&LaAd5GV!mdfRy8Z2T#Cuo2ga*27^jTlC^i#v`1obVGg}R0QjjKaLfscRmhl)y{$N z*Lp0k%w)6C=UAxm2=xrBp!}&TzO>TA85{o4ZA}fNVTKd*SqgE7W}U*4sEK^ng9Xsn zXimnouF=WNtJ~7SJeDTKAUN+Q{wP&}ZT0S`CNL4ss*FR%xmv8%Vazke#&B*`0dtEq zczhs?bMC??#=l>W8_PubQ zI<_p1U~+{X4E4>!Jy+_XMo*l4CF{^?l{@E9QakXs*U_TK z8hD8DyDQ#^bG6nq!uq@}7n^_IEWWw7na zEi{vlLhb#rc>9_wnwt7Rz=8sLd6yObnJvh@ulWK$rT!p+J5?Yp=PMdHZ6t}2*_8C{ z2eU+57oEBY^Fyyz$dpz}jOQsFx>!?@kkVy`l;?7fSH6zXajgz#v@5 z4Z#1z0vLDY930*xMMw6Ypy#^w(KDLic(_EGuU2{jPjT((Z@L^VT(qTd@C8|6avx`h zOYq!JtY&YfGnlHvgA@O}ap$V}*j_k~)Q_jYo~&Y&@O+4E5|Nn6xVlq@L?La31oyU< zDjZLULFp+u^kQ;9OxKd+_NG1ncxDZ^T|7WxmJz&b9-~LcoY5~_37s;S&*pv?EUBFb z_#=TX5=sFh+hkHLeGYYR`vA^yWBquxD&77BRHx~}Iq!D3^(K#_u+0sGANJs`9j|c( zFM~K)tOMxzMatf1;Lbb;Q0aJr28%pF(=ePdsra}dawpX3B!Iwv4KQge!V4aY@CN@W zER^A;p39x|aYXTgjmd71ZOJHsf41(0R8CP`^ruDB-+Nq4|2kPy~e7nOku<%I$W(LPl^`ZnAeVT|{Ch3v59ho>^F&ch08{?IbaiaJ6 z6WQ=#AJ%lmA}lcKyN|i_Swtk6ixGtR}3nX~d;MZlD(3 zM>|d|fe&Yof{alfMn7jffAcJ|=+%h!nK{uAG15jd$E3Mm)B8Y8{VrssC*Y@P-+=S; z9}4X-f>=%p)h&C71~cWjW3}3_Zm%#uTF?QwH~MI-gD37|vx|X%PV)BGHBP#E2?*}F zjh^lA@O#aD*!OuN4!cEx`JW%)6E6mLsXHg=c_PndBmrMa93;~}1;V|n91?YNKOM=r zN`7z!_=}~yLF9freqKC>JQB-CyC=+TH9rF4_fq&Ws|ERmO{nGmiBvV-f!wZE2o;}z z+&}$zNFp3hjrYLHf@XSrP~FyH!&Rwt=r{KFtfzZ^!_ zwQhpb?0@9dT@&J4m4&xw?|_!&B^au_k-jU+!sc67puT>He2HT$RGnc+j5a~TMmw|% zAEO8FK1S80m*~iWGU9Kv0KRZ-=xEs*P*kDJKU0EfG09NgT7aWw?KF7tKRR;bBpwpj zL~U;tK-=m=yhrNA&>a^{qGMOVfWcjiy5xXpRt44eDKMdEHvYYl28)RUwYG>QIp;<( z$nYu7uRqMYvH3PnV{Zc0HuOiMbQfq;)}wtIj+~hW|AE!VrzrLE1tyC5!K(f5=~^vs zYC9y$-Ebryme|_!4o7N(Q*;8`2eWzH?_Ib*q8&F@_`_2fDSmleEmd0@$GVP7an@%E zn%4cFR_?i0dS64Gv&SWe9AkG#?ylRIxT2Jhs9;=S=?58+)wm^k2s?xrzu=5MY&p0R ziY!+^WdC8X$h`v*L5;X%S10Zl6oW=*9#wIULj!hC-WooQ`rdKF*eQ;9lg)Wmx&*me zFXmwhbH9D^iAH@BNtUaSgI>Ac)OKnWX}rT+-!+dw^f=4hdPU$h+fc%N6o(%_`O$mJ zXQB0kOuDdB86zJj;qf*tuv40V+Ifz6z1bfPtvTRwQJx<+M~GW^DT$tXQA>Ob^WjkR zBsgy`%iZ*)4>~R4aiXy>m!oS5Ei)Fw8r^5`*+d<6o|oeflP*|7vZ5=5w2>d zAAPHr4F8>+0@tl|aLl2b=A|`3d2%R<%5>x1;6oJg|oiUIlPpHJtp8PUSZ z3GmEiE%XiD!j?>X_6GkAW-%EMXT2VOx4EFD={MZJC5LD%DZ0L*DP zv651`Q)m|4gBlio^z8ly`rHw}>2V?Aw8Kdg}>B?6a zd(a<47Rhn*W}3m0+;*`1^hJBB>0=N~?9zU5q8Bw%_rOJiC=_bnP1Y5h2H%tFP!^pC z3R52AZI5uQduC1^WPJnKv{7Ox;SWngCh`wyPREl42IR`!5RflxMoD>5XsP-E^DjMt z<6HBfzhDxGd|69Ag{;Mwu?vZ)x(({6v!0yxJ=z@-NOS-4@PLCJE$SE|%f@1`)!P#G zSQ$d-E(bi7^9R)5zlHX5sSxt{4F=bbVN>Hg;0N8s&{q+V+|0T`2}kjl{%5S&!6VB} z^YGa+Ma0BwnBD9OCZ9H7_BiWryk@fyv~AsEeElt#+i)YP@pt+E2ui$gYq49u&*W- z3ywum=hQlInz9?driYS)IxR4*r3gfB1`*Ix;a-kghDP(aWp%K_qz$e0Mbh@ympy%MqAW?g?rq zK2m1|C!F@R5OnMLu;QmE|DxI(GMN64WmwfP?(HwsW4)@wA>p`p#19=03L>{ShPmm) z@gs2Y(p+mSuqlHD%bt^dD#DHQ`%bP%zrYd|<|5=-LcpA2y6eGQY~uQnPFn@YR{6=e zE`{)d?j_P29xz9Y9*Qc&B9$s96@T}Wn+HlktZgnHP&37C(Nj=v;v}-OD2CV5e+2|5 zD)R?7v)_nW8_F%Kz>5tb1+wB@jA>?wmHL$!VKYGXc=$jF*N3_czoSq7bYt&z=Hk0- zk3l1^vAA-GaYrV@C0d7P-8+c5!W_&=*bO2dHE~{|0*uQtUxz^`9?xN(vr`8!)z}Es zgS;Vivn+l*>46y!uCY9HAfA6aLVs=gf`XOo+;j2+8!Ca5UPi(LVHuV)3Wvtva=LlK zd)$8RDyAI~fkj^xxl`J-@%4%Y;8^HS#w)I%@A5C;U+%$^I4wsi@3+9>i_+-1*9Eip zuB5x&cfsu&H{rBIF?5}dCAT{_LHC0(%yDKJhyz+Oyo?d`xt@EwZ#UWVNz)!-X6g}dyAJvq~An}6k=6N(Ks!u0b#)J$w2E_oz| z>%u%)ZZ!h+IqP6j(h}(JM0#K@f?)g{$Vu8lwC8QX=9C98{dzjC!4cSL?*KYE9uO_W zc2E`fFml#O@UZ5SFZ&p`y1kcy5X6Fb&@g1ZUNFm-wj7Ox3LJJuJq1XiOWwMS#` zKjg;5h1{tBGj+!`z~E*sJid1jMz^dZb?PqQ)}w<3TSXYRM+RQ5_J#g`N_h7k4@?-t zSU+$aR-~q2UUw@TOZ$z%?eC%7dmC@sv2xhc{DNb8UWPiesgcf0wxrD_9yTJr#$4kggfkN=QU8c*rE0zRH*y~t<%4(KFhOcq#cgMQZ=$kTfO zAH5~`pZaTvOa3M3v}=c2`Fgg4ze|qS+=FBj=Gog?1^w?g5`&kya3gOJyt8UiW~u}? zG-?4N^NCbGO+cP1A0ro=!c|{6Zjk6p=m;(ct7+1F*NoTXz?9eUPEd~CTR8>JyhwnR za=X!7a~`)>i)EUD)oVoXO->j&-eo|PeO}WS!~0$D_1F^v(gPN&E^OA=n zp>eVu#+jc7>8>u;p*{K6yleEPJps&O7yN^4Lol}cqv;;Q>-N+ z)6$_pH>D0Td*_3E*lymriuH`yb%LV{p7d3IFt57u35d5Ovc6y)%R26XJ1+%LH1_~b zm7dJ~SdxIDMY=F!(|>S$?IG+t&bYc;OJJ?jfAChTlkzQcp!%LE{HT7(Sm3$PyuS^9 zN#$V6g;%_f6IwZ~_x!+4RU1rA{*b+b0U&uc8dePag6d0O(W-qEjCxj+Az5koIc*0- zmCJ)ifh@Pw>OZ)Yw}ijX&0lgr|n-=(HjVy^r|Qo8dihH<_{Ui$aNo z=RK6r4nwm-iW^NwVFOX)O}?6fr54XXB61#M#~+3B3sq>P=|e(94Ct0eA$06pIsS7$ z0rT&L!2H=_Tuc9Es(f<~xOTJI--$$QnR|fuP1PM5Jm!JbOdh%RJcqeBzJtbu(GE6b!7{n^50Bo;G5HLnzH=xb$rb3;GjojEP8)hNjuiqLb1YMoc+!ir$Zj( zmUuw#YIcwH$smuVW%+BGJR#g54o`Psty0Q6wjQtmr2#O%hS{kJ6)Y%|GTGnY2y@JpD2J5P1Z0m zmIAdn5C5JTL66Koup5pdQ`TL;q*FsEJ2f8N1jYIdfsHYXFxT;TNdf1FjfR%(~m zhoQgh3V!H?MR2MxnjUUu{FLh#fIIC6zLzQ_d)H;5ad$4fW9-^*HjU6bCj`Yr9-(_1 zU|){{oiX7EI^JdMiR%t{JkW*nvGoBC?5d%WLC^5i_W^i);s8!u%fn}RLfq2^Rq$k! z8_SrV!mxZ{F0a!MzKtsJd)`h5p$WSH`9DG6kQju#xeae!1i48v)-)^gF(+*2dhFAC z1AD&A$2IwiC^`0#C(`~0+vi>Y{egYZ7hp_^$Lw)ILm*n_1#5o^2u7*R=Gq&Z7V>37 z5>T`0Gg(lOk7k2YA$5Bjn#^GyM~Rm(w{rkST?F`#x;+`Ik<7V00`@`qzU|4l!4&SdL06TrV@w+(1-6Od;qHr0+k_utz*;1GgI3H7CDlQa! z2lLIN$gZiEF=}@xCcjyM_h*_wx85L_P3#2CN#U@!>;Vn5X@Da_);Rxa7xg0LP&G3R z3T9@2b9;|@7q#kBOjjE@em9m^IOzN_wHc%(K1j7oix zG_1lv?|*pdoH7o5yhN4Xdx2E-6Fix}gW9f_;`e8-PDX6#Pz|v?p-lA)M z@YmlFF8ee?)>3D>>E0vopJ)Yo+w-W_>M?khR!Uah^9A|JH4yBx3zi*wjOpv8u*^Id z*0lE$v$9KAbab2?Il2eG>~R7v&mUJV5azztQKNDuC-4fJ5691BOuW|lT+@alpr~_> z?46*B0%vq+=`&$2zM96bXS|*{b6#;MnTSe>XK>jf1Q9=L7(6A#`qPEDd6^s(cW?-G zpHAj->hXGZA4seGM8!N;-Y3mQxLDUiRtoNe|5Uqh4o-uOz8@jxN*D%d$nxd(Ct|OS zJ~nZtqt~HCG~4?a<;!Al!!gDa)QP9@4@1ylnGLEKsY3au@AymH7L8LS@W?wk{-u|_ zaNk&nf98uMdZ>KI`e?a^E0ytt>*fZxPgR z!*)m+S3oK&PKD@j_=&TyRg2P|X^6_+Sqac5b<{U;cVIMr5XbltM>WRE!1$=Yr zAQhkUInUhVAw$+)tG7EASIjP9bK|82Ve)(Mh63}BE}Vr&n?+FBnq@HAEHE#<2NLG( z1x=d*#??3CxW(79+?FC&B;yKoI_3!K8y;bT{A*ZxZ4U2CPynPJ34mV#T|`VPjGS5| z%%7QI1-q>6uvI%52c`eP?a)wSS@M+()D7eMw9W8_WrbH=Ex=bXb8&f33<_T3l080= zP;Zn+4%%J8@XR$}*7yWhUqSlNUznTA-pfr99P&LNi7b82GEnJ#yflk_^lEDj^THtR zO%>wCH0fg2^-@@W`vy$(m<8f`68u>b%uOF24jae+u(yH~O5O5;NizN*6SJFY%nSod z{uW$Zs6v|-ox$Bc(Im?31r}Xo`|_kpqCX=H9Zz>)(5p;B3K9!WHG(}1p z8rn%wM*W`OUvOTp^ZI-~&vRe*b-gdK)v(F;1l(lV#i#5SuFgp@wZjZ(lDSpJ5aUlCI_uvlGT`*U+o<8?TB+6Hv zLDh1F)=qyHu$CQS-5U;g|3p7d6%qsc$mJ-dn}a>83bF3YXKa`=4OUrYqSUSF&_DSN zW_(P#URGGnVneqjTJZ_=Zmu9$Psz=1OtRyva?WpQ# zHLB--CYnMP#Ib1(n6UGFgRclwZK;Mehm7Iu{$MClD5Ej|m12ib66G!x;>I2I1Ml-k zVd*!f4LuLvmMg+Cbv<~sw3{3e|3oZ&;;}oYhEAS44*!nbhL7iK zVe5r2;QT3yDvRoZaKc2cEYs^kv17#xJn!iS4MD*? z&pq#fduS<7^!QSYo#Rc)K0QJ`%YHI(?EjpcV6t|g8Bc5qr1xCn@#A$NuAZJ3@2*Ka z7Mm4;sQN}IlG;T+3RS|3)uQlb`w_aRuoYyJAA;lS?JQTLPhS3Bg`1>|I5S4VNrGG< zxcAKAR%SGVh(AlB_IcrvaBADJ?4M$sp< zZ}#Twb9)IQ3MwFN6d+|ka`!?x0-_H({A9Hy+pfzT4?X| zjeS#}<8Sr-Fm@=0Y%@3wQc{xKX8B3v$bxC``0HN?ohiU(hYDk!(_I>}b@aBf32d9=$A z{zT4zkpstQvZnywMA8j@?^c0p6^;0E@EbHJ3-C`B|3ax5?U-DtLr>=H#l{o)xL3{+ zotOvB-B}&^=V~x+%@8VQ_@HIMSByAj&eOZVI)xqAqeJa3Y_GfmpUqgWT5KTEN!beD z<6E&-{|sb)pNev_d+^oUyAZq78|?4a<0bV|I78ofswP@g;g zbxWrfZp?eAla99YJ`iz%QI5q_JG%PwU(A(I!nK3PVPIZ4ZjGqR-oj_|Kwv5?DOJS7 z%e$FQ`4M9LJm5kw8@pTDl3Agq|0f}Dytj=Gv5q@->h>-i0?6#JHIrXP_@d0B^00fL$s5WN+pmCa3?0Y4fvibiE1g z$oB!KK5MKxT#pX@QB+CB7>ri* zXTs^~Ks>lVjrUFAG>x^6qQ#$Qga6VcTzh*5)Sl}=f6Z}3m8MFx3-g6Wmn-o6t1cCC9aFSVcT0SY_{DF$0wf!&qFS_eUyuDf|ueSUJLNNbAWe{?X!0G&<6!! z_+R5k1tL+QjhLS2xbk3tjXrNCCswmf4?Y{KP|@ zj43DZ9cRmIA`c#2$A3Ge>9^BTXd0*i&b_Z7s$w(kwEh6EN86~A&Rz`J`2(85KXPXI zmS9@LIO7l9BU`H8z`l-+xGYTtmpyKw1{In3N;(g$&I-V%`3{R78*M~LnC zL{NAd3O@bjP%#>cA689jS}GRWY1hd!839Z3P%{=X7RL*RaY(r> z$dAMx8Mic>dEZgx?P2$UPGwQJ&A{0JuyM( z4xSIpfJX0T#+4G_yEgSuuVwo1Zi^KezFxrY1CI2rnGVexe2z(SN1;Ti0Io0jM~*Gd z%l7+oDjsaYn)=g1h5O37>5W4|mXq@H)Zq_bj%hP_m zWUK*VS&f`mDW`Eer-aN_T8}IT3&At`uv$WdKS%Tt=c~v#gQO(=5|S+=j7z90FHf_E9Ys;7Zmw5g(Plfdwt~&xG=m6vcF1mb=S4y zpVmdNdwG2JY}GgP)mbU-iR4PSel`xi>&v6|fD?=zS;U8QzfV(|7j7dHH;)5@(0g|2&NVE6UiFj-|EJ^LUY zXFEN@BdY^(iGC+}6MKs6=X9{{(RS+0^6#(wQ{i@$IA43J0>nNmVm$UFlns6YOY}Wa z@OUUKZaIyz7L`2LmBk=?!5M0vAE zEx~zg=N^C56qCZ0;m0BPVm2sF`hpKPig4fgOL9;Cf!=6$;Y$+O}b{@{;r_WoWgsgLB%@&yTq=jC|Y@wUNe{nQ& zmvAR(jX`lz8BDJ0L)!`8h?Lbwx+%jR=9IsLZ`^(m8;wRg)qm&~e~FG~*He#P3I4Pi zbE>f<0avQoqJ@q#n5xgml2=~5mF3K1x_CQvIbMScq!z=AnhN^;^8~I}_*S&sp#VMt z-KcQH2BMhG^-D>Bd*hc05v(7BSe2iYcUl>hdR4S)KL~=WB4ZXS_`pMw&CzFBYq3Ig zh~N5xTy)ut;f0JxH-|CYu8vZ#mOjiIJ&Ug{DR8^2#Q6Lb_n=IDC%VL60MGK(cv?oRdTky?rZtl#$Ibw$cY%!F0+yq-f?Z!GLk;%` zG{v1Gc>XyEEw*NU?{g6Khq09%g!yNm4sawlSfk7P7qI#A5*QU5gC(z6|52hQbPRog zi)xPRURh4&FH7~IQhaN=Bw`p9TC_o5f_+ECmO^|@4H#&CK(p*1TI&A{UjIA{Ubn7d z!mJp&ddL?||MNrl_BqtSs2<0b2f+6EH(}e&>5yM3%9XtM8THb<$hSq-c@MT;_qNyLnA~@li*$+&)`LuI8%*BPqStB#BtniK4YEK6gFH6 zK+UgJU}R&7yMM&eRJD0XMbhxr4MSAF9fCUgEIYsF0zCBXquifSkY;-t@^2jE*tg4) z0BVndtK(2z^gnv`+Ouq}Gg+KF{u|(+P5|dp^-I|AavO{Kg-Q6w1Sm-Uo0a7OxaE!w z?U%U(dwbn*`&eN1%2{eKWz%*X+wqq9ufCDLxhZIE(+XiZS(uie4fB5u(pM7G(D-{W zV_Ap79=AmN@yHFUIz_R;b34mjKf=n|5|Gp@L=m|>sLF_fSsR^D)vKP~?o-6%^izh0h^xc(EAhZcDtUN+)U2`Di4g zbzoVPxbTM5J=c}=#9;Tq5L)Lh&sk%=lee_@!k8o%5q)gGw@P z9qz&D2N}z4%m^f|kHXD!PcdO*8NH!*7~N<#)yeh71+4dT(*-wLF}NDKhQ>jRm_W6O zF)8}*Bl?_7!Yk{RK+@nrZ0!6G4fN-d{eOI*@k|DO54IwgFLmI)7j1BJyCJ6iu*Koe z*4P#5gEOvWvU5xa?e%Nvtel^)j3?#IO9vJbJIb^XfM`qr9oUPhVLryW5aP2)nwu`F4@yNW>zbd7*9MqJJSzd6Y7d}4V@;m6D@Qwi7(VzNK*o=x zk-;HvTsM{us;Xb$-L*MHVC5|SeK&Ke_LzV^F9}cCjlrD1p7?WJFX`xw#7UOk;9Xxw zmG6JVi-)b~qSP56+-%G1tXcrAtwP|u_$sJp=i;fzi+D-09lSr4LIVEhg@`x zafP&l4`OVgQ1y|xmpk3knNn)_^)=Dar6f{WmmsZXX`i&@bKW63R}RL z=)16SeH;v~*n_oMelQCdV~TqWK2&@n2I9s<<~z%g#EZa`!$$PzGYabF{A{YeI`}{3$Mh(^6SsQ#y1+Es0=H^O6lt^HPlXFd4`NZQ0evq zb>^{|G((uX{_=Owsn;SWCfcE*mlK#Livd9&!c{cDC>dq=lJEdLH05z5T`0Tsatj*I z%!7*jv$(TE41ON81j`0*_ItB2Hth+#zb?a-_@{*OA(EWRQyN;c&i28`%|vKY6y#^V z96-GVpGd)+yChvQ1M3WnXkgeOrq^4No!((!#QpbP3xU5cv zy}MnYH53TV`EyXGvJ$qoCZNXcYIHMArE2g0z|>AhoWZ<-#v@xX=JQz;3V03ihm!ym z#^BC$MU=Hnfqfs9U{9C_M2QNcqLCj|xwrCe^?L&iQGwXf1LSmY7EI_&!*5&i;nv<~ zaKN(?gC^Hu?49T6>drbm;@)H2t)sYne=)JSA&tUrR!|ljiHh4T(N^#UuXStz-}6s6 z=KI{{X{)tCwBKor{Z@+i3KLl$;4q|HB=NjGUXlMcKY*CG?`gQ#L=<`G4--waA?oBY z_+8GYC6!mfah5*a;Zut5-F0aBC_68wl)>|UK4xsXgp=xw~MKVj1z-T+UdAP9#4r8sn<1F|R@tE7p$UmDA<0e32n;aA6%9Ydc`}(zW2T zD;i^NR`bd${PDVu4J<7@M~wH$-~rVQtkZ9Df=WDUH1;ABghP*O=V;g~ZF0&~07? z#IE)V@$@=@H@g}zxX_)~ysip9StjtFc~9cRO}>Xi4O0A)+EUCbwuI4AchK*QhJy(P z%sV$kfcKQwyY3HuV@=k9?!%b%rk03gdSYQlGVE~agM%L?@(*>SK<$EUklVBq=Q>;R z8phqQ{po!ov@Z;2%Qw&;xz1#ZT@lWdv`1xPf|7PMu)i-H>+9d((D4EIvVn(1Y)6$4 zDFIKO4TG3p9i#+waQw^autZQ7ymAB3>2f&+P2YqMgWEB7)EuK1#DKmXArVsz$Oc~} zylfo;_Cg;)VDohvI!}nZXTKOXim?Rl6^d}PZtuaA$UJm0nuqc)lE^{tSiJn>4Lns# zBpG$eWNlzLDwthD^=nf6_PHOa>X}<;ayJJaXkH^%bH`zsXfp79{%{s8dQLaSYG9*> zG9+m~f}`K3kO!xC0L?uQngs_y=*uGTae0TTLX57}t&8dV({Xou5B94hfv)35a$QV@ zo9O)rI-GXEj&66zj#NUWDb_gG(~ILRu8Rsf=V7A4Thd>n#3e?n@$7b?b!IttVZz=; z@GFq*#MhMKkC+_X_gI2^im^bx>Xk!X-9|9F5r;#~pWxohL84?P$?r7rrlEFI>6+#j zsM*gt0%Et|b>(2XOF50_^T-mL1$em4_T4(Guy{zAt_+1{moYYo&vE|3=EsGZ5L)hr zW9RDW^;4|>g0WFm%S!07=x~_QsKMR@@QepRoQxjArH2lP8{{c}oK9(`?6=^Vx28QV>45 zRDqLjrD2S>G)Yy`1@*brII>fK#ApQZEQ-R&TeAv`Hwfc7jBW?_6Yg-b@Hww%PZ&gm z`Qwp3c6Yy(0M<_<;BMUkytLL5lJaEmxKIZXUw#mG*O%}dlMw=!Wkc3?5&o{IX}qsy z4zRg(K6>KUo&H?fi$gzTU?4 z%{E%LF6MN3W*qSeoeptjYp8jHAdP2tG!x+yxbyL6T)Lu@W>zj?oPqODP-#HTzX#!T z(IXK4WdzsmufR_Ndr&EPH*D${!1uQMV3qY!ym~GJkE)2{&L0oxj)|Grx?&^AlxJLN zHup=&CxNGc6W!jyv>@LkOv#9a*zy9h?{x!!bQ}zC+k%o0{*htce@r{e!qYD%@>5v{ zbhOYP&g4bR*Xxr*8#-UY1pOYm`IHGU&UB;CEZSk?!$FAYA1BqX24Rj*Fm!6k0KNAg zF1?-#VNGK=ebZN}_Uj+(3(Y`}X@11xaW$kEP2yhQ_VCVXXo34v5B#=)F{4iTa6XrZ zaY7eq6Gz7AE;&4`BiF}&0WS?>IW&YUcjNZ2msjn3!o zA^wpOZjBV-O51efr-%BS1c_F{b}Kl+SCJ9C zXxa<@Sqj|UbKjzA{vBv~{{>3+UFHd|sDhk(^>oqt1JJfO5#(Rk;L^Gic<$X98d7-+ zMzwoTE;Lo^WtANNVV@2D?Yl$VcfN-8H^M=)r=NOr*Mi~0aMtUphyHW(us~M=sv_6p z_rn+AXx~<-kvE0TMf3SzZEfid{~1^v^%}BPuE#qW3-K%4M~@4&bBqR)Ai|;t9aP?d zo7X+i`I!rQj*k+DOQQTVA0Hw!FCP3~G9THz61*uM4+82%=131MmDa&g{S*-o|^|Vcph~n9q1xsnfaiNS-1pr*k=W+AHzB zRxF%dsYOk{SF!&&7$q{k=wzc4j&gW3|J`y(>f5b2E z#kuP+8RvvA0@D}exZFdDhIfka707b@J4+DfFt1v8Z~++lT7%6$Nh+=2gdyUSprxh= zHWwGb<*HmbyupUvf+IMrJRQ^3#kfUllt3px8d5~pk>GDHVf|KF6b)o&yP_ogxUn9s z_gL`;ZZCy^qJI1)!gc|ZCShjyLyV3M#|)Jg$Y~bimW=+T)Jl{;*;|XqHH+{Aee6Kv z>Irm}5~b(2RAF(R2Ij7}#B}lj<79*2<`yU1BIwSuVf+56hsTLns|bI`br-zmG(uz7 zbfa*d0Ka46S_oS-1q8MoBd*h#Z?-!Z^VPjjW4$AW&U69Ctx{Z0$yU5`&563KJ&$`H z`l8$3B2cOc0eU$H_pSi4V#Z?(a(@gu8DC&YL^RoOUz~q=mphqSwH8yvZBczn2Hb0E zfsIk`An!~VoMSrEqb00M_iHp2`a6j;;H3*UBG$u@8p34$WgzC^=riz}7~a^A$M1cF zH{XvV?H1%G^__zhpJ8gqJWWwS_Tbu(NGF{XqO~#8!1~pFoWy!+)=h840`qE|6Sj)3 zf3=gu$@?Ika|Z0sSYk#%6FK|06PtD|z(_4o{++uK5WUL}5}G$djPnxQe`Pu}JxF9d z6-Pl$m1S{413-SgC%Lz!13oPm!iQQKFXNDXm35a-)^SD;m&IWA z*^yX2{KB+&rU~eekf?W_u;JblD0+7px=jwjC!I)|c55LT7S}O9MK_Hcmqvf_#~3S} zNMzjNsaF30I{vK3)=mL9qZ3PT*qGco6oeC>eKksw zyEexh7X?}1z2=MLa3N#KK`Zv%-G>J&*m>8r5U#8nriFpaF!y;U{r>PO#I}lapD2lO zFIOHTpF_=vcG8jTF@F(mOl%1-AR#_I;|yzNrDA=VB^oQ0z>XmkIQzt#m^PYWaU>tR zN5UX$mjYQOd3T<`zTN=ONQ&)$pkUZ2LLnJeJ&XJ_7@ z2LI^f zBD;Xa8+4#hVF$=f3_!^Zs<63Sj-Nkh32TSkaFxXqu=4hT_}*(k^de#ISf7@GRS--( zq)j_w0zveF0M|?Y2Q1B!L*Hvt;hts=nV#c^o|73Lcn-a zjnAp&!jd&`AvB6tKW8llPM?XF_j4dfF&^jeEl^_A z1U#iOcu^%5baRLo{8x1d%RG$Gwb&61EH}cxQ-~i2LO8=N_PAJL26y3zApf4#IO(kn z2Yn7Z*WSMY-{Dg*XK552nEHf#c_F~(ItGDy?g$1>y@Pss(%e#~U7X}eqTn4q4Y+3) zk_|4*H+uI2%s8Wr+iu#kZ;uT)_N>4#F9E(`J+9cd%tJl4?{nfKFmC1Trr& zRp7v{=MCU=(if+MayYA!J2AGr1-z~lVn>`C=sVTG>T{}aOr-=XR91rR{6kPz!67$) zc0#rFV_5j)C0RU_NH58)1Be#os@-`CaXOi}vu7gF9btNr*HQEz-Upi|X3-5BN{MuY z3h15vN$;EWpr`mYjMP5?=OyhiC7NXz%aLUsq7d+&u-h;a_NKUE34e|SPqUnDN+6(#*2Dxl-iW5~5UiCgzN zq1;#_I@!#F(QXGQCH_$F(U!f8dPAJ~MC24tBnxglMQfcfGF6S@)Zdvns_KOnb0(3< zVl8y`Z$!7%EI&3m6Q`u?fq-ktn9}YCTO_NYN=g|X{CEprH`LJGoD<}C#B}mx$qksz z&W5Ihv$%wLI96-9a`fwxsr_~jO8=e4-9IOiRF?@{+bdS^cjYvGJ@eA_YIP7J(d}?m zJrk4dYzcF@Ld0et=#;vG@n;8#nV%1y*&mFeLX1(mx(reMAJy7JQ91t{?!G;MTV`s) z`5HHTm?VUsH3m@N`AIB~n2HUHSq3@p0n^==!-e)wpq;J@0tZS+OyXfUX&8+STBot6 z>>Vt+mH{JqF*x*Qm^S{&B@r7d$t$Ht;8qb1%QsMRpyL<@uV04p1xYYH_$94ozNKlC z9HBVE1Lpspil0J-_>;}1!~4^UMA|D9#?l42dom(XKy@Wf{1^zbSDk5Qbqi(L19)cU zL|<`2X{3YzpA;R$R`C?@zVH@SU6V)G(qABQmGwGb?SZQWqTJ~fUqM9X8mcs85+jLf z&~CfRIznxM$eZHW$=CSeMh%QcOoS@PLKR@y+`a2yx8G#i{Nn{I{5Kyq3ZKIWKgO{P zlji#T?0{$HKeB(EawTb*8{p5CKsa#B0QHmt!8pYQBR3?XdrUp-9)1I5*>9n?`z_-= zUO_v#46wg<8qMNbIWJbt!nLcCpyP20OpMN_P7V~>4DIP-=W!zRQ5Z~y7C^rw7jy0< zf$%Y3NMrLh+4@l{eEW2M@o&K7$O_)yO{-x2_xb1~Tmm+HE6izmi(`A=vA)M0FiZ6t zcJSZh-7Q(LIcYE68(s{iYyEf$@=mn)?^Td{5{ucT5h!5Q1btT}!LMx+yxrD{(+_uI zc|{IhSYr&o{$;`SWpde*|FxhtcGx$#F0nQX>*zzd@c;E!-**0YA@o>f~*8-l^ zMM%1$2CvFDaD~5z!cB!|cHEy$H%@p0J=#y{gtGPIp2Zt{?N*D^#6K^WkvyY3a$UTX%myh^uq&MUf4c^i zipybK%oo>=Vto~H(`N!{hj&~O0}QC z>O@^)G3J2ldRJh4aU^On5BcBC5$NZTKs8&LCuv|Gcs*D}*X0amx6t{{_M@%w_&o0z|j{Dr`ne7L#U8$vd8fkELP zY+O+QFXwiH@c!BSKMQW-d8c}KtnN>I4r)Qn(hYF+?h{Cv)J;U3#L)RvFkDlvAs$k{ z$s&op+h8Tnzu*=dfKxJIq^}!E+DyC4=jK z;;ehOFlpIjdg{qr`jOpLME>)EZVemEn6we@{m7{gx3Khg9b#(p2dhI5nARQoa6(VK421?F0ayYfFz$P zfWo-5n4BTTKPs{m_sj#bS?VSvj?~ir!=do{@e+_3EQUDP37M8pV1vL$h*`$+2A}fC zH;;p4uq_p)54+LvL}@Cj>4aBgPIFUsMUpA`6Zp~R*TO+PF?{nVAJzv>q;I>zsOG>^ z^v+xdshK^{nq&y>`=scT<<*$QX0Pi}+L#rVjnTGaj&Gm z3~qzQ;Wl(zmq!<`mE`ZzZ)O~bU|ge?L+34I+_bDCS-09)r}KI-eyjI8@X!_EQ^jB4 zcqa&r!~Nm%d^zsZwicrEI}fDM1tp~USe^GCcdre`;j`9oU11{J{@$YXZT|xFAE|<> zk#|(eJ(gTK*@`n*rdjE8A9-(Bh4)fk03SrSyP3Bot?UyB7*0ZmmTcaUZ%S;R?vMMH zKPLqxH+fbXi?pgfOkvzHPkQwQ)Bgl#fUo0ms61FpicBK4)+afVNft>Y@hu zSDF>7o@d|6Y4uonUz{5_Ndk7RZi0Q~>p>wu9c=vK$ah~?hvQ4O6c5If)q&P_aWs=(OG1}@r|xeYS-jvh?`vPYa%ygwG=-mp#_rX;LvZUeWdx1d*HgvBa-V5QXx zt6nvrvfwP@^=>uR>4afAwmSGvUz~q1Xb=9Gatd}ZcC?FI1n`!q(ZWAuuK}B{OZcn`}T-l z^}2?&g2N;$U_Nx!Tj9b}tKg^lCvxlI4Qg*O2&+A|ke96cM$oh$sw+m}$D^C{^{f!| z{TaiH)$|~%uLr1&nsRB7f?=@N&pp6gZ)ehG}0w=}n_npL-(8FkO0v zt~QzswbB(P2kF4a0Qh2<&FQ_J2|npjaQ411pD((Dep3K* zlb^yCtzvrZ8!tzxyKgbi7 zTD(J>L*|gq^zWN%TH)KK0-W}D5ss&xgLDUD1<4ar8u)_!TE}0FgRwGCaB}gTE zx90R1z@FdV(6v*LYtoU7f~x;$$dQ*|quT;oFQ!xJ!y)**X9C}h-5t!f336VvSHU7z z0X(u+hRjIq!=rB;;7n2gX1unB>2t1t<)T?s5G*j*o#hAXazJ=Qo0>)}k>FNYc{gpL37gPDhOT&7IR}ZNTcoL5!4g-fqJ1eG_z9y z?>L52;nFE^uC0acS+N;}hBNT~J1@Gwv4zcio0*rr53YbB|KAoDmT`8Xp;>R}I}JJb z=T(8f|C~jh)?ebSX-)SRe;^(QT97&PB_D!{kYSdR@{)=$3G8g?Bx3d^1|onliL z@4Uz@PED8uzqo9as>-ynu5CS%Y9s)6{;j|bI1@xBtRe1?6Vb!9ju-_!g&0EtlrUiX z8ml+t_Ka01T$Dv5$F$(8<1{*HhaXNqY5^Q=E9kh=ja3Py@Z9As+j(T-TX|#h`o=PJ ztx|(Dxgkzpod@#&3kIW*FmQ5viM5YJ_@V20yr?^G>9_U-x?k}b8Q4(>lgj^qvqC8B zN_zntniivf?*SADKFvFIe-?LuSYmihB#Aq|l3S9WiBnq}K%~414$?@_I%NXp%4)o@ zb~W0}Wm@mZZ#ua>6t!k#gZ`i+JlGvgj||?yu6<45^j`_*Qgb*6{osPyju~)hqcFdD zrx}z!dPPDExSZ1s$9Vq11z5K97+N?nZ*XM!%BeeNE%4h)ZiMjYM5SPyk+05) zsw*Jc^&F(pf9c+e&g`tNyaEJAQL>TZsf3=6iMTKyrA&+z4Xe}CS z*Tu6H-|?LGQKHm8M%o8s7&m7EHiR}}v{e%Z2HIeaP9?dv@f;eI?}mLg3(;F#61iJf zqg8`A_eFmZC@xB*q8c6aZyJQ~tI>dVpu_!9*jh*lIi`hM ze%gTN(RXF$FGOrozN4qCej6-IFu0y zwm0y)UPo2Fy1;FZli2!eF}|u8CNrfi$TVZtfAQl6{grRcS$$A|J3hk+ygjVx=^fWG zKk)_b;M9YSiX?aLgk;RxcMxk=xx%MXI~>gNgmbzN!T-fL2xvO9EU_t`dt!`_7v@03 z_g7fykOqpJ-?U)LHHggr#EG5l1129f;~m$!b52=#pVXt%uxxOl! z@yGRXzW+J8fpr)uG(5pXuUxWffi>y6bQGWT?q>b9b-3`V73eA^!1V%lpG;tPaiec^ zgP{PwDIg2_-vj!-vqHNGmZW_08!|5Lj=^`1lU$#8GJno7vY^Tn=JpohWx2QX^#LC& z@r}le2kp4t)fptCl9?{l2u>%?6SM|Dl&my6*IxKKV7)2(hpW<1;B*NS2*1{4l^4vz%A1PQ~vbu z=!1F??l!;!i~DicfqXV^1mc05GqkAKllUH61({FIW5GISSoql=H}*M_8K&8sANx{h z-O@IAsuF`|b~IwkFKh5Q{*{RCWLoy6V5}RKg&TJ$CWK0GS1z880go4HJskfA9O2I} z7WtE0{QVJ}6}91~pCCq^UW`Ls`-xY24CFux4$ay9^Yu}0tA?i!}7u7hBoMOazF2ZLGfq3Pi>;vwmP2^kJ#SJhn@pCrcLuDKq)+s4R^?X?hP z-3K#%UB$AYd|a!02~^k~&TsE8PVXgY3|Tu1zdvW1u=H$x#EKF+aIOlkIITj{7iFjv z6hP?~IEs#uZZ$#MBwy5fbz4;cwq(9PN7q_vGHt-y7PX(EK_M`Dnnt^A_-Gz9H7ErPO|bD$48* zgU*I-I$%}}gQ1-$kYo)qtE$1~sv&&&?u-v#y5qqeYUK27DXf@q4Zcp0;U<^MV5jUG z{G@V(=W${XzAyWL2^!f@`OFv889ONK3}Y>4jSyBlqZRnx1K#Xsxu5f0RBeSV>-o!v zH@anLyQ>+by8ePNyv85hmdxvQ1(Rw=$#5p?X_)p7jr+o0C zZ)`Ohhn+hdX+zE*eC@&5J~D$mR}ELT(_MoLx(vzb_)Z$U!~t6t7UPJ8JYQ|g0Ni)n zMvrK{1gQ>bet%0fUv{COm4-*bd zO6ga4ZGZ_IZzt6z!w?aeGNavYydvA|kWKbV>2B zP3<&!*)(o*+&+w4KNTu+nbx0tm}g_(#JlT{tczkgzqNjtH~iZd1nTE=8~q~4Uwbc% z_In9mI`rVq$u5{JxR7}Do`A4$1^$j%8gS@XEu0YQLaC4$bp9n*$OHjm9~BODCmlh? zrv`o++koN42(8tIsYK!}WB%SUMG3wldj5-sBPP4G4(PDn>@F9$%W_{foi)5amcwMO z+y{F2W*x*8vK~Vx_VMR?;ldqps5jWhi;WMaNU* zOfA%h?Un1GWNQNc_xUzFPGtGX))D&cp$K0mP#G;QYs2m%b>xYE9??A(i#hA%`A2?x zqUhoi_*=mpPc#j|QWG1xWRD&%x9<_QzD0E?oI@H5G7p2O6Wjq~#GGuWi|dx9^$IrZ*pW7e7Tpu_^2L znq39SU6bgnirv7WCvm_clL{Z259yj8X=C1Iy2?HdlP;`b=SELvygZ+ky z5H#sI{55Gr$r}^M?yN7+<(x~m?99XDnMTl5=#6TN4&l#UL0aBe2MRYApqt4od^3}a z-TJpl%-$~YHhmF2@i2jL(Ac_({3TxNSuf>07aX)U1eNv(VsOEp64mEf^Bvu3$Tlaq z^|gUiE`0)g9TS?k>nj|V{*@h|qlf~3hp32mB+dDF6M3p?;2oa^#@ifW(^FNV@Gl$H zzItIvl_a(*NMjb`5#2xwJfp|B;8cZ$XlYFw>|J3+_)Xkq z@DDn-{-d=IDyYm?RS-?|0c{f>5Zv$?YkWp9qp}JU6hyfar>^1FB6nzw5drBgf31-W zXN=NgbM{;lu-$k9cIAn1z31BD(-WN-<@y@3L)?K*YK62LU+}AgGuqF|#=Y+y$??%z z`sGC^m@z)vrehhnR@(u}g71FRgplC4WKM{-CW;(*0NUHvfI)dUydGg} zI^lEBAspT_;S+iuH*dCiSTjlMfi|;57ZBaQnvaTezJB)W{{N-i5^uiEsEX%WcqDb|5F#fa*dp7+<+4Ly9{E1~cHa;P} z$}XIj_ZIQmy4T_L)z9hcH{T)Hy9CKLKi-+B+vH%lE?f|P&v@Blv^=FAr6oM<#l>N^B8Pg#=t>%7^w zgY|Q_T&)zB;x~USTImF->#{J05&`0^xFX3<0RIuoB z;2?K_*7HX%9B)KC=9Yz zu^fm-HJbrKSoTSo`7?Jz#S{tV<7$W1;R4)ewVRQbAI)jvMqpY>0Y0+v#?x|NAlra3 zwb?mv=7=C(dO1!-lP+LD1(pb-#@~cMh zI&>I~4vmt=#3Z5{wT!CFEP)GT7MYOuneMvyhIivw2=;RigL8f$y{4UkLq>w!k0yJ` z>8r1>>wgrT_al|>AI8mukCIJFLugOy-0!1OG?dadS}F}86)Fv~w`7a#5Rnqj{XWPn zL?kPt%!XuFl)lgRFE~G(bDsOTukpH!y`VI(AL&_rlG@sULjDKIpMPPvHpLE-qnE;Q zE*HbIv{4}OD{Hmy9X$2n17N@_j=e=FDug6vGuat(Edm$u%_IIaR~?8es_Z2^2ez8CmgS*NZ?Y_w}6>5kRz)=)-qcsk*Wr; zeSsIOWAyHSGIc00ehCY9XQP6%Aoq*}FSD~WjmCO`AnjL;kBXOKZ&C;5lx1Rzz9ZFJ zHk0A(J%+CZVr1m{T%5Un5GVOvQL`lrTNb#{0`;@F=$apCT*ij{p>JgK{N=cH+dU|3 zGob5IYSE_kH=QsL1hwh^&_`4neS8M7(p(eQKd6QcLei*H<_&{PmtKACcD%W^9yj); z!kVqZ?9^)vqw`HBirsgi**OpJlVmPAo?(VjA9LVqKpG5<-GuX_+u=aW7SvaM4V{nr z=^tTc16kt?>yUB)B(*7HUi5C-^0pmkY#kzd4tKzqTRBPG=zzvuO!oR08=hGwA@?yK zY|LN%hBrKXmky@Cq3>3qeSn|G<*AzSPoG(+o=I!lxW@_Gw(lUyI!?qo99d9~S8!MNP}EBu+AeR{lu9_seH;ugHyqWKJE-;V}ZC z=$Y)bQXwFc)&(nbJ+SPnCcSQPi{4BU;hKzBk$#U!x{A?0jb}Z^@=Zg~8O>zfl0C8g zl?VtvaD!GpWthKD7r3)JIQ{O1psBr$@=BPK+mUV1vM(KE7Yq{RSy3={*%*4Nld&r1 z6)r!MOqa;JqRyq?s9zrm{xWlNic(VXWo{Xh!&Ah0mt1Id!E4-i+6Zsz#?s?Hlhp9_ z8Cn|7OW(%M0FTdSaVK*Qn?)PY@8251TIdljj~qY^+dz1B&W(ii32-|hCv*adzj2c3v8g2Y!Rf1uxX-qNVVPAAlLJJXDX8&A`8geu6P3=Bhs$_#B2?;1hj!L7EUKzQ!N?ihl`0o7<5etVoM7%~Opj-Kk{r8xNi)2fD4=CG zo4`zd6H7(qAM57FVdS{Hq~bcW@#L&f%yQeu=;SSE)Rs-Na(&UlPa1c)x1(>)1@KwO zczTXPaK0}bH;!ImnTl+}(Z4@YKO_+6wd9ZtY8sG8; z!QI8rV9q09_9u2B^WAsi*1}X;-f#`xNlHWaFdg6Tx&uz?ZUgrfD%hSQgI5)T=nKPCknrT?ekhDV{p**s1FgikRHF+dw-H!B9s!f< zBf)J-jx3vC&WOa#*m~wEv|e9Mc9sXih1}H)%SM3J7^cQB77)ZZu7syh6*;?y;dIbh zxDjui-+IXoHz=;6yC<*W{WX3ttLZ1lr|>2o@ne1`!mgm^A%&X<+ljWpJWOBm7WD&k zaiK#YD)I|+eK*_Uy!?KQPJKY;POBg*TMSA_0pC$e7s)`ybpeo!%oAH zsUZXbvs^fFd@_*Zv;+QJ$;7zOS1{rrO-laN()e8j9-DX)(_ghH?N^T0kCXA|bSW7! znt=FOPN2Z#k5@F80WZmCcE}#l)em~`-2Nac+!X@5lKtVS*KJgP`x57w7=ypLBYu+? z1UZ?vs4R67<+l#w^v@93aql3AE_s3}xj`rx^pWm~jKnSa@nrUZH^f(bg@bluFfTz3 zT0ZDv#qn=MqTn0D67B&a^Oh_degv~M+Mw2~jP#_vAlI+fg6Ew&T%}WnVZK(*Ng7k@gz<{MaC=#jqyt=MwWtFIt}D2G@;}F~zfy^4ArSUv^vYR)q|%U-p~^ z)(WEVE)U$N!Eoc>NWzH(QTEb9!zeIXkB?s61FLz=7SabEwn8hD1vI(`;;pvilxjKM zwP`t3o^r>jzrUd%`7XSl_9dK@ncP+r6-<%y!Wp4C5V(3BTvgsn0<!-ANX>6BF5D0f=Hf0Fn!kuHD9Dq;an`R@`^FNt`(kNssp7% zf?OY6Eqd2UkOWRJn%bZ#So~AaK3{#6Wm4&e4M_%cyk<2 zSIpA&Hw8iE{rwPI$;P%1cbV@rAA3~4(p~S4W4Fa2{3P|9 zeEOb+ZAsQ}U-cIXZk8vQu+&w{h5O;uex#Ehskr8jzU4J9qw*Bk2*((slDn8T->k^MYrt1%8DA+gF1Ke z>dG{yPQ(DZZly9^;hm)LD?e9IgVEpCX=CG3RXp`godYGkv`W_t9Kzj+J?k-)OUJ|a z@>MX<;ez`(+1Oy-N8Z&(!C%X(Q0x&#G#3X@kBtkCX*qlJ^{lwl79|*E3`e^DK6&dWAygpEB>&ix3$fXUfAKO@k|_zh?zG zTAz&Hd`i(RG!$xWWnme2E34jy*+JQV92S~A0qc3+!Iqcduc$WRYV|~V#jTz$8`Z*` zYu;Eaznpk2bAqu28B~+uK^8DM>C{wbDj;!~6s;SgMU`Jr{1p$kV4*8(Wv3k7wJ#SB zF!zd8OJ`%h{V>$D*r2L$KDeCvh8HydgYp$`i7`(B%S6SHrU;Lcr&UF;Lwh+6T^l5P zr?O$j%OkL_Nq{x)Q6s46Ho}WF|8dE;2{InSM?Ttrf%!%W_@-?Y-g%)!MN-4zR--;0 zwi4o+jo8ELd)@Ft!-39S?29}KFCac615Z3Z0OoD+;KF9uo`Y6e&1EsPt0n;FT<>D7 zuwDwySDZk&Oat4-E|bS>CV#Lr0lcJn!FX64@O!O_7o~+wV6Ptewe@mAQf{hb!}st=$is2Ze#7pFqV&7sB(ZyI3D{7f%U< z(r=Sh*mgS#EeC9XPd@^^b!hJh!zxc~#Tkd0{bQ}I*#G%BG-tjh z%*Z`Qo;lYGGWG%Q%AY8AOB*CFM$jeo<1E=7-E@)8Y4j~z&DvL7jG-%jK~qUAzMkWb zCzS=+LnnT-YQA{DoLC`XqNjB13?EzG_Bpb=7BQ?=7nCZ?he`gobk#;L?47=hzT14r z%ngEE&b?Y~`7^Jm^F@F-rC)H&@)0Hq9AsVNRpp4kSi|V_=fF~=ho1lO6GJ=9aoOP% z`um>}tovX_GMggMRk9M|1%E+-v>K+Y|4U46&qaqc9oFYv<=`cxpiMH`=$YO6#P4`5 zNc}OO!*;xE&EjWJH{$|QasZ?GQ$e=B8VU~2q^)L2Xg}BuC8t+I|87^>>yrgb!X4>- zaf-vy{M_PgJMqRfIqtC46KHz7jGVp{fIC85;H=%g>;rXvOfxPJ2qOt%FCG$p4voL z$lJqMUMO%p6G1us2wrag!Z6f#;Y-Fx(b&Mp9aeK7?u*lzcTG#?9lD%07ni}!dyHnv z7eH+c*P))Y8(saR7UH)=VWVp^1o<|?%Bt5eY?y-Uz7&CdOf_oC>5~Ytxp3Ux0EO42 zV#TW83_pj-WQ7R>ws3GI!*F*u&m;GhnC#<4SvU-gBO5A(;pOoRviKR7jtj3v1Ab=PaL*I6 z-n0ytrZfA9H?CuE`bT^t(u?n(R6=mO7}tE!ObF>q)G}KVhj-EkQNqn1s(AgOEBp%f zMb5>tMt=6+MP@j0I}GyZZFpA4e4b|lHReByGw$sseFqN$iP#R`rM|N&G-SB}D@7pH zClenYUc}m{<4u+2Z)4>3TvU0e!n&nkj2^!?U`&HL+fe@_T(tWR7Zh#~7T-low@l&8 zY?#E#v;VQ>9+hCXL>a8hE97WK7y)IsqKSX0rsoDOD#(1pHmh7n&whv2>-U2=n};1& z?10Zd^3sMWSrp0&piA%9VCB#U(3v+4;j{O%-VL4xQ5{V@vGy^1C`lorcRv%0ylSNP zh1msK`#1{!y72QJX|%Y*1;GWp?Bi|a&=euUoq0`~?RQ(89p_R^j&9vYS6L0BRCo;D z?)iom{le(vw2oemECuV@oh&C#3>y4pHe{+ZAlyv_P2W`G+?$@%xjhu6m7|!A(*b%T zDvT^FUWa?OorL`R%V70ofbq|R7;ssZ>s=OvKV`h(h*<+{x%Ui?Np)&BA397Fb#qZ6 z-v^Iww;}Jc3y5uFC!9#GhMre*sLCr*wv-FAIkb!E3inHrS`h(A=^n>*;aqfSU5rGv zmva-p;4hEa>Gq zVSPF8LU{T7;2NtEU;q4$tv}Mh^oT1Si93%?am{3V?*nwTVMo)RT zul{}m0)?nTT0f3?BR$y3*t~v9}TT?$Nsek zaqp4`Xe1)cjd&qQsTm)>XlX&cCv3x}xT%SC-SUK7gl zowCD2U%$g2Lw~&U$B;8WjA4Kl&ZR@9ePCf%K%F}sF-2hovz2rK4hL<=Bm1=AcHlG$ z-wDR$wu$t<%4PWOp9u$+X_4mZabP;8f%9sZ9lcA=cq#EKI_6k|%;E{{nGx6VgC`}$ z-wW{Fh8R{B!$;aHq=hBPmAFMR3~}FIc8Hvo+|Yz!V}^~iFna1r?B1Zq zRV2)I62tRN2&%!6{(P`V^~Kt}J0!?2FaPAc6x8;bLbaHkXyVGS9HOmJ_;UaT*(|~p zJ32ATC4zVg`@p%1W(>5eg9XYIcC=^1oy+!M|K%@zaFh+#R6gO36EA>$u?iM;M$;3A zo4})tlV6~41B1Kw6CEbER2Y(t+jmN^jq7>2R!&QBk)9*&7kmL*B!%;Nn%hyPSOq^{ ztD#vj33y#%|i1B!Yth66kv*IIlQPlyzZ`oAKb{H#Ksvym7 z7T3h$CXSx$r;nuUA=2+OD16I8kj{dXiAB(PVw#ia{2bHNCAfWoYN+4kk4;_M*dc0v znH}7FV9U}Y*4rvLA0MyB>j&I1w|g@*FIU(f?dkSk}elNVHLv(+bH+=Q@3Cgny@%61I5ayo^6K5Bp%;H0wEmwb_ znu-NpJN6!Ix1^x^SQVZWW1(5eJ5Y>|;y7&xBYR%jgU*a@s(!|jHoSidmzjJ(#7lAZ zsQ7>A5R`=DXX2r0{1G`X_M6pptQ3wocwx>wCv;yJi|w0Fp=V(lF&dd*xq0zI2vlO) zIZFIiXfwU|lW=ByF*=-NxLx@(*yR=yw0iz)RAczcwv}R#uQ&#w|M$6CiXcS$GEK7x z0F!Hc(Ek1#S#ZV!zJ%K{J@gkK`K$}@yCrTpn~uvQmSO1N8Qg8-0cScpIKRW@gW1r2 z&YGJ-7|ynXez%p}X;U}t%_nEF%M7eY>KA9twBs&xVfTHQY!byIh12w*Xc9R6-iu&= z7H9tOqZU_6ftLX(Z2ejavzI@FHHRbN@R67K?ZQ7vW2`g0US5Dcvxh*5pM#4}bIHhk zD~x+&0TEXjO<%78);vw7db@5x*}f2F&maiZM3RV+yAGPadk+OY7l~9{JSz2M;_Tjb zJUH3}hi(1gpzFfK=1;ia6HmE&72u%ycXCX*8lUf)$Njf+9Q{YQSW|tP zQzHI2Z+G@nblrFxjc2arg!^^CV&fcQy-p6Lm3HA^jTda*{1}d$zlRxKO}J}w3pg2j zz`kdjF~#vd$bYXwhuNL{V~;LU1(^y4rcG{sxM`4Wy$ zb{?-ji)T5ltb}B%0gRIUkNY*h5ao|Dntih#2I-c;`c!xu4-tV&;{N42#_w!MJ* zEgKKViLt%BJ!$2iLnJ7v8s`lAgR8n87G)=*)X_2gx40IP>zzQgWFMAISy5HpPZ-;~ z2mOxw!OErz+{jr@Qm%)=j4kQ--w*p2rOVLp=i#5UU{Y1Wn z(;uf2QHFn%CLURZ$LgE${D18rj?(PgQ>AdRjTgVoO~zS?e__yMCtPiJVKr6h!_~Q~ zvBT9G5&QG5;Wu>;6J zyCA~=JV0HtO5o>{T_Aq+0!#g~1*w};2Tz7X=q+NRPsOyJwFFRrX{O=IEAe-E@9)*#B zk7R|s4-_?=heMN6WOG?O26f#di&q7LWmq|DB>Ws~{6kBZ z2bxGOaj>QkogE09oz3Ac(+LflAA>3B5onrTgZ|G#iPYOJ^6~;dG2H8gYqN*&Q{6?} z=OMyA)a43ojZ)})tpL01WiirF7}}WsnkrkB=8vAhgC}zdSMDXV8vVZ^ zAJlJCWNTNjsPQKeZr;%%R8NV=_KR=uQr$uLeJKP?-0K*RpqI7U;3I5Ywi2tDE#>pt zGoVmG7UfMXk*g9270V0Y_R7<^OkRMSuab;?@x0u}57~HA^#brZkD+9WBlKJe;S@8? zXUiL#L4B_iY?@mDA>J9lb3YUMMxR2o=_4p(SR8GxuOV?m27E2#P?;lnpuXoG=C>7t z)?yK6XMGm;u)Pd>%W4%|o|R9!PBkE{cVaejMj_n04Sas8qSChq_*^mpFMCD8L6;?X zNudq|JR(6+mcY#Kp?L37K4X7u(>sg%xzIY!EezdKVT_2y6^;6-d{s*AGwR0XN=)5SwE=sNum0k8=>c289k7e zOoP|d;n&RDuuESN(r=aGBEuohvu%TDH>)@A#@ca^Vi+^*$Ym^@vET4Uw}9+oG&!E% zvB-NN5fp6Y;J)P?6d9_*4^nLy_GT4~jN38ir#jTsEW@2j@30Rxf-$2Ly08^sUPC9- zSCpZv>jpv5{t3wcE63xOmT2i4iRoVp;kf@h6cO;nI#~$_5BvcVyWWEacLZ++%m)Wu zC!%K>NlXH@NJYjv_|%m^_Oi6-)xa21Azcff#(OybjG0U-Zva|G{sW~w(Qstm1n>@Z z;$qqe=~^5#HhYXFzB9N}Z#b;mhCjCWQSqi?V=hwob+T+Mui*MqFEzsv#^M?=w2 zqzSrbuR)E4?N}@R4tVDWW2PA|SNBN`)JALt`+H>&ub&A+-^S6pA|5tg;lO^kPOyy1 z#J&9U@PNjP&N1~2jz zL(}?be9Ny&cI1rW+OS|eSYm>`2R{%UYcBCKl7Y`x#K~G?W8xWIjDI}i$TzQ6EV2Ip z4rhxnaqkb5Fnxkvx;N>CY-Zbej|rTJ|AjBVti&x$X8xPnA)K0A4&pit>rp)rG(IL^ zQ_>XLUH?HOTl|~& z�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⇉d2(jXPjxu0)KTSL)KQrcRy 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

FoV7g45go|f#&&t=d1KDfJX9H)SDp2#!hU2 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

%r1aoio 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

{n{0TC){)) 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%0DvB0KP641*)S z6;yhb3>02h!*?y=@X^u(qmxtcvHd8?R{6jgd&CoJKzYLt!r*0KF3cHHqIdYt(Nluw zI8~tr>YBy&mhTk7#XJ)11_D59CfgaZ+0Ix_1-YheL4SI>)4<(F@q9)EuJ28NEuZF* z$`_Ta&zZz};L^0jJq<#?B-1O_btEZY8d~mq6T|4cB#ZG@2CvKDcyt|zecOuv7sm&n-a_4 zYhlSOZ@kR8qM+Z~?yR_}nEWybvwyRH&wuNYuUv;0u_*v!-m_;|R1S9tB*B!Q-kkF; z7rf$S5B!R@c*>GT)xziDaKj`0!{hUiuycg|!zw7)S_nV*-7w`&F?7CrO(wis21INX z9+R^}!M-SBTs)aB@N9M^#Te?e}mxNzyx;c$G;1e%{-f`O5_7^}MsXKb~> z7gZg&cO8KoodR}`%>b3LILu9~#jb}sDBEKVLcax&CzTGXV@#;;iZuF!F;No~Qb4&S z8r06Y zZK0XbIj|}+0Dq^lK15LpUMh{m@>h$|OK&G0?+}Es)v?_EFL5~G`$`P#R{+hP3NRQ? zffu!zsLJ>`-h6T3viKl21*LS0%4G3gv`&Uc!Roj&d_Ud(>kkbdm7*){nu(EkGk0p8 z6|NHXhQ_jdJYkXwug(H2iP{gw_B!~{ZX)sX} zb5A;MIU^3@Hghpbx`4Wxv2S;Q9hNC>$1i^q(L8Yn+?$&N^JDhF^^Rn?6TgX=^Rq1H zxH6K5aqwSdB3)b%g6hVxC^}L|AXFZO+%muRk+cSODFkuhJb|5WY}F;3g>N# zv3kEMU7a-#e?><@7x_s~KKR`^IcX2P>yAU24t0>WJVMoU)k$no2JRDzfPqI&c#0E( z2aF*#pjU{G^IGYWv3c;)Dg~X-X3~4rNAd2NP;xjf7#j^T(AOy+p1GC~d-FF`G0KSd zh`BJ+^x9#Or!=auzM7rwY78;tp}<8GdV#i3bHktAQLIOB#cv%f+>lC^N)^Cb|3>gW zB10mN?#1XcIe4(uguI^N#x<7ih92E~*q$N*r=AYcWbsHW)HuvFJ4^-tg>!K1o*TL8 zxQE!Ct>!gtZiEx>%V}1AF8#^op{=@YwBqhMw303cF`32ayw4P)t?Q{Y=_WFz{*drg zk}AGDLH!OF;PXRb7_z#HexEjxypT47BTdI+_O3sudvK)k})q{Nw%i-}hMLavL z9H*RO9?xy8pE_j?FL~#t5SU$vAMaOp8Mng-txz27~9jCyVzmL zzkIwOuY~Si8Srh#Lt=Gt68?mI5Hs70&G{Oj-z|khar5Ei_#hEb3nBvzwk%h0hl~Wi zr7dAXEMrFTYVZyE$HfEBYVhIur)_A-XOENY26->N`{|MJIP!OD2IJt>v*(6!+D=af zeSvOJcUuG#E=u!MpI305fwfquy@2liN~l(|A@*1@W=&Ndu_+!UKeF%An>OyCln_WC zSypyGU*w3#2fN_T{A1*Y(iZp9GCj99_$}!V|7wKaooEN1h#C0 zf=904eueqm;*&ri5V~snY``le3;czzlMQ@nWW${*ki064K2P;9X=)h$5Z{P}HkXNw zq(Al+HsY-fXQ@tp1`aa*oY3n;cvu`k=6iV(mA!^Y7u+Y($#wAg(gGOe69*aVaOj_y z2=P@raq+`qtnUdYjmIQNb>MxnwZ#D+u1i5Z%UUSj6$=&J`7rivfKFR5lm4tBy28q@KW6b^=gM2~$ z(~X~gk)Qb_FPGwY=P|IA z355pt2Glhd#N?r5T;byiC%3%eZiN`Z_gjHcz z)%4*$A6h835|ol}@G_KRF<_D*?l?UQtjZ%%TeS?*?WE}ymqyTAl*4>fMP%slQ93iB z7R+VTz)7Q@+T3EkINJu;)3X2v*_o&>ZYEeVJ0I=yV)3=*l^*_@`C_uNPT1*1c8TxpD*Q313{^XWD=1Cik?B&$WDQ1j{s zPE|%1*1mW{j)|r~WNi)eF&@K<&IPQiCxG)Di}4X30nK?^;i6&yoU189A%86pJGK|B zG9~D8Q++&khWV?@D(R;m#;~WZ5tlvT$Nl!k^e$c{eJNS^{c0Ikal8Xlc1*{oPU$G7 zQc8r|-EjV^Nc>ao0NM&GV8-0XMEWY@rdO6y?UnI(8oW>>@0WhLg<7|I{xm3)EAGC2 ziuKDY#_1AQAE=)x#qwb}MESf5#AOwu=KU+&`VcYlfQZA+U=6sofORgu&WF+(bC{X( zw0mQYCQcvoCO;jdK|1phBAL z!VY_IJ2QudXm4UpkrC?TpMpuT+wfa_1TTlpA8xPCqe4|u80S|{x2H(b?7^crF1i;+ zT1Lp5$xUc*WE$_)iLEHNqL#$fWO8<|>QTbR2clyS!PZ%8d85*&xIi^ZJbh~+=eZFs z`O``Gjq>Qk`RnurwtnE9Z&0GivklSmb1L-~ulDWwkaQpE?sHt^Sb;nQZX++X~|sqPn+*C*#6BQP^|*1hFdE4y#*D z=rxaKD!>>Z1D?6i`*0HZ$p1t?NJN-7xw7aUXW_tF!(3AQ^e51fJJ_ z(2A3N6eixH@9m7xdd>@?RJs>0&x-;D^LjYqeiGx@JlM&l7`V1doY8ZhrU>mq&5do) zweCMoTka@swrqi<%ftGo+HZ4qcHg^a8%|(ZR8g?{#7~>WH*!}dYQxraAPJ*OLCh-v zdoL-$>8x;GLQps8H+`pVC(^Ncw6TAHJlY z@*@yhXVjsJrWScD?Sb`PxtO#l5A zyfVhF`e?5SX3gvIQB5H4qf-=$Mh%eXX)gFdHU{~7nHOrQG+oNc(2>kpD7!fxuO@B9 z5T^j*=zNLp8{Wd4C6~xlgfkh?Fr`#(>9cplP$J<)k^Ct{3#4^zi;r&_=^HXQ#;v&Q>* zGvWI`eOR?hjIP~Gsiav4+?gbRd;P58+?yWq{6-UUe|(`KD-Oa%q%kM2l4{I!B{O9; zA;9x6NqT>o$Sh^t^_3Y|q8CCBugD_HJ#~RUXC+>dh+=*dc1J4tL`4&0QD~@|+#4;% zv+XCq*moz-DL9{7_3;#GuT8@QonUx(R)UNeH9>3h9IC$ZW!J;?0KX5lv%ByN>^)XN zmjpiNuJvkQepW2X@d?731usa#yn`5hKLM0H_QH!4)=59MA1l)G@aN37t~?J&n=#K3JP& zf$#Sz;CJCLjGCfPT<5RA1TRsn@~#FiU30KXsv*}D%&Cn~J$#akBvsGTaA~(Jre4{{ zbG3iOlRx2)-xsx@fzA}{^X7+;#d~<4Uuf~ZN}Qp`POOB#ovUEq=R#x5_&K>0e6l_hv(dF+*uZvRiUZVR`Z};t&VlMTV$ix*pPn^Sz~n?%+9#lZM-ysr zD0~LGt}mdsekAdfHiyE#M@^9TK7t;*`;ORmBtbG?GWNuHvu|i7Y!gbvPV?h1=eRe7 zgnlPCs^f8rz9`~O#(Eklz%K=@@Ktyk-hCB}yZLA1`m|MW$Z07_d6JBhy^}#za|$-c zYO#598%o>@B_%&&z^=X>yLYv~f!fXZO)Hz%&3ZX&y4fuIC}HojZ(Nh)EVy`G0zBl} zm>V?~wk@sUTJ`d200r-fK$|e9|I)0JJb4ibI~?P2 zkEI%Q3UZfw?~IJguGrwC^v0iy4)8O+OX~^G50S#SZv6YbRv0b7_BN9q+!!53+tV z66WW4!^*rhn0!e9cdaqT^amp7aikL_cG)3mwWEBb6S~vSP#=jE_)dZ{CWkY|yo@Eq z2AU8o19u6&vg1i5j(nl`^$We{WBvpR}+&}k)Og?1}hA%=9PuQU7 zwK{rGE)^EXXwXz69lAWS9vkaR@oe`t8f?6tEX+Cttp81u)N9DQ5)1O&NfYP#=krp8 zlkqppMNT|4LglQP57l5B3dgW}@o&bq)sCi(u7r|~F=FrLkCMTuaPPh={`cHlUw6L+ z+Aqq$?Ps#}UhSU+#e({9!EzT2EcvS^bgTl(^Vqv4QG%D@mdHB91yFnGH+5*u6!Xa32ija*A7th-X>U4=!X60LqSH#5fjDc!)&cm8WYz{hE#V! z@Z1hOd?6nNwbJRTmFZZ)R{`sM13T_`@rPiBTr_)Ix`AieJH<7Q0KgKRtkNgC)^aERzhHlqG4POde?#YMgb;anYY7AA2t`PIu$<%%WIS`U%W$`% z32ro3fbN-DWRk)on&g>CesxWNYbnP;#VG@qjI9E#1?%8rp)rac+Xq(l_Ncju3yE-7gjs!MBgd8~18*bwxJZdJ_px_jQ8)?@&xBt0(W3Yr%bQ1&xxQfEyROz}Ojo zFh&Q=3Tb9eh=Uk2lE_O`u!jit-Hq&;&E zzb8hiR3d&;grHh+Ty%LKh_6mSE42W8859g&g4bx#n_4jN*v=UXKIewNekYIl=iuC| za#R{B!>rn9SaT%>WuL#|jpdGU^L%w!SNkvdeK-OYawK5&xAnY}QW@mZLPsurFddzu zV?pm<8MNINLbY=xm>d3zy0e__S{G+jH|-_9`+{)jpAxLLt0tjNY2eVKgl&i0p{H~Q z1kPjok7o&}&)Y@bU5$cq6ALVzaU8r$mlMVJx2SSjIz~Qy%gayCz$0^F&}rgP@HTEC zb|z7vag%WM5|e1d*}arcM~vs0X@Un@T(FpB?MgOga{VjHp|&|se{Mn(^dGxIeq`$N z;@9cY2nog>xi12fCcft0hE?IKzMZJDRt#=jNk!55mMFCO32*Im=5iV>Cmq}D&?;q= z+-T;RZ4BEr_opn&Nxd8U7`@{O{NoclbKMYID;=C6%peJ4e zONt4d@{k`-FY>^-&1GQzwwET-7T8YpQDlB4Ze61c)h`V(;e$ANQ+yO`o{B(8whb9~ zuEf(We4sc9AflrN4tzAjH0D1PK_z5v6ymV#I?)0-JlvFr>bB1Cph|-mQ(i{jSZSj4 zXHD8$F`MP|CqhVNHdN0IAbQIy;qWr%eb_*`(|-PBy5|=7c=|3qtZ4+}=W?+|>pstS zi2(YP$5J|W1Z*+_aoGwtICW(P^w=`CBgVqm-U+nzk`8Ph^T4Mjws3W62faT*fO|JR z1eLrQr}AtTm%s5CT%V8ye-G@VyKH1QdC@lfdA*su{#O8%9?Q|c;18`xiiYRUoG~`1 z2A5Cq1V47~ZGMo2mu~v9=PL@{-aU-50xx;`eFZpu-ZF4C^M^YnK3I5s8j3nyr;B5g z@y7Z#I!*2ku`{IPT!a&KI6fIx`>X;_#@$htSql=0D{<4QTHbTkr{0wtL>6U@@Jhs3 zFZ4wmS$Qy-lFBUXJyU^!15p@gTY|?kv%%6+5esJJVZf33Q0O}ya!(aBP|@w2Zhxk+&(#*Nw*S4;^@~>Th+MrF`#R9~g=iyQYGuxD{^sJ&koTZQzop z7f(G@1wR{_;Zr+XoFwRsiT!bSYPbR2<*(ABF-cy%O)TA6ca88Hydf5%OYoTJQxa1x z3H288;B~7EngW`^HFO zIi{Uf8!v~T;Y0{~I|b|5z3Z}h7jN=^-XN!(4zqmfs7`$ycu()3H*Mcgy@6(!JK;DE z$xnb{`JFIvaTy+*DL{r#WWsV~W4ttN0vi8O0hM!hD0Lu>G454)TZfzI04+vc6-z8l zmI4iLU*J~Gf*t#IBX>ucPT-G&7abe$eZfI||2PjN z{n6Z61Olbb(N#G-PQ&-I-de?aTyZ*^6hEuxq>~#+xQ;RyeN?Bib60`)%sAYV9YWyk zX1r)%Nw~guB&B$S$PH=pdbEom?Rg0EYQ$h-Q3Fg_EsLiNE1}J61vrbvz`3*)jFoo~ zk4~(_m9E?1)~HSQutySZsSQP$Q_REaz8}+*&XcuVIL_lM!2^@Z;rG)*P`AwCef=+o zOe`~pH@ixiTP*}i7MP%xTpVib4@8XKL~Jha05R7Pu65a4()W=d*`Q2GQyD$GbPJvN zAPh6(525bN$8>K+6uhY)qd4wBCqZ0K4t%s?6S(&_w< zFgF(Zr)z=D_*tsTSh$VS%#|bcos6?@s#K^p8CUOwR+f#>llR8%+%Pm7NXML-1{8c# zjQwl||M;Z~#(5pWrH#xzmT8L5d)=VqR5EcDj5fb46Jwq03+?30q~3ohK?_u{4Ky znhscFWJS(m0;(0Rf+{sFvbZ!H`LydWrL&Swly1OlnyX0lR2%s6Jc&Hn2``!Xm@RL}1-*p3{;Fw0j$Zz6N|~bvuzB6iLRc)od24wH=0*O2a?vZgN1^8cw<& zhtKCUN#&{wv$g;nn66M z04Ii|;W{M)jByC8942t8x0@6n^uPm)E>K}#M5lNoyquQdm&?@ z?S|8qKd6vo6eii7qaV*qqSxpQaA#-r2Z=ujxR%4zJSn)Dpo3(mAiUjLkN;Fgsr6jO zyHc8o6>3)aabzF*B`!zt)@@YqP&OWUT>=j_M&qHYhjBZ<8VLHvat*T0T=BC8VVsJt@`W?9Sx;{zK&{G=k<+6!W9#as-3UO~OiGnf5< zG%_l*U1BjBCdn({3QD{J0@s1{?E+c@|s6 zpv`?3mRK%id=GilK319UpoR82h;wtr z+ne!C7zkW&1)QHR%DS|ZKydg1QB%4|MPC3u_k2mS zISXp8u?la0Z-SBH2wk-jRy4*t?;Ty|az1ZQxJL5U0&@r;hqH z@clwNg3lBBVdZ*!xGWnUw^Txn=QjP|dzS3`9snBM$&ggB2MyE9P)0G1S78Al|M4jO zT{Z#iJNFW=(v?_U+kuYDHvnH!E%ucP;e2+F`*?#f)wgOuRdXgS{BDhZm*`;M;?v}i zQV8!&OgLE^qsk>rngQ*RYe6OTIL`ge?pIr^$Una*T;lJ5d|x6Vc~2Nf{Yl1_`)lyJ zB=fKEO#(&6$Fbee0fXyX@g4hCc&%^ZNrYY_V(K9fk*$DoO<5rBX@Fie6QPgIF>DH1 zhDFtbY<7);O&b~^`HDUI6-lFPc^u43czz`5ghR-fUtAy&g!@x-3v3Iaa%GN z?D3|%_B(KQ?p-C5CDpiPbFX%NCpoxHVnUa0rzKr;Obo88S;M=a7IhCd*N-q$;{jNjEgK-3-9;WT!>wDjpYeM<)k`p>Kf# zH)-!XYGAjIrdFlG-Din(FoF+mUJ8b%?q8_Lil6kCeIVIE-%;k{egyXf0`}E1AC1_h~i&8nI7KB*%`!c=s<2&&ix<&U%W*`|`2zF!Z(C4=s9S_n*N!DRFSt<|8 zqMJ#NjuIXowS_eEZdzkI9g1l>Iq6ZhKm*dlj2y!8vee*u92f4S)F<^lYcx`39zseyx z5O|S#_`l{#x2R(J!XtR9!3U0o8$;jBT+ClC0hcq%acolr9o-xcpDN0ryL=XTw%-lz zxvfX-9CtANIRj4HDxthpKAP3VVYBytZR=um{43lY=jW^=dFEbztgY}8*A%p! z=R^jh{_jfqzW zBbe<<#V2hQa3vrWIH_Ll`q4;Q6a2b2=6xV^@0kjJwt2JN0k+Zkf{&|}3&5Jqk+^JC zJ}7t2#f^-I;`ZYxuIjFbme?L*mg7VuN+fY8G6UvURAKe^PMkkh1;RTFV9VvHApCGH z;g4*@;V;6lBj_Eu|2Uh@oBoz%G%I<7uOu+|xg?aS`oR2M3Fz{DIcEO=ZyfgQs2 zpm{nT`geKZNz+e^esz%Ke*j}o?I_7)5q@PyQQv>G(j7$6< zy_dvc^7uU5d+##|6}(3SE)J4)LzJBD)Wma%!c@R%q-QZ)p*OQWB% z4L!_X$~cJAq3d%!YTS9u@eS{W*)|fmgk?M4=OMix`im4LF&@$QV=j7THTsSv(T2Bc zksNrWZK0jPPy@7lapNdnpX2N&p zBQWyjI(cy@wYSV6lRIP9P1AI0!CPq=bo9s~FISVE3CrXRzU%;pn0Cn7Zw)uB-7)JR zrCWzv;rio5kQ~dPeeZp!_Uj;Adr1~Y4J7e>uOuX86p&p8AIbWdxzuZ2ApIhp454!m zz#E|qs1}Q4x%&P1=UO6Tn(PJL+`VKu+p6rW)1pRFEwJz7L^!J82{jKosC9J)QX)^k z6FIoKqJfr;C1Ka3B{1QV5hPx&#?lzZVhK{ft?z2!t%Mayh>P*Yy=U`|#_3?MP(A(* z2!Np3ljvHlHrjL~gSYs;I&Phi#nqOVK<2_g+@9qFpYGbyi8sx0foUY!@6-+|$GxFU zc_BW|u!9FRq?eoaowVK@;f?HhL9B1{VA6U%1iq!cUJGlH-xS%&%Bt8~mTF@mm}ZusqL9WIP^;|(>i@3?-}Z-g{=N_TF3Zt! zSruGbRDj!!>mm3=6|wS8fmnm+x5!c{BV1nC!}bs&uk=jXr zxr!8ZI>&JZb}XGsXZE+Du(Cc#|ICB$ciLe6h%@Rf^Mhlm=cu1$6E6IdMdT0Xfw|Q& zGGk;hr1r(&?`{WDBesi-(m?!wHb%=ymUXE|$(U3+k@s@N=WgpkWa$U0wj%|0=cM6Y zo%t}L-3lbIl?FD8b5??>SmdLH+9xuQ4M(GLxE#nUmB4V6Cd|>!1gZW){HmWv{WtLI z+nmp5x#$|yW%)i|ejgYsP=(&we6|@GOOwp?utUoP1iq~Wd#y;`@_(zqYUwp91@Tz; zq!~U4uOdgD_3$=GZinpPRXFd;S}@OwB$Gt6J<@SZ7!;**EB$=Jdmta#Z-@7uBG!@K|$93`<{ z+5zRIKgXexsrS+YGB(u!g_so9S$iezqsuHQ9iNL`os^>vURsunlr8BJolFI@+@&0upa@(ncq1 z;M>jK?*|ld?YIa$EZYs1e`hhzw+K3PYB6L^1SDw(f?;wMKD}0iI_qX5jZ&u)E$iuo zMfyZ!ZMMEv6??yh+~IBH+OYlC5j>UTjhlzl@n%y6ZVQiq$$QnQS1jwZ?N@~XrkNRw zOoSObFY0%#Uy1!ws(8l#qTspGLTq|-m#k)4nwUH4WaywbENU^Pqmz)=wPg!Yc~Fj2 zq?MdsQwO$D{X}~=Kk@>b(PL2zsTC#=^CSY(J-lI43foF?X`mbZim1->QgE5p1X`zx zanP(76zT(bpS*9=CFkzYAW6pY73-qG&kC^Wa4v+}6hP(pA+l**J)M)M&eaUa!kvHV zpxvvAdy1QgG-GnCnevK$Jsn0cE(~1WPhs1l>D0ZTg1CHqK$LTi!Irh-)ZE7oG9Ip^ zi=B4EH|FEqc~^sT%-+)}vRR<064mQ!KT3?r40Px^gu)BEP|xTl4UjU0gZ)=|PqbX{ zyG|Ziw^f?XG-|;AP8Hx{!#!NjyZLy@eKQy;iqMx-0*$o}gMj-^c=kyVEa#h(X}{X3 zY56J$uNk4PZ{u)PTRk108xEh`W}vOE7oKm*BhT*^!;h(cH0($=^U68MbCQQK1zC8J zrU2%jWay=z^^kV`22I%flRg`{OFDyVfN>;fu3#5&`y$BnjxC@!63h;iF4!9%j<;f3 z$jaayo0VA;r2Ou40yj0|FC>;gtIsH zhhcw}+dha?+*sO>w zR!JSRa_AD#7qr9H0iQYj;3-||;3T(_CqA@bGXcV9~2I;kF3#N)Rptl6u>i=obX;K+iFi?jG)jZbkKG> z)W}pq`mKvpCA=IP*Q|mQe~PJ_)DCdXt%EUhJL)GiL>+x=;JS4gx&0s<_OP7w#;^|V z-t#Ds_2uI&zrO%h$Zf_C6NNz7%LN98Qt^kyv)*mDv*Gvtp^!#JwqkI_dv1iPyAxC^1@S3;Q&IEl#^&eDlwci?8!ahr)vzUj=nQU-z8F1U8m7PX&Lfok4>zE|yL`eUOtn3$G8 zzZ#Hvqea*=)e078HNekZicn<{3Q6C_NZ!0|n7d94uKf@vZPrFG^gI|#Yn#DUFOCSu zY2pl1<}IqHQm5*@ByLqUc_lvsH>)+GR_-vJ9ycH7S>%!Zg2_0n8HznUJBZ8#_8cpO zfy%K+@EYZq*27Wh>6+9+HUTfbOu&iPCNrMEZ4x+k5UMuSqsZA-SU!Ii+4U|7Jo1=l zeq$|Ot8bu!Uj$&uz$jrs3b5EZ4`%w8_L>K&kntQb>UD0EN^xuHWa@y4;$zg_ya3FN zr@_bYGUTfQwp!XdgHDz15`3$`y}zT*zh<8u2vP&7{+H< zoiE3m?a_lD|C+&5$9fW8xCH(PltVyJJH~#yK}y;~;E91Qw%_nVDYZ(>W0``;@jW=j z9hF`o)nS9~R3?k<4V zXG(B2%@fofv{I$TwJXYb&S0x!PFfR1;DeABjM(Jj{-_chhDLm$(G3*}i{ZTM7w(i- zF)EL50;|7%be4%Oj61{y+E=2*iE%*r5v07BiwEvj!mP~g-Ji81vFd3$)aT`adtLxZU($$U zvdv()R2{brq(Ol~DJE)J;-R-}9LY!-s8TV>Jfj3}t6JcDv@>c|HjsO}k`Wv1DX_lk zbO~u9T#~QPh`(@1OAZVw4uSvnGw9G}2U_ghxm~Cb6XXCVhVF;smLK$TO0+c;!RL?oUsVQIXcNL1zE-XI-Kl83p%tRsL{nOG-vg#^pj;6Cv!*gAa%uC7}Ri&R@s)0$<$mvrKl9ZONw zQiracyq_`lJ;?rF#UPQe28=gbK;y~-&?I7lxmxGRd++u7YjgCltHTq!)YpLgGp2{@ zAkj5hkG(oMI7@mhOkdqctAbZ?f4t6;@58tBw{56JbM5!E8&cud(lnAjGDg-s4<{=+ zE4Y{7%JxUgz;c@>Na@)GhqyA+PFU5Yf#B9LiHh0w`)yyB&d-Ek-tPT70ooN0dW!SEn#Tq?mk z>D`QmqBe}fwjP%-P2})m6FOfqifT^*?eDE~&6hw~AfpQ1X-tH_L;R z_cflhhB5qNc|mEmA^%dZ5w-?};iBGh{CxZ{YA4;|8hfhgJ31An1;&s>6GQBpCxzqN zClj^T2gt>sDu~J1LChI*W_fu5t`}vU%ayfQZ(4(USneU-q#RAc^YCD73RY(wW1FSr z`YB_@w5hIw@gWa^$;58FlqAhvdE`zfOI6Tz2`M16!f?M7A8y{b2{d-a;pL9s#Emi4 zdZ%e&?aM-Z+LMg;*?!~Iu~?Sl>LB1y3$N>{@T^@k{2s{T&5kPpqj_oY&^j1~pTrSA zP7>$8YQlW0L@Xb>N&RbUaOOxn$<-ADU#EDueB>}rQOv^Fc$SL}HG@vmJe($&3UXDE z_)zKpO<^Jb=}9B`~4;CVlg;n|!^z1i$~v zz~haw^kcIqlrVj-H1AF0XAN_O;f(^$IRX`YQ*5f!InKCI1uRde*amYg z_~6^pKP2mrkAB8oJrI{P$1qzVxO1%&<}Y7`UB9h4x7Ts#yJ?6zX_cc{TNe%woFGcU z2B>_$3Z3?6QLAm6!K6JK=KcIlFop>~l-D`gsQ`?+! zaGs(K=e??Ed#4PV{qqNz#{zIUv7bt;$pwiIQfTkAm8SNM&;gbO(|g^DUp{5vij`&H zwPY*0+nC{k^|P?vXA1iLNC6-7jgYg*3>DNf!Qs^d{gJTa^o;iyEtd!*0#DoNM)7XO zbuR?+W0?DJ-2lf=x#78YO8Drh3mn+E1g+xgVDwZFyqr;l>pV7K#=R(T+`_usPlI5k z^Gf>Tls=XJbqFVfZ=(=ZOplR9cotkkrmpx+Qx`D*PhR9^1cqZoHR6)lnyaWFd{q9s?tm5>RTmOe@+%5{^iLk+mxg`ec4$iTqKB=B!G zhB=vIWYaGz>eeZQgDq!hm6{kXm$X99;1}F7i4-bzauN(loFEaS$GERSIS}`pd2a=u z$rkl$?0s1bPb_be+Fvd3?$9_{f8i`KvTpfyjtD>RJ#G*In+2tCwZ=vq_wU9zp4&m`#vmOCkjEnqjNwR{!N+AASz|mC z=5kX}bz&-h9hr;`zXNH~6H)p{K?$t)MPf1Q>uod_fE4L``h?#I4J9|gS=KSQHMA3z z^jRlLuA2(|tq1A2Mer}jiFvuc;NhrGt3o?qpf`!S8z^F%MG{`ybqH!d24Jvo4P5Dn zgy)CFsPK~!u4`K<5cUlHR@g@LcW$ktb7`SM~a$2JwEP2-{~0!B4BL zq`7?>Xv9v2#_<(+^JyU_ADjl_mY0aT`yZ}0Q4At~HsJ}~R-i9>A-rz^s@-XUxC@&2 zr@IqZRvtlz)ZN6aEQSW!s>0t_v(Uy^9Xkw6p!Pb;um4UX5BVFRD9Qysto8+M(M%Xm zJ3wWV;^D9D8QQ9s1Me(i(Ot0-WyyMcMABe=RvGk~=cC#tM||*Ihl=Q>@D9w%$DlDc z)Gbs8ciA~mcE%F&j?N)f>IZR9u#3*`TLKU0449tV%C?JE!NA!Jwh0+YX1))@n*rD9 zrvNMRTre2Vwglqiwgk-KJ5Ar#M`4ozyJwtT&I>M3AWe&e@Iy#D?pb&g?kS|>ku^>5 zTJ$8j`SKNc=C~cUb&H{{BxAEI*^UoVTFAsK8GKzhLK|_E7`TVv(0Rsq`CJEl?UA_S zA=@NgTY#tgkHTne8k|fl#?pKvUZ?v^>aa@~+0q@%k>^k$un6S;w872$tT(vh92wH; z<$eq{qE$3UAGI2QRo_amg>{zG!FzHC+4?~cxT&f5bW$@>+ii?b+Ig)@?}m{#1c-oTq8CY*;ac?B`M{#LLuXw&6cHPwUq^qDyCy(aS9l#rJz*7 z$cpWX9J(eZ8O4_cr@{vT5BdAHYFaRDe0cW|;w#r0F? zfoSm*G<|xHD$Xi_l-5AVvRsdw7RX@3%k|hNx)!e7?|@h7Y)8e=8+|hv=TplICupo8 zmy~32eY^}7Z7)aJN6Wxi*ppoTlnN)KJ0A3X>+V-=)PQi>mzJqU_(BqZBs{=;SRRH@=53q6(&)c92xRNw7+6oCpYnz;FZL&8hZqpl=c^tcxWfB|&r`+6YRe%;@1i z8|c;KF7ET%T)Y&p56ePpsN!f2=s!(I-H$Qc?xa6-@q%ic;%tU`_rs{k>sAOBH={a# z9I3~0U6K{<1W}%GSb5zT1@^q7&H60cJ@SHF?_)d{lUa~IW=BgyvY_=-1RixLhS=g= z@K`?!X5TmphdMqpF5M;iMEyO@_@@BIzsrHYrHl93O@+#9l+dMKxhRn8&pVr}jhc#V zTcN2A9t>~b-Rz0dFO9Gy`|S;IdAtqQ3QvZwdwq!+<3v5$nZkYDl~2_cJHq^D&2-Zj z)@RNN$9Zxp^y=nj656|v(D$n`c!C~?mgiu{i)Q4-_0jYH>>(%33Oo3$=zDE<>c_Z# zZX@Qr>?6}CcQ+gwR1T8pL&7LJFO+_@HUyveSa|WL0Nh>DaKB0fcs$p_uZq!_ljx60 zfw3&(x&poSc)%R-FgzTu&Q_hh(35i zihqltn@SseT>Olj`&ER2Z8nhdAdScz&c(0`VH{oRsU^{zZpU_z({W6d)0c5vj_TG+VCbYaPR)wJ-9|0Yd@2H`-g{4dYK_7CDPxZf zo6%i&^KoGdV>75o7w!gAeJG6izRz5oPAN z;qjsvg0lw6W5sh3Ds`d;a;g1A6<4OW*N#Ov4g&`Rq9{gu(V^!y4t8va`gs-*d; zvSSbxc5i{p!R}=4<6Lz5)&j3Xqak2K8J(6^!IOYhxW#2U%OFL<`D6UNp35S**^_yG z3$5_Xtb-U=Ge+hYXrfCk(~Eto@QiR7I6N1J59uz%sP_fQEFsh)#u~rmDBjc4uI9eDd<(tWEC$_%GKq)Ib<5jal-zKVl>c`4rg97i<{$H7k7wdk{vZIjs$ zYGwS9n`*48zvb@`jU6w+45K3`?0A<}EtrhCL22yWTn@J!*ruC69sGCiJpC6}PAi=> zK+m&>oLSS%dl%&lHNgptcQOaBsVhTm{!(~-zz!sj#e9T3u%2*x@6k$25}wgUuB@p?O~IKM&bB$FQgV^Um?qD6 zGLPSCAMh)t(LsSLO&c4#qX{6YSiNM9zxl3_oZ zBV!8}4X)F5v&ZObqaczcITg(wrJzS`4Sm@Xi@()HA>SjHs=0`uWZe>CaJdP#ZmQ?B z>}yfgry1`KD+5`&7wziI;QPcl&N_l|m6E2C=#T7)g^D^Np95};TFuVv*9VTm*XOEa)ss+ z?P}7D2XC&#*z+ZD`|~%dLpDN%-78ubvIuv2`QqG`Xo$;gA@S^;zDRKm_(TuV*d z750(N7qEwJ*>1Af!H_rhQyQJmzvnfD_S2AC_w{w$y6|`Fau6ymMsc>_`FKSpi2M1V zc~vE97V%@6NHj@FK92vbkOTA63t*pt?(x2yGGb=2m{VFh6NeXHryfQeS&?S|7ZSoj z@ZM|s|X_JKb^h=MGT&zMk%89dv(TU5v=SL#JHhgBx4qsER~BK0W-8_tCuq z_>M>N7I?0L($0Oj^}#NXg_bg^%00TZ$TH|O9iD%YtZp<4wV(wLd8dg zc;9V5RC!Lot<1M^du<3tbur{&sVN;kA;pOwIEFC>@u1untFO^rLBGZ%1K*=2JS1ES zQI-L?ak2-Ix_1bIl<$+ArRH$m>KfUs)j>8tuI7C;n1jbz*P{93BbvV=3q<5aY2m&e z!eiMxzHJ}r+oBfCP(DI$c{g!$l~$A2f9CKSOS8d$uM4#A0TfhrKx=jvG!=0qOBYPU z+xC{w_aGXoEvn(+h%K7s$K#FLO{Bdm4<`gTkftrB7-;!;G%*PirS~vS za|}BDGC<8KN@U54bXfL$m{`9F0Xu1bDwL&#=dL<{Kg*W98x*07^ObQ?P7DIdyz3V*mbjCk>nSbdX#2?;eA=2%Ux%YEm*W;5;AK^!OV z$%1#QC&GBYH-_mt!!D*Zn5s&Ec!N6ow`YCC(P>y&Ax%3#2hjDAy_py2 zG|3`(F*?e$J;rTfdUx?(Yn;Old9F+wt)n&wlQP+<%jKQ+KwFdd(It%j-JO8&oRg`=T| z7+Z0WI1E+7NM8zei})S&YNXBhbt&GIxdRQ`7_4!6p4y7GcJ=V?99 z?Db;&C_!LG;zYDal>+_JNP3BBm-Qk&*!L)!+~Z3JBgtwS8cW*Lh^dPz{PQV3y zPkFd&BEAT!;*F>b6H`6`90@Lf6pI|j(RL$(#F>|Vbr))$zDceHULcNg+OTs?HWV&t z0jkg1jo|Apq@s%ySP?tUpf+VYI9bNG)GR!@XO{+aN$KM@tLxMA(#Nca-%4b>}E z@XPD7+?#v$IFwL_dd}HoyXT0|N?*pG|EVv$v5w9OyhQq4339));G1I` zE*I*-g?WkCa(Es1#Qmf7L1n$K-aMm=Zn7L~=XA7Vo3*+-oXC_bp(wFt8@TzW5zEPp zBRa2!DwJPhUEFNkAF7X??rh65vj->Uwc*e4r{wk72aN`p1@j zYszFD8(*Hnu}-pkMgj`9B{SCcFEUvolDjXcNQ0Igg}#jgbj}_{Q7Ksio~2)3!bv`UG?nT8ko^t5Ce93MaMNqw@3&{Jl3GWka?>m{uV>e|6Es z#~$=}0OLLcO5vu(Lqz_Z7drP`k!(Y&-S4JsWK8>%r=9G+c5HgAGTGP+~A2+b!5Oq(1;JI-O|LeWwTK ze(0^QFC?nR+u(wrCbnE@;T26^!I-ph`a6;)Lk7zWy(tNyR$6grbVM2cJF3aY{%eq4p`<~m&&eKaCmJ->(*|0-XpJ*lSKna~_y1BCs&QF^M-%55<17k5b zxO6W(=%_@SUyYy!o7e`}Un(PRf}yWU;l}1BIBtH2(vq3vuYU>rvPy;rYQDJQxgIRg zZo_oX6p&u91pSuOz?ye2$Uym4`b#Dj$HdgZYSuTN65H{(4Ckq#bO4FZcBAv6+i|3& zjHejg3K{O-1 z0KIf$h;lnf6@9Al{GAK5=}RRB+*Ku6&ChuMoR1LvtP5}EB;z?_Yt&t%$@0(7$i%X3 zpv^B&&i5`xg>yUM>VaseGKoaJ|6K6e@M^5S?gjV$1aUJC2|ywDgz$|zfy&BM*z-pe z-{`5p(A@_7)1F4xS~-weD||48-7{WRFrIkOMp}Ke9SU|Z*8ki@$p7(kIwkj#2bzMiYckH+q}kgt+!D(Io5b)V^&UolU? zj`=HQz7Tv;A8*a~#5*IYv^_crHZy-w*RYyCR;b4MNy2nlK_MMr8mWKo49cI?$$6=W zlC7gt;l%7;z4!lWK&O-@dfDk=`ljWeJtPbFay@YOgqO6y`Wv;-WqT|4V|fNOBgB>Q zvFPW8+@xMfs&>8+AGx%G*Y)LS9pB7Tv>PI|?|0$8q8j`<_>G*&tb>|Y%edzb?@8P7 zaNc&`STwW0MYdUog4Fe$BqHZ4`T1Wq(yAg@rXz{5d&5cFJP9Vqy(IFtGeKsrH`;l) za`{KvNzS!C?(^wxuEypG`JFo#W96B@T=JJ(Um=dw3wPr2mU_akQ%m^zGieLEfAlSH z={<2p8rPr8$8QrDFWD&-ozk*k^ApB%Xc(jg`T4kuvA-_HE|PmwlMmZOE5NKJnO^V+hAA!EVB3yFxVdLF=mZ|-Z8U#R zoKT6pO{jrwA#Tv|%NZX2NPs9)bqw1!88@2N!ulQT4mhg;)NNY7JUJKSf9t{Z zH3zZPPzE2|Xv7~TEN^kKf;)V?i4Hw1WSdS4LFHEzToUvqZ77p91ng z?KK&27A5m1?1NoCLR4o*BoyD%hhw@|=&QhN-X^BiE>@PoiDwtWw#+s>*)d3Ooj6K< zl`7M}VG+Fg%ayPrbt?qRG3G(_54!ST5cG)4(5>e`)3e*(Q(1#Fd_L$28*2ZM!`A9t zsM%=}pv>5(LJ!DG*%rE|L56$3{}?VUZ^nr2C#bIdZlXU@PtpAc&+gwAQ0Z!e3EP{= zic3-WaF!)BtoyQJFY`ZIL(|a7RYXYh-(;hi*zfNPK1;2^a1_MY>k)p98i+GmA7 zs-Mt+jxErYmP{g5)1fl64xOB9P)~jh$eMj7^Np=x*CQR$7?A*v6=FfRpc6djO{cc& zEO5%*k#ZFUcpJ3pdk;@27)R z*iY*HknO4Qx8Y==PPA)I!~us6@@!%V=pAx{vB4O;XxvQBO=zL{eXY3T!aT6Nx(OT? zWutOY7q$3M11=X*P?M*NZ|^0;p4-b%T$XKA`Q+g2hsH2_KobQo=7HMuX8QY|AkTlQ z4{p>?r{z!M;mo=?5YdI|Rx+f!Ay9ufnvD0OVWyQWMhKhuEOrblTb`^+YYd?j@(BXC+emG|eYGvbrquzpuTA)$E|1GOG7AIrSA3&TgBaO0L1FlR|E{`hc-yBj?h z?whg#3!W@n(E$6lA>(cR0tKlK@8K0RY!)}&8QV#0o>Xr!r zZ@mGWuiFp5`WrCeoIU*Q%!AqN%v0Xn0ITz>$l*mv$lvgT2#2r1k?rcB{ZJfLU0kTz zHg|k#D#&}+B*1i!Z)7IZv*c$jCV$h$$*W~KVCE={zj;F zH>SbkE$HDUg{hj6vP)2f|;a2RyJ2K= z6fJn2ME1U_=(Skoi*NB05BC+oZZ|pXe>asxd56>BpcfWFG#Vd6AAyZ-4`>(Xe}e zJ1|2LH(x(U|LGdgAE6a+KP-bh&)T4WY4Td=7I#6DD>r#-9%-P+7h%j1D8zRv!Q85s zb9h?<{iy4wyQHUH2M)OAV(2>?e4H;2!-_9x^NWk*tW66hBrL*5zw_bcAARcjJph&S zwa~J(4!qw~fc%YfWS?^{w!f-@?juoFX~aiOSPT+!#^9Il1N1b0!@)TT70lMecwXd)eMS(?R6r0nc7%3>)cfXvcOL zetM?Cu9*Uu^raLQ>??;A2eXlTwv#UZ%a0AtYUE1a4m^KM5r4J5C9UxWP}(BNdu^x& z6<2%6hs&iTdbF7*d^?>-%MCG$?*Y{uZ^hLm;pB&^EQu|7LQn0hr*rSh;|zmjqVJP{ z(_gH@$FA4tK%y&#W}9L5@m$7z-3|-x-XXJJ1j8ALW^xZS;HGCYEWVw^O>j|V-Hdgt zn^*$3PHJMvuVG^8&`E6mEyA~(XW?bPqqs#%vv<&}nd@TyrgE7w>9mZaAI9`)hhr~q z+P+_0{9+xbi!;QVM?2ukw`St}r5Vjmg@Dit#+UJ|!t|;ZR95{=pRrxP*c0mbD`qZK znl?bRNHrC=SLuCqcpgff%7>L6uYAZl$dmaamnL zZn?UWJL88TXmcSQU1|%)Vp}17z@|4ZB^vKY8bPiS%YW&vCN-~8z#)DY8H{B6m6jR2 z=!iaYqND{)=dw+w&{w>>yE5U;?)g~vl4VVm{%{JmYhl@-5bQEZff>@lyuxZe+#cP{ z^SqXiu`=b*|5y#AA9s-ifvLco_`bLP%sSR7lYrluLZqqbBTq>r1~;G>EQ@QwMG5&- z>%dED!zTlLnx-(gP8nMVH02@6F+8DlP) zw)|U*{a=&G)YmflJ+@o8yyzGn-Q!R;|Pw#E+6geAhkpCQ2K^MF=-nT>A7=SjhTK{UMFjCL!v zbE&K3Fy-?K%$)Io+bv}YTIc+T?woos_7Q~(!j$MwI7Vk!>!P1e{fZCji1tJrBr9*MA{G+j$aM8QPW%LfEB0d>Mzq!?$ZHw_t!+x=Rqj=D4#@C zb%NdMdaz7Wg=(HO^7|{m!PxV3n?f3Bq+a5*sun|QvKszS34|y02B@({2)`T^LFr;q z{8MHL(=}=!&n%wZf#k^=tB<6zcN5soze}n*PGHpHSZuxjoVLb<%+!&>2=uOZMkr`+0fP zKW0M3bj$El^ zq?an9r*(?{U#*F#t<;R0B^sePJ(O%Ii^2&ft8uu8<ofQA9EOD)-B0Jxqw+4vVUCiHhWXYVyjKxay3PG`)-T zcA*||J8X>ibc`YQM(v8@)^T8@Xb$eovvc$7g-=sn5fz(5Fw@`=S}G)AsLv=@s1pbK zrk)}V&nh7Aej1$7v0#1Qb-40EtG?0q8i)}u#j$`|$T3-gGJ4(^{^}8Rocxz)?zKP+ zU4{AcGFV=~6Myn2pvWr&R9PrN1tlKwKK!dkxuTQKipWG8vHa0ht*<^P?2qk zecJa(>AMj4cew$NPuWKGe#G$xojXB{WZT(F;Jte@tP!PPQMdIhygK*8qlD;*yMQW)?ichZs$(Q~x@k|Mg;w@zy z;+deB(gKb%bm-v9CSn@gfy2WJuqjWH8a6qB)C9J7n52)Rvg{r0;{<1BRB)MLGtvH| zGRhiW=G6Xrz@*Fju|K^4UWGJ*s(>R@K2M~9@4c{NRs?t@7Gklx6Zw`fgBxnCg}}cJ zD4EFiG#d3#dn_L2R*Dl3$#Mwe9f9eO3Lw>a0|ws7gs)94L^XdiE!yFUn?%y#O2Q0i z6#hoH-<(N`)2j4Kn;C;Md5DP3Zzu1{63{2x16;W2cx6&DE_QFDh6&0f+M$O^O)dhz zmTYu06d`6I?a=G04BIY;qs^`)-1{gRJcn-67v9HUW>^dr?Pd8z*I4*(qaa=9vH}NV zpYz@CiMj#N&5lT;8K|p(6P(Nfy>6E?RB8D;K>`X0ird_jeuj6feNe zQ8ThjZVAYgg@V_*N-EaOcm%yoxUr!OQawAd!&(a8W(C2Em9L21_hguB>reQ@imxx$TB#2HHNQ#b>myJfqYrn#?t?+WCAjaUFf2QlN_*=g z;CPe{R?97+&OcW|=)||YD>jWVVSWlM+vN{Smo~EJ&Xc!DU?Po*T8DFwmV#8A0UG-C z(#&i8SZlTxr?1I?ZPgFC;J$shbaaf~YFG&0C9-f)Jrd(yU07|GMQ%iF!D%IDX^XZY z7Tlc#JJuhfT{q*vZp8^HjZWT1jp2h zP=4+-c*Iy9rz|JJ5!Fn5x8?};zmMW=Vp;hED;&71KI$O(*bAN<-H2bl3d7P)NzV9v zAolyS4o>!7cz@jwUokf5)9ypm?}-Bb3=Qq|t?VQ7vZL|ojLEzUr}MGn(IK>MvL_>d zjuY3W8^lo|8~2Q7!KC{I@N;h{{!KK-b8;*b5^us)c|PM*m!-gV3mqKHJxm?>tI*f1 ziTCn#4IJ1k#uLi%#l?k4I```0{uePw9e9v+X+7_W^F-GD)q4FZUEs$8m9ptF?!% zH@^_c>j&s-3p2=EbsXm@h!ba@4xClcL}fw}I1fi561=z(j*G9Q$Dgm_Nv`=t>?f@U zS(aDaf9?x;IyVPJnGXF`jP=<0C8_l30PM2W{Ia0XVWoTKT_#HoR=5R5;qcbv@7Le9pPg`~7;+ z^3p&3`sb24b=HD(*SlTN@}eFazA!$8Wh`D)A0!!u{zUdU>pCkY;9=)HFnRZm?)q;B zY<<6!2-s#o%$)`BO(Y+$9f-vR$!$>Xw;ZOLr*i$(=0XHpKO%2MgUzfEoFZERx(^j` znu;&fa&zJC8yDF0ClPoby5acjgAjSC6`xk@!Pr0-`g0lwEx&l+e5YPCc6Wqbm)Fu8 z`9+Xp-b$8=OvO0b1TTUb!NA!IEoGKNQ=bG}nl%*-t6dQ-5^z(=bhM&HIO}LFm|CA8 z<~m4zEtTdZwa>>bj1?)ic`w<{qFCJu59#RmB2+o^ifl0tfk@ez=o_H|w{N9`-?Mb? zDrFvg6dH=W952XW-htmC3UoLq8K3Bva<<-ffX_UWH29VdUa#vU?`qoN;=1)9>#vXU zsg-!mPYEnzXX7c^7L59}A2Z8WLCPOlIGpo|n%EqrGJ6hzXxA`V=ixyjK33p1QiGL| zMaZ)=4z|s=rLV=K=<0}X+&a-fQha)dI$oa~@V89nHVyk>YO@Pc*G%Zp(IZboZOB`Z z6x`d9ps*?64mQg$L=aN+sWGiEq=4HMmU=oeog?+ntIsqb{~Fs+l2KYMVK~C4R~r7 z5{uu2^lpvAl6%KdK(v>uuNDmBU0+FqgC=Ua%far`C7jLXu4s9Z`PSK4H>BB=%;a5w zm-ZKt+PQ2$v976q`Rjg2RairMKYZmHpVGu^g%$`8sK+=D0W?}SOsBuCLHQXzpvFFX z*3l`D>mor1)HN_n(vS+Q`j2JDDsh*~Fg+v3vO^0&@z{L!7fI*zk}r3P=mEPbimQjoLf>kVbVC!em|v(RLm5`oOvCxgC+QUL zX59Jh3lTq9LEeuX#)g5}cwfPV46Cc?WmA6adfi7K{r7?_|E~(4&OCw!=Ita?c`=!1 zf19FX9{B!pgJt4kSW6F}<*5OVYrHiEzEy`$C(|I-Xf1wHokH9v&EVve4p?Z{OdOT- zN%8t3oLrjNkB7qWYvLH)Ceg%wuT=+U)e`BYp<*mM&K$h+szBX`3$Yg`IG!yvpq+8D zzn$Gj#$*)fwVn9EaY;}CGvi<6czy>AJZ(eg#x4x5d&x=EH-q=fSq?AY2&{b_MI?gS zu&`EuojbM3-YI3^Be|Ta_{TujzB=6F69Y!Y?42UJ62fZoIeG_V>C6q#waM&1!#aKb>9UO3HPA()G zoZu#DO>*h!D3%Lxg~GLM^OamZhSOE0&4j%h0Uvvy%fhn{z$UBYz0<-4d+Bm{2>iDJ@L_& z4h)l+gP9A;KYV5~Y7j>sQo+#7E!=aI*fgS+YD z?mSpfZ-{5~pHr;6P4Xpwk}Rh=aP$5qNV=Lw)Joj2@L@MTKPLuB`{ThpYbpE}nhPoZ z8Msg6F-hyPg?wKFmOakmu*fLQT~MvJt2AH`MRbua|3~GocCZXT72-=lkHT>3w=jYBxNn+=w!&<=FDh@7UpEIp}*R z0VDZj;GJDEuDtt}bOl|chYY!N|8!}Xc&3KCH)`X_1$(fA{eEQK_MmD@CqA|o#cOtD zXt5%RWn=`gBYPg1$V>y1W4?&}ig@6=BP`Zc0J-0~I9`40#-mjQ@frH~{BSnxuz5`Gxc;Pe?47gFaW~1h zRf$gaS!i`E3O!cW;xFb-Eq3d`6YN=<}CBbL^)K$s)tp$`I;@PkXisePvhXq&uqA`a50u@S>xk|EtqP5gruJ+ zMBxqbRBnAJROrlO%*Py<7iNX0rj%3Z<@MZ+Z|aD$s~y~|Ohkcu;h_9xoYr()BMDi_ zaN@o!ERPoAL{zc-agz`p9%`dUR=guTP8<4#o+ZPpqF+>bb2Aj4eMU}rq(Icd1rWV) z7OvhBfO8B|iCLpJC_iG}Bj*;BG{xoKJD^v5s}$ooTrW#ezHuHzc5bit;L@G%$MpC4bIJBq*AMr z=zge#@Y8lwWnv!2q`O0T<1!H9^fCUYDtyx2N#EM;BSD4_sd1n({tL(kA+OW4dV3AK z8#zxs@>Pj#mP;fF^>Q(!g*_z$Km6duXI==`{>`Dj zW5m449$QNq;FhHlI0xm@9LD|Wd?N&X7RnIY@P@ne%@o}7(-TjeHNp_y6)>Mu3tv_u z^l=?fy`g}})3rEb+cM5?T}N<}%7>BC{jlFd1JpKVL6Kzxt@Q<3EuTTYt-DN)Ze0OW zI$N>q{1H^>902zvNTQ_)9Dbe0x^#y~72O90l^i|YN1kx@$y5w~sDQ~A8{myt64m8X z!QkREdV-DyxH-y?JHd0A?)wzWy>45<$@bYq@8=rQpk1M;%d)-P%3JhY0+-B4V@@&c zz3}`|COtbQ&z$4~+~i|x@o3;P`k$jaJ;L}9exg}$=>{(rtlbDs-Op+5s_FQ5>paXg zY(x=VanKCwz`5f`>ASvm_{CpKhRYi1)lpNJa9K)(o@kSOYP{gu`dRPbarVymAPSqL z*O6o1mYk8Jhv|VK=0lpzyl)1tsQPhBRM->-1zI&Ascw${6*pqSmtk%^>&bfGNX6i= zr`)0BBQUlv7bj)b!nS>t@Ogm)OndX3yxF-LCJ!5)M^!gjX4h8&kAm#&q;DTnP?E)r~^VUE4xGTm74Yn4-`h+CtDelByRx02pUxy!_EQB6AH(1!N3vE&@P%2x>7^ROm zDiVSyeud>Yd7g2P8p%@Ova{r$QaWB-+ew>i%b>Kg1dfGhf`@GqT#dg*)0h1vyM{dB zXzFX?dAkk!q$^bm34O1)Z!2MU?$n$Nlyw0H-QP!mN-4mIK^_HM?(fR zAgb-y<5{6_zxX(DV)x1GWWyj<{4O#2t&c7i?Py%(1DX2+F>{qVm?*{|3Iw9=RXr%; z{Z145P3g_+I|vn)ql1E5SywcNEZ+Z>bZo2S8Wv=NbfFC#_2?wQx*j-orGt3)Fz z%ixfM4yk)HPIxYQQ@O{A z8u1Q{q7!cSh+umx=fTXquyJ}Y>OZQ4TX&Ar(+ykTyvkziKwEJ4C_%;l%Ft200Ti@i zF^c?o_z{*fO(lxgn?aX98C2qZNomOe5V?4aZeQlj z^0&$`=Rqk1boa7*y%KU&OB|N{jG`w$X>(p_Z2`l}Da;9Bg@$Lcp~t3~+TQencJ_PN zzH}YFJOh65Yv{<5$W*>yrh2YIg)%4hyJ0y7} zv%HWlc>L9ecD_}pFjs=SKk5OGZsoz2*h-kTjb-2i5?MZf6|QV*CMOlHQGecquubag&p+ z(DD67I9!_xq93Nvpj*}SpdIU{p1eU%D0y?|?=i*9W%=l{Fp+FLca_LI$b(VydPsMW zhQ@_e5U5Q!TEbJ%oVmw3r+cGmnI~>M#(YezK3L_<`nx7V$n(Pq{pXpZrHeQ73(iJk z(WrsYTLczzWw5j0A>C13OmlD6VWjI$IP-?N1AL27+(Df&O>1bpLnD^X&P08I zw=}(e4`^&JgFKCR{Qq5jg~tJySxq_9m2-$we>rY_P`hfR z_cDJK@nrWnIa|lMCLglV+&7hc)G-0i;%c0BzXf9!3&C|~=GGc5!!~m{%)KfIjoKL) zvbh0A{?_9IH|8#~5W}9Hep*tg4Ext=qsh)pF#Mjx$#|=c&Ms{*qt60LR^B9Aat(3X zhC1wC`j?#RUjP|9zUn>JOeRl1rPEtP0GBl+qmg_Cf0s zs$8~5_a>=B`tT)Z8Fm>)p;=8BOw78^N#7fVy+1=x=bsPUm-C0X^VRTOxESZ|6`(y= zRPj+%B+-gm3NUroaf(fh>Te>J4YrGm3aIqd!B4Scss=|blc(qrC*0>93ZyUz9K zbFLMZl!?*!*aY%-ItR6~a?$^+2?mW=qx+F|B)WVsWS>KR&uzwu6SdsJ*?g#kNUx4H>jD75!+SnAoK1!N9cSzTUU!A?{qJ{|X_Wr>{zBG-Dn7<@c*$1y2dCn2do1lsniYSwR z6qaROqiCE8B_44Q$~+9*;9}VGA7jKcT_l||tcexN?MrO~uECzwWK--x=x#0n`Hzeb6c{F zoK30^4{^dxm^ng^7pF!!gHNS7XAox4bMuzqjw0qKh&+U{ii-4zNd>tkYJ|c46=*x| zNoZw0PW@AlWpE4=|AI42R5M3U;de5ydp=sNcc7N*Nmz64xwi3_0TEo`DBr+M~jIFWETQZa7mn>(4Z4i>tH)&+J zcq*~o<_UId_Csfu09*}W`BV3kq~6{PFGOTwq5cRpSXWOP7f8^C;tb4q-V7rqHQbt$ zkLZm}b5U-Z34I&hL^L(`l8G-n@IwR3Ra;1LW%O%dV)rTPWOtd0g>Hei141M$ED=}B z=fd=+a!wcTMidaKrHjud!|HzzNSn4Ap4MP|;o0eArPnBxb+f_C4Nr*C)Iyy5+7Fdj zk49->G%lH{MGVsFF;i8UMCb6rg3}qW z;zxZ^{B1A5nHRi;xd+x_u1MX0srp*nx+xY;JgI_rf-%rlp@h5a_M-ALMe>?;J|nh= zVT{6loTB!GEafZK8@^jj?Mm}-h`Gb?Wg?D5^wVDoxitPw7M;E26nE$^CBLf*;eJCS zPIRf!p6zmA-_=J7bfnxN0N=JI7TxyLy_4{8t%j z6Df+TPGthUewK#1a=#DI~z~u^aaM>4t zsb&-kxwH3C@MHQg;|$5}F^3l=0uUs4ldK3Th6Cyi^t-zmOqQ}|Vr4Tv*xXB|m+L~} zUJ00yDu@lcJ+Oi0dC1ko)nG5X3-vSd(cuqs zwcjYFgP;gMwR!Q*&su1pjils(J>mKOhUQ@fX6CV8RJRkmQzLLlJ`QG97}Cjk_3(Oq zJJgL%kOO1uV8)mu1bE!m-Sll8XnB1Y@cpzIi_`qb?VrxLqU!>8P81Tp-NwshkOdhTUMA zGfq5CG54x+3W@zyN<@m%Fz1~;*I4d071_NCVvHMM(NF}r-B604gbYrmeoTL6455zs^9;aP+_z7roN!5$T8b}k-cb2hou z8Z63`pk!DcI?NNvlY|9S=~^`7(p{y)?aUE(I~fz!SwPM3X8L{0Y?PQ+0|m*4InT_5 zFip3Kb6EZX*QKxv?taXMn(a@CTz?^Vk)s(ncCod5ss$X$o`y?!Tp-@Rirm{RgCVDu z63;ozseCyO`_9-P=jTyQ_ig4DSX>9&*lauT{1W)@PzzQ|C&1OoO(;>31$ytl5ZP{$fqc^gc;Nw$_3fe;+n}%j3GZ>;l=PS|Dwa%W_gYU?VOB3)XMP z-g(MQLn#EOkF7!J$hna6LK_X#`B5n3ANl%95Pf2np=4$u2JPmBu-7ekXCM}SnVaD$ z;q~x6lpoIy&Le{#ySOLp713F^9Ufl(LX;m4l6uQ5?t!)dOzF(RBq0+pdCIsAtEzCX zVjH^GiRvAX_raXa?c`T)8ze3b#Q?Fh|Awu%=jsm_{OP- z^DQ@-sBAe%gTChC!^<^rW8GHpznM&3Z_{MZE?gKq4yVt+p?l&gb}=sSBJm@=FJL3hkyt@kQW zci6)Xnfyv?N4Zoe^fi6`QWe`W7QpP~&&Z__74F|-*;pr<0?Dm{9R9!mXs~`9td9=_ zrMa=heP9-I`Q9TdGZM(9pVpYKFby@jM3HCK4E*`Ko!DI{#rLXfp;}Q5FU?YgiTuqV z`^g3WtgQps0^AnF2~lYRM5UVdtjHA3$9NSAm;yyQTBr|c|$eusO1kLwI_h=4zEFPQitnR zbE)K?W_BkUg42dd87I96AUhAZI|^`gg(v8F+TfGx|2W&%NWiq}Nh5N6Vb?$3|!y4E>&xsoB5~M4IA9IBd=Ro=|!rbU}jN_9;Mxt|H=mI=4fSq+bo+w}Wf zHTu$YJDqP;jh~A3Ao4;UD&1?vR=swd{dAc4^p%jQt7<#X~-vIcXttAgGvvu1@0XZE@QMqUy6%E#=EL#Wn6a4V0Q3-id zoC5xNlVqoT9uebZ?3lb?WUa{z>^{u)$qrYDKrJ{mH{*hWM%*(u z5i&xm@nE_j$cx|O)F=f)$)k<*%4RN>izdUgIlHiDhX_&Oug5u4X5$?>dk`Hl!-R$W za4C8<>|%L=Ul~4Vd>|1tj^8BdL#4#H^9VP^su`X#9^lZ8rFbn?84j3F#p#nSoU3ga z&>h4}=APWadbpR#!niHeYGnWz*#txA(w}q`q`+bKXNuczQbCDc^2Y?|oZmTgyI zeQ!gNOFVGQGMFRo9F1ZX^XbM&eQ05fGAp%GRB@P%qRg-AAId|sSU&0xuLdb;7sFPG zbcE<5uw0RkR<)+$;^R#imLxzFwvOmrzGy%gwG-w|h@<<~L=074!(7YEmw5$HOxyQb%Z7QUlIy+m1QwWT4#g52R^e7uF3H!kQVm_}0@MbgFj}@eC(; z{!R=ghrD$->(b%(l2Gh)D2IT9u{3z$IvB6_M~6P~p8c zMVV}vtgWGel@H0KQ`V@lN{&<4wh$)-TFHrl9DK$0mA$3v*q_c12el7TC3k6zy0DR` zn5e+Q&_x*d&KAaAvDx_WOc?!H4t8a}`PWqO%!f4i;q8Pi6|oqU!#Z0x98tNi3^jZcQ0ba5 z6@8`)C6e*Lw|Fx->7j$qH@u`~HH+|TZUuEXzK`waqk)_7gB*w`Cx<7jX{A90T3@Mz zDSyL3Y@XA=kupnE)OAAckuA7*Qz4G!c;m_!(a7KRj$?dY5bi#br^`&2;Zsp98u`Kq zSJDm8zp4%k{gUV#izG12=_i48;W+(l0p5x^&vlsciIz_1#pJ)0AiRbj{++u(Y7@FK z{dgq&x5pY^ZH-2k`OR2+x)c`tEQY|kBjjFa2TVCM%FU@%!|!*UkWX;{)AltWPhBKO zd|?~vO=t7;7*ul9Pi` zP#&CuXOo6GNjil4hiAD?z*bdy*{T-OCzH4~GZzq(Q=YhQH7~}W&%xX0mclH}m89(f za3*e6b0WU^!~4alDEs0Voy*R`d*`QOR&o`1W=TU9>BJvH2XO29C|vYG6+Iuxf$q;5 z-1n-30F*_w7GSQ zW6aJ7*gX@zd~zUmBFgLz_Xe4DY7_DLs)kpqWzliV3LN<61F5rKQDOahQs>%CwlD8S z&ppNP+$|sesYK9_Ty`Hl{~U2j5<$y|132T;D23MZ)NGa@N6V-j-aqW6!qVGN+$a;v zoI*kGQWbD69fV&zE6M3`DNKDBL?WMiV3>amSI9<*`ZC5%(#CjB==*5Ut?oqm9c3KJ zyGh_5Yzu!bOb5BVo#?vi3#rz1fx30R#80b~-d-9Fn%Unt&-P|Rt#dwJekF-IdRyTj z+q+LJ$p?>1J&?9qkmhaf!aMt|Ig?^*>64WabdzHT-ev6nxHJ>U?mJ7fe8O<-)n(F^ z_LUyH`jL4?9?@AId$3_=2OR$`iXV3tqq4zaJlFf0JSy>l62U2;R3(Oyl}O`^c&VF` z1p4Y^GM|7HEjFsco>6h+zcmFW9Odch&`C0!be8i#`8$2UBZDh#Mew1m2|2;eUEx1n zLGNTP3Z3HMaBwmD%|1vLO9N>Zn29P*tjk=Ihp&ffNY~E7!ryV0kopZA=Ts zyXn;)c2?}kLme3f#?GohtJVQhpq_wNFFJ!{mIIVzo+dM71wk#v1KYgPLHNfpmj95% zk(2;fA*zCvwLb7cstj5Wt;N?7DY!ZB1U+DUo`$N+K-$6}YA?70i@$Z^2I*?LtokqA zuxl6GRh1;fm31lI7NfsuDHb^Lfn|mi&JSRYJz9y`j6ZSVNXaLBs^9M@)pg;+F3 z-;cwFsjm2=ApqL@YUrmsal|RA9V7N9z#A_qa0zG}kXFv4#wm^TLP!R-=dpdMZ!4>&GJM6e37{E-6CjfNx<-=g?RNv zGn{VCfZGKHpwhP-8>Tl=&n0ybcVrLqY88;*0bW?{I82^+>%a%zR?N%yg}{wGxMoQK zl>OTWo>$lzWo;Ds%Q;Ve&nbj<{W+xZn-rUotCI_=8`0$k>$vRq#eco3n5yc^x@t?H z>fj2!95rRg+m{MC@~I#atF`dq>S+@F*bMo8baNFut5A?e z(nV~>Wohw~_K$jS9*t+iX$eyrXwgEimery1p8trx3S%`^D}w4@5hx2gC}aF@s)P8lY~paR5ax)b~=pMetbl~YaYa9BNkXy zE)Ca@KP3|L8{lsgQvX*hV$GL1mnEfQAFjivNyIK(UbBgUCJ zFgdma%CGu?w7nVle(!}|`J)s@RWW0kDrd#HEkM`Kz`J_{@#>6NJoQOePdQfs_$8$A z+`}+*G_HYH7gJ#Q;trC2sSj66FlRye3L53X@~0|&RKRc+`4+hr10~Hdp!FH8wv0fk zF~H^9BZOyFTS)B5?eK4J1?=CIiz?CtB^!(&IXVZ{HRfTtW;yLIT#b$uQ{Z2FIE*&# zN2Lo<#8)K|Zc0wUH)28PXV=cn@REZSxVLWwZcHTG>4C*bFpgjEyrAfK$CyU`ovmB5Jqt9i>*=YCSmv7Lg6NubsJC7SLBG<`Yu#zWcY%-EdFi5@wKB{uE<}UVn+Wf$U~C%u zPN(t3z~HDlRqp8l!P867pfVJ$M`v?2ZF6y<_)$7`B9XB%f78_K2I#tmc{`0YK;c_0 ze3d`Xk+u%w+_`j=jHk6D|A9rw9}^9g-^5^tq8L0fxk`DI_-*;!+qAZ2){~#4a`_~Dhl6;eW6VopOM6E z1tdzwi_{0nvn=Wy939t$HXCPrEvg86Oueu+*aMjL4;WfR<9s)%RU9Ly>t z5$1-P;ic`NneP_T!#A1y-?uf#+7$r ze6JM&Ai-u%3M^ZAqwFBA{mHt`=H;k$e>xl)Il!$I>n07tx>TWQ3+%~tWbarm`W&dj z#`;8XK5!ImJGAk})n>fN`Uh5e{Ggk}-czO-Fugbl8@{fl_r`uvi{}|&8D0nJ>(&g6 zE2yA%81rrChJ%{^Kic#;7yS7K>CoYeT)UeqasHdRkdYz||90n)6V~HIbjdBc`2)MV z4+R*n*^ZTNKgk)vb?_$TJw2||OVE*n#`RBV^Oq`?wK4?rlWf+fRfAs*Vxhjo8bAFx z49+Wju++>9Cx=pr?97E|w=ow!>UiUWuOe7`_5{cK!&Vd=T7mW~;}|q27@yY1LUvdY zxSndm9JNn$J@*!|+de`A-zCGsEp0gZT>=A|Hp0Ybb9!>{H92FOkLUUealq36Z+;2J zXFSWj5wRQ)Gio1HPCYf$ah885dfG$yP$ZV^WTt?!Rc+R+gVn zYhvrK3Sv(iJk-s{<7S$mv2Qn;jmqNZ0b#t*ozXwgwx7K5Y=XBF(bx{^cwKJ}RxM41 z_GK$E#w`srl-dUtK53$}?rw&9OJTUor%lg{zM)V0{v(E)9MR;9D(W8Q;SL(M!orxJ zB;rR6nuxW5<578#{uM<;`P48ZVLR#?CSqOIW+IlFf{|nyERxlEdja%VxWrMU)~yjNBU2(^X~nJtRHR)=hvm8PE|Q>G-G^RuSOWKX@*ng z59rsz94J-J2mZuh+#D`V6OWhaa0-pkMIal-Y_IDsX$d5!@he>~Fav|54neNsYO+k! z2{tNL!Tsv%rT+&j#F?aU$t)sRB^B}=#KbB-k(C8vNsuwNGOFN0B+zMP}xf&lm$|s*MsDNy^H|~3pi0c={fbT>H8tRtQqJbCG z?}j4`r?7qT)iyYOzXdGqw_p_i8#*Xa4qLdlXi6o(mlEbudBF!OeqAJ%7uMjWGi4}6 zV!=s02dm4c!HiyOynCjO5TS=;;#3jGpx6YZR8#3szU?r{y4*{~7m!=m(QC=U@Vo6Y#2sE8fx z&Ux>Lv(!5@8R|c=Oj1-eUS{mxe*1iQJ;eq_i&En!s!8dJvXe zNHz#_N#DS9c#u8^ZoJIH!1I}UKk^jd%E=$JeM%H=2`oa=%h-Sed~kgY%ZdJ{faj;J zBaNn=l!rM8!_#NLagjURpYJt^Vj%NuniRsD*;*Lbx|Z%;B8pkD0_1tBJR)YZO4@v^@{Q-2yz!~2S_Q1u~cw9esJ60^u!_8%dcz}-w z3|Vj2`?V^*aBaZ%LEXmG5UYU4W*B^qPu7}irB~UzlF|7Zs2lqvNabKk}j?^q5VQgNsI=dchy(Y;` zzjdgPpozn`wZSKjc|t-LV}d4|2RzD$$3FGA@p~MGx!aNy&3|-_qcxt1?gE?I^{_fR z3?c^OFh0{4{t2@lP40U5T7eux)x#v$PtrDGk0>o{=UjUU%r5|vNeLWAMw9X8wY+D}b??84`3I^lL<2d3ZsKz(ez z;G@wTSdnfG#a~%2FC_|Z{b~W5zZ^oAB$MJruQ+P1dtp??1)SZBK&NvR-jUi4C*q!y z#a&V4w`VKJaKhQM#(@vFQb=@a1N7BsLh)1wR0>ps8`1$B)5aRCX={P^7h^DRQWcG^ z`ZMN10p82+gx}i2pmd@cZH?qmTecOi2Q6S>j4oPM2H3Ffq-M|K@pDBI~OXWyDoupH?F-6V4;p0+ux z!+_U^aEXc*o6Fy!UiS~C21(_%iN{>(XirME}qIg!tvfB$z9DDvJ+y* z$&;*P+Oi=D^SAs*(=sABcF(Qxs)Yz9hn8Ws&l*_eSjJJfS%hD*df@pj9{k&z4f7ed z;f5?2W^``FqcxoH%Uo!GIfZ2J9&s!Ehxn8VKcZ}#uq~^UmPt@m%^sI z?m)bkW3GQO@soT^>h3w|b!H0SC%4)Gjgv``;qjUdK0HduNCXN8hvV1qCU}0dp02w3 zgADp~;iJJ|=&4K``N6_JjPZa3xeZU;pfb%0KASTR zw*Wsrep89EYs(<(eF(n0SA;Uklw6dKV(ij7xUskb+LxPguem1RVB7^tCwZYFf>O!F z4V*YA!j-&diBya`(b^pcYdi|MXO-{LfA9FnmmoD_-j>4l6?xFkI*lhLB1njsB+fs& z9`CYD{Pnyq+pFNGtPAhq88y6|1jo*|aQEDd$5WPNaR23Qu6u7QZm6oq zcXO2R1#HEcrB-lCs0|PGYNDWj9&~2%<4P}I^y@6-Dmfx)##8pe0}f{jQH^p-e4 zszoq5;2L#2KhPSxNFi5=UnRK6phS< zIQvX)R=zp)oco!3_0u%?W+V*@I z5=R`nZVWvCIMjGW1@5%Ag@m~>m^J2s5|zbxS2v1EEMX@}w8HSkgU zG-8&TLYiU=;6UpX_-U_#J*CHpK%O^R-u+HRJ}bb=P9tuuN%62kca~WexGN*USAQ|{Q10K$ofT?$r zaH5IrMI>6_;_+p0!Au`KrTO9M2DV>OJxNneB*Eyz{qRdz9<^N_aC)Vl5s|IKWM

bOSNZ2jMKfB{t|3!y5mlWdTSPNWvPaay}y2@JYkhBWzT-l4oe=!!oB zig#w?@V>v$E0>CAKPSPprc}D}He+mVu7;RGWoZ2ykM=X~qEgczFkE{WYE6w%@1rk7 zkA>rnS!$>vw*ij0NTXrRNxU|#obH>%T%i(%R3=B5IzIP9i8m3nTjLFQ&1q)6WAaL;pFMz)MB*Ijyj9w+EXy8qr>3GbE=r z((M}Wp-~9%i9--B?a0Hv%^|S;$xBp-z5y@#0$_jBB(lNu6@Gf@$;ljRg^M-K^u~%p znv9Nk`G^v(eD({baYq?{YdXd?_hM?e4Xzp;hCkO+@SAoZ+5TXVOjTQm=KKcUL{2qK zQxN9fsN9J+?C#@=#C*^{#)YobOE5pMo9AZvk*Zy4fPE8og2(xn;3=s9v2KZ^?nnpf z*s9_@kU;SYS5P|{!4dwQO<%<&fwI>Jxc<8fMo#{~ep7K;c{zkUn=cQp>e=|;`qgkw zMixp|_>gWFe>y9182&AA!HJRk=+g@sxJb8>b)&wZu2?bMvgIy(dj13#E50Hv6$Nl= z(F}}{Rlp~jjD2yl0yW0VVUOQlxbmqMrR(27yWo8oelQC(67uj@TsKY?lZKrBi{$y1 zy)f`A1CM3T$IV_ML?SGd24%I8l(j5(Ykh{MSyf|wm2W7eYBCin-#**#Hu^(OF~^bd8lJMaeEYv>nWBTIaHLE_>Tjnijm zGoHI38hif4r|z%d!K*qvY^a12&d(w3<&Wr-T*kYTeNNS`cA)4cUDA8I9}IXtweMa_RrO)xp71_o>vfyg}pa?m{=xa$@& z4xbu&{FjZDH@{KtiQSwPJ3Z;nuaVGJr%E!5Od!Ji6Gz*#3LRO0J^qd=EE#9taZWY3 zdgC$(c`yyO8-^hr@xre65)@yqM7#0jyy|_=VImAbOJff$8h%Fe_TPoY&7N>+8Ovf8 zih-W>9^&~v0o#f+ptm!V%6hgzN6<@L+?0m9!b-^4a*C}Y_V`!2AFfVm!i?Uaj1fM_OOeL4T#jO18aCxUADzZGF&(_yi z93cjl(qA}IfvsrxPYq1wp25uRE5VU51^W|XLD;E|EM%GQomJ1N))@o5tuqblf&{?u znJe6EWjlNf0KeIj`8%JjqYjx39N#S;=`+dcaLS;ZUYp#C8?KdOr>H$#|9l+7*8Cx6 zydYduZ9^`|E++BeM|jQ;qR7sR;`q|y0t8oh!bip}+^kcBS7W5%i-;E7kJ$qb8^R$Z zm_qam7slFN1ZU-jG3k5}o-I&AkuR6fY0?r}rIrPpC^m~W;1e~iU|9RfpBfMB1*`sJ zIF|Vbf@3{!y-P35iBiNj?T0aFz#CN0&c*%f4&&EPqU2EeNw6CK!0v6E(BW4yQD-?P zHCG)JirmEGoc#gXp%b`*hmz@5#wD!%F35kzH{-?sEkvO>DcHH79fP*~#!ET}apVDl z``if9I5!NR8(88d)$ppRQ9%RX`hiD#I3L*O5VCC4X8CX^c{tqwnu9-fi-)f53zWF08n`}bOjo9~` z!fvo-=h*nO-!U!m1q{57gYQ*2Kt#OZmDX+CGAIH1O)K!rtx{^UxCD%D`CwuYsOKq->o!&5)#C%W zWWFYm(Y1qrDo^2kMlNY&d=Zas4m4P>yqviYh&UPhB6nEUIa3}2K#J}(<| zss-8I-2vb6?ozk7Vv8#;`N34dTKE+6 z3|4gufe&N1tCj`B`u&wGzf}ejeJ3!>wik1p2I2O`QZ~fVBq#PX;NMLmFn7mF+W9Sl zv91nMNmX||x_&Mc3mOs8*Z)D1>_X-juco}W>`c@USa6wf8#;G}a*T&Rg2vB{Yyc6t^J%uAGSoNM!`uNW%`~~Q@a?KCDW4$7f8msmvn7SN z4`h1a*ryOI5IRUFugYQ_??5cBh=OmuahzRSrOE0$DU|ai8V+np!W;I;?#uRY%`z8) z^cr!rI+a%CN76ri&#C8>hqMMB!ufUw)VU)~8+Xq^g~}szrWC@zKkrbaxE>dl-iIw+ z>1;o=4YhBILg?e4cxoUF(xdBm%JuRfcg!C}k|%KOmsUcJ=~{?Snt_dyE65k$mk{F~ z3Q@L|_;E@ZK0cAoX`dYloBf7(Ge6%2zbD`ES6Kw4?yI~sHigryI%IP{!9zxuS~`b2I^3|ZXHg~n#7kdTT0Hm-GjsV7x8%b8(1P!il4HU zU~CZT1+tw6VVCM^`;1P~lQmknRM5`~a;b%PKVwktHPV7fI&9aqTc{M^J zj`+cE%M@qnH?XF%jb&*V`*gvOflh56!HUVl5a8d5PVYAYv5*DfwWq-JA;SU} z+rTRg9;zM^B%1$zgP@5&o?$MN79S^QZw){>n-QpsWY~`EY}|N0s)Wz^w0Z`Q~g~CmuoKSts;qZX7A~73Izyc}5-C`DEF` zBK&Pr0FT9`ct4{rq1**`7-=~}M|9h%l0*Pl*2J>s+k4np(?bQXRMPpXUAT8e2;5e! zq`f;!=+zh%ILLg9JA^DX23p+U1nWyQX;$NXu|`lNY4~h&4!WG)ihasy*nNqBko^Ok z{JjMRr?sI(SP5=ZI7yf|hkk#)fE-j`O8TU>;+||f^iUhqEG*3?+%p1P`+uIWPwhXF zrx65`6t5Af0YkiSI2C-&JF&ipdGB>A=$&wHe8QeXSt3_(s;VMQ@JxXGi(;fJXbPPj zIsrCL=;!>>UJq?5F7$*|2ukIAz$CUWIdx(XmR-35{t9Cd$K$|-PnSsZ0ZVLf&!j#4 zA(|zmOiaESlMlPh(foA?gf#?{#}Yk6M7|P~KjeXyjw@bXuZ7EZSA%QcAj&-tfo2xT zv*5LZ^(r5h8ScSru0i0pm!j8->ueX-3U;%SIWnJR`T1@saKAg9zLkl_Ea`lhGxaGx z+~$ByH#V`v9qU#7c!-~7Nvr&m6N#q z(ldDR?s~9Y{s=#o27rQdJ)Sw*tzm7eNX)bM(@LdQl5H~wWP<%M^;j}4HM*Ctr9Br8 zIi#YsZ5J^$G6F?A1(qu=h0Cea>3@3}%e1Qw!ZwTW4IBq>=&=S~zLZYQ!ee3O73Nzw z`~?%D>>=@oGVB~a2}0sExIOp^&1jg(x8BnO8+PTQUO+wV`<(y<`lrbyqg&{pEI`g2 z7U1?-1oG@wzvJB-eM>aEeW2n`33*DZ@Yv-!*b{voU2LO>jlnkX**FoEHyVOPz#*z; zIfq~uOV*=%>R>OeBYOh&r&a3a)g zcBJArjX+M*8%GXQk=~pCaT>~WQRjCaHV=D)a@1VV6S=smKsiZh(>Qhss2wT zP*j5OPI*C3~s}+FL3T60frZ>P=R}0iU6oKlH1}U`)TyFbX$RSXGC$&nG3I)}b^IyO&QMNL4_r zwin6s2&c+n&gc>w2+a!TVa4kNkaL{}C$}e}zGXFJbu%Z>^O=}x{fDDbcM~+G3i7*- zOY)`L#hDvVkjoQvr}gniP5i?&6K4vnZrKi4RBhaMt!pnAqox zKNeTQv$zV}ktqUU|8b?A5CH5}S&jPFKXqp`dj&No;Dnu-ZnGp7hw zz4pVaDS^Z#BoMzB-Nlj((Nn}_kKXavSSoQwjr9p!W0($^Bq zoqntY8>&WO#_d*^IGE1apF0tB_9NQf65wZ_Nx)yvfNpIYfs@BS;Dz!CqOQa8Us8Uw z`lWI{=Qul~o*g2GW?X>_axCjQKL+&wQ^ws?hLjlxpvoFiu1lsqoSYuO+)&RsOWRp@ zD?hn z{b@zDhqqz=4ikJ_v>m_ilVDt>#azCdJV&ElXyf0}2I{YzO^?rop$V;J$ zg(P?9A_0D0BJ*Z!Jcl0dzCfau8@%>Z;s5Ro#zy@>G`87-&l=W}*h{^{Slb_a%Gxk; zZZb?AW|?=4c>fsdN^6EO*l7v!ztoM;UHhhU z^AycF1FxoFluIM^V|ky{k6%GB${Q23LvXTcH0VzC#E&wv$Wi`_e69g!n%q-(V-pD7 zUusFN?HU|h7KFx~YFK=F9Wnai3fI-6;p~)GSawJgjlTSc1{GcyBKn4TWB=nNO0v6@ zULuCD4Dz@`1su?n#~BwE;P*?1QR#&Vj_hnD0hiy9fuzT{P%r^LH>hE+_$Rg(OUFZJ zST=Hw5^BW()q5KOCK8h%s`NdlwSEuidJ6MTd&T0gjw;t}M>h67mxo)L*%-L&2~Xl# zCi41yV8pVNCdr&*&RuP~&a@K+cF1F9Z6m4{*kjn}V|-##imq!*;Z~R;zb)7tc7=M; zBe$R8nrYinc4;5}rxrlHXGPJLcbUMC%!ZKoFU-X>2^SwagD!SEVdT*={*}}Zc+Nr{ z>&^(lvwgMjHO3EQ{tJWUj6Gf8`Vbq$ooGp3AFX(zh;csuQ2Hxl^j~M)h*U?tC2W7jK`I6lDNnzw^ zmotj~v%!-1GxYA^0nL-P-{6G%Oo+Vi3-Q*$D4VbeG#^#sblE(#_|*@N+ni9hp$3~b zy5cFWKb*UoNLG7TU?d4!h?%HfV*E5~NV zLEb7i=6IR256yK>k^(y|$c_qz#Z_In>eCOJ@VgNtJ%u3Fv>w`Bma6Y_5`c5&UU=uf z9Gp017{YCMc%pC`KWK|9KGy06=d}XB?E>`QvKq$rC8L0UFxHs2U}T3ZcZuLly!%&( zKR!B(JF_DYloDI%u>CJc9bm5|Oc?Dqw}Ad;#&;ddgW+;V5S^63x`M;JhQH0|_-_>u z)gb(_IPw$4u-|IoO$%?F5y&QXtd01k6 zkk&4~1Bth~Nu#6~zb5Dvc2-X0$2E?_$L0rMVxtFvrt3LnPoHuAjx8oaI>76mnE+zi zW^l)>4YE^a;;)yPEa!KD_LNF-g=-t&RM#l3i{-)V)g?Hk!y4}=JE6%8VZaN!@Z7D( zcqvjB6jr!suGR?y_4Vpdw|<1}GtWYaQwQo6o8frtZfrDUv$`@HnDWh-eiNL)Eo3u` zTc1*4>%-Y7R8@(g*Y1OLYCPRy@C&opJ@#gR7>=pvvKjAnqH=Honz;NU$;dh|gDW@%0$zvoMW5+~rQO_8rN?759 zt_ZfD{|l<@ES+2?2M22JgGaIqzigKn3YX|%70dT6+bYcc?w`Xl?y2m|ln+Z29I;*5 z34Hj``2Cm<6oGB%Cx zv@i>{&!5C6E>C$!Pk2(vS0Bhw2RoCf+=Nq|<77>J0lBxm4f9x*^Q8!Y-C-*Pm zoQ(!^$3_fDF$MGT-O$u`5{@O)Pk9ncen!}YQ>=jau@m12Ok z8VR6r^Aa5LK1h=Gl`w~E1&L@GfZw%hnAK>9VH%tGDzR16b*nGvXiP`*;c46<$q=y2 z76nU3cm4OQa+*x?|FF9K?fb8B6DB6P=#-8TX}E!+)!scvE`sz}BC) ziQtJ|JW*T@meU2e+gavt-)4PqX^h5QyA9wDJEu6!Pa=a;-C=vjb4Z+f73DP3VUE;e zlz34BArd)Qtk3pVRRPF(LIR9TcWY&|X**>mlc#HXM znltf$Tn9cp9m6qw??^H_SX9%_975li$5#ceidk@UiYC#m zC&w}2!WddzI1C;0#o+HBbGRTW#jRNHj$@&WjdSiQ{ACQ*wI(w`{r)%Rm2%;Te0IWf zN3Nk*xg8d2zCv~DJvr9;4Hcg(ZR zpm#xl4i&$KqlRJB^T=G@CiOzxgR^+t!1ZL;i@(@0@)=COUVujb_26~N9Xp3UfPl{q zG}uota0#1nXN-dAo-{c2#2eqFDDfi|=O9`((+!q0xJj|{xO{mdW-wO6fvFKF=pYZa z+C?zDeLl`Rs(@QJm*MG-oA6$84Vnn8BI+j6SW7 z=Ko%pVu$nBGne5hN0ff=50X=+@DHx7!>9}kjOn{ZufJJ{M)?JJMzjoLyq)0MwPKWT zum|Ibu^>LA3l8N{+|G{cxOx9p4%gfV1Es}5X>^!O9&}}F(v|!OZ-5e60}fXXHMM^6 z0q-qFp$Y*eYcU4rrET~wau~Y%yBQ-rjz)|s(M?I>oPov+)VEHh32$!@j@M%n;B^Sr zoD9P5`Wbw&llO2|!HR-iv53uQiDv3a4yrAALQG;r`AG};AVH_%1SvfT{#1y%ZhufI zCJQbpUBb&})?u)eDtITBfz-dnVErZ@`;~&p5?MYRlemX%QswwI;UliPm4KnvI^=;l zg*CzxxVxHr(D+0FYug&p2?VK$U*Ip)D@& zC~SWL=c_-$RjUfl;ID(6hCkIP*R>FiT>VBatN-LI*_29s_pQMg)^B-lauM8hIS_E{ z0SJnE!RUfGA|UgLjD0OZW9c`bxY`~ilf2>FxFmn`_&78sr(?3E3Q;}~0mAjnt;yya z$!Q0P@*LK&-yIBLlSH}E;{|Z|+-w}Me~Bu)FELiQ5w(mGClO*SGY}(93!9#Dbhj1b zm5a|9L&u4(eszQNTylU8_P2^UH<=rlIE8ytOn_fj*$KC5e#0TY6p>l*7{(U;;E=w} zy!(YRB-`)=3AacBDW|hExaAz_v3mpAJImlwk3ZVH3&Q&KWnih@gQ43d^4Fa(hTX4{ zz+m-q(3^V^(!Dkll}*#oe2N#&67__zJa5SU_Z{_3iovp74L&$uLf58j`pFCErNa5J zQs4njyxosC3xc5j#8x1(5j1miI*wvHXRXIe)Hy4}&(lhV*+F95l#CKg_=%f>`qp^oJ-VPDc_sne!^a%7e}5BPPRfb3Iu6 zr5Nkd3i0F%8UFi)j|*;fHK0Sqdz28m3sl_;L*>Nz=h$brt*8>ZHC|)j7Y)`+c!4J$ zWs&w-2DIH^59rk$p_+zMNzWluO!->~^UKpM;8Z2%V zgL^-hknz-HIC=Fv311aJ1Dmwa`b8pW|B%AwogvWM_Y|(oi(vP)F)9->3r8n=Q<}iR zcHu`jXxaih`TK~w#Ab+dX@$T5K1b}jIS5;7lls4B(GKl+QCCY~-H0@5A2B1>k2RrA zeH3aMNbm-}*YKidzriCfA|X9hk7H@VCybj2Glt4&~T+5AReyhpkUV`PU5ep)Tq;77pp-UeR9g_}&3K4R>MsnOLx4&+_;8y1|E?D;=+x zQ*E(8uwrxj0>Pblb8;n7h%ZD7-CeLeRRe36Z(v@qS;Uo74C22nI96_IP~GZJCVxJM z=iFrYr`e9a-$RjP{9A-Qu4~C&14qo(HRk=d;{F#b>d!Fb(J2CF_D=B32S_$}QLeQcx7d48?$cUI4*tWP~gQNmo^qP5i zqTeGGE5&ePfc5qQSo&EAvoy+-3W5($PmmwLXXl9q>k@jMHfQcQf=g^rLS@9o&353xhqU<8NcuLu_!z+QW@d zJ>eB}n3j=8adS~-ZWJ+kABLAVJ%9;YtguNe8+K1^LXD1es5|e7t!o6iBL@vR#ZRK} z4{OY9TOACJX#(Ir@{0(xo8bo6XCPQ90U@F$Xnm><;o}S3vEVgMJ^hu|2(095MJU48 z-bJMQVL6f0T|jp|FG6mZH){J?L9bc?UFzOL0Y7 z1`a(9f*H4Xu;%w8*rKqOJ8?<_$j@wosoghmNw^?aeu5mlKK25qoL+^4z2AAuUC)A9 z>k}~lnosYYW*KGu4RrsLcIHZLgB`wQq$tyZ^dDqiOO<@Oowp5UHaQ@dV~Qf_6po!f zNJ@qS;iALoRTxo2zRN_!IERB#5Y@r{JrX7y;J&E91TE6IF=gAzf+wF}r&+0?opeuZ7b3?^k7mn@0 zEYd5Wz`Yh~f)E=pHCp4KddGLzF8?gj;EQp>1I@+1?vP0_VL2@n9#s7$pln z;f@%4YC4TIyAOTaDlo3~G>Z5?)BJB{KPqL*6ThFU&@YtD9u(lT+d(fKA5Ou? zH$5?bQX-Z*d%-#qONK)!`P)1nqk|;4Hc2k9TB?^E(72Dem1{U5Ez2OU67YT4AW5-J z1u?t(VBgt@&iV7m{-HJK;-rknnF}kqE)~T~)?&@bF*tNgl;0E{$yxI@7Gmpa(afNR zUb~n?oKG?aY0C~!aEyWp@xt5^!@1}yD!?C&a)V)Z-sN8!g_XO%;861{@?nD@^~kKn zy&)xZRsK_$(e8o$?UMZF%qA?DQ3kW*zmT0;Ei}OY1PxGB#mm=>VM65?m6%gT8iv*a zTh7D4$xE<6t{KeRr@}X-G`elYbpD0E=`j7{bzb4ttR8Uy-YElY+L! zWGyW?YFhwz>#owB^3|x+I+1(*k_^gm+26F=p53E#I3F7ZsJc%-z4jp+c|0R%>ikK* z4n~ko@diZfi5CtWdj=LU&!J|94qlwK0(U27;rZ6(@KC52%@tB$^Q7mH{!5r&d2kjs zShP?{rBCQ&at1}1Ye~5$ijM21;IQ;u%?FOMe3zFKIYOTI!7F?vzPhAI1Kiev=*I3_>%sNvLK!OG4-6F1 zO4lqr{UDZvGqked=YK3q?xIetf}*i7 z^A3icWE__XQn*HQkd{e&rX_!rctz_3VE)wxIwjT{#n#C~`@+Le_2mVeQ{~}3F>!MC zQxtDc)ifNE5a#~UK^nNCg`O<;fQ;8t{Gg#_uyh&YQm!?`dRaS|rKJe(0<_VR@w>K& z`Qr)P9bb|-Hh0bvH+yZ2aw>!z z)l4vIdjSS7M(9qnT3iwOfJpT_|Uf!j=n5{g4{}a_OlGX^i8=8!F|4@YLySK%Se(REN~szMhEV)b9GYWRUCe*jR8{^ za9^@cOepz|Sq~$z?ScsGU$4#XyOQv2`hLv)-jAZ??^#abFP@f5hrP@TlX?9ChIO>k z*pxQtYuQ0kg+|GSBV~A?@d+-QBLH6pB4Czp2|N@zNTod9LtsuTq*aB2{i6m_Rr(F= z&EK-~bTjz$h-39NT`<{Gh^{jFSgEy)ckmb6k!XB^qN4TWS7HRLpQM9Nhl_E}$W`>{ zX#lvRN1_?);7(CBs= zJ@Z}}GcUb@H`|1{j$&zq3dK+h_Z|`|EDh$Rxv;7=9}Zph;N3jr4ucKD*A1V!ghSXgL@NVNPT)Qs^rW?fJ?7XL#qbT9r^Yx8Rm%YvmWk>=FrT^nm_J!kiptb?!v2O3=r+s5N0N`o(-+ZjH%pM8ttE=zzE%NGrJU`Yw9&)% zC#fztud#Sa6h3I4z<;pSo05%=2>1Yss3FLi~S5yng0z}{agY4x*@PZ(G(OPM&Z^I?Vx-4QGVcA#tL5Y17os_V46T4 zROe0w-PZGX`^LF|yz+!n(uBp&bnANzKQ5=>aRB zMdIL0=9@F{;Ry%L;mXV_E_loC!JqSeN!RGD*TQI1_jYt zWh<0KyWxU|$sBH5GKs01$qktwjQ0k1gQSEe?~1=1)K2@0ChhiE6~p`r5{zq{C&m}A zJqd#PSEWuBalY{qLAW|EoTtWe$UY)0 zbEtg}A4w0;keqn-?{ z`ST^%E{sKmQa?E1S_`r&h1hV71M3Ve*&Nk}Ga56IKXZl(3C(Rr$+`lb?}vV{%%LDF zupc{iyr(y3MuEJ_B);|1JY2@+@uxEb(J}QoGzZ?t)jNpVlN)sYEqet4W^EYprm;|ACt0Jkqfd|~$d_98{#q`Cs70vhSEnrOIf98Zk? zf2VLRz*)MvSjVF!+1gFEq)((M%54Ypwa1M%oaNf z%DH;vL*a8!3@L!OcFN!_+)Mn6f1i|2T&mx51)4;VeIpLpKBzk>mcaNpMdW znjC9|eOteRa)KbPT_nk^{n&w*jUwUBicWky>I75IH^M5r&ops17qcIy!(R;(UX^;w9YBoQfBdn8)U=wDU(5X-Vu}$m;_a;CZdm$ z7ZRye7?r#OH|)4UJ=Mb?_<#$MSCivsrR~JVO%-5q-x-I|rNHdq8$hX3ILS)_ljkVH zl#zJ6uB!uQeezJzGY%Z|T=3HZ0hsk^2EWrd7;fwRBbga9xshBO)S8yTGO2vr=imXJ zQ#$Y(zN72W4-8W0qRVYh2vROXz0c3!R&g9Kw+ZzAUWH*S6L=@A15X~eBd@pA;uz-< zEVw~okadqe(q{99k26>H=VUZDoy*m*7lynOVjL%yt0(y@VA`yc@OYIHd1TmtW9d`4 z5=|e7^QzY*(L{ppp5K6LmOO&Pvr};8=tMFhD;M**F*rdmAJ^HP!_ec7tdFHh`j@iL zpsO2ZYR$>>*OSJ4JNEyORgNE*#gK%jp|tKx1nwDN84+J)e$>UvM0C&l z64{cnS7k-WtWQ!#d+!u28Y(GmjeFjghW1dQq>@A-O;q;pe1Cs{$3xuCJ?H&?y`In8 zAo#+Xcs6@rw44}s^$J0pA>Rs)`aJxes0oJv6(S3Q@(^@TyQdUM%|xoDFwi z9ozTsZyyCI-FWnrwWESb)|~n5JhT$~%jTcVWh7I_-n{+rsm_SGz}R=iwhhFySDydf zUwnA8KBtJI`Dv7$F;lrW2A$!RHk*+MWsp@7)2W5bT)xC! zO;EHy2-3Qf`H44o^6Kox`SI>iV5m2y?=*7*)-SEbD@SW#xL1gqtI&Yb=5x4LtX?yI z=rL+=!3k~J{mJG;G48Nr7p;!lf*+|I@a!I=O8!kMYVU+c2ldHjy?o3po`)MfShrg! z4!%y2`oH9LjS{9PiNb6x1bqi9mgzGF6o@5a^x zPry4=94@NV6M;4n=(!O9Nr(bpLA-~L>^V*>TkKf^-)c76z zeRCA&xP{>y%Nn{&au&C-CkfR344`4f5%?-%1Z#v9xYhl0a6Tx1a5p_p<(%2&mR%;|EhO614sS*}Rsq^US{DgOLze@5Vk07Aa&$^;fKTt_wB) zT|qm0Ti9NqLn`~GF<0Aj+;g*mP9gj0^|Qa|?;ZE?eTfg7ooc|#nkYQo=nA_#hTv3E z0*-yyfdxO+VDR1*j>tJ{kZ?DHQkz9IcjX0Gy1xS^y1CI1`DZA9_!Z1e)q&&3YT%BY z0N=pm0t(NixOd_sY`LM$S-kxN`8zKi>@Ge>L-y8K9To+t-ech5Qv_cZi*SG5mf;OfBQlYnU-Abuo+lBZ=oqXG zKZ@;_gt(VQ?n1h}By34LL)*#%VES<%oOy`lnP!S|ubfO^`{?hGmy&?)tnYAL?h@7Z z=W_q1)nLoq5)fwZfimqCfVPWym-b}R^c(ZwvQZ%QyC%ea_0o=R%=N-=`Rsly?FNn~ z<*<%hjrTMunQL4H*K~zQphE-iL{d5K{%<)bKlCTErW0B2$DC?Jn~}TeMYQ$M0ubp6 zhGNZ6P&Cj-#w`cwr^j!AFebX&kwENT^@*JmRk-j4#rIYc+@i{1oUwkCcE#DiXR-Ns zdCD5pX{)A+w-RW$FmwHe)bcE~oS~w5CRg_AQh0w2;r3Hq2;B7(!&nD!XFfrdDK^Au z@IK~ncfpi?L+n*siMf4|`0GU!tUDu4uSd)UGuBUw$mPP1(VI~6cn>b&=a6j$jN6er z3)O6tpk>YxkTzoX`?a4~gVzna9!^A`Ls4LL?;ITQO2EU(ZTKgfx$_p5L6OQn8fh)X ze-;-4sZ$UaOUQB8GY{pa-ETqA<~-cbbRc=6C14!0LjS?BNnHFHjo)sH@Qc>O;LeKy z1x1S<;nxnGng}C$A=fJYnurR*n8Wt zp`8$o_awJ@14_3_!rO`d)Wt;$z1k-5KiG=G#It^+a~)PE!SRKU!Fs(L=bF1R9LrEf z37m==4_!bxN(9!49)iDS?c|jI1DvP&2&Nn!fTdG^p!j7zxkTR5rv*81<;)+LTeqHn ziZLpVn{5HD3HkVZh7w=Zt%mdVs4RD)WF=Vs8KZ|U{VTNJCCpc;qp&7rHK>eF?g6JnbH6J*mkp zeAEa%Zhh?U(+p3e82?IC8fLydiT2JjNuR_kuydTiU*%m&ITJcCYHk%QDNjZ*msrMo z9)PIJVRS;?Gu-`w`8W5wu)EP^{AJ7fBc%k|j!43p*u8Yoetma^#DHGJBo|$$FRG7d6JerxfaZLxpENj_lbYoUC$| zcXXv8_ALxXqbXwi#7kTlILSN$Km5=*Esq!cF`K-LK7po@2AF$t0hrYyJdHk&_hV~d z{=?}Q5nh4w4}GOlPG4befD^C5$sMJyadF%A54iNQ0~*x{)5-Hb;h_b7s486qzUyn~ z{q3%>>DFG4oSDff%>j4TgN4(18~%I4iS+ zT(m3Xgeon?jNPgvwZ02r;Q^R`crWhb4!||L7rdGG`=Pbh8!8+!@%>9xuFs2y$hMdu zc*z28Jw1%Y0bzxAggo_|$|v$8yaVwstH+d43G9?({jMZG$n}urR)4X^=-(E&ss10# z+$6yj;LN~-X6GQbwvj%a8;{D8#_&RYKb}1FSO3&l8CCxw0|DXdG0E^9wU%Cs#{Zn) zaCi+_r~Dnt)YFORAqkGq+Mjq!zNVnCs2StFeZ`?SUx{N*7Z@(}LyHTS>1wZBuw`#Y zi~nUSmc~QbwL1M`xP>nqvf!i0N)k0<%%8m6i}0Uyf>W?8Y%=`_GQS&8Cg25r8TkX( zU$>#NZWgAU(S#n`ZssHQfa=@(z@yX$obxE|e$z~L*95|u6H~dd3XSOA5K8R6^6~Dz zMQ~6m4VL_<0c|ZlJd<96va(}%$yfnBzwpo^{|Xu?{UGwcq-l%r9(eV)6qajA(ygs8 zA$}$Ehz-1lWVdNtuAVlA550s3ey+H`0`PBAAZ}q9I=e(SvhlVzZ5>Yqc&=99;p9Wc za?4=sh9~gdd&y$!Ian1K0%F$#I8ACZuzscmnW5WGwPf1R;Jyj2cG|F%ST&G=4Qm9sr$4yRg{Q<|MED`iU!MzCl-8leLzWvz z^}uX{ULNPNCs=**V_kx5x;QWh2F#xk1f~x%Q`U}^!QnVhCzW`AT*x`CRf%7>)#AYL63h${*YNWpVE;vTtW(GV`{fec%J(kNVfqYG z9HPDg%97lIM^vs z4%x3>a;#sozKt>A>ey*wujeRPFxwrDMCgFp8%N+jrZD%yTPW)7Mfcfk9=dxEUi!BY zGklz|q~`$YXFnw`HX5>f^$I$^CjvZIxkKTe35=&Ahu+uXNe{aPOkE_!9rr0itvM+; zxX>T!zqs?(sP~Y=rmta{Weqw<%;45$#Bqup4B*i3Qfm9=6tu-XhKtcD$987vSBdrPyfu0ry=^VtKb|{8dnl6Sdt~ ze{}&aSGj}rXMull(m~ugH42vZJSIi;aZt_Ju|}Qe@rzVE#CJ&0OQVTc!%&3^%16| z+4mJ$A@>5x4ZARU=~pmf{PUkKcdot84=VpC_2ixx8;aDe( zT#*VDDyz_JWhJI>66A|d(*h|ke`?t`3I-q8x%MR-PTn5&J;z?<_MRj_lo3RM$E@w{Rn zRP)VBD)eA^v>k_D#(g`i~rPQXF1KXXpL-&M-SaZ*TBd0%? z&CUX8t@;1Y)<3Rob_Z za}YG^Fv!js#N1P-uuOr{4BJ}Rv^fMHDa1qi>>1pRv4hf0h%C>%oJ0a z1qWbuDd3;-BY0hxy({*)!97gI?mK^A{_rYPLK+tMh?e?!+kUV=3bec^Y) z7*-lFPRO2XB+-Pz?6NKRFNF2ujLINee*`<;ZUvf}iAC?lXx@h$TxrAM${umTWs~IK ztuvAQ?>yK~s%7?!TVR|d$UzzAjb<*C;JKcVoTN!4 zUTi^Y{(Q2yRt9&`d?;eG(WdBP+>`E!?^~yE+hbPY2`yht-_s69_uRuU&EP`yJ2uD> z>LX`bTOsRj2G8NqY4Ts`cVcLCoR(kwMyK9shH0kXSSEiZWLgJ6#zax-E&qh*Rk=cx zLKv*XcVs^=6{E&%>0rm*!uxve5HzEj_grcc-=Uz0&TcG%!J~sPbx8(qt9K@xNj(T= zneV_JYu4FUR%5=lcyi)icuPKzPv~IQMD>%;#$3iWhmruFe=9SOwzJ<7{u(!{!p|CAh415%e`P@3GVgykY(y z@xfRyTrAEt>6*53(0`2HeR36KUIY}*{4Ic-Zwgqp>klq9Sw{wgD>(*}RmqH*5`4|M zAF+&OZQM^x0*UFlI2ybK9Dcjw{FE>V*7PL%9W~&cUq0TNk_T??Y!AKC1#JuYQ2b*n zCq~nc6SPj8yVLLz=mkY!{G@5zo!4tX?o0^j-Ojjgk@IPL=`_q3N#?m2`~%f|Q})@X zaA4m?c-L_gHe8nChR!np$9s41V)ZZxzw<(!`|3EuXN*&LE0p)b{4Gys`Wt-IA;Q1B zWj&5aHZIp|hZqjqXBRj^g;!y zIaP&si$j`*H@&h>8xw@*3&;zBstuQiB53adKwXP5frGn|@hw4zIivK<#K*+~ybnM-2nv0P`%64?E#;5+98s zyP?=wpHnFy!S_D;5Bwj=;j)TZ5RfIzcd#92a|j{yGkJ%NM3}D=RZm=(mayNAG|X>j z{o%TNBD7WpLT!sNM)3kWQ$K@AdIz;*z8u}`EX*pnOHl=QYrc%r>c3lIqg@qJ=Le)J z?+X~GOl1A{w{)RkBi$ys6%U?>$5&rv;gf+Jyq)fbMqV~BpLMVbk5J85|awlc58lI5`&G*tks((b~#N0Yc`|C~XS-1%62 z`3V}av;0SHE8f%^rqa>=FnyZ=p0a!dMs4%q(CP$z*M%}@I4g}VJQ;;Xl5u!uo;UpY zAjuVIF=caVMeGZkg1#3uVM^dj7-9UGbux@$!~cyELm|A^&&B!H6TiYK_j2O6coE)w z{0g2(c!HRqEy~!hL(8c{Jl{#ofWU&w}+a|#8<37WZrX#STvjt=1!tr0< zZZg4PDV_}|#+Lz+oIB^0fMX;>!VPO#E>x48eWHjn1u{_AoiRS^EXbylFY(#8NLX}u zBb?MQ4t6oqcPYv{_Sz9eXL3Cy$%!nDjt^dHxN$Oa`m zC!+!BhuvYnm>B=?mMNT=&oN+k&I~V>Nb%LVZ-|0<44e`iplYYG*j!E-H{6$mRV#vE zQ~5@Gp4b3;bX4SbkC~if3?efY!}@$!2M+r!(0J5*cgGFhm;G*1pDa>**Mkcm)kt=s?nohRElALztK&qpc*UIy?k`&QBFd8Ry+dx58KOTELO7`*FK*L-Y zm&{be!Ijde@shp2Ba$)fKmh2+ambudF+92X9$a=D#6j&?yf;6Le*KaH=ho)J@qkO1 zbL27Ae$t3<`L~(d_yLdwb#U)@6lwMn=l`1)fL3Qi;QMk3{;xd7XgF~e?=07(8<_9q zopqajO#3tReH+hN9V*PdCZfwYU_Nkvw;`!6n+J~r*txNmIk$wXQH%A%Go|C`j-*hs z<2uVj{qdore_vA2Eke=B68wm$cX*Q*1AUuSXg52jaX;*^wymYa$i6&E{$nS6I_O z7=M~QL1ozh7+!k@8+&SqPoXFHzTu-?jvoDHq5{hN$kC*hV=rf5I@=kr}Yrt z>mVF#mtptc4AhV}gt!aE)aAry{M)AvCbhowiA6V^X0nQ!`?7A~q3ihgls*ku`HS9~ z>5nHFJ?|ZZF!K4UW%2|v>H*0vtZ0E0GC`pXnpHt(ae5`5l)ZgFuiOh3+icfD1P>tGB zP&t%De-1W+gv@!EnY$4W3Iu|z&0+jL%>)%Dw^83^NnoNV#SII51U`)GHBI~jW*7)_ zGyV&J<#bwhzLzo5JWhDG_cYG%%OdCpyzT8}I*|1TMv=@dTUUg#OUMZi{f# zJ=F{cuIR(&a>fL=t79G>QCLtn1(!P8qc&fNTfkz`|HZgbX*PSzwoeA#=|yniwoQ!)khv)J3X1Bt+6Ki=*>u%ys7jeE~0-q-C^)5V7?@P8NUBvI_ zv|#mtbo?(ag5$KR6i?hY#)8lWyr$`o(^yW%p)(jwqSdJFG((jG4mtwiTE z9awn&KE6`gM;z9SamvEA;jp4JET3}=y^gJiWrb`fCT@V|-#*1Z3eL1)a|Vi;Wbzhv zj06APX4rqSo;PMUgK8aZ!XND4e1+RTntb;uiL=ne{fnls_e}yEa}?wsTg!uUM+Z5d z$uaCsKTM>;5@63==1uw0gQ7P+g4yn~u-22Y1x#GvujVm&$gGc8uF0qMrv&)wsuf^w z_8EVMm9i|6CL9i)jrp0Wuz%MeeX=BsPJ1#B4J+3mM?e8$q&#Vj;ymD=%SL|9E{uHN zgLkCD@Ym}ea=zdx&bwHOFAOtaZ<{mzW*Kn}cL9_-9tCIC<&)k`b);HuE_AMqz>}*& zc`X|c;e)I;m?n1}MiNiqw&cyY@OumANo@rV zU&+u1q62@Cj?OIjQPl>PYj4xnm7g#uqmmrpiESaF|{+p2q^QP~7ijN_sFwjj4kh?11&7t!cR5dID>f!GD?XRnweCrta;-2%%kL&4u>#20e$bV=8C6pz@`KDD zGN#U2jLMpTnhksOb9{H;_o6MBA0rNDjpa}}I2|m%dSPBg4Bk2UmsCkLV1{5k-MhJ- z&V6r==Ld7pb9NNgfBXddepA!}=45t|`yt(>LB~n-^;Dqsy z!|{U34qmBe6SiNQj%Qh)W&+E|h>4m&SEB^qB8h`eg1u<+TadeBRWs(AS>bOdAI9Nu z2m9Dq99rrI7f*PT(cWxqdbAYX#@3T8y>I01ifi;Pj)0nMG5EDQll0jsjEC(+XYV-y z0xS!)c5wvezhXX?JrBUZ!V(TFHKCJ^vkc5HS@KDspVzro5o;D-z_N}Cy!m1jwjI6) z*X>S#&*?Zg=c1v;8x6Sy12lSzN~x&4Wog$;m<^3S^u5B zjb6l=*N4>V{4>~_YYWH!dB7^&M({Y7f_8gT=7WSz z${ITu)DY%Vv14GmPnhfXB#F1;ryc8k7~#uv>%i9eCXDT>Ap381kPE7}aFnraboV@= z-*=n?Qv+pqSvLZ~28@yTHV3RG=0kP+O-x;M75;n^;hUv8l3ceK^1Z5^7rdtf40>*% z&xZg=e_#$GQ-;AOT85esQ;5@ki*a)vkeqS$Hg~@W4oc6U?&KlxpB;b-@7588#flel35HJICd3tJtB zV2;5S^!Zl}!M4?qo;nZDZqx+b7t_F@ip?88w}QYSw*M)(jpv6>;Dgh0j1Tz$C;C-G z-yoOQQIi3_&Fir4G4m5IcmaJKZlrWz7@a#z;gQW0zJb0leDU zIux!peh&t{6Zs7Vq41KGl(e?Aq0wJaZYQSF<%KF>wAqQazY0PbM6g|Rh1`8m0)a2< z3lkgmV@UrXH8QWk7u(N(n8_O$HR?dgbN%o}M+f&SdEt7OdmQq`8Y*Wt!!GM)&imtL z^oa8oG+es^b<6jFK-Mhw`SgMV0?80EDHS)JFQm<8W9ToTiyLBAL7mrQy5h7itWrEj z%PWh?LF-HS{BSe`v;6o=(QtUT2*G)EE!Z)>kwMQR6!_7FYL7pWgRg|RM!HpKXgm(h zDc{j)=1dGp2!`}Z8KR|=i8aY9>DGuVkh*Rk%oZ2nN50br2l+q@;EmFNSB)re&zw&E zw2f2xQx~S%pG3vEZAj{W)7%-iAdsB}Q&d;tvC>K~%-VrlE?kH0ck0k%XaqJqAK--U zkl?x-%%hr*1TpcGC_f;Nk=nCgl6AZ<^i0TQw85| z%X5Q5Jiu}NN3?N|BFl?%U~alKl+IiRgR&Ht?u^IPpTxL9o&R8xz!1tVxP`7ugUPRi z9Egg341eY=BP)_G!`fsUXtWL{`E9b?wCzvPulXv=K={FO_a%_LKLcbX*Pt9KCofit2j6-atAlF6ZaQ@rx zLAWMV6`~D?X*SFA$MYm{&WC=@$Oc9A+u=u+0N=RdAQZ1n z2f2jRq$%efb`*`Gc8et6V@(FQi{3&}#tp9TIDrKh3*mv27pU%v$BpaV(Y3Ub9LiT( z*{?2z=bnl4qqp``xq+Ev(Zx|RzIllJ9vowC3MrI1@r76|`oy?y74UX_21(Rp-4%Hk zFqk}!=g;WET0Yxzl-|G-fxBSrP!ju$xxd1bFl6Ye>(0eca3B#*EIETK z>R+PdHZ5=u5JlBKil-wrP~e#Y>sEGdtMNIQ znREnRz6LJ&YlCt>F4N_5f_&d+YCuvdu`n)}#4eJ-bIu1qab`Z8pWj8_(E_UJUyl-v z=kd(*L99I(MHS1Y^5y3Wg8HpjoWDLTxMwfm+9m&CZk#d>TkzmCKLu(Qx#JW02ynKO zWp~#&v|9BN2Y!k24-0xj%b^JP_kM&7`c5WsSA|ijSqK-)*8(>CK!2(i7H;lhUP@;S z>eAx8(so9v(6_MeJnOklZ${Hg@5uM$$26%Rmu~g;g@aD=RB3oInDqPcv{#McrY|fL zW^D!H{I7W6j0;|$cNtn`d#SBl6KuOpv3ph{X-#Z}r($04G2$Nl&cBZr3+*vXWCqSZ zti*92*hNGPY9O;%gu9&WPo!65!htE5;r$CP=&(M*%?5dp$PXc1=AW2*RED4T?h6#} z>_OjLS*~YEA{-RlkB3P)<7c{{`onjm=yxlqvCfQAr4;`6=`r*-?Sh4m6X9*#AjIDb z1Oe4VjAwH@tme31^X9m5CNC1{~`np{bq#8vWY$3(MI=-zr89;Pq1MA3df)`!2cJ5;iCyGN6 zu~dKGO}gp#FFd1c1WyKUqvOL7D&5zB{8N+o{hn#)XuA=!`x>$IQ87$-t_B$@?wB(C zR{wfsCi+Ir<|_EclgRCR&|?C2XhR5mM!&fS`b0{uoTZ?O)V3SDt$lqS9z38d@0C`jsV&R3ovfJV&C zVjdMhHZOAp-!lzhv-dLgzJ3jw?&(A*#21{isyKp+Jiw6qgf^#|qR-8xXpr;_f*4$m@t@x0e6_^ z!|x7za~qTEyPP=pcFlq{_lt=~aDh)F_*>UdLEa`**l7%}`^C9xsRNvlvr_zj zE@?2hh&ckcKZZqvPK+HtjpH_Q0&h=e-vQ@5IieDUU@bmCoW-|e-SuhQkzm$m+u93M z>LIa=ZzP|O3G_pvQH}iOAasB?&TEyYDVKyuF3D(hh>< za4+wJ^HhF~@M83ktimmyPT{ilHK@9uF*JNu;qHca;5uIe`v1r4m-mA)LsxV;SO|}` zd_Wm9ptQ0L=dye9)#=|?EUAglSLa5u9KGPfTuW+t&J*|e#Ny%G3TUvp znaoIR$B7S^XDLk$48;;qaz+JtyEz5#bva}IJ28H+axG3S_k(A%0?~L!JY%*>a*KxE z(awhgeADw^;MK<#o<(9aZZ+tjHO?Do=p{k4JXwxe!d~>pk!14lU@$&C-UHsV0?7iw z7i1&9pY_Cop!tUjJYOWoUlKN%+xluJL=4LV?@%{R&ku#LMIzjGo(!b7s6yQGL8?2c z8QtZ6Q`P(tvhwO@u=LWQbH)mwOCc5NPTz%v<%zKQVi_)u45HsN7C~2WCyIP*#D3cY z_~Bg!xxF)n%G~~jG%p&Dr@!WfGX~Bs9TDQUvX^eEY6R}5I6OBc2t)S@l9uBN@VfK| zm`VJ@Vy{{hf76DcxfT!=m;?FW#~`<;3eD!*!`aI^ShPX}U`U4lJF9`J_}pVNL4ZxG zi(q1t2;bO#04r19lk`F@Soq8kUJa$gX+>|=Me4-wdgGVg0t17x{1!Ie&R z=H?s1^3EuDQsBo?Jn91=zYEKs1c0}w3LLIJj~YJTQE2;AUeWo#@aRV=)@(25ZMtlN zg9aBtW5#)?IV8nZs?>$l1#G9scsKNn0D7~tN^O5F)m!$MbSE%IjHU!muOA^stf47$DlW%iMEw)gZ|S$;rE9GP>TA3RZY&IxH1Vg*6G2+*ln;iVmnmdx&G4ogj#gR1ZWHJLx+5EDwpDhlAbSc!2)+I z@9u;*Dx2`3O8|!WuLRC2Wxi)jD-2!>!w?hZYz-Slg*J*FO4YoTyL@SVNHx0f*_~mY z8hpC;8b5!DBli{v@x{81!Y?NqY!CHD&gqw+_$-z9l)GDzm@lGn5MkQLLqP=1FKtob*a@(e6-Pq!Wv zhK0l0H)HV2kMR+@rt(E=C>UP-Or5NH^=*}|VaUe~;O4o3WnV?P&PRekY1<#(1BcH< z?5z($e7rAHh7oa+RxDmo1E?#X#D=YAQq3MS#~>g(v5=|SKR z+Y`)rjpr?Ipwp#zT&!w~$-V|yBFR{y+Ewtxk^P>_yd(AgE*MGN!EA`-N~DZ&qE!@a zu%FBK($gTe-G=!4?L{K6khrW9d2QNUM&N6_rQ z4J1-)1DU*EfIoZS4*Gn44)QsXXt|>gbVF`4{xNeOhVozsX9!a{E1_Px6kEPd#DP5x zu*u{AIptnP!z1jmbyf`2?Y;{o24Z+tR}c%0%CL%K$KgAPbHC@PV#=FO zHoZknrd@#(PaSCH5oO%C?^-}`+=D~&XO1QDF32o)$@S?IK8W06=-0T6ei}X>b!xzuWb>q{y zBHYn{0uV_lhuUTBcx}`Oj||3PZOM0tvJ>E{gv}+M7mF~}eiSd|6w%|~hf&ukkWMm`@M{r}<|9;`CsiyDfo@i&_~XlVy6fOANK5`fzE1MTg*%VYW9t!)?k|I>=NKoaig`t6*2087M|$K_ z5bB5AqKew={t>kq)9tPnc7;sEl5BHyc_jcpT_504GZheg{g8O}RDfz-75eZxK>grv z_;XO5%R9w7UM;u4@BT1W9b}G*fya2aI0gce9`p3yJtyTQ9yDN;Ee4G|K%ww49Cm6( zmCgj{n!J?1$LKs*GFFbz%b6%NdKfIt_!x6q1x+RSXceA}?h<13+o?Y234Vef+X}H$ zEE%ffqd+<748B&I%%3D24r#W&F!^E}S)b~vG`z1M_$VtvS-XUf$0 z`T)c$;(o73qr$7C zCx0c5ElY+p$-iK){}ywvy@#^5%@F0d17j_>p|OSyt#Kct=hpRs`?vsiPH`#TyqAJQ z6F;H3tQPUTeT}ZZS_dDrXK`D4Q-RZ=imTQSk}LZs5b|xf@Iogb{*mGO2{mFGbD=7) zk-^A=65RF7VR4{W7zW;p<9T5(k`@(7LvIRFiGfSdI$IT_zwjYtb}&?IprE8O4!ngG zh|RM=d`l#Iqm{$v!I-4z4!vQrL^&XvGrhWDC&1KM z^=P~&gml~Wa}0JDWA2jzSf2il&G;{2wC)+QH7*i!l{>*Gup8DjwPNtY9ynb%jHjg( zA-8Nd`C%;#nnj<%)uaK}v^_u~dI!Ctm0((60XY%$7TQm|B}tb(@P3p!I-Y1}PJ>Zg z*!&rqo?e8TPn_`MLAFEbK1?U8M&X|o);M54jc-t9g>eBV=tSFFycK%O=%LyBp*BAe z^%~^q-5fR4*%}HkV#CRr<%JiVav@CD2M&xn!`8!3F@LO@79MORJq0tV$lJddc}kRX z<3KGQl~98Jj_BaLcW#hj+=ZRWrKF#X~$xaD@J(>H;jXNwk}6auL^%= ztI)3>+z}KK&{1hE&WrHJUy(uhGfmN>O0>W*#|^Qlsx5Zc66vbVAO892{pXmjh!Rkg)AE=5@V*@$(&Ma(OYfv`uuyFuKw`N0ikRRyly~X=I7cq?c zAB|q63jM#Gut9GCrsw<9c{iqU?;WkBtA*Wp{t}E&aZ`r7Bj!72cAi%O{^4M(SZN`- zHVPLd#lXwp6g_v8ajUmlft^kz)vjW!;P>M+y08oGfhhKUdrsz*Z-be(U8uFb5Z6iU z<5?~7VS5o(7&sROe^v)0iOJ&4*>)9lL7BgyZW+FLtci<@Yti*R5AAo^v9pAAZ;kZe zve+6doWB>DQyC^78Uf48v-n2L>-r>gh}cYA0hL?D`P*kdCkg3&M2NAVEEuPDG<64t zY&rp^NiMi|s2Xw=Ye=V@6H3LqQ1xsbHlLQki}xQAb&*;81jY*yTyz#wwb^;9@Di1S z9>Unelgw`dkZ^4yxEiHHbC@3{N)+I>v$G(^MTjf&LKi+vxrK)!4#1XZIb7HD3KbMp zajLKuHpsd_@_+S(E&JQ(HdM_;75-1AO+rg!4qC9u05! zL(;ZT+ICHqeAIQ~+)?U8M+*}Fm7|#@ z^MTa1^VZ)v!doC|5AjAGxbB`a5&Jxa`6{>Jdz)(g6UWM+$I%(;UX;LzHTw%(?je=W zngjFHN6CuCb!6+obx?MC2&VTB!}OQyQM1&q@JgvSbHJoh-y5FT)O9FORy#yuQ0eCi}o#U=DpU$ahMms6yCt8$C`=3gZwb+cejuhhW zICHu|?-`lj?+2|9vLJ2uP2Q(lI}2w=KZ2eAuHmKGtFSL67o$xQsQSA39O>XjIP$Fm z1Se-h>&<)^sPtx>1P=Ty+C#(=KGKfKpWtz{Guli(1Ivd3@ZG9MkTug4K5&!3bM!o= zR!I=B(3;Ne=>UJ>0Ia=xjlQlG;x=pYVC$i|V00iE*v**NziA>`*t~_Z$=zu2y#Qb6 z<%7j(A6OboF?tmrGs{`Gl>dt=X~(imyFBtMp2Ju1gOFyBh;#B2psdaplnx@Aue}ek zRj0|$QD0Ow4#pH0MF@5Xrs@CHz^mKK=#3=Q7xfMSd)->fu@{Df?h10w*O;u%OQ#tM zLfo`{Hn`Zujm#7mqgVdb(wvqVbcu5zsi+YqrGhKLbKHY=|IQ<|7Gh*KyRRzSO~oBA zLi80u7>HsR++4H)RoH8GFl+;f4*QIne&g^UJ+|PXbU6)vT0u5Wb0_Z|w&9lr-6Ya9 z2ZW}4#Z607!J%CaE{fT~g-hjl@W)QNdZZCGwvW)_!4PVbvzK&d6hfld6}-Xa5yKl| z_&J2#Z^w3k`G$=UaW4!?XLQr3S1tHo3}d|6%)s>K2;Rk=BWU@=0T%`V!pzU))P_*x z?OufQKRjbB^LEHm7UQ3*GY9z_i6CfQL!K)Q!G;wSt4ScKT_nI=%^O9LZ)x~e_7g?% zHn^fa0O6mK$mEP>! zxZfZTKfcO^jKZ&|(WOV#lN{*KI%_+u6j!Rj60!m#(YR|ri0XKN+GS5%FrWoX7Qd#oaS`R-sR%dvU7&F- zy)a|ra@=C(fLnKQLBFMn?ozuAJN=en-1K4^uXh#h{{0KbrxARWDaHM5t3U^M_i(ml z5hhL-)hAT zk~E}J+NF}xq@*Ey-`_vr{Bj=ebKduTU9Z>kDX8TKWbz%>|8{3R9Th_n{vUM(@h+rsgBW@m+%{Nq?d4oS;hiIY?SqlH|fv;O_WHV}$`0yN>@q-P5&`|%RzaHQB5OsE_1%x zs;UY-VHxl|B7j_~jv;?9TK2c70` zp#zVOvzqOHpa$PZ#%1QsedyHW{-{5(w5oT@R z<)%MxBkG0cqLx&g@`HbcfAE}> z6xs1X6R+zkXuf)xPA?9};hVnqkaK$m2}?bX5(cIa_%RhNZGYid%SrNjNeDQ^GFf2V zuYi@QH^TSZj>Ei2=JF-C z03I^zuz#Z7bYryu$!mBF8?JW{Z$CTuD&#<`m4Z=uzyeUZfqp&Ui6=-tN@+)eI0$g1 zhTk*$w|01~<3qEpqv68Db5d{bi{o>j5v3QI@W&$)FLn{M<8MWoa$g(_*pDBW4CV5o zW4KK?2PE#7piU99uXc$6|8vo(&tFJap0r}}sgBH^)|%M|tD&BW3+6=agwADhP_*|g z!%`-=#;K1+W)89}Jfg_+&_bG`d=5>opQXM%`V3db893z)aP{XFDm#=we^04tzA~wU zN4Acf$Z=t^;HL%2THmF)%&!R-B_x7)sR(Y1sX!5f1`^u87d&G3f^j>C?qtpxCc7-) zYkezTDs#q$z;}>TW=A%iUW-Gu3{TdTVKnuclK~YEFwAhp9X`cy#&A2mT$n|@j;b^B z0uPqrMG^K2Aybs~`GX#p__)Nn#W17jtEQT3!ZTD;-oidx-4-tr{WOWcI! z#r1Gu>l@9Ezp<#``-?7!`Nr9G<^rw|;GmIJGjsQI&VB2bfHFO<7#rC_n)P%@*A*$Y zip3jvID0uKTY?8Ok2V8!@!~v)yNNTd=0e<+OEk?l5mj%DqWpLT)|lL&w{_2gzQcVq zKIje&QWNMl{fS`|Gb~YSb7XJW2(Hb=C@D9I(gvCI*s`T`dru*Gx9Av%n4ZT6?gzji zm|-(DR+5^sdi30A4%V(aU`W9VwBudT>Si$hdk{*jUQS@*%`(U?WRs*sGf=rygnc@# z_}xSmPq@mX`;3Jsh)vLD5&`SZ>7EKPESzsE{YK=&rf zUP>m<`G3*#_FZ^jS00+qS&sfpM{0Fm8cN!|pcyYr$c0E5uHC1P(3@47D^%_QrTKqI zv1lD;{(eJ+Z%|x6_L2@o`NIxdrVlrwhmPu#^nI)guFZ?bI`LrgwC^$FrfZ^{e?bsy zo{BSqOUeBk#_~*`VEo!J9gn?jwA8qNrLke z{M?JKB5c#6qHMksKjHkJGEAKM2^U;WL7o0T7)tELJ=vGRG%5$x)E~ppt3i0300}a`wE*|U zM3UIH47$&d>4Sa$fvKx9h*B9s@2zM^=*gq2&OIgm2?tm?-yxW+5syn!$ACz3r)Tj$7;?!!eVtIbSCwa zr=Q=zg7gUV)6YQl1|N+qf95lSzPKlG0(w?687(_w5ccK(SIi0`7QM#vTHb_rh9~Ji zGmkt~7G)myT7Y=aJZHOhd?mLcsDuGL*5j4QN5fwMsfVG}84Db35Ri^3ae&YttA9sZHDIPGe zC4xR!wjcWD%>8ON}6*l;#ubF1=Ov14H zSAZkSoHhHMq3QZ{I>&Jcc{oF`LQstT?b`$mKIV-dT1l}uT=EXcV^mbD!b1$tKrdyRE+CQ|Syzwe9PWceZvOG!Nr@|T5RXlWr-pK*e%zj(N(EgMldAp;$l_u`3JerRv|8`oGq z#I#Ku;Nul$$3}+1L@_gyQooL8w@>G`Z7?KKp1z!j)f9H>oFpHgn1We~CpIr*!JQo$ z*e=+B&CIT^S@{V)adwDtSyV%WcsZoAWnhIuF3#FAhT451Tzd2Z5eq&H%12lzCHWVw z@DOPD7=W3Uag6(u9|Y^;IKAmzut(ki&a6{`C#Llvw^EMQhTFi7PkLC%WWPGZwv(bp zLv%b-uF>cdhW~H|C_XQt9{JT&?Q{biXxM{^cl{v9x(*EolF%kU0OD56gF5$@_~Hnm z#h?bgx-t05e+(u1bm18PD0;1`fmi8OP;p&~-EyJ_wkcUt)?ZzSo@>RLh1>A&&wXG! zegGeg0L=3V#;wZkted>^$dWKSC{;g&Hcp#RxjF-Qm3F|?rR^~CZ5cR6Nm1n&*J1n2 zE;7xy*pNa0+!Db6DkLPAs) zkos&d{JFdhdOzEd*^8FI$^}e*x%&mvyHg~5`mJ!_cqtxs`GqAm=RxoWg4C5_Fs^)x z^6Ia_`9>>zk6%ES2mV4mCW|fASJ03O`s*5WZ=cq|Fb4hs@P3DD^c; zFf*3XyA$xXr5+bL9D|7|A-uEB8xs_~$m7&FoO|C_(>lftQf;lfJ2i=f0ng+!> z&oHjwHkCEshzc#6Kw*_BO`p7iIcDbApHmHn^8CPCCI|1F{-T@COIo`B5#}nn!;*H! z$@P-qa8>Nb{J%%x;S6iob;X7A`&KsD@jMn?bnjz_Nj7KB&@;U2T7&^|d+_jPCewfF z3m%GehMyI#I9^@^PxIZV;n(+AY2Sb*BX+n0s<^)$ zW9Lrd%#TJmW05i{eNKb_1er5T;W5;n#lsa*5QmR$isY7@6&U}Q4O`xXqSmG*xW5uv zhn1F-fB%_7*PajXUF`$Z%nQZYu4bSarJnm@M;oN9*a}jPNywM`5xW1D(|^jd*`j^+ zWJAdXNC?Qq`GUu&6iXfIbr|laP7u*rc@MuCRN*G$Ww<6}AvKv11-9Q92cu&y)n=8l z9F-g3Ykoiem05%Vqv6=Jvl-M%z2NS89`^bNCool^0TwJVq??!7;FGFTcv(|!o>&Pip0q}}>u+&Mm;p#dKW4d4U4ulXyJ>FT&DvTTL=QKtXYRvF zaP<%iM}6EN{EH?04wmJn+JC}x4ENx^SFNIQSFA|l9AjKnk^v3}8RxqQ3xpu7v_8qSk8jb{GTwsG_Z$T^{!YI{~P#iGe9Lf3j?P>NAYt% zI9?{{hM~CK+!?du^1$_=1)Sly;Y6$-p8q97nr3LyJBBjo@ydjboYlc)Uz*|U8Wmi9 zvzQesx(v#_t6`lLYc}OF+_(m+QMZ7}sR$z|#XCam)2& zW_Mf-fx;Vz`D|@4c?j^xaS(!5JcV?f9#%kF6H2!J!?E2%D8|1F&pvg)4Lx=cWZ;9G z$L(a`6jwxmON)=oTHJ(~suI$(BAJ;W_-h9??@XzTt7-#&05wQtJcqM$zJKmS9W z8k^B$K`4~TO5@3sGFWNy0t>`W(b|4vIC4@J^X1m!ET3EOZ&weD-wr1R*KMhk_6=&U zHw-(YmU7;W_~JXJtFPL>97`W;U>KTA_REKdyY7c6bZ}!xqArD^a$fe#rN!|2r6`kG zXofd?8i`f1IW79;1AZr$QqQI=Y9V5XgQ{bAa7R7H?>UK~t+U7j(q=fK{B+jD%m#Zt}W*bgh;H_Z}WtEgHv>IvmLvDh-9kgBQrG z)iHRqMug1B_s1;$2-v-sc^9w$PGa|+M!}_fK#E$BW9$sPDKV4vU6hCqE=waBgNY z_0|)^NgFRrl?S|KB#U+eFJWuiV!HoMFI=DajP1sL*w)(y?DB7P%Z0Nz|3@~~y4ImT zcEF%n1$Hm3!fZdr2NRS5Uhkq%=qbU=HRdSWoyp1h;Q)G0Jlw0T?YPoHoIPQg3RRn! z_s7F(Jf!g+)D)FzoOp~zmZ2b=+7{)Ms&;NuVaDNNgnGuh{=iT6zgCaVUdQ$!N6TyQ747@YACmRW2emya-vMJDg=^stfi{CR|vb7H88 zzb@@s?!nn5GYga&zA$%&1{CG5qV&!obiOqYZ~kMlfr0B`cTG02QGAW_<}$v`!_4nq z+Z|%1l5nNWcO0~4oVq^**c;_|xL-rZ8EskvSndyiWlkG$>9RyH;?d+-n)ie3(_^?P zY7vz446zpRC1SPx5G+tY+;BOO^+)U<*cX4n6pvbbf42t0#E*k#;tcRT_8y9)XR==0 z`@-=#`<-zc%z+(|jbQlqH0^wAgoWiV@tyuUoECP&U5^VfUEPjUabJndV zGZaHtG&4DcdMp>T(wYM&y_~7ZgedSmz6FD10X6i`&y*p@)z<=(g~4PwLp9 z%6l6;9z{XJ>ZNpNzvAJQQxVE?N9iX5XIbQr{J5vKU6k!;U*1l_%FqmTv1{ZhcI8T2p?u<9P@C;{?oAU zog5lIyF_M8Y=zg2=_owR#cz5JWV1~qJiPxH=QyvX+x`You22n)7L9|w}Nvy$OV zRRMfFt^hJc(x^L=`Ci+4$(NB~j`P7PWFn3n4WnkJGd+N3j&)(>CT;YwH7Cn6mlKZj zU6$L!Rn&gF7k<`xjbYcG;xm&E)IYj0^j-AGDA9H1q7 zE~|wE;MXd~nfY`UlRL|U$FG@lRdIpl^;8M;i2X_w+azhY-Vp3}D1-gO@|eLmtJ;s$ zF%G5-aETqu*?mkF7GK{)rlPLmf5)Zq&1)`d7(_r}qz?cm&DILL+atgv=mQBK%%hdH3{U2@AIkd=;~5uKx~=~`dHXF049xC;m{vLb zQ`!aD>ssJMY$#2?8w1)tM@ZC$Krl~{{442Uu>Y;1%}|zLHYB{X3O-J?G{Ayjlkm3;cl2vcb+JLYmft*Py>* zEiuw8hUd5ElSOT+psMl;3(e|LbKhc6-y#QoEM|WYN=e{aE&SIU#L`)wh0~RVAk8wT zhs`B0aMTY!YF%U5$m*e&b`TM`*@9=?j^mp3u6QwG9uBxyq5Ehyv<9i+&~Xv2Qb7XF z-F+OQ7zS|W*h>(U3j?)VqLkk?2cc*s>MhE_1G^VtNklnG;4!Diq=zx~v_Cv!&X;Ft zD3#Q!hr&(IS;GvEvNm#pKK~dChcaApN3Hp|pX^L&?A<3AczPzPy3R)LiB4!@2p}eI zFLE^lRuP{ok3nH?AB4#Bu#;Zuqxt3lGIg25@}H_8-%^W7)A}x$<-*3njn1_7HXlB# zS_Tp#Qdp4q0eP!qY3KJ=DB=o$y!$Qm3^OMmkC-z>q#*pW-+^I^Ye9c4)8%q%gv7)` z^e|@bMGBoT!n`ZS9{{p>Zf1B*zNT^g|d7EaBxIoL-7I>Ym}X?p}`eN^zLE{vGyg2_@F{N}P`Y zx4=F#f|facMz*>=?O4fhXc85v`6I>=>=KEcn#uD<_|o>s13nXtB(@ytlzXPU@iI!L}9$&T8KOqhb1zv zan%V6*s!u456ifL(;=oC{g>icKpY)nSPLWHW6?Ay3V-jcgv`}HiN$|2*q51e#e`@A zs+^m^I36x|inc?u(po5v5~pqFywOLs3isE(fW}o{2#-DwJKur_t}`>7Rgs?|%Bu#g z6}I4=fKggmD1a$HL(z5o4{E!(ppE1YG8HfmA02{dzw$whkbj<=;m(VPt_X13wBqrb z;!jN2b(3xkTTb2ktl_+m82fR=Zr0=a3^)`P1wNNMAkCnhK4|raz`bfLcYelo*DMHD z8t&-Zt%5vXnDe^-PqMXT1*l!kz%DFAopoHySr89r1sa$+-YfJu=?W3^FJMZ6Ae)X} zfV+{^(Cv{<7F{farz2XhcKbofo@oGw-F)Dp$2Js-dIf>+qtQ`15q?E`Am3_cFWlJ% zG6kLV&EGrtt7a3d`WMWwg`R-yovpa&y#u8GzKTZA8CTF39~6sTNCls4gx}rCMA5bd zZ_GCXqd`yDxM&NmzZU{#WDJ(L=!2JlJNB3eaW6Nmp!0K0@xLQgAS%F%(eqQ$F;yPR zof$TbN3S7(mm zd7r?(whxk|LTLV!C>lJ?24zV;_WkF=_#Z2ThF$c-qXVBo+-{mY-uEBG=+1z7?GEr+ zvV`+)eG&mUG&7; ztJrlZ1I=v1AuFheihtY*&#zwsUj4VUjb%?dZc{S*JU^Q{%Mi=0bMRcT1AdA6Nyqzs z(c`;Iu~v*i(-|J_5BUJFl8%Mv$LoQ!`6cG2XOpJva>!-zviAr2!bsZ)-0Dk(MrLPV zS}h4nvJ*&@rxC0$-GmhynKYVv6}ERZXnI%Ifs569R@lyJ+>tE}`~DShx|T|T^Tumv z_(K_fNyuT&I0pyM6ritt4j8IL5VkdP=3REipv*Rw?>Z0M$guI;HnyO9$Z{sTltV=a znqXY0hVk7_W4%Z&yeSVN^gAzRCHB*3zq{BsQbIMNK7v{LdAylW3U8e&>B`v=fLdqa z#IbJ}d%TKXZk`K)+0j^Yq7NI*{E0?t2w2Wp!gTj6P$BOl>o;?k_@KOscIniTu8W?a zmaq=j?~K7=+6IQB&&l2~QRqnLW516r!xvhwAoq_q1ZCQz?r|O5bIOg}^SzA|O=i#% zix8grgZSN8#&jK|uwEh&ZT=0CSC1>ebAc}`<_`iTU516=;RSQP7vgV;`54Qxrc%j~ zRH#dlMm~r~0kM%R-%NXV z2jK3+LCPwQq<5aJMJeMN4IP&udPBSt77r(5CtnLWuBVCg3d4xGHjKUd7@qrR9mMoZ zVt(c%$P*vfYx0+fdo2TnSp}@S7tX=fTiIZ7Ee-{bw*o8cC-w*!LJ<2Mbrb2t_7Pt8 z*Jol(2Kg_%&+mewY-WCXya8mJcrfYSeVTOf8N^)DVeTXEuy|_?th5Wl`CqE>PG%9@ z`eg+t?44k~?!w$6^{ptP6-~a!pC&!s!H_y7M1Nb4Vej91s2GzYqfD1Pwk?X`y2ikf zA$}||bp@XO4%S`sm*5`xM7*ZHES1>fjg%?h{r8$@%NQ5)R^UpdtbM}G22?|k!%UNo$09kD;*wmd%)~nee}_u zK6-A)8!}fv3EK0WXa~m$P}76duJgwsCrKJQ-2rMmPPp>EE|NdZxZ3Xm>Ob!yD$JSn zqhtzpZ;r<}ZFjU2KZwD6H(54^#=w6?HEk?-j^=?5*~0w}AU*8{Z_*Z!`M0IX=mIHR z?lpin8?K-MhNH;R!_Z_92n9QB@Z|nc`t$yKR&QfB{<0C_T3$cGxpg8NDn32Inlydf zc&QC%-_R!AX)$D6;|Hi-bHupUE?BkZDP9r2Lygy$aq>dspl7xiSCXR-2k-n~WoOr6 zK&&>tOX`R1=J6P7I0XmJ?j#~MdSLs^1~ThJxHGH8VJci2eB}9wA5R=Y@dSy!9EUUW zqwq!j$X=}!Mkare*^h-&G-wW80eg?-5Fy~3{qZpTW zgi15}hzf&;bYiRxK8Fc%yBYT1sL(8IRof1~H~Nx&IuS7Uu>~BNACFSL8<>6K5PfBk zMkW{y*XQMnp(i*VxxNu-q_z)k^1MM$odC+y@g65CGBI{-D7uI@VAnol6n^NBW;%)R z%v=sj%2g8?`>y13w8t zW8ECelD%4 zvWDmSEI7&JTtbTNV5NBmbmexSu>48dzlWDCp{9*@yL>n{EzS63pD=sAP!rw?S%D6N zlI*{%Y^W<8pnD{yP*UkC_*aEsvfO;^xn%+NtN+p0yvopW(+;yVM_8n6CfJjBe314M z@=}>+)8#0t%|D9VdmHeEtU4@BK8_0>-hw4oVIbUa4Fel&NK~Xhc3UaZlQ%TUzt5St zM5z#hZ;WA2Su-)b!FZI~Yq9Fa4seuI;vDJuhz?`#@%++Da4_0{rN$M7xXbR;JKzWD z*0%t%Z-V|^CIu=_YH8ZMr+CW87AtC_FjcW0Yo8R;g@^xxQL8$1URV#&1B)T}(^=eF z7X(iKlu>I{7Tq%7hO+0ELxI|TkkKDwIwPv6uKyikl-n^Zqlo$J64fU=zbM-g8))Q?p(f&nDC{e9BcccK0Uo!O$O{r_|sQ%Oi{nCmxL~S$HmL1MFsU zQI->~3`;y8g(`M{jiD>!m1FvLR$LJOmV@VS`Czwt5Dt2z! z?6-mF6XFHWxYfARpdHqKd`3)2H|y{P9a!vlfExO*fK#piXzi0%cy+-K&^(Y&*Cy`A ztyLq~*HVhARwKxhbQ-%J@^FWLOml*&G*K!e0-i|}q4(8k*i?E9Htd+y!D@-R&9@jNnLPbs!oJ;cs&9Rx>lOHnix{3iwS`z{b{CntEoqEXfZlc=x zsjM~iA5n0y8v+@YP{;QxB>eUvPKZNckG9>I zg3*ej*uz@^-}=(b$y#FiT@iNBtAof5%A$B=gp?@R?;qE|X^4j+UNRDz?9KQgjUpR?M zq5<$guOB@(x8m-|PI6Ck7Ws0u7PRm2vW34QlxvyLyH@eo;N%U57R!-j$t0-Z$%U@n zJw#2U6D$=%Va#wN8U)9}kxfCcEw~A!J}&}A8baS|x}tXrANR;SL9!#ukvJA65vwmI z7~Ahmif)gshVJ631qLpgRc?;(UJ236(M?9dyxb6E97Dd z@*&JT65>T)Kwrg27#7%oql;TO`*!;yT@;DNF%F!% zZccp;kKXd*qmfvUWir=2Eq&B%<0QHEW(ld3Jc_~t<>c_C`)GgkKiG217fNL=;vy;L zy!y@p92no3q0d@4x9=$D!bS+yuK6nG^o?Bm#fHy6f0=FI}O`HzOy9ldr{XR7AiuV(dWtx$jgjEX`B6Y z!HW}QcD@BjITT}=Z5HQy(iA!9m;zVi8gbU9c62&eggLEp=&dswH?}T=bNBsm-KA;> zF`0ygh5T&$op(X@*9)e{`Vt>{y3rqU0c4~6W`=9nOXTJ^;H-cukPs?hDN2-r%<>kh zc+DQqXzQU$vgTNAuJ$MTFIvT;nbQ>D! zIFsQ^hy}SB-w|8VrWp!YTQ%0gOw5P2)`;GH z?cvD1M^L@%J5l?cOm8GVgx%^P^srVn?b@&(%#ZP~PZjgBUnUQr*6JUau{Ii)6%TQG z4XH8Z~TC2W<@XiVL?nkW>n!SY#MQ1v1K{dY}Z)*27U z^r}ObQGW8w>kaE=SqfUV?Pl(&a=1=%4p-->Bs{(+MPHAy@a9@etj{SR-YbGphV!1; z_pJtv=@D4F^9fcuXu@^;MUTBdNgvu>WAy|S5`~AUz%J-T>pNeu?xY4NJMgk?I^U4D zi z4ZQ`AiX5nu!FL>q*@XIP93rFJNJr*`;OCp2tXuutar6`~-nK8r43$UF<8m8r?F++@ zp$SYW$p_CGRha%B0y>U`IJo)%%yY4#(g)kX)aNF~jW=M}k3JkepT@W&-atluBb?uH zkR+TmCTfgVJB%kd_nMs%=qO0R=Jj7tzbF(7J9BB+?K(Wa`4KLXOd?BPNq`5_0h%5c zWXE3mhZ^(k!DKRl^|g|5O&zO8YU2eN7Z}ILpbdRls0De0SAr#G=mwMsctbI0j7RwE}iWdXI=SBI>yL5!b0$}p-9qqrp>cAKq* zly0UEtdaxUg^TF)p8~2-@D3~H#p1_=e6&zLLPu480rR>+C=;NWo$l~m=rg&yM~}D{ zO+sjLHRQgY$$hkT4}3QYft`b=!Rf##-Zpl_JAnn*@a`6-i!0K3IgFp2FsPbSjfqQvTQe6Jgvj@6915RHDBiY_ra8v5=1=84`lYK z5ruO~H0nF^JPs$|{U58b)jl5#{Vj35^nNU!XNR7~8t`X#E{1Mf3jg)4rp9ZJfKPh| zln6>g%giC-fALY3a^w5dZZkUilgd z!+E2*hCy6N3pFE6A9_fOiZ6s6cVONZ3t=hoLX%e-c=(DimI|A}i@N7fp&o#jo*YK& ziUF_`<6xHU28=c~4a9>W0iv z8JPJr2~|a7Ft13Aots#WFEsRV;GZSU$es-{>$<^LOowsDodCUfCwyM7K*f2F0gtsO zbU+}SKM%&NRp436Q(PA!!FE#L2D3ku!IlTkC?hS% zUUz2#je{iNg4CjpnRd|NqN}9-j!?92swG8#txtcOcu|SsS;jvi@QGATy8J+({ zr`%F;>n#sv{*XwMmbQZP^L^OMWMow&__%LsV$rC!nwi`E#F*+%xH4-J&ht0ovg3h_ z>$U-(UeUr_(e1GD^J=tzWe155zvAOOXWB5-2dB$Lxq-C;sGp{c^Q6@=NhyMrzws-v zD`{ozy|oBEJ8sbZCl}y|(K<}nYXR=E&lnyx!l%S!nmiRx;|?(F(XRsFUgQl`6+FnZ zWD2O@d~SE$Ros@P0mZyb7qYF8v*d_0Xlbj^*Ro}3aq}N)Z?2`5uNJdgMV_G8(taHM zRfjc92k=u*8j5)+;gPm>Ecg0Ju8-!!pHv>yuSvkS_hT3rV+>HMe%wm_a#rRhpm6;R zI<&Ee7|!2=W^H|7^G6j9ZFx>@f_-4a0cKupl?h@lHXJu$AM{rj1iixbc#T^Jt-%GH zBd{RiT+L>9!~9f6MtwkX)!LN~ptgCDl5;rfHOoC+m-&fFt8^pny` z*zU)ghgUELI@OKA%I* zzH!I!twVU@&`T7p-NM;g-h|J2BhZ6KiQREO6xEr1S9mM zSN`#Gh4Xsx-<&d96HyIHE4rzQ4C6_5$iSf#E^vRbS*@mFa4#2WV%{oTtS-wbeY%k4 zA7u=a)4T9ZuPi$K>_Z8?C@9K(3eK5NpiHNY&g7`Tp2{K!zZk>0skMa0h5RK(yctAp ztN|3>eFc?^F{m!Zf) zzoc;-HuACc8>cz4Ob-5%jRBr{xgWQwO=3c@4*R5J9#}7TC%)ai@Nv5f1Wv7o=LZF$ z_fI3lpLvaHGZ(_pU<0rfB)A9CETNd;ypMmF&DJgbg{mq;bo1HI5PYx|c6f?$CAxgj zU~de0sVof3$4>YX1^xk9>?%+?r zn3+}RlKu?EPQOQ^Z<^#+>l7?gx!7THQsQk zMegZ)xLqTQ*}d1(vlq`${~e0N$U6dFJM(fiMe1?q&Ii9A zXq=x<+&<2N8NW+GVV3}Ri8YHj30b2Q(}7P*BVhNRH{)uKL>0y3#Ef|s*7`hyzGWpW zfzos;p7Qgf#!~^ zdv@-)*{6skAH9uBC+p~#2M0H&MM0XsFndb71$s*VK{ZE)j)t%yTrwDv?oe8&I)MBq z)$n{uDjjQ#2UB+&+*qGaPDnRunhyJtWz+5;A?^zF>Ja9deg)n;7Wi*rKSY~3z$w>m z7eVeoAgDT)t6 zm7#pj^nRyaQa>kI$GWbz7NUx&$5Y`$)(^Lp}n-`x;-QqeS>#Z3Fu+D4a#2ZK)rqQ zxLSh)ptSS~y1lL-3tu(D*x*m5SA8lK9Pw=v9kt zFw8KXCXLqPfym1Yr)my1%T2+=t69J3*VlYCKl5i)eN221|y6<1>pxhx!E=j=_A= zp?8PO%2C46rOeK0$^v}8&*AFI*OLRaubBQB;rto>4__T=#=pB~a8vd3(ZfN6t-$pq ziEkyiKRcY!#7P!2-z%}SrPWzm6IQtWKLc{)N_-`4*A}Hm> zb%#yBc?l2uX3tRw^$5gQ-Inx_jXO5{xd`Q<+Tb#E55kr`A|b>YUk9o)d%;%_f7T!W zC~eK1n?^CiY&A!9=owfy%mmqmOh0S9kW>XbgH2{Qxcu6WC7Kk%%fCY3m=a!CNnmQ? z0t7mCqa=?wCKm;PBzG1&*_?5*=~m(l-&`!|UI12;`p_S6mtI;GPd`2IK(%8RVAwzg zT|a!JL6YBd^J7{`eQ-Z)K9G&)rEOtR!$G{ZL73~u9|K)?ufyC;Vc2OmoU7uzm8@7{ z&Iw5>g}_~lbN8=N0JMHfPRu-jb@D4&{N-m^*^a5m_I6_>n^?o~ZQ<~AmN2(I+!H@D zJt^mX_Q0y%OHEm^Oph=H;#NI{IQA8o881i4*;J~sawqxb&E!O-uE4bF19%|T3q|=J zQ2W^!3@;0@YotG7q}5t-@I(y!+Q}he?Q7wkS2~zx2|#td6Dqrwqtf@yAXYe+oQ^Ai zs*#1*^05>jjSb_shek{~azJ+E~@@QVP` zbI4?}`Nwefb#=6Esl@n#I_ePE0GwDobXm6#ma0U8;R3TK{4=Lt%P^$_n@--v$BMG$tf zqa((*QM+v!_mhPOhIXz-^^8CmX-$LZ6F)Hb5eMcfgP3jrI(J14;c=5Tq7|OWxx9G}+hffN6e*z0TtXd}ZWhPz z+e*-W&+=#adyph!Gp*D5GOqeC{ z8im#gdzcwM2Bp=(xP6xpTYSTNSa4nx?~zT6Gx`=wHl`E0*7CCD|K`Jj#s!?rIZH`o zQ5gN#(u8}uesOXPY_KER5e)T0@Zrr)yb~UdcBQ9amAM1%2@7W4lMM6Z?q-Z-?gNK2 zJ2*kVv+=mKCtO^)6uREM1!ofO>j~fuN6x9#tfLE(L_tfGlG}GwBGH=SyJlpEUA~uRxv&2XM|8`5#B;;aBtf z{_%Dx4J$<`B9--_p>toy9w9QacSRXV$V@6pJMFXxE!w+tU#GMep(Ul#kTj%068YWV z-#@^^@jmZ!-`DkeJ)iXXK}4Mvma%HO2TsZI+?pH-()E5nl*}DMixZ`Ks{PAxd*5;D z#5%@X&R1ZIdMD@Xv>ebp;|;PdKgrdbap2v3kF;Fu!4laT*s!|mA5W-#wJ?1ZvrXVCmHjP-0co+aT4HqBGuhMyAt+lF|0f(dtE`zaWGslcDs zQwjw-rR>jJN(_e6v3r3Kjr->bjxMiIE5@F=MEp^M_mk5-{TDcFX6LI_PEZr3jBOvv zu{3TP_N^G_lx%&4*TY7M`|27vk#`NZ6(nQ#q@P(CrAMJDz!9csW9M431EB(C!~ zjYoD&&Q%!k2P(EoPA=Jm^%_o{`4WrR`XX2v`+TZ;M9tH9w`ETj+F zpoozqcjlQlpc29Oo#9?IZgVPD=`6#dy|I|HJ`x;M-;&xuVQ$g6kDz@0G?;#W39IQ` z2um{tHIb>*#xVj6_to-F8@F=A&b7ehDed&2qY277ttZDLa=@{^3Lir{94u^tY1byx zsY||t-O(3x-(_Lc`CW>~W-h|osz{CvVh zqKOjY`nvVdhc{Gc>4+PIZZH7D;vldVS&mcV3wKb)#Om0znioxAMDL=c@Z zf)`_F;1&C2yfL?SPUf_HoKd%eCs%j{2M)C0s{FNBJ^2?_eON=Br9`e`nlpDNDX zG**vZjC-am5XVdOIY5@qh+(dlIZ(dc2d3!i(%BCJU?6D#ZXR!kP{Rq_q#y4%+Jmq4 z!j5wYk+ekJkFG@bl^k64=!J>+nd7A2g}sbh(qm$V-YVl{PJAQ%(tjINo=avQ{2|Ey zFTI*h+a<`|SGSyYeo^6$b(g}t1)sq7u^{*H*8|Xfu7N(aQwOtke6R}m4%>J3lfZ9l zN#s}@+Jq69B+Zz0xn}q%fpzw$Y((j{`ye@88w1$+AY}Os^1gWsZRTFljeT(x@$DH|~ z#J#XsQHjbn+d-?vdL*{Lai4V=+|ks4O6%=}D;Y#ptja)bo;^C)&E|7WmeKBlUNWgG z0{WD%fSFYkiY@vI+opejylOc(b6J@f1k~a2!XPj{yc6^*XK;<`oH!b3t1^lS7a&h>srlEQ5?$HakFrM-pQwvF)dq9{K(-UqIw#*u*M;TU1ykE&)|Sg>A-8=CkC zK17Z{SE3JCK7R`?D?2zQ=SOg&?{>Ot{(IDjK2BUTRZ(d7Wu%9>q~Ur2-g;hu0v_AI zX<8>NTNQ~zdv;^gH=n#VdRG_h?-`@@hzRCeV#L< zteFlzm*SY8VK-xD1%uPVel*o;0i*xkq5J!<=vb=;|LvNJzZK5IiUu953^WCs|CH&= zwl(y~NHs*U^S*IgKVx=!VQZ`gX^V};(i7frigOAkn~Ctfw%&)nOD+iAhPZG?1PVng z!D^N%tevV6km6|JRP^ zq-SO^V(NT;tos7Ajwxa6v=?-*&lBR*?oPfuWwUwyNGQy;wPF(%I zoVTK4F5H>?7PnZ6!lQ|UaPLkx%9v?^`A{zDENg}4@I*LtxC(5_9N>k$BP`~8#IGI0 z+4ALM_~K7HgvaiOhu(5r%>zPupGV8E|Mo4ia_AFh=h4U1+~Ga8I|*^8*zF<@W$xqZ zpLW@8cj6(yU<7W4+hLsC5M$~oqW?|CuT9OOvtRX*d7z35M?|DRJ>EdnP)x%Q!_OnbVVX8StWu-Tgynwu^f`L*9c1zLh0?_%4nJA zjeI9jbjiF(5~W$+O>hrh3Grh2)Cjn!;*U9s1t@<@g@1Z59(oSxqd@z2@X%*xTu0Wg z3P{CHg(12pTn{JwaH1QuR*hu0(F%L%2R;H;q0pgn3tnNoR5Z3bWp!#HUs~zlU{q>fOQWz6}QZ zw{zB;7SJPP3fFjn64(3?qIzfuT>N6s`u@|%>dMJ{Sy30v_$&@A<_oQ5fl%8o#?|&v z=RS*m$=mL{7b2G(ff2WPFr>H|^gl>)^;7P_nRP5%m@hQ7Siz8`FGLOV=*K+o*OV-v zMJ9)ER?$NUVEeqQ{Zd?ki;P?2TL|-)%mRt%7Hr(<1qV(qqhjwCpyv%&y!3c66fwqX zpG69_m{f?r7uMmx)p=+{MYwL{FzD#iLcrEk=IML|TeT8#hi?`oQd7x|K?6E>ohxRa zVRxTDn`wxqFxO{09|xy5LP66T3{@B>;xk{91s#T*rFzx$ovIW){(b`Y=;=|K(&!B; z{-!vzxftkvBf3mxDWc_M$eAY%*{}R~Qze;;D=Qm14w_`|{?`jn=I2AF<|O#;@_{pD z$6H(#H5>P=x(|m6GB`JW%^>2Nj^N~!MIiSK;8L~&2rn_B8vAWvW=8;Ly@W3)95{}R z{$Ic<%?FQ6uAu6&f`o5-7^IU^&~)N*T4{C+LI<)~uhN9<$|LwF@*1pneg^!5IgEXG z7k0FNgemb+V3IzIb!@G0%CBf}Da*&9)OmPe1_$T4#A3mQLY&&KhIggaX)a@&$C(?z zzF+T9Pzup?URho;&G7G>dpFg{-8JF#mkZ@fg#sPu;cwSyzC&u-64Ak)tl#nrRz&* z+M5N3WB$_rN~&P}vR>TqO&LvJmkCRuN#*`OK}zrwk*a$vAdA(T}byQc~=^S^G%w_uzWteHc5c3&dgy|&-#R!t+4*&9>yPK9DDuO zptW)Y)Aw(IkfV9vclj+$s+zGsf44unSRbP|n;pRUMF@7xyM#SQ++lVx zz{9AS@Z)+H&Di>|UKp`98YIp*(z_lT zvga*Tqb7#sMCN%Oy|nTIZ}*{7^mL3Z?7Aq&Hx8IZE@U^uwLLnF+iZd72Onaik||hj zii54c++b+t1 zH-gG!Yg}_4NJi@vIIkOt3m^k#jV#B#t+|lV^@X=OT?2MKdIjIy>v5~93_s$KAot&+ zTnPV>0*S{pm@mK`lSTt!-&h5;`lZ5q=)8u;D5c{n-Hj+#tdDugy37Ub2KO9R(a)PB z;Ft}2AEgO!^CsOw*VB_oy`MCA>%IhI+i8$>dN!ui{_q|Fov+{8F_gdH@l8;lik7Dqw^=Rp%0wQuOJNb7H zjX0KqU#GK0XmufOc__#)>TiH{+3&QkA{RaPjH0}{D`X4i!4dmR&fUXpAU=B&G+VI` z_q!wcDHMkM2ivGtQ#sD>OGlTo9$0MOjP1(0&}Q4ud0qF3mRMS1W6pl+Iz4M=@F(To_8nRu?K)(&@l~jUiUKl*j&m~Um+~xAA5r>;{ z;c3Qw5KT#dtezNHw)ikgEq{&GyQ{!7XA^vRxd|VY$Iwu1A%6Pic;bCS5_Qfy;Q>xN zt<{Xd;nXos#2;7qZnqth4BI$Y#8R=BxN|P;HwG6A=CfSg3Rh`6{W5 zjjJi`oKS!!A>MSA;Xbf0HNi_pZan96VQ@R?6wK{-0242Y^94qKf~J@_cSW-oEV`ph z>o2wP?%o;!S`$d>74mU7z8LwT z6ZylvO8gC;p(}51Qixz)}WgT+FF7+k+9-hJ#7$^a^9gi_+0U_Mf0py*cwAa&}xAu?> z9*p@)EvCGJs?E=^al0Js-;>GPo8iHc;a|rqZ-sf5g?cn@V>dqU3BuMLJJ9b{9(+^R zg~`wTVS*;}0z7$!k}4CpkFTC3(G?twJChCacZa~H!5pq7*yC@;pttm6yS>9XkZTbG zo+-&NoV*`ytD9kt;fw738x`?-a{_ri;~uoG-HMGRKj|m?Vo+`j1+$}zh@3|}<68>h zp}cC^__Pi!cBa8-%yS%gqKkPWE->c}<9@z9M)VTcU#`^%&sD!*b&Vay=+5P@sZ9m< zepjBQm>ylT$qj$sts)=m-{TocIZ)GSCAVF@;MgJ+p64+HN7Xc}>1)Q@x9aHAtU@qn z`*}xvjPLJ%#n(m>e3|JbyqY~mFgB|Xjz5owzUYfEZ-ybt*l}QV!ylr4!XCHGYGLol zJX+w8i$UFb7`{J`& zKUm>=0xtBv2fedt^i*^^T0Wc)3(s!E2$pAvboIr-wO3fS_8q+G?}9$esTxGNE7}j~A zA{-2HVHp5hS2X_;jnY%!fof7RFM{iVwSjW{;LK1EUcZVgT~$Djg9Gw%Rq1RU3YldE zShRHk?^}x$bX`b7-yhl-T+pQ}+7%0HRo$WF5FaITp1^`yO10G=V@cH%`Z2`|{@UBa z^w3f;_bmdcY41?aRttic`l0vxcq${Uz_m(X?EOj3oQ6|upr$tg6 zVj--@og_^+qY@(L@b;P~Feh>%H`x9smb%P`N!xbfILmq%bXCC9qGr%Na{>PCeT@lW zhnSzn1GYZE2}HQFh;0=?)zKa$<2# ziZ2)Ef#U|RamrB%?sYBTl*t|?^}6M-;dCuysE$E6xy>@}d{Eyo9Sy$}g7=pe7!#ku z*E6q#3C(plgR899Cb|u_*)Bo3LOZmytA@8?BA_wtAy3L751W0MH!>*(r7R|Jce6cY zKAl6~`0~ln4ofuB`VG}3?Aeu(7kF)!MQXuNfPo`Th z%J9cT5KldRi1(waP;f|qE34~-bt|6I?6~O=aQy^%z?qC6|7*drmE&OYaT)IQnuo`n zpJ2lbZwNHHfgc4vfav~;^H{z5!nBH4AW|HRZ*>>*HU6lAtJFB24SGhuMh=p$t23$P zu~ZuPs0i+y%Z8$B*)Z_&Bhp@P{2kcKY0S1^Yy_dlL_ z4z(g;e0z&G@cB_Asz~!-&yovZvv5C14@`lJKfhyV!yJg8)JbvnRII))#Q!o<13rv_ z7#)*}`>X!Z%X6xrZ!+t$bVy**liPHT$Xu{C-Hm_tFn)y7TDVtU37UJlKygkCEmk>! znQXp<Dx$4>1Pc+6#=I(~1{+iXkCmBS_Tr!F+NMH~m<{9ChK?Zu}AwmRz6?gCD8t zh$m{uZo<~iZqYfAALida4Q~@tC+)hf7Sn=p{rG1lZC54f_lwyoM> z;|b3oRBIA1 zUDHI#&TU|x@saM$`2foXUZKW_J-Mc+#4UD?1&$%}P0sYh3nnX|o5=8ER``J0{#M4K zT0t|TH`1>o0$kPfO}Jmb8OI8b!>UFxtTFQ<(&N`q+ew^^&r#u*T$;si8BHY@mU~n8 z#g$l|w+Sm=c4F3nHcod`5c=IMfyiS8SdS;1yEw} zmviQD6vmKdJQk$EIv5?)bW$;ln&z@y*C;m3v?4oy7r~i=K;&mUfSmy$bV|8C{Jk_8 zN_yUdONA&mXTAmKsg#2Dw;y!#lBb$AItL6*8 z|Nh|2TPMPgK2k-@S1$(jn}u+qy_r7yYmWKdU%+s&48HCNfG}bTUw7HD*^3*w+_4JQ z-dM~lJ97xyzkkNvIg{~DdNTQ(q5)++EDyZ!2MPPI46FyL==~MN;BaFeX!XzJ&im&B zj~j1NEAJa{S!ot|rN%le$C`0V+B6h%UXCa79)Qo@`&g2Zg?g)oG5Zq_>y3kXFJ{P+ zEs2x4kAA0N+4LCJ+bzKQ-?L%K_q$-GDa}9V#V0EN{h$e>MX<M&2 zSa$+eK_OOLuSKd}2un{zKtsxM&XHa(`1M4TKh#!-*I(Zz^Y5l$(ozw=`iDGJn<$0t z>Tzuf}0vFS#@#FUH$zZ6^f(O1-a-Y_`;?U0(5a$A{3kB8FmqB1j8|?UuA5@v+m0=`Kr|HRCJsUn zd*^MqwG_AmCpbK9#+R9Sld-4E$e{8V+}0jP>ER@*n^%uYzeec?mLu)GE{wL9o4{AR z6qRNMV{3Ay-X!C-_$peEyXUh3aE?dOnLdLMJ){F?C70mUhZ}LSN+}*#WC5lD%v&Z= zOV<1nAm+`b_*VH1_OJ}Zk53=K4ir&%EIs%+hr}+Bu&i4 zyThW1s(G#ik857M8zQHnqVOernw1HDwMQ^H^aGYIjR)VRU^uJlM83BaLD*A6IKVt` zrhGwuCQk-*e=xs}-3GY!>H%Y8G+}Oi1ih>kNP{!JV=U_vH&?Q*nyL-d4Kdb7`Zz9I zz8nK5{Uoh_SPs^t1!Tu$Fh}$Pk1^%L+>zbDn~~PTFJk&RwK*!564boP}2JOh~GwIQM4!IHo0iL%i9sLA0N61+?6>!`w}pSWpuEJhud!`_@MteCeD z%(f--e7--1Tieue+pP$4JrHs1u~l#THz)jIya8l4v4*02IsTqt2a~S) zB6*oYMw11&!bMzg7rP9b4~D{x19PeJ*?3OeZC5ID@i`hb=0T#@HWEH{Ip?lNGA73R z6R9D4y47kenK$tm{JI>0!+l)HwR)nbukr;`Ma=1`Uq^7+#mDenQ=5n#cO&MZb+lx; zBYa!=2xeBsg4?WQ+}j%o|6R0(h_E(zSyhMDJAYvcUy>ZlQY1M$vf0@(g32capzp;N zeB>|453)*zf3wbD%-8@Fo1}x5&u297h^8M;y{2chO?j@Jviuq2x8YQECN%W)K~(Q~ zsJY$^1MG9ujIsqKpCDlBTdZ!=#bM`HxN}uBZam1IXN7EtIFO72fjQYpv+sfb&_VoU zgz&T69_1N_ZBL~W6&+{YlO4YBUjIA2^J+E3a6|Ci`e&?1@Ek8pxdWD^QD7@C&Yd(j zA1-dMz-a%k`11BJrRl8Wx-AJsdPKOJ>OJ)CUme9c2W41p)SEW1DuFg}1sp=0FSq(gLyNzw`A8Ws04%4C7_YA z9PwH#Y}R-RFJ7e3e}ifC>d+*3!QX%`k8H?^&=$h=u7RWXm0*F~dRWc6@9rKk@OHZg z@~TBazrUN1>Kph{DIBAAQoQ)=4fy>E!@XH8)WDXx+4Pzi69~XEN1Wc1ipLDw*KDac zpXNU`qXA{{*tlms_`mYS(8wgTJ$nmxhWTURw|dNaEduSjW1!*r9(fl=aE@j>X-NG6 zG1HSEE|dLMAG!}Q33fn^L{i@&mIJC4M2UMzB>q(pH0}IM6jkNGWY>OL6)^)1*42Zo zqAHf@x?tnd434ASAn;dQ$C6EZ@a&Fe99=XY>RXEOx8!@+I6IX+Q+$a0n+$8&Rp*b& zWqMA38%kNfz$kI{o@lSb@K?;~8P2{xVSCwoJ_8QcTGP309;kfC4hPmf!_A$>*vNcf z8-a)YQ~NN<;Xcpl&=pd7FO<_XVK&S>b_1Qie8KOg>Aamh2G z7!7vewY#2%HHnO|xu+N&#fHPDb;BsF_yDRWbmJY*La_49LTla6EI0I?Hio;x><5)_ zZ)qFv(4xhx8yH0b*5pIt$t%#X-UW+F%izcXbx{1ffcOdR!}g#E&bF0v;o1o6YgC4U z-iEg~U6v zgEx)kUAZ)c3o%~iluXmn78WvHt?G-57)f}!J<@&yk8YT#^QOrH%dvQY%r3u zxcwJz-E>j-Zt@Uo7tVr`vu<>X@KrFIxtcx`O6Ig3XFV2AD|{-^$Cy@DV9YX8Q|HN3 zQB^U#AbARpRtRu6dfL$i=a)gzB1w!AGlsn!0N*Y}LNN zx}U7uoV^jWHzeV#Y1?7ed`k$)$;B%9&#>g&2rRZqftBAxpS^+5b?hT0URKe0M9oe&AOoM+@J)v~( z5sbRF43cD56R{Ur@L?zidQ#-TE9?<2jhzLwP>}L7=i%<5RGtp`h?D;aV*Nc&td|vo z8)H^jJRrtz{Ubt4g6r^|b^(51&zvnglmDBhgugTP;6v|Va5#$OpU)Z6s80loH{af${HgVny>V98vTk1FL*sVxi>tpZ_@<00IlFM%}{_c6<{ z6~*e6vHQ3u>(+OZLao^-IlT)#RNRTibtSNOQUqhcS(sRVi?_*378G8wu9|By3bzRm zv&4FI8y3obDE}I}e)#KoZ+?KHnlA};ehWET%u`iz3KSQzym)UJY=4%94(#6=u-_3D z%qMipX~qRP-~`N7Kr0d^@E@5x;zi!yPb}s~VkhGS)hup>-2)pztvLizpNNn|#@mzE zUXF`@^zq>NVmdvg3q-Bg5Jg=|ewuW^?teWPEMZ6Jd?H$xUHDj*34(8F& z;T`^AO|vJxqMwp8z|X%8^EVwtHOCs>u%i{rXxd@r&R*;{D!~l4V^x3chvN_Zp!2*k zt{lmtvR1x4*`YNcAwG+?teK1d9?hdEAqv^g^JF1m`6jaaRuiJ4H_6Wu=2ws01Jl7b zP;8!r(v_J+fjXktofMG%+<-c%wIoO?h;=L<@?Yj>p8PP$|Q<#7WbgUV_U2$ zs>AV|L$v7R8nDsI0_$tSFqqUyGZ(IBj2wAzJ9&8?iMhzoddHIwPBGE%grW- zMCO*2{thgK*ltd z@7)CUEsapiyt{(^cpo|RvQZ>W3onOXV{DIVz8O?L zZNYh{$#!s)UdHr{;p#7mC zbouoP5;whuFTLj3^KUd{*HO5w>Q0#eLm-ATZdMZQfa1p%$ac$uc+ET)_HSvTcTz@3T;xSEE4TrN7Ic!Kl~E8;lt7vfWRT5PqVS^VEBsZEB92C@ zaNjT=3I}V^$hHhaERQ2M-;{Y}W1;N^eV$d?kCJME?$|Xk}oEg+jK;_SbOS zupZJ<*?GUa3gv!ra8-2$y++dT{o)-Ub?px4cCkIqJW!8+RyS~#8`{IEfKs?_ke|JE zZXOa9XSn9`oO3Ni6W@q1htix#dS^*KxT@Yo+T4rAQO$IhQvoW+w9`fZ)M<_6LM)!% z0`e0kz_4x!dMy&EJNQ(!Uv_%jXfnht~A=8v#3u#5AhhDz=?m?JNP+og(01jQML9uCaQ~YBirE0*q*ak+0z3_Z(5l+vj#f+csB;A{Nj_Me* zCFdJ%`ZEa(4jO{sO=4wNVARliD4#MQEjbv2m1ioc{2!JZ5RWS20=rOv1;@yV9ycCyE?KOZKDi{qQzgxZ+JnrjhKSL$ZC$`gDzh8 z#ukhh4F#2&N08C@7+(#SgVFM*u!(05ea6-BIHQhy*N$WR!47=bc@SU3WTD|=K7CST zO&<*W064P=n-hPMHPX>=@zFL2-uVNxB8=&bjm~iB(rG&L(>@r~{0wGX3xBb{=F99YSu&AihA&wM;Pjw4&%O;cEm)XowvD7md`nq!SioE0?*oK zkXxZw@N#)ClqXc6ac~fpFL%Zd$4f}yr&qA5;Q(&G^S^$C2=`=I7#5u`2fg8i=+>omO%E8*+Z2I*2d!iND1gg*H;G+){;XLbJ z`l$(U&nm5ilkGlOpm-NF#7$uX``rHxW%C~E^pmGMw_~$`H|m`8;e~kQP(96e9NWW+ zdOQAp11lj8?y^1)>%JZXhX_~H8-9W6ccWR3@ewTJR%4oj2z+x|gD0pJWY`7c%4N!s zy~zwzi$5cKuyDhENqBO{A8KbMvDxw+NN97$jPh!@JpUWW9k&3LyMwq%bqjN}*@5u9 ze&qZvf$U}Hs9*m9mg|+omZEpi(R>~cq=w>!1V<{((?jBV6u+vkhfx!IoGqtFzE2ZI zccS`a7stYiOKL_$G&g0Y74Ir@Io_CIKhoW}Mcs9ljMpmlei|uL9BoIYs zx5k3!=xp4y(-ZCU-otrYE8H06h_j7;k~0tD;q|f=5J#V2_Gl4aa$L`x7@|1vUoxy% zZIcyr2{817HzttTDAKnBttWb5l&33{i!rv|C4W#izJM{KU2G>7ha&n{V6prwXcxRm zLtdPxt2zYeR|R)C($RuRe+li7HqAEe_yoUC0xW1}jJbnW*zviTW=($y?KVDW!Tcew z1IFlvvIqF1wg77+ThK~emAbiWlBD_*^cKr?j4us_?~C1t@?{s4{Irm)+pL5V(#<&S zt0Mf=ISc;;G;yYiKg(H9;C{%WIDdL8%zh)l{fL+V2&*H^uunZu~wGK{ z{brvr|JQc#TX+vwDg>=OCioiC|2h##gR`jB7QObcJy~T`tSxoO!+h zMI^jf_dtO2-{W7@&cl>9a|xF|jeSh9!~=zH2=E;li#BYo8uLaAa`!H{1%h6axFM}9 zZ)7wNpBR0HA8MY&Sl)`9lyU>tM|BVtr3rEI6S)zW+&I@8^YG_6A%2KR1Lgh|gOP=g zQRj&zh9;-OCeNK9zfTuA`!uoN^C>cv7VMip8Qxw>Ci^e?fx{&aSTed6z?k_=S>{UM zyCJG>n~f7AKJb+5BS7J`t{&Igo8FpPh$2pvU~7H>l`~gD+X@X>Wl;bpHYw3M$$GF~ zw3}>r5{yz}U!k^G0#^yogk>^r)Pzq^B(4EMu6;r;4Sl+G7W=Sufs zBH02P<19I~{_^-rRfzw0>VKH8$${mZH{ckh1Nw@+RP2`@?j1|V(R@k%!cut%sUN}O zcRkQLI~sZ3%u|>d4~=0wG&IPdsS@R2QS_N7v%?*Ard8mble5tL^ePZ7-UMCu{v*B3 zeVF{A81JNY;seI{=$HS3R_3y>qhlI;p242kA470gD+S^r{E5sjS2&)O3N6?~=IagO z>mx2?=K2+wysR0vWxHZkxCR`onM}VLv3~WgGU_I%jSCy~VBO}AIO^F)@`I*jbD}5m z?@8(qgObm<^Dqzoct1s@vo$bx!YevDYzmTb6-2(T8eOM7=ftK>hU*S|oIXz%uRoPQ z_c|HgrR;M&NlkYcGi$*3xdHIn_6pEI_8)R&0FDXFr2`w8zpG>p;?!o!iwaim*`Yge;5{ohR_jb8<=ZBS!sD1f};+p)1!8%qx2^`)C>TMfpIx(lGXE=7LfnW&EoWEX$wB ze^@ykq)Y$e$xqi{((cuutrCKw-_GHs!8hbdYZ+*Mw17f(U3@x{4+krx!1$~w2qarW zoJI`@#z{l2iaRwMP~iStE&@}N=Huh6AaGi6iL5xQj8kv_Aae&8zk0)6n7`!#NX6RY z*_>!{t=XU<7YXtZ}>Q@9R5Qm>=z{Zz9za4LLKPNm&urJBEi_?DR5e)8;y(l zP|j!)F6@axV^2qVu)hp8YAZ8WU=T;OV=L8qB+PBt76U^e&YU^BChk6YHl3E z2ZfgS^ieTJYbKIti?=W~kIkS|T1o#%CLVB=Lh<4}JY-u4^DIB`mP;h!hS_7FrI!L- z`(jY=cnp}2e8bV)R0vaYrdyor!PDpq&QX6v28Jf#>6vLzJL56P_&Z{fF&FF4*}-V; zH{6?BOT0G=aH(rIk(*hDusE^s2q9P496!myg{*j$O_S!#ayqxoc_MDrGbSdf_Sm?qnYa4r6Br1q!dRaNc%@g0KjBg<{ITQU&rKW*)?e941&0F50nZw;Eil`%=8up(@*y>0J~6ig*f+<$6b*35ay>`c?_p2`cYui z4VqR-pkSvSU+uOZW>qv{crs9sb+mM|CH zg2^tZVtojG|J;DG>%N>}tv=|~YK2^L9gr<3hu4tS)W*TifD8Sv!n6UK&xghM* zN;{?Gp!RDpEM~jUpk{ykVKRxYWzmK8QEWGB?GEb}1W~0~)i9|s3NuItZWLPwJ9Q-a zzI9un(EcQ@kI(^+g4r;%Sq`q5v+R}Vw{1~+Ei7qtJD z6c%@9qTW4GVT)KU^tmDJ`S}wkuh@v@MHb|fSPhx9h{C}?-5BW=K|8VGQJr6y_g!7yFD0_C?cUcq-Mc=GZQd8E4*p3H8h`3u7!{N7_!d+rCI zUP*1dUSUb&Xil~vh%96CqpYj91Q8qZ>G-}oV59FtT)*7JbBT3$^rQiJi~oS3TZ4Gt zrU1p20H^=l2dRm7adksASwB$^?0!B+&nq#|d^rG~?V@n%Qay3X7Ba_Z7>KM@BWlTY z@bS=IxR87ur1F`REAqEuZJov?YK(s2%X%VfNmM1!Ms@) z8|RJH-{@wevC)1*zT!B;jeZ-U*k=wtf8S}iS#LMUOD-ll|LLOS4Jn~xyCL42!m@IS zpCB^h9>JvdRMq1Rq=gQV^b9prt9^v-%-elcV=?ZWT10;9c42z$EhuGw$G>m|M0eDp z3ekmsA`h@qw+4bs-SJC{EEg!!h>Gi-iDk+{;bR?H@W^z;E+yt?8#D$h2?GdP`+!FA z5=p?`161>{3w^b*8=sW5V~fvi{PnPtnnN;3F@}k@SP~XpJ4{|>N^zgN9l?8_F0>6a z2v)clVb!P2s61so3~$Q-^`_g@!%GYvZO;WG>qU^EYzuL}?}L{c!sPt7ICqs18NI0t z{%DPYjaP$^e|HQ%>iA3Z)&Ej?86lWcMS8$}08CGd3f*WT^c%B0%JS2ovc?;(op(aT zyNn;%k%{OLG!O)Y|M=UhGf+3z#o6|NjSNIfNMs7C$( z?kOmQ?i789c@>Tm-g9WX>^4mP`UX7DZiTr=*T7@3?|A9Z0vKWa(7QYK&}Etu+^wl2 z@M4xS%I3(zs`JbnAe{-Ha)lT+>N>9a5n*1C7CE#k=_r3 z5%KWLcm?Y1*CV?X;(1<%8G^EMdFbkU3s)wjLi2?8BuVWvG>ft4aa9IQm3Ik=r&C0&`;UL*rOZ@pc1w92ZHVW1S#( z+fyi*!@++4J3NsKC&*lj<>+r24L!k+Fi5!oQ!x~4N|(U*`2w&C7Zqw6KEY!ay1Z`; z+tBX$80~+=;=a^6Jln62Rc8aiurm<6Ub6ktnv^M={i|5!jM74NZD+cvBMkp|@aU=smb^N@C-9{GHO$_t%oVNAfOQ*m zx#(6ER3G-EuczEVsfBi^Ag{)C&#hogx0|@>*eHzeS&uT=sc2Eyjd6T7@A_ejA04Dg z>*?<(6DZBqRhQzkAVWOz^8gI(D+7_~`7q61PMGT-&6^Kvk&9RZ4ojkNq1|%0V&w-v z_T_?}&Jc=;j6g;9Zgy8NigPsWpjRB1qon0YFmKyM7k|7!;{U0EcH|+TPj;eI;5?KI zd$~kO;w8NK<4COoPvKq#ME~!;nAXF%fH!Wzs6~6QWo86VS#=lVg7YEIqzxuJ_EEF3 zYv?($R^b0}Ch55+D;%#j2O8dllaH}JIA?_Qmf4;B6}y{6{u`U6PBJ3Lido0PE(NDM z)zf$9jWK0N3d+<8{@qlAx-!dnN99g{VDSPhtI5T>Y!z;8ia1#rR*e>qyy2!!JguDI zN)mRC<91DYh*|5z(PzXNN6g;vY)TWE)AS8+=Dqk~q9gOd6l2pA51xlyC0(I<2vv>< z$ty1@p?7T<$eSF4XZx8KQ=9F(C+iEx&3!AlWFXFk*ocwd!>nIoH-c*UvuW0M0lZBJ z#lMOQu*t*)OJ&XjXKIg@@{dU43}>)(%>ivUW=69~huOEI@tS%GEak7Gn{B2-qW3qb zUt9!z8{gtgM;T~zFQjuV+cBdx4Xz2Qp{rXOrz@7>dy$V2!t#JQlAX9|?+ZxESA-3x z>%lRHf}O)Ubl!FVek5wZsKT)j-*p>S9}R}+6|dmt?p2u9F`Lut&Jk#6D8ihHqqxie z`3Zcd7NSqiHh4A3R#4megIwmPz=F9=*gH*vb2M_rS$lqvK09A%W*OW67>jLjR1&y9 z(!&XfZq(LN25hB^@KEy*?sHV9FJ|6_Ri)wRy0R5d_b|wQtcUj$i6G|%;gCD@7^C8FeMV2)V^ZJOJ9tgkp#K!iSTJ=l%YkD2zO=i8+dw$ z@kaTp5N7SeQx;al?}Iq!X`IITXA|&-<26vy)FKPc7D2t;Q9L8)gAJzI!nxvk=(;H# zxBuzI3k{CYMSi1EK^1vimJItsqN&ByEQmiI2a7MMlS<(o_$PQs=Nue?q61lw?pDW` zz9GOHW_;R4DekoLKgh6WGv^D(aZdR&OnW_oO;XPw?6E7neUgsv>;8~d?-Up`Bq*ba zB=$i*ULADdO%wkN&som(keLfT(((aY%?#j5s2rQ;`QWFta;#p{gOC3`$8OdOKY1@6 zmQIOaIeTm!HrM;C63NeRn+ufpQ(OYneu9WrYndb3_|P+K+a=I-Kz z<)4WW&kF_~M&bowBJ2E}$C^Ptu9IT?N=~bx%HB3a?^Hq$^EQ6C?yTI<# z#yA-0kCA(-$b^V;m^hEI+&=e$rr7~VEP4(bZfP3cSCSHLV{>$^Fa*(uQK%``3uZ^; zSkEUK+QzryNQ8{=T66?m`Q|NS_`D)RYH?WotD84HZ5wJ|EP%ES5A;5fK>zz(PgWm# z2Z!rB=~K+ZmbAT4H7b`E%bvMW9uHvBGDR#5xsP66Klr*g2H@$Ue(ddy!3P(dAyhb# zeQ&)ee>VXPB1?IukCFuD?ftB4{e;fby+|iP4N$8I(3_2LjIsVy4@5%d7(3J|I}6b* z%#%6ChHpS(X~}XYG!7Xc!AS7DH28 z;m)~0w3E|;)F-2ae_fQ=JFWrcWFJ6bZ$9;4S+>zLB*AOE0~D$opk<|jz~4879^;$9 z-Ogz2+I1X7Y)uTusEfd|vEJ~P9HJ^-1yC|)F5WCi0XK6e;1^Xv`ojP3&9td?t{EyA z%2Ru>Op*|(D>S=s5i?|8@a<|(Vw1xVZ1WKj?!o&|W5S%=l)1VBpTX~eA2?+|m6%Sv zfQ{dOvy59S9Ecmwh4dZ;!Jii}_9x@wpO6y@72kl%LRfry`w6ho=>)CdcDUcCiWkph zllMNEypt8{>8ivw5ZiJD)F!>*=|uDp&zoxeu6x1gnK=wk*q-XQbuFCvIuZZ=;!xto zR=WCu9_~$;N;kPqgl=vx45}_dx-A|jH-Cc}#pQIo?<4dfV#0T!;=+G1HBehufD((w zqB`rHe^!`Cw$BVkjgc6Lj(-h!Y8lQv{|rK=2I5-1dY+zAICRc+BV9z6>aK8www1sS&Ddaa~8~G-k~I^cFfP#CvP`Vvd{MmH9h-{u|mhAv053xhiAC+ z&}O)sa01_zjKL3{kIZvesstHef z#Gl@}6@*LYF2kY)>)=x3bt+(N=Mbw0;1zxYrX@WkyK;|#c|<0xG31l^d4DLLJjw4c zO$VbFWpKT*fgGLA2c@|^!2i#WJp1hrNi9p3dJL4{zK-co)~5&pDRtr3+X=w6FGMl7 z476B^Fh~9;+OmGYi`_v)V{In(%#X*9gQt0$OJ1PTNHje!2!^_3FI?ha3ac#rAjxVC z@e%E#Z>NnDPF9|U2`aCdSBNp+Cd7clotG$_za#UPW`jSL!V}Ra#6%Bc(va)dgqXorv=erSif3F!<5=c-dnXRa&$QQf#`&BO4{?GJ8iJ zkFh}C-hAGez-pSA+aMT=x4vB z0Wp{G@n>)3HQr#X&keXZ`Z298?Bk_<41qWMXG6c3y6{z#CCktxVL{CjTp2Qzn%czT zkhdglU%!F%R9=(ifhkn)XAv*GZGszR-?D65Z9~uqJ?xPd~u?N{`()m$hr`eOfX=a zj8bs@vJGc#h{iYS&vA3vG_L!q7})IkL6+{3fG#;Lbj_+_8GU)71SY}`n~PxGS4G6X znqbJbQ23!G#EBC{=%y(lX!H> zRdUa49|RaF2xC%eFuU$7&tYE^e*9bmx$n+^YeG7z>VM*8W~V{VV-0Gmyai?}DsrY1 z>!7p990P3SkY!i6l33=}${r^EMb$X7fH@rfd*M0jW;J`pfxfsmT$UDvo;%&JLn#YJ zg)HLSxrE0K(QU@xT0hx)KOS?3rU~1c`>}|37v|ALc=(J9+OQm8RF@oY@{BL& z8ry|2g_cDsz9U%i;{=k5G7K+vBN|)zXrP^dbB*qRPjx#{PLmWyBrGFioueNHs+1Aa z#}}Y2{W#EjlZ7XHQ$e>kkF-kLq4U584B0$JczvTBT%7$4gngUg>C-OEN=w3&ghA9{ z&(Sm~MY5r{1}C08Nfn-Z2=r+wEWR>VV7+uMsb6getqaAuiPJ3cR{MPTWU4|QaN3-N zyc5;$$VN{aWe__JaB}h#OkjKWdx9Te6n}$SRyM(m&u4I~l@Gn% z9~@XECG;#?hfPh%c==)`Tn_Sq(M2EOtbr3KzeLy=5DS61fAJN&J31Q8KBuY=YF>Yg zm0MI8dvP@}IU|m%W$Pewsf4l?6Bs?$eB=elsGXx5IaBJ1d--V?ljVn30-A|TsWESvVIoK; z<-w&X0j#G|K;p-K$A5G8V_)=k2y+a?v1hx8*diI4BYqL?HaG)kuMcB%Vo-N$H11{V zw|8zLovq9Eo{XKfv?7_;Q`L=@%=7SHm4tA|?liQ2s35cs{SJS%LSWm%E!d-93m+c- z;_Y9M4zg}+|CjI{EbmRhPdbu@{?3&w7h8%8&WmzUn~|7_{ovJI)&Q*uN?cEMI38Z| z9`cVm;#SdxpuqkojjIpP>*eLxxa~a5TJA&bp1lX#U3vUd@}czd*?;IN;CS!YUdc=H z6eQ%G!7R;ETvQlJc7YWfNLmglyj^s>`wyzV(g*J(H}RA&&jtU9zv%s_bbLMA0%RZY zh#=4lajG?#uSg+z%wtYN?ZY zr_-3q@o<>`4b#MJ1otc*v7sJO{?dKsrwl{&gmpA@oiw_C{zAvZ1YwNzE%-j5z$eS{ zam$T7a9^?*9a-M@{fFb|nWbzfp+8C(KXo~3fB%KQO>W@WHR;GXhoX9R9!awp%{8Y; zLPtd@Cg+G_UCCz|IsS(i6FjaE$)~v$~l~5&ejLPP}(Db z$ErrEcn6RE{fYHYbI~bTKs+b>K%L4q@+@1CbNkPO zembHeEZtj-Cj%Fd#@Gk!_d>CBN+j-!tpG7u=2~zmu7R?EC2-`h5m_iRj4uXG!QF@`+%9^b6dfGEz1P&?U&9Gl<1Wtix?e%#ixF`0 znHF^R)Ii$fc8Iy*MqETb8Ty}D4jcZw=2ib?%%LqWG5{ zUh)g$&*i~F+n03nV_A+1xCuWNS@P~4&4UR}y4Y=2Lzn!_25*f-&{Ngsw*GD)FI^v? z0h>`;eNTmLf4k7~&_9$2W(=@w2ddjIzzu~ebin5_B<5N}=;8`27kWdy{s^=$x=rqF z)Ds%^f5dCs-SMg2bK*EwOlU3FBIvn{^s4U(=%09lpUB@yzDj)OjXO374#?4#iA88> zk^`z0u244K8+57|*J+ml)@9wog_{-N*xNX=X)n+N^FQGcJ1cf~;sfP8JKB6b87fqD z7&9{wF01BY&;CTXJ8B{N1=fL+qc}`vfnuM!x_{RQW;tMI6A5?Za_1nWmDaPeo0kZ0Bnt?ompm;4>q#-xM)FHaD){|?tr zPeRc~mLGb!4V8_p49Dfo2Ya~rqsv*!BZv$7`0KUN8bhV1^p?J&mebHIGrN=Qpz z4IO2hNPXIQsDCyOU%Gh;6y^qk)l4ZaLy*XNFC_xeCpLJo{gL3x&>h?_b_b$IIib1g zV_fC-gIbSfj@b5iOnfWG6&Q+hiweB(+I$7L!e(dJR-`~`U@$qHe1%pNT0&XN73AMh zz|V@IpuJO^IUOrt;qneR)5_L~)%uumt`-c&I^vevF?g0ff|B(q5ZzjA`1SOCI9uV2 z-ZL6N01aE&%hsfG5R7oKZSCowrG}^eJ+>z@r z|Dg`-`@A0y9sWxb{oZ1rogek?eG01o*5VQUiFk3nG&dZoBJ6xJ8S9&hVI(IJ=lmWI zeT6f5!V^dEW*O`K+r(3|*={gZ@fB)zCzf?+lPCdg0b17l9pIafrj!3GHS9hywlPEOZEX!&1`~?}7(|fh#3GPP(_kELu;|3mMw#p({?Gg?`FHP9!WDSES zmATaHHi%k0OBfTRf~rMZ1P11j$aCz$Co98oJL@}-Hz~oaZH0o168o`1zX+vkUcv!Y zSq#1(1u~8ucx=OKGQL3>?&rLODNBC}*3~ke<=J%7nJ9x}#%95U39oRi+g>;}BMqMh zouX?_!8QNo2ZYMheePVuOma%&_3*VbbK|pF8?eT9Rn_h2& zju)z&!KEZPms3m2We(!FPixTNWe?Op7T}{@C1^cW0J-ZYaUa@-cvdg`Fz4}O(Cha? zV|`7Ozp#l~G7f|NSRa1Q&1}ZgZ^59jwY21P7_MrTCo>JQ!TJ6e&ZVdk^Ct$-jHh2P z!{j4=4fzL-%-3@DT_fXQ`QzHbNV56DVbBly1tCNfOt1Zd!?$YDdU`2n_qPf@PgzH0 zt6O-oyPe581sy7CFv6FeDNm0iN(qmhxkx6S<>Ss1A29#mZd8PKAT>IcaY1`QZ>bhN zKVyYJJ@h91aQiL&;bemQg@0g`em#y}=EsZD9>cj=h;zGh1*G)sGI~#{5XYN7rF#^% zz@Me>aBK5nSkIT>V$+G zW1;;;EE#&*1-3yo@UZ_0UVAtSy!ebawQU}$cyA+^Q1cGCr;Gs~p}{5nT*&<9Tk&$@ z5QuE}j`c2?xD%Z5yz^f$t7JLOW4Rzum*$qX4iJ^8{>*Qs%Kd1&4+~EJ#gN^A`#dF4 zhQ37YgR{u8sJjrIeiQ-^_%ly{1K6|7(sBPT^nM)$YfcDBx@iG2#}{XxvWe%vf}+fg zZiv5#)NSu$+~rT8;N4V$9}3{bit%*Y!E};wSzNfvSco(EO1Lv!2tJoL2#*!K#Nb{} zT6ob3+K94Hp6yxSO%mIg0ahTjC%H@_* z@E94#6Yt6gCzge957{GF6(m5T$Y$_%iX?rW85kHLfbd7Z>8oIX-dQntC_#iytMi2| z=R=s=JslhT)X2uy`S5N18i-peMyAhr!QY}*1Gg`Yg2h&;Sk#gNI%kJLMC1d(<1AUR5jnFs?5e&$3^I zo63o763Z#acjEz-6J%uQ6OeHQFvB1UZe!gx3yJP)Vq+{Wf7 zPrxkw1tH>)({yoSB6!sZ;6N2OEmFW4ts`* z@KU)s_1<+F4aWtOA(>{JoAU-r!i~`D#Ygg=R2nG7W#NkXnq2sXAVK1Nce?so05~@6 zffL7;!44}qoMn0w%sXy^^6)$S>rn!ctKLAPL^FsDcf*D0NuYeZ3Y&bo&{T5`EbPsM z@7eG0UB@I)JbMwH%A4KLqmLC4n@xaHV&SWq8_A<80L%gk}O-8&KLVi12eRnj^?8NnCJ z#Y8B01?SHmU?^%?qIfTkWp5YZ@{oftBi@9~5$rJacm-MS&;}FJvjhW+o1jc76f6S< z@pNky8l15O(etWEt95ZI9f9u8gS>LHTAUuvvbeu|@add-o`X#jFNK+nXkVXsT0#TyhUq8)VS>4HY!&SQ8#|D~7y$jRJvfQ2=ql;!Ii*77#sW_%pTU{4BOJ+ zY3*2?UjBow_`qBxqjE^lyG!uEgyj@wt6}nlSlmCNgY{bRg5|O|GjN)ODum@qax*VIq%qqj zkX%OL$W7V+?%I3sZ6Sxd_!_V}*9(nOe;G!VH{x;f1{4@WXxrD1xZ#+R&~u9|`Bzj- zi;e`q#sP6|UQq+yTqGcc`;yQ?g|ZCQC%kPaq&`W~AeA^5Wo>U^&MOX@>vAz7JO_C& z0ox|!!MC5Cv|y#A@bX|Co-}WQLpP>jIOAd~trO?=6#8OD_fyy(^Oa1nIY7%BShq)N zj?ln+1#vx}14FKcc+GMQR~?*3y^@3ji1C#kHwBQz)fb^Ce+;UxPNpkU-xDprY;2YTdci%0=qx0-Yvdn2T(AsR zx;T^EA2-pw{};8&@?L7I^1Lnh(*zoWRu z_1Q!@b3K|hGKbDGTQE!15-xgMLRyv-;Wp_-c=2E~4*0l3gtQCHU-yD!|5jj*sbLsJ zo#AQGKRB-C47fdj*sCWXuVDf%&5wuMqy+94o@3|9LC|#!racbwFzTN(RF&=|lk>ll zgr7!8y&nKsIm|n8F%iA|*jg%+<|?@=jhA7CDdePI{G@7foA;@xLO(ytFkP}aF;94Lyau<`VM2;21)H^e=u$> zfWN^HVD#7kUJ#Au%}O=HV&IcumKz)mwFtJFXznYZn?!ne1D|Fc#Wv<4+B|+QCL~Sag4Q@=dt(Y3Io^gV)+uC*!((_k z;|lJm5fKh)RYCbpK3OB3O{)exKT2mIji z8T}NEVdZ*XcR-M23Yoc9{Qsq!S8CzKO*T8_hP=OB9U)D&*OKY~mg_Q011 z3gOZ-J6yA{4%54TfreKc_-t!OM}ZGkH%Gy#h?|B7t+miij^!(lwV@+F09TwcgjFj{ zNKTm!clE6lc4z!yUge8a;y+Jn6gvwee(VDK|F+`#)^MD=VF_BiVyx0MdyGyLlB#*7 zG_=MJRbRS*$UZmBUET$9_hty^9aqDJHr`-#z8X#XSiWK6FgZIp9-@upNV1tBWcDq_ zZ5Nm;>tqP(xLRU`$7)nBzJ~uvy=N|z2>2Nwg=a+m(MNIJxM^269_ea;4+kC!D%jpR z^wT(DlT8Bif;tlo#syzv5{>4+u3)$Pb+CMOoqS#Pk|gU*gl)zT$!yKJ(Bg0dM?DP& zS8fO=t2R)XI=0@L>7jLaBw4-n6}~u_h~&^l=)Lj`e!71m4ztGN_r>?{Xml|yQJ-03S$W}d92F&Wn&wqhHZ`^X4fy=Dj=?)wG4eeLka*$;*$FrU$i zI}q+_LQ=juvsvdCOtNBboZWK5+HeEZe{FF2S@*9Wq}+I}KP4 z`sYKqbo&ANv^djC7Z0I#^kQgRlPHKzHYTz8mV#@ye?xWdZW3tjjpui#l8>bgkXs)M zRWCKLz$A|CV+QD}{n=!S#ut$N^Bz<$SHk-fLDX(iAwRHu3)YKP;jV4-;J3pCDw@0o z9?5UO&$d~p>?kAbwJkx1Pocc|wwpmsaXURV#O4NtU(qo8Clz~XO`g4G89S84TPM89 ztZ^#X>pujM%fIo8FZ+;JhfmPA3rk?#l8-#N^cWpBtwa$gOS;HB2=-2ULhWovb5iZ$ zr14k^dSs`dZhkGUH|wSW5-)Mm*JmJ6egkTZ5QP~IxbjpcPCl&((>6t6)$&#<@nV>i zObQbmUhx5rEGFE{2RG3%(wZ1<7U8U~%kxUKi{aGg33PPgcHVCv|lCVHK5kIlMl2YL2hC$2H&2@&B^e=!+uc^ly(mqN2Nlv zQa{K)E&>ymZaANHOi*!Rp0H^!|m4k5)MP z?saId_=a+|W7xjB9*ml*p>$CpJ??CZHzrNRlZ9oxdDr6b&0=+^use^tK?=;;?vP8B zB3#(*5A2;JN1oR=z#E%~wENC9TDJBL>^oTvV+V}j{ym;xFyRXR8RLq#Po%+`BSSb> zQV+K7jm2+s0^ok4C-3c82^i}k$(4o9qsvGP{`qp8n8x~IfbL32ZtJBlWcBbsW(z)8 zY5{2$Z@|LF2Uaey2ggc7(zzf9e{^2Q&0blg;@S!buhoIk3$;*Idl(O1noB0U6yv;3 z%W~}pQ(0#~ikLj)Q=HU5MALY6C(8KMmWaSX?m{QiV$A}qOsf-kqJj*|`2 z#j$8U_=ONNQ4;jQ0hT7(k~!%i#PfnQm+R&a&*IsgP3jLa1e=k5GQ<0l562>wZHK=ks4wpx{ zL-1Zra&qn@VRp(CDq=jEixMuz#~-)jvUXQ6u1=tlnr`q6XOLHM2p9a+x!aNN$)>y# z4E~q^!Gk@#wf+*^gv&qh?4Afv)_zIz{X|gKuN?gnO_tguXVF6wZlVE%!}v4jAdFu{ zzRgJ_mETiPOU0R*F3v-<+k5aweFU7fOk}Ji9`*ZIhXDt@=thGFBw$N1-5X|!pZ=@? zt3gk+C^-&0?}X#zxuK}H+6|=NmB8}uAUN3R#~5uKX4>T8rbt6hUB7~+s+!W!U%7Nc zPdE(vCz2DR(@9czA$Gp*qLFjbc#i6opqv}S)}Q|f6Mw;UhZfAnM;NER15&gG@b_{X zIH}FYa}M>;+~kgzFQ?+a-Z5nV6K`}_&;%{>wxFx~G9V=$@a_3md{H-_Ed9I#xzqRH zoSZ7xw(BncnZY0QzaT0so0-LOjm^08i6(D@oEl!K>m`eAZ_)UtMR42pD*1H20tS>) zAc$qPt_Mhh<3lI#3!4V|dnMudseagX|1>EwEW_g)_JH0~1<;t>NAi^OaC}A*?pWmx zX>(F}&#up+UeC>zVoMW_J`{nscZO3)D})>8SAlf0Cv|*ul;~-sVq_D`52-z64D7$e zdP6jEQd5FR+fuUVy9>TQ}XvbWl(eLJAKI2$B{U^p;n6g|?p(=NTETsmE!@ezc|Tc3xDUGT>=L3gLdU}fJH*sSmzHLh!AOTg|zX>QKZ zIglY;2(|~jK)y%}1Vaca&(e77<=W`a6H#z3r2)r{>3~$mAo~*4P^5N}2@1N>aKD~C zOl6&b({H=5mUVS%pI5`^-J+aerxe%FcL}tGtcUD!56Q1F*sK2$jtkFVo>LcIj=x9a z(wxvJYdN;~cfyMGiNLWJRKkxC$cXm^73L>g*svM&S+Dw{?Mq0o?N+$)Shex^+!r@tg12w7k7h#!Fzt2>0{^h-ZR>4ur4AuAhJj%J>z3jrjnwVKY;8De)c1t6T|5BnJ!#yL+>q=-?n?lB(R>eE<$8nd1FDzr-$8*Wqpb(V@Yet9T?Q4vSen5tp zxOL(o(KHlpnMMS?{_wt9N;s?HIGnkzjGJCffIZ(81glN5sM(ANJkV(Z3--LnwK;#N zbNgB}+J-RrF_t;hU2w*|jgYc20Rw0Q;{)Br%FPu}{`?zU4>o|q$=!ml=N;jU>2z?u z(T5VZx&_f$lF)A`B$I?IvFq9rtm)5#mFrw^Q0=%N{Y))1C z5Z6k5EDe}R9z1uWKh^e;nO~jYX@CPxne78!H-12<_B)8&9YR0dO#zjUuV8w784j?0 zqp`uTVAYj5a6mi@$BwT6`X_<$dlup12R7&%BY~~$?$CMp6~659!OYoTKyJ65aPbIV zaOch^GBWNjo0W-i8jdx58>eqL;2K5UZL5e{jjV8b%}Unslor~Is0rPd$suJ7k`!ybl*IchiCMqNJ)=Ot_*?LRb*L6+%zQbJIqt3E!DH z!MwgpxU*XY^+n^T`-ht#uM$Fyn;prZ1?z;C+d<=(+vLC6qk;s5IFd8E5zV7@(JIA* z+FxM~j+NV~epCm2caxpJ9-F$nY) z7rtb_bKfg@m}{B@Q!1BY#RO4q-13#YaHE5m^VJW!Ja<9xxdNQQ_EXKG7Vu@;T~PWs zkDJ1JTFFTqOje15oE2_x_I4I?Q#?ZNsb{fpp$+VD?ILD&0XU|}8lT$J3)Coi|-O3ACd@e5aBDq{-{StJe&v@ST#CLch4Pi#@BWe&^ z4-33GGUcTS@v`)W7p;@%(~aV|%(sxVe`np(3RzZLOrx{qjWAyEJ5Elyx`+pk#X(i#{vjS%uy7 zY^MyTzqb{v|MLI^J5J!iPsd?S3CC$y;H3n6*j)IDc0X!{Fpsa$_~t$~JeUaDzdxbj z+(GPp`ksHL_#I|gg)-h^5}2M7pi(?rhvIKR^{2Hs=7RvYMX@`YK3|xtVvc*mpWsI? zBMiNl2@lM7Q!O)b&Te!PRLd&EQ=>-Q^7SqZ&b^O@K@xPzvI3mAMiDhHWRP=XQ!w#Z zCmi;v$E;s1V9-wW{gnN|$3Ya&2ryb}1kL___UA(E@oi<{c7gKqLAR4lE>xpWmV z{*j6$ubseab`!r_Z# z2F|+h0TXK_xPHwTOlEzq!E6QYwPHOj6?p>H??#cM<}R2VVNbTixZsGz3x1~QPhz3@ z5<_+C!QWkkyBfCvEA_9yb}fIj7wp1MW(jot_UEuhHUtl^N}}!^fiyEX5?k$W!Q@+t zhLxS1t+ z90mqbp2GtL?$-7fxVWteUaOy?L(u~eyu$<vU!f@4F*zWlo4G%2`iQNJgDoL3+1|{(B?42TUGEA zi*BUBmf=JEkm5|(Eu#fXyR_lQOmn0QY;e?}e6ZTF5LULA(pzk%U#GZ*u6?)}^gNt+ z&e`SUFg#i{M{)Jx-QfPRD8HV-MMZBkxkc z=2klt8rY!xwMT$ktI^@(J(PKm^FVCg#LbI zIOqEv{$W#R%n|7le36eQ8GcJ(r>z)wdq52{gHbRiKM!I|)WI(|8gftXqT-M0;V3&- zZ@IFA%ox}JKJKs4NZ5=Q*FAz;)s;X^*eoLZEU&+x<%n(#Fy7+@;?k>x3tAumScj-3pC)ZZwYp0*kzAVZ)&Y+_|xzST3CmA2Po|Kyw$a+Z0V2es9K}MtPy* z>0&tlw}=#mDG|M*1bWQ76617Z_#Y>!WBu3#u;TR)oGJT-IVu`(a8(^FiQWY9ic@gq zmfd8!c^CJ0q+gV950lyF}EHPo3^ht z{s9_euaAMA35*??i_uaxpxS#KbaW~N-FvcNtGodTG{}Xy{BiV4FU6ENGxoDP<0NfZfXmc*;67vwVWDmd_~$~Z_@2wdrj;C#Gl1s zxOcQJ2SOg+i==4Z{~2#S`T`F=RKg48JaBt+2(l}KAstztqs*2hPwgNN3yPt!vJ-PR z|3&MOD7Y5Wi~Z+qXy52~e9$+D#BvY@Di%P*9tAKkx1#SPLh*`xIUGA(13yokgemu` zcz@a|;p)0dsM^$wAsycE^xX|2b(CWq-UpDSl!%ErE!3UciGP{@b5DpW4j*M1dtE7E z6Y+)Q-IF=fugP>sW;%%W2QT&5A%Ktnqv$;RYX1H>UfN1ZSs{C5MJV0#zTXfM%E;a` zN%oA8c4?RPRB39UbeHWW&cUf>-^SLhOorOVaF$l(+b8X3SC0pm&d`y_|lyx9sFv-q6K znC)2VcMH(a5=sSrGoHi_m}u;Y5)z*<(qSVGeEvw}&nnX0w^dOl)e#n*2%+BE17J0= z8Zus*foo_0yuVQmN~7!Qxt1#pUI2Hl6(;hwy;xa{#&G~J^G#s@c(dm%eQv+x{FL7`%axH68eClN(fQX~x)EcIEhB3#$nsyZ4&YMh_8wTT2bu zaxMo;^xt9m$q^80`V5P#!mwCrJ_w)!Jn(&ui)Z^VhI$YuTm2RCjIuCk^dqj9Y*0@& z6ykkOo)1;#99%pg3kp7h+%GfDne0>X)qb7qutSJDI>@6_?Eg>-n~hI1gXZVz$RdIvLe zcSH570{rnf9|8nQ!SmrD_!e=cxTZX5R)X-({UhCy6o6fsKp3X6t9Cd(ZS8hYYsp8zMt1S>Su^rU!ScBWQGic6c(cx0_Vogg`C|@l_|*aTy0aPEBpm-6dWOfQYeV@Sd9q_(6~f$a@OW1#+mR39EBP(z z2eUSycls54KXL-d!9g&%Ym0u(yE!x3mXnRib@1QeySVBC>$Wi#<|mgyNDUr^Th$-2 zbVnUy{Mz85@xx@Z&P`JLUoxn8OJYXjYII8eg4`m;e%a-T`=m<1i}4#J6W!p*tUD-u zx`c_7HA;H~A2*BhpPpBS&S1udj%p+eu18V126bvw zTT5a~df@Zi+2|9GYd|=Lo5#IBjB9gb|8kBj=gUTKw z(t^DpaCiVW+?S^%n~qW3`t3s(hTvZe`U3T0E{zuGY2{bR;yV_iJ) z0vtO30xVCXdNywq->g`MB{Sc$Uh7A!Ug39g~|Gdz4? z6cja!sqef+a77o;z^aVau)puU(!CJsR0dB*mQ&9K1^DOiWV$TH6kzKtXtQP?!cC+V zHTUr)?+L0(MB$jx8s6|E1D+A00YLhHTm%mLm&G|xAe4EMEb&ZhV7=%kBgK*ra3}%c^rS=|j$dCWQ z_&URE204vq8KH}VVxoL0r6p8wr2)vZT#ch!9A->jM^syDVgCA$aGrS%+y4qHu-AcQk!54_1DXhTcYLG}3dxGlzU}l~Muibn~H? zCf^|cWp9Ntksaj5&33ZQO_;B_mvbT7WDpv}u4AA4J3N$plv6a%3upH}h8cQ|$V+mA+?l=L zXeo}Xp#bmS3PQjALVS?`J))bi3~9z++#nQ+U!t3!vVH)w_x%9;&<>)yY_@Y-g6QU) z1y>(G&W&<5yLpibb)A}6JUt#9{TxAm`Vp9T_%~fGFTh_EU4kPzdJwfZ0N2hh1}TeV z-d^K0*jb;=&iZXgjPqbg+8QFX*%n7gC}(Im0IuHYqv3vx3A7^&R@L2s{jY-|*mVIu zF-9UT?Tp-;pV<8VJiU7=7asJ*qT1}2IP+*Zma(}lxgtU({8iu%lir_t(F4%wNvlLfWdBA$NH}HfTi*4HMnVR|*|D33&ZGLjF*F+zWW(2ZcWEfQK3kP|bW>l^~ zw5YEn*5`WQ!}Bz#`NsH2OT@{5t*81&H63s$J%+hd4s-ZH^w*_bFq#yP#o~)#t2GDA z%@aX?)p}ab*fVu6+Q2k&93JWR@`mS4h8sOBKjzL@Y)cg}P}iK;y*YxCuFPRDo&XA# zYTR?mw_$5W4qancN1r+EfN4diLFsZo{BTIYvFPtqEUXYVC*{IEk3P7S{Ev*WcftHW zvZQxtI{aGNOiZR_*Dt|Xat0PY*MeECllZEgPa*x9CzJ+`a&CRH$HRWw zczNR+-r3zXoTW2#K;+XHi8~?2JyI#dIqhN&yS1)?>!U;PU+{KlNn!8ZPqn;=@LynZ zZz(!`vSR#>S9s$>3%+#u0nb0>qEEgz#*0Ogs-DaA;@2rKIkp=wO^k%^=ZAO!EWeSS zodqdJTwtsj=s}lW5Pv=uBU~So>(A^NABwq@KPTfEMK9cAH-+9Ue!#i!6^ef}h4`{R z+^|FKHJo4A4a*I+p`ktDu2C!_x{nc{d$nLcB7tQ21-0g(`X9m8TrwS%N^6<*0D0sBz2ngG`gFMC4I)VR^$6K7~}CXep2j0V?@?0r#cfxmC-L(9A>SbtL)s%&<_@9}tW zwiYM(N<%oDQVoi(oAK9xCB_+O)0n&CU@!5LXZ)}XF6`R~-yD9Dk6QMq^GE=S&EjGE z-4LR!Vh?BSJ`k|Ih&rVi=)@T3-dQKmwCorv2hIhXv;y$*issDn4};|oo?+!dd1`O_ z29<63u)Zb<|CGOiXD_ArGt5-M&wD8rING7&g~#e#-IpNg9|^Y)mXlY{v{Bnx5zdMJ zrW=;r;3?_)f`ay2Oi|o`QfE@oA>bG1uf-qup;=2Thdbyi)e#8O@Ftz#U!dH=W60I8 z#z0pKIOb!64N7@r{Hg%F%~s(w9$*}~9x>3|mdDHea2ju&mjiyfJ5Mph4;|}6AhbFd zpR5$+r(`zMygh9YU$2164*6r2;t~35%Mj0T-5VlCEE%(W21aUaBk!Y*azaF-fS2lm zH^n#ep8F_)-ytD9AI18t%eUZkF;_62TLulSE}%R^oS%99CzEV`DX=d*uX{@ZItbi@W0Svw&9WRc8w$jn+Npr| z^vINm{V=F9&hl*aSjjp*+D*EgKYznO(@YNCSD53o=yrVjdJU-z>_i7`t^+vm*3uv{u}FvPJ|{JN2}t#7pZVA-4LgoO~v~)?0vF* zAFr&0`73_N@_YNc=D|BvVX!glf;#4YEb zs&_F?KQa@MWzS-UR^Y;a@tC=_505uXb0gI}@$6s>S`F>N^tpA+U0r}JPj^6HLov_g z@k|&jUrr959RclYIhcJ!i0^e$iskY{P)}$M&MdS7jia~WTU!7qX}-nJRhMwj*-v!R zBTrPcXh(mQOjsJrI(0K0h?>P4SYjfmejD0x@?{MYa$+{`+O3Nawl;+t{=ZvW8UX9w z7K6nghi07UhvEcpj9hHbGT7g#Qf@jKyhA^&}TQhT}!X!MymP7RzKJ z=y`=U{AcqOua{_0skfCp8ts4$8a$G%T}GU5SWp|~14L@TmgJSD(z|S?{_kcA)nkd& zr4Nnis^d|pp0OH77fpp-nS02m^JRF{C=5b8IzaSU8NFvB#@x2PxZPkIYRaU88=k@q z|LNi;T|-ze6@V**G{Aq=2~@XX&xGp=uzt}O{3_39TnY+6uV8pZ7l=ho;I~-x5_6M-T(cJB@eAuHA0NSTTZswlP+i+ggsg8o^h+R} zzq6j|e-0z3em?@?VCEc_VC-hjURZK92mdIDaydx@u;4dia5j76-!UQhB-w_2rOd50 zJe_a!t$}3g+=H2k@3HE4Hggb8=cS~T!LV^NTskIv1rMxUf;Flv z*TfgYZ;iZ^o!t^}BgPZD?;qglSDgVdtuWSg2_?D;E;#Kd>(Beij52~ zXK?QO6hNqQEw=d0p}IPCshHk~ZFYai^S>)F;zS%S-P1#BxRo$B{T7-Uc!Ksw1XS$| zq-*XwLF&dHoaVF*8rk{qzD7M=x>}eoY$b_XC;NbA!B+a_Sog+Z;~-qq{2mQzZsW&Q zrIcl*1a(Z=WvtgkBOo%oap;&RKV_@1dSb>J@+mU+XxeH7ZYzrw5_ z<~8VZrdw_|(1jQ4K~`upM9nm%kCG%&wITtH->G1g)^)g+^n)~ZT!Li7X`FkrvtY#o zN%*_$yns!q%Rs7jExffZ zAeA56KygTyKB)b|Jmv@uT8a4bi!{HE(dz?C$0}jsf>BC2U z8t}dS0L#VN;(vCc{1yd&<{M$leNy9!_cbr!K9>3j7!c%pk5L6JO?zylE zNXsBZiy+q9B4WH1?symjSub-@=X4xdt#g{q%p~~+>P8rJsU6-l&7o(G4pW1mFR1-< zE)=Y_V|<0z_&M-BKDUmBz7FM1hsS;%_BY2iI6 zbX=41EnmWU}VO|)eR!*3=Z35To**mx@;zoDL&O`IfU8KLnkCS0P zi*J0e1iS-6VZsSPZjwtIEo1JB4;hoV3E+aZ#?0?)`xs}}&xaf8M=-3!hi*02rg^Ie zVad9iSSXnWNB5|(ox%ySz+xsn5*v%b#YPag=RbU%A%;@l{t+*y6|4hj3dLuSp3BqcyN{*+{dQsCJ=p~i?;1O^y&3@Xt||C z+@47A&zxQXLrw>=XMZi!ZJP=WcMn6;m2?ufWiKkCG@amN1-3PS8#i~7oqFF{FX;^# zcJ&7A^Tn3;l>Qmnh-<|9;jd;B2}|7ocB|A;UZ+T%e<_V;-H;4!f^6@Y@@I6w~E{U$+dtG46wHGavHg1Sil-iA|tenu1r4ufWQ8*5E&M zi1WaC6TId}f!z9|cz(7m?|1Vh_>kkvQxy4;?(aeNa3#O(7!ex@+A1MZXzSTpbf zEmS2~7JDaX`)Pu+Sp?>2zW`H@&+th80`!fwLj6(%pHjwOvwsE=oU@Q6E{?Zj^XdTNVTTCU+5;{-G~att$B|HazJn^d2$VvtwDr=SWPJ!q>rPe45aeI>XMOKX8yp-8hvy>s zILkPJDE|3^_4^#Lg3H`wS6pG|^&RAyl^dMDz zxEhg{m&!5kHp}oa2dTW#DE^vPqJDV-rH@i==rN8RDE)Vs?idau|G8DuuR$MiO-=?+ zPtF{SuDWA#b|T9utS40+F)%N%6nC<`OhD~0dZ_NE?`IFf1KUoLY}Zbczt^HG>woUr zIs#XkSUzU`W9Z#nNMz;>L0)$`OjWA^pTsS=?P@9M`CfrZlS079UIt9qS>5KG6HHH9 zj5Fm}X0yr*Uq0^yTAIHav5Crg=Kb2 z4#J)KFmjvyfBd;PiFc%F1!@a0pQ=A&%xY}sr1wt5Dar!4s?ig36D!fNNdR4!WRifS zQ}7|5F`-^_Y1mIkUZ?H|zDr1=ooiy?bOf7C)J*5kzs$~6ODA*37S@om9U-vz=uXq%*RGQ4hQ}k|klZ5t+*OGp`+?r&sKJO4 z<155$!KY0Xc(SIHe3f{P0W&MHrrHiZ1eCJ(Jxeu0O}MEN>*gW=!p>!j$}FZiD3 z1L>Ex@)EYbN8wBUIIF9WWbNNix#ulW&esn&)&9aK(>>vm=K{EVZ5@1fxdz+lZ|FQ( z3MGNIM8;th3kD`Zm**Msbec6-H02NzL1*|lb`AY!ZUZ@%u@dJ5;JX)1C_TFpnnp|5 zJNY@LOa4KA?pso|C^r_a?ub*a)*-!{sC_OLE}(bp0mYT|*@2 z+6Ok-ehQ7t!tqO{B{WHwQSGt;?3~K7ASJFOq~#s?pkf5`6-S6}>3RH*>q;k0EFiB= zgyYd|?7cguA1xc(iKBrIt}!SEm6P9bdifW$x#CNIX1ymmi-X|!uK+rIBIC;LD8|I_ zdVKmH!cu87cyuxzFAol*=@|k3vZ_Gp(Dw#>q8C83FP}W_oXg!F>j`s~dE)!UiO8Sn zMfR;_{;mDYSEir@qmKruZg2q!v0M%1eeu{ZVuLn!p5c*AA9%9DX(WqfC4D<3A%5T~ zDu@U05=uCbwZ0b?Dz`zb)OGZKSWNPrT41F}A2upz;PU+u&?n3VEt$`7GcOM{?xhp= z+|3wsIt3by`_U^@2R<&aBeMF1tVZCi?;BrH3yZMG5-?s&$beteF z_bKyzXj9vP6*!!g3&FAOXk_*a1LP!#ncy-qsbo5YpXdO=t;}D4dYr^tTjNoWJYEpd z!unStWMg$6s<-;#V__3m)%pt8ynT+_zpR0Yp1R=Ya|Ko|&q0ZN7kqbn5-!T^p?`(V z+3c3!a{Wm}?*}{oc1Mwwf4xC`YaC`JU7}ylUIDcm;`C&}UbH(D3g)hMkajc@%bcBv zvg>z9i%v(?`F7N*A)ooEDqyFw7Dh~bj2e@A;mn6-w0)aT`IcT-DC!6T`x2ql?E~C< z=|siHV_?<$m6%fL2z6|qAiQk=6rTpb>9-Y-c;FH81KaTdTEOM;K0Ft45o$W4Kp@D4 zq`mJYCcUR1JSH6FIjqb4Zwx;K^w6S_PB{Fhie_AT3lZ`Sp!bo&{)iAL&3X)u_@FHik0f#F zK0i|&*gjwVLd|SAZjuCFxSQz2uO)DXBM*D~-ok?F4PgG(8m5M@^WEK0vP%CS8thNS zR(*HeIc);t%BG~wkQ9MO;jJ(`)ti^87Y_m_M7b4P%<+}nvy{I^tP7WPfrc?peeg&W zMkF1@wY5X!QkOHHqK*(NqK?~7s-amxEt}E5MY9(JH_`!A=KR63$_vk7-^OddHX-${tG!6uNg+? zcy_~2k&k$v-9s(Kld;{|gidd)K+f(ix_MF$MBHqHv@J@QG1U!k77L@qx>B$SvBgjR z4tVbPUQU#b2Q<&kr{5dm&~)<)GWh#7=H>blkNOghe*{~FYVK8UwfM^VF=6WG)dykk z9T^byv%lTcXX3sRT`y6?tl&a6J-wbKWm43Cnr4d>y=asyc7Z4cfq zKT&pf3d^**z!9Ho(9j@@HGreNZF&wqd<%p zt3cbVtMDY3d4tcTZeRdf?*05|dms91$L9;ot(WTe{q&sgxv}z3e%k!Mb%{3K3t2F&#`^MJqpjyokZ;Xj`5Saa3^m$%CDS( zkL@m}e%YX{o`2#4CLb~c`<1nH<-#9e>Yxc#%I#RDmJjETH;@~{aj5O!LjK6i!1*1I z(79iPKYMo}*|*|09ZGM9ldn>t>d9vaO*oP2Y4IOa%@xC!hhX2!FypS7^b$svN^1Cmt9OYD^Dhy zdY2$)nln1@s>bV|+(^yob+C%_4LU_9b9av`(8)cs$keEvaCE$p+^Mley1@g61Gi#b z^$<2baV5)q^QfumQ^t2O#mUxw&~k+fYy2j|>s<>makn)dbc;t*?K)`PI0RKq64ZX3 zJ^ZRG!?x*R=oWbm-)H9H#8gYV+2;-8-3o(Nj339|HHY}}hsc`H)kMfXGsW*|D>(ZG zqDNL6OiX!zV*A%Y@0NCIy`~u3T3^BYav}92Fc+qOOvD%=12Q)25%?^!VL4w%)ax`u zwHMP#@Z*Q@z>8((`=SB&4`I5V0UX$D0$A;#7JE*EVE#Bd%3gwSD^YyfTmioC)^l?B z%7H9j0j6hCF)x!PX5HvJb}HFGa^z3AmAZAypB3naLY)F;4f!;kRUBum{P z*8yJto50_$G>EoAJ|L9t#O7f2MB7e^`>gZ{=vW5Q-Nmm!&sLD@`|2_LG}%Ds-`Gs4 zco9xeY=*s)O7OO9C_PX)4+f<^kmPVvcqC1cxEzOZcGo>N_K0NvTZ+}Ei*Rd$68x;B5}ed+jWsfP_)eq@^k#;k z;a~wzn683pXY+~elX{rwY7J5aW3Z{C5o#lcFzgIta$L2dLA+kPzBvU_k`|!nMtkUr zE<(5KJX%E;qw17GcsjSA*SRwu*RLn&V09A3q~qY%ub;dx!l96B^@@JzD+SJ3UHI|x zFnr9mK+ip_$L+;jJ11{J0Q+8CDDa|u=%JK#sXIQG(z6^Vq8Bg3zxCb|HoZ>31lOa` zT%AL+ymd*wEC=#LmH0Q;i9&V!4Y+jN5YJ@W;^=TUJ*F0c*4uvL%k4Z^uU&~s$CmRn zbGtylp&kDdHN>~td6=+Gn5*>K9^5Ohq0rDNu)G-nFS{ml?`!Z-@X#UD|IOIbL5`%| zun9Z53t_IQeWByp;m&y7i7)2X(@Df(OPIijfgjW%8}F3@wY?35cR+iY}-h-FLw>Cmr$`+1Blsifd9Yw@VDNU>dL*xomT!Jd^8E0d;8#-q64IPttNX})?!3o7VDLy z$O(<_q;OgT4LtUobXb(&g$pBe%E4ni-zQh0Yx*NxHi_Mz=e2{=L@P|o*og^22}D|1 zjO%ro2XZpXP?*C-2Q4FbVdM=9r-q`5TnpUReTh~U6{$|W+i=~S1#mb%2DBu1;L|x@ zP}Oicn>*gdM~fx68zL>p3^f7n3UYxoJWC+Lb`_|s*Fr{o>hWkQ;+Uc-9^O!bAHQc1 zwe3fl+bx-_EC>XZuK84P$~HVY=>Q~rw8jUr`E+8WAKXwA1J933aLU+Z%vQUAQu{Z9 z_DM&w-2WnG+6!@W20LKij1Xvc*M-ARTX-C!N_Z$E#wW+b`AhZ*aLu$^;fee`l)mhR zqMbaTd@rKq8xApAEo5@5Dg3ojU{0saFk@mRc^F-e(pfj))lSxTj#|lAD*A*9&r8XK z{co{o<8Ek6P=P4PV;n)jZ#?bit+;e+HpbLcfXbz6e7MwlqheMmV|}OLXo@{ZRf}M$ zUKkG9Erf@07NDv20oFR)ho*rn+_K~yF8JAr;jClzvS9>&8S%h!dkv|%8UUPA%H(ye z0jcp*f(u%$$R~r~pYBEUvoxXKlkqmsO(KPnu~;8?1ec$d;MX_yV04@#{puNPcs+%; zvEc%Io0kQV{Vbmv>V{|7-E)<}1ALp?OwA8{;H;`?fge*siHdv%^~k@@m~O97I$fP} zI%W!WYGTgM+a{oD)aB)<&+y-D*PIpp;2;=7Mdw>X9Jd zW*y`49kGU#y(Y+QV%>-6Q2MN=AI3i`l3khYAV4-kqx@@VU%n0>R2ZR)Z4lO7U4rv? zQ=nqVj(G>}PyvStTs8Oo*l1maQ|q!x7@NI^X8i&+i-)MH?t_n%e_-%xGxFF`8D*U- zvBUcltUByR8mtGfK8ufU>oU;z>Hm3O`S7ar4}G(s2j=Eja?rya3mybP&G1LCY}Q28 zlSN=5TmU+gUZH%`St}CN3zeENq-JauhO95EW;R18QlYycT7`iXXpRF2=8oj${%gvK;mU|b9ns39v z`KzSa)R1Qx+5v4&lac#&5wt`-#<2~bNwi%V;VH#|sN)UZ@55TW?fu8e*HxjUCW*rK zHUaKcg)s1F=kRiD+`qPkXU| zEM^W~3~A!n*ScYJekZ)R_7f~eJ7KP~8xE!qK+iXEI_bnSUjIKsuyHel!K@`1oN^!N zMqlJN_o9>AEc~N1&UzX-z@II^@9j$?I_I1ru4+GyI_#o_n<*Nbmw|E2J=k)@03`Fr zNugO8sagCP+hVgYX6y<<7J`zFm2V>y6*GJ;5Rsj>=s$rtDEZdcM z<7l1>>r?!I<2qfCFrEi#qA##&o;#Q&%z>wyYSqVB&c%XmNIhfeii$~5p!c|iSM}DM znn`Q`jbd|Do)t!=Z%VNoQ6P$Bwqi`{3vl1yP2ZV#!K!^}D9+C9U3D|i@>CIyc1B`j zr7vvQV~wJ*(RgfVYU*+6*Vw7=n;0Pl46d{~~+$;|Oa{OnNQ@{NG`OESKy&*CBdmGW-LIw=Ze5c#4YIEST8450*3`_ocV~W3F>fD2-^vM)!PSL()VCUFH7JvVW z!6LS)=VG40C22wa=0_($r__`~rb}}V%Y|c&%XGX}?Dzk936y9D!O=JSq3EFs98Nq& zT8g&e?ILaBc6$g7^gn>gnhG#i)1onJreOLqQ?lw`4@ntZ4r6_b2q#$#*EEKq#xaCr zR-^FPI*yiKn#f%x>4m((Ef~xAM$m$u4#v7nOk##>-LPT7+*kLyfBN7&l56abH#pYPEOZYh}hpY?p)&KX-v9 zu4opA->P@8V>FW^G5;x!tmp&F6ASpne~?7S zJqBLm>C`!S{X|9gB7crH%l=~>`UjaZr*i{*4q@(t%2=AKVF6<@J@Beb6<=yr!I^9? zT<2pBd+JNb?uaw&cc70q{RR1IA+In?#}aqp*Qd4nqp`j4G`UbJ!p$AD#~&H0`145*?|X?i z_@~UnACsJEps*aQu$Y5w;$QIe!#vo#V<~zH#bas`^IUA3#2>ov4($~FO=x_;NabNxTGu{H6EUaOq*}aZRLhKd;Xw^ z0Gs8Xo5auH34w939Q@VKM;&zw;vGRDWLhgI4@|}+8Bx$5UQWWF2|~yd9>&Xg!Y$P< z+?DAEE_Y+-;MOmwt64(*y-WdZ%pi2<2h4VVheJ&vxS1OY)syycU+)>E8%`yHiu)z{ zzUMvoN=IQ;@pt_Az5#m;jMSG3=AfoC>7^IPlDIz)KZcZA!_$?UEk`4=4<$x#Gxv zXnH2X-B=fh#ZEgh#XSUb%l$b);%t9#z>Wxo*~96s#Tck5$Tf>R4>=}?L8xehQ2DOe%SD!O?4xZ0Q#;3|AjJe-SZr8jc0^9mX z)pB7zpDTdVY{Ssr1+n>*ErbSsKxO9kEvrvq`*K}gTuz_ZN!y* z-MFqH3DxH{LD+vs@Pvc{S(=~1GQ5Q(^msmKR>oq8f}MKb*YB976@iOB%HoP+c{p;W z3}sUu(%bvi;Yt++YJK4fp0qUIXuRS%99^>owfW3T8T*KSn>>+wC8Yx&7EYpHKCPou zL;`7XizoIrEhk|!lF=%u7gXO1a%~`e*$%srk16(e(Pa@SG8;h!8y#@b zZi2aF9j$Bs21e^VNV^Un^L#d<%;u?lyNBpK{>h&UENAS%bsf zSMb~#TevPYnU7~mNqpZ*ICJw4d0{7mPwLIFX6j6Cvg&IPeImfk+L4CUo^K#;$`Qf~ z&%x>`rEuX1V+woEqDM7^`F0Pd;hq-8g4)rKaV*Dr?)piG$y9(%fHr74hcH0KAv2Pb6gp zq4XgS?Pf~whu*D)*ZK>f!_o~bo?eEiu~r&q&@b^`B zPNv=oa>jEe2HtCgaieV9<9UV}%PCS1>0jiY{dYLJFaezNt?**OHf-M3heF>)xY<`j zVY}KX8cbVo=EJwtVJ36g3yX4%*!RHDm~|%3r^4;L!+1dBJq8yPLh;e9sH`6cZmWg( zJL<-P|KL6>7Tbfrj=e;qFJi=t;|M1@+*5_}PQhpb>w|DQz8_uo4#>qK&B3**tpq+t1?Y;nq z8u4a~51H_F7EC_181DEj{pyB$tF?q4_u9Z1IL!l!GgNxr1SU8BU;Ua9@xa zzMHd+{MGaYgHNC7HkOwt{TmHQO=`$_A_xPCa&)Wn4OEZ~rw6AN!KCy+$aftg0?LlW z!!wRz??P@yjS8)Zzp}A6hXWdQR%pgpByG-GaG>HRda4xA)3YL3_Cud)Rk-8pi_ZA9 zYatkzPZP|j2ifM$h3{IKs5~%1Y$CYEhA*p&6^{;Wma<+5%ZF(INy2?qv4dXCBVu52EfNk(e3K=_+HY&oPsmMP2g z@9nU{*Pl{R& zKiBJy^L@_e`F!4=cPl}@YYKW-eSz6e-$VSoi=?8k9aLKPLfLFhP?|jeF?tcu7ppI%f&)(8={=Wsz_QToSd+r~CzGaggS&;fJ_DW**!2)66kVdM zBM=XKmBWg~zli=PEeLX5#Us~0!Ik9>sFnAPbA5XzETExZ@0N$)bJH}uf5j1%ha2z|=QU1hy#g;v1o$JdNti#g6}Nsl1Um6Nu$2wMZ_GpG zbh{JBW<1BGK8%A)-Qb!}895WtkNcR{a$nh943=mE+c(jmxcVAIF}-hRKr3lKk0`cu z1SbzB!L=nTa9U#tdKyfE%>t`%D->%N8G#m?hF z0ZD%9Od+l{>plwZAk^WKJYLQ|1XfYs;3_FXtA!6icAYxDJzoGtL!a>9#dB!FZ6R{L zl2j(+DdTsmk!|`*``Og?WBz=b`S+OwPRU0=BiJ;c2JjVI$ zZcEI{xhYI%y)q4=^DIua*#}1+JIM7LcvlsoLat}%&mU3i5z|{ z3K=2-{AG3z@!M5R%y(N)<~Is(W$vfJ)S@U7f9@w;%4Q+EwM;9vcLBSz2S6=19i`^j zQitOjAmLCHg~6; zB-e7HOGfw9gW&$)0W@C$_?|Hxz29VDtqf32#<6%XXaO0=SdP?pi2PXRgDaeC=$>_J z;c#CWbWXNKlgzK=P@WQ|bA4gaHbb&NHidaXKSPX3H^AE8P~l+-0#7XPjOuM7{$7~B zL}{4u7UvTCl^Njkdz36~=E4P*XKmbK$7|d@8$MeLf^yOTN-O7*)L}aexVjkAyIt`! z`!2_;vFBCTKKNP`0jGb}fY6I4Fw)FAP@I2bp^Q4oDD?$NbuYNZv^iHJ#-VNsqyHX= z;V%DXcv07h52o^<{WY`4A|qi-h{zCm{Xk3>=@l4=jRXp`eh1 z5&neH%Z1TVfw^QSSNZ-j;q6}c_Meb8NrPtP3D z`LJOYR%S}TLD4YCYz~47rDz=Sd4WHVmV^8^W2kCzA^k_LLRG|X+~_)$Un=E-Te#5_ zViVv1t4&x4?ld1 z<_W?Rq9x9O;lFMeWo!*3<|`(~FCb(09^uG;G2m+%!)9qMu+4o1`jAgH&PySGFNT6- z1`j@(J96}TyWo;!G`=}^92ZShhfH5#`gpk{#D0s0SanCx?X)8M`J9=4A9a)_x{~2IVg8|vTkH%L;8NK^S~x=n z`E@yT(a{l(n@|Gue({CKdk?U&BRQk8--o`~Bg)^RI}ID!G@$2jEv-1`hf{9*(G}~~ zfwrC)KkD{V@DS0#c1>YiH&6@e-Cj`IcMU$8&VV0`AD*+c11#=Jcn_}o)zP2bS!$E28Q;E?C!_d|7#c~E#QG7~YN?3R zkACFw!zppa;xo4AB5r}lG1B7{g3|*V$kdT`P+TdAnn$)`r?Vet zo=upJpKmJdbty*g=W4i0=>=pz%A+b_-$lFLATrpRtz)mX=Ner{<3^17uBURm%363 z(IOm7ya!KQ#kjrSFVPD!7vW6hZ#s?bN=hX)d1p_2!@j+r@r?K^j8CkhdoGFaM{X67 zk~~@Nkv)R^n=B)1xONydn&*OrO&qGPI*PgH)?hD8<;y}R2J-&l#&3^6LD>)W?DBAJ zl{9i!h;X;hO#;~#Z#2=mkDK1{Fjcb=7UiEq*H$kOI#~ie|MFpjuN}k-`=RH+UtIa3 zl4Tk@SiiU!=yy(o;^k@Vt}KMBja0Bm4XL$+1*9w92I2SLsE1+`cwaL`o^udzMdMIP zwH#~3GC=xaDqNR)3s3uRLG>bQEcNE#&qG|8+%<{r3l|}C!y7rhyLO|pS{so$W5!C_ zk3fC+N^Lz^ccR7mQnQ|9QG=6L>5k`(C{;E|=Z@EBIG|Mxx*zv3k0;9l&7Kc!UJ5kG zBANW`c#U!wo?uSiR%%eF1`C9INa3zjwELCGQ=e0dwW_XIpLh#DRJUNen-u@S+7h_2 zr<{aLIRzgkDsi17R^ib5%VfEr2@Dq=fhBz+=za4L%UWK>m_6cH$@H0zix85 z6c#T!4NIeTfo{P^lsE5&8T)tR8JGgn9cSr>#wt*oTtYc+9>vqghX&@tpPOMwBhxz=^!#kUw_|oh= z{djmB={#Y$6!HrCOwXgR_yXV#|HdM}EI7px;T}m|Pv@WM!>sGB98-N~+`@LeMO}PM z2${@vUZRfAR+oeFo}Vybn+X3PM-;q69->WK4U|m%i$+08D0(g#k7Pvi$?<)GyzEm*A*jt8u`;Qjp!UYg70$^BajC!g#G-F$1<{%{1V zzZS!eu>n$UJ_1n+2oLQVAU@{|T7KGyW^*2~on;mN-SZax_Q>*YEbsyupKWBpiOsN+ z=Y%yIEHj?RM8ejpzvRv05)f)gLgeBLT#}w4>kBnc%1751B9n94A?`9=VOUS-}zGKDuMxt!#L^ zqkw9UJw}OH=`dnDhjm}g0huXX^p?^Lk`Zl(Vdsv(=M!CMTyO${!+t?&Ry@bJ?;&K` zq#$~$Lh>3RT)+JkrdPef`YodPS5_AHDT(q|`U`P4*s^Y-UK?nOmc!1q_Sp3x0UjGB zU|luy?T2xob)GEPY>$Coi=M)9gO-f%8tHWK&eaZ@us>5+)zP!7=2EyLggLoKCB?f?@80ZC$0MEw$mDQkDdbQW(N|pRv98^RpV3j zKG@(Bj=Sr{GU$FGZf=_fVoE#i`|OW_k}WvTg^Qmy`tYJpl%u;~1`3Hg!O$NmZuc5n z%zTl^x>^IlphFIKjy=n;;D$k*k2PfcJPxNy#QA9=4LsE}*8Yd{VT9!v@^#l_~*&H7lIVbg2%BE1BKrZJJ3h=4KA}XEH0oIXW(-?( zU170a4K7Y|#paHIJkENvohoH7W zg1?D@H}@-x^ItH1zVxaiCQhCM>x<5ys#iWZb&7HistAx32lYWc<~8nF8-wP7KDa0O zA?S&V;*&>Kcxaj^o$$;6RJ@0&HAj+0uJVS~s8X1GiD1R+eK@6i1e(v6qs?VGZhz5g z=#&?NcU+Q921KTwUUz-{YK&|v}g@vdf>lC7QC6m^;N zJtGF=*>`?vOD;&v^&{>_y}XPs@fBY1sj-zQhMOcpe6b@&^p;>drvfGx zyRi3-WssTzh*w7gZ?L%%r*C>j9&2Tg(1L#Sy#0m@olxU%ea|QB|4MRmITs;ByBxNh z?1907RMhZOz_j`Gkl2@xPbXAjX^#yAn6VxX-BMJlJxneReuBXAWi(w|nwQ{~42Atq z@XO8#fTukWu$H6x{WJ#rxdmzhr!h<=1+Ps|CMB+4@z@7RZsVOOTEF)lT0Z>(f1iYs zx5h(M=wc5&WI7WQj_oB2mi$D1@g~OodW4O$Bf((R3XEnxK!vh%WCk)<{J~*(sdX7j z`x{{PL^bGYlg1g(4nmdW8=VjBUvc`%vvA<20KdK9Hne*g;|c9>xE6L5_i}dQT*kj~ z)%(ghF;$*Fhp-&gg+E|aW=~Q){2`gK@qbvC@}`>z@hkJvp?psRR2?aS8Lf;{Vz3HS z?=@ru3oPPk_X^Ui86^-UI{-LdHD@H1Kx>%f>tuhWpx^4ljdf z&oglMm;m=&Xg!{ew}r#6F5uFb2D18|DRw#)64z@AWNw%h>3ScJR)PuOtC5KdD{44T zb*GRsk7W4XCB|4~nTWpX=g`?-oa5+!AFb4vK>qu;jI}Gu)!pa^v2mL4_{nDU-(o?W zJnoaY_rd5j;T1MrEC;I#Pn!edimcOl63qx9D7!Pa-@m4Gk=+`{Y5fzDG%*yta0k>QC?V?IDYExrkCm& zD^;i%lWIyJyP)N55l@v8Ze>f6PoW1!+pp6pw3E}T#5_hDC*wE zYfC%nkLF(ZIa0*D;9+R4G=u}E|Da!B7v14Hm8)A5&Wm}d4l4EsvCYB(XzOqEE@R%> zEgSKV9qT7IXWWbredKK0YqH|cIA$nb!1C9!V6Z$IudkQEuv<5w=xqa*DEh;ZqE3sbt;~K21(iruNNm z*?V0;&rD8&Al`2}uWUIKoeF|K%aWk?2HTn0I>N%(7i7iD7clWn2rcKi<3e)*ej3yC zQrbS@F|7gmOLZ0Ere-{(AA-Z}Mr78N4;WJGNzNJN;Hqh7QRde#tTYTm8Brl@bNmD1 z8cX5F!uMD^Z6eFMJ|N*g1o;uJgK+FpHns&l1cN)D$u*YqyZF=vWh_kaNVgdOfp9%Y zTc_ja>wDl%!$UZy{Dt^OGS6PJ9H_GuSTEz`ZIcNBW5bEuu9tj{O->A+?79SpTka6= zjitP(my9R3-vK-?aEK@02Q1BkVU6|^^1-hg)f0;#_U9(3dmG04dsi5WGaF$0{1v2^ zb%8xNrHQwV?BLCPc7`U*L!C<-V8e19tWCZP`Hxv=VKyJ@48^z-yQYIr+%=Blgk|u% zHv{#z{)b(!evtdl$!Ox*1@3`T84kj;VfC(dIKO!U_dH|gw~P`zr(Fq>(#0%~`4G&% z$#aT++d|lp*ChO^9z3tH!i;6sl%zz^DHh>qu|c2o*%gD~nwz-6Hx`n<&F2^yB%+yT zJ4AW*U~z9ebqmM?x!Xn1-)svjRUV^-L?%aPGZ$;d-@;O}J#d<GU{3#f0 z=R2U@Cu`bLp#mzW+u@V35STfK@V2bzfge}Tku8i*c*r{koDE-ruOY>k^0Gwm{VC$2 z_m=Undcko(5iWYQfd=?v@o_tFx!^{xd{4p|BCpBq_(-f*kl-8h)??|`R{H+T8Mf#Kw2Pv%+bHKrnD%?7J2Nk(*VCTIi$l0@!MyPq> zK7|a35s9Yr*uCViwJD04yiif zEUDLk^_kG#k%%w5UZ93l6YGRcMX7%Ya5FQ5Oq};qXKubLoyrS@UGtq;XITc`7H)-( zVqtISzeW3bAg9Cb&k7z!>j3T19uD;6lb~FM9?SDzEX`@_!I8<0JU2w!mlJ zllba^j3uDV;ODm{aQnon$gx~|^mP@-qc`W!Uk1<6ixISy(_%5+nRNy_xzVV(+7CRa>I{IMxzC|WA&N)}>BIM=iR1(+ zge}K-bmq@Cs?s@}p3-Xp#kHO|n|ab4Z5}~Iq#brdCcxnc!}PL2#^(G!8(uvK#~Unf z6Z>u<$5gS19@*v0GA%pl?eA;x?k5YB+bIFPZ#+qe7Z-JvP0>^#0#ChjM{{*uSbb-N z{r5w#)2tSBZ+Ft+_ueqK^9W{dVZC!l_&D%q6e^nCQS~f4i{rlFF3xTIV_pIOZ8?p> zaUOJ-`RHQ*n~UX%=Rt4r6~^te!?;z7@N~y^BD;7Duy6FO4%zECoi;B|UTjJo{rhWMCQzKom*Mv+BtwO66j4|fT z#lqWJaKPawM=I*8uY-ca3t9fV*>Zft%UT#5vI+GArt+Kh*OIR-X=pvBOpldk zn+B|j-MD{;GLzXzvE6=Hi>nf@ac zz+!yNyA=WhMHII!Nkrp{W|*8jjOWy!;)bLHdkDgog;XE9VAIVLln@25yeh@L)%uIl{`M+NJ2k3qk&%NVjKW;SP6Z?9muFm z283yOWALIS(4gyw0l)j8SL-7FHLZinGs)x)B!cT+S?=yomahdh7@lJX#Sezzimxwf zEpXvn67&Jn*4NOhSOU)Ld*Ju_ERGUBKzT!HO5Em$k1M9-i70>8XH z!AP$Ib}bO+|MPbzSXV^_5~3ixOB5c(dcw;o6;PfhK+0!{qRAx$y}ttRn9uTr4tZGg z(t+kM&gZn)R-EG~&68lm^z199aNGD7%$xgwa9aC0CDC_~|Go=&qtEcbm2I$#u}ft- z&f^h-Kxj+;2|?qNxs$C~eso1XMoHQda`PlsKAFZjeRC5WS{DohVw)gG$%WIW+Q(Bn zrUYB~Uf93z6^tY$K>ERrP;DYlZb?aUJIazkIgj;Fri4IRxErjW`3#p{YSP&?ngBbC z-w=Nrdx%;_L4N!V^yMF844e{lc@d3Y`KchP6b}zoBQa=U6dkS7qaHcV~k*Iqn6H>;* zVCm}#{Ie5|5;d_3G*}@*3peGnIWvnEX)^}xfqtECacl6Yn!wq$JPqB9?i1dN=QvQ_ z0WJHLscGzH;MV(NkYzhA+c%RGzTJfJ%PBndm<$nlHn3BbdDX1N=^F_NvSI2`@=R+# zcABYTXF?6(y3fMQWjD$8a54T92~WH|*%UUzG*}jS5$Yqw`SPg}p!gyhE|*Dfm^5zRGyna?0mG)+b)`%$o9q9KT&wu zvmP`?M&Ui@F9@fl!lgK2?tHUU8pSh%%E;~5CVdoJN5#Oc-JY&#z6;kHPmmph+u>B- zbJ(@$3Z%F=knt7|j33TnnaVo0E3t!ZT1R-7vpk5A+-lf%=oGAvN<_t11u)=pi-s|# zL+p|;zX3<(hd04(w2~Rs_@hn-6G-Puv4)spJ zO#4yn3-*TBQr4)GIuU<%gyQK(bn3oRKC*o=H-^qCW z3K#Z03PO{H9K5Zw0~C+N;NyD_(QwZMwg-{mwv;L1lb64F>B~<*MRoz)KA(fU()*Ag zqDl9%-|;z}NiZ-~8?>^N$k^LIsKgsW;N>nJmivd9VtU{NLd`4PVTX zl;kE_vOJ9Tao~U6Naj59MO*n5IEmW;{)MU7VK0q)o;AUV(+RXMC=>T}q|xi{i{R{g zb)36s0$*yQ8`-k#7@nG#i+zcnwCwRX$7<|0%zVF@=SSsGf8|+v?q)dTJ(vxKn~cEa zJyMAbmTBO8qIw(`*b$$Fr6XZDVeJG|WxbYC@zuj4ojg}C|bT&903p*p7tl;3$n z&cq@}dEE#Xu4KdBHZ?5ktAg~)vV76~p>Q_sRI! zDE-(h#$BTH5?#lR!?H<|km8gEV-_>Xc^CG~{UE^K*|7$a@Ap!%tlzMC_GB25ErIPy z>2N(Ol>67!`qlYcLM5ItTGMmzYRx#tn=y^km{RR^#6uBClv7J`1M9iF@6CVA9K{LeotA90N z?nEKXeldk_wzdUl^&NoMhs)^mqH)^fcMHV7Z6|&a-gMA9hJn@at z>6`}2;=b5)`4aUtZz3(Cwm3U04W@Yrb6aO>;aA5&V%aOe&r!FhB?9;H*T)CxoTnRs zPOgWw;#_<`(HmyH^2QBjl@L`Q2;cYAkZf;P*p)2G-+Um37%Fx!T`L>z1W)2}jqUM4 zFXM()`M?UR6tq0jPXBrIph(>(;xCbh7j~CG*DGfjvC(0^21jz%gF{{#1dxS`mGDQ! z6o|Vi#P?q&$^E^FWyu+v%3Xs;@5n3Q+u}TQjc-Ifzo+m)ToqEptD&Z1D%Ynvkxpy$ zCvzBgT1Ak+9kp!OGonOP5?t`W<-a&?83$kP*^!M?9-%YyUv3Dl2c0Z0(yKEB{d1?| zBN>*h9A(~e*^dNvGu`9R5@HqFi4JRpN$w3hs85dpzvj%0{GuWn@;ZUBBHhWFn?7Wx z#TdR_X$uO*e@L8n48Fg59Nqc_d5$v&$T$6Y81|{08e8_#Y_T3Z>={HIPSrp?%P?P< ztO|@oig#E}c8Bf*p1g?-?HV$L){B|wB_j)-TbXw9@GGWyd12YD`;d}j1=fC%Bu_bk z4khn`sDst$_c06moEQ&vZ#wNx`V5g|7M1V!g(FAJF}1K8CjD9i9dzU|%&|{dm_KK20-jTA!k;CP7;Mx>Ka@p)_W3^ab!Ocum2>` z^7M*HFtHDGgs3WUzGjv=-Rw0Hua4@HEA!%CV{Jb z$zmA+jAU#cPDU8&4XuKOPlD;QRxY)1FT>eQ640f;iQ|6dIeeNChKYHq_(staCECQ{ z?voIr|MM}rb0+Y&s<4dqD?OA>J4*6)ye5ms&*9J6k0H%FjZA)~iH+_Fytm@4f1+9x zGum&G&S|aqTjo31^NyjBw=w)Z{ub^hrozB752Bgbh^Jmef|s!X-|X*hC{Bw&J(r{K z@xL$VdBqD}ZL8tb+1-WO6Nf@N5Pvom1Sb&`})O zdxn_&jU$|fkDxA<$(#B80=>Ta81R_6;0pSly|3gYO8W23PD z^b35TnFOJ-YOLpFI_n#>YE0Je96C+*VZyro0@it_{Y$ZdG`2=U)`I^kEsLuTu%`vd=LB0=bmt5)Tb>URCV9N4CyOBN<7Ybm_+RMV>j3N0HPC(ePKdNv4cQVI zcy;}C9Py68BaaVIr(8R_+GrcJ`@ME2fqT;=8mzRR=0lrPA&ckjaF!-CwcyAH7))O-l;TgX$`E)AE3CGm?z zKIr8h#aZ8*L3~gRZM_&rcY!F1$Zdw2k{jT(@*Qk2+6p5aBiw80k9)ow;*IOtD5J2L z1Y0J;YZF1ZHUKz_eOA7Evf%C8Yj`+Mn7BRnA^Cw_@Y7&Ecz*7sR@Zmq;mXfE$tf>T zTD6!uhWSuS?S0s6`587;YHGt(Tk4%+3*lTFI2yo1v8so#h|O)=#Y*X~vjbRsI+#-5 z3MiQR4GwH`#?Jn2@I`zUM|;LMAal~_udX`g^SFzJ-`?O-mRWF`F&&P4xdp*2gSL@9 z^NSVj$)=r0;Op5TvaIq6ZCl?4(`)ua?)hR&63?NBE$z_LrHGE` z^r3OF82Ueb11ltQ!L>mOgsmR&7FeW$$bMfG?()K=NvU8sV>x7`aX@ogIA>Mmij0lV zi^*bHB`bQ?!{mkabu*CF>z zDcsqqjtXm=AoHIIT3t@X!jd4~Zq84ldTMn>@nY8AZaM%*rwH=bHT!}5wUq$V6j9`C zCiIdx5aoN5`nhA!FmoCDeviP9{OK%foQVM^YVqdF@8}XGOUAO4iAPE?>a58`H7yzL z;qFje68j4RZZE)K)3vbH_B{Nm*2OJ3DX=ooh=#82gz^h+I6a~m4Mxi_Yg-E531+i< z_FD|w-HX;@k|Z~48D7jZr%k%|&^$qi(<8qPZM<*dc@@U;yzdL62RFe6m2!m)P{l^aj2A6NE9N! zl64jZ(B58;b_tiT_c*~AJu&ohv4v8)iB686iQAOlf&8*>tYiE+JyN_Aa$ME1Z8#eL z+aeCSd5QS!uNY))VES^;J}mq1AC!pIAIa613v*Ls|%!s_#R4DGMt7brQW;xe`Cd+Ctj*`*>?v25Q|4z))FHzSg8L zkj;+4rA2S>m)s|qdhRY<^4fwW>Q*rMS2Q*_)zOXam*FyJGe=_93|dlo40k>ZMGY4z z?$WE#V71nf6J-?)$NL{b?Y}HEkb47_j?8P^)CKARnjmD!`XSDx@c3j8n~hR&^kNhF zYjX?3W(-4ea~Mi}^~81S$8nB$FFgLpe2f*af#?q3u!7{3Hq=ey1?z>o%D8)Ew{myoOH3D$~Eeo%)z4kpoSVV3udi zX?<>k=e*@~T)Q|Nxrjb6s-6Kpu4A0r~B9LNg5 zDW2l|`?;@4&%sg7`Ck)JcHQ@k%YPk7qW)>{Yy3czR|s)G4`gS|ly1Q5{-=1{>C*Hq z(@Vxy+rYn5vteWRPJ9#fm3$nYOhnq)-C)XW+)x^d+JQ5`UuGOEXUg$kH2Z+JMK?OG zE`co?*O7cM#eC~+Xv)sG5n}~FB|u~7{ z?`r6hFQLb&*8w?fxcd%96Fbu1El}X!%!)(BmBEnLlngici@?kMJkv)O;f=4Mpy?(7 ztMuYgaQ<~HZ7hW<)p;~#-Y_1P=Hqk)2Ye(ck$Y`mKV*z8o|EBI=MOdyJU}`{ zfPcEXnqIk^Mt*m1#CIhtpjwp&P6w6wW4f)VK1Ulpj%4A7HLloF>4M4Y{NTl}!^Abn ziensBMrUVdLS6D1SY{WCnqDPjAnhYwc=nBX3NOIB-@5pDu`QPFT7vUiRd91{1ogi9 zA56nQx&kdQnv8&!&jH%rzY03mw!?2NM=H6HM^2ZTy?%N8Fukzo1}U9iLidQ-k@WZi z-oa1L!J%J^u+11)T0wG49|f1dT=zt+;mL zmnn~`|7F0_q)}qX_Pv|Uf6(ImC`$5p_+>KVuRak4ecLOjSoxRGi%)T_l_Q!}Yk(5t z_1P`#pnT^}hE^)e}f9_E+BU30A6DE=fkdcu$6U<9!jr)CkJnXdv*!==lh#v+o-@j zHDhYj_!&M#3p!7u&EfxW&)$cq7=H&FPHxuLFAc$X%V}WtM+_~+HlgzzX78y` zgS3g(pd&B{;b&}N(}jB4Z26A9)O?3ql}7QI-$mZG^(^a9_Y5voq)^vUL2hmSaE9mh zC-@?M8E(>Tf+STzzK&S}F55VfD`Qvd1Roc%Mi zk?1WUSN}CoUXC!gy!$acHVA_KG!s@Cy~0Dd1|N16!T$Ih#$UDqKapPi*2O;G$y4|q z(}&^iGnWiSl>s`@&KkE)lEs;)ol3m_HCJF8Q1wf+VWs{4yW@&OR^Jq{&yg=4k9FP?oN!u?a50dKG=ry46D(4z8HV+!a&-fqXs$`3Na^OF0Gg= z&i|+|2U0HYBJQfw`MJ&YSfFf!&!XetH_z&hf%z1lz7by z<@6g{Wt3!Y!0?aRaQle|ncB{@s;pbscu@laM!rGLMia7PgAcAv&4X@pcO3ZdIE`NH z4`Ss@aH_rtn0*{1iF4B7!}q%+x;7Q(P3wRK8a13&iFy>N_so#KUky>YXF;q&kR*Dr zyRNAqymqh!9F#^`r*TN1){COQlF?4G2;y&w@oNIs;1Lm1x}{4H-1;N2&in}`H%sxa zYcX$XkvZI0=ZA@6;#|A&3VM;fUbRXT(0voQH_x2}`^G4|x<8zjM{kCiPMz?0h9K;# z@}xIKj^cntA)0lK)5Bv6VSn#x7z?e#1ovq0{~EjvmE8hs<_oboJBLO~7UV_+gb8+i`j%1tjAO!xW z2c7GC5$8Rjl1u$@w$m?ANSlUN7j(dUT_G-4ubqf*@Pt|Shse&5yLj7kFZlJmAyCOX;bq3ph306`y}Ti({RR z(3))qWdBqga4jOv%B!%%W+QHuV_dF7Lj2gGVyv9uh6_)mVr5V*B(vvgZQCqG zDZ4@6;nyUnX90}5_Tw+X+wkFtCsFC2L2e${2YDwNFm$94AKv;130{?WV9|59D&7Lb zG80-i$Kk9`9|HOw-EiO^J$)$%kL^u@$W8a?pDpDm zDN;pu?w!gvvT-77HwT062LW{LY=#?bemH612c9<{p<;pqm79@{-wQ19=(A*W*5iVi z;w#7y8-^3gh_+8Vv0+X{x<*3u)XQ{Q`C4Q&VRW?lshEz5*7RrBCA2p* zUNkZ9pr4$Cxn|eK$kY>G$w>zVHT_vPQkL6 ze-I}$5o(uhgM?x;&aI;fc;}HYcKxn`ON`~WZV?B!^lX64$)R{_q62Z?IZU&y7|*7$pG@HBIo6X*cw^m9j36T8y=c zhK(ELz+Z3xhJ?N5&DWe2r7i%-D$9j%@ucLUV?XK9GP>4c|T=*fX<)E zIkD~q?b_6V8(p|?JimgxJLLxED?9PXD^Y%%ZWBsetHB+CTVV5xc=9Ye85+!4$7*{V z-mD0Mqw8!)*vVHAIpZwm9l8s<`;mmgJ7_nz#IA+u(EHaLP98i=4_uZc3*I{6r(jK} zv3ZG4KgNOI6L+v~J^<=_7Q^_z%TRmQo#+mY!X}T)P%O3;*3GhnlJ0q!S=vX{r;79E z#z^qv*2Q9vjwu|gDW$%RGVtI~2-xmquM<7aaae5$Dm%vD@4_eOyG9*X&Thk5(3l90ZU0QY=Q9rQA|q_LRRdvv^NF2e zHng=_!RA>`-~ZjVI~yzYDsPFLT!0JK`PI)dL&VNXhnRIOJVK_Aaysvy~EL zyTvfn?rNfITxQ^|Ay1g&FpPeMCOEaliHHjR2L*Ap*mik{+}5&!01rR><()*TmarLc zl_Y;lN;pUQL>c~1(RujQ_`Y$xsi8C|sYF&qMpkw1>mVVrDI-zDS4Lz;86_$$Bn|Bn zEp3f+U#Cq&Xm2UeE|nFM-~Ia!qj(u>KAz1Smyr(?=-k*yI}Uy{OKId$aIXKxI1%Ecdfmv9dE0>`YTk*o+Sf+ezo zTpzZ#TsF-Z#+PQJ)<;nY+~|m3H&~;Io-ZuB^9Vk+6qD)3*=S)IkD{VkFl6CIUwy2` z9;ZUE2v))ENe)=X7Tp$dtP5sh2%PpbH2hvcUTHrdrK~dZ{U(%!dOJ5^kkv{pZlnoTDU252b!}`(?o=8qb0;uVzU5;*@|G5RfWw??ZAUC zs2N|+(Hkhl0GT*yoTZDlTu&$n{SDsB+i9%M9-MG33(l^;h`*b@qxGKwoI5iILd=xm zlu{~ZU^;+}bp{PGE2KsaDYz^vkK-ZE_TAHsDc}ArcG%Z|aj_j-7|cN9f*f+~{ydN` z?qRH453otz0XLq0pr7KTxof<#aqWy=&P(!(wk7t_j=(eExPXU-ts!{Sx*hv^QgQa$ zhjh^ldF~lWSCB9GftQ=E;-q&+(9y;OZ|`itX;Z2|?Q9C3AE-ymt`1^cu?W7m!NK$E^J==rzj&wSphv z(UYFoFQ19Cly|cJ@liPW>n)vpT!0T6GW?si+Qio|7K3cglCLU4^yOwLm|v{U7umcD z%)gtn%w7t(iArGqwP0wUEk@(Tis0o&T{7F|H92xNna)4UoTh3YSl_b+1^F*{Y0o=Q zWH1hN*H=>gf_tRYbQrQqC-V1A0NAi00aGH_^XA3DFlQe!?_&^3{w{I2T>U5vBC1|-B$lSZp~=iwF*yzD-5$b~s1e$|R*)|*Z$}c3 zcR-ZQ3v9aWf#xSn$&x*X@M=OVF6$|xmZm>Rhxc_X|9A(do?t8*TS30$+qtBvF&lNB zUxpi9xoFd-3D$R1VZT5de0pC*(<@Iy`OtKHVta>m7O#_8;>9TFT1_>!FkjM*7I>~Y zott~+B*ff2iC5}dFn6R0Urk7Yz2=4JR_TZ{>;-v}c3;U3?j88oU4dq+=ELdDid?%} z0(entGIz&jXBhwE56{$I!|R$9GT(U~4hP-A?7ucJk$JN&xF&I`avIS0Odwq7ET=*- zVyrtD3-fh_F-p@FOqUy>LfBN46>k*#%AmC@uVtw15B|SCn7Hkq2<4i9Hj|E z@G--S?0)10!7c4rrA^_dgaCK1{eC#+M!|O1D7o*u09M#6L5_MW2F*DD-xpWGuk1wZ zI{X}h7KBhW?|zPfTmey86b(nV)$qKfbipE9kZUazN;jX<%0T$%kIh zcq9&@n{MJMpDj>&dl_csP|P_VM!zp-ECj)|FmGWAgxEIWZ%<7OZvTL#@{{;y{^sC+ z18gViA;lG>ZXAP7LGEI^6zD!APGhxYc*of@!hKQ$DNUnf3*%F|H@iT7>|KaL0a#MF zpSc+nGV2R{@%~~JZoZ8K-y!=rPAGmvewak!*%4vxrI+=PWyf5BO}lW@w)L1&*8l>A zS>Rjg%W`0zV6;yhbm=F^afrePH@z|9>3`6mJII;3VHI4jQHQcFCHl-in0_0+MAqod zV|hYFluf;fWojSr`(P$#&dCAJO|M^=7A%WfzFvZngf>ndzCe>ZGDL6Aa)>bg&dV-p z12x6@Tru7p1iu78Xva|&=KgXcew~2h$9!G2%SD})(G|DMyBxP`W;-WA;nK_ z`9d83ilIrXAj|RF?xOC!r*zpzYc%V71X^?M zkeWrGp!mWJPzw;{=g|)0ck?tE*{+DUVkW__Kh>zSToRQ(>_X+6c6e7!jbz;4 zC1LJew+Z~I3|8%Cq#d~f`Q zz2u(mbW~cy&O4^euTZQCelF#3GWh}(8*v2Jf(`IopeI|Ke-DCgy@4GQRQSttj$vHL zISf;{f;X0mp>ClTE-H40%Z&+;soO%#^Lxp@4~wCBBHKw=_F$TM4>(l3fP?GRVNA0H zJM!yDykjb4b&7IKuSdbkDi_o-+5yf3k5O_5bJe`)M6oy>$g~ZD8I$ek^F3NHGj0=H z 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