Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions deployment/api_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
🚀 EMOTION DETECTION API SERVER
"""🚀 EMOTION DETECTION API SERVER
===============================
REST API server for emotion detection with comprehensive security headers.
"""
Expand Down
5 changes: 2 additions & 3 deletions deployment/cloud-run/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""
Environment Configuration Management - Phase 3 Cloud Run Optimization
"""Environment Configuration Management - Phase 3 Cloud Run Optimization
Provides environment-specific settings for development, staging, and production
"""

Expand Down Expand Up @@ -216,4 +215,4 @@ def to_dict(self) -> Dict[str, Any]:

def get_config() -> EnvironmentConfig:
"""Get the global configuration instance"""
return config
return config
11 changes: 5 additions & 6 deletions deployment/cloud-run/debug_api_import.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Debug script to isolate the 'int' object is not callable error
"""Debug script to isolate the 'int' object is not callable error
"""

import sys
Expand All @@ -21,7 +20,7 @@

try:
print("2. Importing Flask-RESTX...")
from flask_restx import Api, Resource, fields, Namespace
from flask_restx import Api, Namespace
print("✅ Flask-RESTX imported successfully")
except Exception as e:
print(f"❌ Flask-RESTX import failed: {e}")
Expand Down Expand Up @@ -75,21 +74,21 @@ def test_handler(error):
# Now let's test the actual imports from secure_api_server.py
try:
print("\n7. Testing security_headers import...")
from security_headers import add_security_headers
from security_headers import add_security_headers # noqa: F401
print("✅ security_headers imported successfully")
except Exception as e:
print(f"❌ security_headers import failed: {e}")

try:
print("8. Testing rate_limiter import...")
from rate_limiter import rate_limit
from rate_limiter import rate_limit # noqa: F401
print("✅ rate_limiter imported successfully")
except Exception as e:
print(f"❌ rate_limiter import failed: {e}")

try:
print("9. Testing model_utils import...")
from model_utils import ensure_model_loaded, predict_emotions, get_model_status, validate_text_input
from model_utils import ensure_model_loaded, predict_emotions, get_model_status, validate_text_input # noqa: F401
print("✅ model_utils imported successfully")
except Exception as e:
print(f"❌ model_utils import failed: {e}")
Expand Down
15 changes: 7 additions & 8 deletions deployment/cloud-run/debug_errorhandler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Debug script to investigate the errorhandler issue
"""Debug script to investigate the errorhandler issue
"""

import sys
Expand All @@ -13,7 +12,7 @@

try:
from flask import Flask
from flask_restx import Api, Resource, fields, Namespace
from flask_restx import Api
print("✅ Imports successful")
except Exception as e:
print(f"❌ Import failed: {e}")
Expand All @@ -33,26 +32,26 @@
sys.exit(1)

# Let's inspect the API object in detail
print(f"\n🔍 API object details:")
print("\n🔍 API object details:")
print(f"Type: {type(api)}")
print(f"Dir: {[attr for attr in dir(api) if not attr.startswith('_')]}")
print(f"Has errorhandler: {'errorhandler' in dir(api)}")

try:
errorhandler_method = getattr(api, 'errorhandler')
errorhandler_method = api.errorhandler
print(f"✅ errorhandler method found: {type(errorhandler_method)}")
print(f"errorhandler callable: {callable(errorhandler_method)}")
except Exception as e:
print(f"❌ errorhandler method access failed: {e}")

# Let's check if there are any global variables that might be interfering
print(f"\n🔍 Checking for global variable conflicts...")
print("\n🔍 Checking for global variable conflicts...")
print(f"Built-in errorhandler: {getattr(__builtins__, 'errorhandler', 'Not found')}")
print(f"Global errorhandler: {globals().get('errorhandler', 'Not found')}")

# Let's try to call errorhandler directly
try:
print(f"\n🔍 Testing errorhandler call...")
print("\n🔍 Testing errorhandler call...")
result = api.errorhandler(429)
print(f"✅ errorhandler(429) call successful: {type(result)}")
except Exception as e:
Expand All @@ -67,4 +66,4 @@
except Exception as e:
print(f"❌ Could not get Flask-RESTX version: {e}")

print("\n🔍 Debug complete.")
print("\n🔍 Debug complete.")
17 changes: 8 additions & 9 deletions deployment/cloud-run/debug_errorhandler_detailed.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Detailed debug script to understand the errorhandler issue
"""Detailed debug script to understand the errorhandler issue
"""

import os
Expand All @@ -25,13 +24,13 @@
exit(1)

# Let's inspect the API object in detail
print(f"\n🔍 API object details:")
print("\n🔍 API object details:")
print(f"Type: {type(api)}")
print(f"Dir: {[attr for attr in dir(api) if not attr.startswith('_')]}")
print(f"Has errorhandler: {'errorhandler' in dir(api)}")

