iris-vector-rag 0.2.1__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.
- adapters/rag_templates_bridge.py +578 -0
- common/__init__.py +1 -0
- common/batch_utils.py +294 -0
- common/config.py +58 -0
- common/connection_manager.py +242 -0
- common/connection_pool.py +445 -0
- common/database.py +141 -0
- common/database_schema_manager.py +289 -0
- common/db_init_with_indexes.py +181 -0
- common/db_vector_utils.py +181 -0
- common/environment_manager.py +220 -0
- common/huggingface_utils.py +206 -0
- common/iris_client.py +92 -0
- common/iris_connection_manager.py +411 -0
- common/iris_connection_pool.py +360 -0
- common/iris_connector.py +71 -0
- common/iris_dbapi_connector.py +323 -0
- common/iris_index_utils.py +195 -0
- common/iris_sql_utils.py +704 -0
- common/iris_stream_reader.py +166 -0
- common/llm_cache_config.py +308 -0
- common/llm_cache_iris.py +671 -0
- common/llm_cache_manager.py +911 -0
- common/utils.py +559 -0
- common/vector_sql_utils.py +584 -0
- evaluation_framework/__init__.py +66 -0
- evaluation_framework/biomedical_question_generator.py +826 -0
- evaluation_framework/comparative_analysis_system.py +1173 -0
- evaluation_framework/empirical_reporting.py +1298 -0
- evaluation_framework/evaluation_orchestrator.py +1123 -0
- evaluation_framework/execute_production_evaluation.py +382 -0
- evaluation_framework/pmc_data_pipeline.py +1332 -0
- evaluation_framework/production_evaluation_config.py +353 -0
- evaluation_framework/ragas_metrics_framework.py +1013 -0
- evaluation_framework/real_production_evaluation.py +544 -0
- evaluation_framework/run_10k_evaluation.py +175 -0
- evaluation_framework/simple_test.py +364 -0
- evaluation_framework/statistical_evaluation_methodology.py +1016 -0
- evaluation_framework/test_framework.py +281 -0
- evaluation_framework/test_iris_connectivity.py +244 -0
- evaluation_framework/test_small_scale_evaluation.py +432 -0
- evaluation_framework/true_e2e_evaluation.py +639 -0
- evaluation_framework/visualization_engine.py +585 -0
- iris_rag/__init__.py +284 -0
- iris_rag/config/default_config.yaml +295 -0
- iris_vector_rag-0.2.1.dist-info/METADATA +499 -0
- iris_vector_rag-0.2.1.dist-info/RECORD +50 -0
- iris_vector_rag-0.2.1.dist-info/WHEEL +5 -0
- iris_vector_rag-0.2.1.dist-info/entry_points.txt +2 -0
- iris_vector_rag-0.2.1.dist-info/top_level.txt +4 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
IRIS Stream Reader Utility
|
|
4
|
+
Handles reading IRIS stream objects properly from JDBC connections.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def read_iris_stream(stream_obj: Any) -> str:
|
|
14
|
+
"""
|
|
15
|
+
Read content from an IRIS stream object returned by JDBC.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
stream_obj: Stream object from IRIS JDBC connection
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
String content of the stream
|
|
22
|
+
"""
|
|
23
|
+
if stream_obj is None:
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
# Check if it's already a string
|
|
28
|
+
if isinstance(stream_obj, str):
|
|
29
|
+
return stream_obj
|
|
30
|
+
|
|
31
|
+
# Handle different stream types from DBAPI vs JDBC
|
|
32
|
+
|
|
33
|
+
# JDBC streams (Java objects) - use readAllBytes()
|
|
34
|
+
if (
|
|
35
|
+
hasattr(stream_obj, "readAllBytes")
|
|
36
|
+
and str(type(stream_obj)).find("java") != -1
|
|
37
|
+
):
|
|
38
|
+
# Use readAllBytes for IRIS JDBC streams - this gets the actual content
|
|
39
|
+
try:
|
|
40
|
+
content_bytes = stream_obj.readAllBytes()
|
|
41
|
+
if hasattr(content_bytes, "__iter__"):
|
|
42
|
+
return bytes(content_bytes).decode("utf-8", errors="ignore")
|
|
43
|
+
else:
|
|
44
|
+
return str(content_bytes)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.warning(f"Failed to read JDBC stream with readAllBytes: {e}")
|
|
47
|
+
|
|
48
|
+
# DBAPI streams (Python objects) - use read()
|
|
49
|
+
elif hasattr(stream_obj, "read") and str(type(stream_obj)).find("java") == -1:
|
|
50
|
+
# For DBAPI streams, read() should work normally
|
|
51
|
+
try:
|
|
52
|
+
content_bytes = stream_obj.read()
|
|
53
|
+
if isinstance(content_bytes, bytes):
|
|
54
|
+
return content_bytes.decode("utf-8", errors="ignore")
|
|
55
|
+
elif isinstance(content_bytes, str):
|
|
56
|
+
return content_bytes
|
|
57
|
+
else:
|
|
58
|
+
return str(content_bytes)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
logger.warning(f"Failed to read DBAPI stream: {e}")
|
|
61
|
+
|
|
62
|
+
# JDBC streams fallback - read() often returns length not content for JDBC
|
|
63
|
+
elif hasattr(stream_obj, "read"):
|
|
64
|
+
try:
|
|
65
|
+
content_bytes = stream_obj.read()
|
|
66
|
+
if isinstance(content_bytes, bytes):
|
|
67
|
+
return content_bytes.decode("utf-8", errors="ignore")
|
|
68
|
+
elif isinstance(content_bytes, str):
|
|
69
|
+
return content_bytes
|
|
70
|
+
else:
|
|
71
|
+
# For JDBC, this is likely a length, not content
|
|
72
|
+
if str(type(stream_obj)).find("java") != -1:
|
|
73
|
+
logger.debug(
|
|
74
|
+
f"JDBC stream.read() returned length ({content_bytes}), not content"
|
|
75
|
+
)
|
|
76
|
+
return ""
|
|
77
|
+
else:
|
|
78
|
+
return str(content_bytes)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.warning(f"Failed to read stream as fallback: {e}")
|
|
81
|
+
|
|
82
|
+
# Handle Java String objects
|
|
83
|
+
if hasattr(stream_obj, "toString"):
|
|
84
|
+
return str(stream_obj.toString())
|
|
85
|
+
|
|
86
|
+
# Handle numeric stream lengths (IRIS sometimes returns length instead of content)
|
|
87
|
+
if hasattr(stream_obj, "__int__") or str(type(stream_obj)).find("JInt") != -1:
|
|
88
|
+
logger.warning(
|
|
89
|
+
f"Stream object appears to be length ({stream_obj}), not content"
|
|
90
|
+
)
|
|
91
|
+
return ""
|
|
92
|
+
|
|
93
|
+
# Last resort - convert to string
|
|
94
|
+
return str(stream_obj)
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"Failed to read IRIS stream: {e}")
|
|
98
|
+
return ""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_document_content_properly(cursor, doc_id: str) -> tuple[str, str, str]:
|
|
102
|
+
"""
|
|
103
|
+
Get document content with proper stream handling.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Tuple of (doc_id, title, content)
|
|
107
|
+
"""
|
|
108
|
+
try:
|
|
109
|
+
cursor.execute(
|
|
110
|
+
"""
|
|
111
|
+
SELECT doc_id, title, text_content
|
|
112
|
+
FROM RAG.SourceDocuments
|
|
113
|
+
WHERE doc_id = ?
|
|
114
|
+
""",
|
|
115
|
+
(doc_id,),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
result = cursor.fetchone()
|
|
119
|
+
if not result:
|
|
120
|
+
return doc_id, "", ""
|
|
121
|
+
|
|
122
|
+
fetched_doc_id, title_stream, content_stream = result
|
|
123
|
+
|
|
124
|
+
# Read streams properly
|
|
125
|
+
title = read_iris_stream(title_stream)
|
|
126
|
+
content = read_iris_stream(content_stream)
|
|
127
|
+
|
|
128
|
+
return fetched_doc_id, title, content
|
|
129
|
+
|
|
130
|
+
except Exception as e:
|
|
131
|
+
logger.error(f"Failed to get document content for {doc_id}: {e}")
|
|
132
|
+
return doc_id, "", ""
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_stream_reading():
|
|
136
|
+
"""Test stream reading functionality."""
|
|
137
|
+
from iris_connector import get_iris_connection
|
|
138
|
+
|
|
139
|
+
conn = get_iris_connection()
|
|
140
|
+
cursor = conn.cursor()
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
# Get a sample document
|
|
144
|
+
cursor.execute("SELECT TOP 1 doc_id FROM RAG.SourceDocuments")
|
|
145
|
+
result = cursor.fetchone()
|
|
146
|
+
|
|
147
|
+
if result:
|
|
148
|
+
doc_id = result[0]
|
|
149
|
+
doc_id, title, content = get_document_content_properly(cursor, doc_id)
|
|
150
|
+
|
|
151
|
+
print(f"Document ID: {doc_id}")
|
|
152
|
+
print(f"Title: {title[:100]}...")
|
|
153
|
+
print(f"Content: {content[:200]}...")
|
|
154
|
+
print(f"Content length: {len(content)}")
|
|
155
|
+
|
|
156
|
+
return len(content) > 0
|
|
157
|
+
else:
|
|
158
|
+
print("No documents found")
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
finally:
|
|
162
|
+
cursor.close()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
test_stream_reading()
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Cache Configuration Module
|
|
3
|
+
|
|
4
|
+
This module provides configuration management for the LLM caching layer,
|
|
5
|
+
supporting both YAML file configuration and environment variable overrides.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import yaml
|
|
10
|
+
import logging
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Dict, Any, Optional
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class CacheConfig:
|
|
20
|
+
"""Configuration model for LLM caching."""
|
|
21
|
+
|
|
22
|
+
# Core settings
|
|
23
|
+
enabled: bool = True
|
|
24
|
+
backend: str = "iris" # memory, iris, redis
|
|
25
|
+
ttl_seconds: int = 3600
|
|
26
|
+
normalize_prompts: bool = False
|
|
27
|
+
max_cache_size: int = 1000
|
|
28
|
+
|
|
29
|
+
# IRIS-specific settings
|
|
30
|
+
table_name: str = "llm_cache"
|
|
31
|
+
iris_schema: str = "RAG"
|
|
32
|
+
connection_timeout: int = 30
|
|
33
|
+
cleanup_batch_size: int = 1000
|
|
34
|
+
auto_cleanup: bool = True
|
|
35
|
+
cleanup_interval: int = 86400
|
|
36
|
+
|
|
37
|
+
# Key generation settings
|
|
38
|
+
include_temperature: bool = True
|
|
39
|
+
include_max_tokens: bool = True
|
|
40
|
+
include_model_name: bool = True
|
|
41
|
+
hash_algorithm: str = "sha256"
|
|
42
|
+
normalize_whitespace: bool = True
|
|
43
|
+
normalize_case: bool = False
|
|
44
|
+
|
|
45
|
+
# Monitoring settings
|
|
46
|
+
monitoring_enabled: bool = True
|
|
47
|
+
log_operations: bool = False
|
|
48
|
+
track_stats: bool = True
|
|
49
|
+
metrics_interval: int = 300
|
|
50
|
+
|
|
51
|
+
# Error handling settings
|
|
52
|
+
graceful_fallback: bool = True
|
|
53
|
+
max_retries: int = 3
|
|
54
|
+
retry_delay: int = 1
|
|
55
|
+
operation_timeout: int = 10
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_env(cls) -> "CacheConfig":
|
|
59
|
+
"""Create configuration from environment variables."""
|
|
60
|
+
config = cls()
|
|
61
|
+
|
|
62
|
+
# Override with environment variables if present
|
|
63
|
+
if "LLM_CACHE_ENABLED" in os.environ:
|
|
64
|
+
config.enabled = os.environ["LLM_CACHE_ENABLED"].lower() in (
|
|
65
|
+
"true",
|
|
66
|
+
"1",
|
|
67
|
+
"yes",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if "LLM_CACHE_BACKEND" in os.environ:
|
|
71
|
+
config.backend = os.environ["LLM_CACHE_BACKEND"]
|
|
72
|
+
|
|
73
|
+
if "LLM_CACHE_TTL" in os.environ:
|
|
74
|
+
config.ttl_seconds = int(os.environ["LLM_CACHE_TTL"])
|
|
75
|
+
|
|
76
|
+
if "LLM_CACHE_TABLE" in os.environ:
|
|
77
|
+
config.table_name = os.environ["LLM_CACHE_TABLE"]
|
|
78
|
+
|
|
79
|
+
if "LLM_CACHE_NORMALIZE_PROMPTS" in os.environ:
|
|
80
|
+
config.normalize_prompts = os.environ[
|
|
81
|
+
"LLM_CACHE_NORMALIZE_PROMPTS"
|
|
82
|
+
].lower() in ("true", "1", "yes")
|
|
83
|
+
|
|
84
|
+
if "LLM_CACHE_MAX_SIZE" in os.environ:
|
|
85
|
+
config.max_cache_size = int(os.environ["LLM_CACHE_MAX_SIZE"])
|
|
86
|
+
|
|
87
|
+
if "LLM_CACHE_IRIS_SCHEMA" in os.environ:
|
|
88
|
+
config.iris_schema = os.environ["LLM_CACHE_IRIS_SCHEMA"]
|
|
89
|
+
|
|
90
|
+
logger.info(
|
|
91
|
+
f"Cache configuration loaded from environment: backend={config.backend}, enabled={config.enabled}"
|
|
92
|
+
)
|
|
93
|
+
return config
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def from_yaml(cls, config_path: str = "config/cache_config.yaml") -> "CacheConfig":
|
|
97
|
+
"""Create configuration from YAML file with environment variable overrides."""
|
|
98
|
+
config = cls()
|
|
99
|
+
|
|
100
|
+
# Load from YAML file if it exists
|
|
101
|
+
yaml_path = Path(config_path)
|
|
102
|
+
if yaml_path.exists():
|
|
103
|
+
try:
|
|
104
|
+
with open(yaml_path, "r") as f:
|
|
105
|
+
yaml_data = yaml.safe_load(f)
|
|
106
|
+
|
|
107
|
+
if "llm_cache" in yaml_data:
|
|
108
|
+
cache_data = yaml_data["llm_cache"]
|
|
109
|
+
|
|
110
|
+
# Core settings
|
|
111
|
+
config.enabled = cache_data.get("enabled", config.enabled)
|
|
112
|
+
config.backend = cache_data.get("backend", config.backend)
|
|
113
|
+
config.ttl_seconds = cache_data.get(
|
|
114
|
+
"ttl_seconds", config.ttl_seconds
|
|
115
|
+
)
|
|
116
|
+
config.normalize_prompts = cache_data.get(
|
|
117
|
+
"normalize_prompts", config.normalize_prompts
|
|
118
|
+
)
|
|
119
|
+
config.max_cache_size = cache_data.get(
|
|
120
|
+
"max_cache_size", config.max_cache_size
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# IRIS settings
|
|
124
|
+
if "iris" in cache_data:
|
|
125
|
+
iris_data = cache_data["iris"]
|
|
126
|
+
config.table_name = iris_data.get(
|
|
127
|
+
"table_name", config.table_name
|
|
128
|
+
)
|
|
129
|
+
config.iris_schema = iris_data.get("schema", config.iris_schema)
|
|
130
|
+
config.connection_timeout = iris_data.get(
|
|
131
|
+
"connection_timeout", config.connection_timeout
|
|
132
|
+
)
|
|
133
|
+
config.cleanup_batch_size = iris_data.get(
|
|
134
|
+
"cleanup_batch_size", config.cleanup_batch_size
|
|
135
|
+
)
|
|
136
|
+
config.auto_cleanup = iris_data.get(
|
|
137
|
+
"auto_cleanup", config.auto_cleanup
|
|
138
|
+
)
|
|
139
|
+
config.cleanup_interval = iris_data.get(
|
|
140
|
+
"cleanup_interval", config.cleanup_interval
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Key generation settings
|
|
144
|
+
if "key_generation" in cache_data:
|
|
145
|
+
key_data = cache_data["key_generation"]
|
|
146
|
+
config.include_temperature = key_data.get(
|
|
147
|
+
"include_temperature", config.include_temperature
|
|
148
|
+
)
|
|
149
|
+
config.include_max_tokens = key_data.get(
|
|
150
|
+
"include_max_tokens", config.include_max_tokens
|
|
151
|
+
)
|
|
152
|
+
config.include_model_name = key_data.get(
|
|
153
|
+
"include_model_name", config.include_model_name
|
|
154
|
+
)
|
|
155
|
+
config.hash_algorithm = key_data.get(
|
|
156
|
+
"hash_algorithm", config.hash_algorithm
|
|
157
|
+
)
|
|
158
|
+
config.normalize_whitespace = key_data.get(
|
|
159
|
+
"normalize_whitespace", config.normalize_whitespace
|
|
160
|
+
)
|
|
161
|
+
config.normalize_case = key_data.get(
|
|
162
|
+
"normalize_case", config.normalize_case
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Monitoring settings
|
|
166
|
+
if "monitoring" in cache_data:
|
|
167
|
+
monitor_data = cache_data["monitoring"]
|
|
168
|
+
config.monitoring_enabled = monitor_data.get(
|
|
169
|
+
"enabled", config.monitoring_enabled
|
|
170
|
+
)
|
|
171
|
+
config.log_operations = monitor_data.get(
|
|
172
|
+
"log_operations", config.log_operations
|
|
173
|
+
)
|
|
174
|
+
config.track_stats = monitor_data.get(
|
|
175
|
+
"track_stats", config.track_stats
|
|
176
|
+
)
|
|
177
|
+
config.metrics_interval = monitor_data.get(
|
|
178
|
+
"metrics_interval", config.metrics_interval
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Error handling settings
|
|
182
|
+
if "error_handling" in cache_data:
|
|
183
|
+
error_data = cache_data["error_handling"]
|
|
184
|
+
config.graceful_fallback = error_data.get(
|
|
185
|
+
"graceful_fallback", config.graceful_fallback
|
|
186
|
+
)
|
|
187
|
+
config.max_retries = error_data.get(
|
|
188
|
+
"max_retries", config.max_retries
|
|
189
|
+
)
|
|
190
|
+
config.retry_delay = error_data.get(
|
|
191
|
+
"retry_delay", config.retry_delay
|
|
192
|
+
)
|
|
193
|
+
config.operation_timeout = error_data.get(
|
|
194
|
+
"operation_timeout", config.operation_timeout
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
logger.info(f"Cache configuration loaded from YAML: {config_path}")
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.warning(
|
|
201
|
+
f"Failed to load cache config from {config_path}: {e}. Using defaults."
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
logger.info(
|
|
205
|
+
f"Cache config file not found at {config_path}. Using defaults."
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Apply environment variable overrides
|
|
209
|
+
config = cls._apply_env_overrides(config)
|
|
210
|
+
|
|
211
|
+
return config
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def _apply_env_overrides(cls, config: "CacheConfig") -> "CacheConfig":
|
|
215
|
+
"""Apply environment variable overrides to configuration."""
|
|
216
|
+
# Override with environment variables if present
|
|
217
|
+
if "LLM_CACHE_ENABLED" in os.environ:
|
|
218
|
+
config.enabled = os.environ["LLM_CACHE_ENABLED"].lower() in (
|
|
219
|
+
"true",
|
|
220
|
+
"1",
|
|
221
|
+
"yes",
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
if "LLM_CACHE_BACKEND" in os.environ:
|
|
225
|
+
config.backend = os.environ["LLM_CACHE_BACKEND"]
|
|
226
|
+
|
|
227
|
+
if "LLM_CACHE_TTL" in os.environ:
|
|
228
|
+
config.ttl_seconds = int(os.environ["LLM_CACHE_TTL"])
|
|
229
|
+
|
|
230
|
+
if "LLM_CACHE_TABLE" in os.environ:
|
|
231
|
+
config.table_name = os.environ["LLM_CACHE_TABLE"]
|
|
232
|
+
|
|
233
|
+
if "LLM_CACHE_NORMALIZE_PROMPTS" in os.environ:
|
|
234
|
+
config.normalize_prompts = os.environ[
|
|
235
|
+
"LLM_CACHE_NORMALIZE_PROMPTS"
|
|
236
|
+
].lower() in ("true", "1", "yes")
|
|
237
|
+
|
|
238
|
+
if "LLM_CACHE_MAX_SIZE" in os.environ:
|
|
239
|
+
config.max_cache_size = int(os.environ["LLM_CACHE_MAX_SIZE"])
|
|
240
|
+
|
|
241
|
+
if "LLM_CACHE_REDIS_URL" in os.environ:
|
|
242
|
+
config.redis_url = os.environ["LLM_CACHE_REDIS_URL"]
|
|
243
|
+
|
|
244
|
+
if "LLM_CACHE_IRIS_SCHEMA" in os.environ:
|
|
245
|
+
config.iris_schema = os.environ["LLM_CACHE_IRIS_SCHEMA"]
|
|
246
|
+
|
|
247
|
+
return config
|
|
248
|
+
|
|
249
|
+
def validate(self) -> bool:
|
|
250
|
+
"""Validate the configuration settings."""
|
|
251
|
+
if self.backend not in ["memory", "iris"]:
|
|
252
|
+
logger.error(
|
|
253
|
+
f"Invalid cache backend: {self.backend}. Supported backends: memory, iris"
|
|
254
|
+
)
|
|
255
|
+
return False
|
|
256
|
+
|
|
257
|
+
if self.ttl_seconds <= 0:
|
|
258
|
+
logger.error(f"Invalid TTL: {self.ttl_seconds}")
|
|
259
|
+
return False
|
|
260
|
+
|
|
261
|
+
if self.max_cache_size <= 0:
|
|
262
|
+
logger.error(f"Invalid max cache size: {self.max_cache_size}")
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
if self.hash_algorithm not in ["sha256", "md5", "sha1"]:
|
|
266
|
+
logger.error(f"Invalid hash algorithm: {self.hash_algorithm}")
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
272
|
+
"""Convert configuration to dictionary."""
|
|
273
|
+
return {
|
|
274
|
+
"enabled": self.enabled,
|
|
275
|
+
"backend": self.backend,
|
|
276
|
+
"ttl_seconds": self.ttl_seconds,
|
|
277
|
+
"normalize_prompts": self.normalize_prompts,
|
|
278
|
+
"max_cache_size": self.max_cache_size,
|
|
279
|
+
"table_name": self.table_name,
|
|
280
|
+
"iris_schema": self.iris_schema,
|
|
281
|
+
"connection_timeout": self.connection_timeout,
|
|
282
|
+
"redis_url": self.redis_url,
|
|
283
|
+
"redis_prefix": self.redis_prefix,
|
|
284
|
+
"monitoring_enabled": self.monitoring_enabled,
|
|
285
|
+
"graceful_fallback": self.graceful_fallback,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def load_cache_config(config_path: Optional[str] = None) -> CacheConfig:
|
|
290
|
+
"""
|
|
291
|
+
Load cache configuration from YAML file with environment overrides.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
config_path: Path to YAML config file. Defaults to 'config/cache_config.yaml'
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
CacheConfig instance
|
|
298
|
+
"""
|
|
299
|
+
if config_path is None:
|
|
300
|
+
config_path = "config/cache_config.yaml"
|
|
301
|
+
|
|
302
|
+
config = CacheConfig.from_yaml(config_path)
|
|
303
|
+
|
|
304
|
+
if not config.validate():
|
|
305
|
+
logger.warning("Cache configuration validation failed. Using safe defaults.")
|
|
306
|
+
config = CacheConfig() # Use defaults
|
|
307
|
+
|
|
308
|
+
return config
|