Fss-Rag-Mini/scripts/test-configs.py
BobAi 2f2dd6880b Add comprehensive LLM provider support and educational error handling
 Features:
- Multi-provider LLM support (OpenAI, Claude, OpenRouter, LM Studio)
- Educational config examples with setup guides
- Comprehensive documentation in docs/LLM_PROVIDERS.md
- Config validation testing system

🎯 Beginner Experience:
- Friendly error messages for common mistakes
- Educational explanations for technical concepts
- Step-by-step troubleshooting guidance
- Clear next-steps for every error condition

🛠 Technical:
- Extended LLMConfig dataclass for cloud providers
- Automated config validation script
- Enhanced error handling in core components
- Backward-compatible configuration system

📚 Documentation:
- Provider comparison tables with costs/quality
- Setup instructions for each LLM provider
- Troubleshooting guides and testing procedures
- Environment variable configuration options

All configs pass validation tests. Ready for production use.
2025-08-14 16:39:12 +10:00

124 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Test script to validate all config examples are syntactically correct
and contain required fields for FSS-Mini-RAG.
"""
import yaml
import sys
from pathlib import Path
from typing import Dict, Any, List
def validate_config_structure(config: Dict[str, Any], config_name: str) -> List[str]:
"""Validate that config has required structure."""
errors = []
# Required sections
required_sections = ['chunking', 'streaming', 'files', 'embedding', 'search']
for section in required_sections:
if section not in config:
errors.append(f"{config_name}: Missing required section '{section}'")
# Validate chunking section
if 'chunking' in config:
chunking = config['chunking']
required_chunking = ['max_size', 'min_size', 'strategy']
for field in required_chunking:
if field not in chunking:
errors.append(f"{config_name}: Missing chunking.{field}")
# Validate types and ranges
if 'max_size' in chunking and not isinstance(chunking['max_size'], int):
errors.append(f"{config_name}: chunking.max_size must be integer")
if 'min_size' in chunking and not isinstance(chunking['min_size'], int):
errors.append(f"{config_name}: chunking.min_size must be integer")
if 'strategy' in chunking and chunking['strategy'] not in ['semantic', 'fixed']:
errors.append(f"{config_name}: chunking.strategy must be 'semantic' or 'fixed'")
# Validate embedding section
if 'embedding' in config:
embedding = config['embedding']
if 'preferred_method' in embedding:
valid_methods = ['ollama', 'ml', 'hash', 'auto']
if embedding['preferred_method'] not in valid_methods:
errors.append(f"{config_name}: embedding.preferred_method must be one of {valid_methods}")
# Validate LLM section (if present)
if 'llm' in config:
llm = config['llm']
if 'synthesis_temperature' in llm:
temp = llm['synthesis_temperature']
if not isinstance(temp, (int, float)) or temp < 0 or temp > 1:
errors.append(f"{config_name}: llm.synthesis_temperature must be number between 0-1")
return errors
def test_config_file(config_path: Path) -> bool:
"""Test a single config file."""
print(f"Testing {config_path.name}...")
try:
# Test YAML parsing
with open(config_path, 'r') as f:
config = yaml.safe_load(f)
if not config:
print(f"{config_path.name}: Empty or invalid YAML")
return False
# Test structure
errors = validate_config_structure(config, config_path.name)
if errors:
print(f"{config_path.name}: Structure errors:")
for error in errors:
print(f"{error}")
return False
print(f"{config_path.name}: Valid")
return True
except yaml.YAMLError as e:
print(f"{config_path.name}: YAML parsing error: {e}")
return False
except Exception as e:
print(f"{config_path.name}: Unexpected error: {e}")
return False
def main():
"""Test all config examples."""
script_dir = Path(__file__).parent
project_root = script_dir.parent
examples_dir = project_root / 'examples'
if not examples_dir.exists():
print(f"❌ Examples directory not found: {examples_dir}")
sys.exit(1)
# Find all config files
config_files = list(examples_dir.glob('config*.yaml'))
if not config_files:
print(f"❌ No config files found in {examples_dir}")
sys.exit(1)
print(f"🧪 Testing {len(config_files)} config files...\n")
all_passed = True
for config_file in sorted(config_files):
passed = test_config_file(config_file)
if not passed:
all_passed = False
print(f"\n{'='*50}")
if all_passed:
print("✅ All config files are valid!")
print("\n💡 To use any config:")
print(" cp examples/config-NAME.yaml /path/to/project/.mini-rag/config.yaml")
sys.exit(0)
else:
print("❌ Some config files have issues - please fix before release")
sys.exit(1)
if __name__ == '__main__':
main()