crca 1.4.0__py3-none-any.whl → 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CRCA.py +172 -7
- MODEL_CARD.md +53 -0
- PKG-INFO +8 -2
- RELEASE_NOTES.md +17 -0
- STABILITY.md +19 -0
- architecture/hybrid/consistency_engine.py +362 -0
- architecture/hybrid/conversation_manager.py +421 -0
- architecture/hybrid/explanation_generator.py +452 -0
- architecture/hybrid/few_shot_learner.py +533 -0
- architecture/hybrid/graph_compressor.py +286 -0
- architecture/hybrid/hybrid_agent.py +4398 -0
- architecture/hybrid/language_compiler.py +623 -0
- architecture/hybrid/main,py +0 -0
- architecture/hybrid/reasoning_tracker.py +322 -0
- architecture/hybrid/self_verifier.py +524 -0
- architecture/hybrid/task_decomposer.py +567 -0
- architecture/hybrid/text_corrector.py +341 -0
- benchmark_results/crca_core_benchmarks.json +178 -0
- branches/crca_sd/crca_sd_realtime.py +6 -2
- branches/general_agent/__init__.py +102 -0
- branches/general_agent/general_agent.py +1400 -0
- branches/general_agent/personality.py +169 -0
- branches/general_agent/utils/__init__.py +19 -0
- branches/general_agent/utils/prompt_builder.py +170 -0
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/METADATA +8 -2
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/RECORD +303 -20
- crca_core/__init__.py +35 -0
- crca_core/benchmarks/__init__.py +14 -0
- crca_core/benchmarks/synthetic_scm.py +103 -0
- crca_core/core/__init__.py +23 -0
- crca_core/core/api.py +120 -0
- crca_core/core/estimate.py +208 -0
- crca_core/core/godclass.py +72 -0
- crca_core/core/intervention_design.py +174 -0
- crca_core/core/lifecycle.py +48 -0
- crca_core/discovery/__init__.py +9 -0
- crca_core/discovery/tabular.py +193 -0
- crca_core/identify/__init__.py +171 -0
- crca_core/identify/backdoor.py +39 -0
- crca_core/identify/frontdoor.py +48 -0
- crca_core/identify/graph.py +106 -0
- crca_core/identify/id_algorithm.py +43 -0
- crca_core/identify/iv.py +48 -0
- crca_core/models/__init__.py +67 -0
- crca_core/models/provenance.py +56 -0
- crca_core/models/refusal.py +39 -0
- crca_core/models/result.py +83 -0
- crca_core/models/spec.py +151 -0
- crca_core/models/validation.py +68 -0
- crca_core/scm/__init__.py +9 -0
- crca_core/scm/linear_gaussian.py +198 -0
- crca_core/timeseries/__init__.py +6 -0
- crca_core/timeseries/pcmci.py +181 -0
- crca_llm/__init__.py +12 -0
- crca_llm/client.py +85 -0
- crca_llm/coauthor.py +118 -0
- crca_llm/orchestrator.py +289 -0
- crca_llm/types.py +21 -0
- crca_reasoning/__init__.py +16 -0
- crca_reasoning/critique.py +54 -0
- crca_reasoning/godclass.py +206 -0
- crca_reasoning/memory.py +24 -0
- crca_reasoning/rationale.py +10 -0
- crca_reasoning/react_controller.py +81 -0
- crca_reasoning/tool_router.py +97 -0
- crca_reasoning/types.py +40 -0
- crca_sd/__init__.py +15 -0
- crca_sd/crca_sd_core.py +2 -0
- crca_sd/crca_sd_governance.py +2 -0
- crca_sd/crca_sd_mpc.py +2 -0
- crca_sd/crca_sd_realtime.py +2 -0
- crca_sd/crca_sd_tui.py +2 -0
- cuda-keyring_1.1-1_all.deb +0 -0
- cuda-keyring_1.1-1_all.deb.1 +0 -0
- docs/IMAGE_ANNOTATION_USAGE.md +539 -0
- docs/INSTALL_DEEPSPEED.md +125 -0
- docs/api/branches/crca-cg.md +19 -0
- docs/api/branches/crca-q.md +27 -0
- docs/api/branches/crca-sd.md +37 -0
- docs/api/branches/general-agent.md +24 -0
- docs/api/branches/overview.md +19 -0
- docs/api/crca/agent-methods.md +62 -0
- docs/api/crca/operations.md +79 -0
- docs/api/crca/overview.md +32 -0
- docs/api/image-annotation/engine.md +52 -0
- docs/api/image-annotation/overview.md +17 -0
- docs/api/schemas/annotation.md +34 -0
- docs/api/schemas/core-schemas.md +82 -0
- docs/api/schemas/overview.md +32 -0
- docs/api/schemas/policy.md +30 -0
- docs/api/utils/conversation.md +22 -0
- docs/api/utils/graph-reasoner.md +32 -0
- docs/api/utils/overview.md +21 -0
- docs/api/utils/router.md +19 -0
- docs/api/utils/utilities.md +97 -0
- docs/architecture/causal-graphs.md +41 -0
- docs/architecture/data-flow.md +29 -0
- docs/architecture/design-principles.md +33 -0
- docs/architecture/hybrid-agent/components.md +38 -0
- docs/architecture/hybrid-agent/consistency.md +26 -0
- docs/architecture/hybrid-agent/overview.md +44 -0
- docs/architecture/hybrid-agent/reasoning.md +22 -0
- docs/architecture/llm-integration.md +26 -0
- docs/architecture/modular-structure.md +37 -0
- docs/architecture/overview.md +69 -0
- docs/architecture/policy-engine-arch.md +29 -0
- docs/branches/crca-cg/corposwarm.md +39 -0
- docs/branches/crca-cg/esg-scoring.md +30 -0
- docs/branches/crca-cg/multi-agent.md +35 -0
- docs/branches/crca-cg/overview.md +40 -0
- docs/branches/crca-q/alternative-data.md +55 -0
- docs/branches/crca-q/architecture.md +71 -0
- docs/branches/crca-q/backtesting.md +45 -0
- docs/branches/crca-q/causal-engine.md +33 -0
- docs/branches/crca-q/execution.md +39 -0
- docs/branches/crca-q/market-data.md +60 -0
- docs/branches/crca-q/overview.md +58 -0
- docs/branches/crca-q/philosophy.md +60 -0
- docs/branches/crca-q/portfolio-optimization.md +66 -0
- docs/branches/crca-q/risk-management.md +102 -0
- docs/branches/crca-q/setup.md +65 -0
- docs/branches/crca-q/signal-generation.md +61 -0
- docs/branches/crca-q/signal-validation.md +43 -0
- docs/branches/crca-sd/core.md +84 -0
- docs/branches/crca-sd/governance.md +53 -0
- docs/branches/crca-sd/mpc-solver.md +65 -0
- docs/branches/crca-sd/overview.md +59 -0
- docs/branches/crca-sd/realtime.md +28 -0
- docs/branches/crca-sd/tui.md +20 -0
- docs/branches/general-agent/overview.md +37 -0
- docs/branches/general-agent/personality.md +36 -0
- docs/branches/general-agent/prompt-builder.md +30 -0
- docs/changelog/index.md +79 -0
- docs/contributing/code-style.md +69 -0
- docs/contributing/documentation.md +43 -0
- docs/contributing/overview.md +29 -0
- docs/contributing/testing.md +29 -0
- docs/core/crcagent/async-operations.md +65 -0
- docs/core/crcagent/automatic-extraction.md +107 -0
- docs/core/crcagent/batch-prediction.md +80 -0
- docs/core/crcagent/bayesian-inference.md +60 -0
- docs/core/crcagent/causal-graph.md +92 -0
- docs/core/crcagent/counterfactuals.md +96 -0
- docs/core/crcagent/deterministic-simulation.md +78 -0
- docs/core/crcagent/dual-mode-operation.md +82 -0
- docs/core/crcagent/initialization.md +88 -0
- docs/core/crcagent/optimization.md +65 -0
- docs/core/crcagent/overview.md +63 -0
- docs/core/crcagent/time-series.md +57 -0
- docs/core/schemas/annotation.md +30 -0
- docs/core/schemas/core-schemas.md +82 -0
- docs/core/schemas/overview.md +30 -0
- docs/core/schemas/policy.md +41 -0
- docs/core/templates/base-agent.md +31 -0
- docs/core/templates/feature-mixins.md +31 -0
- docs/core/templates/overview.md +29 -0
- docs/core/templates/templates-guide.md +75 -0
- docs/core/tools/mcp-client.md +34 -0
- docs/core/tools/overview.md +24 -0
- docs/core/utils/conversation.md +27 -0
- docs/core/utils/graph-reasoner.md +29 -0
- docs/core/utils/overview.md +27 -0
- docs/core/utils/router.md +27 -0
- docs/core/utils/utilities.md +97 -0
- docs/css/custom.css +84 -0
- docs/examples/basic-usage.md +57 -0
- docs/examples/general-agent/general-agent-examples.md +50 -0
- docs/examples/hybrid-agent/hybrid-agent-examples.md +56 -0
- docs/examples/image-annotation/image-annotation-examples.md +54 -0
- docs/examples/integration/integration-examples.md +58 -0
- docs/examples/overview.md +37 -0
- docs/examples/trading/trading-examples.md +46 -0
- docs/features/causal-reasoning/advanced-topics.md +101 -0
- docs/features/causal-reasoning/counterfactuals.md +43 -0
- docs/features/causal-reasoning/do-calculus.md +50 -0
- docs/features/causal-reasoning/overview.md +47 -0
- docs/features/causal-reasoning/structural-models.md +52 -0
- docs/features/hybrid-agent/advanced-components.md +55 -0
- docs/features/hybrid-agent/core-components.md +64 -0
- docs/features/hybrid-agent/overview.md +34 -0
- docs/features/image-annotation/engine.md +82 -0
- docs/features/image-annotation/features.md +113 -0
- docs/features/image-annotation/integration.md +75 -0
- docs/features/image-annotation/overview.md +53 -0
- docs/features/image-annotation/quickstart.md +73 -0
- docs/features/policy-engine/doctrine-ledger.md +105 -0
- docs/features/policy-engine/monitoring.md +44 -0
- docs/features/policy-engine/mpc-control.md +89 -0
- docs/features/policy-engine/overview.md +46 -0
- docs/getting-started/configuration.md +225 -0
- docs/getting-started/first-agent.md +164 -0
- docs/getting-started/installation.md +144 -0
- docs/getting-started/quickstart.md +137 -0
- docs/index.md +118 -0
- docs/js/mathjax.js +13 -0
- docs/lrm/discovery_proof_notes.md +25 -0
- docs/lrm/finetune_full.md +83 -0
- docs/lrm/math_appendix.md +120 -0
- docs/lrm/overview.md +32 -0
- docs/mkdocs.yml +238 -0
- docs/stylesheets/extra.css +21 -0
- docs_generated/crca_core/CounterfactualResult.md +12 -0
- docs_generated/crca_core/DiscoveryHypothesisResult.md +13 -0
- docs_generated/crca_core/DraftSpec.md +13 -0
- docs_generated/crca_core/EstimateResult.md +13 -0
- docs_generated/crca_core/IdentificationResult.md +17 -0
- docs_generated/crca_core/InterventionDesignResult.md +12 -0
- docs_generated/crca_core/LockedSpec.md +15 -0
- docs_generated/crca_core/RefusalResult.md +12 -0
- docs_generated/crca_core/ValidationReport.md +9 -0
- docs_generated/crca_core/index.md +13 -0
- examples/general_agent_example.py +277 -0
- examples/general_agent_quickstart.py +202 -0
- examples/general_agent_simple.py +92 -0
- examples/hybrid_agent_auto_extraction.py +84 -0
- examples/hybrid_agent_dictionary_demo.py +104 -0
- examples/hybrid_agent_enhanced.py +179 -0
- examples/hybrid_agent_general_knowledge.py +107 -0
- examples/image_annotation_quickstart.py +328 -0
- examples/test_hybrid_fixes.py +77 -0
- image_annotation/__init__.py +27 -0
- image_annotation/annotation_engine.py +2593 -0
- install_cuda_wsl2.sh +59 -0
- install_deepspeed.sh +56 -0
- install_deepspeed_simple.sh +87 -0
- mkdocs.yml +252 -0
- ollama/Modelfile +8 -0
- prompts/__init__.py +2 -1
- prompts/default_crca.py +9 -1
- prompts/general_agent.py +227 -0
- prompts/image_annotation.py +56 -0
- pyproject.toml +17 -2
- requirements-docs.txt +10 -0
- requirements.txt +21 -2
- schemas/__init__.py +26 -1
- schemas/annotation.py +222 -0
- schemas/conversation.py +193 -0
- schemas/hybrid.py +211 -0
- schemas/reasoning.py +276 -0
- schemas_export/crca_core/CounterfactualResult.schema.json +108 -0
- schemas_export/crca_core/DiscoveryHypothesisResult.schema.json +113 -0
- schemas_export/crca_core/DraftSpec.schema.json +635 -0
- schemas_export/crca_core/EstimateResult.schema.json +113 -0
- schemas_export/crca_core/IdentificationResult.schema.json +145 -0
- schemas_export/crca_core/InterventionDesignResult.schema.json +111 -0
- schemas_export/crca_core/LockedSpec.schema.json +646 -0
- schemas_export/crca_core/RefusalResult.schema.json +90 -0
- schemas_export/crca_core/ValidationReport.schema.json +62 -0
- scripts/build_lrm_dataset.py +80 -0
- scripts/export_crca_core_schemas.py +54 -0
- scripts/export_hf_lrm.py +37 -0
- scripts/export_ollama_gguf.py +45 -0
- scripts/generate_changelog.py +157 -0
- scripts/generate_crca_core_docs_from_schemas.py +86 -0
- scripts/run_crca_core_benchmarks.py +163 -0
- scripts/run_full_finetune.py +198 -0
- scripts/run_lrm_eval.py +31 -0
- templates/graph_management.py +29 -0
- tests/conftest.py +9 -0
- tests/test_core.py +2 -3
- tests/test_crca_core_discovery_tabular.py +15 -0
- tests/test_crca_core_estimate_dowhy.py +36 -0
- tests/test_crca_core_identify.py +18 -0
- tests/test_crca_core_intervention_design.py +36 -0
- tests/test_crca_core_linear_gaussian_scm.py +69 -0
- tests/test_crca_core_spec.py +25 -0
- tests/test_crca_core_timeseries_pcmci.py +15 -0
- tests/test_crca_llm_coauthor.py +12 -0
- tests/test_crca_llm_orchestrator.py +80 -0
- tests/test_hybrid_agent_llm_enhanced.py +556 -0
- tests/test_image_annotation_demo.py +376 -0
- tests/test_image_annotation_operational.py +408 -0
- tests/test_image_annotation_unit.py +551 -0
- tests/test_training_moe.py +13 -0
- training/__init__.py +42 -0
- training/datasets.py +140 -0
- training/deepspeed_zero2_0_5b.json +22 -0
- training/deepspeed_zero2_1_5b.json +22 -0
- training/deepspeed_zero3_0_5b.json +28 -0
- training/deepspeed_zero3_14b.json +28 -0
- training/deepspeed_zero3_h100_3gpu.json +20 -0
- training/deepspeed_zero3_offload.json +28 -0
- training/eval.py +92 -0
- training/finetune.py +516 -0
- training/public_datasets.py +89 -0
- training_data/react_train.jsonl +7473 -0
- utils/agent_discovery.py +311 -0
- utils/batch_processor.py +317 -0
- utils/conversation.py +78 -0
- utils/edit_distance.py +118 -0
- utils/formatter.py +33 -0
- utils/graph_reasoner.py +530 -0
- utils/rate_limiter.py +283 -0
- utils/router.py +2 -2
- utils/tool_discovery.py +307 -0
- webui/__init__.py +10 -0
- webui/app.py +229 -0
- webui/config.py +104 -0
- webui/static/css/style.css +332 -0
- webui/static/js/main.js +284 -0
- webui/templates/index.html +42 -0
- tests/test_crca_excel.py +0 -166
- tests/test_data_broker.py +0 -424
- tests/test_palantir.py +0 -349
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/WHEEL +0 -0
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Operational tests for image annotation engine - testing basic functionality with simplified API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
import tempfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from PIL import Image
|
|
12
|
+
import cv2
|
|
13
|
+
|
|
14
|
+
# Add parent directory to path
|
|
15
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
|
16
|
+
|
|
17
|
+
# Image annotation operational tests can be slow and may require extra deps/LLM access.
|
|
18
|
+
if os.environ.get("CRCA_RUN_IMAGE_ANNOTATION_TESTS") != "1":
|
|
19
|
+
pytest.skip("Set CRCA_RUN_IMAGE_ANNOTATION_TESTS=1 to run image annotation tests", allow_module_level=True)
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from image_annotation.annotation_engine import ImageAnnotationEngine
|
|
23
|
+
from image_annotation import AnnotationResult
|
|
24
|
+
IMAGE_ANNOTATION_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
IMAGE_ANNOTATION_AVAILABLE = False
|
|
27
|
+
pytest.skip("Image annotation not available", allow_module_level=True)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def create_test_image(width=500, height=500, image_type="simple"):
|
|
31
|
+
"""Create a test image for testing."""
|
|
32
|
+
img = np.zeros((height, width, 3), dtype=np.uint8)
|
|
33
|
+
|
|
34
|
+
if image_type == "simple":
|
|
35
|
+
# Simple geometric shapes
|
|
36
|
+
cv2.rectangle(img, (100, 100), (400, 400), (255, 255, 255), 2)
|
|
37
|
+
cv2.circle(img, (250, 250), 50, (255, 255, 255), 2)
|
|
38
|
+
cv2.line(img, (0, 0), (500, 500), (255, 255, 255), 2)
|
|
39
|
+
elif image_type == "circuit":
|
|
40
|
+
# Circuit-like diagram
|
|
41
|
+
for i in range(0, width, 50):
|
|
42
|
+
cv2.line(img, (i, 0), (i, height), (255, 255, 255), 1)
|
|
43
|
+
for i in range(50, width, 100):
|
|
44
|
+
cv2.circle(img, (i, height//2), 20, (255, 255, 255), 2)
|
|
45
|
+
elif image_type == "architectural":
|
|
46
|
+
# Architectural drawing style
|
|
47
|
+
for i in range(0, width, 20):
|
|
48
|
+
cv2.line(img, (0, i), (width, i), (255, 255, 255), 1)
|
|
49
|
+
cv2.line(img, (i, 0), (i, height), (255, 255, 255), 1)
|
|
50
|
+
|
|
51
|
+
return img
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TestSimplifiedAPI:
|
|
55
|
+
"""Test the simplified/standardized API usage."""
|
|
56
|
+
|
|
57
|
+
def test_annotate_file_path(self):
|
|
58
|
+
"""Test annotate with file path - simplest usage."""
|
|
59
|
+
engine = ImageAnnotationEngine()
|
|
60
|
+
|
|
61
|
+
# Create temporary image file
|
|
62
|
+
img = create_test_image()
|
|
63
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
64
|
+
cv2.imwrite(f.name, img)
|
|
65
|
+
temp_path = f.name
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
# Simplest usage - just pass file path
|
|
69
|
+
# Should return overlay (numpy array) by default for simplified API
|
|
70
|
+
result = engine.annotate(temp_path)
|
|
71
|
+
|
|
72
|
+
# File paths return overlay by default (simplified API)
|
|
73
|
+
assert isinstance(result, np.ndarray)
|
|
74
|
+
assert len(result.shape) == 3 # BGR image
|
|
75
|
+
|
|
76
|
+
# Can also request AnnotationResult explicitly
|
|
77
|
+
result_full = engine.annotate(temp_path, output="all")
|
|
78
|
+
assert isinstance(result_full, AnnotationResult)
|
|
79
|
+
assert result_full.annotation_graph is not None
|
|
80
|
+
assert result_full.processing_time > 0
|
|
81
|
+
finally:
|
|
82
|
+
os.unlink(temp_path)
|
|
83
|
+
|
|
84
|
+
def test_annotate_numpy_array(self):
|
|
85
|
+
"""Test annotate with numpy array - backward compatible."""
|
|
86
|
+
engine = ImageAnnotationEngine()
|
|
87
|
+
img = create_test_image()
|
|
88
|
+
|
|
89
|
+
# Old API still works
|
|
90
|
+
result = engine.annotate(img)
|
|
91
|
+
|
|
92
|
+
assert isinstance(result, AnnotationResult)
|
|
93
|
+
assert len(result.annotation_graph.entities) >= 0
|
|
94
|
+
|
|
95
|
+
def test_annotate_output_overlay(self):
|
|
96
|
+
"""Test annotate with overlay output format."""
|
|
97
|
+
engine = ImageAnnotationEngine()
|
|
98
|
+
img = create_test_image()
|
|
99
|
+
|
|
100
|
+
# Request overlay format - should return numpy array
|
|
101
|
+
overlay = engine.annotate(img, output="overlay")
|
|
102
|
+
|
|
103
|
+
assert isinstance(overlay, np.ndarray)
|
|
104
|
+
assert len(overlay.shape) == 3 # BGR image
|
|
105
|
+
|
|
106
|
+
def test_annotate_output_json(self):
|
|
107
|
+
"""Test annotate with JSON output format."""
|
|
108
|
+
engine = ImageAnnotationEngine()
|
|
109
|
+
img = create_test_image()
|
|
110
|
+
|
|
111
|
+
# Request JSON format
|
|
112
|
+
json_output = engine.annotate(img, output="json")
|
|
113
|
+
|
|
114
|
+
assert isinstance(json_output, dict)
|
|
115
|
+
assert "entities" in json_output or "error" in json_output
|
|
116
|
+
|
|
117
|
+
def test_annotate_output_report(self):
|
|
118
|
+
"""Test annotate with report output format."""
|
|
119
|
+
engine = ImageAnnotationEngine()
|
|
120
|
+
img = create_test_image()
|
|
121
|
+
|
|
122
|
+
# Request report format
|
|
123
|
+
report = engine.annotate(img, output="report")
|
|
124
|
+
|
|
125
|
+
assert isinstance(report, str)
|
|
126
|
+
assert len(report) > 0
|
|
127
|
+
|
|
128
|
+
def test_annotate_batch_auto_detection(self):
|
|
129
|
+
"""Test automatic batch processing detection."""
|
|
130
|
+
engine = ImageAnnotationEngine()
|
|
131
|
+
|
|
132
|
+
# Create multiple test images
|
|
133
|
+
images = []
|
|
134
|
+
temp_files = []
|
|
135
|
+
for i in range(3):
|
|
136
|
+
img = create_test_image()
|
|
137
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
138
|
+
cv2.imwrite(f.name, img)
|
|
139
|
+
images.append(f.name)
|
|
140
|
+
temp_files.append(f.name)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
# Pass list - should auto-detect batch processing
|
|
144
|
+
results = engine.annotate(images)
|
|
145
|
+
|
|
146
|
+
assert isinstance(results, list)
|
|
147
|
+
assert len(results) == 3
|
|
148
|
+
# Results should be in requested format (default is overlay for new API)
|
|
149
|
+
# But since we passed file paths, it might return AnnotationResult
|
|
150
|
+
assert all(isinstance(r, (AnnotationResult, np.ndarray, dict, str)) for r in results)
|
|
151
|
+
finally:
|
|
152
|
+
for f in temp_files:
|
|
153
|
+
if os.path.exists(f):
|
|
154
|
+
os.unlink(f)
|
|
155
|
+
|
|
156
|
+
def test_annotate_batch_mixed_inputs(self):
|
|
157
|
+
"""Test batch processing with mixed input types."""
|
|
158
|
+
engine = ImageAnnotationEngine()
|
|
159
|
+
|
|
160
|
+
# Create mix of file path and numpy array
|
|
161
|
+
img1 = create_test_image()
|
|
162
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
163
|
+
cv2.imwrite(f.name, img1)
|
|
164
|
+
temp_path = f.name
|
|
165
|
+
|
|
166
|
+
img2 = create_test_image()
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
# Mix file path and numpy array
|
|
170
|
+
results = engine.annotate([temp_path, img2])
|
|
171
|
+
|
|
172
|
+
assert isinstance(results, list)
|
|
173
|
+
assert len(results) == 2
|
|
174
|
+
finally:
|
|
175
|
+
if os.path.exists(temp_path):
|
|
176
|
+
os.unlink(temp_path)
|
|
177
|
+
|
|
178
|
+
def test_query_simple(self):
|
|
179
|
+
"""Test query interface with simple query."""
|
|
180
|
+
engine = ImageAnnotationEngine()
|
|
181
|
+
img = create_test_image()
|
|
182
|
+
|
|
183
|
+
# Save to temp file for query
|
|
184
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
185
|
+
cv2.imwrite(f.name, img)
|
|
186
|
+
temp_path = f.name
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
# Simple query
|
|
190
|
+
result = engine.query(temp_path, "find all circles")
|
|
191
|
+
|
|
192
|
+
assert isinstance(result, dict)
|
|
193
|
+
assert "answer" in result
|
|
194
|
+
assert "entities" in result
|
|
195
|
+
assert "measurements" in result
|
|
196
|
+
assert "confidence" in result
|
|
197
|
+
finally:
|
|
198
|
+
if os.path.exists(temp_path):
|
|
199
|
+
os.unlink(temp_path)
|
|
200
|
+
|
|
201
|
+
def test_query_with_measurements(self):
|
|
202
|
+
"""Test query interface requesting measurements."""
|
|
203
|
+
engine = ImageAnnotationEngine()
|
|
204
|
+
img = create_test_image()
|
|
205
|
+
|
|
206
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
207
|
+
cv2.imwrite(f.name, img)
|
|
208
|
+
temp_path = f.name
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
# Query requesting measurements
|
|
212
|
+
result = engine.query(temp_path, "find the largest circle and measure its area")
|
|
213
|
+
|
|
214
|
+
assert isinstance(result, dict)
|
|
215
|
+
assert "measurements" in result
|
|
216
|
+
# May or may not have measurements depending on what was found
|
|
217
|
+
finally:
|
|
218
|
+
if os.path.exists(temp_path):
|
|
219
|
+
os.unlink(temp_path)
|
|
220
|
+
|
|
221
|
+
def test_query_count_objects(self):
|
|
222
|
+
"""Test query interface for counting objects."""
|
|
223
|
+
engine = ImageAnnotationEngine()
|
|
224
|
+
img = create_test_image()
|
|
225
|
+
|
|
226
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
227
|
+
cv2.imwrite(f.name, img)
|
|
228
|
+
temp_path = f.name
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
# Count query
|
|
232
|
+
result = engine.query(temp_path, "count how many lines are in this image")
|
|
233
|
+
|
|
234
|
+
assert isinstance(result, dict)
|
|
235
|
+
assert "answer" in result
|
|
236
|
+
assert "entities" in result
|
|
237
|
+
finally:
|
|
238
|
+
if os.path.exists(temp_path):
|
|
239
|
+
os.unlink(temp_path)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TestAutoFeatures:
|
|
243
|
+
"""Test automatic features (type detection, parameter tuning, etc.)."""
|
|
244
|
+
|
|
245
|
+
def test_auto_image_type_detection(self):
|
|
246
|
+
"""Test automatic image type detection."""
|
|
247
|
+
engine = ImageAnnotationEngine()
|
|
248
|
+
engine.config.auto_detect_type = True
|
|
249
|
+
|
|
250
|
+
# Circuit-like image
|
|
251
|
+
circuit_img = create_test_image(image_type="circuit")
|
|
252
|
+
result = engine.annotate(circuit_img, output="all")
|
|
253
|
+
|
|
254
|
+
# Should have detected image type in metadata
|
|
255
|
+
if isinstance(result, AnnotationResult):
|
|
256
|
+
detected_type = result.annotation_graph.metadata.get("image_type", "unknown")
|
|
257
|
+
assert detected_type in ["circuit", "general", "technical", "unknown"]
|
|
258
|
+
|
|
259
|
+
def test_auto_parameter_tuning(self):
|
|
260
|
+
"""Test automatic parameter tuning."""
|
|
261
|
+
engine = ImageAnnotationEngine()
|
|
262
|
+
engine.config.auto_tune_params = True
|
|
263
|
+
|
|
264
|
+
img = create_test_image()
|
|
265
|
+
result = engine.annotate(img)
|
|
266
|
+
|
|
267
|
+
# Should complete without errors (tuning happens internally)
|
|
268
|
+
assert isinstance(result, AnnotationResult)
|
|
269
|
+
|
|
270
|
+
def test_auto_retry_on_failure(self):
|
|
271
|
+
"""Test automatic retry logic."""
|
|
272
|
+
engine = ImageAnnotationEngine()
|
|
273
|
+
engine.config.auto_retry = True
|
|
274
|
+
engine.config.max_retries = 2
|
|
275
|
+
|
|
276
|
+
# Very simple image that might need retry
|
|
277
|
+
img = np.zeros((100, 100, 3), dtype=np.uint8)
|
|
278
|
+
result = engine.annotate(img)
|
|
279
|
+
|
|
280
|
+
# Should complete (may retry internally)
|
|
281
|
+
assert isinstance(result, AnnotationResult)
|
|
282
|
+
|
|
283
|
+
def test_caching_enabled(self):
|
|
284
|
+
"""Test that caching works."""
|
|
285
|
+
engine = ImageAnnotationEngine()
|
|
286
|
+
engine.config.cache_enabled = True
|
|
287
|
+
|
|
288
|
+
img = create_test_image()
|
|
289
|
+
|
|
290
|
+
# First annotation
|
|
291
|
+
result1 = engine.annotate(img)
|
|
292
|
+
|
|
293
|
+
# Second annotation (should use cache for primitives)
|
|
294
|
+
result2 = engine.annotate(img)
|
|
295
|
+
|
|
296
|
+
# Both should complete
|
|
297
|
+
assert isinstance(result1, AnnotationResult)
|
|
298
|
+
assert isinstance(result2, AnnotationResult)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class TestErrorHandling:
|
|
302
|
+
"""Test error handling in simplified API."""
|
|
303
|
+
|
|
304
|
+
def test_invalid_file_path(self):
|
|
305
|
+
"""Test handling of invalid file path."""
|
|
306
|
+
engine = ImageAnnotationEngine()
|
|
307
|
+
|
|
308
|
+
# Non-existent file
|
|
309
|
+
result = engine.annotate("nonexistent_file.png", output="all")
|
|
310
|
+
|
|
311
|
+
# Should return error result, not crash
|
|
312
|
+
if isinstance(result, AnnotationResult):
|
|
313
|
+
assert "error" in result.json_output or len(result.annotation_graph.entities) == 0
|
|
314
|
+
|
|
315
|
+
def test_empty_image(self):
|
|
316
|
+
"""Test handling of empty/blank image."""
|
|
317
|
+
engine = ImageAnnotationEngine()
|
|
318
|
+
|
|
319
|
+
# Empty image
|
|
320
|
+
img = np.zeros((100, 100, 3), dtype=np.uint8)
|
|
321
|
+
result = engine.annotate(img)
|
|
322
|
+
|
|
323
|
+
# Should complete without crashing
|
|
324
|
+
assert isinstance(result, AnnotationResult)
|
|
325
|
+
|
|
326
|
+
def test_batch_with_errors(self):
|
|
327
|
+
"""Test batch processing continues on individual errors."""
|
|
328
|
+
engine = ImageAnnotationEngine()
|
|
329
|
+
|
|
330
|
+
img = create_test_image()
|
|
331
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
|
|
332
|
+
cv2.imwrite(f.name, img)
|
|
333
|
+
temp_path = f.name
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
# Mix valid and invalid inputs
|
|
337
|
+
results = engine.annotate([temp_path, "nonexistent.png", img])
|
|
338
|
+
|
|
339
|
+
# Should return results for all (some may be errors)
|
|
340
|
+
assert isinstance(results, list)
|
|
341
|
+
assert len(results) == 3
|
|
342
|
+
finally:
|
|
343
|
+
if os.path.exists(temp_path):
|
|
344
|
+
os.unlink(temp_path)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class TestConfiguration:
|
|
348
|
+
"""Test configuration options."""
|
|
349
|
+
|
|
350
|
+
def test_custom_config(self):
|
|
351
|
+
"""Test using custom configuration."""
|
|
352
|
+
from image_annotation.annotation_engine import AnnotationConfig
|
|
353
|
+
|
|
354
|
+
config = AnnotationConfig(
|
|
355
|
+
gpt_model="gpt-4o-mini",
|
|
356
|
+
cache_enabled=False,
|
|
357
|
+
auto_retry=False,
|
|
358
|
+
output_format="json"
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
engine = ImageAnnotationEngine(config=config)
|
|
362
|
+
|
|
363
|
+
assert engine.config.cache_enabled is False
|
|
364
|
+
assert engine.config.auto_retry is False
|
|
365
|
+
assert engine.config.output_format == "json"
|
|
366
|
+
|
|
367
|
+
def test_config_override(self):
|
|
368
|
+
"""Test overriding config parameters."""
|
|
369
|
+
engine = ImageAnnotationEngine(
|
|
370
|
+
gpt_model="gpt-4o",
|
|
371
|
+
cache_enabled=False
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
assert engine.config.gpt_model == "gpt-4o"
|
|
375
|
+
assert engine.config.cache_enabled is False
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class TestIntegration:
|
|
379
|
+
"""Test integration with CR-CA."""
|
|
380
|
+
|
|
381
|
+
def test_crca_agent_with_image_tools(self):
|
|
382
|
+
"""Test CR-CA agent can use image annotation tools."""
|
|
383
|
+
try:
|
|
384
|
+
from CRCA import CRCAAgent
|
|
385
|
+
except ImportError:
|
|
386
|
+
pytest.skip("CR-CA not available")
|
|
387
|
+
|
|
388
|
+
# Create agent with image annotation enabled
|
|
389
|
+
agent = CRCAAgent(
|
|
390
|
+
model_name="gpt-4o-mini",
|
|
391
|
+
use_image_annotation=True
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# Check that tools are available
|
|
395
|
+
tool_names = []
|
|
396
|
+
if hasattr(agent, 'tools_list_dictionary') and agent.tools_list_dictionary:
|
|
397
|
+
for tool in agent.tools_list_dictionary:
|
|
398
|
+
if isinstance(tool, dict):
|
|
399
|
+
func_name = tool.get("function", {}).get("name", "")
|
|
400
|
+
if func_name:
|
|
401
|
+
tool_names.append(func_name)
|
|
402
|
+
|
|
403
|
+
# Image annotation tools should be available
|
|
404
|
+
assert "annotate_image" in tool_names or "query_image" in tool_names or len(tool_names) == 0
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
if __name__ == "__main__":
|
|
408
|
+
pytest.main([__file__, "-v"])
|