|
|
|
import logging |
|
import os |
|
from azure.cosmos import CosmosClient |
|
from azure.cosmos.exceptions import CosmosHttpResponseError |
|
from pymongo import MongoClient |
|
import certifi |
|
from datetime import datetime |
|
import io |
|
import base64 |
|
import matplotlib.pyplot as plt |
|
from matplotlib.figure import Figure |
|
import bcrypt |
|
print(f"Bcrypt version: {bcrypt.__version__}") |
|
|
|
logging.basicConfig(level=logging.DEBUG) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
cosmos_client = None |
|
user_database = None |
|
user_container = None |
|
|
|
|
|
mongo_client = None |
|
mongo_db = None |
|
analysis_collection = None |
|
|
|
|
|
def initialize_cosmos_sql_connection(): |
|
global cosmos_client, user_database, user_container |
|
try: |
|
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT") |
|
cosmos_key = os.environ.get("COSMOS_KEY") |
|
|
|
print(f"Cosmos Endpoint: {cosmos_endpoint}") |
|
print(f"Cosmos Key: {'*' * len(cosmos_key) if cosmos_key else 'Not set'}") |
|
|
|
if not cosmos_endpoint or not cosmos_key: |
|
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas") |
|
|
|
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key) |
|
user_database = cosmos_client.get_database_client("user_database") |
|
user_container = user_database.get_container_client("users") |
|
|
|
print(f"user_container initialized: {user_container is not None}") |
|
logger.info("Conexión a Cosmos DB SQL API exitosa") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}") |
|
return False |
|
|
|
|
|
def initialize_mongodb_connection(): |
|
global mongo_client, mongo_db, analysis_collection |
|
try: |
|
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING") |
|
if not cosmos_mongodb_connection_string: |
|
logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada") |
|
return False |
|
|
|
mongo_client = MongoClient(cosmos_mongodb_connection_string, |
|
tls=True, |
|
tlsCAFile=certifi.where(), |
|
retryWrites=False, |
|
serverSelectionTimeoutMS=5000, |
|
connectTimeoutMS=10000, |
|
socketTimeoutMS=10000) |
|
|
|
mongo_client.admin.command('ping') |
|
|
|
mongo_db = mongo_client['aideatext_db'] |
|
analysis_collection = mongo_db['text_analysis'] |
|
|
|
logger.info("Conexión a Cosmos DB MongoDB API exitosa") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True) |
|
return False |
|
|
|
|
|
def create_user(username, password, role): |
|
global user_container |
|
try: |
|
print(f"Attempting to create user: {username} with role: {role}") |
|
if user_container is None: |
|
print("Error: user_container is None. Attempting to reinitialize connection.") |
|
if not initialize_cosmos_sql_connection(): |
|
raise Exception("Failed to initialize SQL connection") |
|
|
|
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') |
|
print(f"Password hashed successfully for user: {username}") |
|
user_data = { |
|
'id': username, |
|
'password': hashed_password, |
|
'role': role, |
|
'created_at': datetime.utcnow().isoformat() |
|
} |
|
user_container.create_item(body=user_data) |
|
print(f"Usuario {role} creado: {username}") |
|
return True |
|
except Exception as e: |
|
print(f"Detailed error in create_user: {str(e)}") |
|
return False |
|
|
|
|
|
def create_admin_user(username, password): |
|
return create_user(username, password, 'Administrador') |
|
|
|
|
|
def create_student_user(username, password): |
|
return create_user(username, password, 'Estudiante') |
|
|
|
|
|
|
|
def get_user(username): |
|
try: |
|
query = f"SELECT * FROM c WHERE c.id = '{username}'" |
|
items = list(user_container.query_items(query=query, enable_cross_partition_query=True)) |
|
user = items[0] if items else None |
|
if user: |
|
print(f"Usuario encontrado: {username}, Rol: {user.get('role')}") |
|
else: |
|
print(f"Usuario no encontrado: {username}") |
|
return user |
|
except Exception as e: |
|
print(f"Error al obtener usuario {username}: {str(e)}") |
|
return None |
|
|
|
|
|
|
|
def display_student_progress(username, lang_code='es'): |
|
student_data = get_student_data(username) |
|
|
|
if student_data is None: |
|
st.warning("No se encontraron datos para este estudiante.") |
|
st.info("Intenta realizar algunos análisis de texto primero.") |
|
return |
|
|
|
st.title(f"Progreso de {username}") |
|
|
|
if student_data['entries_count'] > 0: |
|
|
|
if student_data['word_count']: |
|
with st.expander("Total de palabras por categoría gramatical", expanded=False): |
|
df = pd.DataFrame(list(student_data['word_count'].items()), columns=['category', 'count']) |
|
df['label'] = df.apply(lambda x: f"{POS_TRANSLATIONS[lang_code].get(x['category'], x['category'])}", axis=1) |
|
df = df.sort_values('count', ascending=False) |
|
|
|
fig, ax = plt.subplots(figsize=(12, 6)) |
|
bars = ax.bar(df['label'], df['count'], color=df['category']) |
|
|
|
ax.set_xlabel('Categoría Gramatical') |
|
ax.set_ylabel('Cantidad de Palabras') |
|
ax.set_title('Total de palabras por categoría gramatical') |
|
plt.xticks(rotation=45, ha='right') |
|
|
|
for bar in bars: |
|
height = bar.get_height() |
|
ax.text(bar.get_x() + bar.get_width()/2., height, f'{height}', ha='center', va='bottom') |
|
|
|
plt.tight_layout() |
|
st.pyplot(fig) |
|
|
|
|
|
morphosyntax_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'morphosyntax'] |
|
if morphosyntax_entries: |
|
with st.expander("Análisis Morfosintáctico - Diagramas de Arco", expanded=False): |
|
for i, entry in enumerate(morphosyntax_entries): |
|
st.subheader(f"Análisis {i+1} - {entry['timestamp']}") |
|
st.write(entry['text']) |
|
for j, diagram in enumerate(entry.get('arc_diagrams', [])): |
|
st.subheader(f"Diagrama de Arco {j+1}") |
|
st.write(diagram, unsafe_allow_html=True) |
|
|
|
|
|
if student_data['semantic_analyses']: |
|
with st.expander("Análisis Semántico - Diagramas de Red", expanded=False): |
|
for i, entry in enumerate(student_data['semantic_analyses']): |
|
st.subheader(f"Análisis Semántico {i+1} - {entry['timestamp']}") |
|
st.write(entry['text']) |
|
if 'network_diagram' in entry: |
|
image_bytes = base64.b64decode(entry['network_diagram']) |
|
st.image(image_bytes) |
|
|
|
|
|
if student_data['discourse_analyses']: |
|
with st.expander("Análisis del Discurso - Comparación de Grafos", expanded=False): |
|
for i, entry in enumerate(student_data['discourse_analyses']): |
|
st.subheader(f"Análisis del Discurso {i+1} - {entry['timestamp']}") |
|
st.write("Texto del documento patrón:") |
|
st.write(entry.get('text1', 'No disponible')) |
|
st.write("Texto del documento comparado:") |
|
st.write(entry.get('text2', 'No disponible')) |
|
if 'graph1' in entry: |
|
st.image(base64.b64decode(entry['graph1'])) |
|
if 'graph2' in entry: |
|
st.image(base64.b64decode(entry['graph2'])) |
|
|
|
|
|
if student_data['chat_history']: |
|
with st.expander("Historial de Conversaciones del Chat", expanded=False): |
|
for i, chat in enumerate(student_data['chat_history']): |
|
st.subheader(f"Conversación {i+1} - {chat['timestamp']}") |
|
for message in chat['messages']: |
|
if message['role'] == 'user': |
|
st.write("Usuario: " + message['content']) |
|
else: |
|
st.write("Asistente: " + message['content']) |
|
st.write("---") |
|
else: |
|
st.warning("No se encontraron entradas para este estudiante.") |
|
st.info("Intenta realizar algunos análisis de texto primero.") |
|
|
|
|
|
st.write("Datos del estudiante (para depuración):") |
|
st.json(student_data) |
|
|
|
|
|
|
|
def store_morphosyntax_result(username, text, repeated_words, arc_diagrams): |
|
if analysis_collection is None: |
|
logger.error("La conexión a MongoDB no está inicializada") |
|
return False |
|
|
|
try: |
|
word_count = {} |
|
for word, color in repeated_words.items(): |
|
category = color |
|
word_count[category] = word_count.get(category, 0) + 1 |
|
|
|
analysis_document = { |
|
'username': username, |
|
'timestamp': datetime.utcnow(), |
|
'text': text, |
|
'word_count': word_count, |
|
'arc_diagrams': arc_diagrams, |
|
} |
|
|
|
result = analysis_collection.insert_one(analysis_document) |
|
|
|
logger.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}") |
|
return False |
|
|
|
|
|
def store_semantic_result(username, text, network_diagram): |
|
try: |
|
|
|
buf = io.BytesIO() |
|
network_diagram.savefig(buf, format='png') |
|
buf.seek(0) |
|
img_str = base64.b64encode(buf.getvalue()).decode('utf-8') |
|
|
|
analysis_document = { |
|
'username': username, |
|
'timestamp': datetime.utcnow(), |
|
'text': text, |
|
'network_diagram': img_str, |
|
'analysis_type': 'semantic' |
|
} |
|
|
|
result = analysis_collection.insert_one(analysis_document) |
|
|
|
logger.info(f"Análisis semántico guardado con ID: {result.inserted_id} para el usuario: {username}") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error al guardar el análisis semántico para el usuario {username}: {str(e)}") |
|
return False |
|
|
|
|
|
|
|
def store_discourse_analysis_result(username, text1, text2, graph1, graph2): |
|
try: |
|
|
|
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10)) |
|
|
|
|
|
ax1.imshow(graph1.get_figure().canvas.renderer.buffer_rgba()) |
|
ax1.set_title("Documento Patrón: Relaciones semánticas relevantes") |
|
ax1.axis('off') |
|
|
|
|
|
ax2.imshow(graph2.get_figure().canvas.renderer.buffer_rgba()) |
|
ax2.set_title("Documento Comparado con el documento patrón: Relaciones semánticas relevantes") |
|
ax2.axis('off') |
|
|
|
|
|
plt.tight_layout() |
|
|
|
|
|
buf = io.BytesIO() |
|
fig.savefig(buf, format='png') |
|
buf.seek(0) |
|
img_str = base64.b64encode(buf.getvalue()).decode('utf-8') |
|
|
|
|
|
plt.close(fig) |
|
plt.close(graph1.get_figure()) |
|
plt.close(graph2.get_figure()) |
|
|
|
analysis_document = { |
|
'username': username, |
|
'timestamp': datetime.utcnow(), |
|
'text1': text1, |
|
'text2': text2, |
|
'combined_graph': img_str, |
|
'analysis_type': 'discourse' |
|
} |
|
|
|
result = analysis_collection.insert_one(analysis_document) |
|
|
|
logger.info(f"Análisis discursivo guardado con ID: {result.inserted_id} para el usuario: {username}") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error al guardar el análisis discursivo para el usuario {username}: {str(e)}") |
|
return False |
|
|
|
|
|
def store_chat_history(username, messages): |
|
try: |
|
chat_document = { |
|
'username': username, |
|
'timestamp': datetime.utcnow(), |
|
'messages': messages |
|
} |
|
result = chat_collection.insert_one(chat_document) |
|
logger.info(f"Chat history saved with ID: {result.inserted_id} for user: {username}") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Error saving chat history for user {username}: {str(e)}") |
|
return False |