try:
errorhandler_method = getattr(api, 'errorhandler')
errorhandler_method = api.errorhandler
print(f"✅ errorhandler method found: {type(errorhandler_method)}")
print(f"errorhandler callable: {callable(errorhandler_method)}")
print(f"errorhandler bound: {errorhandler_method.__self__ if hasattr(errorhandler_method, '__self__') else 'Not bound'}")
Expand All @@ -40,18 +39,18 @@

# Let's try to understand what happens when we call errorhandler
try:
print(f"\n🔍 Testing errorhandler call step by step...")
print("\n🔍 Testing errorhandler call step by step...")

# First, let's see what the method looks like
print(f"errorhandler method: {errorhandler_method}")
print(f"errorhandler method type: {type(errorhandler_method)}")

# Let's try calling it with different approaches
print(f"\nTrying direct call...")
print("\nTrying direct call...")
result = errorhandler_method(429)
print(f"Direct call result: {type(result)} - {result}")

print(f"\nTrying bound call...")
print("\nTrying bound call...")
result2 = api.errorhandler(429)
print(f"Bound call result: {type(result2)} - {result2}")

Expand All @@ -64,7 +63,7 @@
print(f"Error details: {e}")

# Let's check if there are any global variables that might be interfering
print(f"\n🔍 Checking for global variable conflicts...")
print("\n🔍 Checking for global variable conflicts...")
print(f"Built-in errorhandler: {getattr(__builtins__, 'errorhandler', 'Not found')}")
print(f"Global errorhandler: {globals().get('errorhandler', 'Not found')}")

Expand All @@ -76,4 +75,4 @@
except Exception as e:
print(f"❌ Could not get versions: {e}")

print("\n🔍 Debug complete.")
print("\n🔍 Debug complete.")
4 changes: 2 additions & 2 deletions deployment/cloud-run/docs_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ def serve_openapi_spec():
if os.path.commonpath([abs_spec_path, allowed_dir]) != allowed_dir:
return jsonify({'error': 'Invalid OpenAPI spec path'}), 400

with open(abs_spec_path, 'r', encoding='utf-8') as f:
with open(abs_spec_path, encoding='utf-8') as f:
content = f.read()
# Use a standard YAML mimetype
return Response(content, mimetype='application/x-yaml')
except Exception as e:
except Exception:
# Avoid leaking exact path in error; log on server side only if needed
return jsonify({'error': 'OpenAPI spec not found'}), 404

Expand Down
8 changes: 3 additions & 5 deletions deployment/cloud-run/health_monitor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""
Cloud Run Health Monitor - Phase 3 Optimization
"""Cloud Run Health Monitor - Phase 3 Optimization
Provides comprehensive health checks, graceful shutdown, and monitoring
"""

Expand Down Expand Up @@ -88,7 +87,6 @@ def check_model_health() -> Dict[str, Any]:
"""Check if ML models are loaded and responding"""
try:
# Import models (this will fail if models aren't loaded)
from secure_api_server import app

# Test model loading
start_time = time.time()
Expand All @@ -97,7 +95,7 @@ def check_model_health() -> Dict[str, Any]:
import importlib
modules_to_check = [
'src.models.emotion_detection.bert_classifier',
'src.models.summarization.t5_summarizer',
'src.models.summarization.t5_summarizer',
'src.models.voice_processing.whisper_transcriber'
]

Expand Down Expand Up @@ -239,4 +237,4 @@ def request_completed(self):

def get_health_monitor() -> HealthMonitor:
"""Get the global health monitor instance"""
return health_monitor
return health_monitor
6 changes: 2 additions & 4 deletions deployment/cloud-run/minimal_api_server.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#!/usr/bin/env python3
"""
Minimal Emotion Detection API Server
"""Minimal Emotion Detection API Server
Uses known working PyTorch/transformers combination
Matches the actual model architecture: RoBERTa with 12 emotion classes
"""

import logging
import os
import time
import os

from flask import Flask, request, jsonify
import psutil
Expand Down Expand Up @@ -155,4 +153,4 @@ def root():

# Start server
port = int(os.getenv('PORT', '8080'))
app.run(host='0.0.0.0', port=port, debug=False, threaded=True)
app.run(host='0.0.0.0', port=port, debug=False, threaded=True)
7 changes: 3 additions & 4 deletions deployment/cloud-run/minimal_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Minimal test to isolate the API setup issue
"""Minimal test to isolate the API setup issue
"""

import os
Expand All @@ -11,7 +10,7 @@
try:
print("1. Importing modules...")
from flask import Flask
from flask_restx import Api, Resource, fields, Namespace
from flask_restx import Api, fields, Namespace
print("✅ Imports successful")
except Exception as e:
print(f"❌ Imports failed: {e}")
Expand Down Expand Up @@ -69,4 +68,4 @@ def test_handler(error):
print(f"API errorhandler type: {type(api.errorhandler)}")
exit(1)

print("🎉 All tests passed!")
print("🎉 All tests passed!")
23 changes: 9 additions & 14 deletions deployment/cloud-run/model_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""
Shared model utilities for Cloud Run deployment.
"""Shared model utilities for Cloud Run deployment.

