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.
Files changed (50) hide show
  1. adapters/rag_templates_bridge.py +578 -0
  2. common/__init__.py +1 -0
  3. common/batch_utils.py +294 -0
  4. common/config.py +58 -0
  5. common/connection_manager.py +242 -0
  6. common/connection_pool.py +445 -0
  7. common/database.py +141 -0
  8. common/database_schema_manager.py +289 -0
  9. common/db_init_with_indexes.py +181 -0
  10. common/db_vector_utils.py +181 -0
  11. common/environment_manager.py +220 -0
  12. common/huggingface_utils.py +206 -0
  13. common/iris_client.py +92 -0
  14. common/iris_connection_manager.py +411 -0
  15. common/iris_connection_pool.py +360 -0
  16. common/iris_connector.py +71 -0
  17. common/iris_dbapi_connector.py +323 -0
  18. common/iris_index_utils.py +195 -0
  19. common/iris_sql_utils.py +704 -0
  20. common/iris_stream_reader.py +166 -0
  21. common/llm_cache_config.py +308 -0
  22. common/llm_cache_iris.py +671 -0
  23. common/llm_cache_manager.py +911 -0
  24. common/utils.py +559 -0
  25. common/vector_sql_utils.py +584 -0
  26. evaluation_framework/__init__.py +66 -0
  27. evaluation_framework/biomedical_question_generator.py +826 -0
  28. evaluation_framework/comparative_analysis_system.py +1173 -0
  29. evaluation_framework/empirical_reporting.py +1298 -0
  30. evaluation_framework/evaluation_orchestrator.py +1123 -0
  31. evaluation_framework/execute_production_evaluation.py +382 -0
  32. evaluation_framework/pmc_data_pipeline.py +1332 -0
  33. evaluation_framework/production_evaluation_config.py +353 -0
  34. evaluation_framework/ragas_metrics_framework.py +1013 -0
  35. evaluation_framework/real_production_evaluation.py +544 -0
  36. evaluation_framework/run_10k_evaluation.py +175 -0
  37. evaluation_framework/simple_test.py +364 -0
  38. evaluation_framework/statistical_evaluation_methodology.py +1016 -0
  39. evaluation_framework/test_framework.py +281 -0
  40. evaluation_framework/test_iris_connectivity.py +244 -0
  41. evaluation_framework/test_small_scale_evaluation.py +432 -0
  42. evaluation_framework/true_e2e_evaluation.py +639 -0
  43. evaluation_framework/visualization_engine.py +585 -0
  44. iris_rag/__init__.py +284 -0
  45. iris_rag/config/default_config.yaml +295 -0
  46. iris_vector_rag-0.2.1.dist-info/METADATA +499 -0
  47. iris_vector_rag-0.2.1.dist-info/RECORD +50 -0
  48. iris_vector_rag-0.2.1.dist-info/WHEEL +5 -0
  49. iris_vector_rag-0.2.1.dist-info/entry_points.txt +2 -0
  50. iris_vector_rag-0.2.1.dist-info/top_level.txt +4 -0
