v5Dev / modules /database /semantic_mongo_live_db.py
AIdeaText's picture
Update modules/database/semantic_mongo_live_db.py
c9030f8 verified
raw
history blame
6.78 kB
# modules/database/semantic_mongo_live_db.py
import logging
from datetime import datetime, timezone
import base64
from bson import Binary
from pymongo.errors import PyMongoError
# Configuración del logger
logger = logging.getLogger(__name__)
COLLECTION_NAME = 'student_semantic_live_analysis'
def store_student_semantic_live_result(username, text, analysis_result, lang_code='en'):
"""
Guarda el resultado del análisis semántico en vivo en MongoDB.
Versión mejorada con manejo robusto de errores y verificación de datos.
"""
try:
# 1. Validación exhaustiva de los parámetros de entrada
if not username or not isinstance(username, str):
logger.error("Nombre de usuario inválido o vacío")
return False
if not text or not isinstance(text, str):
logger.error("Texto de análisis inválido o vacío")
return False
if not analysis_result or not isinstance(analysis_result, dict):
logger.error("Resultado de análisis inválido o vacío")
return False
# 2. Preparación del gráfico conceptual con múltiples formatos soportados
concept_graph_data = None
if 'concept_graph' in analysis_result and analysis_result['concept_graph'] is not None:
try:
graph_data = analysis_result['concept_graph']
if isinstance(graph_data, bytes):
# Codificar a base64 para almacenamiento eficiente
concept_graph_data = base64.b64encode(graph_data).decode('utf-8')
elif isinstance(graph_data, str):
# Si ya es string (base64), usarlo directamente
concept_graph_data = graph_data
elif isinstance(graph_data, Binary):
# Si es Binary de pymongo, convertirlo
concept_graph_data = base64.b64encode(graph_data).decode('utf-8')
else:
logger.warning(f"Formato de gráfico no soportado: {type(graph_data)}")
except Exception as e:
logger.error(f"Error al procesar gráfico conceptual: {str(e)}", exc_info=True)
# Continuar sin gráfico en lugar de fallar completamente
# 3. Preparación del documento con validación de campos
analysis_document = {
'username': username,
'timestamp': datetime.now(timezone.utc),
'text': text[:10000], # Limitar tamaño para prevenir documentos muy grandes
'analysis_type': 'semantic_live',
'language': lang_code,
'metadata': {
'version': '1.0',
'source': 'live_interface'
}
}
# Campos opcionales con validación
if 'key_concepts' in analysis_result and isinstance(analysis_result['key_concepts'], list):
analysis_document['key_concepts'] = analysis_result['key_concepts'][:50] # Limitar a 50 conceptos
if 'concept_centrality' in analysis_result and isinstance(analysis_result['concept_centrality'], dict):
analysis_document['concept_centrality'] = analysis_result['concept_centrality']
if concept_graph_data:
analysis_document['concept_graph'] = concept_graph_data
# 4. Operación de base de datos con manejo de errores específico
try:
collection = get_collection(COLLECTION_NAME)
if not collection:
logger.error("No se pudo obtener la colección MongoDB")
return False
result = collection.insert_one(analysis_document)
if result.inserted_id:
logger.info(f"Análisis guardado exitosamente para {username}. ID: {result.inserted_id}")
return True
logger.error("La operación de inserción no devolvió un ID")
return False
except PyMongoError as mongo_error:
logger.error(f"Error de MongoDB al guardar análisis: {str(mongo_error)}", exc_info=True)
return False
except Exception as e:
logger.error(f"Error inesperado al guardar análisis: {str(e)}", exc_info=True)
return False
def get_student_semantic_live_analysis(username, limit=10):
"""
Recupera los análisis semánticos en vivo de un estudiante.
Versión mejorada con paginación y manejo de errores.
"""
try:
# Validación de parámetros
if not username or not isinstance(username, str):
logger.error("Nombre de usuario inválido para recuperación")
return []
if not isinstance(limit, int) or limit <= 0:
limit = 10 # Valor por defecto si el límite es inválido
# Consulta con proyección para optimizar transferencia
query = {
"username": username,
"analysis_type": "semantic_live"
}
projection = {
"timestamp": 1,
"text": {"$substr": ["$text", 0, 200]}, # Solo primeros 200 caracteres
"key_concepts": {"$slice": ["$key_concepts", 10]}, # Solo primeros 10 conceptos
"concept_graph": 1,
"_id": 1,
"metadata": 1
}
# Operación de base de datos con manejo de errores
try:
collection = get_collection(COLLECTION_NAME)
if not collection:
logger.error("No se pudo obtener la colección MongoDB")
return []
cursor = collection.find(query, projection).sort("timestamp", -1).limit(limit)
results = list(cursor)
# Post-procesamiento para asegurar formato consistente
for doc in results:
if 'concept_graph' in doc and isinstance(doc['concept_graph'], str):
try:
# Convertir base64 string a bytes para compatibilidad
doc['concept_graph'] = base64.b64decode(doc['concept_graph'])
except Exception as e:
logger.warning(f"Error al decodificar gráfico: {str(e)}")
doc.pop('concept_graph', None)
logger.info(f"Recuperados {len(results)} análisis para {username}")
return results
except PyMongoError as mongo_error:
logger.error(f"Error de MongoDB al recuperar análisis: {str(mongo_error)}")
return []
except Exception as e:
logger.error(f"Error inesperado al recuperar análisis: {str(e)}", exc_info=True)
return []
__all__ = [
'store_student_semantic_live_result',
'get_student_semantic_live_analysis'
]