Skip to content
179 changes: 179 additions & 0 deletions AI_SERVICE_DECOUPLING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# AI Service Decoupling - Implementation Summary

## Overview
This refactoring addresses the tight coupling issue between the main application and specific AI service providers. The implementation introduces a dependency injection pattern that makes it easy to swap service providers, add abstractions for testing, and improve overall scalability.

## Problem Statement
**Original Issue:** The main application (`main.py`) directly imported and called AI services (e.g., `ai_service`, `hf_service`), creating tight coupling that made it difficult to:
- Swap service providers
- Add abstractions for testing
- Mock services for unit tests
- Scale or modify individual services independently

## Solution Architecture

### 1. Service Interfaces (`ai_interfaces.py`)
- **Protocols Defined**: Abstract protocols for all AI services using Python's `Protocol` type
- `ActionPlanService`: Generate action plans for civic issues
- `ChatService`: Conversational AI functionality
- `MLASummaryService`: Generate MLA information summaries
- `DetectionService`: Generic interface for all image detection services

- **Dependency Injection Container**: `AIServiceContainer` holds all service instances
- **Global Access**: `get_ai_services()` provides access to initialized services
- **Initialization**: `initialize_ai_services()` sets up the global container

### 2. Concrete Implementations

#### Gemini AI Services (`gemini_services.py`)
- `GeminiActionPlanService`
- `GeminiChatService`
- `GeminiMLASummaryService`

#### HuggingFace Detection Services (`hf_detection_services.py`)
- `HFVandalismDetectionService`: Graffiti and vandalism detection
- `HFInfrastructureDetectionService`: Infrastructure damage detection
- `HFFloodingDetectionService`: Flooding and waterlogging detection
- `PotholeDetectionService`: Local pothole detection
- `GarbageDetectionService`: Local garbage detection

#### Mock Services for Testing
- `mock_services.py`: Mock implementations of Gemini services
- `mock_detection_services.py`: Mock implementations of detection services

### 3. Service Factory (`ai_factory.py`)
- **Environment-based Configuration**: Services selected via `AI_SERVICE_TYPE` environment variable
- `"gemini"`: Production services (default)
- `"mock"`: Testing/mock services
- **Factory Functions**: Create individual services or all services at once
- **Easy Switching**: Change service provider without modifying application code

### 4. Application Integration (`main.py`)
**Before:**
```python
from hf_service import detect_vandalism_clip, detect_flooding_clip, detect_infrastructure_clip
from pothole_detection import detect_potholes
from garbage_detection import detect_garbage

# Direct calls to services
detections = await detect_vandalism_clip(pil_image, client=client)
```

**After:**
```python
from ai_interfaces import get_ai_services, initialize_ai_services
from ai_factory import create_all_ai_services

# Initialization at startup
services = create_all_ai_services()
initialize_ai_services(*services)

# Usage via dependency injection
ai_services = get_ai_services()
detections = await ai_services.vandalism_detection_service.detect(pil_image, client=client)
```

## Benefits

### 1. **Loose Coupling**
- Application code depends on interfaces, not concrete implementations
- Easy to swap between different service providers
- No direct imports of service implementations in main application

### 2. **Testability**
- Mock services can be easily injected for unit testing
- Tests run faster without external API calls
- Predictable test behavior with mock services

### 3. **Flexibility**
- Add new service providers by implementing the protocol
- Switch providers via environment variable
- No code changes needed to swap implementations

### 4. **Maintainability**
- Clear separation of concerns
- Service implementations isolated in their own modules
- Changes to one service don't affect others

### 5. **Scalability**
- Easy to add new detection types
- Simple to implement caching or rate limiting per service
- Can use different providers for different services

## Testing

### Test Coverage
1. **Unit Tests**: `test_ai_services.py` - Original AI services
2. **Comprehensive Tests**: `test_comprehensive_ai_services.py` - All services including detection
3. **Integration Tests**: Existing endpoint tests continue to work

### Running Tests
```bash
# Test basic AI services
python backend/test_ai_services.py

# Test all services including detection
python backend/test_comprehensive_ai_services.py

# Use mock services for testing
export AI_SERVICE_TYPE=mock
python backend/test_comprehensive_ai_services.py
```

## Configuration

### Environment Variables
- `AI_SERVICE_TYPE`: Service provider selection
- `"gemini"`: Use Gemini AI and HuggingFace (default)
- `"mock"`: Use mock services for testing
- `GEMINI_API_KEY`: API key for Gemini services
- `HF_TOKEN`: Token for HuggingFace API (optional)

## Migration Path

### For Adding New Services
1. Define protocol in `ai_interfaces.py`
2. Implement concrete class in appropriate module
3. Create mock version in mock module
4. Add factory function in `ai_factory.py`
5. Update container initialization

### For Switching Providers
1. Implement new service class following the protocol
2. Add to factory with new service type
3. Set `AI_SERVICE_TYPE` environment variable

## Files Modified
- `backend/ai_interfaces.py`: Extended with detection service protocols
- `backend/main.py`: Removed direct imports, added DI pattern
- `backend/ai_factory.py`: Added detection service factories

## Files Added
- `backend/hf_detection_services.py`: HuggingFace detection implementations
- `backend/mock_detection_services.py`: Mock detection implementations
- `backend/test_comprehensive_ai_services.py`: Comprehensive test suite

## Verification

### No Tight Coupling
✅ All direct imports of `hf_service` removed from `main.py`
✅ All direct imports of detection modules removed from `main.py`
✅ All services accessed via `get_ai_services()` dependency injection
✅ Services can be swapped without changing application code

### Tests Pass
✅ All existing tests continue to pass
✅ New comprehensive tests verify all services work
✅ Mock services can be used for fast testing

## Future Enhancements

1. **Add More Providers**: Easy to add OpenAI, Anthropic, or other AI providers
2. **Service Chaining**: Combine multiple services in pipelines
3. **Caching Layer**: Add caching decorator to service methods
4. **Rate Limiting**: Implement rate limiting per service
5. **Monitoring**: Add service health checks and metrics
6. **Circuit Breaker**: Add resilience patterns for external APIs

## Conclusion
The refactoring successfully eliminates tight coupling between the application and AI service providers. The new architecture provides flexibility, testability, and maintainability while preserving all existing functionality. The implementation follows SOLID principles and makes the codebase more professional and production-ready.
Loading
Loading