|
|
from typing import List, Dict, Any |
|
|
from mcp import Resource |
|
|
from datetime import datetime |
|
|
import logging |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
class ModelResource(Resource): |
|
|
"""Resource representing a loaded model""" |
|
|
def __init__(self, model_name: str, model_info: Dict[str, Any]): |
|
|
self.model_name = model_name |
|
|
self.model_info = model_info |
|
|
super().__init__( |
|
|
uri=f"model://{model_name}", |
|
|
name=model_name, |
|
|
description=f"{model_name} model information and status", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get model information as JSON""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.model_info, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri |
|
|
}) |
|
|
|
|
|
class StanceDetectionResource(ModelResource): |
|
|
"""Resource for stance detection model""" |
|
|
def __init__(self): |
|
|
from services.stance_model_manager import stance_model_manager |
|
|
|
|
|
model_info = { |
|
|
"type": "stance_detection", |
|
|
"description": "Detects PRO/CON stance for topic-argument pairs", |
|
|
"capabilities": ["single_prediction", "batch_prediction"], |
|
|
"input_format": {"topic": "string", "argument": "string"}, |
|
|
"output_format": { |
|
|
"predicted_stance": "PRO/CON", |
|
|
"confidence": "float", |
|
|
"probabilities": {"PRO": "float", "CON": "float"} |
|
|
} |
|
|
} |
|
|
|
|
|
if stance_model_manager and stance_model_manager.model_loaded: |
|
|
model_info.update({ |
|
|
"loaded": True, |
|
|
"device": str(stance_model_manager.device), |
|
|
"model_id": getattr(stance_model_manager, 'model_id', 'unknown') |
|
|
}) |
|
|
else: |
|
|
model_info["loaded"] = False |
|
|
|
|
|
super().__init__("stance_detection", model_info) |
|
|
|
|
|
class KPAResource(ModelResource): |
|
|
"""Resource for Keypoint-Argument matching model""" |
|
|
def __init__(self): |
|
|
from services.label_model_manager import kpa_model_manager |
|
|
|
|
|
model_info = { |
|
|
"type": "keypoint_argument_matching", |
|
|
"description": "Matches arguments with key points (apparie/non_apparie)", |
|
|
"capabilities": ["single_prediction", "batch_prediction"], |
|
|
"input_format": {"argument": "string", "key_point": "string"}, |
|
|
"output_format": { |
|
|
"prediction": "0/1", |
|
|
"label": "apparie/non_apparie", |
|
|
"confidence": "float", |
|
|
"probabilities": {"non_apparie": "float", "apparie": "float"} |
|
|
} |
|
|
} |
|
|
|
|
|
if kpa_model_manager and kpa_model_manager.model_loaded: |
|
|
model_info.update({ |
|
|
"loaded": True, |
|
|
"device": str(kpa_model_manager.device), |
|
|
"model_id": getattr(kpa_model_manager, 'model_id', 'unknown'), |
|
|
"max_length": getattr(kpa_model_manager, 'max_length', 256) |
|
|
}) |
|
|
else: |
|
|
model_info["loaded"] = False |
|
|
|
|
|
super().__init__("kpa_matching", model_info) |
|
|
|
|
|
class STTResource(Resource): |
|
|
"""Resource for Speech-to-Text capabilities""" |
|
|
def __init__(self): |
|
|
from config import GROQ_API_KEY, GROQ_STT_MODEL |
|
|
|
|
|
super().__init__( |
|
|
uri="service://speech-to-text", |
|
|
name="speech_to_text", |
|
|
description="Speech-to-Text service using Groq Whisper API", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
self.config = { |
|
|
"provider": "Groq", |
|
|
"model": GROQ_STT_MODEL, |
|
|
"enabled": bool(GROQ_API_KEY), |
|
|
"language": "English only", |
|
|
"max_audio_size": "10MB", |
|
|
"supported_formats": ["wav", "mp3", "m4a", "mp4"] |
|
|
} |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get STT service information""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.config, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri |
|
|
}) |
|
|
|
|
|
class TTSResource(Resource): |
|
|
"""Resource for Text-to-Speech capabilities""" |
|
|
def __init__(self): |
|
|
from config import GROQ_API_KEY, GROQ_TTS_MODEL, GROQ_TTS_VOICE |
|
|
|
|
|
super().__init__( |
|
|
uri="service://text-to-speech", |
|
|
name="text_to_speech", |
|
|
description="Text-to-Speech service using Groq PlayAI TTS", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
self.config = { |
|
|
"provider": "Groq", |
|
|
"model": GROQ_TTS_MODEL, |
|
|
"voice": GROQ_TTS_VOICE, |
|
|
"enabled": bool(GROQ_API_KEY), |
|
|
"language": "English only", |
|
|
"format": "wav/mp3", |
|
|
"voices_available": ["Aaliyah-PlayAI", "Aria-PlayAI", "Dexter-PlayAI", "Fiona-PlayAI"] |
|
|
} |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get TTS service information""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.config, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri |
|
|
}) |
|
|
|
|
|
class ChatbotResource(Resource): |
|
|
"""Resource for Chatbot capabilities""" |
|
|
def __init__(self): |
|
|
from config import GROQ_API_KEY, GROQ_CHAT_MODEL |
|
|
|
|
|
super().__init__( |
|
|
uri="service://chatbot", |
|
|
name="chatbot", |
|
|
description="Chatbot service using Groq LLM API", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
self.config = { |
|
|
"provider": "Groq", |
|
|
"model": GROQ_CHAT_MODEL, |
|
|
"enabled": bool(GROQ_API_KEY), |
|
|
"language": "English only", |
|
|
"features": ["conversation", "context_awareness", "voice_chat"], |
|
|
"max_context_length": 8192 |
|
|
} |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get chatbot service information""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.config, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri |
|
|
}) |
|
|
|
|
|
class ArgumentGenerationResource(Resource): |
|
|
"""Resource for Argument Generation model (à compléter)""" |
|
|
def __init__(self): |
|
|
super().__init__( |
|
|
uri="model://argument-generation", |
|
|
name="argument_generation", |
|
|
description="Persuasive argument generation model", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
self.config = { |
|
|
"type": "argument_generation", |
|
|
"status": "not_implemented", |
|
|
"description": "TODO: Implement your argument generation model", |
|
|
"planned_capabilities": [ |
|
|
"single_argument_generation", |
|
|
"batch_generation", |
|
|
"stance_controlled_generation", |
|
|
"counter_argument_generation" |
|
|
] |
|
|
} |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get argument generation model information""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.config, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri, |
|
|
"note": "This is a placeholder. Implement your model in services/argument_generation.py" |
|
|
}) |
|
|
|
|
|
class SystemHealthResource(Resource): |
|
|
"""Resource for system health and status""" |
|
|
def __init__(self): |
|
|
super().__init__( |
|
|
uri="system://health", |
|
|
name="system_health", |
|
|
description="System health and service status", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get system health information""" |
|
|
import json |
|
|
from datetime import datetime |
|
|
|
|
|
|
|
|
model_status = {} |
|
|
try: |
|
|
from services.stance_model_manager import stance_model_manager |
|
|
model_status["stance_detection"] = { |
|
|
"loaded": stance_model_manager.model_loaded if stance_model_manager else False |
|
|
} |
|
|
except: |
|
|
model_status["stance_detection"] = {"loaded": False} |
|
|
|
|
|
try: |
|
|
from services.label_model_manager import kpa_model_manager |
|
|
model_status["kpa_matching"] = { |
|
|
"loaded": kpa_model_manager.model_loaded if kpa_model_manager else False |
|
|
} |
|
|
except: |
|
|
model_status["kpa_matching"] = {"loaded": False} |
|
|
|
|
|
|
|
|
from config import GROQ_API_KEY |
|
|
service_status = { |
|
|
"stt": bool(GROQ_API_KEY), |
|
|
"tts": bool(GROQ_API_KEY), |
|
|
"chatbot": bool(GROQ_API_KEY), |
|
|
"argument_generation": False |
|
|
} |
|
|
|
|
|
return json.dumps({ |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"status": "operational", |
|
|
"models": model_status, |
|
|
"services": service_status, |
|
|
"api_version": "1.0.0", |
|
|
"mcp_version": "1.0.0" |
|
|
}) |
|
|
|
|
|
class APIDocumentationResource(Resource): |
|
|
"""Resource for API documentation""" |
|
|
def __init__(self): |
|
|
super().__init__( |
|
|
uri="documentation://api", |
|
|
name="api_documentation", |
|
|
description="API endpoints documentation", |
|
|
mime_type="application/json" |
|
|
) |
|
|
|
|
|
self.documentation = { |
|
|
"endpoints": { |
|
|
"mcp": { |
|
|
"/mcp/health": "GET - Health check", |
|
|
"/mcp/resources": "GET - List all resources", |
|
|
"/mcp/tools": "GET - List all tools", |
|
|
"/mcp/tools/call": "POST - Call a tool" |
|
|
}, |
|
|
"models": { |
|
|
"/api/v1/kpa/predict": "POST - KPA prediction", |
|
|
"/api/v1/stance/predict": "POST - Stance prediction", |
|
|
"/api/v1/stance/batch-predict": "POST - Batch stance prediction" |
|
|
}, |
|
|
"voice": { |
|
|
"/api/v1/stt/": "POST - Speech to text", |
|
|
"/api/v1/tts/": "POST - Text to speech", |
|
|
"/voice-chat/voice": "POST - Voice chat", |
|
|
"/voice-chat/text": "POST - Text chat" |
|
|
} |
|
|
}, |
|
|
"authentication": "Currently none (add JWT or API key based auth)", |
|
|
"rate_limits": "None configured", |
|
|
"version": "2.0.0" |
|
|
} |
|
|
|
|
|
async def get_content(self) -> str: |
|
|
"""Get API documentation""" |
|
|
import json |
|
|
return json.dumps({ |
|
|
**self.documentation, |
|
|
"timestamp": datetime.now().isoformat(), |
|
|
"uri": self.uri |
|
|
}) |
|
|
|
|
|
def get_resources() -> List[Resource]: |
|
|
"""Return all available MCP resources""" |
|
|
resources = [] |
|
|
|
|
|
try: |
|
|
resources.append(StanceDetectionResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create StanceDetectionResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(KPAResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create KPAResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(STTResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create STTResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(TTSResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create TTSResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(ChatbotResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create ChatbotResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(ArgumentGenerationResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create ArgumentGenerationResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(SystemHealthResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create SystemHealthResource: {e}") |
|
|
|
|
|
try: |
|
|
resources.append(APIDocumentationResource()) |
|
|
except Exception as e: |
|
|
logger.warning(f"Failed to create APIDocumentationResource: {e}") |
|
|
|
|
|
logger.info(f"Created {len(resources)} MCP resources") |
|
|
return resources |