This module provides common functionality for model loading, inference,
and error handling to eliminate code duplication between API servers.
Expand Down Expand Up @@ -48,7 +47,7 @@ def _load_repo_id_from_config() -> Optional[str]:
cfg_path = Path('deployment/custom_model_config.json')
if cfg_path.exists():
try:
with open(cfg_path, 'r') as f:
with open(cfg_path) as f:
cfg = json.load(f)
repo_id = cfg.get('model_name') or cfg.get('repo_id')
if repo_id:
Expand All @@ -74,8 +73,7 @@ def _resolve_model_repo_id() -> str:


def ensure_model_loaded() -> bool:
"""
Thread-safe model loading with proper error handling.
"""Thread-safe model loading with proper error handling.

Returns:
bool: True if model is loaded successfully, False otherwise
Expand Down Expand Up @@ -163,14 +161,13 @@ def ensure_model_loaded() -> bool:
with model_lock:
model_loading = False

logger.exception(f"❌ Failed to load model: {str(e)}")
logger.exception(f"❌ Failed to load model: {e!s}")
logger.error("Model loading failed - check model configuration")
return False


def predict_emotions(text: str) -> Dict[str, Any]:
"""
Predict emotions for given text.
"""Predict emotions for given text.

Args:
text (str): Input text to analyze
Expand Down Expand Up @@ -258,7 +255,7 @@ def predict_emotions(text: str) -> Dict[str, Any]:
}

except Exception as e:
logger.exception(f"❌ Prediction failed: {str(e)}")
logger.exception(f"❌ Prediction failed: {e!s}")
return {
'error': 'Prediction failed',
'emotions': [],
Expand All @@ -267,8 +264,7 @@ def predict_emotions(text: str) -> Dict[str, Any]:


def get_model_status() -> Dict[str, Any]:
"""
Get current model status.
"""Get current model status.

Returns:
Dict[str, Any]: Model status information
Expand All @@ -287,8 +283,7 @@ def get_model_status() -> Dict[str, Any]:


def validate_text_input(text: str) -> Tuple[bool, str]:
"""
Validate text input for prediction.
"""Validate text input for prediction.

Args:
text (str): Text to validate
Expand All @@ -300,4 +295,4 @@ def validate_text_input(text: str) -> Tuple[bool, str]:
return False, 'Text must be a non-empty string'
if len(text) > MAX_TEXT_LENGTH:
return False, f'Text too long (max {MAX_TEXT_LENGTH} characters)'
return True, ''
return True, ''
9 changes: 4 additions & 5 deletions deployment/cloud-run/onnx_api_server.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#!/usr/bin/env python3
"""
Simplified ONNX-Based Emotion Detection API Server
"""Simplified ONNX-Based Emotion Detection API Server
Uses simple string tokenization - no complex dependencies
"""
import logging
import os
import time
import re
from typing import Dict, List, Optional, Tuple
from typing import Dict, List, Tuple
import threading

import numpy as np
Expand Down Expand Up @@ -75,7 +74,7 @@ def load_vocab() -> Dict[str, int]:
try:
if os.path.exists(VOCAB_PATH):
vocab_dict = {}
with open(VOCAB_PATH, 'r', encoding='utf-8') as f:
with open(VOCAB_PATH, encoding='utf-8') as f:
for i, line in enumerate(f):
word = line.strip()
if word:
Expand Down Expand Up @@ -362,4 +361,4 @@ def load(self):

except ImportError:
# Development server
app.run(host='127.0.0.1', port=8080, debug=False)
app.run(host='127.0.0.1', port=8080, debug=False)
5 changes: 2 additions & 3 deletions deployment/cloud-run/robust_predict.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
🚀 EMOTION DETECTION API FOR CLOUD RUN
"""🚀 EMOTION DETECTION API FOR CLOUD RUN
======================================
Robust Flask API optimized for Cloud Run deployment.
"""
Expand Down Expand Up @@ -301,4 +300,4 @@ def load(self):
'loglevel': 'info'
}

StandaloneApplication(app, options).run()
StandaloneApplication(app, options).run()
Loading
Loading