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
|