Upload 216 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- app.py +150 -0
- assets/img/AIdeaTextCard.jpg +0 -0
- assets/img/Mesa de trabajo 1png 0.3.png +0 -0
- assets/img/logo_92x92.jpg +0 -0
- assets/img/logo_92x92.png +0 -0
- assets/img/text.txt +0 -0
- modules/23-7-2024_auth.py +135 -0
- modules/23-7-2024_ui.py +344 -0
- modules/__init__.py +112 -0
- modules/__init__Old-V3.py +180 -0
- modules/__pycache__/__init__.cpython-311.pyc +0 -0
- modules/admin/__init__.py +0 -0
- modules/admin/__pycache__/__init__.cpython-311.pyc +0 -0
- modules/admin/__pycache__/admin_ui.cpython-311.pyc +0 -0
- modules/admin/admin_ui.py +49 -0
- modules/admin/txt.txt +0 -0
- modules/auth/__init__.py +0 -0
- modules/auth/__pycache__/__init__.cpython-311.pyc +0 -0
- modules/auth/__pycache__/auth.cpython-311.pyc +0 -0
- modules/auth/auth.py +119 -0
- modules/auth/txt.txt +0 -0
- modules/chatbot/__init__.py +0 -0
- modules/chatbot/__pycache__/__init__.cpython-311.pyc +0 -0
- modules/chatbot/__pycache__/chatbot.cpython-311.pyc +0 -0
- modules/chatbot/chatbot.py +46 -0
- modules/chatbot/chatbot_open_Source_Model-test.py +124 -0
- modules/chatbot/txt.txt +0 -0
- modules/database/__init__.py +0 -0
- modules/database/__pycache__/__init__.cpython-311.pyc +0 -0
- modules/database/__pycache__/chat_db.cpython-311.pyc +0 -0
- modules/database/__pycache__/database.cpython-311.pyc +0 -0
- modules/database/__pycache__/database_init.cpython-311.pyc +0 -0
- modules/database/__pycache__/database_oldFromV2.cpython-311.pyc +0 -0
- modules/database/__pycache__/mongo_db.cpython-311.pyc +0 -0
- modules/database/__pycache__/morphosintax_db.cpython-311.pyc +0 -0
- modules/database/__pycache__/morphosintax_mongo_db.cpython-311.pyc +0 -0
- modules/database/__pycache__/morphosintaxis_export.cpython-311.pyc +0 -0
- modules/database/__pycache__/sql_db.cpython-311.pyc +0 -0
- modules/database/backUp/database.py +216 -0
- modules/database/backUp/databaseBackUp23-9-24.py +581 -0
- modules/database/backUp/database_oldFromV2.py +473 -0
- modules/database/backUp/database_v3-2ok.py +629 -0
- modules/database/chat_db.py +45 -0
- modules/database/database_init.py +80 -0
- modules/database/mongo_db.py +51 -0
- modules/database/morphosintax_mongo_db.py +49 -0
- modules/database/morphosintaxis_export.py +78 -0
- modules/database/morphosintaxis_export_v1.py +97 -0
- modules/database/sql_db.py +129 -0
- modules/database/txt.txt +0 -0
app.py
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#app.py de v3
|
2 |
+
#app.py
|
3 |
+
import logging
|
4 |
+
import streamlit as st
|
5 |
+
import sys
|
6 |
+
import os
|
7 |
+
from dotenv import load_dotenv
|
8 |
+
from datetime import datetime
|
9 |
+
|
10 |
+
def setup_logging():
|
11 |
+
log_dir = 'logs'
|
12 |
+
if not os.path.exists(log_dir):
|
13 |
+
os.makedirs(log_dir)
|
14 |
+
current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
|
15 |
+
log_filename = f'{log_dir}/app_log_{current_time}.txt'
|
16 |
+
logging.basicConfig(
|
17 |
+
level=logging.DEBUG,
|
18 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
19 |
+
filename=log_filename,
|
20 |
+
filemode='w'
|
21 |
+
)
|
22 |
+
console = logging.StreamHandler()
|
23 |
+
console.setLevel(logging.INFO)
|
24 |
+
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
25 |
+
console.setFormatter(formatter)
|
26 |
+
logging.getLogger('').addHandler(console)
|
27 |
+
logging.info(f"Logging iniciado. Archivo de log: {log_filename}")
|
28 |
+
|
29 |
+
setup_logging()
|
30 |
+
load_dotenv()
|
31 |
+
|
32 |
+
st.set_page_config(page_title="AIdeaText", layout="wide", page_icon="random")
|
33 |
+
|
34 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
35 |
+
|
36 |
+
#########IMPORTACIONES LOCALES#######################################
|
37 |
+
from translations import get_translations
|
38 |
+
|
39 |
+
from session_state import initialize_session_state
|
40 |
+
|
41 |
+
from modules.ui.ui import main as ui_main
|
42 |
+
|
43 |
+
from modules.utils.spacy_utils import load_spacy_models
|
44 |
+
|
45 |
+
from modules.morphosyntax.morphosyntax_interface import (
|
46 |
+
display_morphosyntax_interface
|
47 |
+
)
|
48 |
+
|
49 |
+
###Importaciones de la base de datos###
|
50 |
+
from modules.database.database_init import (
|
51 |
+
initialize_database_connections
|
52 |
+
)
|
53 |
+
|
54 |
+
from modules.database.sql_db import (
|
55 |
+
create_student_user,
|
56 |
+
get_student_user,
|
57 |
+
update_student_user,
|
58 |
+
delete_student_user,
|
59 |
+
store_application_request,
|
60 |
+
store_student_feedback
|
61 |
+
)
|
62 |
+
|
63 |
+
|
64 |
+
from modules.database.mongo_db import (
|
65 |
+
get_collection,
|
66 |
+
insert_document,
|
67 |
+
find_documents,
|
68 |
+
update_document,
|
69 |
+
delete_document
|
70 |
+
)
|
71 |
+
|
72 |
+
from modules.database.morphosintax_mongo_db import (
|
73 |
+
store_student_morphosyntax_result,
|
74 |
+
get_student_morphosyntax_analysis
|
75 |
+
)
|
76 |
+
|
77 |
+
from modules.database.chat_db import (
|
78 |
+
store_chat_history,
|
79 |
+
get_chat_history
|
80 |
+
)
|
81 |
+
|
82 |
+
from modules.studentact.student_activities_v2 import (
|
83 |
+
display_student_progress
|
84 |
+
)
|
85 |
+
|
86 |
+
from modules.auth.auth import (
|
87 |
+
authenticate_student,
|
88 |
+
register_student,
|
89 |
+
update_student_info,
|
90 |
+
delete_student
|
91 |
+
)
|
92 |
+
|
93 |
+
from modules.admin.admin_ui import admin_page
|
94 |
+
|
95 |
+
from modules.chatbot.chatbot import (
|
96 |
+
initialize_chatbot,
|
97 |
+
process_chat_input
|
98 |
+
)
|
99 |
+
|
100 |
+
print("Configurando página")
|
101 |
+
st.cache_data.clear()
|
102 |
+
st.cache_resource.clear()
|
103 |
+
|
104 |
+
logging.basicConfig(level=logging.INFO)
|
105 |
+
logger = logging.getLogger(__name__)
|
106 |
+
|
107 |
+
@st.cache_resource
|
108 |
+
def initialize_nlp_models():
|
109 |
+
logger.info("Cargando modelos de spaCy")
|
110 |
+
models = load_spacy_models()
|
111 |
+
logger.info("Modelos de spaCy cargados exitosamente")
|
112 |
+
return models
|
113 |
+
|
114 |
+
def app_main():
|
115 |
+
try:
|
116 |
+
logger.info("Entrando en app_main()")
|
117 |
+
|
118 |
+
# Inicializar el estado de la sesión
|
119 |
+
initialize_session_state()
|
120 |
+
|
121 |
+
# Inicializar conexiones a bases de datos si no se ha hecho
|
122 |
+
if 'db_initialized' not in st.session_state:
|
123 |
+
st.session_state.db_initialized = initialize_database_connections()
|
124 |
+
|
125 |
+
# Cargar modelos NLP si no se ha hecho
|
126 |
+
if 'nlp_models' not in st.session_state:
|
127 |
+
logger.info("Inicializando modelos NLP en la sesión")
|
128 |
+
st.session_state.nlp_models = initialize_nlp_models()
|
129 |
+
logger.info("Modelos NLP inicializados y almacenados en la sesión")
|
130 |
+
|
131 |
+
# Configurar la página inicial si no está configurada
|
132 |
+
if 'page' not in st.session_state:
|
133 |
+
st.session_state.page = 'login'
|
134 |
+
|
135 |
+
logger.info(f"Página actual: {st.session_state.page}")
|
136 |
+
logger.info(f"Rol del usuario: {st.session_state.role}")
|
137 |
+
|
138 |
+
# Dirigir el flujo a la interfaz de usuario principal
|
139 |
+
logger.info(f"Llamando a ui_main() desde app_main()")
|
140 |
+
ui_main()
|
141 |
+
|
142 |
+
except Exception as e:
|
143 |
+
logger.error(f"Error en app_main: {str(e)}", exc_info=True)
|
144 |
+
st.error("Se ha producido un error en la aplicación. Por favor, inténtelo de nuevo más tarde.")
|
145 |
+
if st.button("Reiniciar aplicación"):
|
146 |
+
st.rerun()
|
147 |
+
|
148 |
+
if __name__ == "__main__":
|
149 |
+
print("Llamando a app_main()")
|
150 |
+
app_main()
|
assets/img/AIdeaTextCard.jpg
ADDED
assets/img/Mesa de trabajo 1png 0.3.png
ADDED
assets/img/logo_92x92.jpg
ADDED
assets/img/logo_92x92.png
ADDED
assets/img/text.txt
ADDED
File without changes
|
modules/23-7-2024_auth.py
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
### auth.py
|
2 |
+
import os
|
3 |
+
from azure.cosmos import CosmosClient, exceptions
|
4 |
+
import bcrypt
|
5 |
+
import base64
|
6 |
+
|
7 |
+
################################################################################################################
|
8 |
+
def clean_and_validate_key(key):
|
9 |
+
key = key.strip()
|
10 |
+
while len(key) % 4 != 0:
|
11 |
+
key += '='
|
12 |
+
try:
|
13 |
+
base64.b64decode(key)
|
14 |
+
return key
|
15 |
+
except:
|
16 |
+
raise ValueError("La clave proporcionada no es válida")
|
17 |
+
|
18 |
+
# Azure Cosmos DB configuration
|
19 |
+
endpoint = os.environ.get("COSMOS_ENDPOINT")
|
20 |
+
key = os.environ.get("COSMOS_KEY")
|
21 |
+
|
22 |
+
if not endpoint or not key:
|
23 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
24 |
+
|
25 |
+
key = clean_and_validate_key(key)
|
26 |
+
|
27 |
+
try:
|
28 |
+
client = CosmosClient(endpoint, key)
|
29 |
+
database = client.get_database_client("user_database")
|
30 |
+
container = database.get_container_client("users")
|
31 |
+
# Prueba de conexión
|
32 |
+
database_list = list(client.list_databases())
|
33 |
+
print(f"Conexión exitosa. Bases de datos encontradas: {len(database_list)}")
|
34 |
+
except Exception as e:
|
35 |
+
print(f"Error al conectar con Cosmos DB: {str(e)}")
|
36 |
+
raise
|
37 |
+
|
38 |
+
#############################################################################################################3
|
39 |
+
def hash_password(password):
|
40 |
+
"""Hash a password for storing."""
|
41 |
+
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
42 |
+
|
43 |
+
################################################################################################################
|
44 |
+
def verify_password(stored_password, provided_password):
|
45 |
+
"""Verify a stored password against one provided by user"""
|
46 |
+
return bcrypt.checkpw(provided_password.encode('utf-8'), stored_password.encode('utf-8'))
|
47 |
+
|
48 |
+
################################################################################################################
|
49 |
+
def register_user(username, password, additional_info=None):
|
50 |
+
try:
|
51 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
52 |
+
existing_user = list(container.query_items(query=query, enable_cross_partition_query=True))
|
53 |
+
|
54 |
+
if existing_user:
|
55 |
+
return False # User already exists
|
56 |
+
|
57 |
+
new_user = {
|
58 |
+
'id': username,
|
59 |
+
'password': hash_password(password),
|
60 |
+
'role': 'Estudiante',
|
61 |
+
'additional_info': additional_info or {}
|
62 |
+
}
|
63 |
+
|
64 |
+
new_user['partitionKey'] = username
|
65 |
+
|
66 |
+
container.create_item(body=new_user)
|
67 |
+
return True
|
68 |
+
except exceptions.CosmosHttpResponseError as e:
|
69 |
+
print(f"Error al registrar usuario: {str(e)}")
|
70 |
+
return False
|
71 |
+
|
72 |
+
|
73 |
+
################################################################################################################
|
74 |
+
def authenticate_user(username, password):
|
75 |
+
"""Authenticate a user."""
|
76 |
+
try:
|
77 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
78 |
+
results = list(container.query_items(query=query, partition_key=username))
|
79 |
+
|
80 |
+
if results:
|
81 |
+
stored_user = results[0]
|
82 |
+
if verify_password(stored_user['password'], password):
|
83 |
+
return True
|
84 |
+
except exceptions.CosmosHttpResponseError:
|
85 |
+
pass
|
86 |
+
|
87 |
+
return False
|
88 |
+
|
89 |
+
|
90 |
+
################################################################################################################
|
91 |
+
def get_user_role(username):
|
92 |
+
"""Get the role of a user."""
|
93 |
+
try:
|
94 |
+
query = f"SELECT c.role FROM c WHERE c.id = '{username}'"
|
95 |
+
results = list(container.query_items(query=query, partition_key=username))
|
96 |
+
|
97 |
+
if results:
|
98 |
+
return results[0]['role']
|
99 |
+
except exceptions.CosmosHttpResponseError:
|
100 |
+
pass
|
101 |
+
|
102 |
+
return None
|
103 |
+
|
104 |
+
################################################################################################################
|
105 |
+
def update_user_info(username, new_info):
|
106 |
+
"""Update user information."""
|
107 |
+
try:
|
108 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
109 |
+
results = list(container.query_items(query=query, partition_key=username))
|
110 |
+
|
111 |
+
if results:
|
112 |
+
user = results[0]
|
113 |
+
user['additional_info'].update(new_info)
|
114 |
+
container.upsert_item(user, partition_key=username)
|
115 |
+
return True
|
116 |
+
except exceptions.CosmosHttpResponseError:
|
117 |
+
pass
|
118 |
+
|
119 |
+
return False
|
120 |
+
|
121 |
+
################################################################################################################
|
122 |
+
def delete_user(username):
|
123 |
+
"""Delete a user."""
|
124 |
+
try:
|
125 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
126 |
+
results = list(container.query_items(query=query, partition_key=username))
|
127 |
+
|
128 |
+
if results:
|
129 |
+
user = results[0]
|
130 |
+
container.delete_item(item=user['id'], partition_key=username)
|
131 |
+
return True
|
132 |
+
except exceptions.CosmosHttpResponseError:
|
133 |
+
pass
|
134 |
+
|
135 |
+
return False
|
modules/23-7-2024_ui.py
ADDED
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# modules/ui.py
|
2 |
+
# Importaciones estandar de python
|
3 |
+
import io
|
4 |
+
import streamlit as st
|
5 |
+
import matplotlib
|
6 |
+
matplotlib.use('Agg')
|
7 |
+
import matplotlib.pyplot as plt
|
8 |
+
import squarify
|
9 |
+
import pandas as pd
|
10 |
+
from datetime import datetime
|
11 |
+
import base64
|
12 |
+
from spacy import displacy
|
13 |
+
import re
|
14 |
+
from .morpho_analysis import POS_COLORS, POS_TRANSLATIONS # Asegúrate de que esta importación esté presente
|
15 |
+
print("POS_COLORS:", POS_COLORS)
|
16 |
+
print("POS_TRANSLATIONS:", POS_TRANSLATIONS)
|
17 |
+
|
18 |
+
# Importaciones locales
|
19 |
+
from .auth import authenticate_user, register_user, get_user_role
|
20 |
+
from .database import get_student_data, store_analysis_result
|
21 |
+
from .morpho_analysis import get_repeated_words_colors, highlight_repeated_words, POS_COLORS, POS_TRANSLATIONS
|
22 |
+
from .syntax_analysis import visualize_syntax
|
23 |
+
|
24 |
+
#########################################################################
|
25 |
+
# Define colors for grammatical categories
|
26 |
+
POS_COLORS = {
|
27 |
+
'ADJ': '#FFA07A', # Light Salmon
|
28 |
+
'ADP': '#98FB98', # Pale Green
|
29 |
+
'ADV': '#87CEFA', # Light Sky Blue
|
30 |
+
'AUX': '#DDA0DD', # Plum
|
31 |
+
'CCONJ': '#F0E68C', # Khaki
|
32 |
+
'DET': '#FFB6C1', # Light Pink
|
33 |
+
'INTJ': '#FF6347', # Tomato
|
34 |
+
'NOUN': '#90EE90', # Light Green
|
35 |
+
'NUM': '#FAFAD2', # Light Goldenrod Yellow
|
36 |
+
'PART': '#D3D3D3', # Light Gray
|
37 |
+
'PRON': '#FFA500', # Orange
|
38 |
+
'PROPN': '#20B2AA', # Light Sea Green
|
39 |
+
'SCONJ': '#DEB887', # Burlywood
|
40 |
+
'SYM': '#7B68EE', # Medium Slate Blue
|
41 |
+
'VERB': '#FF69B4', # Hot Pink
|
42 |
+
'X': '#A9A9A9', # Dark Gray
|
43 |
+
}
|
44 |
+
|
45 |
+
POS_TRANSLATIONS = {
|
46 |
+
'es': {
|
47 |
+
'ADJ': 'Adjetivo',
|
48 |
+
'ADP': 'Adposición',
|
49 |
+
'ADV': 'Adverbio',
|
50 |
+
'AUX': 'Auxiliar',
|
51 |
+
'CCONJ': 'Conjunción Coordinante',
|
52 |
+
'DET': 'Determinante',
|
53 |
+
'INTJ': 'Interjección',
|
54 |
+
'NOUN': 'Sustantivo',
|
55 |
+
'NUM': 'Número',
|
56 |
+
'PART': 'Partícula',
|
57 |
+
'PRON': 'Pronombre',
|
58 |
+
'PROPN': 'Nombre Propio',
|
59 |
+
'SCONJ': 'Conjunción Subordinante',
|
60 |
+
'SYM': 'Símbolo',
|
61 |
+
'VERB': 'Verbo',
|
62 |
+
'X': 'Otro',
|
63 |
+
},
|
64 |
+
'en': {
|
65 |
+
'ADJ': 'Adjective',
|
66 |
+
'ADP': 'Adposition',
|
67 |
+
'ADV': 'Adverb',
|
68 |
+
'AUX': 'Auxiliary',
|
69 |
+
'CCONJ': 'Coordinating Conjunction',
|
70 |
+
'DET': 'Determiner',
|
71 |
+
'INTJ': 'Interjection',
|
72 |
+
'NOUN': 'Noun',
|
73 |
+
'NUM': 'Number',
|
74 |
+
'PART': 'Particle',
|
75 |
+
'PRON': 'Pronoun',
|
76 |
+
'PROPN': 'Proper Noun',
|
77 |
+
'SCONJ': 'Subordinating Conjunction',
|
78 |
+
'SYM': 'Symbol',
|
79 |
+
'VERB': 'Verb',
|
80 |
+
'X': 'Other',
|
81 |
+
},
|
82 |
+
'fr': {
|
83 |
+
'ADJ': 'Adjectif',
|
84 |
+
'ADP': 'Adposition',
|
85 |
+
'ADV': 'Adverbe',
|
86 |
+
'AUX': 'Auxiliaire',
|
87 |
+
'CCONJ': 'Conjonction de Coordination',
|
88 |
+
'DET': 'Déterminant',
|
89 |
+
'INTJ': 'Interjection',
|
90 |
+
'NOUN': 'Nom',
|
91 |
+
'NUM': 'Nombre',
|
92 |
+
'PART': 'Particule',
|
93 |
+
'PRON': 'Pronom',
|
94 |
+
'PROPN': 'Nom Propre',
|
95 |
+
'SCONJ': 'Conjonction de Subordination',
|
96 |
+
'SYM': 'Symbole',
|
97 |
+
'VERB': 'Verbe',
|
98 |
+
'X': 'Autre',
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
##########################################################################
|
103 |
+
def login_page():
|
104 |
+
st.title("Iniciar Sesión")
|
105 |
+
username = st.text_input("Usuario")
|
106 |
+
password = st.text_input("Contraseña", type='password')
|
107 |
+
if st.button("Iniciar Sesión"):
|
108 |
+
if authenticate_user(username, password):
|
109 |
+
st.success(f"Bienvenido, {username}!")
|
110 |
+
st.session_state.logged_in = True
|
111 |
+
st.session_state.username = username
|
112 |
+
st.session_state.role = get_user_role(username)
|
113 |
+
st.experimental_rerun()
|
114 |
+
else:
|
115 |
+
st.error("Usuario o contraseña incorrectos")
|
116 |
+
|
117 |
+
##########################################################################
|
118 |
+
def register_page():
|
119 |
+
st.title("Registrarse")
|
120 |
+
new_username = st.text_input("Nuevo Usuario")
|
121 |
+
new_password = st.text_input("Nueva Contraseña", type='password')
|
122 |
+
|
123 |
+
additional_info = {}
|
124 |
+
additional_info['carrera'] = st.text_input("Carrera")
|
125 |
+
|
126 |
+
if st.button("Registrarse"):
|
127 |
+
if register_user(new_username, new_password, additional_info):
|
128 |
+
st.success("Registro exitoso. Por favor, inicia sesión.")
|
129 |
+
else:
|
130 |
+
st.error("El usuario ya existe o ocurrió un error durante el registro")
|
131 |
+
|
132 |
+
##########################################################################
|
133 |
+
def get_chatbot_response(input_text):
|
134 |
+
# Esta función debe ser implementada o importada de otro módulo
|
135 |
+
# Por ahora, retornamos un mensaje genérico
|
136 |
+
return "Lo siento, el chatbot no está disponible en este momento."
|
137 |
+
|
138 |
+
##########################################################################
|
139 |
+
def display_chat_interface():
|
140 |
+
st.markdown("### Chat con AIdeaText")
|
141 |
+
|
142 |
+
if 'chat_history' not in st.session_state:
|
143 |
+
st.session_state.chat_history = []
|
144 |
+
|
145 |
+
for i, (role, text) in enumerate(st.session_state.chat_history):
|
146 |
+
if role == "user":
|
147 |
+
st.text_area(f"Tú:", value=text, height=50, key=f"user_message_{i}", disabled=True)
|
148 |
+
else:
|
149 |
+
st.text_area(f"AIdeaText:", value=text, height=50, key=f"bot_message_{i}", disabled=True)
|
150 |
+
|
151 |
+
user_input = st.text_input("Escribe tu mensaje aquí:")
|
152 |
+
|
153 |
+
if st.button("Enviar"):
|
154 |
+
if user_input:
|
155 |
+
st.session_state.chat_history.append(("user", user_input))
|
156 |
+
response = get_chatbot_response(user_input)
|
157 |
+
st.session_state.chat_history.append(("bot", response))
|
158 |
+
st.experimental_rerun()
|
159 |
+
|
160 |
+
##########################################################################
|
161 |
+
|
162 |
+
def display_student_progress(username, lang_code='es'):
|
163 |
+
print("lang_code:", lang_code)
|
164 |
+
student_data = get_student_data(username)
|
165 |
+
|
166 |
+
if student_data is None:
|
167 |
+
st.warning("No se encontraron datos para este estudiante.")
|
168 |
+
st.info("Intenta realizar algunos análisis de texto primero.")
|
169 |
+
return
|
170 |
+
|
171 |
+
st.title(f"Progreso de {username}")
|
172 |
+
|
173 |
+
if student_data['entries_count'] > 0:
|
174 |
+
if 'word_count' in student_data and student_data['word_count']:
|
175 |
+
st.subheader("Total de palabras por categoría gramatical")
|
176 |
+
|
177 |
+
df = pd.DataFrame(list(student_data['word_count'].items()), columns=['category', 'count'])
|
178 |
+
df['label'] = df.apply(lambda x: f"{POS_TRANSLATIONS[lang_code].get(x['category'], x['category'])}", axis=1)
|
179 |
+
|
180 |
+
# Ordenar el DataFrame por conteo de palabras, de mayor a menor
|
181 |
+
df = df.sort_values('count', ascending=False)
|
182 |
+
|
183 |
+
fig, ax = plt.subplots(figsize=(12, 6))
|
184 |
+
bars = ax.bar(df['label'], df['count'], color=[POS_COLORS.get(cat, '#CCCCCC') for cat in df['category']])
|
185 |
+
|
186 |
+
ax.set_xlabel('Categoría Gramatical')
|
187 |
+
ax.set_ylabel('Cantidad de Palabras')
|
188 |
+
ax.set_title('Total de palabras por categoría gramatical')
|
189 |
+
plt.xticks(rotation=45, ha='right')
|
190 |
+
|
191 |
+
# Añadir etiquetas de valor en las barras
|
192 |
+
for bar in bars:
|
193 |
+
height = bar.get_height()
|
194 |
+
ax.text(bar.get_x() + bar.get_width()/2., height,
|
195 |
+
f'{height}',
|
196 |
+
ha='center', va='bottom')
|
197 |
+
|
198 |
+
plt.tight_layout()
|
199 |
+
|
200 |
+
buf = io.BytesIO()
|
201 |
+
fig.savefig(buf, format='png')
|
202 |
+
buf.seek(0)
|
203 |
+
st.image(buf, use_column_width=True)
|
204 |
+
else:
|
205 |
+
st.info("No hay datos de conteo de palabras disponibles.")
|
206 |
+
|
207 |
+
# Diagramas de Arco (consolidados)
|
208 |
+
st.header("Diagramas de Arco")
|
209 |
+
with st.expander("Ver todos los Diagramas de Arco"):
|
210 |
+
for i, entry in enumerate(student_data['entries']):
|
211 |
+
if 'arc_diagrams' in entry and entry['arc_diagrams']:
|
212 |
+
st.subheader(f"Entrada {i+1} - {entry['timestamp']}")
|
213 |
+
st.write(entry['arc_diagrams'][0], unsafe_allow_html=True)
|
214 |
+
|
215 |
+
# Diagramas de Red (consolidados)
|
216 |
+
st.header("Diagramas de Red")
|
217 |
+
with st.expander("Ver todos los Diagramas de Red"):
|
218 |
+
for i, entry in enumerate(student_data['entries']):
|
219 |
+
if 'network_diagram' in entry and entry['network_diagram']:
|
220 |
+
st.subheader(f"Entrada {i+1} - {entry['timestamp']}")
|
221 |
+
try:
|
222 |
+
# Decodificar la imagen base64
|
223 |
+
image_bytes = base64.b64decode(entry['network_diagram'])
|
224 |
+
st.image(image_bytes)
|
225 |
+
except Exception as e:
|
226 |
+
st.error(f"Error al mostrar el diagrama de red: {str(e)}")
|
227 |
+
else:
|
228 |
+
st.warning("No se encontraron entradas para este estudiante.")
|
229 |
+
st.info("Intenta realizar algunos análisis de texto primero.")
|
230 |
+
|
231 |
+
##############################################################Mostrar entradas recientes######################################################################
|
232 |
+
#st.header("Entradas Recientes")
|
233 |
+
#for i, entry in enumerate(student_data['entries'][:5]): # Mostrar las 5 entradas más recientes
|
234 |
+
#with st.expander(f"Entrada {i+1} - {entry['timestamp']}"):
|
235 |
+
#st.write(entry['text'])
|
236 |
+
#else:
|
237 |
+
#st.warning("No se encontraron entradas para este estudiante.")
|
238 |
+
#st.info("Intenta realizar algunos análisis de texto primero.")
|
239 |
+
|
240 |
+
##########################################################################
|
241 |
+
def display_text_analysis_interface(nlp_models, lang_code):
|
242 |
+
translations = {
|
243 |
+
'es': {
|
244 |
+
'title': "AIdeaText - Análisis morfológico y sintáctico",
|
245 |
+
'input_label': "Ingrese un texto para analizar (máx. 5,000 palabras):",
|
246 |
+
'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.",
|
247 |
+
'analyze_button': "Analizar texto",
|
248 |
+
'repeated_words': "Palabras repetidas",
|
249 |
+
'legend': "Leyenda: Categorías gramaticales",
|
250 |
+
'arc_diagram': "Análisis sintáctico: Diagrama de arco",
|
251 |
+
'network_diagram': "Análisis sintáctico: Diagrama de red",
|
252 |
+
'sentence': "Oración"
|
253 |
+
},
|
254 |
+
'en': {
|
255 |
+
'title': "AIdeaText - Morphological and Syntactic Analysis",
|
256 |
+
'input_label': "Enter a text to analyze (max 5,000 words):",
|
257 |
+
'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.",
|
258 |
+
'analyze_button': "Analyze text",
|
259 |
+
'repeated_words': "Repeated words",
|
260 |
+
'legend': "Legend: Grammatical categories",
|
261 |
+
'arc_diagram': "Syntactic analysis: Arc diagram",
|
262 |
+
'network_diagram': "Syntactic analysis: Network diagram",
|
263 |
+
'sentence': "Sentence"
|
264 |
+
},
|
265 |
+
'fr': {
|
266 |
+
'title': "AIdeaText - Analyse morphologique et syntaxique",
|
267 |
+
'input_label': "Entrez un texte à analyser (max 5 000 mots) :",
|
268 |
+
'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.",
|
269 |
+
'analyze_button': "Analyser le texte",
|
270 |
+
'repeated_words': "Mots répétés",
|
271 |
+
'legend': "Légende : Catégories grammaticales",
|
272 |
+
'arc_diagram': "Analyse syntaxique : Diagramme en arc",
|
273 |
+
'network_diagram': "Analyse syntaxique : Diagramme de réseau",
|
274 |
+
'sentence': "Phrase"
|
275 |
+
}
|
276 |
+
}
|
277 |
+
|
278 |
+
t = translations[lang_code]
|
279 |
+
|
280 |
+
if 'input_text' not in st.session_state:
|
281 |
+
st.session_state.input_text = ""
|
282 |
+
|
283 |
+
# Añadimos una clave única basada en el idioma seleccionado
|
284 |
+
sentence_input = st.text_area(
|
285 |
+
t['input_label'],
|
286 |
+
height=150,
|
287 |
+
placeholder=t['input_placeholder'],
|
288 |
+
value=st.session_state.input_text,
|
289 |
+
key=f"text_input_{lang_code}" # Clave única basada en el idioma
|
290 |
+
)
|
291 |
+
st.session_state.input_text = sentence_input
|
292 |
+
|
293 |
+
# sentence_input = st.text_area(t['input_label'], height=150, placeholder=t['input_placeholder'], value=st.session_state.input_text)
|
294 |
+
# st.session_state.input_text = sentence_input
|
295 |
+
|
296 |
+
if st.button(t['analyze_button'], key=f"analyze_button_{lang_code}"):
|
297 |
+
if sentence_input:
|
298 |
+
doc = nlp_models[lang_code](sentence_input)
|
299 |
+
|
300 |
+
with st.expander(t['repeated_words'], expanded=True):
|
301 |
+
word_colors = get_repeated_words_colors(doc)
|
302 |
+
highlighted_text = highlight_repeated_words(doc, word_colors)
|
303 |
+
st.markdown(highlighted_text, unsafe_allow_html=True)
|
304 |
+
|
305 |
+
st.markdown(f"##### {t['legend']}")
|
306 |
+
legend_html = "<div style='display: flex; flex-wrap: wrap;'>"
|
307 |
+
for pos, color in POS_COLORS.items():
|
308 |
+
if pos in POS_TRANSLATIONS:
|
309 |
+
legend_html += f"<div style='margin-right: 10px;'><span style='background-color: {color}; padding: 2px 5px;'>{POS_TRANSLATIONS[pos]}</span></div>"
|
310 |
+
legend_html += "</div>"
|
311 |
+
st.markdown(legend_html, unsafe_allow_html=True)
|
312 |
+
|
313 |
+
with st.expander(t['arc_diagram'], expanded=True):
|
314 |
+
sentences = list(doc.sents)
|
315 |
+
arc_diagrams = []
|
316 |
+
for i, sent in enumerate(sentences):
|
317 |
+
st.subheader(f"{t['sentence']} {i+1}")
|
318 |
+
html = displacy.render(sent, style="dep", options={"distance": 100})
|
319 |
+
html = html.replace('height="375"', 'height="200"')
|
320 |
+
html = re.sub(r'<svg[^>]*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html)
|
321 |
+
html = re.sub(r'<g [^>]*transform="translate\((\d+),(\d+)\)"', lambda m: f'<g transform="translate({m.group(1)},50)"', html)
|
322 |
+
st.write(html, unsafe_allow_html=True)
|
323 |
+
arc_diagrams.append(html)
|
324 |
+
|
325 |
+
with st.expander(t['network_diagram'], expanded=True):
|
326 |
+
fig = visualize_syntax(sentence_input, nlp_models[lang_code], lang_code)
|
327 |
+
st.pyplot(fig)
|
328 |
+
|
329 |
+
if store_analysis_result(
|
330 |
+
st.session_state.username,
|
331 |
+
sentence_input,
|
332 |
+
word_colors,
|
333 |
+
arc_diagrams,
|
334 |
+
fig
|
335 |
+
):
|
336 |
+
st.success("Análisis guardado correctamente.")
|
337 |
+
else:
|
338 |
+
st.error("Hubo un problema al guardar el análisis. Por favor, inténtelo de nuevo.")
|
339 |
+
st.error(f"Falló el guardado del análisis. Username: {st.session_state.username}")
|
340 |
+
|
341 |
+
##########################################################################
|
342 |
+
def display_teacher_interface():
|
343 |
+
st.write("Bienvenido, profesor. Aquí podrás ver el progreso de tus estudiantes.")
|
344 |
+
# Aquí puedes agregar la lógica para mostrar el progreso de los estudiantes
|
modules/__init__.py
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# modules/__init__.py
|
2 |
+
|
3 |
+
def load_auth_functions():
|
4 |
+
from .auth.auth import authenticate_student, register_student, update_student_info, delete_student
|
5 |
+
return {
|
6 |
+
'authenticate_student': authenticate_student,
|
7 |
+
'register_student': register_student,
|
8 |
+
'update_student_info': update_student_info,
|
9 |
+
'delete_student': delete_student
|
10 |
+
}
|
11 |
+
|
12 |
+
def load_database_functions():
|
13 |
+
|
14 |
+
from .database.database_init import (
|
15 |
+
initialize_database_connections
|
16 |
+
)
|
17 |
+
|
18 |
+
from .database.sql_db import (
|
19 |
+
create_student_user,
|
20 |
+
get_student_user,
|
21 |
+
update_student_user,
|
22 |
+
delete_student_user,
|
23 |
+
store_application_request,
|
24 |
+
store_student_feedback
|
25 |
+
)
|
26 |
+
from .database.mongo_db import (
|
27 |
+
get_collection,
|
28 |
+
insert_document,
|
29 |
+
find_documents,
|
30 |
+
update_document,
|
31 |
+
delete_document,
|
32 |
+
)
|
33 |
+
from .database.morphosintax_mongo_db import (
|
34 |
+
store_student_morphosyntax_result,
|
35 |
+
get_student_morphosyntax_analysis,
|
36 |
+
update_student_morphosyntax_analysis,
|
37 |
+
delete_student_morphosyntax_analysis,
|
38 |
+
get_student_morphosyntax_data
|
39 |
+
)
|
40 |
+
from .database.chat_db import store_chat_history, get_chat_history
|
41 |
+
|
42 |
+
return {
|
43 |
+
'initialize_database_connections': initialize_database_connections,
|
44 |
+
'create_student_user': create_student_user,
|
45 |
+
'get_student_user': get_student_user,
|
46 |
+
'update_student_user': update_student_user,
|
47 |
+
'delete_student_user': delete_student_user,
|
48 |
+
'store_application_request': store_application_request,
|
49 |
+
'store_student_feedback': store_student_feedback,
|
50 |
+
'get_collection': get_collection,
|
51 |
+
'insert_document': insert_document,
|
52 |
+
'find_documents': find_documents,
|
53 |
+
'update_document': update_document,
|
54 |
+
'delete_document': delete_document,
|
55 |
+
'store_student_morphosyntax_result': store_student_morphosyntax_result,
|
56 |
+
'get_student_morphosyntax_analysis': get_student_morphosyntax_analysis,
|
57 |
+
'update_student_morphosyntax_analysis': update_student_morphosyntax_analysis,
|
58 |
+
'delete_student_morphosyntax_analysis': delete_student_morphosyntax_analysis,
|
59 |
+
'get_student_morphosyntax_data': get_student_morphosyntax_data,
|
60 |
+
'store_chat_history': store_chat_history,
|
61 |
+
'get_chat_history': get_chat_history
|
62 |
+
}
|
63 |
+
|
64 |
+
def load_ui_functions():
|
65 |
+
# No importamos nada de ui.py aquí
|
66 |
+
return {} # Retornamos un diccionario vacío
|
67 |
+
|
68 |
+
def load_student_activities_functions():
|
69 |
+
from .studentact.student_activities import display_student_progress
|
70 |
+
return {
|
71 |
+
'display_student_progress': display_student_progress
|
72 |
+
}
|
73 |
+
|
74 |
+
def load_morphosyntax_functions():
|
75 |
+
from .morphosyntax.morphosyntax_interface import display_morphosyntax_interface
|
76 |
+
from .morphosyntax.morphosyntax_process import process_morphosyntactic_input
|
77 |
+
return {
|
78 |
+
'display_morphosyntax_interface': display_morphosyntax_interface,
|
79 |
+
'process_morphosyntactic_input': process_morphosyntactic_input
|
80 |
+
}
|
81 |
+
|
82 |
+
def load_admin_functions():
|
83 |
+
from .admin.admin_ui import admin_page
|
84 |
+
return {
|
85 |
+
'admin_page': admin_page
|
86 |
+
}
|
87 |
+
|
88 |
+
def load_utils_functions():
|
89 |
+
from .utils.spacy_utils import load_spacy_models
|
90 |
+
return {
|
91 |
+
'load_spacy_models': load_spacy_models
|
92 |
+
}
|
93 |
+
|
94 |
+
def load_chatbot_functions():
|
95 |
+
from .chatbot.chatbot import initialize_chatbot, process_chat_input
|
96 |
+
return {
|
97 |
+
'initialize_chatbot': initialize_chatbot,
|
98 |
+
'process_chat_input': process_chat_input
|
99 |
+
}
|
100 |
+
|
101 |
+
# Función para cargar todas las funciones
|
102 |
+
def load_all_functions():
|
103 |
+
return {
|
104 |
+
**load_auth_functions(),
|
105 |
+
**load_database_functions(),
|
106 |
+
# **load_ui_functions(),
|
107 |
+
**load_admin_functions(),
|
108 |
+
**load_morphosyntax_functions(),
|
109 |
+
**load_utils_functions(),
|
110 |
+
**load_chatbot_functions(),
|
111 |
+
**load_student_activities_functions()
|
112 |
+
}
|
modules/__init__Old-V3.py
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# modules/__init__.py
|
2 |
+
|
3 |
+
def load_auth_functions():
|
4 |
+
from .auth.auth import authenticate_user, register_user
|
5 |
+
return {
|
6 |
+
'authenticate_user': authenticate_user,
|
7 |
+
'register_user': register_user
|
8 |
+
}
|
9 |
+
|
10 |
+
def load_database_function():
|
11 |
+
from .database.database_oldFromV2 import (
|
12 |
+
initialize_mongodb_connection,
|
13 |
+
initialize_database_connections,
|
14 |
+
create_admin_user,
|
15 |
+
create_student_user,
|
16 |
+
get_user,
|
17 |
+
get_student_data,
|
18 |
+
get_user_files,
|
19 |
+
delete_file,
|
20 |
+
store_application_request,
|
21 |
+
store_user_feedback,
|
22 |
+
store_morphosyntax_result,
|
23 |
+
store_semantic_result,
|
24 |
+
store_discourse_analysis_result,
|
25 |
+
store_chat_history,
|
26 |
+
export_analysis_and_chat,
|
27 |
+
manage_file_contents
|
28 |
+
)
|
29 |
+
return {
|
30 |
+
'initialize_mongodb_connection': initialize_mongodb_connection,
|
31 |
+
'initialize_database_connections': initialize_database_connections,
|
32 |
+
'create_admin_user': create_admin_user,
|
33 |
+
'create_student_user': create_student_user,
|
34 |
+
'get_user': get_user,
|
35 |
+
'get_student_data': get_student_data,
|
36 |
+
'get_user_files': get_user_files,
|
37 |
+
'delete_file': delete_file,
|
38 |
+
'store_application_request': store_application_request,
|
39 |
+
'store_user_feedback': store_user_feedback,
|
40 |
+
'store_morphosyntax_result': store_morphosyntax_result,
|
41 |
+
'store_semantic_result': store_semantic_result,
|
42 |
+
'store_discourse_analysis_result': store_discourse_analysis_result,
|
43 |
+
'store_chat_history': store_chat_history,
|
44 |
+
'export_analysis_and_chat': export_analysis_and_chat,
|
45 |
+
'manage_file_contents': manage_file_contents
|
46 |
+
}
|
47 |
+
|
48 |
+
def load_ui_functions():
|
49 |
+
# No importamos nada de ui.py aquí
|
50 |
+
return {} # Retornamos un diccionario vacío
|
51 |
+
|
52 |
+
|
53 |
+
def load_student_activities_functions():
|
54 |
+
from .studentact.student_activities_v2 import display_student_progress
|
55 |
+
return {
|
56 |
+
'display_student_progress': display_student_progress
|
57 |
+
}
|
58 |
+
|
59 |
+
def load_morphosyntax_functions():
|
60 |
+
from .morphosyntax.morphosyntax_interface import display_morphosyntax_interface
|
61 |
+
from .morphosyntax.morphosyntax_process import process_morphosyntactic_input
|
62 |
+
return {
|
63 |
+
'display_morphosyntax_interface': display_morphosyntax_interface,
|
64 |
+
'process_morphosyntactic_input': process_morphosyntactic_input
|
65 |
+
}
|
66 |
+
|
67 |
+
def load_semantic_functions():
|
68 |
+
from .semantic.semantic_interface_68ok import display_semantic_interface
|
69 |
+
from .semantic.semantic_process import process_semantic_input
|
70 |
+
return {
|
71 |
+
'display_semantic_interface': display_semantic_interface,
|
72 |
+
'process_semantic_input': process_semantic_input
|
73 |
+
}
|
74 |
+
|
75 |
+
def load_discourse_functions():
|
76 |
+
from .discourse.discourse_interface import display_discourse_interface
|
77 |
+
from .discourse.discourse_process import process_discourse_input
|
78 |
+
return {
|
79 |
+
'display_discourse_interface': display_discourse_interface,
|
80 |
+
'process_discourse_input': process_discourse_input
|
81 |
+
}
|
82 |
+
|
83 |
+
def load_email_functions():
|
84 |
+
from .email.email import send_email_notification
|
85 |
+
return {
|
86 |
+
'send_email_notification': send_email_notification
|
87 |
+
}
|
88 |
+
|
89 |
+
def load_admin_functions():
|
90 |
+
from .admin.admin_ui import admin_page
|
91 |
+
return {
|
92 |
+
'admin_page': admin_page
|
93 |
+
}
|
94 |
+
|
95 |
+
def load_text_analysis_functions():
|
96 |
+
from .text_analysis.morpho_analysis import (
|
97 |
+
generate_arc_diagram,
|
98 |
+
perform_advanced_morphosyntactic_analysis,
|
99 |
+
perform_pos_analysis,
|
100 |
+
perform_morphological_analysis,
|
101 |
+
analyze_sentence_structure,
|
102 |
+
get_repeated_words_colors,
|
103 |
+
highlight_repeated_words,
|
104 |
+
)
|
105 |
+
from .text_analysis.semantic_analysis import (
|
106 |
+
perform_semantic_analysis,
|
107 |
+
generate_summary,
|
108 |
+
extract_entities,
|
109 |
+
analyze_sentiment,
|
110 |
+
create_topic_graph,
|
111 |
+
visualize_topic_graph,
|
112 |
+
ENTITY_LABELS
|
113 |
+
)
|
114 |
+
from .text_analysis.discourse_analysis import (
|
115 |
+
perform_discourse_analysis,
|
116 |
+
compare_semantic_analysis
|
117 |
+
)
|
118 |
+
return {
|
119 |
+
'generate_arc_diagram': generate_arc_diagram,
|
120 |
+
'perform_advanced_morphosyntactic_analysis': perform_advanced_morphosyntactic_analysis,
|
121 |
+
'perform_pos_analysis': perform_pos_analysis,
|
122 |
+
'perform_morphological_analysis': perform_morphological_analysis,
|
123 |
+
'analyze_sentence_structure': analyze_sentence_structure,
|
124 |
+
'get_repeated_words_colors': get_repeated_words_colors,
|
125 |
+
'highlight_repeated_words': highlight_repeated_words,
|
126 |
+
'perform_semantic_analysis': perform_semantic_analysis,
|
127 |
+
'generate_summary': generate_summary,
|
128 |
+
'extract_entities': extract_entities,
|
129 |
+
'analyze_sentiment': analyze_sentiment,
|
130 |
+
'create_topic_graph': create_topic_graph,
|
131 |
+
'visualize_topic_graph': visualize_topic_graph,
|
132 |
+
'ENTITY_LABELS': ENTITY_LABELS,
|
133 |
+
'perform_discourse_analysis': perform_discourse_analysis,
|
134 |
+
'compare_semantic_analysis': compare_semantic_analysis
|
135 |
+
}
|
136 |
+
|
137 |
+
def load_utils_functions():
|
138 |
+
from .utils.spacy_utils import load_spacy_models
|
139 |
+
return {
|
140 |
+
'load_spacy_models': load_spacy_models
|
141 |
+
}
|
142 |
+
|
143 |
+
def load_chatbot_functions():
|
144 |
+
from .chatbot.chatbot import (
|
145 |
+
ClaudeAPIChat,
|
146 |
+
initialize_chatbot,
|
147 |
+
process_chat_input,
|
148 |
+
get_connectors,
|
149 |
+
handle_semantic_commands,
|
150 |
+
generate_topics_visualization,
|
151 |
+
extract_topics,
|
152 |
+
get_semantic_chatbot_response
|
153 |
+
)
|
154 |
+
return {
|
155 |
+
'ClaudeAPIChat': ClaudeAPIChat,
|
156 |
+
'initialize_chatbot': initialize_chatbot,
|
157 |
+
'process_chat_input': process_chat_input,
|
158 |
+
'get_connectors': get_connectors,
|
159 |
+
'handle_semantic_commands': handle_semantic_commands,
|
160 |
+
'generate_topics_visualization': generate_topics_visualization,
|
161 |
+
'extract_topics': extract_topics,
|
162 |
+
'get_semantic_chatbot_response': get_semantic_chatbot_response
|
163 |
+
}
|
164 |
+
|
165 |
+
# Función para cargar todas las funciones
|
166 |
+
def load_all_functions():
|
167 |
+
return {
|
168 |
+
**load_auth_functions(),
|
169 |
+
**load_database_function(),
|
170 |
+
# **load_ui_functions(),
|
171 |
+
**load_admin_functions(),
|
172 |
+
**load_morphosyntax_functions(),
|
173 |
+
**load_semantic_functions(),
|
174 |
+
**load_discourse_functions(),
|
175 |
+
**load_text_analysis_functions(),
|
176 |
+
**load_utils_functions(),
|
177 |
+
**load_chatbot_functions(),
|
178 |
+
**load_email_functions()
|
179 |
+
**load_student_activities_functions() # Añadimos las nuevas funciones de actividades del estudiante
|
180 |
+
}
|
modules/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (4.19 kB). View file
|
|
modules/admin/__init__.py
ADDED
File without changes
|
modules/admin/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (147 Bytes). View file
|
|
modules/admin/__pycache__/admin_ui.cpython-311.pyc
ADDED
Binary file (3.07 kB). View file
|
|
modules/admin/admin_ui.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from ..database.sql_db import (
|
3 |
+
get_user,
|
4 |
+
get_student_user,
|
5 |
+
get_admin_user,
|
6 |
+
get_teacher_user,
|
7 |
+
create_student_user,
|
8 |
+
update_student_user,
|
9 |
+
delete_student_user
|
10 |
+
)
|
11 |
+
|
12 |
+
from ..database.morphosintax_mongo_db import get_student_morphosyntax_analysis
|
13 |
+
|
14 |
+
def admin_page():
|
15 |
+
st.title("Panel de Administración")
|
16 |
+
st.write(f"Bienvenido, {st.session_state.username}")
|
17 |
+
|
18 |
+
# Sección para crear nuevos usuarios estudiantes
|
19 |
+
st.header("Crear Nuevo Usuario Estudiante")
|
20 |
+
new_username = st.text_input("Correo electrónico del nuevo usuario", key="admin_new_username")
|
21 |
+
new_password = st.text_input("Contraseña", type="password", key="admin_new_password")
|
22 |
+
if st.button("Crear Usuario", key="admin_create_user"):
|
23 |
+
if create_student_user(new_username, new_password):
|
24 |
+
st.success(f"Usuario estudiante {new_username} creado exitosamente")
|
25 |
+
else:
|
26 |
+
st.error("Error al crear el usuario estudiante")
|
27 |
+
|
28 |
+
# Sección para ver datos de estudiantes
|
29 |
+
st.header("Ver Datos de Estudiantes")
|
30 |
+
student_username = st.text_input("Nombre de usuario del estudiante", key="admin_view_student")
|
31 |
+
if st.button("Ver Datos", key="admin_view_student_data"):
|
32 |
+
student = get_student_user(student_username)
|
33 |
+
if student:
|
34 |
+
st.write(f"Información del estudiante {student_username}:")
|
35 |
+
st.json(student)
|
36 |
+
|
37 |
+
student_data = get_student_morphosyntax_analysis(student_username)
|
38 |
+
if student_data:
|
39 |
+
st.write("Datos de análisis del estudiante:")
|
40 |
+
st.json(student_data)
|
41 |
+
else:
|
42 |
+
st.info("No hay datos de análisis para este estudiante.")
|
43 |
+
else:
|
44 |
+
st.error("Estudiante no encontrado")
|
45 |
+
|
46 |
+
# Botón para cerrar sesión
|
47 |
+
if st.button("Cerrar Sesión", key="admin_logout"):
|
48 |
+
st.session_state.clear()
|
49 |
+
st.experimental_rerun()
|
modules/admin/txt.txt
ADDED
File without changes
|
modules/auth/__init__.py
ADDED
File without changes
|
modules/auth/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (146 Bytes). View file
|
|
modules/auth/__pycache__/auth.cpython-311.pyc
ADDED
Binary file (6.44 kB). View file
|
|
modules/auth/auth.py
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from azure.cosmos import CosmosClient, exceptions
|
3 |
+
from azure.cosmos.exceptions import CosmosHttpResponseError
|
4 |
+
import bcrypt
|
5 |
+
import base64
|
6 |
+
from ..database.sql_db import (
|
7 |
+
get_user,
|
8 |
+
get_student_user,
|
9 |
+
get_admin_user,
|
10 |
+
get_teacher_user,
|
11 |
+
create_student_user,
|
12 |
+
update_student_user,
|
13 |
+
delete_student_user
|
14 |
+
)
|
15 |
+
|
16 |
+
import logging
|
17 |
+
|
18 |
+
logger = logging.getLogger(__name__)
|
19 |
+
|
20 |
+
# ... (código de inicialización)
|
21 |
+
def clean_and_validate_key(key):
|
22 |
+
key = key.strip()
|
23 |
+
while len(key) % 4 != 0:
|
24 |
+
key += '='
|
25 |
+
try:
|
26 |
+
base64.b64decode(key)
|
27 |
+
return key
|
28 |
+
except:
|
29 |
+
raise ValueError("La clave proporcionada no es válida")
|
30 |
+
|
31 |
+
# Verificar las variables de entorno
|
32 |
+
endpoint = os.getenv("COSMOS_ENDPOINT")
|
33 |
+
key = os.getenv("COSMOS_KEY")
|
34 |
+
|
35 |
+
if not endpoint or not key:
|
36 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
37 |
+
|
38 |
+
key = clean_and_validate_key(key)
|
39 |
+
####################################################
|
40 |
+
|
41 |
+
|
42 |
+
def authenticate_user(username, password):
|
43 |
+
try:
|
44 |
+
user_item = get_user(username)
|
45 |
+
if user_item and verify_password(user_item['password'], password):
|
46 |
+
logger.info(f"Usuario autenticado: {username}, Rol: {user_item['role']}")
|
47 |
+
return True, user_item['role']
|
48 |
+
logger.warning(f"Autenticación fallida para el usuario: {username}")
|
49 |
+
return False, None
|
50 |
+
except Exception as e:
|
51 |
+
logger.error(f"Error durante la autenticación del usuario: {str(e)}")
|
52 |
+
return False, None
|
53 |
+
|
54 |
+
def authenticate_admin(username, password):
|
55 |
+
return authenticate_user(username, password)
|
56 |
+
|
57 |
+
def authenticate_student(username, password):
|
58 |
+
return authenticate_user(username, password)
|
59 |
+
|
60 |
+
def authenticate_teacher(username, password):
|
61 |
+
return authenticate_user(username, password)
|
62 |
+
|
63 |
+
############################
|
64 |
+
def register_student(username, password, additional_info=None):
|
65 |
+
try:
|
66 |
+
if get_student_user(username):
|
67 |
+
logger.warning(f"Intento de registro de estudiante existente: {username}")
|
68 |
+
return False # El estudiante ya existe
|
69 |
+
|
70 |
+
success = create_student_user(username, password, additional_info)
|
71 |
+
if success:
|
72 |
+
logger.info(f"Nuevo estudiante registrado: {username}")
|
73 |
+
return True
|
74 |
+
else:
|
75 |
+
logger.error(f"Error al registrar nuevo estudiante: {username}")
|
76 |
+
return False
|
77 |
+
except Exception as e:
|
78 |
+
logger.error(f"Error al registrar estudiante: {str(e)}")
|
79 |
+
return False
|
80 |
+
|
81 |
+
def update_student_info(username, new_info):
|
82 |
+
try:
|
83 |
+
success = update_student_user(username, new_info)
|
84 |
+
if success:
|
85 |
+
logger.info(f"Información del estudiante actualizada: {username}")
|
86 |
+
return True
|
87 |
+
else:
|
88 |
+
logger.error(f"Error al actualizar información del estudiante: {username}")
|
89 |
+
return False
|
90 |
+
except Exception as e:
|
91 |
+
logger.error(f"Error al actualizar información del estudiante: {str(e)}")
|
92 |
+
return False
|
93 |
+
|
94 |
+
def delete_student(username):
|
95 |
+
try:
|
96 |
+
success = delete_student_user(username)
|
97 |
+
if success:
|
98 |
+
logger.info(f"Estudiante eliminado: {username}")
|
99 |
+
return True
|
100 |
+
else:
|
101 |
+
logger.error(f"Error al eliminar estudiante: {username}")
|
102 |
+
return False
|
103 |
+
except Exception as e:
|
104 |
+
logger.error(f"Error al eliminar estudiante: {str(e)}")
|
105 |
+
return False
|
106 |
+
|
107 |
+
|
108 |
+
# ... (funciones de hash y verificación de contraseña)
|
109 |
+
|
110 |
+
def hash_password(password):
|
111 |
+
"""Hash a password for storing."""
|
112 |
+
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
113 |
+
|
114 |
+
##################################################################################33
|
115 |
+
|
116 |
+
def verify_password(stored_password, provided_password):
|
117 |
+
"""Verify a stored password against one provided by user"""
|
118 |
+
return bcrypt.checkpw(provided_password.encode('utf-8'), stored_password.encode('utf-8'))
|
119 |
+
######################################################################################################
|
modules/auth/txt.txt
ADDED
File without changes
|
modules/chatbot/__init__.py
ADDED
File without changes
|
modules/chatbot/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (149 Bytes). View file
|
|
modules/chatbot/__pycache__/chatbot.cpython-311.pyc
ADDED
Binary file (3.3 kB). View file
|
|
modules/chatbot/chatbot.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from ..text_analysis.morpho_analysis import perform_advanced_morphosyntactic_analysis
|
3 |
+
from ..text_analysis.semantic_analysis import perform_semantic_analysis
|
4 |
+
from ..text_analysis.discourse_analysis import perform_discourse_analysis
|
5 |
+
|
6 |
+
class AIdeaTextChatbot:
|
7 |
+
def __init__(self):
|
8 |
+
self.conversation_history = []
|
9 |
+
|
10 |
+
def handle_morphosyntactic_input(self, user_input, lang_code, nlp_models, t):
|
11 |
+
if user_input.startswith('/analisis_morfosintactico'):
|
12 |
+
text_to_analyze = user_input.split('[', 1)[1].rsplit(']', 1)[0]
|
13 |
+
result = perform_advanced_morphosyntactic_analysis(text_to_analyze, nlp_models[lang_code])
|
14 |
+
if result is None or 'arc_diagrams' not in result:
|
15 |
+
return t.get('morphosyntactic_analysis_error', 'Error en el análisis morfosintáctico'), None, None
|
16 |
+
return t.get('morphosyntactic_analysis_completed', 'Análisis morfosintáctico completado'), result['arc_diagrams'], result
|
17 |
+
else:
|
18 |
+
# Aquí puedes manejar otras interacciones relacionadas con el análisis morfosintáctico
|
19 |
+
return self.generate_response(user_input, lang_code), None, None
|
20 |
+
|
21 |
+
|
22 |
+
def handle_semantic_input(self, user_input, lang_code, nlp_models, t):
|
23 |
+
# Implementar lógica para análisis semántico
|
24 |
+
pass
|
25 |
+
|
26 |
+
def handle_discourse_input(self, user_input, lang_code, nlp_models, t):
|
27 |
+
# Implementar lógica para análisis de discurso
|
28 |
+
pass
|
29 |
+
|
30 |
+
def handle_generate_response(self, prompt, lang_code):
|
31 |
+
# Aquí iría la lógica para generar respuestas generales del chatbot
|
32 |
+
# Puedes usar la API de Claude aquí si lo deseas
|
33 |
+
pass
|
34 |
+
|
35 |
+
def initialize_chatbot():
|
36 |
+
return AIdeaTextChatbot()
|
37 |
+
|
38 |
+
def process_chat_input(user_input, lang_code, nlp_models, analysis_type, t, file_contents=None):
|
39 |
+
chatbot = st.session_state.get('aideatext_chatbot')
|
40 |
+
if not chatbot:
|
41 |
+
chatbot = initialize_chatbot()
|
42 |
+
st.session_state.aideatext_chatbot = chatbot
|
43 |
+
|
44 |
+
if analysis_type == 'morphosyntactic':
|
45 |
+
return chatbot.handle_morphosyntactic_input(user_input, lang_code, nlp_models, t)
|
46 |
+
# ... manejar otros tipos de análisis ...
|
modules/chatbot/chatbot_open_Source_Model-test.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from transformers import GPT2LMHeadModel, GPT2Tokenizer
|
2 |
+
import torch
|
3 |
+
from torch.optim import Adam
|
4 |
+
from torch.utils.data import DataLoader, Dataset
|
5 |
+
import json
|
6 |
+
import tqdm
|
7 |
+
|
8 |
+
tokenizer = GPT2Tokenizer.from_pretrained("openai-community/gpt2")
|
9 |
+
model = GPT2LMHeadModel.from_pretrained("openai-community/gpt2")
|
10 |
+
|
11 |
+
class MultilingualChatData(Dataset):
|
12 |
+
def __init__(self, file_path, tokenizer, max_length=512):
|
13 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
14 |
+
self.data = json.load(f)
|
15 |
+
self.tokenizer = tokenizer
|
16 |
+
self.max_length = max_length
|
17 |
+
|
18 |
+
def __len__(self):
|
19 |
+
return len(self.data)
|
20 |
+
|
21 |
+
def __getitem__(self, idx):
|
22 |
+
item = self.data[idx]
|
23 |
+
input_text = f"<startofstring> {item['input']} <bot>: {item['output']} <endofstring>"
|
24 |
+
encoding = self.tokenizer(input_text, truncation=True, padding='max_length', max_length=self.max_length, return_tensors="pt")
|
25 |
+
return encoding['input_ids'].squeeze(), encoding['attention_mask'].squeeze()
|
26 |
+
|
27 |
+
class MultilingualChatbot:
|
28 |
+
def __init__(self):
|
29 |
+
self.models = {
|
30 |
+
'en': GPT2LMHeadModel.from_pretrained("microsoft/DialoGPT-medium"),
|
31 |
+
'es': GPT2LMHeadModel.from_pretrained("DeepESP/gpt2-spanish"),
|
32 |
+
'fr': GPT2LMHeadModel.from_pretrained("asi/gpt-fr-cased-small")
|
33 |
+
}
|
34 |
+
self.tokenizers = {
|
35 |
+
'en': GPT2Tokenizer.from_pretrained("microsoft/DialoGPT-medium"),
|
36 |
+
'es': GPT2Tokenizer.from_pretrained("DeepESP/gpt2-spanish"),
|
37 |
+
'fr': GPT2Tokenizer.from_pretrained("asi/gpt-fr-cased-small")
|
38 |
+
}
|
39 |
+
for tokenizer in self.tokenizers.values():
|
40 |
+
tokenizer.pad_token = tokenizer.eos_token
|
41 |
+
tokenizer.add_special_tokens({
|
42 |
+
"bos_token": "<startofstring>",
|
43 |
+
"eos_token": "<endofstring>"
|
44 |
+
})
|
45 |
+
tokenizer.add_tokens(["<bot>:"])
|
46 |
+
|
47 |
+
for model in self.models.values():
|
48 |
+
model.resize_token_embeddings(len(self.tokenizers['en'])) # Assuming all tokenizers have the same vocabulary size
|
49 |
+
|
50 |
+
self.device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
|
51 |
+
for model in self.models.values():
|
52 |
+
model.to(self.device)
|
53 |
+
|
54 |
+
def train(self, lang, data_file, epochs=5, batch_size=32, learning_rate=1e-4):
|
55 |
+
model = self.models[lang]
|
56 |
+
tokenizer = self.tokenizers[lang]
|
57 |
+
|
58 |
+
chat_data = MultilingualChatData(data_file, tokenizer)
|
59 |
+
data_loader = DataLoader(chat_data, batch_size=batch_size, shuffle=True)
|
60 |
+
|
61 |
+
optimizer = Adam(model.parameters(), lr=learning_rate)
|
62 |
+
|
63 |
+
model.train()
|
64 |
+
for epoch in range(epochs):
|
65 |
+
total_loss = 0
|
66 |
+
for batch in tqdm.tqdm(data_loader, desc=f"Epoch {epoch+1}/{epochs}"):
|
67 |
+
input_ids, attention_mask = [b.to(self.device) for b in batch]
|
68 |
+
|
69 |
+
optimizer.zero_grad()
|
70 |
+
outputs = model(input_ids, attention_mask=attention_mask, labels=input_ids)
|
71 |
+
loss = outputs.loss
|
72 |
+
loss.backward()
|
73 |
+
optimizer.step()
|
74 |
+
|
75 |
+
total_loss += loss.item()
|
76 |
+
|
77 |
+
print(f"Epoch {epoch+1}/{epochs}, Loss: {total_loss/len(data_loader):.4f}")
|
78 |
+
|
79 |
+
torch.save(model.state_dict(), f"model_state_{lang}.pt")
|
80 |
+
|
81 |
+
def generate_response(self, prompt, src_lang):
|
82 |
+
model = self.models.get(src_lang, self.models['en'])
|
83 |
+
tokenizer = self.tokenizers.get(src_lang, self.tokenizers['en'])
|
84 |
+
|
85 |
+
input_text = f"<startofstring> {prompt} <bot>: "
|
86 |
+
input_ids = tokenizer.encode(input_text, return_tensors='pt').to(self.device)
|
87 |
+
|
88 |
+
attention_mask = torch.ones(input_ids.shape, dtype=torch.long, device=self.device)
|
89 |
+
|
90 |
+
output = model.generate(
|
91 |
+
input_ids,
|
92 |
+
attention_mask=attention_mask,
|
93 |
+
max_length=1000,
|
94 |
+
pad_token_id=tokenizer.eos_token_id,
|
95 |
+
no_repeat_ngram_size=3,
|
96 |
+
do_sample=True,
|
97 |
+
top_k=50,
|
98 |
+
top_p=0.95,
|
99 |
+
temperature=0.7,
|
100 |
+
num_return_sequences=1,
|
101 |
+
length_penalty=1.0,
|
102 |
+
repetition_penalty=1.2
|
103 |
+
)
|
104 |
+
|
105 |
+
decoded_output = tokenizer.decode(output[0], skip_special_tokens=True)
|
106 |
+
return decoded_output.split("<bot>:")[-1].strip()
|
107 |
+
|
108 |
+
def initialize_chatbot():
|
109 |
+
return MultilingualChatbot()
|
110 |
+
|
111 |
+
def get_chatbot_response(chatbot, prompt, src_lang):
|
112 |
+
return chatbot.generate_response(prompt, src_lang)
|
113 |
+
|
114 |
+
# Ejemplo de uso
|
115 |
+
if __name__ == "__main__":
|
116 |
+
chatbot = initialize_chatbot()
|
117 |
+
|
118 |
+
# Entrenar el modelo en español (asumiendo que tienes un archivo de datos en español)
|
119 |
+
chatbot.train('es', './spanish_chat_data.json', epochs=3)
|
120 |
+
|
121 |
+
# Generar respuestas
|
122 |
+
print(get_chatbot_response(chatbot, "Hola, ¿cómo estás?", 'es'))
|
123 |
+
print(get_chatbot_response(chatbot, "Hello, how are you?", 'en'))
|
124 |
+
print(get_chatbot_response(chatbot, "Bonjour, comment allez-vous?", 'fr'))
|
modules/chatbot/txt.txt
ADDED
File without changes
|
modules/database/__init__.py
ADDED
File without changes
|
modules/database/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (150 Bytes). View file
|
|
modules/database/__pycache__/chat_db.cpython-311.pyc
ADDED
Binary file (1.78 kB). View file
|
|
modules/database/__pycache__/database.cpython-311.pyc
ADDED
Binary file (25.1 kB). View file
|
|
modules/database/__pycache__/database_init.cpython-311.pyc
ADDED
Binary file (4.18 kB). View file
|
|
modules/database/__pycache__/database_oldFromV2.cpython-311.pyc
ADDED
Binary file (25.2 kB). View file
|
|
modules/database/__pycache__/mongo_db.cpython-311.pyc
ADDED
Binary file (3.7 kB). View file
|
|
modules/database/__pycache__/morphosintax_db.cpython-311.pyc
ADDED
Binary file (1.79 kB). View file
|
|
modules/database/__pycache__/morphosintax_mongo_db.cpython-311.pyc
ADDED
Binary file (2.72 kB). View file
|
|
modules/database/__pycache__/morphosintaxis_export.cpython-311.pyc
ADDED
Binary file (4.2 kB). View file
|
|
modules/database/__pycache__/sql_db.cpython-311.pyc
ADDED
Binary file (8.24 kB). View file
|
|
modules/database/backUp/database.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# database.py
|
2 |
+
# Versión 3 actualizada para manejar chat_history_v3
|
3 |
+
|
4 |
+
import streamlit as st
|
5 |
+
import logging
|
6 |
+
import os
|
7 |
+
from pymongo import MongoClient
|
8 |
+
import certifi
|
9 |
+
from datetime import datetime, timezone
|
10 |
+
import uuid
|
11 |
+
|
12 |
+
logging.basicConfig(level=logging.DEBUG)
|
13 |
+
logger = logging.getLogger(__name__)
|
14 |
+
|
15 |
+
# Variables globales para Cosmos DB MongoDB API
|
16 |
+
mongo_client = None
|
17 |
+
mongo_db = None
|
18 |
+
analysis_collection = None
|
19 |
+
chat_collection_v3 = None # Nueva variable global para chat_history_v3
|
20 |
+
|
21 |
+
def initialize_mongodb_connection():
|
22 |
+
global mongo_client, mongo_db, analysis_collection, chat_collection_v3
|
23 |
+
try:
|
24 |
+
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
|
25 |
+
if not cosmos_mongodb_connection_string:
|
26 |
+
logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada")
|
27 |
+
return False
|
28 |
+
|
29 |
+
mongo_client = MongoClient(cosmos_mongodb_connection_string,
|
30 |
+
tls=True,
|
31 |
+
tlsCAFile=certifi.where(),
|
32 |
+
retryWrites=False,
|
33 |
+
serverSelectionTimeoutMS=5000,
|
34 |
+
connectTimeoutMS=10000,
|
35 |
+
socketTimeoutMS=10000)
|
36 |
+
|
37 |
+
mongo_client.admin.command('ping')
|
38 |
+
|
39 |
+
mongo_db = mongo_client['aideatext_db']
|
40 |
+
analysis_collection = mongo_db['text_analysis']
|
41 |
+
chat_collection_v3 = mongo_db['chat_history_v3'] # Inicializar la nueva colección
|
42 |
+
|
43 |
+
# Crear índices para chat_history_v3
|
44 |
+
chat_collection_v3.create_index([("username", 1), ("timestamp", -1)])
|
45 |
+
chat_collection_v3.create_index([("username", 1), ("analysis_type", 1), ("timestamp", -1)])
|
46 |
+
|
47 |
+
logger.info("Conexión a Cosmos DB MongoDB API exitosa")
|
48 |
+
return True
|
49 |
+
except Exception as e:
|
50 |
+
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
|
51 |
+
return False
|
52 |
+
|
53 |
+
def store_chat_history_v3(username, messages, analysis_type):
|
54 |
+
try:
|
55 |
+
logger.info(f"Guardando historial de chat para el usuario: {username}, tipo de análisis: {analysis_type}")
|
56 |
+
logger.debug(f"Mensajes a guardar: {messages}")
|
57 |
+
|
58 |
+
chat_document = {
|
59 |
+
'username': username,
|
60 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
61 |
+
'analysis_type': analysis_type,
|
62 |
+
'messages': messages
|
63 |
+
}
|
64 |
+
result = chat_collection_v3.insert_one(chat_document)
|
65 |
+
logger.info(f"Historial de chat guardado con ID: {result.inserted_id} para el usuario: {username}")
|
66 |
+
return True
|
67 |
+
except Exception as e:
|
68 |
+
logger.error(f"Error al guardar el historial de chat para el usuario {username}: {str(e)}")
|
69 |
+
return False
|
70 |
+
|
71 |
+
def get_chat_history_v3(username, analysis_type=None, limit=10):
|
72 |
+
try:
|
73 |
+
logger.info(f"Obteniendo historial de chat para el usuario: {username}, tipo de análisis: {analysis_type}")
|
74 |
+
|
75 |
+
query = {"username": username}
|
76 |
+
if analysis_type:
|
77 |
+
query["analysis_type"] = analysis_type
|
78 |
+
|
79 |
+
cursor = chat_collection_v3.find(query).sort("timestamp", -1).limit(limit)
|
80 |
+
|
81 |
+
chat_history = []
|
82 |
+
for chat in cursor:
|
83 |
+
chat_history.append({
|
84 |
+
"timestamp": chat["timestamp"],
|
85 |
+
"analysis_type": chat["analysis_type"],
|
86 |
+
"messages": chat["messages"]
|
87 |
+
})
|
88 |
+
|
89 |
+
logger.info(f"Se obtuvieron {len(chat_history)} entradas de chat para el usuario: {username}")
|
90 |
+
return chat_history
|
91 |
+
except Exception as e:
|
92 |
+
logger.error(f"Error al obtener el historial de chat para el usuario {username}: {str(e)}")
|
93 |
+
return []
|
94 |
+
|
95 |
+
def delete_chat_history_v3(username, analysis_type=None):
|
96 |
+
try:
|
97 |
+
logger.info(f"Eliminando historial de chat para el usuario: {username}, tipo de análisis: {analysis_type}")
|
98 |
+
|
99 |
+
query = {"username": username}
|
100 |
+
if analysis_type:
|
101 |
+
query["analysis_type"] = analysis_type
|
102 |
+
|
103 |
+
result = chat_collection_v3.delete_many(query)
|
104 |
+
|
105 |
+
logger.info(f"Se eliminaron {result.deleted_count} entradas de chat para el usuario: {username}")
|
106 |
+
return True
|
107 |
+
except Exception as e:
|
108 |
+
logger.error(f"Error al eliminar el historial de chat para el usuario {username}: {str(e)}")
|
109 |
+
return False
|
110 |
+
|
111 |
+
def export_chat_history_v3(username, analysis_type=None):
|
112 |
+
try:
|
113 |
+
logger.info(f"Exportando historial de chat para el usuario: {username}, tipo de análisis: {analysis_type}")
|
114 |
+
|
115 |
+
query = {"username": username}
|
116 |
+
if analysis_type:
|
117 |
+
query["analysis_type"] = analysis_type
|
118 |
+
|
119 |
+
cursor = chat_collection_v3.find(query).sort("timestamp", -1)
|
120 |
+
|
121 |
+
export_data = list(cursor)
|
122 |
+
|
123 |
+
logger.info(f"Se exportaron {len(export_data)} entradas de chat para el usuario: {username}")
|
124 |
+
return export_data
|
125 |
+
except Exception as e:
|
126 |
+
logger.error(f"Error al exportar el historial de chat para el usuario {username}: {str(e)}")
|
127 |
+
return []
|
128 |
+
|
129 |
+
# Funciones específicas para cada tipo de análisis
|
130 |
+
|
131 |
+
def store_morphosyntax_result(username, text, repeated_words, arc_diagrams, pos_analysis, morphological_analysis, sentence_structure):
|
132 |
+
if analysis_collection is None:
|
133 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
134 |
+
return False
|
135 |
+
|
136 |
+
try:
|
137 |
+
word_count = {}
|
138 |
+
for word, color in repeated_words.items():
|
139 |
+
category = color # Asumiendo que 'color' es la categoría gramatical
|
140 |
+
word_count[category] = word_count.get(category, 0) + 1
|
141 |
+
|
142 |
+
analysis_document = {
|
143 |
+
'username': username,
|
144 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
145 |
+
'text': text,
|
146 |
+
'repeated_words': repeated_words,
|
147 |
+
'word_count': word_count,
|
148 |
+
'arc_diagrams': arc_diagrams,
|
149 |
+
'pos_analysis': pos_analysis,
|
150 |
+
'morphological_analysis': morphological_analysis,
|
151 |
+
'sentence_structure': sentence_structure,
|
152 |
+
'analysis_type': 'morphosyntax'
|
153 |
+
}
|
154 |
+
|
155 |
+
result = analysis_collection.insert_one(analysis_document)
|
156 |
+
logger.info(f"Análisis morfosintáctico guardado con ID: {result.inserted_id} para el usuario: {username}")
|
157 |
+
return True
|
158 |
+
except Exception as e:
|
159 |
+
logger.error(f"Error al guardar el análisis morfosintáctico para el usuario {username}: {str(e)}")
|
160 |
+
return False
|
161 |
+
|
162 |
+
# Aquí puedes agregar funciones similares para análisis semántico y de discurso
|
163 |
+
|
164 |
+
def get_student_data(username):
|
165 |
+
if analysis_collection is None or chat_collection_v3 is None:
|
166 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
167 |
+
return None
|
168 |
+
|
169 |
+
formatted_data = {
|
170 |
+
"username": username,
|
171 |
+
"entries": [],
|
172 |
+
"entries_count": 0,
|
173 |
+
"word_count": {},
|
174 |
+
"chat_history": {
|
175 |
+
"morphosyntax": [],
|
176 |
+
"semantic": [],
|
177 |
+
"discourse": []
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
try:
|
182 |
+
logger.info(f"Buscando datos de análisis para el usuario: {username}")
|
183 |
+
cursor = analysis_collection.find({"username": username})
|
184 |
+
|
185 |
+
for entry in cursor:
|
186 |
+
formatted_entry = {
|
187 |
+
'timestamp': entry.get("timestamp"),
|
188 |
+
"analysis_type": entry.get("analysis_type", "morphosyntax")
|
189 |
+
}
|
190 |
+
|
191 |
+
if formatted_entry["analysis_type"] == "morphosyntax":
|
192 |
+
formatted_entry.update({
|
193 |
+
"text": entry.get("text", ""),
|
194 |
+
"word_count": entry.get("word_count", {}),
|
195 |
+
"arc_diagrams": entry.get("arc_diagrams", [])
|
196 |
+
})
|
197 |
+
for category, count in formatted_entry["word_count"].items():
|
198 |
+
formatted_data["word_count"][category] = formatted_data["word_count"].get(category, 0) + count
|
199 |
+
|
200 |
+
formatted_data["entries"].append(formatted_entry)
|
201 |
+
|
202 |
+
formatted_data["entries_count"] = len(formatted_data["entries"])
|
203 |
+
formatted_data["entries"].sort(key=lambda x: x["timestamp"], reverse=True)
|
204 |
+
|
205 |
+
# Obtener historial de chat para cada tipo de análisis
|
206 |
+
for analysis_type in ["morphosyntax", "semantic", "discourse"]:
|
207 |
+
chat_history = get_chat_history_v3(username, analysis_type)
|
208 |
+
formatted_data["chat_history"][analysis_type] = chat_history
|
209 |
+
|
210 |
+
except Exception as e:
|
211 |
+
logger.error(f"Error al obtener datos del estudiante {username}: {str(e)}")
|
212 |
+
|
213 |
+
logger.info(f"Datos formateados para {username}: {formatted_data}")
|
214 |
+
return formatted_data
|
215 |
+
|
216 |
+
# Puedes agregar más funciones según sea necesario para manejar otros tipos de datos o análisis
|
modules/database/backUp/databaseBackUp23-9-24.py
ADDED
@@ -0,0 +1,581 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# database.py
|
2 |
+
import logging
|
3 |
+
import os
|
4 |
+
from azure.cosmos import CosmosClient
|
5 |
+
from azure.cosmos.exceptions import CosmosHttpResponseError
|
6 |
+
from pymongo import MongoClient
|
7 |
+
import certifi
|
8 |
+
from datetime import datetime
|
9 |
+
import io
|
10 |
+
from io import BytesIO
|
11 |
+
import base64
|
12 |
+
import matplotlib.pyplot as plt
|
13 |
+
from matplotlib.figure import Figure
|
14 |
+
import bcrypt
|
15 |
+
print(f"Bcrypt version: {bcrypt.__version__}")
|
16 |
+
import uuid
|
17 |
+
import plotly.graph_objects as go # Para manejar el diagrama de Sankey
|
18 |
+
import numpy as np # Puede ser necesario para algunas operaciones
|
19 |
+
logging.basicConfig(level=logging.DEBUG)
|
20 |
+
logger = logging.getLogger(__name__)
|
21 |
+
|
22 |
+
# Variables globales para Cosmos DB SQL API
|
23 |
+
application_requests_container = None
|
24 |
+
cosmos_client = None
|
25 |
+
user_database = None
|
26 |
+
user_container = None
|
27 |
+
user_feedback_container = None
|
28 |
+
|
29 |
+
# Variables globales para Cosmos DB MongoDB API
|
30 |
+
mongo_client = None
|
31 |
+
mongo_db = None
|
32 |
+
analysis_collection = None
|
33 |
+
chat_collection = None # Nueva variable global
|
34 |
+
|
35 |
+
|
36 |
+
##############################################################################--- INICIO DE LAS BASES DE DATOS --- ###############################
|
37 |
+
def initialize_database_connections():
|
38 |
+
try:
|
39 |
+
print("Iniciando conexión a MongoDB")
|
40 |
+
mongodb_success = initialize_mongodb_connection()
|
41 |
+
print(f"Conexión a MongoDB: {'exitosa' if mongodb_success else 'fallida'}")
|
42 |
+
except Exception as e:
|
43 |
+
print(f"Error al conectar con MongoDB: {str(e)}")
|
44 |
+
mongodb_success = False
|
45 |
+
|
46 |
+
try:
|
47 |
+
print("Iniciando conexión a Cosmos DB SQL API")
|
48 |
+
sql_success = initialize_cosmos_sql_connection()
|
49 |
+
print(f"Conexión a Cosmos DB SQL API: {'exitosa' if sql_success else 'fallida'}")
|
50 |
+
except Exception as e:
|
51 |
+
print(f"Error al conectar con Cosmos DB SQL API: {str(e)}")
|
52 |
+
sql_success = False
|
53 |
+
|
54 |
+
return {
|
55 |
+
"mongodb": mongodb_success,
|
56 |
+
"cosmos_sql": sql_success
|
57 |
+
}
|
58 |
+
|
59 |
+
#####################################################################################33
|
60 |
+
def initialize_cosmos_sql_connection():
|
61 |
+
global cosmos_client, user_database, user_container, application_requests_container, user_feedback_container
|
62 |
+
logger.info("Initializing Cosmos DB SQL API connection")
|
63 |
+
try:
|
64 |
+
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
|
65 |
+
cosmos_key = os.environ.get("COSMOS_KEY")
|
66 |
+
logger.info(f"Cosmos Endpoint: {cosmos_endpoint}")
|
67 |
+
logger.info(f"Cosmos Key: {'*' * len(cosmos_key) if cosmos_key else 'Not set'}")
|
68 |
+
|
69 |
+
if not cosmos_endpoint or not cosmos_key:
|
70 |
+
logger.error("COSMOS_ENDPOINT or COSMOS_KEY environment variables are not set")
|
71 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
72 |
+
|
73 |
+
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
|
74 |
+
user_database = cosmos_client.get_database_client("user_database")
|
75 |
+
user_container = user_database.get_container_client("users")
|
76 |
+
application_requests_container = user_database.get_container_client("application_requests")
|
77 |
+
user_feedback_container = user_database.get_container_client("user_feedback")
|
78 |
+
|
79 |
+
logger.info(f"user_container initialized: {user_container is not None}")
|
80 |
+
logger.info(f"application_requests_container initialized: {application_requests_container is not None}")
|
81 |
+
logger.info(f"user_feedback_container initialized: {user_feedback_container is not None}")
|
82 |
+
|
83 |
+
logger.info("Conexión a Cosmos DB SQL API exitosa")
|
84 |
+
return True
|
85 |
+
except Exception as e:
|
86 |
+
logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}", exc_info=True)
|
87 |
+
return False
|
88 |
+
|
89 |
+
############################################################################################3
|
90 |
+
def initialize_mongodb_connection():
|
91 |
+
global mongo_client, mongo_db, analysis_collection, chat_collection
|
92 |
+
try:
|
93 |
+
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
|
94 |
+
if not cosmos_mongodb_connection_string:
|
95 |
+
logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada")
|
96 |
+
return False
|
97 |
+
|
98 |
+
mongo_client = MongoClient(cosmos_mongodb_connection_string,
|
99 |
+
tls=True,
|
100 |
+
tlsCAFile=certifi.where(),
|
101 |
+
retryWrites=False,
|
102 |
+
serverSelectionTimeoutMS=5000,
|
103 |
+
connectTimeoutMS=10000,
|
104 |
+
socketTimeoutMS=10000)
|
105 |
+
|
106 |
+
mongo_client.admin.command('ping')
|
107 |
+
|
108 |
+
mongo_db = mongo_client['aideatext_db']
|
109 |
+
analysis_collection = mongo_db['text_analysis']
|
110 |
+
chat_collection = mongo_db['chat_history'] # Inicializar la nueva colección
|
111 |
+
|
112 |
+
# Verificar la conexión
|
113 |
+
mongo_client.admin.command('ping')
|
114 |
+
|
115 |
+
logger.info("Conexión a Cosmos DB MongoDB API exitosa")
|
116 |
+
return True
|
117 |
+
except Exception as e:
|
118 |
+
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
|
119 |
+
return False
|
120 |
+
|
121 |
+
##############################################################################--- FIN DEL INICIO DE LAS BASES DE DATOS --- ################################################################################################################################
|
122 |
+
########################################################## -- INICIO DE GESTION DE USUARIOS ---##########################################################
|
123 |
+
def create_user(username, password, role):
|
124 |
+
global user_container
|
125 |
+
try:
|
126 |
+
print(f"Attempting to create user: {username} with role: {role}")
|
127 |
+
if user_container is None:
|
128 |
+
print("Error: user_container is None. Attempting to reinitialize connection.")
|
129 |
+
if not initialize_cosmos_sql_connection():
|
130 |
+
raise Exception("Failed to initialize SQL connection")
|
131 |
+
|
132 |
+
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
133 |
+
print(f"Password hashed successfully for user: {username}")
|
134 |
+
user_data = {
|
135 |
+
'id': username,
|
136 |
+
'password': hashed_password,
|
137 |
+
'role': role,
|
138 |
+
'created_at': datetime.utcnow().isoformat()
|
139 |
+
}
|
140 |
+
user_container.create_item(body=user_data)
|
141 |
+
print(f"Usuario {role} creado: {username}") # Log para depuración
|
142 |
+
return True
|
143 |
+
except Exception as e:
|
144 |
+
print(f"Detailed error in create_user: {str(e)}")
|
145 |
+
return False
|
146 |
+
|
147 |
+
#######################################################################################################
|
148 |
+
def create_admin_user(username, password):
|
149 |
+
return create_user(username, password, 'Administrador')
|
150 |
+
|
151 |
+
#######################################################################################################
|
152 |
+
def create_student_user(username, password):
|
153 |
+
return create_user(username, password, 'Estudiante')
|
154 |
+
|
155 |
+
#######################################################################################################
|
156 |
+
# Funciones para Cosmos DB SQL API (manejo de usuarios)
|
157 |
+
def get_user(username):
|
158 |
+
try:
|
159 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
160 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
161 |
+
user = items[0] if items else None
|
162 |
+
if user:
|
163 |
+
print(f"Usuario encontrado: {username}, Rol: {user.get('role')}") # Log añadido
|
164 |
+
else:
|
165 |
+
print(f"Usuario no encontrado: {username}") # Log añadido
|
166 |
+
return user
|
167 |
+
except Exception as e:
|
168 |
+
print(f"Error al obtener usuario {username}: {str(e)}")
|
169 |
+
return None
|
170 |
+
|
171 |
+
########################################################## -- FIN DE GESTION DE USUARIOS ---##########################################################
|
172 |
+
|
173 |
+
########################################################## -- INICIO GESTION DE ARCHIVOS ---##########################################################
|
174 |
+
|
175 |
+
def store_file_contents(username, file_name, file_contents, analysis_type):
|
176 |
+
if user_container is None:
|
177 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
178 |
+
return False
|
179 |
+
try:
|
180 |
+
document = {
|
181 |
+
'id': f"{username}_{analysis_type}_{file_name}",
|
182 |
+
'username': username,
|
183 |
+
'file_name': file_name,
|
184 |
+
'analysis_type': analysis_type,
|
185 |
+
'file_contents': file_contents,
|
186 |
+
'timestamp': datetime.utcnow().isoformat()
|
187 |
+
}
|
188 |
+
user_container.upsert_item(body=document)
|
189 |
+
logger.info(f"Contenido del archivo guardado para el usuario: {username}, tipo de análisis: {analysis_type}")
|
190 |
+
return True
|
191 |
+
except Exception as e:
|
192 |
+
logger.error(f"Error al guardar el contenido del archivo para el usuario {username}: {str(e)}")
|
193 |
+
return False
|
194 |
+
|
195 |
+
def retrieve_file_contents(username, file_name, analysis_type):
|
196 |
+
print(f"Attempting to retrieve file: {file_name} for user: {username}")
|
197 |
+
if user_container is None:
|
198 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
199 |
+
return None
|
200 |
+
try:
|
201 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}_{analysis_type}_{file_name}'"
|
202 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
203 |
+
if items:
|
204 |
+
return items[0]['file_contents']
|
205 |
+
else:
|
206 |
+
logger.info(f"No se encontró contenido de archivo para el usuario: {username}, tipo de análisis: {analysis_type}")
|
207 |
+
return None
|
208 |
+
except Exception as e:
|
209 |
+
logger.error(f"Error al recuperar el contenido del archivo para el usuario {username}: {str(e)}")
|
210 |
+
return None
|
211 |
+
|
212 |
+
def get_user_files(username, analysis_type=None):
|
213 |
+
if user_container is None:
|
214 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
215 |
+
return []
|
216 |
+
try:
|
217 |
+
if analysis_type:
|
218 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}' AND c.analysis_type = '{analysis_type}'"
|
219 |
+
else:
|
220 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}'"
|
221 |
+
|
222 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
223 |
+
return items
|
224 |
+
except Exception as e:
|
225 |
+
logger.error(f"Error al obtener la lista de archivos del usuario {username}: {str(e)}")
|
226 |
+
return []
|
227 |
+
|
228 |
+
def delete_file(username, file_name, analysis_type):
|
229 |
+
if user_container is None:
|
230 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
231 |
+
return False
|
232 |
+
try:
|
233 |
+
user_container.delete_item(item=f"{username}_{analysis_type}_{file_name}", partition_key=username)
|
234 |
+
logger.info(f"Archivo eliminado para el usuario: {username}, tipo de análisis: {analysis_type}")
|
235 |
+
return True
|
236 |
+
except Exception as e:
|
237 |
+
logger.error(f"Error al eliminar el archivo para el usuario {username}: {str(e)}")
|
238 |
+
return False
|
239 |
+
|
240 |
+
########################################################## -- FIN GESTION DE ARCHIVOS ---##########################################################
|
241 |
+
|
242 |
+
########################################################## -- INICIO GESTION DE FORMULARIOS ---##########################################################
|
243 |
+
def store_application_request(name, email, institution, role, reason):
|
244 |
+
global application_requests_container
|
245 |
+
logger.info("Entering store_application_request function")
|
246 |
+
try:
|
247 |
+
logger.info("Checking application_requests_container")
|
248 |
+
if application_requests_container is None:
|
249 |
+
logger.error("application_requests_container is not initialized")
|
250 |
+
return False
|
251 |
+
|
252 |
+
logger.info("Creating application request document")
|
253 |
+
application_request = {
|
254 |
+
"id": str(uuid.uuid4()),
|
255 |
+
"name": name,
|
256 |
+
"email": email,
|
257 |
+
"institution": institution,
|
258 |
+
"role": role,
|
259 |
+
"reason": reason,
|
260 |
+
"requestDate": datetime.utcnow().isoformat()
|
261 |
+
}
|
262 |
+
|
263 |
+
logger.info(f"Attempting to store document: {application_request}")
|
264 |
+
application_requests_container.create_item(body=application_request)
|
265 |
+
logger.info(f"Application request stored for email: {email}")
|
266 |
+
return True
|
267 |
+
except Exception as e:
|
268 |
+
logger.error(f"Error storing application request: {str(e)}")
|
269 |
+
return False
|
270 |
+
|
271 |
+
#######################################################################################################
|
272 |
+
def store_user_feedback(username, name, email, feedback):
|
273 |
+
global user_feedback_container
|
274 |
+
logger.info(f"Attempting to store user feedback for user: {username}")
|
275 |
+
try:
|
276 |
+
if user_feedback_container is None:
|
277 |
+
logger.error("user_feedback_container is not initialized")
|
278 |
+
return False
|
279 |
+
|
280 |
+
feedback_item = {
|
281 |
+
"id": str(uuid.uuid4()),
|
282 |
+
"username": username,
|
283 |
+
"name": name,
|
284 |
+
"email": email,
|
285 |
+
"feedback": feedback,
|
286 |
+
"timestamp": datetime.utcnow().isoformat()
|
287 |
+
}
|
288 |
+
|
289 |
+
result = user_feedback_container.create_item(body=feedback_item)
|
290 |
+
logger.info(f"User feedback stored with ID: {result['id']} for user: {username}")
|
291 |
+
return True
|
292 |
+
except Exception as e:
|
293 |
+
logger.error(f"Error storing user feedback for user {username}: {str(e)}")
|
294 |
+
return False
|
295 |
+
|
296 |
+
|
297 |
+
########################################################## -- FIN GESTION DE FORMULARIOS ---##########################################################
|
298 |
+
|
299 |
+
########################################################## -- INICIO ALMACENAMIENTO ANÁLISIS MORFOSINTÁCTICO ---##########################################################
|
300 |
+
|
301 |
+
def store_morphosyntax_result(username, text, repeated_words, arc_diagrams, pos_analysis, morphological_analysis, sentence_structure):
|
302 |
+
if analysis_collection is None:
|
303 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
304 |
+
return False
|
305 |
+
|
306 |
+
try:
|
307 |
+
word_count = {}
|
308 |
+
for word, color in repeated_words.items():
|
309 |
+
category = color # Asumiendo que 'color' es la categoría gramatical
|
310 |
+
word_count[category] = word_count.get(category, 0) + 1
|
311 |
+
|
312 |
+
analysis_document = {
|
313 |
+
'username': username,
|
314 |
+
'timestamp': datetime.utcnow(),
|
315 |
+
'text': text,
|
316 |
+
'word_count': word_count,
|
317 |
+
'arc_diagrams': arc_diagrams,
|
318 |
+
'pos_analysis': pos_analysis,
|
319 |
+
'morphological_analysis': morphological_analysis,
|
320 |
+
'sentence_structure': sentence_structure
|
321 |
+
}
|
322 |
+
|
323 |
+
result = analysis_collection.insert_one(analysis_document)
|
324 |
+
logger.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}")
|
325 |
+
return True
|
326 |
+
except Exception as e:
|
327 |
+
logger.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}")
|
328 |
+
return False
|
329 |
+
|
330 |
+
########################################################## -- FIN ALMACENAMIENTO ANÁLISIS MORFOSINTÁCTICO ---##########################################################
|
331 |
+
|
332 |
+
|
333 |
+
##########################################--- INICIO SECCIÓN DEL ANÁLISIS SEMÁNTICO ---###############################################
|
334 |
+
|
335 |
+
def store_file_semantic_contents(username, file_name, file_contents):
|
336 |
+
if user_container is None:
|
337 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
338 |
+
return False
|
339 |
+
try:
|
340 |
+
document = {
|
341 |
+
'id': f"{username}_semantic_{file_name}",
|
342 |
+
'username': username,
|
343 |
+
'file_name': file_name,
|
344 |
+
'file_contents': file_contents,
|
345 |
+
'analysis_type': 'semantic',
|
346 |
+
'timestamp': datetime.utcnow().isoformat()
|
347 |
+
}
|
348 |
+
user_container.upsert_item(body=document)
|
349 |
+
logger.info(f"Contenido del archivo semántico guardado para el usuario: {username}")
|
350 |
+
return True
|
351 |
+
except Exception as e:
|
352 |
+
logger.error(f"Error al guardar el contenido del archivo semántico para el usuario {username}: {str(e)}")
|
353 |
+
return False
|
354 |
+
|
355 |
+
def store_semantic_result(username, text, analysis_result):
|
356 |
+
if analysis_collection is None:
|
357 |
+
print("La conexión a MongoDB no está inicializada")
|
358 |
+
return False
|
359 |
+
try:
|
360 |
+
# Convertir los conceptos clave a una lista de tuplas
|
361 |
+
key_concepts = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts']]
|
362 |
+
|
363 |
+
# Convertir los gráficos a imágenes base64
|
364 |
+
graphs = {}
|
365 |
+
for graph_name in ['relations_graph', 'entity_graph', 'topic_graph']:
|
366 |
+
if graph_name in analysis_result:
|
367 |
+
buf = BytesIO()
|
368 |
+
analysis_result[graph_name].savefig(buf, format='png')
|
369 |
+
buf.seek(0)
|
370 |
+
graphs[graph_name] = base64.b64encode(buf.getvalue()).decode('utf-8')
|
371 |
+
|
372 |
+
analysis_document = {
|
373 |
+
'username': username,
|
374 |
+
'timestamp': datetime.utcnow(),
|
375 |
+
'text': text,
|
376 |
+
'key_concepts': key_concepts,
|
377 |
+
'graphs': graphs,
|
378 |
+
'summary': analysis_result.get('summary', ''),
|
379 |
+
'entities': analysis_result.get('entities', {}),
|
380 |
+
'sentiment': analysis_result.get('sentiment', ''),
|
381 |
+
'topics': analysis_result.get('topics', []),
|
382 |
+
'analysis_type': 'semantic'
|
383 |
+
}
|
384 |
+
|
385 |
+
result = analysis_collection.insert_one(analysis_document)
|
386 |
+
print(f"Análisis semántico guardado con ID: {result.inserted_id} para el usuario: {username}")
|
387 |
+
return True
|
388 |
+
except Exception as e:
|
389 |
+
print(f"Error al guardar el análisis semántico para el usuario {username}: {str(e)}")
|
390 |
+
return False
|
391 |
+
|
392 |
+
##########################################--- FIN DE LA SECCIÓN DEL ANÁLISIS SEMÁNTICO ---###############################################
|
393 |
+
|
394 |
+
############################################--- INICIO DE LA SECCIÓN DEL ANÁLISIS DEL DISCURSO ###################################################################
|
395 |
+
|
396 |
+
def store_discourse_analysis_result(username, text1, text2, analysis_result):
|
397 |
+
if analysis_collection is None:
|
398 |
+
print("La conexión a MongoDB no está inicializada")
|
399 |
+
return False
|
400 |
+
|
401 |
+
try:
|
402 |
+
# Convertir los grafos individuales a imágenes base64
|
403 |
+
buf1 = BytesIO()
|
404 |
+
analysis_result['graph1'].savefig(buf1, format='png')
|
405 |
+
buf1.seek(0)
|
406 |
+
img_str1 = base64.b64encode(buf1.getvalue()).decode('utf-8')
|
407 |
+
|
408 |
+
buf2 = BytesIO()
|
409 |
+
analysis_result['graph2'].savefig(buf2, format='png')
|
410 |
+
buf2.seek(0)
|
411 |
+
img_str2 = base64.b64encode(buf2.getvalue()).decode('utf-8')
|
412 |
+
|
413 |
+
# Crear una imagen combinada
|
414 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
|
415 |
+
ax1.imshow(plt.imread(BytesIO(base64.b64decode(img_str1))))
|
416 |
+
ax1.axis('off')
|
417 |
+
ax1.set_title("Documento 1: Relaciones Conceptuales")
|
418 |
+
ax2.imshow(plt.imread(BytesIO(base64.b64decode(img_str2))))
|
419 |
+
ax2.axis('off')
|
420 |
+
ax2.set_title("Documento 2: Relaciones Conceptuales")
|
421 |
+
|
422 |
+
buf_combined = BytesIO()
|
423 |
+
fig.savefig(buf_combined, format='png')
|
424 |
+
buf_combined.seek(0)
|
425 |
+
img_str_combined = base64.b64encode(buf_combined.getvalue()).decode('utf-8')
|
426 |
+
plt.close(fig)
|
427 |
+
|
428 |
+
# Convertir los conceptos clave a listas de tuplas
|
429 |
+
key_concepts1 = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts1']]
|
430 |
+
key_concepts2 = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts2']]
|
431 |
+
|
432 |
+
# Crear el documento para guardar
|
433 |
+
analysis_document = {
|
434 |
+
'username': username,
|
435 |
+
'timestamp': datetime.utcnow(),
|
436 |
+
#'text1': text1,
|
437 |
+
#'text2': text2,
|
438 |
+
'graph1': img_str1,
|
439 |
+
'graph2': img_str2,
|
440 |
+
'combined_graph': img_str_combined,
|
441 |
+
'key_concepts1': key_concepts1,
|
442 |
+
'key_concepts2': key_concepts2,
|
443 |
+
'analysis_type': 'discourse'
|
444 |
+
}
|
445 |
+
|
446 |
+
# Insertar el documento en la base de datos
|
447 |
+
result = analysis_collection.insert_one(analysis_document)
|
448 |
+
print(f"Análisis discursivo guardado con ID: {result.inserted_id} para el usuario: {username}")
|
449 |
+
return True
|
450 |
+
except Exception as e:
|
451 |
+
print(f"Error al guardar el análisis discursivo para el usuario {username}: {str(e)}")
|
452 |
+
print(f"Tipo de excepción: {type(e).__name__}")
|
453 |
+
print(f"Detalles de la excepción: {e.args}")
|
454 |
+
return False
|
455 |
+
|
456 |
+
############################################--- FIN DE LA SECCIÓN DEL ANÁLISIS DEL DISCURSO ###################################################################
|
457 |
+
|
458 |
+
|
459 |
+
################################################-- INICIO DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
460 |
+
def store_chat_history(username, messages):
|
461 |
+
try:
|
462 |
+
logger.info(f"Attempting to save chat history for user: {username}")
|
463 |
+
logger.debug(f"Messages to save: {messages}")
|
464 |
+
|
465 |
+
chat_document = {
|
466 |
+
'username': username,
|
467 |
+
'timestamp': datetime.utcnow(),
|
468 |
+
'messages': messages
|
469 |
+
}
|
470 |
+
result = chat_collection.insert_one(chat_document)
|
471 |
+
logger.info(f"Chat history saved with ID: {result.inserted_id} for user: {username}")
|
472 |
+
logger.debug(f"Chat content: {messages}")
|
473 |
+
return True
|
474 |
+
except Exception as e:
|
475 |
+
logger.error(f"Error saving chat history for user {username}: {str(e)}")
|
476 |
+
return False
|
477 |
+
|
478 |
+
#######################################################################################################
|
479 |
+
def export_analysis_and_chat(username, analysis_data, chat_data):
|
480 |
+
try:
|
481 |
+
export_data = {
|
482 |
+
"username": username,
|
483 |
+
"timestamp": datetime.utcnow(),
|
484 |
+
"analysis": analysis_data,
|
485 |
+
"chat": chat_data
|
486 |
+
}
|
487 |
+
|
488 |
+
# Aquí puedes decidir cómo quieres exportar los datos
|
489 |
+
# Por ejemplo, podrías guardarlos en una nueva colección en MongoDB
|
490 |
+
export_collection = mongo_db['exports']
|
491 |
+
result = export_collection.insert_one(export_data)
|
492 |
+
|
493 |
+
# También podrías generar un archivo JSON o CSV y guardarlo en Azure Blob Storage
|
494 |
+
|
495 |
+
return True
|
496 |
+
except Exception as e:
|
497 |
+
logger.error(f"Error al exportar análisis y chat para {username}: {str(e)}")
|
498 |
+
return False
|
499 |
+
|
500 |
+
################################################-- FIN DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
501 |
+
|
502 |
+
#######################################################################################################################################################
|
503 |
+
|
504 |
+
def get_student_data(username):
|
505 |
+
if analysis_collection is None or chat_collection is None:
|
506 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
507 |
+
return None
|
508 |
+
formatted_data = {
|
509 |
+
"username": username,
|
510 |
+
"entries": [],
|
511 |
+
"entries_count": 0,
|
512 |
+
"word_count": {},
|
513 |
+
"semantic_analyses": [],
|
514 |
+
"discourse_analyses": [],
|
515 |
+
"chat_history": []
|
516 |
+
}
|
517 |
+
try:
|
518 |
+
logger.info(f"Buscando datos de análisis para el usuario: {username}")
|
519 |
+
cursor = analysis_collection.find({"username": username})
|
520 |
+
|
521 |
+
for entry in cursor:
|
522 |
+
formatted_entry = {
|
523 |
+
"timestamp": entry.get("timestamp", datetime.utcnow()),
|
524 |
+
"analysis_type": entry.get("analysis_type", "morphosyntax")
|
525 |
+
}
|
526 |
+
|
527 |
+
if formatted_entry["analysis_type"] == "morphosyntax":
|
528 |
+
formatted_entry.update({
|
529 |
+
"text": entry.get("text", ""),
|
530 |
+
"word_count": entry.get("word_count", {}),
|
531 |
+
"arc_diagrams": entry.get("arc_diagrams", [])
|
532 |
+
})
|
533 |
+
for category, count in formatted_entry["word_count"].items():
|
534 |
+
formatted_data["word_count"][category] = formatted_data["word_count"].get(category, 0) + count
|
535 |
+
|
536 |
+
elif formatted_entry["analysis_type"] == "semantic":
|
537 |
+
formatted_entry.update({
|
538 |
+
"key_concepts": entry.get("key_concepts", []),
|
539 |
+
"graph": entry.get("graph", "")
|
540 |
+
})
|
541 |
+
formatted_data["semantic_analyses"].append(formatted_entry)
|
542 |
+
|
543 |
+
elif formatted_entry["analysis_type"] == "discourse":
|
544 |
+
formatted_entry.update({
|
545 |
+
"text1": entry.get("text1", ""),
|
546 |
+
"text2": entry.get("text2", ""),
|
547 |
+
"key_concepts1": entry.get("key_concepts1", []),
|
548 |
+
"key_concepts2": entry.get("key_concepts2", []),
|
549 |
+
"graph1": entry.get("graph1", ""),
|
550 |
+
"graph2": entry.get("graph2", ""),
|
551 |
+
"combined_graph": entry.get("combined_graph", "")
|
552 |
+
})
|
553 |
+
formatted_data["discourse_analyses"].append(formatted_entry)
|
554 |
+
|
555 |
+
formatted_data["entries"].append(formatted_entry)
|
556 |
+
|
557 |
+
formatted_data["entries_count"] = len(formatted_data["entries"])
|
558 |
+
formatted_data["entries"].sort(key=lambda x: x["timestamp"], reverse=True)
|
559 |
+
|
560 |
+
for entry in formatted_data["entries"]:
|
561 |
+
entry["timestamp"] = entry["timestamp"].isoformat()
|
562 |
+
|
563 |
+
except Exception as e:
|
564 |
+
logger.error(f"Error al obtener datos de análisis del estudiante {username}: {str(e)}")
|
565 |
+
|
566 |
+
try:
|
567 |
+
logger.info(f"Buscando historial de chat para el usuario: {username}")
|
568 |
+
chat_cursor = chat_collection.find({"username": username})
|
569 |
+
for chat in chat_cursor:
|
570 |
+
formatted_chat = {
|
571 |
+
"timestamp": chat["timestamp"].isoformat(),
|
572 |
+
"messages": chat["messages"]
|
573 |
+
}
|
574 |
+
formatted_data["chat_history"].append(formatted_chat)
|
575 |
+
|
576 |
+
formatted_data["chat_history"].sort(key=lambda x: x["timestamp"], reverse=True)
|
577 |
+
|
578 |
+
except Exception as e:
|
579 |
+
logger.error(f"Error al obtener historial de chat del estudiante {username}: {str(e)}")
|
580 |
+
logger.info(f"Datos formateados para {username}: {formatted_data}")
|
581 |
+
return formatted_data
|
modules/database/backUp/database_oldFromV2.py
ADDED
@@ -0,0 +1,473 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# database.py
|
2 |
+
# database.py de la versión 3 al 26-9-2024
|
3 |
+
import streamlit as st
|
4 |
+
import logging
|
5 |
+
import os
|
6 |
+
import pandas as pd
|
7 |
+
from azure.cosmos import CosmosClient
|
8 |
+
from azure.cosmos.exceptions import CosmosHttpResponseError
|
9 |
+
from pymongo import MongoClient
|
10 |
+
import certifi
|
11 |
+
from datetime import datetime, timezone
|
12 |
+
from io import BytesIO
|
13 |
+
import base64
|
14 |
+
import matplotlib.pyplot as plt
|
15 |
+
from matplotlib.figure import Figure
|
16 |
+
import bcrypt
|
17 |
+
print(f"Bcrypt version: {bcrypt.__version__}")
|
18 |
+
import uuid
|
19 |
+
import plotly.graph_objects as go # Para manejar el diagrama de Sankey
|
20 |
+
import numpy as np # Puede ser necesario para algunas operaciones
|
21 |
+
logging.basicConfig(level=logging.DEBUG)
|
22 |
+
logger = logging.getLogger(__name__)
|
23 |
+
|
24 |
+
# Variables globales para Cosmos DB SQL API
|
25 |
+
application_requests_container = None
|
26 |
+
cosmos_client = None
|
27 |
+
user_database = None
|
28 |
+
user_container = None
|
29 |
+
user_feedback_container = None
|
30 |
+
|
31 |
+
# Variables globales para Cosmos DB MongoDB API
|
32 |
+
mongo_client = None
|
33 |
+
mongo_db = None
|
34 |
+
analysis_collection = None
|
35 |
+
chat_collection = None # Nueva variable global
|
36 |
+
|
37 |
+
|
38 |
+
##############################################################################--- INICIO DE LAS BASES DE DATOS --- ###############################
|
39 |
+
def initialize_database_connections():
|
40 |
+
try:
|
41 |
+
print("Iniciando conexión a MongoDB")
|
42 |
+
mongodb_success = initialize_mongodb_connection()
|
43 |
+
print(f"Conexión a MongoDB: {'exitosa' if mongodb_success else 'fallida'}")
|
44 |
+
except Exception as e:
|
45 |
+
print(f"Error al conectar con MongoDB: {str(e)}")
|
46 |
+
mongodb_success = False
|
47 |
+
|
48 |
+
try:
|
49 |
+
print("Iniciando conexión a Cosmos DB SQL API")
|
50 |
+
sql_success = initialize_cosmos_sql_connection()
|
51 |
+
print(f"Conexión a Cosmos DB SQL API: {'exitosa' if sql_success else 'fallida'}")
|
52 |
+
except Exception as e:
|
53 |
+
print(f"Error al conectar con Cosmos DB SQL API: {str(e)}")
|
54 |
+
sql_success = False
|
55 |
+
|
56 |
+
return {
|
57 |
+
"mongodb": mongodb_success,
|
58 |
+
"cosmos_sql": sql_success
|
59 |
+
}
|
60 |
+
|
61 |
+
#####################################################################################33
|
62 |
+
def initialize_cosmos_sql_connection():
|
63 |
+
global cosmos_client, user_database, user_container, application_requests_container, user_feedback_container
|
64 |
+
logger.info("Initializing Cosmos DB SQL API connection")
|
65 |
+
try:
|
66 |
+
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
|
67 |
+
cosmos_key = os.environ.get("COSMOS_KEY")
|
68 |
+
logger.info(f"Cosmos Endpoint: {cosmos_endpoint}")
|
69 |
+
logger.info(f"Cosmos Key: {'*' * len(cosmos_key) if cosmos_key else 'Not set'}")
|
70 |
+
|
71 |
+
if not cosmos_endpoint or not cosmos_key:
|
72 |
+
logger.error("COSMOS_ENDPOINT or COSMOS_KEY environment variables are not set")
|
73 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
74 |
+
|
75 |
+
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
|
76 |
+
user_database = cosmos_client.get_database_client("user_database")
|
77 |
+
user_container = user_database.get_container_client("users")
|
78 |
+
application_requests_container = user_database.get_container_client("application_requests")
|
79 |
+
user_feedback_container = user_database.get_container_client("user_feedback")
|
80 |
+
|
81 |
+
logger.info(f"user_container initialized: {user_container is not None}")
|
82 |
+
logger.info(f"application_requests_container initialized: {application_requests_container is not None}")
|
83 |
+
logger.info(f"user_feedback_container initialized: {user_feedback_container is not None}")
|
84 |
+
|
85 |
+
logger.info("Conexión a Cosmos DB SQL API exitosa")
|
86 |
+
return True
|
87 |
+
except Exception as e:
|
88 |
+
logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}", exc_info=True)
|
89 |
+
return False
|
90 |
+
|
91 |
+
############################################################################################3
|
92 |
+
def initialize_mongodb_connection():
|
93 |
+
global mongo_client, mongo_db, analysis_collection, chat_collection
|
94 |
+
try:
|
95 |
+
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
|
96 |
+
if not cosmos_mongodb_connection_string:
|
97 |
+
logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada")
|
98 |
+
return False
|
99 |
+
|
100 |
+
mongo_client = MongoClient(cosmos_mongodb_connection_string,
|
101 |
+
tls=True,
|
102 |
+
tlsCAFile=certifi.where(),
|
103 |
+
retryWrites=False,
|
104 |
+
serverSelectionTimeoutMS=5000,
|
105 |
+
connectTimeoutMS=10000,
|
106 |
+
socketTimeoutMS=10000)
|
107 |
+
|
108 |
+
mongo_client.admin.command('ping')
|
109 |
+
|
110 |
+
mongo_db = mongo_client['aideatext_db']
|
111 |
+
# export = mongo_db['export']
|
112 |
+
analysis_collection = mongo_db['text_analysis']
|
113 |
+
chat_collection = mongo_db['chat_history'] # Inicializar la nueva colección
|
114 |
+
|
115 |
+
# Verificar la conexión
|
116 |
+
mongo_client.admin.command('ping')
|
117 |
+
|
118 |
+
logger.info("Conexión a Cosmos DB MongoDB API exitosa")
|
119 |
+
return True
|
120 |
+
except Exception as e:
|
121 |
+
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
|
122 |
+
return False
|
123 |
+
|
124 |
+
##############################################################################--- FIN DEL INICIO DE LAS BASES DE DATOS --- ################################################################################################################################
|
125 |
+
########################################################## -- INICIO DE GESTION DE USUARIOS ---##########################################################
|
126 |
+
def create_user(username, password, role):
|
127 |
+
global user_container
|
128 |
+
try:
|
129 |
+
print(f"Attempting to create user: {username} with role: {role}")
|
130 |
+
if user_container is None:
|
131 |
+
print("Error: user_container is None. Attempting to reinitialize connection.")
|
132 |
+
if not initialize_cosmos_sql_connection():
|
133 |
+
raise Exception("Failed to initialize SQL connection")
|
134 |
+
|
135 |
+
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
136 |
+
print(f"Password hashed successfully for user: {username}")
|
137 |
+
user_data = {
|
138 |
+
'id': username,
|
139 |
+
'password': hashed_password,
|
140 |
+
'role': role,
|
141 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
142 |
+
}
|
143 |
+
user_container.create_item(body=user_data)
|
144 |
+
print(f"Usuario {role} creado: {username}") # Log para depuración
|
145 |
+
return True
|
146 |
+
except Exception as e:
|
147 |
+
print(f"Detailed error in create_user: {str(e)}")
|
148 |
+
return False
|
149 |
+
|
150 |
+
#######################################################################################################
|
151 |
+
def create_admin_user(username, password):
|
152 |
+
return create_user(username, password, 'Administrador')
|
153 |
+
|
154 |
+
#######################################################################################################
|
155 |
+
def create_student_user(username, password):
|
156 |
+
return create_user(username, password, 'Estudiante')
|
157 |
+
|
158 |
+
#######################################################################################################
|
159 |
+
# Funciones para Cosmos DB SQL API (manejo de usuarios)
|
160 |
+
def get_user(username):
|
161 |
+
try:
|
162 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
163 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
164 |
+
user = items[0] if items else None
|
165 |
+
if user:
|
166 |
+
print(f"Usuario encontrado: {username}, Rol: {user.get('role')}") # Log añadido
|
167 |
+
else:
|
168 |
+
print(f"Usuario no encontrado: {username}") # Log añadido
|
169 |
+
return user
|
170 |
+
except Exception as e:
|
171 |
+
print(f"Error al obtener usuario {username}: {str(e)}")
|
172 |
+
return None
|
173 |
+
|
174 |
+
########################################################## -- FIN DE GESTION DE USUARIOS ---##########################################################
|
175 |
+
|
176 |
+
########################################################## -- INICIO GESTION DE ARCHIVOS ---##########################################################
|
177 |
+
|
178 |
+
def manage_file_contents(username, file_name, analysis_type, file_contents=None):
|
179 |
+
if user_container is None:
|
180 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
181 |
+
return None
|
182 |
+
|
183 |
+
item_id = f"{analysis_type}_{file_name}"
|
184 |
+
|
185 |
+
try:
|
186 |
+
if file_contents is not None:
|
187 |
+
# Storing or updating file
|
188 |
+
document = {
|
189 |
+
'id': item_id,
|
190 |
+
'username': username,
|
191 |
+
'file_name': file_name,
|
192 |
+
'analysis_type': analysis_type,
|
193 |
+
'file_contents': file_contents,
|
194 |
+
'timestamp': datetime.now(timezone.utc).isoformat()
|
195 |
+
}
|
196 |
+
user_container.upsert_item(body=document, partition_key=username)
|
197 |
+
logger.info(f"Contenido del archivo guardado/actualizado para el usuario: {username}, tipo de análisis: {analysis_type}")
|
198 |
+
return True
|
199 |
+
else:
|
200 |
+
# Retrieving file
|
201 |
+
item = user_container.read_item(item=item_id, partition_key=username)
|
202 |
+
return item['file_contents']
|
203 |
+
except CosmosHttpResponseError as e:
|
204 |
+
if e.status_code == 404:
|
205 |
+
logger.info(f"No se encontró el archivo para el usuario: {username}, tipo de análisis: {analysis_type}")
|
206 |
+
return None
|
207 |
+
else:
|
208 |
+
logger.error(f"Error de Cosmos DB al manejar el archivo para el usuario {username}: {str(e)}")
|
209 |
+
return None
|
210 |
+
except Exception as e:
|
211 |
+
logger.error(f"Error al manejar el archivo para el usuario {username}: {str(e)}")
|
212 |
+
return None
|
213 |
+
|
214 |
+
|
215 |
+
def get_user_files(username, analysis_type=None):
|
216 |
+
if user_container is None:
|
217 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
218 |
+
return []
|
219 |
+
try:
|
220 |
+
if analysis_type:
|
221 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}' AND c.analysis_type = '{analysis_type}'"
|
222 |
+
else:
|
223 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}'"
|
224 |
+
|
225 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
226 |
+
return items
|
227 |
+
except Exception as e:
|
228 |
+
logger.error(f"Error al obtener la lista de archivos del usuario {username}: {str(e)}")
|
229 |
+
return []
|
230 |
+
|
231 |
+
|
232 |
+
|
233 |
+
def delete_file(username, file_name, analysis_type):
|
234 |
+
if user_container is None:
|
235 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
236 |
+
return False
|
237 |
+
|
238 |
+
try:
|
239 |
+
item_id = f"{analysis_type}_{file_name}"
|
240 |
+
user_container.delete_item(item=item_id, partition_key=username)
|
241 |
+
logger.info(f"Archivo eliminado para el usuario: {username}, tipo de análisis: {analysis_type}, nombre: {file_name}")
|
242 |
+
return True
|
243 |
+
|
244 |
+
if success:
|
245 |
+
# Invalidar caché
|
246 |
+
cache_key = f"student_data_{username}"
|
247 |
+
if cache_key in st.session_state:
|
248 |
+
del st.session_state[cache_key]
|
249 |
+
|
250 |
+
|
251 |
+
|
252 |
+
except CosmosHttpResponseError as e:
|
253 |
+
logger.error(f"Cosmos DB error al eliminar el archivo para el usuario {username}: {str(e)}")
|
254 |
+
return False
|
255 |
+
|
256 |
+
except Exception as e:
|
257 |
+
logger.error(f"Error al eliminar el archivo para el usuario {username}: {str(e)}")
|
258 |
+
return False
|
259 |
+
|
260 |
+
########################################################## -- FIN GESTION DE ARCHIVOS ---##########################################################
|
261 |
+
|
262 |
+
########################################################## -- INICIO GESTION DE FORMULARIOS ---##########################################################
|
263 |
+
def store_application_request(name, email, institution, role, reason):
|
264 |
+
global application_requests_container
|
265 |
+
logger.info("Entering store_application_request function")
|
266 |
+
try:
|
267 |
+
logger.info("Checking application_requests_container")
|
268 |
+
if application_requests_container is None:
|
269 |
+
logger.error("application_requests_container is not initialized")
|
270 |
+
return False
|
271 |
+
|
272 |
+
logger.info("Creating application request document")
|
273 |
+
application_request = {
|
274 |
+
"id": str(uuid.uuid4()),
|
275 |
+
"name": name,
|
276 |
+
"email": email,
|
277 |
+
"institution": institution,
|
278 |
+
"role": role,
|
279 |
+
"reason": reason,
|
280 |
+
"requestDate": datetime.utcnow().isoformat()
|
281 |
+
}
|
282 |
+
|
283 |
+
logger.info(f"Attempting to store document: {application_request}")
|
284 |
+
application_requests_container.create_item(body=application_request)
|
285 |
+
logger.info(f"Application request stored for email: {email}")
|
286 |
+
return True
|
287 |
+
except Exception as e:
|
288 |
+
logger.error(f"Error storing application request: {str(e)}")
|
289 |
+
return False
|
290 |
+
|
291 |
+
#######################################################################################################
|
292 |
+
def store_user_feedback(username, name, email, feedback):
|
293 |
+
global user_feedback_container
|
294 |
+
logger.info(f"Attempting to store user feedback for user: {username}")
|
295 |
+
try:
|
296 |
+
if user_feedback_container is None:
|
297 |
+
logger.error("user_feedback_container is not initialized")
|
298 |
+
return False
|
299 |
+
|
300 |
+
feedback_item = {
|
301 |
+
"id": str(uuid.uuid4()),
|
302 |
+
"username": username,
|
303 |
+
"name": name,
|
304 |
+
"email": email,
|
305 |
+
"feedback": feedback,
|
306 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
307 |
+
}
|
308 |
+
|
309 |
+
result = user_feedback_container.create_item(body=feedback_item)
|
310 |
+
logger.info(f"User feedback stored with ID: {result['id']} for user: {username}")
|
311 |
+
return True
|
312 |
+
except Exception as e:
|
313 |
+
logger.error(f"Error storing user feedback for user {username}: {str(e)}")
|
314 |
+
return False
|
315 |
+
|
316 |
+
########################################################## -- FIN GESTION DE FORMULARIOS ---##########################################################
|
317 |
+
|
318 |
+
########################################################## -- INICIO ALMACENAMIENTO ANÁLISIS MORFOSINTÁCTICO ---##########################################################
|
319 |
+
|
320 |
+
def store_morphosyntax_result(username, text, repeated_words, arc_diagrams, pos_analysis, morphological_analysis, sentence_structure):
|
321 |
+
if analysis_collection is None:
|
322 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
323 |
+
return False
|
324 |
+
|
325 |
+
try:
|
326 |
+
word_count = {}
|
327 |
+
for word, color in repeated_words.items():
|
328 |
+
category = color # Asumiendo que 'color' es la categoría gramatical
|
329 |
+
word_count[category] = word_count.get(category, 0) + 1
|
330 |
+
|
331 |
+
analysis_document = {
|
332 |
+
'username': username,
|
333 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
334 |
+
'text': text,
|
335 |
+
'repeated_words': repeated_words,
|
336 |
+
'word_count': word_count,
|
337 |
+
'arc_diagrams': arc_diagrams,
|
338 |
+
'pos_analysis': pos_analysis,
|
339 |
+
'morphological_analysis': morphological_analysis,
|
340 |
+
'sentence_structure': sentence_structure,
|
341 |
+
'analysis_type': 'morphosyntax'
|
342 |
+
}
|
343 |
+
|
344 |
+
result = analysis_collection.insert_one(analysis_document)
|
345 |
+
logger.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}")
|
346 |
+
return True
|
347 |
+
except Exception as e:
|
348 |
+
logger.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}")
|
349 |
+
return False
|
350 |
+
|
351 |
+
|
352 |
+
################################################-- INICIO DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
353 |
+
def store_chat_history(username, messages):
|
354 |
+
try:
|
355 |
+
logger.info(f"Attempting to save chat history for user: {username}")
|
356 |
+
logger.debug(f"Messages to save: {messages}")
|
357 |
+
|
358 |
+
chat_document = {
|
359 |
+
'username': username,
|
360 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
361 |
+
'messages': messages
|
362 |
+
}
|
363 |
+
result = chat_collection.insert_one(chat_document)
|
364 |
+
logger.info(f"Chat history saved with ID: {result.inserted_id} for user: {username}")
|
365 |
+
logger.debug(f"Chat content: {messages}")
|
366 |
+
return True
|
367 |
+
except Exception as e:
|
368 |
+
logger.error(f"Error saving chat history for user {username}: {str(e)}")
|
369 |
+
return False
|
370 |
+
|
371 |
+
#######################################################################################################
|
372 |
+
def export_analysis_and_chat(username, analysis_data, chat_data):
|
373 |
+
try:
|
374 |
+
export_data = {
|
375 |
+
"username": username,
|
376 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
377 |
+
"analysis": analysis_data,
|
378 |
+
"chat": chat_data
|
379 |
+
}
|
380 |
+
|
381 |
+
# Aquí puedes decidir cómo quieres exportar los datos
|
382 |
+
# Por ejemplo, podrías guardarlos en una nueva colección en MongoDB
|
383 |
+
export_collection = mongo_db['exports']
|
384 |
+
result = export_collection.insert_one(export_data)
|
385 |
+
|
386 |
+
# También podrías generar un archivo JSON o CSV y guardarlo en Azure Blob Storage
|
387 |
+
|
388 |
+
return True
|
389 |
+
except Exception as e:
|
390 |
+
logger.error(f"Error al exportar análisis y chat para {username}: {str(e)}")
|
391 |
+
return False
|
392 |
+
|
393 |
+
################################################-- FIN DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
394 |
+
########--- STUDENT DATA -------
|
395 |
+
|
396 |
+
def get_student_data(username):
|
397 |
+
if analysis_collection is None or chat_collection is None:
|
398 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
399 |
+
return None
|
400 |
+
formatted_data = {
|
401 |
+
"username": username,
|
402 |
+
"entries": [],
|
403 |
+
"entries_count": 0,
|
404 |
+
"word_count": {},
|
405 |
+
"semantic_analyses": [],
|
406 |
+
"discourse_analyses": [],
|
407 |
+
"chat_history": []
|
408 |
+
}
|
409 |
+
try:
|
410 |
+
logger.info(f"Buscando datos de análisis para el usuario: {username}")
|
411 |
+
cursor = analysis_collection.find({"username": username})
|
412 |
+
|
413 |
+
for entry in cursor:
|
414 |
+
formatted_entry = {
|
415 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
416 |
+
"analysis_type": entry.get("analysis_type", "morphosyntax")
|
417 |
+
}
|
418 |
+
|
419 |
+
if formatted_entry["analysis_type"] == "morphosyntax":
|
420 |
+
formatted_entry.update({
|
421 |
+
"text": entry.get("text", ""),
|
422 |
+
"word_count": entry.get("word_count", {}),
|
423 |
+
"arc_diagrams": entry.get("arc_diagrams", [])
|
424 |
+
})
|
425 |
+
for category, count in formatted_entry["word_count"].items():
|
426 |
+
formatted_data["word_count"][category] = formatted_data["word_count"].get(category, 0) + count
|
427 |
+
|
428 |
+
elif formatted_entry["analysis_type"] == "semantic":
|
429 |
+
formatted_entry.update({
|
430 |
+
"key_concepts": entry.get("key_concepts", []),
|
431 |
+
"graph": entry.get("graph", "")
|
432 |
+
})
|
433 |
+
formatted_data["semantic_analyses"].append(formatted_entry)
|
434 |
+
|
435 |
+
elif formatted_entry["analysis_type"] == "discourse":
|
436 |
+
formatted_entry.update({
|
437 |
+
"text1": entry.get("text1", ""),
|
438 |
+
"text2": entry.get("text2", ""),
|
439 |
+
"key_concepts1": entry.get("key_concepts1", []),
|
440 |
+
"key_concepts2": entry.get("key_concepts2", []),
|
441 |
+
"graph1": entry.get("graph1", ""),
|
442 |
+
"graph2": entry.get("graph2", ""),
|
443 |
+
"combined_graph": entry.get("combined_graph", "")
|
444 |
+
})
|
445 |
+
formatted_data["discourse_analyses"].append(formatted_entry)
|
446 |
+
|
447 |
+
formatted_data["entries"].append(formatted_entry)
|
448 |
+
|
449 |
+
formatted_data["entries_count"] = len(formatted_data["entries"])
|
450 |
+
formatted_data["entries"].sort(key=lambda x: x["timestamp"], reverse=True)
|
451 |
+
|
452 |
+
for entry in formatted_data["entries"]:
|
453 |
+
entry["timestamp"] = entry["timestamp"].isoformat()
|
454 |
+
|
455 |
+
except Exception as e:
|
456 |
+
logger.error(f"Error al obtener datos de análisis del estudiante {username}: {str(e)}")
|
457 |
+
|
458 |
+
try:
|
459 |
+
logger.info(f"Buscando historial de chat para el usuario: {username}")
|
460 |
+
chat_cursor = chat_collection.find({"username": username})
|
461 |
+
for chat in chat_cursor:
|
462 |
+
formatted_chat = {
|
463 |
+
"timestamp": chat["timestamp"].isoformat(),
|
464 |
+
"messages": chat["messages"]
|
465 |
+
}
|
466 |
+
formatted_data["chat_history"].append(formatted_chat)
|
467 |
+
|
468 |
+
formatted_data["chat_history"].sort(key=lambda x: x["timestamp"], reverse=True)
|
469 |
+
|
470 |
+
except Exception as e:
|
471 |
+
logger.error(f"Error al obtener historial de chat del estudiante {username}: {str(e)}")
|
472 |
+
logger.info(f"Datos formateados para {username}: {formatted_data}")
|
473 |
+
return formatted_data
|
modules/database/backUp/database_v3-2ok.py
ADDED
@@ -0,0 +1,629 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# database.py
|
2 |
+
import logging
|
3 |
+
import os
|
4 |
+
from azure.cosmos import CosmosClient
|
5 |
+
from azure.cosmos.exceptions import CosmosHttpResponseError
|
6 |
+
from pymongo import MongoClient
|
7 |
+
import certifi
|
8 |
+
from datetime import datetime, timezone
|
9 |
+
import io
|
10 |
+
from io import BytesIO
|
11 |
+
import base64
|
12 |
+
import matplotlib.pyplot as plt
|
13 |
+
from matplotlib.figure import Figure
|
14 |
+
import bcrypt
|
15 |
+
print(f"Bcrypt version: {bcrypt.__version__}")
|
16 |
+
import uuid
|
17 |
+
import plotly.graph_objects as go # Para manejar el diagrama de Sankey
|
18 |
+
import numpy as np # Puede ser necesario para algunas operaciones
|
19 |
+
logging.basicConfig(level=logging.DEBUG)
|
20 |
+
logger = logging.getLogger(__name__)
|
21 |
+
|
22 |
+
# Variables globales para Cosmos DB SQL API
|
23 |
+
application_requests_container = None
|
24 |
+
cosmos_client = None
|
25 |
+
user_database = None
|
26 |
+
user_container = None
|
27 |
+
user_feedback_container = None
|
28 |
+
|
29 |
+
# Variables globales para Cosmos DB MongoDB API
|
30 |
+
mongo_client = None
|
31 |
+
mongo_db = None
|
32 |
+
analysis_collection = None
|
33 |
+
chat_collection = None # Nueva variable global
|
34 |
+
|
35 |
+
|
36 |
+
##############################################################################--- INICIO DE LAS BASES DE DATOS --- ###############################
|
37 |
+
def initialize_database_connections():
|
38 |
+
try:
|
39 |
+
print("Iniciando conexión a MongoDB")
|
40 |
+
mongodb_success = initialize_mongodb_connection()
|
41 |
+
print(f"Conexión a MongoDB: {'exitosa' if mongodb_success else 'fallida'}")
|
42 |
+
except Exception as e:
|
43 |
+
print(f"Error al conectar con MongoDB: {str(e)}")
|
44 |
+
mongodb_success = False
|
45 |
+
|
46 |
+
try:
|
47 |
+
print("Iniciando conexión a Cosmos DB SQL API")
|
48 |
+
sql_success = initialize_cosmos_sql_connection()
|
49 |
+
print(f"Conexión a Cosmos DB SQL API: {'exitosa' if sql_success else 'fallida'}")
|
50 |
+
except Exception as e:
|
51 |
+
print(f"Error al conectar con Cosmos DB SQL API: {str(e)}")
|
52 |
+
sql_success = False
|
53 |
+
|
54 |
+
return {
|
55 |
+
"mongodb": mongodb_success,
|
56 |
+
"cosmos_sql": sql_success
|
57 |
+
}
|
58 |
+
|
59 |
+
#####################################################################################33
|
60 |
+
def initialize_cosmos_sql_connection():
|
61 |
+
global cosmos_client, user_database, user_container, application_requests_container, user_feedback_container
|
62 |
+
logger.info("Initializing Cosmos DB SQL API connection")
|
63 |
+
try:
|
64 |
+
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
|
65 |
+
cosmos_key = os.environ.get("COSMOS_KEY")
|
66 |
+
logger.info(f"Cosmos Endpoint: {cosmos_endpoint}")
|
67 |
+
logger.info(f"Cosmos Key: {'*' * len(cosmos_key) if cosmos_key else 'Not set'}")
|
68 |
+
|
69 |
+
if not cosmos_endpoint or not cosmos_key:
|
70 |
+
logger.error("COSMOS_ENDPOINT or COSMOS_KEY environment variables are not set")
|
71 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
72 |
+
|
73 |
+
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
|
74 |
+
user_database = cosmos_client.get_database_client("user_database")
|
75 |
+
user_container = user_database.get_container_client("users")
|
76 |
+
application_requests_container = user_database.get_container_client("application_requests")
|
77 |
+
user_feedback_container = user_database.get_container_client("user_feedback")
|
78 |
+
|
79 |
+
logger.info(f"user_container initialized: {user_container is not None}")
|
80 |
+
logger.info(f"application_requests_container initialized: {application_requests_container is not None}")
|
81 |
+
logger.info(f"user_feedback_container initialized: {user_feedback_container is not None}")
|
82 |
+
|
83 |
+
logger.info("Conexión a Cosmos DB SQL API exitosa")
|
84 |
+
return True
|
85 |
+
except Exception as e:
|
86 |
+
logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}", exc_info=True)
|
87 |
+
return False
|
88 |
+
|
89 |
+
############################################################################################3
|
90 |
+
def initialize_mongodb_connection():
|
91 |
+
global mongo_client, mongo_db, analysis_collection, chat_collection
|
92 |
+
try:
|
93 |
+
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
|
94 |
+
if not cosmos_mongodb_connection_string:
|
95 |
+
logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada")
|
96 |
+
return False
|
97 |
+
|
98 |
+
mongo_client = MongoClient(cosmos_mongodb_connection_string,
|
99 |
+
tls=True,
|
100 |
+
tlsCAFile=certifi.where(),
|
101 |
+
retryWrites=False,
|
102 |
+
serverSelectionTimeoutMS=5000,
|
103 |
+
connectTimeoutMS=10000,
|
104 |
+
socketTimeoutMS=10000)
|
105 |
+
|
106 |
+
mongo_client.admin.command('ping')
|
107 |
+
|
108 |
+
mongo_db = mongo_client['aideatext_db']
|
109 |
+
analysis_collection = mongo_db['text_analysis']
|
110 |
+
chat_collection = mongo_db['chat_history'] # Inicializar la nueva colección
|
111 |
+
|
112 |
+
# Verificar la conexión
|
113 |
+
mongo_client.admin.command('ping')
|
114 |
+
|
115 |
+
logger.info("Conexión a Cosmos DB MongoDB API exitosa")
|
116 |
+
return True
|
117 |
+
except Exception as e:
|
118 |
+
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
|
119 |
+
return False
|
120 |
+
|
121 |
+
##############################################################################--- FIN DEL INICIO DE LAS BASES DE DATOS --- ################################################################################################################################
|
122 |
+
########################################################## -- INICIO DE GESTION DE USUARIOS ---##########################################################
|
123 |
+
def create_user(username, password, role):
|
124 |
+
global user_container
|
125 |
+
try:
|
126 |
+
print(f"Attempting to create user: {username} with role: {role}")
|
127 |
+
if user_container is None:
|
128 |
+
print("Error: user_container is None. Attempting to reinitialize connection.")
|
129 |
+
if not initialize_cosmos_sql_connection():
|
130 |
+
raise Exception("Failed to initialize SQL connection")
|
131 |
+
|
132 |
+
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
133 |
+
print(f"Password hashed successfully for user: {username}")
|
134 |
+
user_data = {
|
135 |
+
'id': username,
|
136 |
+
'password': hashed_password,
|
137 |
+
'role': role,
|
138 |
+
'created_at': datetime.utcnow().isoformat()
|
139 |
+
}
|
140 |
+
user_container.create_item(body=user_data)
|
141 |
+
print(f"Usuario {role} creado: {username}") # Log para depuración
|
142 |
+
return True
|
143 |
+
except Exception as e:
|
144 |
+
print(f"Detailed error in create_user: {str(e)}")
|
145 |
+
return False
|
146 |
+
|
147 |
+
#######################################################################################################
|
148 |
+
def create_admin_user(username, password):
|
149 |
+
return create_user(username, password, 'Administrador')
|
150 |
+
|
151 |
+
#######################################################################################################
|
152 |
+
def create_student_user(username, password):
|
153 |
+
return create_user(username, password, 'Estudiante')
|
154 |
+
|
155 |
+
#######################################################################################################
|
156 |
+
# Funciones para Cosmos DB SQL API (manejo de usuarios)
|
157 |
+
def get_user(username):
|
158 |
+
try:
|
159 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
160 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
161 |
+
user = items[0] if items else None
|
162 |
+
if user:
|
163 |
+
print(f"Usuario encontrado: {username}, Rol: {user.get('role')}") # Log añadido
|
164 |
+
else:
|
165 |
+
print(f"Usuario no encontrado: {username}") # Log añadido
|
166 |
+
return user
|
167 |
+
except Exception as e:
|
168 |
+
print(f"Error al obtener usuario {username}: {str(e)}")
|
169 |
+
return None
|
170 |
+
|
171 |
+
########################################################## -- FIN DE GESTION DE USUARIOS ---##########################################################
|
172 |
+
|
173 |
+
########################################################## -- INICIO GESTION DE ARCHIVOS ---##########################################################
|
174 |
+
|
175 |
+
def store_file_contents(username, file_name, file_contents, analysis_type):
|
176 |
+
if user_container is None:
|
177 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
178 |
+
return False
|
179 |
+
try:
|
180 |
+
document = {
|
181 |
+
'id': f"{username}_{analysis_type}_{file_name}",
|
182 |
+
'username': username,
|
183 |
+
'file_name': file_name,
|
184 |
+
'analysis_type': analysis_type,
|
185 |
+
'file_contents': file_contents,
|
186 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
187 |
+
}
|
188 |
+
user_container.upsert_item(body=document)
|
189 |
+
logger.info(f"Contenido del archivo guardado para el usuario: {username}, tipo de análisis: {analysis_type}")
|
190 |
+
return True
|
191 |
+
except Exception as e:
|
192 |
+
logger.error(f"Error al guardar el contenido del archivo para el usuario {username}: {str(e)}")
|
193 |
+
return False
|
194 |
+
|
195 |
+
def retrieve_file_contents(username, file_name, analysis_type):
|
196 |
+
print(f"Attempting to retrieve file: {file_name} for user: {username}")
|
197 |
+
if user_container is None:
|
198 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
199 |
+
return None
|
200 |
+
try:
|
201 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}_{analysis_type}_{file_name}'"
|
202 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
203 |
+
if items:
|
204 |
+
return items[0]['file_contents']
|
205 |
+
else:
|
206 |
+
logger.info(f"No se encontró contenido de archivo para el usuario: {username}, tipo de análisis: {analysis_type}")
|
207 |
+
return None
|
208 |
+
except Exception as e:
|
209 |
+
logger.error(f"Error al recuperar el contenido del archivo para el usuario {username}: {str(e)}")
|
210 |
+
return None
|
211 |
+
|
212 |
+
def get_user_files(username, analysis_type=None):
|
213 |
+
if user_container is None:
|
214 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
215 |
+
return []
|
216 |
+
try:
|
217 |
+
if analysis_type:
|
218 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}' AND c.analysis_type = '{analysis_type}'"
|
219 |
+
else:
|
220 |
+
query = f"SELECT c.file_name, c.analysis_type, c.timestamp FROM c WHERE c.username = '{username}'"
|
221 |
+
|
222 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
223 |
+
return items
|
224 |
+
except Exception as e:
|
225 |
+
logger.error(f"Error al obtener la lista de archivos del usuario {username}: {str(e)}")
|
226 |
+
return []
|
227 |
+
|
228 |
+
def delete_file(username, file_name, analysis_type):
|
229 |
+
if user_container is None:
|
230 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
231 |
+
return False
|
232 |
+
try:
|
233 |
+
user_container.delete_item(item=f"{username}_{analysis_type}_{file_name}", partition_key=username)
|
234 |
+
logger.info(f"Archivo eliminado para el usuario: {username}, tipo de análisis: {analysis_type}")
|
235 |
+
return True
|
236 |
+
except Exception as e:
|
237 |
+
logger.error(f"Error al eliminar el archivo para el usuario {username}: {str(e)}")
|
238 |
+
return False
|
239 |
+
|
240 |
+
########################################################## -- FIN GESTION DE ARCHIVOS ---##########################################################
|
241 |
+
|
242 |
+
########################################################## -- INICIO GESTION DE FORMULARIOS ---##########################################################
|
243 |
+
def store_application_request(name, email, institution, role, reason):
|
244 |
+
global application_requests_container
|
245 |
+
logger.info("Entering store_application_request function")
|
246 |
+
try:
|
247 |
+
logger.info("Checking application_requests_container")
|
248 |
+
if application_requests_container is None:
|
249 |
+
logger.error("application_requests_container is not initialized")
|
250 |
+
return False
|
251 |
+
|
252 |
+
logger.info("Creating application request document")
|
253 |
+
application_request = {
|
254 |
+
"id": str(uuid.uuid4()),
|
255 |
+
"name": name,
|
256 |
+
"email": email,
|
257 |
+
"institution": institution,
|
258 |
+
"role": role,
|
259 |
+
"reason": reason,
|
260 |
+
"requestDate": datetime.utcnow().isoformat()
|
261 |
+
}
|
262 |
+
|
263 |
+
logger.info(f"Attempting to store document: {application_request}")
|
264 |
+
application_requests_container.create_item(body=application_request)
|
265 |
+
logger.info(f"Application request stored for email: {email}")
|
266 |
+
return True
|
267 |
+
except Exception as e:
|
268 |
+
logger.error(f"Error storing application request: {str(e)}")
|
269 |
+
return False
|
270 |
+
|
271 |
+
#######################################################################################################
|
272 |
+
def store_user_feedback(username, name, email, feedback):
|
273 |
+
global user_feedback_container
|
274 |
+
logger.info(f"Attempting to store user feedback for user: {username}")
|
275 |
+
try:
|
276 |
+
if user_feedback_container is None:
|
277 |
+
logger.error("user_feedback_container is not initialized")
|
278 |
+
return False
|
279 |
+
|
280 |
+
feedback_item = {
|
281 |
+
"id": str(uuid.uuid4()),
|
282 |
+
"username": username,
|
283 |
+
"name": name,
|
284 |
+
"email": email,
|
285 |
+
"feedback": feedback,
|
286 |
+
"timestamp":datetime.now(timezone.utc).isoformat(),
|
287 |
+
}
|
288 |
+
|
289 |
+
result = user_feedback_container.create_item(body=feedback_item)
|
290 |
+
logger.info(f"User feedback stored with ID: {result['id']} for user: {username}")
|
291 |
+
return True
|
292 |
+
except Exception as e:
|
293 |
+
logger.error(f"Error storing user feedback for user {username}: {str(e)}")
|
294 |
+
return False
|
295 |
+
|
296 |
+
|
297 |
+
########################################################## -- FIN GESTION DE FORMULARIOS ---##########################################################
|
298 |
+
|
299 |
+
########################################################## -- INICIO ALMACENAMIENTO ANÁLISIS MORFOSINTÁCTICO ---##########################################################
|
300 |
+
|
301 |
+
def store_morphosyntax_result(username, text, repeated_words, arc_diagrams, pos_analysis, morphological_analysis, sentence_structure):
|
302 |
+
if analysis_collection is None:
|
303 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
304 |
+
return False
|
305 |
+
|
306 |
+
try:
|
307 |
+
word_count = {}
|
308 |
+
for word, color in repeated_words.items():
|
309 |
+
category = color # Asumiendo que 'color' es la categoría gramatical
|
310 |
+
word_count[category] = word_count.get(category, 0) + 1
|
311 |
+
|
312 |
+
analysis_document = {
|
313 |
+
'username': username,
|
314 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
315 |
+
'text': text,
|
316 |
+
'word_count': word_count,
|
317 |
+
'arc_diagrams': arc_diagrams,
|
318 |
+
'pos_analysis': pos_analysis,
|
319 |
+
'morphological_analysis': morphological_analysis,
|
320 |
+
'sentence_structure': sentence_structure
|
321 |
+
}
|
322 |
+
|
323 |
+
result = analysis_collection.insert_one(analysis_document)
|
324 |
+
logger.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}")
|
325 |
+
return True
|
326 |
+
except Exception as e:
|
327 |
+
logger.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}")
|
328 |
+
return False
|
329 |
+
|
330 |
+
########################################################## -- FIN ALMACENAMIENTO ANÁLISIS MORFOSINTÁCTICO ---##########################################################
|
331 |
+
|
332 |
+
|
333 |
+
##########################################--- INICIO SECCIÓN DEL ANÁLISIS SEMÁNTICO ---###############################################
|
334 |
+
|
335 |
+
def store_file_semantic_contents(username, file_name, file_contents):
|
336 |
+
if user_container is None:
|
337 |
+
logger.error("La conexión a Cosmos DB SQL API no está inicializada")
|
338 |
+
return False
|
339 |
+
try:
|
340 |
+
document = {
|
341 |
+
'id': f"{username}_semantic_{file_name}",
|
342 |
+
'username': username,
|
343 |
+
'file_name': file_name,
|
344 |
+
'file_contents': file_contents,
|
345 |
+
'analysis_type': 'semantic',
|
346 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
347 |
+
}
|
348 |
+
user_container.upsert_item(body=document)
|
349 |
+
logger.info(f"Contenido del archivo semántico guardado para el usuario: {username}")
|
350 |
+
return True
|
351 |
+
except Exception as e:
|
352 |
+
logger.error(f"Error al guardar el contenido del archivo semántico para el usuario {username}: {str(e)}")
|
353 |
+
return False
|
354 |
+
|
355 |
+
def store_semantic_result(username, text, analysis_result):
|
356 |
+
if analysis_collection is None:
|
357 |
+
print("La conexión a MongoDB no está inicializada")
|
358 |
+
return False
|
359 |
+
try:
|
360 |
+
# Convertir los conceptos clave a una lista de tuplas
|
361 |
+
key_concepts = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts']]
|
362 |
+
|
363 |
+
# Convertir los gráficos a imágenes base64
|
364 |
+
graphs = {}
|
365 |
+
for graph_name in ['relations_graph', 'entity_graph', 'topic_graph']:
|
366 |
+
if graph_name in analysis_result:
|
367 |
+
buf = BytesIO()
|
368 |
+
analysis_result[graph_name].savefig(buf, format='png')
|
369 |
+
buf.seek(0)
|
370 |
+
graphs[graph_name] = base64.b64encode(buf.getvalue()).decode('utf-8')
|
371 |
+
|
372 |
+
analysis_document = {
|
373 |
+
'username': username,
|
374 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
375 |
+
'text': text,
|
376 |
+
'key_concepts': key_concepts,
|
377 |
+
'graphs': graphs,
|
378 |
+
'summary': analysis_result.get('summary', ''),
|
379 |
+
'entities': analysis_result.get('entities', {}),
|
380 |
+
'sentiment': analysis_result.get('sentiment', ''),
|
381 |
+
'topics': analysis_result.get('topics', []),
|
382 |
+
'analysis_type': 'semantic'
|
383 |
+
}
|
384 |
+
|
385 |
+
result = analysis_collection.insert_one(analysis_document)
|
386 |
+
print(f"Análisis semántico guardado con ID: {result.inserted_id} para el usuario: {username}")
|
387 |
+
return True
|
388 |
+
except Exception as e:
|
389 |
+
print(f"Error al guardar el análisis semántico para el usuario {username}: {str(e)}")
|
390 |
+
return False
|
391 |
+
|
392 |
+
##########################################--- FIN DE LA SECCIÓN DEL ANÁLISIS SEMÁNTICO ---###############################################
|
393 |
+
|
394 |
+
############################################--- INICIO DE LA SECCIÓN DEL ANÁLISIS DEL DISCURSO ###################################################################
|
395 |
+
|
396 |
+
def store_discourse_analysis_result(username, text1, text2, analysis_result):
|
397 |
+
if analysis_collection is None:
|
398 |
+
print("La conexión a MongoDB no está inicializada")
|
399 |
+
return False
|
400 |
+
|
401 |
+
try:
|
402 |
+
# Convertir los grafos individuales a imágenes base64
|
403 |
+
buf1 = BytesIO()
|
404 |
+
analysis_result['graph1'].savefig(buf1, format='png')
|
405 |
+
buf1.seek(0)
|
406 |
+
img_str1 = base64.b64encode(buf1.getvalue()).decode('utf-8')
|
407 |
+
|
408 |
+
buf2 = BytesIO()
|
409 |
+
analysis_result['graph2'].savefig(buf2, format='png')
|
410 |
+
buf2.seek(0)
|
411 |
+
img_str2 = base64.b64encode(buf2.getvalue()).decode('utf-8')
|
412 |
+
|
413 |
+
# Crear una imagen combinada
|
414 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
|
415 |
+
ax1.imshow(plt.imread(BytesIO(base64.b64decode(img_str1))))
|
416 |
+
ax1.axis('off')
|
417 |
+
ax1.set_title("Documento 1: Relaciones Conceptuales")
|
418 |
+
ax2.imshow(plt.imread(BytesIO(base64.b64decode(img_str2))))
|
419 |
+
ax2.axis('off')
|
420 |
+
ax2.set_title("Documento 2: Relaciones Conceptuales")
|
421 |
+
|
422 |
+
buf_combined = BytesIO()
|
423 |
+
fig.savefig(buf_combined, format='png')
|
424 |
+
buf_combined.seek(0)
|
425 |
+
img_str_combined = base64.b64encode(buf_combined.getvalue()).decode('utf-8')
|
426 |
+
plt.close(fig)
|
427 |
+
|
428 |
+
# Convertir los conceptos clave a listas de tuplas
|
429 |
+
key_concepts1 = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts1']]
|
430 |
+
key_concepts2 = [(concept, float(frequency)) for concept, frequency in analysis_result['key_concepts2']]
|
431 |
+
|
432 |
+
# Crear el documento para guardar
|
433 |
+
analysis_document = {
|
434 |
+
'username': username,
|
435 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
436 |
+
#'text1': text1,
|
437 |
+
#'text2': text2,
|
438 |
+
'graph1': img_str1,
|
439 |
+
'graph2': img_str2,
|
440 |
+
'combined_graph': img_str_combined,
|
441 |
+
'key_concepts1': key_concepts1,
|
442 |
+
'key_concepts2': key_concepts2,
|
443 |
+
'analysis_type': 'discourse'
|
444 |
+
}
|
445 |
+
|
446 |
+
# Insertar el documento en la base de datos
|
447 |
+
result = analysis_collection.insert_one(analysis_document)
|
448 |
+
print(f"Análisis discursivo guardado con ID: {result.inserted_id} para el usuario: {username}")
|
449 |
+
return True
|
450 |
+
except Exception as e:
|
451 |
+
print(f"Error al guardar el análisis discursivo para el usuario {username}: {str(e)}")
|
452 |
+
print(f"Tipo de excepción: {type(e).__name__}")
|
453 |
+
print(f"Detalles de la excepción: {e.args}")
|
454 |
+
return False
|
455 |
+
|
456 |
+
############################################--- FIN DE LA SECCIÓN DEL ANÁLISIS DEL DISCURSO ###################################################################
|
457 |
+
|
458 |
+
|
459 |
+
################################################-- INICIO DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
460 |
+
def store_chat_history(username, messages):
|
461 |
+
try:
|
462 |
+
logger.info(f"Attempting to save chat history for user: {username}")
|
463 |
+
logger.debug(f"Messages to save: {messages}")
|
464 |
+
|
465 |
+
chat_document = {
|
466 |
+
'username': username,
|
467 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
468 |
+
'messages': messages
|
469 |
+
}
|
470 |
+
result = chat_collection.insert_one(chat_document)
|
471 |
+
logger.info(f"Chat history saved with ID: {result.inserted_id} for user: {username}")
|
472 |
+
logger.debug(f"Chat content: {messages}")
|
473 |
+
return True
|
474 |
+
except Exception as e:
|
475 |
+
logger.error(f"Error saving chat history for user {username}: {str(e)}")
|
476 |
+
return False
|
477 |
+
|
478 |
+
#######################################################################################################
|
479 |
+
def export_analysis_and_chat(username, analysis_data, chat_data):
|
480 |
+
try:
|
481 |
+
export_data = {
|
482 |
+
"username": username,
|
483 |
+
'timestamp':datetime.now(timezone.utc).isoformat(),
|
484 |
+
"analysis": analysis_data,
|
485 |
+
"chat": chat_data
|
486 |
+
}
|
487 |
+
|
488 |
+
# Aquí puedes decidir cómo quieres exportar los datos
|
489 |
+
# Por ejemplo, podrías guardarlos en una nueva colección en MongoDB
|
490 |
+
export_collection = mongo_db['exports']
|
491 |
+
result = export_collection.insert_one(export_data)
|
492 |
+
|
493 |
+
# También podrías generar un archivo JSON o CSV y guardarlo en Azure Blob Storage
|
494 |
+
|
495 |
+
return True
|
496 |
+
except Exception as e:
|
497 |
+
logger.error(f"Error al exportar análisis y chat para {username}: {str(e)}")
|
498 |
+
return False
|
499 |
+
|
500 |
+
################################################-- FIN DE LA SECCIÓN DEL CHATBOT --- ###############################################################
|
501 |
+
|
502 |
+
#######################################################################################################################################################
|
503 |
+
|
504 |
+
def get_student_data(username):
|
505 |
+
if analysis_collection is None or chat_collection is None:
|
506 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
507 |
+
return None
|
508 |
+
formatted_data = {
|
509 |
+
"username": username,
|
510 |
+
"entries": [],
|
511 |
+
"entries_count": 0,
|
512 |
+
"word_count": {},
|
513 |
+
"semantic_analyses": [],
|
514 |
+
"discourse_analyses": [],
|
515 |
+
"chat_history": []
|
516 |
+
}
|
517 |
+
try:
|
518 |
+
logger.info(f"Buscando datos de análisis para el usuario: {username}")
|
519 |
+
cursor = analysis_collection.find({"username": username})
|
520 |
+
|
521 |
+
for entry in cursor:
|
522 |
+
formatted_entry = {
|
523 |
+
"timestamp": entry.get("timestamp", datetime.now(timezone.utc).isoformat()),
|
524 |
+
"analysis_type": entry.get("analysis_type", "morphosyntax")
|
525 |
+
}
|
526 |
+
|
527 |
+
if formatted_entry["analysis_type"] == "morphosyntax":
|
528 |
+
formatted_entry.update({
|
529 |
+
"text": entry.get("text", ""),
|
530 |
+
"word_count": entry.get("word_count", {}),
|
531 |
+
"arc_diagrams": entry.get("arc_diagrams", [])
|
532 |
+
})
|
533 |
+
for category, count in formatted_entry["word_count"].items():
|
534 |
+
formatted_data["word_count"][category] = formatted_data["word_count"].get(category, 0) + count
|
535 |
+
|
536 |
+
elif formatted_entry["analysis_type"] == "semantic":
|
537 |
+
formatted_entry.update({
|
538 |
+
"key_concepts": entry.get("key_concepts", []),
|
539 |
+
"graph": entry.get("graph", "")
|
540 |
+
})
|
541 |
+
formatted_data["semantic_analyses"].append(formatted_entry)
|
542 |
+
|
543 |
+
elif formatted_entry["analysis_type"] == "discourse":
|
544 |
+
formatted_entry.update({
|
545 |
+
"text1": entry.get("text1", ""),
|
546 |
+
"text2": entry.get("text2", ""),
|
547 |
+
"key_concepts1": entry.get("key_concepts1", []),
|
548 |
+
"key_concepts2": entry.get("key_concepts2", []),
|
549 |
+
"graph1": entry.get("graph1", ""),
|
550 |
+
"graph2": entry.get("graph2", ""),
|
551 |
+
"combined_graph": entry.get("combined_graph", "")
|
552 |
+
})
|
553 |
+
formatted_data["discourse_analyses"].append(formatted_entry)
|
554 |
+
|
555 |
+
formatted_data["entries"].append(formatted_entry)
|
556 |
+
|
557 |
+
formatted_data["entries_count"] = len(formatted_data["entries"])
|
558 |
+
formatted_data["entries"].sort(key=lambda x: x["timestamp"], reverse=True)
|
559 |
+
|
560 |
+
for entry in formatted_data["entries"]:
|
561 |
+
entry["timestamp"] = entry["timestamp"].isoformat()
|
562 |
+
|
563 |
+
except Exception as e:
|
564 |
+
logger.error(f"Error al obtener datos de análisis del estudiante {username}: {str(e)}")
|
565 |
+
|
566 |
+
try:
|
567 |
+
logger.info(f"Buscando historial de chat para el usuario: {username}")
|
568 |
+
chat_cursor = chat_collection.find({"username": username})
|
569 |
+
for chat in chat_cursor:
|
570 |
+
formatted_chat = {
|
571 |
+
"timestamp": chat["timestamp"].isoformat(),
|
572 |
+
"messages": chat["messages"]
|
573 |
+
}
|
574 |
+
formatted_data["chat_history"].append(formatted_chat)
|
575 |
+
|
576 |
+
formatted_data["chat_history"].sort(key=lambda x: x["timestamp"], reverse=True)
|
577 |
+
|
578 |
+
except Exception as e:
|
579 |
+
logger.error(f"Error al obtener historial de chat del estudiante {username}: {str(e)}")
|
580 |
+
logger.info(f"Datos formateados para {username}: {formatted_data}")
|
581 |
+
return formatted_data
|
582 |
+
|
583 |
+
################################################################
|
584 |
+
def get_user_analysis_summary(username):
|
585 |
+
if analysis_collection is None:
|
586 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
587 |
+
return []
|
588 |
+
try:
|
589 |
+
summary = analysis_collection.aggregate([
|
590 |
+
{"$match": {"username": username}},
|
591 |
+
{"$group": {
|
592 |
+
"_id": "$analysis_type",
|
593 |
+
"count": {"$sum": 1},
|
594 |
+
"last_analysis": {"$max": "$timestamp"}
|
595 |
+
}}
|
596 |
+
])
|
597 |
+
return list(summary)
|
598 |
+
except Exception as e:
|
599 |
+
logger.error(f"Error al obtener el resumen de análisis para el usuario {username}: {str(e)}")
|
600 |
+
return []
|
601 |
+
|
602 |
+
#######################################################################
|
603 |
+
def get_user_recent_chats(username, limit=5):
|
604 |
+
if chat_collection is None:
|
605 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
606 |
+
return []
|
607 |
+
try:
|
608 |
+
recent_chats = chat_collection.find(
|
609 |
+
{"username": username},
|
610 |
+
{"messages": {"$slice": -5}}
|
611 |
+
).sort("timestamp", -1).limit(limit)
|
612 |
+
return list(recent_chats)
|
613 |
+
except Exception as e:
|
614 |
+
logger.error(f"Error al obtener chats recientes para el usuario {username}: {str(e)}")
|
615 |
+
return []
|
616 |
+
|
617 |
+
#################################################
|
618 |
+
def get_user_analysis_details(username, analysis_type, skip=0, limit=10):
|
619 |
+
if analysis_collection is None:
|
620 |
+
logger.error("La conexión a MongoDB no está inicializada")
|
621 |
+
return []
|
622 |
+
try:
|
623 |
+
details = analysis_collection.find(
|
624 |
+
{"username": username, "analysis_type": analysis_type}
|
625 |
+
).sort("timestamp", -1).skip(skip).limit(limit)
|
626 |
+
return list(details)
|
627 |
+
except Exception as e:
|
628 |
+
logger.error(f"Error al obtener detalles de análisis para el usuario {username}: {str(e)}")
|
629 |
+
return []
|
modules/database/chat_db.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#/modules/database/chat_db.py
|
2 |
+
from .mongo_db import insert_document, find_documents
|
3 |
+
from datetime import datetime, timezone
|
4 |
+
import logging
|
5 |
+
from .database_init import get_mongodb # Asegúrate de que esta importación esté al principio del archivo
|
6 |
+
|
7 |
+
logger = logging.getLogger(__name__)
|
8 |
+
|
9 |
+
COLLECTION_NAME = 'chat_history-v3'
|
10 |
+
|
11 |
+
def store_chat_history(username, messages, analysis_type):
|
12 |
+
chat_document = {
|
13 |
+
'username': username,
|
14 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
15 |
+
'messages': messages,
|
16 |
+
'analysis_type': analysis_type
|
17 |
+
}
|
18 |
+
|
19 |
+
result = insert_document(COLLECTION_NAME, chat_document)
|
20 |
+
if result:
|
21 |
+
logger.info(f"Historial de chat guardado con ID: {result} para el usuario: {username}")
|
22 |
+
return True
|
23 |
+
return False
|
24 |
+
|
25 |
+
def get_chat_history(username, analysis_type, limit=None):
|
26 |
+
query = {"username": username}
|
27 |
+
if analysis_type:
|
28 |
+
query["analysis_type"] = analysis_type
|
29 |
+
|
30 |
+
db = get_mongodb()
|
31 |
+
collection = db['chat_history-v3']
|
32 |
+
cursor = collection.find(query).sort("timestamp", -1)
|
33 |
+
if limit:
|
34 |
+
cursor = cursor.limit(limit)
|
35 |
+
|
36 |
+
return list(cursor)
|
37 |
+
|
38 |
+
#def get_chat_history(username, analysis_type=None, limit=10):
|
39 |
+
# query = {"username": username}
|
40 |
+
# if analysis_type:
|
41 |
+
# query["analysis_type"] = analysis_type
|
42 |
+
|
43 |
+
# return find_documents(COLLECTION_NAME, query, sort=[("timestamp", -1)], limit=limit)
|
44 |
+
|
45 |
+
# Agregar funciones para actualizar y eliminar chat si es necesario
|
modules/database/database_init.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from azure.cosmos import CosmosClient
|
4 |
+
from pymongo import MongoClient
|
5 |
+
import certifi
|
6 |
+
|
7 |
+
logging.basicConfig(level=logging.DEBUG)
|
8 |
+
logger = logging.getLogger(__name__)
|
9 |
+
|
10 |
+
# Variables globales para Cosmos DB SQL API
|
11 |
+
cosmos_client = None
|
12 |
+
user_database = None
|
13 |
+
user_container = None
|
14 |
+
application_requests_container = None
|
15 |
+
user_feedback_container = None
|
16 |
+
|
17 |
+
# Variables globales para Cosmos DB MongoDB API
|
18 |
+
mongo_client = None
|
19 |
+
mongo_db = None
|
20 |
+
|
21 |
+
def initialize_cosmos_sql_connection():
|
22 |
+
global cosmos_client, user_database, user_container, application_requests_container, user_feedback_container
|
23 |
+
try:
|
24 |
+
cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
|
25 |
+
cosmos_key = os.environ.get("COSMOS_KEY")
|
26 |
+
|
27 |
+
if not cosmos_endpoint or not cosmos_key:
|
28 |
+
raise ValueError("COSMOS_ENDPOINT and COSMOS_KEY environment variables must be set")
|
29 |
+
|
30 |
+
cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
|
31 |
+
user_database = cosmos_client.get_database_client("user_database")
|
32 |
+
user_container = user_database.get_container_client("users")
|
33 |
+
application_requests_container = user_database.get_container_client("application_requests")
|
34 |
+
user_feedback_container = user_database.get_container_client("user_feedback")
|
35 |
+
|
36 |
+
logger.info("Conexión a Cosmos DB SQL API exitosa")
|
37 |
+
return True
|
38 |
+
except Exception as e:
|
39 |
+
logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}", exc_info=True)
|
40 |
+
return False
|
41 |
+
|
42 |
+
def initialize_mongodb_connection():
|
43 |
+
global mongo_client, mongo_db
|
44 |
+
try:
|
45 |
+
cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
|
46 |
+
if not cosmos_mongodb_connection_string:
|
47 |
+
raise ValueError("MONGODB_CONNECTION_STRING environment variable is not set")
|
48 |
+
|
49 |
+
mongo_client = MongoClient(cosmos_mongodb_connection_string,
|
50 |
+
tls=True,
|
51 |
+
tlsCAFile=certifi.where(),
|
52 |
+
retryWrites=False,
|
53 |
+
serverSelectionTimeoutMS=5000,
|
54 |
+
connectTimeoutMS=10000,
|
55 |
+
socketTimeoutMS=10000)
|
56 |
+
|
57 |
+
mongo_client.admin.command('ping')
|
58 |
+
|
59 |
+
mongo_db = mongo_client['aideatext_db']
|
60 |
+
|
61 |
+
logger.info("Conexión a Cosmos DB MongoDB API exitosa")
|
62 |
+
return True
|
63 |
+
except Exception as e:
|
64 |
+
logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
|
65 |
+
return False
|
66 |
+
|
67 |
+
def initialize_database_connections():
|
68 |
+
sql_success = initialize_cosmos_sql_connection()
|
69 |
+
mongodb_success = initialize_mongodb_connection()
|
70 |
+
return sql_success and mongodb_success
|
71 |
+
|
72 |
+
def get_sql_containers():
|
73 |
+
if user_container is None or application_requests_container is None or user_feedback_container is None:
|
74 |
+
initialize_cosmos_sql_connection()
|
75 |
+
return user_container, application_requests_container, user_feedback_container
|
76 |
+
|
77 |
+
def get_mongodb():
|
78 |
+
if mongo_db is None:
|
79 |
+
initialize_mongodb_connection()
|
80 |
+
return mongo_db
|
modules/database/mongo_db.py
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .database_init import get_mongodb
|
2 |
+
import logging
|
3 |
+
|
4 |
+
logger = logging.getLogger(__name__)
|
5 |
+
|
6 |
+
def get_collection(collection_name):
|
7 |
+
db = get_mongodb()
|
8 |
+
return db[collection_name]
|
9 |
+
|
10 |
+
def insert_document(collection_name, document):
|
11 |
+
collection = get_collection(collection_name)
|
12 |
+
try:
|
13 |
+
result = collection.insert_one(document)
|
14 |
+
logger.info(f"Documento insertado en {collection_name} con ID: {result.inserted_id}")
|
15 |
+
return result.inserted_id
|
16 |
+
except Exception as e:
|
17 |
+
logger.error(f"Error al insertar documento en {collection_name}: {str(e)}")
|
18 |
+
return None
|
19 |
+
|
20 |
+
def find_documents(collection_name, query, sort=None, limit=None):
|
21 |
+
collection = get_collection(collection_name)
|
22 |
+
try:
|
23 |
+
cursor = collection.find(query)
|
24 |
+
if sort:
|
25 |
+
cursor = cursor.sort(sort)
|
26 |
+
if limit:
|
27 |
+
cursor = cursor.limit(limit)
|
28 |
+
return list(cursor)
|
29 |
+
except Exception as e:
|
30 |
+
logger.error(f"Error al buscar documentos en {collection_name}: {str(e)}")
|
31 |
+
return []
|
32 |
+
|
33 |
+
def update_document(collection_name, query, update):
|
34 |
+
collection = get_collection(collection_name)
|
35 |
+
try:
|
36 |
+
result = collection.update_one(query, update)
|
37 |
+
logger.info(f"Documento actualizado en {collection_name}: {result.modified_count} modificado(s)")
|
38 |
+
return result.modified_count
|
39 |
+
except Exception as e:
|
40 |
+
logger.error(f"Error al actualizar documento en {collection_name}: {str(e)}")
|
41 |
+
return 0
|
42 |
+
|
43 |
+
def delete_document(collection_name, query):
|
44 |
+
collection = get_collection(collection_name)
|
45 |
+
try:
|
46 |
+
result = collection.delete_one(query)
|
47 |
+
logger.info(f"Documento eliminado de {collection_name}: {result.deleted_count} eliminado(s)")
|
48 |
+
return result.deleted_count
|
49 |
+
except Exception as e:
|
50 |
+
logger.error(f"Error al eliminar documento de {collection_name}: {str(e)}")
|
51 |
+
return 0
|
modules/database/morphosintax_mongo_db.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#/modules/database/morphosintax_mongo_db.py
|
2 |
+
from .mongo_db import insert_document, find_documents, update_document, delete_document
|
3 |
+
from ..utils.svg_to_png_converter import process_and_save_svg_diagrams
|
4 |
+
from datetime import datetime, timezone
|
5 |
+
import logging
|
6 |
+
|
7 |
+
logger = logging.getLogger(__name__)
|
8 |
+
|
9 |
+
COLLECTION_NAME = 'student_morphosyntax_analysis'
|
10 |
+
|
11 |
+
def store_student_morphosyntax_result(username, text, arc_diagrams):
|
12 |
+
analysis_document = {
|
13 |
+
'username': username,
|
14 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
15 |
+
'text': text,
|
16 |
+
'arc_diagrams': arc_diagrams,
|
17 |
+
'analysis_type': 'morphosyntax'
|
18 |
+
}
|
19 |
+
|
20 |
+
result = insert_document(COLLECTION_NAME, analysis_document)
|
21 |
+
if result:
|
22 |
+
# Procesar y guardar los diagramas SVG como PNG
|
23 |
+
png_ids = process_and_save_svg_diagrams(username, str(result), arc_diagrams)
|
24 |
+
|
25 |
+
# Actualizar el documento con los IDs de los PNGs
|
26 |
+
update_document(COLLECTION_NAME, {'_id': result}, {'$set': {'png_diagram_ids': png_ids}})
|
27 |
+
|
28 |
+
logger.info(f"Análisis morfosintáctico del estudiante guardado con ID: {result} para el usuario: {username}")
|
29 |
+
return True
|
30 |
+
return False
|
31 |
+
|
32 |
+
def get_student_morphosyntax_analysis(username, limit=10):
|
33 |
+
query = {"username": username, "analysis_type": "morphosyntax"}
|
34 |
+
return find_documents(COLLECTION_NAME, query, sort=[("timestamp", -1)], limit=limit)
|
35 |
+
|
36 |
+
def update_student_morphosyntax_analysis(analysis_id, update_data):
|
37 |
+
query = {"_id": analysis_id}
|
38 |
+
update = {"$set": update_data}
|
39 |
+
return update_document(COLLECTION_NAME, query, update)
|
40 |
+
|
41 |
+
def delete_student_morphosyntax_analysis(analysis_id):
|
42 |
+
query = {"_id": analysis_id}
|
43 |
+
return delete_document(COLLECTION_NAME, query)
|
44 |
+
|
45 |
+
def get_student_morphosyntax_data(username):
|
46 |
+
analyses = get_student_morphosyntax_analysis(username, limit=None) # Obtener todos los análisis
|
47 |
+
return {
|
48 |
+
'entries': analyses
|
49 |
+
}
|
modules/database/morphosintaxis_export.py
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from io import BytesIO
|
2 |
+
from reportlab.lib import colors
|
3 |
+
from reportlab.lib.pagesizes import letter
|
4 |
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak
|
5 |
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
6 |
+
from reportlab.lib.units import cm
|
7 |
+
from svglib.svglib import svg2rlg
|
8 |
+
from reportlab.graphics import renderPM
|
9 |
+
import base64
|
10 |
+
import cairosvg
|
11 |
+
from reportlab.graphics import renderPDF
|
12 |
+
from reportlab.lib.utils import ImageReader
|
13 |
+
|
14 |
+
#importaciones locales
|
15 |
+
from .morphosintax_mongo_db import get_student_morphosyntax_data
|
16 |
+
from .chat_db import get_chat_history
|
17 |
+
|
18 |
+
# Placeholder para el logo
|
19 |
+
LOGO_PATH = "assets\img\logo_92x92.png" # Reemplaza esto con la ruta real de tu logo
|
20 |
+
|
21 |
+
# Definir el tamaño de página carta manualmente (612 x 792 puntos)
|
22 |
+
LETTER_SIZE = (612, 792)
|
23 |
+
|
24 |
+
def add_logo(canvas, doc):
|
25 |
+
logo = Image(LOGO_PATH, width=2*cm, height=2*cm)
|
26 |
+
logo.drawOn(canvas, doc.leftMargin, doc.height + doc.topMargin - 0.5*cm)
|
27 |
+
|
28 |
+
def export_user_interactions(username, analysis_type):
|
29 |
+
# Obtener historial de chat (que ahora incluye los análisis morfosintácticos)
|
30 |
+
chat_history = get_chat_history(username, analysis_type)
|
31 |
+
|
32 |
+
# Crear un PDF
|
33 |
+
buffer = BytesIO()
|
34 |
+
doc = SimpleDocTemplate(
|
35 |
+
buffer,
|
36 |
+
pagesize=letter,
|
37 |
+
rightMargin=2*cm,
|
38 |
+
leftMargin=2*cm,
|
39 |
+
topMargin=2*cm,
|
40 |
+
bottomMargin=2*cm
|
41 |
+
)
|
42 |
+
|
43 |
+
story = []
|
44 |
+
styles = getSampleStyleSheet()
|
45 |
+
|
46 |
+
# Título
|
47 |
+
story.append(Paragraph(f"Interacciones de {username} - Análisis {analysis_type}", styles['Title']))
|
48 |
+
story.append(Spacer(1, 0.5*cm))
|
49 |
+
|
50 |
+
# Historial del chat y análisis
|
51 |
+
for entry in chat_history:
|
52 |
+
for message in entry['messages']:
|
53 |
+
role = message['role']
|
54 |
+
content = message['content']
|
55 |
+
story.append(Paragraph(f"<b>{role.capitalize()}:</b> {content}", styles['BodyText']))
|
56 |
+
story.append(Spacer(1, 0.25*cm))
|
57 |
+
|
58 |
+
# Si hay visualizaciones (diagramas SVG), convertirlas a imagen y añadirlas
|
59 |
+
if 'visualizations' in message and message['visualizations']:
|
60 |
+
for svg in message['visualizations']:
|
61 |
+
drawing = svg2rlg(BytesIO(svg.encode('utf-8')))
|
62 |
+
img_data = BytesIO()
|
63 |
+
renderPM.drawToFile(drawing, img_data, fmt="PNG")
|
64 |
+
img_data.seek(0)
|
65 |
+
img = Image(img_data, width=15*cm, height=7.5*cm)
|
66 |
+
story.append(img)
|
67 |
+
story.append(Spacer(1, 0.5*cm))
|
68 |
+
|
69 |
+
story.append(PageBreak())
|
70 |
+
|
71 |
+
# Construir el PDF
|
72 |
+
doc.build(story)
|
73 |
+
buffer.seek(0)
|
74 |
+
return buffer
|
75 |
+
|
76 |
+
# Uso en Streamlit:
|
77 |
+
# pdf_buffer = export_user_interactions(username, 'morphosyntax')
|
78 |
+
# st.download_button(label="Descargar PDF", data=pdf_buffer, file_name="interacciones.pdf", mime="application/pdf")
|
modules/database/morphosintaxis_export_v1.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# database_export.py
|
2 |
+
|
3 |
+
import pandas as pd
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
from io import BytesIO
|
6 |
+
#importaciones locales
|
7 |
+
from .morphosintax_mongo_db import get_student_morphosyntax_analysis
|
8 |
+
from .chat_db import get_chat_history
|
9 |
+
|
10 |
+
|
11 |
+
def export_user_interactions(username, analysis_type):
|
12 |
+
# Obtener historial de chat (que ahora incluye los análisis morfosintácticos)
|
13 |
+
chat_history = get_chat_history(username, analysis_type)
|
14 |
+
|
15 |
+
# Crear un PDF
|
16 |
+
buffer = BytesIO()
|
17 |
+
doc = SimpleDocTemplate(
|
18 |
+
buffer,
|
19 |
+
pagesize=letter,
|
20 |
+
rightMargin=2*cm,
|
21 |
+
leftMargin=2*cm,
|
22 |
+
topMargin=2*cm,
|
23 |
+
bottomMargin=2*cm
|
24 |
+
)
|
25 |
+
|
26 |
+
story = []
|
27 |
+
styles = getSampleStyleSheet()
|
28 |
+
|
29 |
+
# Título
|
30 |
+
story.append(Paragraph(f"Interacciones de {username} - Análisis {analysis_type}", styles['Title']))
|
31 |
+
story.append(Spacer(1, 0.5*cm))
|
32 |
+
|
33 |
+
# Historial del chat y análisis
|
34 |
+
for entry in chat_history:
|
35 |
+
for message in entry['messages']:
|
36 |
+
role = message['role']
|
37 |
+
content = message['content']
|
38 |
+
story.append(Paragraph(f"<b>{role.capitalize()}:</b> {content}", styles['BodyText']))
|
39 |
+
story.append(Spacer(1, 0.25*cm))
|
40 |
+
|
41 |
+
# Si hay visualizaciones (diagramas SVG), convertirlas a imagen y añadirlas
|
42 |
+
if 'visualizations' in message and message['visualizations']:
|
43 |
+
for svg in message['visualizations']:
|
44 |
+
drawing = svg2rlg(BytesIO(svg.encode('utf-8')))
|
45 |
+
img_data = BytesIO()
|
46 |
+
renderPM.drawToFile(drawing, img_data, fmt="PNG")
|
47 |
+
img_data.seek(0)
|
48 |
+
img = Image(img_data, width=15*cm, height=7.5*cm)
|
49 |
+
story.append(img)
|
50 |
+
story.append(Spacer(1, 0.5*cm))
|
51 |
+
|
52 |
+
story.append(PageBreak())
|
53 |
+
|
54 |
+
# Construir el PDF
|
55 |
+
doc.build(story)
|
56 |
+
buffer.seek(0)
|
57 |
+
return buffer
|
58 |
+
|
59 |
+
#def export_user_interactions(username, analysis_type):
|
60 |
+
# Obtener análisis morfosintáctico
|
61 |
+
#morphosyntax_data = get_student_morphosyntax_analysis(username)
|
62 |
+
|
63 |
+
# Obtener historial de chat
|
64 |
+
#chat_history = get_chat_history(username, analysis_type)
|
65 |
+
|
66 |
+
# Crear un DataFrame con los datos
|
67 |
+
#df = pd.DataFrame({
|
68 |
+
# 'Timestamp': [entry['timestamp'] for entry in chat_history],
|
69 |
+
# 'Role': [msg['role'] for entry in chat_history for msg in entry['messages']],
|
70 |
+
# 'Content': [msg['content'] for entry in chat_history for msg in entry['messages']]
|
71 |
+
#})
|
72 |
+
|
73 |
+
# Crear un PDF
|
74 |
+
#buffer = BytesIO()
|
75 |
+
#plt.figure(figsize=(12, 6))
|
76 |
+
#plt.axis('off')
|
77 |
+
#plt.text(0.5, 0.98, f"Interacciones de {username} - Análisis {analysis_type}", ha='center', va='top', fontsize=16)
|
78 |
+
#plt.text(0.5, 0.95, f"Total de interacciones: {len(df)}", ha='center', va='top', fontsize=12)
|
79 |
+
|
80 |
+
# Añadir tabla con las interacciones
|
81 |
+
#plt.table(cellText=df.values, colLabels=df.columns, cellLoc='center', loc='center')
|
82 |
+
|
83 |
+
# Añadir diagramas de arco si es análisis morfosintáctico
|
84 |
+
#if analysis_type == 'morphosyntax' and morphosyntax_data:
|
85 |
+
# for i, analysis in enumerate(morphosyntax_data):
|
86 |
+
# plt.figure(figsize=(12, 6))
|
87 |
+
# plt.axis('off')
|
88 |
+
# plt.text(0.5, 0.98, f"Diagrama de Arco {i+1}", ha='center', va='top', fontsize=16)
|
89 |
+
# plt.imshow(analysis['arc_diagrams'][0]) # Asumiendo que arc_diagrams es una lista de imágenes
|
90 |
+
|
91 |
+
#plt.savefig(buffer, format='pdf', bbox_inches='tight')
|
92 |
+
#buffer.seek(0)
|
93 |
+
#return buffer
|
94 |
+
|
95 |
+
# Uso:
|
96 |
+
# pdf_buffer = export_user_interactions(username, 'morphosyntax')
|
97 |
+
# st.download_button(label="Descargar PDF", data=pdf_buffer, file_name="interacciones.pdf", mime="application/pdf")
|
modules/database/sql_db.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .database_init import get_sql_containers
|
2 |
+
from datetime import datetime, timezone
|
3 |
+
import logging
|
4 |
+
import bcrypt
|
5 |
+
import uuid
|
6 |
+
|
7 |
+
logger = logging.getLogger(__name__)
|
8 |
+
|
9 |
+
def get_user(username, role=None):
|
10 |
+
user_container, _, _ = get_sql_containers()
|
11 |
+
try:
|
12 |
+
query = f"SELECT * FROM c WHERE c.id = '{username}'"
|
13 |
+
if role:
|
14 |
+
query += f" AND c.role = '{role}'"
|
15 |
+
items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
|
16 |
+
return items[0] if items else None
|
17 |
+
except Exception as e:
|
18 |
+
logger.error(f"Error al obtener usuario {username}: {str(e)}")
|
19 |
+
return None
|
20 |
+
|
21 |
+
def get_admin_user(username):
|
22 |
+
return get_user(username, role='Administrador')
|
23 |
+
|
24 |
+
def get_student_user(username):
|
25 |
+
return get_user(username, role='Estudiante')
|
26 |
+
|
27 |
+
def get_teacher_user(username):
|
28 |
+
return get_user(username, role='Profesor')
|
29 |
+
|
30 |
+
def create_user(username, password, role, additional_info=None):
|
31 |
+
user_container, _, _ = get_sql_containers()
|
32 |
+
try:
|
33 |
+
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
34 |
+
user_data = {
|
35 |
+
'id': username,
|
36 |
+
'password': hashed_password,
|
37 |
+
'role': role,
|
38 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
39 |
+
'additional_info': additional_info or {}
|
40 |
+
}
|
41 |
+
user_container.create_item(body=user_data)
|
42 |
+
logger.info(f"Usuario {role} creado: {username}")
|
43 |
+
return True
|
44 |
+
except Exception as e:
|
45 |
+
logger.error(f"Error al crear usuario {role}: {str(e)}")
|
46 |
+
return False
|
47 |
+
|
48 |
+
def create_student_user(username, password, additional_info=None):
|
49 |
+
return create_user(username, password, 'Estudiante', additional_info)
|
50 |
+
|
51 |
+
def create_teacher_user(username, password, additional_info=None):
|
52 |
+
return create_user(username, password, 'Profesor', additional_info)
|
53 |
+
|
54 |
+
def create_admin_user(username, password, additional_info=None):
|
55 |
+
return create_user(username, password, 'Administrador', additional_info)
|
56 |
+
|
57 |
+
|
58 |
+
###########################################################
|
59 |
+
def update_student_user(username, new_info):
|
60 |
+
user_container, _, _ = get_sql_containers()
|
61 |
+
try:
|
62 |
+
user = get_student_user(username)
|
63 |
+
if user:
|
64 |
+
user['additional_info'].update(new_info)
|
65 |
+
user_container.upsert_item(body=user)
|
66 |
+
logger.info(f"Información del estudiante actualizada: {username}")
|
67 |
+
return True
|
68 |
+
else:
|
69 |
+
logger.warning(f"Intento de actualizar estudiante no existente: {username}")
|
70 |
+
return False
|
71 |
+
except Exception as e:
|
72 |
+
logger.error(f"Error al actualizar información del estudiante {username}: {str(e)}")
|
73 |
+
return False
|
74 |
+
|
75 |
+
|
76 |
+
def delete_student_user(username):
|
77 |
+
user_container, _, _ = get_sql_containers()
|
78 |
+
try:
|
79 |
+
user = get_student_user(username)
|
80 |
+
if user:
|
81 |
+
user_container.delete_item(item=user['id'], partition_key=username)
|
82 |
+
logger.info(f"Estudiante eliminado: {username}")
|
83 |
+
return True
|
84 |
+
else:
|
85 |
+
logger.warning(f"Intento de eliminar estudiante no existente: {username}")
|
86 |
+
return False
|
87 |
+
except Exception as e:
|
88 |
+
logger.error(f"Error al eliminar estudiante {username}: {str(e)}")
|
89 |
+
return False
|
90 |
+
|
91 |
+
def store_application_request(name, lastname, email, institution, current_role, desired_role, reason):
|
92 |
+
_, application_requests_container, _ = get_sql_containers()
|
93 |
+
try:
|
94 |
+
application_request = {
|
95 |
+
"id": str(uuid.uuid4()),
|
96 |
+
"name": name,
|
97 |
+
"lastname": lastname,
|
98 |
+
"email": email,
|
99 |
+
"institution": institution,
|
100 |
+
"current_role": current_role,
|
101 |
+
"desired_role": desired_role,
|
102 |
+
"reason": reason,
|
103 |
+
"requestDate": datetime.utcnow().isoformat()
|
104 |
+
}
|
105 |
+
application_requests_container.create_item(body=application_request)
|
106 |
+
logger.info(f"Solicitud de aplicación almacenada para el email: {email}")
|
107 |
+
return True
|
108 |
+
except Exception as e:
|
109 |
+
logger.error(f"Error al almacenar la solicitud de aplicación: {str(e)}")
|
110 |
+
return False
|
111 |
+
|
112 |
+
def store_student_feedback(username, name, email, feedback):
|
113 |
+
_, _, user_feedback_container = get_sql_containers()
|
114 |
+
try:
|
115 |
+
feedback_item = {
|
116 |
+
"id": str(uuid.uuid4()),
|
117 |
+
"username": username,
|
118 |
+
"name": name,
|
119 |
+
"email": email,
|
120 |
+
"feedback": feedback,
|
121 |
+
"role": "Estudiante",
|
122 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
123 |
+
}
|
124 |
+
result = user_feedback_container.create_item(body=feedback_item)
|
125 |
+
logger.info(f"Feedback de estudiante almacenado con ID: {result['id']} para el usuario: {username}")
|
126 |
+
return True
|
127 |
+
except Exception as e:
|
128 |
+
logger.error(f"Error al almacenar el feedback del estudiante {username}: {str(e)}")
|
129 |
+
return False
|
modules/database/txt.txt
ADDED
File without changes
|