@@ -0,0 +1,584 @@
1
+ """
2
+ Vector SQL Utilities for IRIS Database
3
+
4
+ This module encapsulates workarounds for InterSystems IRIS SQL vector operations limitations.
5
+ It provides helper functions that RAG pipelines can use to safely construct SQL queries
6
+ with vector operations.
7
+
8
+ Key IRIS SQL Limitations Addressed:
9
+
10
+ 1. TO_VECTOR() Function Rejects Parameter Markers:
11
+ The TO_VECTOR() function does not accept parameter markers (?, :param, or :%qpar),
12
+ which are standard in SQL for safe query parameterization.
13
+
14
+ 2. TOP/FETCH FIRST Clauses Cannot Be Parameterized:
15
+ The TOP and FETCH FIRST clauses, essential for limiting results in vector similarity
16
+ searches, do not accept parameter markers.
17
+
18
+ 3. Client Drivers Rewrite Literals:
19
+ Python, JDBC, and other client drivers replace embedded literals with :%qpar(n)
20
+ even when no parameter list is supplied, creating misleading parse errors.
21
+
22
+ These limitations force developers to use string interpolation instead of parameterized
23
+ queries, which introduces potential security risks. This module provides functions to
24
+ validate inputs and safely construct SQL queries using string interpolation.
25
+
26
+ SAFE VECTOR UTILITIES:
27
+ - build_safe_vector_dot_sql(): Safe single-parameter query builder
28
+ - execute_safe_vector_search(): Safe execution with single vector parameter
29
+
30
+ QUARANTINED UTILITIES (pending IRIS fix):
31
+ - format_vector_search_sql(): Deprecated - see docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
32
+ - format_vector_search_sql_with_params(): Deprecated - see docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
33
+ - execute_vector_search_with_params(): Deprecated - see docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
34
+
35
+ For more details on these limitations, see docs/IRIS_SQL_VECTOR_OPERATIONS.md
36
+ """
37
+
38
+ import logging
39
+ import re
40
+ from typing import Any, List, Tuple
41
+
42
+ logger = logging.getLogger(__name__)
43
+
44
+
45
+ def validate_vector_string(vector_string: str) -> bool:
46
+ """
47
+ Validates that a vector string contains a valid vector format.
48
+ Allows negative numbers and scientific notation while preventing SQL injection.
49
+
50
+ Args:
51
+ vector_string: The vector string to validate, typically in format "[0.1,-0.2,...]"
52
+
53
+ Returns:
54
+ bool: True if valid vector format, False otherwise
55
+
56
+ Example:
57
+ >>> validate_vector_string("[0.1,-0.2,3.5e-4]")
58
+ True
59
+ >>> validate_vector_string("'; DROP TABLE users; --")
60
+ False
61
+ """
62
+ # Check basic structure
63
+ stripped = vector_string.strip()
64
+ if not (stripped.startswith("[") and stripped.endswith("]")):
65
+ return False
66
+
67
+ # Extract content between brackets
68
+ content = stripped[1:-1]
69
+ if not content.strip():
70
+ return False
71
+
72
+ # Validate each number
73
+ parts = content.split(",")
74
+ for part in parts:
75
+ try:
76
+ float(part.strip())
77
+ except ValueError:
78
+ return False
79
+
80
+ # Check for SQL injection patterns
81
+ if re.search(
82
+ r"(DROP|DELETE|INSERT|UPDATE|SELECT|;|--)", vector_string, re.IGNORECASE
83
+ ):
84
+ return False
85
+
86
+ return True
87
+
88
+
89
+ def validate_top_k(top_k: Any) -> bool:
90
+ """
91
+ Validates that top_k is a positive integer.
92
+ This is important for security when using string interpolation.
93
+
94
+ Args:
95
+ top_k: The value to validate
96
+
97
+ Returns:
98
+ bool: True if top_k is a positive integer, False otherwise
99
+
100
+ Example:
101
+ >>> validate_top_k(10)
102
+ True
103
+ >>> validate_top_k(0)
104
+ False
105
+ >>> validate_top_k("10; DROP TABLE users; --")
106
+ False
107
+ """
108
+ if not isinstance(top_k, int):
109
+ return False
110
+ return top_k > 0
111
+
112
+
113
+ def format_vector_search_sql(
114
+ table_name: str,
115
+ vector_column: str,
116
+ vector_string: str,
117
+ embedding_dim: int,
118
+ top_k: int,
119
+ id_column: str = "doc_id",
120
+ content_column: str = "text_content",
121
+ additional_where: str = None,
122
+ ) -> str:
123
+ """
124
+ @deprecated - Quarantined pending IRIS fix
125
+ See docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
126
+
127
+ Constructs a SQL query for vector search using careful string concatenation
128
+ to avoid IRIS driver auto-parameterization issues.
129
+
130
+ IRIS-specific workaround: The IRIS driver converts embedded literals to :%qpar(n)
131
+ parameter markers automatically, but TO_VECTOR() and TOP clauses cannot accept
132
+ parameter markers. This function constructs SQL to avoid triggering the
133
+ auto-parameterization.
134
+
135
+ Args:
136
+ table_name: The name of the table to search
137
+ vector_column: The name of the column containing vector embeddings
138
+ vector_string: The vector string to search for, in format "[0.1,0.2,...]"
139
+ embedding_dim: The dimension of the embedding vectors
140
+ top_k: The number of results to return
141
+ id_column: The name of the ID column (default: "doc_id")
142
+ content_column: The name of the content column (default: "text_content")
143
+ Set to None if you don't want to include content in results
144
+ additional_where: Additional WHERE clause conditions (default: None)
145
+
146
+ Returns:
147
+ str: The formatted SQL query string
148
+
149
+ Raises:
150
+ ValueError: If any of the inputs fail validation
151
+
152
+ Example:
153
+ >>> format_vector_search_sql(
154
+ ... "SourceDocuments",
155
+ ... "embedding",
156
+ ... "[0.1,0.2,0.3]",
157
+ ... 768,
158
+ ... 10,
159
+ ... "doc_id",
160
+ ... "text_content"
161
+ ... )
162
+ 'SELECT TOP 10 doc_id, text_content,
163
+ VECTOR_COSINE(embedding, TO_VECTOR('[0.1,0.2,0.3]', FLOAT, 768)) AS score
164
+ FROM SourceDocuments
165
+ WHERE embedding IS NOT NULL
166
+ ORDER BY score DESC'
167
+ """
168
+ # Validate table_name to prevent SQL injection (allow schema.table format)
169
+ if not re.match(r"^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)?$", table_name):
170
+ raise ValueError(f"Invalid table name: {table_name}")
171
+
172
+ # Validate column names to prevent SQL injection
173
+ for col in [vector_column, id_column]:
174
+ if not re.match(r"^[a-zA-Z0-9_]+$", col):
175
+ raise ValueError(f"Invalid column name: {col}")
176
+
177
+ if content_column and not re.match(r"^[a-zA-Z0-9_]+$", content_column):
178
+ raise ValueError(f"Invalid content column name: {content_column}")
179
+
180
+ # Validate vector_string
181
+ if not validate_vector_string(vector_string):
182
+ raise ValueError(f"Invalid vector string: {vector_string}")
183
+
184
+ # Validate embedding_dim
185
+ if not isinstance(embedding_dim, int) or embedding_dim <= 0:
186
+ raise ValueError(f"Invalid embedding dimension: {embedding_dim}")
187
+
188
+ # Validate top_k
189
+ if not validate_top_k(top_k):
190
+ raise ValueError(f"Invalid top_k value: {top_k}")
191
+
192
+ # Convert values to strings to avoid auto-parameterization
193
+ top_k_str = str(top_k)
194
+ embedding_dim_str = str(embedding_dim)
195
+
196
+ # Construct SQL using string concatenation to avoid f-string literal detection
197
+ select_parts = ["SELECT TOP ", top_k_str, " ", id_column]
198
+ if content_column:
199
+ select_parts.extend([", ", content_column])
200
+
201
+ # Construct TO_VECTOR call carefully to avoid parameter detection
202
+ # Use FLOAT datatype to match how test data was created (see tests/fixtures/embedding_generator.py:247)
203
+ vector_func_parts = [
204
+ ", VECTOR_COSINE(",
205
+ vector_column,
206
+ ", TO_VECTOR('",
207
+ vector_string,
208
+ "', FLOAT, ",
209
+ embedding_dim_str,
210
+ ")) AS score",
211
+ ]
212
+ select_parts.extend(vector_func_parts)
213
+ select_clause = "".join(select_parts)
214
+
215
+ # Construct the WHERE clause
216
+ where_parts = ["WHERE ", vector_column, " IS NOT NULL"]
217
+ if additional_where:
218
+ where_parts.extend([" AND (", additional_where, ")"])
219
+ where_clause = "".join(where_parts)
220
+
221
+ # Construct the full SQL query using string concatenation
222
+ sql_parts = [
223
+ select_clause,
224
+ " FROM ",
225
+ table_name,
226
+ " ",
227
+ where_clause,
228
+ " ORDER BY score DESC",
229
+ ]
230
+
231
+ return "".join(sql_parts)
232
+
233
+
234
+ def format_vector_search_sql_with_params(
235
+ table_name: str,
236
+ vector_column: str,
237
+ embedding_dim: int,
238
+ top_k: int,
239
+ id_column: str = "doc_id",
240
+ content_column: str = "text_content",
241
+ additional_where: str = None,
242
+ ) -> str:
243
+ """
244
+ @deprecated - Quarantined pending IRIS fix
245
+ See docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
246
+
247
+ Constructs a SQL query for vector search using parameter placeholders.
248
+ Uses string concatenation to avoid IRIS driver auto-parameterization issues.
249
+
250
+ IRIS-specific workaround: Even when using ? placeholders, the IRIS driver
251
+ can still auto-parameterize literals in f-strings. This function uses
252
+ string concatenation to avoid triggering the auto-parameterization.
253
+
254
+ Args:
255
+ table_name: The name of the table to search
256
+ vector_column: The name of the column containing vector embeddings
257
+ embedding_dim: The dimension of the embedding vectors (for documentation)
258
+ top_k: The number of results to return
259
+ id_column: The name of the ID column (default: "doc_id")
260
+ content_column: The name of the content column (default: "text_content")
261
+ additional_where: Additional WHERE clause conditions (default: None)
262
+
263
+ Returns:
264
+ str: The formatted SQL query string with ? placeholder
265
+ """
266
+ # Validate inputs (reuse existing validation)
267
+ if not re.match(r"^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)?$", table_name):
268
+ raise ValueError(f"Invalid table name: {table_name}")
269
+
270
+ for col in [vector_column, id_column]:
271
+ if not re.match(r"^[a-zA-Z0-9_]+$", col):
272
+ raise ValueError(f"Invalid column name: {col}")
273
+
274
+ if content_column and not re.match(r"^[a-zA-Z0-9_]+$", content_column):
275
+ raise ValueError(f"Invalid content column name: {content_column}")
276
+
277
+ if not validate_top_k(top_k):
278
+ raise ValueError(f"Invalid top_k value: {top_k}")
279
+
280
+ # Convert values to strings to avoid auto-parameterization
281
+ top_k_str = str(top_k)
282
+ embedding_dim_str = str(embedding_dim)
283
+
284
+ # Construct SQL using string concatenation to avoid f-string literal detection
285
+ select_parts = ["SELECT TOP ", top_k_str, " ", id_column]
286
+ if content_column:
287
+ select_parts.extend([", ", content_column])
288
+
289
+ # Construct TO_VECTOR call with ? placeholder but avoid embedding dimension parameterization
290
+ # Use FLOAT datatype to match how test data was created (see tests/fixtures/embedding_generator.py:247)
291
+ vector_func_parts = [
292
+ ", VECTOR_COSINE(",
293
+ vector_column,
294
+ ", TO_VECTOR(?, FLOAT, ",
295
+ embedding_dim_str,
296
+ ")) AS score",
297
+ ]
298
+ select_parts.extend(vector_func_parts)
299
+ select_clause = "".join(select_parts)
300
+
301
+ # Construct the WHERE clause
302
+ where_parts = ["WHERE ", vector_column, " IS NOT NULL"]
303
+ if additional_where:
304
+ where_parts.extend([" AND (", additional_where, ")"])
305
+ where_clause = "".join(where_parts)
306
+
307
+ # Construct the full SQL query using string concatenation
308
+ sql_parts = [
309
+ select_clause,
310
+ " FROM ",
311
+ table_name,
312
+ " ",
313
+ where_clause,
314
+ " ORDER BY score DESC",
315
+ ]
316
+
317
+ return "".join(sql_parts)
318
+
319
+
320
+ def execute_vector_search_with_params(
321
+ cursor: Any, sql: str, vector_string: str, table_name: str = "RAG.SourceDocuments"
322
+ ) -> List[Tuple]:
323
+ """
324
+ @deprecated - Quarantined pending IRIS fix
325
+ See docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
326
+
327
+ Executes a vector search SQL query using parameters.
328
+
329
+ Args:
330
+ cursor: A database cursor object
331
+ sql: The SQL query with ? placeholder
332
+ vector_string: The vector string to use as parameter
333
+ table_name: The table name for diagnostic queries (optional, defaults to RAG.SourceDocuments)
334
+
335
+ Returns:
336
+ List[Tuple]: The query results
337
+ """
338
+ results = []
339
+ try:
340
+ # Use the provided table name directly instead of parsing from SQL
341
+ logger.debug(f"Using table name: {table_name}")
342
+
343
+ count_sql = f"SELECT COUNT(*) FROM {table_name} WHERE embedding IS NOT NULL"
344
+ logger.debug(f"Executing count SQL: {count_sql}")
345
+ try:
346
+ cursor.execute(count_sql)
347
+ embedding_result = cursor.fetchone()
348
+ # Handle both real results and mock objects
349
+ if embedding_result:
350
+ try:
351
+ embedding_count = (
352
+ embedding_result[0]
353
+ if hasattr(embedding_result, "__getitem__")
354
+ else 0
355
+ )
356
+ except (TypeError, IndexError):
357
+ # Handle Mock objects or other non-subscriptable results
358
+ embedding_count = 0
359
+ else:
360
+ embedding_count = 0
361
+ logger.debug(
362
+ f"Table {table_name} has {embedding_count} rows with embeddings"
363
+ )
364
+ except Exception as count_error:
365
+ logger.error(f"Error executing count SQL: {count_error}")
366
+ logger.error(f"Count SQL was: {count_sql}")
367
+ # Skip count check and proceed with vector search
368
+ embedding_count = 0
369
+
370
+ # Also check total rows
371
+ total_sql = f"SELECT COUNT(*) FROM {table_name}"
372
+ logger.debug(f"Executing total SQL: {total_sql}")
373
+ try:
374
+ cursor.execute(total_sql)
375
+ total_result = cursor.fetchone()
376
+ # Handle both real results and mock objects
377
+ if total_result:
378
+ try:
379
+ total_count = (
380
+ total_result[0] if hasattr(total_result, "__getitem__") else 0
381
+ )
382
+ except (TypeError, IndexError):
383
+ # Handle Mock objects or other non-subscriptable results
384
+ total_count = 0
385
+ else:
386
+ total_count = 0
387
+ logger.debug(f"Table {table_name} has {total_count} total rows")
388
+ except Exception as total_error:
389
+ logger.error(f"Error executing total count SQL: {total_error}")
390
+ logger.error(f"Total SQL was: {total_sql}")
391
+ # Skip total count check and proceed with vector search
392
+ total_count = 0
393
+
394
+ logger.debug(f"Executing vector search SQL: {sql}")
395
+ logger.debug(f"Vector string parameter: {vector_string[:100]}...")
396
+
397
+ # Execute the SQL with parameter binding
398
+ cursor.execute(sql, [vector_string])
399
+
400
+ # Try to fetch results with better error handling
401
+ try:
402
+ fetched_rows = cursor.fetchall()
403
+ if fetched_rows:
404
+ results = fetched_rows
405
+ # Handle Mock objects that don't have len()
406
+ try:
407
+ result_count = len(results)
408
+ logger.debug(f"Found {result_count} results.")
409
+ except (TypeError, AttributeError):
410
+ # Handle Mock objects or other non-sequence types
411
+ logger.debug("Found results (count unavailable due to mock object)")
412
+ else:
413
+ logger.debug("No results returned from vector search")
414
+ except StopIteration as e:
415
+ logger.error(f"StopIteration error during fetchall(): {e}")
416
+ logger.error(
417
+ "This usually indicates the cursor is empty or in an invalid state"
418
+ )
419
+ # Return empty results instead of raising
420
+ results = []
421
+ except Exception as fetch_error:
422
+ logger.error(f"Error during fetchall(): {fetch_error}")
423
+ raise
424
+ except Exception as e:
425
+ logger.error(f"Error during vector search: {e}")
426
+ logger.error(f"SQL was: {sql}")
427
+ logger.error(f"Vector parameter was: {vector_string[:100]}...")
428
+ raise
429
+ return results
430
+
431
+
432
+ # =============================================================================
433
+ # SAFE VECTOR UTILITIES (PROVEN PATTERN)
434
+ # =============================================================================
435
+
436
+
437
+ def build_safe_vector_dot_sql(
438
+ table: str,
439
+ vector_column: str,
440
+ vector_string: str,
441
+ vector_dimension: int,
442
+ id_column: str = "doc_id",
443
+ extra_columns: list[str] | None = None,
444
+ top_k: int = 5,
445
+ additional_where: str | None = None,
446
+ ) -> str:
447
+ """
448
+ Build safe vector search SQL with embedded vector string.
449
+
450
+ CRITICAL: TO_VECTOR() does NOT accept parameter markers (?, :param, etc.)
451
+ Vector string MUST be embedded directly in SQL with data type and dimension.
452
+
453
+ Args:
454
+ table: Table name (e.g., "RAG.SourceDocuments")
455
+ vector_column: Vector column name (e.g., "embedding")
456
+ vector_string: Vector as bracketed comma-separated string (e.g., "[0.1,0.2,0.3]")
457
+ vector_dimension: Dimension of the vector (e.g., 384)
458
+ id_column: ID column name (default: "doc_id")
459
+ extra_columns: Additional columns to select (optional)
460
+ top_k: Number of results to return (default: 5)
461
+ additional_where: Additional WHERE conditions (optional)
462
+
463
+ Returns:
464
+ str: Safe SQL query with embedded vector string
465
+
466
+ Example:
467
+ sql = build_safe_vector_dot_sql("RAG.SourceDocuments", "embedding", "[0.1,0.2,0.3]", 384, "doc_id", ["title"], 5)
468
+ cursor.execute(sql) # No parameters needed - vector embedded in SQL
469
+ """
470
+ # Validate identifiers to prevent SQL injection
471
+ import re
472
+
473
+ # Validate table name (allow schema.table format)
474
+ if not re.match(r"^[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)?$", table):
475
+ raise ValueError(f"Invalid table name: {table}")
476
+
477
+ # Validate column names
478
+ for col in [vector_column, id_column]:
479
+ if not re.match(r"^[a-zA-Z0-9_]+$", col):
480
+ raise ValueError(f"Invalid column name: {col}")
481
+
482
+ if extra_columns:
483
+ for col in extra_columns:
484
+ if not re.match(r"^[a-zA-Z0-9_]+$", col):
485
+ raise ValueError(f"Invalid extra column name: {col}")
486
+
487
+ # Validate top_k
488
+ if not isinstance(top_k, int) or top_k <= 0:
489
+ raise ValueError(f"Invalid top_k value: {top_k}")
490
+
491
+ # Validate vector_dimension
492
+ if not isinstance(vector_dimension, int) or vector_dimension <= 0:
493
+ raise ValueError(f"Invalid vector_dimension: {vector_dimension}")
494
+
495
+ # Validate vector string (security check)
496
+ if not validate_vector_string(vector_string):
497
+ raise ValueError(f"Invalid vector string: {vector_string}")
498
+
499
+ # Build SELECT clause
500
+ select_parts = [f"SELECT TOP {top_k} {id_column}"]
501
+ if extra_columns:
502
+ select_parts.extend([f", {col}" for col in extra_columns])
503
+ # IMPORTANT: Embed vector string directly with FLOAT type and dimension
504
+ # TO_VECTOR does NOT accept ? parameters
505
+ # Use FLOAT to match how test data was created (see tests/fixtures/embedding_generator.py:247)
506
+ select_parts.append(f", VECTOR_DOT_PRODUCT({vector_column}, TO_VECTOR('{vector_string}', FLOAT, {vector_dimension})) AS score")
507
+
508
+ # Build FROM clause
509
+ from_clause = f" FROM {table}"
510
+
511
+ # Build WHERE clause
512
+ where_parts = [f" WHERE {vector_column} IS NOT NULL"]
513
+ if additional_where:
514
+ where_parts.append(f" AND ({additional_where})")
515
+
516
+ # Build ORDER BY clause
517
+ order_clause = " ORDER BY score DESC"
518
+
519
+ # Combine all parts
520
+ sql = "".join(select_parts) + from_clause + "".join(where_parts) + order_clause
521
+ return sql
522
+
523
+
524
+ def execute_safe_vector_search(
525
+ cursor, sql: str
526
+ ) -> list[tuple]:
527
+ """
528
+ Execute safe vector search with embedded vector string.
529
+
530
+ IMPORTANT: The vector string is already embedded in the SQL
531
+ (from build_safe_vector_dot_sql), so NO parameters are passed.
532
+
533
+ Args:
534
+ cursor: Database cursor
535
+ sql: SQL query from build_safe_vector_dot_sql() with embedded vector
536
+
537
+ Returns:
538
+ list[tuple]: Query results
539
+
540
+ Example:
541
+ sql = build_safe_vector_dot_sql("RAG.SourceDocuments", "embedding", "[0.1,0.2,0.3]")
542
+ results = execute_safe_vector_search(cursor, sql)
543
+ """
544
+ # Execute with NO parameters - vector is embedded in SQL
545
+ cursor.execute(sql)
546
+ return cursor.fetchall()
547
+
548
+
549
+ def execute_vector_search(cursor: Any, sql: str) -> List[Tuple]:
550
+ """
551
+ @deprecated - Quarantined pending IRIS fix
552
+ See docs/reports/IRIS_VECTOR_SQL_PARAMETERIZATION_REPRO.md
553
+
554
+ Executes a vector search SQL query using the provided cursor.
555
+ Handles common errors and returns the results.
556
+
557
+ Args:
558
+ cursor: A database cursor object
559
+ sql: The SQL query to execute
560
+
561
+ Returns:
562
+ List[Tuple]: The query results
563
+
564
+ Raises:
565
+ Exception: If the query execution fails
566
+
567
+ Example:
568
+ >>> cursor = connection.cursor()
569
+ >>> sql = format_vector_search_sql(...)
570
+ >>> results = execute_vector_search(cursor, sql)
571
+ """
572
+ results = []
573
+ try:
574
+ logger.debug(f"Executing vector search SQL: {sql[:100]}...")
575
+ cursor.execute(sql) # No parameters passed as all are interpolated
576
+ fetched_rows = cursor.fetchall()
577
+ if fetched_rows:
578
+ results = fetched_rows
579
+ logger.debug(f"Found {len(results)} results.")
580
+ except Exception as e:
581
+ logger.error(f"Error during vector search: {e}")
582
+ # Re-raise the exception so the calling pipeline can handle it
583
+ raise
584
+ return results
@@ -0,0 +1,66 @@
1
+ """
2
+ Biomedical RAG Pipeline Evaluation Framework
3
+
4
+ A comprehensive, statistically rigorous evaluation system for comparing
5
+ biomedical RAG pipelines with empirical evidence and actionable insights.
6
+ """
7
+
8
+ __version__ = "1.0.0"
9
+ __author__ = "RAG Templates Team"
10
+
11
+ # Import warnings configuration
12
+ import warnings
13
+
14
+ warnings.filterwarnings("ignore", category=FutureWarning)
15
+ warnings.filterwarnings("ignore", category=UserWarning)
16
+
17
+ # Core components
18
+ try:
19
+ from .biomedical_question_generator import (
20
+ QuestionGenerationConfig,
21
+ create_biomedical_question_generator,
22
+ )
23
+ except ImportError as e:
24
+ print(f"Warning: Question generator not available - {e}")
25
+
26
+ try:
27
+ from .ragas_metrics_framework import create_biomedical_ragas_framework
28
+ except ImportError as e:
29
+ print(f"Warning: RAGAS framework not available - {e}")
30
+
31
+ try:
32
+ from .statistical_evaluation_methodology import create_statistical_framework
33
+ except ImportError as e:
34
+ print(f"Warning: Statistical framework not available - {e}")
35
+
36
+ try:
37
+ from .comparative_analysis_system import create_comparative_analysis_system
38
+ except ImportError as e:
39
+ print(f"Warning: Comparative analysis not available - {e}")
40
+
41
+ try:
42
+ from .pmc_data_pipeline import PMCProcessingConfig, create_pmc_data_pipeline
43
+ except ImportError as e:
44
+ print(f"Warning: PMC pipeline not available - {e}")
45
+
46
+ try:
47
+ from .evaluation_orchestrator import EvaluationOrchestrator
48
+ except ImportError as e:
49
+ print(f"Warning: Evaluation orchestrator not available - {e}")
50
+
51
+ try:
52
+ from .empirical_reporting import create_empirical_reporting_framework
53
+ except ImportError as e:
54
+ print(f"Warning: Empirical reporting not available - {e}")
55
+
56
+ __all__ = [
57
+ "create_biomedical_question_generator",
58
+ "QuestionGenerationConfig",
59
+ "create_biomedical_ragas_framework",
60
+ "create_statistical_framework",
61
+ "create_comparative_analysis_system",
62
+ "create_pmc_data_pipeline",
63
+ "PMCProcessingConfig",
64
+ "EvaluationOrchestrator",
65
+ "create_empirical_reporting_framework",
66
+ ]