File size: 20,831 Bytes
188cada 90c6006 6415a87 5b5c9f7 e0f08c6 90c6006 8f2cd6a 93d367b 46ac0c4 47f7094 2c6717b 90c6006 758c30a a75392b 46ac0c4 72ea239 46ac0c4 72ea239 46ac0c4 88905b5 b9fc721 88905b5 72ea239 46ac0c4 04ba1ff 2089116 04ba1ff 5780733 06f7789 5780733 3e62e24 5780733 e16e5fe 06f7789 1b630f7 758c30a a7dd8fc ca32070 78ac4ef 6462a7a ca32070 6462a7a 46ac0c4 6462a7a ca32070 78ac4ef b9fc721 90c6006 839ecde b9fc721 46ac0c4 90c6006 46ac0c4 90c6006 46ac0c4 90c6006 46ac0c4 b9fc721 e16e5fe 78ac4ef e16e5fe b9fc721 e16e5fe 9323bdb 46ac0c4 9323bdb 46ac0c4 9323bdb e16e5fe 9323bdb e16e5fe 9323bdb e16e5fe b9fc721 e16e5fe 78ac4ef 8740c87 78ac4ef 8740c87 78ac4ef 8740c87 78ac4ef 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 261f399 8740c87 1b630f7 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 8740c87 46ac0c4 dfd108d 46ac0c4 dfd108d 46ac0c4 dfd108d 839ecde 78ac4ef fa815ca 46ac0c4 fa815ca 46ac0c4 e16e5fe b9fc721 e16e5fe 839ecde e16e5fe 261f399 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
#old.app.py
import logging
import datetime
import io
import base64
import os
import streamlit as st
import spacy
from spacy import displacy
import re
import numpy as np
import certifi
#from transformers import BlenderbotTokenizer, BlenderbotForConditionalGeneration
from azure.cosmos import CosmosClient
from azure.cosmos.exceptions import CosmosHttpResponseError
from pymongo import MongoClient
from pymongo.server_api import ServerApi
from bson.objectid import ObjectId
from datetime import datetime
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
from dotenv import load_dotenv
load_dotenv()
from modules.auth import clean_and_validate_key, register_user, authenticate_user, get_user_role
from modules.morpho_analysis import get_repeated_words_colors, highlight_repeated_words, POS_COLORS, POS_TRANSLATIONS
from modules.syntax_analysis import visualize_syntax
# Azure Cosmos DB configuration
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
cosmos_key = os.environ.get("COSMOS_KEY")
if not cosmos_endpoint or not cosmos_key:
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
try:
cosmos_key = clean_and_validate_key(cosmos_key)
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
# SQL API database for user management
user_database = cosmos_client.get_database_client("user_database")
user_container = user_database.get_container_client("users")
print("Conexión a Cosmos DB SQL API exitosa")
except Exception as e:
print(f"Error al conectar con Cosmos DB SQL API: {str(e)}")
raise
# MongoDB API configuration for text analysis results
#mongo_connection_string = os.environ.get("MONGODB_CONNECTION_STRING")
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")
else:
logger.info("La variable de entorno MONGODB_CONNECTION_STRING está configurada")
# Variable global para el cliente de MongoDB
mongo_client = None
db = None
analysis_collection = None
####################################################################################################################
def initialize_mongodb_connection():
global mongo_client, db, analysis_collection
try:
# Crear el cliente de MongoDB con configuración TLS
mongo_client = MongoClient(cosmos_mongodb_connection_string,
tls=True,
tlsCAFile=certifi.where(),
retryWrites=False,
serverSelectionTimeoutMS=5000,
connectTimeoutMS=10000,
socketTimeoutMS=10000)
# Forzar una conexión para verificar
mongo_client.admin.command('ping')
# Seleccionar la base de datos y la colección
db = mongo_client['aideatext_db']
analysis_collection = 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
##################################################################################################################3
def get_student_data(username):
if analysis_collection is None:
logger.error("La conexión a MongoDB no está inicializada")
return None
try:
# Buscar los datos del estudiante
student_data = analysis_collection.find({"username": username}).sort("timestamp", -1)
if not student_data:
return None
# Formatear los datos
formatted_data = {
"username": username,
"entries": [],
"entries_count": 0,
"word_count": {},
"arc_diagrams": [],
"network_diagrams": []
}
for entry in student_data:
formatted_data["entries"].append({
"timestamp": entry["timestamp"].isoformat(),
"text": entry["text"]
})
formatted_data["entries_count"] += 1
# Agregar conteo de palabras
for category, count in entry.get("word_count", {}).items():
if category in formatted_data["word_count"]:
formatted_data["word_count"][category] += count
else:
formatted_data["word_count"][category] = count
# Agregar diagramas
formatted_data["arc_diagrams"].extend(entry.get("arc_diagrams", []))
formatted_data["network_diagrams"].append(entry.get("network_diagram", ""))
return formatted_data
except Exception as e:
logger.error(f"Error al obtener datos del estudiante {username}: {str(e)}")
return None
##################################################################################################################
# Función para insertar un documento
def insert_document(document):
try:
result = analysis_collection.insert_one(document)
logger.info(f"Documento insertado con ID: {result.inserted_id}")
return result.inserted_id
except Exception as e:
logger.error(f"Error al insertar documento: {str(e)}", exc_info=True)
return None
# Configure the page to use the full width
st.set_page_config(
page_title="AIdeaText",
layout="wide",
page_icon="random"
)
#####################################################################################################
@st.cache_resource
def load_chatbot_model():
try:
from transformers import BlenderbotTokenizer, BlenderbotForConditionalGeneration
tokenizer = BlenderbotTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
model = BlenderbotForConditionalGeneration.from_pretrained("facebook/blenderbot-400M-distill")
return tokenizer, model
except Exception as e:
logger.error(f"Error al cargar el modelo del chatbot: {str(e)}")
return None, None
# Load the chatbot model
chatbot_tokenizer, chatbot_model = load_chatbot_model()
def get_chatbot_response(input_text):
if chatbot_tokenizer is None or chatbot_model is None:
return "Lo siento, el chatbot no está disponible en este momento."
try:
inputs = chatbot_tokenizer(input_text, return_tensors="pt")
reply_ids = chatbot_model.generate(**inputs)
return chatbot_tokenizer.batch_decode(reply_ids, skip_special_tokens=True)[0]
except Exception as e:
logger.error(f"Error al generar respuesta del chatbot: {str(e)}")
return "Lo siento, hubo un error al procesar tu mensaje."
########################################################################################################
def load_spacy_models():
return {
'es': spacy.load("es_core_news_lg"),
'en': spacy.load("en_core_web_lg"),
'fr': spacy.load("fr_core_news_lg")
}
#########################################################################################################
def store_analysis_result(username, text, repeated_words, arc_diagrams, network_diagram):
if analysis_collection is None:
logging.error("La conexión a MongoDB no está inicializada")
return False
try:
# Convertir el gráfico de matplotlib a base64
buffer = io.BytesIO()
network_diagram.savefig(buffer, format='png')
buffer.seek(0)
network_diagram_base64 = base64.b64encode(buffer.getvalue()).decode()
# Contar palabras repetidas por categoría gramatical
word_count = {}
for word, color in repeated_words.items():
category = POS_TRANSLATIONS.get(color, 'Otros')
word_count[category] = word_count.get(category, 0) + 1
# Crear el documento para MongoDB
analysis_document = {
'username': username, # Este campo se usará como sharded key
'timestamp': datetime.datetime.utcnow(),
'text': text,
'word_count': word_count,
'arc_diagrams': arc_diagrams,
'network_diagram': network_diagram_base64
}
# Insertar el documento en la colección
result = analysis_collection.insert_one(analysis_document)
logging.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}")
return True
except Exception as e:
logging.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}")
return False
#############################################################################################33
def login_page():
st.title("Iniciar Sesión")
username = st.text_input("Usuario")
password = st.text_input("Contraseña", type='password')
if st.button("Iniciar Sesión"):
if authenticate_user(username, password):
st.success(f"Bienvenido, {username}!")
st.session_state.logged_in = True
st.session_state.username = username
st.session_state.role = get_user_role(username)
st.experimental_rerun()
else:
st.error("Usuario o contraseña incorrectos")
#####################################################################################################3
def register_page():
st.title("Registrarse")
new_username = st.text_input("Nuevo Usuario")
new_password = st.text_input("Nueva Contraseña", type='password')
role = st.selectbox("Rol", ["Estudiante", "Profesor"])
additional_info = {}
if role == "Estudiante":
additional_info['carrera'] = st.text_input("Carrera")
elif role == "Profesor":
additional_info['departamento'] = st.text_input("Departamento")
if st.button("Registrarse"):
if register_user(new_username, new_password, role, additional_info):
st.success("Registro exitoso. Por favor, inicia sesión.")
else:
st.error("El usuario ya existe o ocurrió un error durante el registro")
############################################################################################
def main_app():
# Load spaCy models
nlp_models = load_spacy_models()
# Language selection
languages = {
'Español': 'es',
'English': 'en',
'Français': 'fr'
}
selected_lang = st.sidebar.selectbox("Select Language / Seleccione el idioma / Choisissez la langue", list(languages.keys()))
lang_code = languages[selected_lang]
# Translations
translations = {
'es': {
'title': "AIdeaText - Análisis morfológico y sintáctico",
'input_label': "Ingrese un texto para analizar (máx. 5,000 palabras):",
'input_placeholder': "El objetivo de esta aplicación es que mejore sus habilidades de redacción. Para ello, después de ingresar su texto y presionar el botón obtendrá tres vistas horizontales. La primera, le indicará las palabras que se repiten por categoría gramátical; la segunda, un diagrama de arco le indicara las conexiones sintácticas en cada oración; y la tercera, es un grafo en el cual visualizara la configuración de su texto.",
'analyze_button': "Analizar texto",
'repeated_words': "Palabras repetidas",
'legend': "Leyenda: Categorías gramaticales",
'arc_diagram': "Análisis sintáctico: Diagrama de arco",
'network_diagram': "Análisis sintáctico: Diagrama de red",
'sentence': "Oración"
},
'en': {
'title': "AIdeaText - Morphological and Syntactic Analysis",
'input_label': "Enter a text to analyze (max 5,000 words):",
'input_placeholder': "The goal of this app is for you to improve your writing skills. To do this, after entering your text and pressing the button you will get three horizontal views. The first will indicate the words that are repeated by grammatical category; second, an arc diagram will indicate the syntactic connections in each sentence; and the third is a graph in which you will visualize the configuration of your text.",
'analyze_button': "Analyze text",
'repeated_words': "Repeated words",
'legend': "Legend: Grammatical categories",
'arc_diagram': "Syntactic analysis: Arc diagram",
'network_diagram': "Syntactic analysis: Network diagram",
'sentence': "Sentence"
},
'fr': {
'title': "AIdeaText - Analyse morphologique et syntaxique",
'input_label': "Entrez un texte à analyser (max 5 000 mots) :",
'input_placeholder': "Le but de cette application est d'améliorer vos compétences en rédaction. Pour ce faire, après avoir saisi votre texte et appuyé sur le bouton vous obtiendrez trois vues horizontales. Le premier indiquera les mots répétés par catégorie grammaticale; deuxièmement, un diagramme en arcs indiquera les connexions syntaxiques dans chaque phrase; et le troisième est un graphique dans lequel vous visualiserez la configuration de votre texte.",
'analyze_button': "Analyser le texte",
'repeated_words': "Mots répétés",
'legend': "Légende : Catégories grammaticales",
'arc_diagram': "Analyse syntaxique : Diagramme en arc",
'network_diagram': "Analyse syntaxique : Diagramme de réseau",
'sentence': "Phrase"
}
}
# Use translations
t = translations[lang_code]
# Create two columns: one for chat and one for analysis
col1, col2 = st.columns([1, 2])
with col1:
st.markdown(f"### Chat con AIdeaText")
# Initialize chat history if it doesn't exist
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
# Display chat history
for i, (role, text) in enumerate(st.session_state.chat_history):
if role == "user":
st.text_area(f"Tú:", value=text, height=50, key=f"user_message_{i}", disabled=True)
else:
st.text_area(f"AIdeaText:", value=text, height=50, key=f"bot_message_{i}", disabled=True)
# User input field
user_input = st.text_input("Escribe tu mensaje aquí:")
if st.button("Enviar"):
if user_input:
# Add user message to history
st.session_state.chat_history.append(("user", user_input))
# Get chatbot response
response = get_chatbot_response(user_input)
# Add chatbot response to history
st.session_state.chat_history.append(("bot", response))
# Clear input field
st.experimental_rerun()
with col2:
st.markdown(f"### {t['title']}")
if st.session_state.role == "Estudiante":
# Agregar un botón para ver el progreso del estudiante
if st.button("Ver mi progreso"):
student_data = get_student_data(st.session_state.username)
if student_data:
st.success("Datos obtenidos exitosamente")
# Mostrar estadísticas generales
st.subheader("Estadísticas generales")
st.write(f"Total de entradas: {student_data['entries_count']}")
# Mostrar gráfico de conteo de palabras
st.subheader("Conteo de palabras por categoría")
st.bar_chart(student_data['word_count'])
# Mostrar entradas recientes
st.subheader("Entradas recientes")
for entry in student_data['entries'][:5]: # Mostrar las 5 entradas más recientes
st.text_area(f"Entrada del {entry['timestamp']}", entry['text'], height=100)
# Aquí puedes agregar más visualizaciones según necesites
else:
st.warning("No se encontraron datos para este estudiante")
if st.session_state.role == "Estudiante":
# Student interface code
if 'input_text' not in st.session_state:
st.session_state.input_text = ""
sentence_input = st.text_area(t['input_label'], height=150, placeholder=t['input_placeholder'], value=st.session_state.input_text)
st.session_state.input_text = sentence_input
if st.button(t['analyze_button']):
if sentence_input:
doc = nlp_models[lang_code](sentence_input)
# Highlighted Repeated Words
with st.expander(t['repeated_words'], expanded=True):
word_colors = get_repeated_words_colors(doc)
highlighted_text = highlight_repeated_words(doc, word_colors)
st.markdown(highlighted_text, unsafe_allow_html=True)
# Legend for grammatical categories
st.markdown(f"##### {t['legend']}")
legend_html = "<div style='display: flex; flex-wrap: wrap;'>"
for pos, color in POS_COLORS.items():
if pos in POS_TRANSLATIONS:
legend_html += f"<div style='margin-right: 10px;'><span style='background-color: {color}; padding: 2px 5px;'>{POS_TRANSLATIONS[pos]}</span></div>"
legend_html += "</div>"
st.markdown(legend_html, unsafe_allow_html=True)
# Arc Diagram
with st.expander(t['arc_diagram'], expanded=True):
sentences = list(doc.sents)
arc_diagrams = []
for i, sent in enumerate(sentences):
st.subheader(f"{t['sentence']} {i+1}")
html = displacy.render(sent, style="dep", options={"distance": 100})
html = html.replace('height="375"', 'height="200"')
html = re.sub(r'<svg[^>]*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html)
html = re.sub(r'<g [^>]*transform="translate\((\d+),(\d+)\)"', lambda m: f'<g transform="translate({m.group(1)},50)"', html)
st.write(html, unsafe_allow_html=True)
arc_diagrams.append(html)
# Network graph
with st.expander(t['network_diagram'], expanded=True):
fig = visualize_syntax(sentence_input, nlp_models[lang_code], lang_code)
st.pyplot(fig)
# Store analysis results
if store_analysis_result(
st.session_state.username,
sentence_input,
word_colors,
arc_diagrams,
fig
):
st.success("Análisis guardado correctamente.")
else:
st.error("Hubo un problema al guardar el análisis. Por favor, inténtelo de nuevo.")
logger.error(f"Falló el guardado del análisis. Username: {st.session_state.username}")
elif st.session_state.role == "Profesor":
# Teacher interface code
st.write("Bienvenido, profesor. Aquí podrás ver el progreso de tus estudiantes.")
# Add logic to display student progress
#####################################################################################################
def main():
if not initialize_mongodb_connection():
st.warning("La conexión a la base de datos MongoDB no está disponible. Algunas funciones pueden no estar operativas.")
if 'logged_in' not in st.session_state:
st.session_state.logged_in = False
if not st.session_state.logged_in:
menu = ["Iniciar Sesión", "Registrarse"]
choice = st.sidebar.selectbox("Menu", menu)
if choice == "Iniciar Sesión":
login_page()
elif choice == "Registrarse":
register_page()
else:
if st.sidebar.button("Cerrar Sesión"):
st.session_state.logged_in = False
st.experimental_rerun()
main_app()
if __name__ == "__main__":
main() |