Upload 281 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +16 -0
- src/assets/img/AIdeaTextCard.jpg +3 -0
- src/assets/img/AIdeaText_Logo_vectores.png +3 -0
- src/assets/img/ALPHA_Startup Badges.png +3 -0
- src/assets/img/Ico-20x20.ico +0 -0
- src/assets/img/Logo20x20.png +0 -0
- src/assets/img/Logo24x24.png +0 -0
- src/assets/img/Logo32x32.png +0 -0
- src/assets/img/Logo40x40.png +0 -0
- src/assets/img/Logo48x48.png +0 -0
- src/assets/img/Logo64x64.png +0 -0
- src/assets/img/Logo_100x100.png +0 -0
- src/assets/img/Logo_300x300.png +0 -0
- src/assets/img/Mesa de trabajo 1png 0.3.png +0 -0
- src/assets/img/aideaText-ICO.png +0 -0
- src/assets/img/aideaText-Logo-32x32.png +0 -0
- src/assets/img/aideaText_icon.ico +0 -0
- src/assets/img/aideaText_logo.png +0 -0
- src/assets/img/assets_img_logo_92x92.ico +3 -0
- src/assets/img/logo120x120.png +0 -0
- src/assets/img/logo_92x92.jpg +0 -0
- src/assets/img/logo_92x92.png +0 -0
- src/assets/img/socialmedia/AIdeaTextCard.jpg +3 -0
- src/assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg +3 -0
- src/assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg +3 -0
- src/assets/img/socialmedia/_MG_2535.jpg +3 -0
- src/assets/img/socialmedia/_MG_2585.jpg +3 -0
- src/assets/img/socialmedia/_MG_2587.jpg +3 -0
- src/assets/img/socialmedia/_MG_2590.jpg +3 -0
- src/assets/img/socialmedia/_MG_2678.jpg +3 -0
- src/assets/img/socialmedia/_MG_2727.jpg +3 -0
- src/assets/img/socialmedia/_MG_2735.jpg +3 -0
- src/assets/img/socialmedia/_MG_2790.jpg +3 -0
- src/assets/img/socialmedia/_MG_2845.JPG +3 -0
- src/assets/img/socialmedia/txt.txt +1 -0
- src/assets/img/text.txt +0 -0
- src/modules/23-7-2024_auth.py +135 -0
- src/modules/23-7-2024_ui.py +344 -0
- src/modules/__init__.py +319 -0
- src/modules/__init__Old-V3.py +180 -0
- src/modules/__pycache__/__init__.cpython-311.pyc +0 -0
- src/modules/admin/__init__.py +0 -0
- src/modules/admin/__pycache__/__init__.cpython-311.pyc +0 -0
- src/modules/admin/__pycache__/admin_ui.cpython-311.pyc +0 -0
- src/modules/admin/admin_ui.py +250 -0
- src/modules/admin/txt.txt +0 -0
- src/modules/auth/__init__.py +0 -0
- src/modules/auth/__pycache__/__init__.cpython-311.pyc +0 -0
- src/modules/auth/__pycache__/auth.cpython-311.pyc +0 -0
- src/modules/auth/auth.py +195 -0
.gitattributes
CHANGED
@@ -33,3 +33,19 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
src/assets/img/AIdeaText_Logo_vectores.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
src/assets/img/AIdeaTextCard.jpg filter=lfs diff=lfs merge=lfs -text
|
38 |
+
src/assets/img/ALPHA_Startup[[:space:]]Badges.png filter=lfs diff=lfs merge=lfs -text
|
39 |
+
src/assets/img/assets_img_logo_92x92.ico filter=lfs diff=lfs merge=lfs -text
|
40 |
+
src/assets/img/socialmedia/_MG_2535.jpg filter=lfs diff=lfs merge=lfs -text
|
41 |
+
src/assets/img/socialmedia/_MG_2585.jpg filter=lfs diff=lfs merge=lfs -text
|
42 |
+
src/assets/img/socialmedia/_MG_2587.jpg filter=lfs diff=lfs merge=lfs -text
|
43 |
+
src/assets/img/socialmedia/_MG_2590.jpg filter=lfs diff=lfs merge=lfs -text
|
44 |
+
src/assets/img/socialmedia/_MG_2678.jpg filter=lfs diff=lfs merge=lfs -text
|
45 |
+
src/assets/img/socialmedia/_MG_2727.jpg filter=lfs diff=lfs merge=lfs -text
|
46 |
+
src/assets/img/socialmedia/_MG_2735.jpg filter=lfs diff=lfs merge=lfs -text
|
47 |
+
src/assets/img/socialmedia/_MG_2790.jpg filter=lfs diff=lfs merge=lfs -text
|
48 |
+
src/assets/img/socialmedia/_MG_2845.JPG filter=lfs diff=lfs merge=lfs -text
|
49 |
+
src/assets/img/socialmedia/AIdeaTextCard.jpg filter=lfs diff=lfs merge=lfs -text
|
50 |
+
src/assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg filter=lfs diff=lfs merge=lfs -text
|
51 |
+
src/assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg filter=lfs diff=lfs merge=lfs -text
|
src/assets/img/AIdeaTextCard.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/AIdeaText_Logo_vectores.png
ADDED
![]() |
Git LFS Details
|
src/assets/img/ALPHA_Startup Badges.png
ADDED
![]() |
Git LFS Details
|
src/assets/img/Ico-20x20.ico
ADDED
|
src/assets/img/Logo20x20.png
ADDED
![]() |
src/assets/img/Logo24x24.png
ADDED
![]() |
src/assets/img/Logo32x32.png
ADDED
![]() |
src/assets/img/Logo40x40.png
ADDED
![]() |
src/assets/img/Logo48x48.png
ADDED
![]() |
src/assets/img/Logo64x64.png
ADDED
![]() |
src/assets/img/Logo_100x100.png
ADDED
![]() |
src/assets/img/Logo_300x300.png
ADDED
![]() |
src/assets/img/Mesa de trabajo 1png 0.3.png
ADDED
![]() |
src/assets/img/aideaText-ICO.png
ADDED
![]() |
src/assets/img/aideaText-Logo-32x32.png
ADDED
![]() |
src/assets/img/aideaText_icon.ico
ADDED
|
src/assets/img/aideaText_logo.png
ADDED
![]() |
src/assets/img/assets_img_logo_92x92.ico
ADDED
|
Git LFS Details
|
src/assets/img/logo120x120.png
ADDED
![]() |
src/assets/img/logo_92x92.jpg
ADDED
![]() |
src/assets/img/logo_92x92.png
ADDED
![]() |
src/assets/img/socialmedia/AIdeaTextCard.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2535.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2585.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2587.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2590.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2678.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2727.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2735.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2790.jpg
ADDED
![]() |
Git LFS Details
|
src/assets/img/socialmedia/_MG_2845.JPG
ADDED
|
Git LFS Details
|
src/assets/img/socialmedia/txt.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
txtx
|
src/assets/img/text.txt
ADDED
File without changes
|
src/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
|
src/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
|
src/modules/__init__.py
ADDED
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
# Agregar nuevo import para current_situation
|
13 |
+
def load_current_situation_functions():
|
14 |
+
"""
|
15 |
+
Carga las funciones relacionadas con el análisis de situación actual.
|
16 |
+
Returns:
|
17 |
+
dict: Diccionario con las funciones de situación actual
|
18 |
+
"""
|
19 |
+
from .studentact.current_situation_interface import (
|
20 |
+
display_current_situation_interface,
|
21 |
+
display_metrics_in_one_row,
|
22 |
+
display_empty_metrics_row,
|
23 |
+
display_metrics_analysis,
|
24 |
+
display_comparison_results,
|
25 |
+
display_metrics_and_suggestions,
|
26 |
+
display_radar_chart,
|
27 |
+
suggest_improvement_tools,
|
28 |
+
prepare_metrics_config
|
29 |
+
)
|
30 |
+
|
31 |
+
from .studentact.current_situation_analysis import (
|
32 |
+
correlate_metrics,
|
33 |
+
analyze_text_dimensions,
|
34 |
+
analyze_clarity,
|
35 |
+
analyze_vocabulary_diversity,
|
36 |
+
analyze_cohesion,
|
37 |
+
analyze_structure,
|
38 |
+
get_dependency_depths,
|
39 |
+
normalize_score,
|
40 |
+
generate_sentence_graphs,
|
41 |
+
generate_word_connections,
|
42 |
+
generate_connection_paths,
|
43 |
+
create_vocabulary_network,
|
44 |
+
create_syntax_complexity_graph,
|
45 |
+
create_cohesion_heatmap
|
46 |
+
)
|
47 |
+
|
48 |
+
return {
|
49 |
+
'display_current_situation_interface': display_current_situation_interface,
|
50 |
+
'display_metrics_in_one_row': display_metrics_in_one_line,
|
51 |
+
'display_empty_metrics_row': display_empty_metrics_row,
|
52 |
+
'display_metrics_analysis': display_metrics_analysis,
|
53 |
+
'display_comparison_results': display_comparison_results,
|
54 |
+
'display_metrics_and_suggestions': display_metrics_and_suggestions,
|
55 |
+
'display_radar_chart': display_radar_chart,
|
56 |
+
'suggest_improvement_tools': suggest_improvement_tools,
|
57 |
+
'prepare_metrics_config': prepare_metrics_config,
|
58 |
+
'display_empty_metrics_row' : display_empty_metrics_row,
|
59 |
+
'correlate_metrics': correlate_metrics,
|
60 |
+
'analyze_text_dimensions': analyze_text_dimensions,
|
61 |
+
'analyze_clarity': analyze_clarity,
|
62 |
+
'analyze_vocabulary_diversity': analyze_vocabulary_diversity,
|
63 |
+
'analyze_cohesion': analyze_cohesion,
|
64 |
+
'analyze_structure': analyze_structure,
|
65 |
+
'get_dependency_depths': get_dependency_depths,
|
66 |
+
'normalize_score': normalize_score,
|
67 |
+
'generate_sentence_graphs': generate_sentence_graphs,
|
68 |
+
'generate_word_connections': generate_word_connections,
|
69 |
+
'generate_connection_paths': generate_connection_paths,
|
70 |
+
'create_vocabulary_network': create_vocabulary_network,
|
71 |
+
'create_syntax_complexity_graph': create_syntax_complexity_graph,
|
72 |
+
'create_cohesion_heatmap': create_cohesion_heatmap
|
73 |
+
}
|
74 |
+
|
75 |
+
def load_database_functions():
|
76 |
+
|
77 |
+
from .database.database_init import (
|
78 |
+
initialize_database_connections,
|
79 |
+
get_container,
|
80 |
+
get_mongodb
|
81 |
+
)
|
82 |
+
|
83 |
+
# Importar funciones SQL
|
84 |
+
from .database.sql_db import (
|
85 |
+
create_student_user,
|
86 |
+
get_student_user,
|
87 |
+
update_student_user,
|
88 |
+
delete_student_user,
|
89 |
+
store_application_request,
|
90 |
+
store_student_feedback,
|
91 |
+
record_login,
|
92 |
+
record_logout,
|
93 |
+
get_recent_sessions,
|
94 |
+
get_user_total_time
|
95 |
+
)
|
96 |
+
|
97 |
+
from .database.mongo_db import (
|
98 |
+
get_collection,
|
99 |
+
insert_document,
|
100 |
+
find_documents,
|
101 |
+
update_document,
|
102 |
+
delete_document,
|
103 |
+
)
|
104 |
+
|
105 |
+
from .database.morphosintax_mongo_db import (
|
106 |
+
store_student_morphosyntax_result,
|
107 |
+
get_student_morphosyntax_analysis,
|
108 |
+
update_student_morphosyntax_analysis,
|
109 |
+
delete_student_morphosyntax_analysis,
|
110 |
+
get_student_morphosyntax_data
|
111 |
+
)
|
112 |
+
|
113 |
+
from .database.semantic_mongo_db import (
|
114 |
+
store_student_semantic_result,
|
115 |
+
get_student_semantic_analysis,
|
116 |
+
update_student_semantic_analysis,
|
117 |
+
delete_student_semantic_analysis,
|
118 |
+
get_student_semantic_data
|
119 |
+
)
|
120 |
+
|
121 |
+
from .database.discourse_mongo_db import (
|
122 |
+
store_student_discourse_result,
|
123 |
+
get_student_discourse_analysis,
|
124 |
+
update_student_discourse_analysis,
|
125 |
+
delete_student_discourse_analysis,
|
126 |
+
get_student_discourse_data
|
127 |
+
)
|
128 |
+
|
129 |
+
# Agregar nueva importación para current_situation
|
130 |
+
from .database.current_situation_mongo_db import (
|
131 |
+
store_current_situation_result,
|
132 |
+
verify_storage,
|
133 |
+
get_recent_sessions,
|
134 |
+
get_student_situation_history,
|
135 |
+
update_exercise_status
|
136 |
+
)
|
137 |
+
|
138 |
+
# Importar nuevas funciones de análisis morfosintáctico iterativo
|
139 |
+
from .morphosyntax_iterative_mongo_db import (
|
140 |
+
store_student_morphosyntax_base,
|
141 |
+
store_student_morphosyntax_iteration,
|
142 |
+
get_student_morphosyntax_analysis,
|
143 |
+
update_student_morphosyntax_analysis,
|
144 |
+
delete_student_morphosyntax_analysis,
|
145 |
+
get_student_morphosyntax_data
|
146 |
+
)
|
147 |
+
|
148 |
+
from .database.chat_mongo_db import store_chat_history, get_chat_history
|
149 |
+
|
150 |
+
return {
|
151 |
+
# Nuevas funciones morfosintácticas iterativas
|
152 |
+
'store_student_morphosyntax_base': store_student_morphosyntax_base,
|
153 |
+
'store_student_morphosyntax_iteration': store_student_morphosyntax_iteration,
|
154 |
+
'get_student_morphosyntax_iterative_analysis': get_student_morphosyntax_analysis, # Renombrada para evitar conflicto
|
155 |
+
'update_student_morphosyntax_iterative': update_student_morphosyntax_analysis, # Renombrada para evitar conflicto
|
156 |
+
'delete_student_morphosyntax_iterative': delete_student_morphosyntax_analysis, # Renombrada para evitar conflicto
|
157 |
+
'get_student_morphosyntax_iterative_data': get_student_morphosyntax_data,
|
158 |
+
'store_current_situation_result': store_current_situation_result,
|
159 |
+
'verify_storage': verify_storage,
|
160 |
+
'get_recent_sessions': get_recent_sessions,
|
161 |
+
'get_student_situation_history': get_student_situation_history,
|
162 |
+
'update_exercise_status': update_exercise_status,
|
163 |
+
'initialize_database_connections': initialize_database_connections,
|
164 |
+
'get_container': get_container,
|
165 |
+
'get_mongodb': get_mongodb,
|
166 |
+
'create_student_user': create_student_user,
|
167 |
+
'get_student_user': get_student_user,
|
168 |
+
'update_student_user': update_student_user,
|
169 |
+
'delete_student_user': delete_student_user,
|
170 |
+
'store_application_request': store_application_request,
|
171 |
+
'store_student_feedback': store_student_feedback,
|
172 |
+
'get_collection': get_collection,
|
173 |
+
'insert_document': insert_document,
|
174 |
+
'find_documents': find_documents,
|
175 |
+
'update_document': update_document,
|
176 |
+
'delete_document': delete_document,
|
177 |
+
'store_student_morphosyntax_result': store_student_morphosyntax_result,
|
178 |
+
'get_student_morphosyntax_analysis': get_student_morphosyntax_analysis,
|
179 |
+
'update_student_morphosyntax_analysis': update_student_morphosyntax_analysis,
|
180 |
+
'delete_student_morphosyntax_analysis': delete_student_morphosyntax_analysis,
|
181 |
+
'get_student_morphosyntax_data': get_student_morphosyntax_data,
|
182 |
+
'store_student_semantic_result': store_student_semantic_result,
|
183 |
+
'get_student_semantic_analysis': get_student_semantic_analysis,
|
184 |
+
'update_student_semantic_analysis': update_student_semantic_analysis,
|
185 |
+
'delete_student_semantic_analysis': delete_student_semantic_analysis,
|
186 |
+
'get_student_semantic_data': get_student_semantic_data,
|
187 |
+
'store_chat_history': store_chat_history,
|
188 |
+
'get_chat_history': get_chat_history,
|
189 |
+
'store_student_discourse_result': store_student_discourse_result,
|
190 |
+
'get_student_discourse_analysis': get_student_discourse_analysis,
|
191 |
+
'update_student_discourse_analysis': update_student_discourse_analysis,
|
192 |
+
'delete_student_discourse_analysis': delete_student_discourse_analysis,
|
193 |
+
'get_student_discourse_data': get_student_discourse_data,
|
194 |
+
'record_login': record_login,
|
195 |
+
'record_logout': record_logout,
|
196 |
+
'get_recent_sessions': get_recent_sessions,
|
197 |
+
'get_user_total_time': get_user_total_time
|
198 |
+
}
|
199 |
+
|
200 |
+
def load_ui_functions():
|
201 |
+
# No importamos nada de ui.py aquí
|
202 |
+
return {} # Retornamos un diccionario vacío
|
203 |
+
|
204 |
+
def load_student_activities_v2_functions():
|
205 |
+
from .studentact.student_activities_v2 import display_student_activities
|
206 |
+
return {
|
207 |
+
'display_student_progress': display_student_activities
|
208 |
+
}
|
209 |
+
|
210 |
+
def load_morphosyntax_functions():
|
211 |
+
from .morphosyntax.morphosyntax_interface import (
|
212 |
+
initialize_arc_analysis_state,
|
213 |
+
reset_arc_analysis_state,
|
214 |
+
display_arc_diagrams,
|
215 |
+
display_morphosyntax_results
|
216 |
+
)
|
217 |
+
from .morphosyntax.morphosyntax_process import (
|
218 |
+
process_morphosyntactic_input,
|
219 |
+
format_analysis_results,
|
220 |
+
perform_advanced_morphosyntactic_analysis # Añadir esta función
|
221 |
+
)
|
222 |
+
|
223 |
+
return {
|
224 |
+
#Interface
|
225 |
+
'initialize_arc_analysis_state': initialize_arc_analysis_state,
|
226 |
+
'reset_arc_analysis_state': reset_morpho_state,
|
227 |
+
'display_arc_diagrams': display_arc_diagrams,
|
228 |
+
'display_morphosyntax_interface': display_morphosyntax_interface,
|
229 |
+
#Process
|
230 |
+
'process_morphosyntactic_input': process_morphosyntactic_input,
|
231 |
+
'format_analysis_results': format_analysis_results,
|
232 |
+
'perform_advanced_morphosyntactic_analysis': perform_advanced_morphosyntactic_analysis
|
233 |
+
}
|
234 |
+
|
235 |
+
def load_semantic_functions():
|
236 |
+
from .semantic.semantic_interface import (
|
237 |
+
display_semantic_interface,
|
238 |
+
display_semantic_results
|
239 |
+
)
|
240 |
+
from modules.semantic.semantic_process import (
|
241 |
+
process_semantic_input,
|
242 |
+
format_semantic_results
|
243 |
+
)
|
244 |
+
|
245 |
+
return {
|
246 |
+
'display_semantic_interface': display_semantic_interface,
|
247 |
+
'display_semantic_results': display_semantic_results,
|
248 |
+
'process_semantic_input': process_semantic_input,
|
249 |
+
'format_semantic_results': format_analysis_results,
|
250 |
+
}
|
251 |
+
|
252 |
+
|
253 |
+
def load_discourse_functions():
|
254 |
+
from .discourse.discourse_interface import (
|
255 |
+
display_discourse_interface,
|
256 |
+
display_discourse_results
|
257 |
+
)
|
258 |
+
from modules.discourse.discourse_process import (
|
259 |
+
perform_discourse_analysis, # Este es el nombre correcto de la función
|
260 |
+
extract_key_concepts, # Función adicional que necesitamos
|
261 |
+
generate_concept_graph, # Función adicional que necesitamos
|
262 |
+
calculate_similarity_matrix # Función adicional que necesitamos
|
263 |
+
)
|
264 |
+
|
265 |
+
return {
|
266 |
+
'display_discourse_interface': display_discourse_interface,
|
267 |
+
'display_discourse_results': display_discourse_results,
|
268 |
+
'perform_discourse_analysis': perform_discourse_analysis,
|
269 |
+
'extract_key_concepts': extract_key_concepts,
|
270 |
+
'generate_concept_graph': generate_concept_graph,
|
271 |
+
'calculate_similarity_matrix': calculate_similarity_matrix
|
272 |
+
}
|
273 |
+
|
274 |
+
def load_admin_functions():
|
275 |
+
from .admin.admin_ui import admin_page
|
276 |
+
return {
|
277 |
+
'admin_page': admin_page
|
278 |
+
}
|
279 |
+
|
280 |
+
def load_utils_functions():
|
281 |
+
from .utils.spacy_utils import load_spacy_models
|
282 |
+
return {
|
283 |
+
'load_spacy_models': load_spacy_models
|
284 |
+
}
|
285 |
+
|
286 |
+
def load_chatbot_functions():
|
287 |
+
"""
|
288 |
+
Carga las funciones del módulo de chatbot
|
289 |
+
Returns:
|
290 |
+
dict: Diccionario con las funciones del chatbot
|
291 |
+
"""
|
292 |
+
from modules.chatbot.sidebar_chat import (
|
293 |
+
display_sidebar_chat
|
294 |
+
)
|
295 |
+
|
296 |
+
from modules.chatbot.chat_process import (
|
297 |
+
ChatProcessor
|
298 |
+
)
|
299 |
+
|
300 |
+
return {
|
301 |
+
'display_sidebar_chat': display_sidebar_chat,
|
302 |
+
'ChatProcessor': ChatProcessor
|
303 |
+
}
|
304 |
+
|
305 |
+
# Función para cargar todas las funciones
|
306 |
+
def load_all_functions():
|
307 |
+
return {
|
308 |
+
**load_auth_functions(),
|
309 |
+
**load_database_functions(),
|
310 |
+
# **load_ui_functions(),
|
311 |
+
**load_admin_functions(),
|
312 |
+
**load_morphosyntax_functions(),
|
313 |
+
**load_semantic_functions(),
|
314 |
+
**load_discourse_functions(),
|
315 |
+
**load_utils_functions(),
|
316 |
+
**load_chatbot_functions(),
|
317 |
+
**load_student_activities_functions(),
|
318 |
+
**load_current_situation_functions() # Agregar el nuevo loader
|
319 |
+
}
|
src/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 |
+
}
|
src/modules/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (4.19 kB). View file
|
|
src/modules/admin/__init__.py
ADDED
File without changes
|
src/modules/admin/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (147 Bytes). View file
|
|
src/modules/admin/__pycache__/admin_ui.cpython-311.pyc
ADDED
Binary file (3.07 kB). View file
|
|
src/modules/admin/admin_ui.py
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#modules/admin/admin_ui.py
|
2 |
+
|
3 |
+
import streamlit as st
|
4 |
+
|
5 |
+
from datetime import datetime
|
6 |
+
|
7 |
+
from ..database.sql_db import (
|
8 |
+
get_user,
|
9 |
+
get_student_user,
|
10 |
+
get_admin_user,
|
11 |
+
get_teacher_user,
|
12 |
+
create_student_user,
|
13 |
+
update_student_user,
|
14 |
+
delete_student_user,
|
15 |
+
record_login,
|
16 |
+
record_logout,
|
17 |
+
get_recent_sessions,
|
18 |
+
get_user_total_time
|
19 |
+
)
|
20 |
+
|
21 |
+
from ..database.morphosintax_mongo_db import get_student_morphosyntax_analysis
|
22 |
+
|
23 |
+
from ..auth.auth import hash_password # Agregar esta importación al inicio
|
24 |
+
|
25 |
+
#######################################################################################
|
26 |
+
def format_duration(seconds):
|
27 |
+
"""Convierte segundos a formato legible"""
|
28 |
+
if not seconds:
|
29 |
+
return "0h 0m"
|
30 |
+
hours = seconds // 3600
|
31 |
+
minutes = (seconds % 3600) // 60
|
32 |
+
return f"{hours}h {minutes}m"
|
33 |
+
|
34 |
+
def admin_page():
|
35 |
+
st.title("Panel de Administración")
|
36 |
+
st.write(f"Bienvenido, {st.session_state.username}")
|
37 |
+
|
38 |
+
# Crear tres tabs para las diferentes secciones
|
39 |
+
tab1, tab2, tab3 = st.tabs([
|
40 |
+
"Gestión de Usuarios",
|
41 |
+
"Búsqueda de Usuarios",
|
42 |
+
"Actividad de la Plataforma"
|
43 |
+
])
|
44 |
+
|
45 |
+
|
46 |
+
########################################################
|
47 |
+
# Tab 1: Gestión de Usuarios
|
48 |
+
with tab1:
|
49 |
+
st.header("Crear Nuevo Usuario Estudiante")
|
50 |
+
|
51 |
+
# Crear dos columnas para el formulario
|
52 |
+
col1, col2 = st.columns(2)
|
53 |
+
|
54 |
+
with col1:
|
55 |
+
new_username = st.text_input(
|
56 |
+
"Correo electrónico del nuevo usuario",
|
57 |
+
key="admin_new_username"
|
58 |
+
)
|
59 |
+
|
60 |
+
with col2:
|
61 |
+
new_password = st.text_input(
|
62 |
+
"Contraseña",
|
63 |
+
type="password",
|
64 |
+
key="admin_new_password"
|
65 |
+
)
|
66 |
+
|
67 |
+
if st.button("Crear Usuario", key="admin_create_user", type="primary"):
|
68 |
+
if new_username and new_password: # Verificamos que ambos campos tengan valor
|
69 |
+
try:
|
70 |
+
# Hashear la contraseña antes de crear el usuario
|
71 |
+
hashed_password = hash_password(new_password)
|
72 |
+
if create_student_user(new_username, hashed_password, {'partitionKey': new_username}):
|
73 |
+
st.success(f"Usuario estudiante {new_username} creado exitosamente")
|
74 |
+
else:
|
75 |
+
st.error("Error al crear el usuario estudiante")
|
76 |
+
except Exception as e:
|
77 |
+
st.error(f"Error al crear usuario: {str(e)}")
|
78 |
+
else:
|
79 |
+
st.warning("Por favor complete todos los campos")
|
80 |
+
|
81 |
+
#######################################################################
|
82 |
+
# Tab 2: Búsqueda de Usuarios
|
83 |
+
with tab2:
|
84 |
+
st.header("Búsqueda de Usuarios")
|
85 |
+
|
86 |
+
search_col1, search_col2 = st.columns([2,1])
|
87 |
+
|
88 |
+
with search_col1:
|
89 |
+
student_username = st.text_input(
|
90 |
+
"Nombre de usuario del estudiante",
|
91 |
+
key="admin_view_student"
|
92 |
+
)
|
93 |
+
|
94 |
+
with search_col2:
|
95 |
+
search_button = st.button(
|
96 |
+
"Buscar",
|
97 |
+
key="admin_view_student_data",
|
98 |
+
type="primary"
|
99 |
+
)
|
100 |
+
|
101 |
+
if search_button:
|
102 |
+
student = get_student_user(student_username)
|
103 |
+
if student:
|
104 |
+
# Crear tabs para diferentes tipos de información
|
105 |
+
info_tab1, info_tab2, info_tab3 = st.tabs([
|
106 |
+
"Información Básica",
|
107 |
+
"Análisis Realizados",
|
108 |
+
"Tiempo en Plataforma"
|
109 |
+
])
|
110 |
+
|
111 |
+
with info_tab1:
|
112 |
+
st.subheader("Información del Usuario")
|
113 |
+
st.json(student)
|
114 |
+
|
115 |
+
with info_tab2:
|
116 |
+
st.subheader("Análisis Realizados")
|
117 |
+
student_data = get_student_morphosyntax_analysis(student_username)
|
118 |
+
if student_data:
|
119 |
+
st.json(student_data)
|
120 |
+
else:
|
121 |
+
st.info("No hay datos de análisis para este estudiante.")
|
122 |
+
|
123 |
+
with info_tab3:
|
124 |
+
st.subheader("Tiempo en Plataforma")
|
125 |
+
total_time = get_user_total_time(student_username)
|
126 |
+
if total_time:
|
127 |
+
st.metric(
|
128 |
+
"Tiempo Total",
|
129 |
+
format_duration(total_time)
|
130 |
+
)
|
131 |
+
else:
|
132 |
+
st.info("No hay registros de tiempo para este usuario")
|
133 |
+
else:
|
134 |
+
st.error("Estudiante no encontrado")
|
135 |
+
|
136 |
+
#######################################################################
|
137 |
+
# Tab 3: Actividad de la Plataforma
|
138 |
+
with tab3:
|
139 |
+
st.header("Actividad Reciente")
|
140 |
+
|
141 |
+
# Agregar botón de actualización
|
142 |
+
if st.button("Actualizar datos", key="refresh_sessions", type="primary"):
|
143 |
+
st.rerun()
|
144 |
+
|
145 |
+
# Mostrar spinner mientras carga
|
146 |
+
with st.spinner("Cargando datos de sesiones..."):
|
147 |
+
# Obtener sesiones recientes
|
148 |
+
recent_sessions = get_recent_sessions(20) # Aumentado a 20 para más datos
|
149 |
+
|
150 |
+
if recent_sessions:
|
151 |
+
# Crear dataframe para mostrar los datos
|
152 |
+
sessions_data = []
|
153 |
+
for session in recent_sessions:
|
154 |
+
try:
|
155 |
+
# Manejar el formato de fecha con manejo de excepciones
|
156 |
+
try:
|
157 |
+
login_time = datetime.fromisoformat(
|
158 |
+
session['loginTime'].replace('Z', '+00:00')
|
159 |
+
).strftime("%Y-%m-%d %H:%M:%S")
|
160 |
+
except Exception as e:
|
161 |
+
login_time = session['loginTime']
|
162 |
+
|
163 |
+
# Manejar el caso de logout_time cuando la sesión está activa
|
164 |
+
if session.get('logoutTime') and session['logoutTime'] != "Activo":
|
165 |
+
try:
|
166 |
+
logout_time = datetime.fromisoformat(
|
167 |
+
session['logoutTime'].replace('Z', '+00:00')
|
168 |
+
).strftime("%Y-%m-%d %H:%M:%S")
|
169 |
+
except Exception as e:
|
170 |
+
logout_time = session['logoutTime']
|
171 |
+
else:
|
172 |
+
logout_time = "Activo"
|
173 |
+
|
174 |
+
# Agregar datos a la lista
|
175 |
+
sessions_data.append({
|
176 |
+
"Usuario": session.get('username', 'Desconocido'),
|
177 |
+
"Inicio de Sesión": login_time,
|
178 |
+
"Fin de Sesión": logout_time,
|
179 |
+
"Duración": format_duration(session.get('sessionDuration', 0))
|
180 |
+
})
|
181 |
+
except Exception as e:
|
182 |
+
st.error(f"Error procesando sesión: {str(e)}")
|
183 |
+
continue
|
184 |
+
|
185 |
+
# Mostrar información de depuración si hay problemas
|
186 |
+
with st.expander("Información de depuración", expanded=False):
|
187 |
+
st.write("Datos crudos recuperados:")
|
188 |
+
st.json(recent_sessions)
|
189 |
+
|
190 |
+
st.write("Datos procesados para mostrar:")
|
191 |
+
st.json(sessions_data)
|
192 |
+
|
193 |
+
# Mostrar tabla con estilos
|
194 |
+
st.dataframe(
|
195 |
+
sessions_data,
|
196 |
+
hide_index=True,
|
197 |
+
column_config={
|
198 |
+
"Usuario": st.column_config.TextColumn(
|
199 |
+
"Usuario",
|
200 |
+
width="medium"
|
201 |
+
),
|
202 |
+
"Inicio de Sesión": st.column_config.TextColumn(
|
203 |
+
"Inicio de Sesión",
|
204 |
+
width="medium"
|
205 |
+
),
|
206 |
+
"Fin de Sesión": st.column_config.TextColumn(
|
207 |
+
"Fin de Sesión",
|
208 |
+
width="medium"
|
209 |
+
),
|
210 |
+
"Duración": st.column_config.TextColumn(
|
211 |
+
"Duración",
|
212 |
+
width="small"
|
213 |
+
)
|
214 |
+
}
|
215 |
+
)
|
216 |
+
|
217 |
+
# Añadir métricas resumen
|
218 |
+
total_sessions = len(sessions_data)
|
219 |
+
total_users = len(set(session['Usuario'] for session in sessions_data))
|
220 |
+
|
221 |
+
metric_col1, metric_col2 = st.columns(2)
|
222 |
+
with metric_col1:
|
223 |
+
st.metric("Total de Sesiones", total_sessions)
|
224 |
+
with metric_col2:
|
225 |
+
st.metric("Usuarios Únicos", total_users)
|
226 |
+
else:
|
227 |
+
st.info("No hay registros de sesiones recientes o hubo un problema al recuperarlos.")
|
228 |
+
|
229 |
+
# Ayuda de depuración
|
230 |
+
if st.button("Mostrar diagnóstico"):
|
231 |
+
st.write("Verificando la función get_recent_sessions:")
|
232 |
+
container = get_container("users_sessions")
|
233 |
+
if container:
|
234 |
+
st.success("✅ Conectado al contenedor users_sessions")
|
235 |
+
else:
|
236 |
+
st.error("❌ No se pudo conectar al contenedor users_sessions")
|
237 |
+
|
238 |
+
|
239 |
+
#######################################################################
|
240 |
+
# Agregar una línea divisoria antes del botón
|
241 |
+
st.markdown("---")
|
242 |
+
|
243 |
+
#######################################################################
|
244 |
+
# Centrar el botón de cierre de sesión
|
245 |
+
col1, col2, col3 = st.columns([2,1,2])
|
246 |
+
with col2:
|
247 |
+
if st.button("Cerrar Sesión", key="admin_logout", type="primary", use_container_width=True):
|
248 |
+
from ..auth.auth import logout
|
249 |
+
logout()
|
250 |
+
st.rerun()
|
src/modules/admin/txt.txt
ADDED
File without changes
|
src/modules/auth/__init__.py
ADDED
File without changes
|
src/modules/auth/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (146 Bytes). View file
|
|
src/modules/auth/__pycache__/auth.cpython-311.pyc
ADDED
Binary file (6.44 kB). View file
|
|
src/modules/auth/auth.py
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
##########modules/auth/auth.py
|
2 |
+
|
3 |
+
import os
|
4 |
+
import streamlit as st
|
5 |
+
from azure.cosmos import CosmosClient, exceptions
|
6 |
+
from azure.cosmos.exceptions import CosmosHttpResponseError
|
7 |
+
import bcrypt
|
8 |
+
import base64
|
9 |
+
from ..database.sql_db import (
|
10 |
+
get_user,
|
11 |
+
get_student_user,
|
12 |
+
get_admin_user,
|
13 |
+
create_student_user,
|
14 |
+
update_student_user,
|
15 |
+
delete_student_user,
|
16 |
+
record_login,
|
17 |
+
record_logout
|
18 |
+
)
|
19 |
+
|
20 |
+
import logging
|
21 |
+
|
22 |
+
from datetime import datetime, timezone
|
23 |
+
|
24 |
+
logger = logging.getLogger(__name__)
|
25 |
+
|
26 |
+
def clean_and_validate_key(key):
|
27 |
+
"""Limpia y valida la clave de CosmosDB"""
|
28 |
+
key = key.strip()
|
29 |
+
while len(key) % 4 != 0:
|
30 |
+
key += '='
|
31 |
+
try:
|
32 |
+
base64.b64decode(key)
|
33 |
+
return key
|
34 |
+
except:
|
35 |
+
raise ValueError("La clave proporcionada no es válida")
|
36 |
+
|
37 |
+
# Verificar las variables de entorno
|
38 |
+
endpoint = os.getenv("COSMOS_ENDPOINT")
|
39 |
+
key = os.getenv("COSMOS_KEY")
|
40 |
+
|
41 |
+
if not endpoint or not key:
|
42 |
+
raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
|
43 |
+
|
44 |
+
key = clean_and_validate_key(key)
|
45 |
+
|
46 |
+
|
47 |
+
def authenticate_user(username, password):
|
48 |
+
"""Autentica un usuario y registra el inicio de sesión"""
|
49 |
+
try:
|
50 |
+
user_item = get_user(username)
|
51 |
+
|
52 |
+
if not user_item:
|
53 |
+
logger.warning(f"Usuario no encontrado: {username}")
|
54 |
+
return False, None
|
55 |
+
|
56 |
+
if verify_password(user_item['password'], password):
|
57 |
+
logger.info(f"Usuario autenticado: {username}, Rol: {user_item['role']}")
|
58 |
+
|
59 |
+
try:
|
60 |
+
session_id = record_login(username)
|
61 |
+
if session_id:
|
62 |
+
st.session_state.session_id = session_id
|
63 |
+
st.session_state.username = username
|
64 |
+
st.session_state.login_time = datetime.now(timezone.utc).isoformat()
|
65 |
+
logger.info(f"Sesión iniciada: {session_id}")
|
66 |
+
else:
|
67 |
+
logger.warning("No se pudo registrar la sesión")
|
68 |
+
except Exception as e:
|
69 |
+
logger.error(f"Error al registrar inicio de sesión: {str(e)}")
|
70 |
+
|
71 |
+
return True, user_item['role']
|
72 |
+
|
73 |
+
logger.warning(f"Contraseña incorrecta para usuario: {username}")
|
74 |
+
return False, None
|
75 |
+
|
76 |
+
except Exception as e:
|
77 |
+
logger.error(f"Error durante la autenticación del usuario: {str(e)}")
|
78 |
+
return False, None
|
79 |
+
|
80 |
+
def authenticate_student(username, password):
|
81 |
+
"""Autentica un estudiante"""
|
82 |
+
success, role = authenticate_user(username, password)
|
83 |
+
if success and role == 'Estudiante':
|
84 |
+
return True, role
|
85 |
+
return False, None
|
86 |
+
|
87 |
+
def authenticate_admin(username, password):
|
88 |
+
"""Autentica un administrador"""
|
89 |
+
success, role = authenticate_user(username, password)
|
90 |
+
if success and role == 'Administrador':
|
91 |
+
return True, role
|
92 |
+
return False, None
|
93 |
+
|
94 |
+
def register_student(username, password, additional_info=None):
|
95 |
+
"""Registra un nuevo estudiante"""
|
96 |
+
try:
|
97 |
+
if get_student_user(username):
|
98 |
+
logger.warning(f"Estudiante ya existe: {username}")
|
99 |
+
return False
|
100 |
+
|
101 |
+
hashed_password = hash_password(password)
|
102 |
+
|
103 |
+
# Asegurarse que additional_info tenga el rol correcto
|
104 |
+
if not additional_info:
|
105 |
+
additional_info = {}
|
106 |
+
additional_info['role'] = 'Estudiante'
|
107 |
+
|
108 |
+
success = create_student_user(username, hashed_password, additional_info)
|
109 |
+
if success:
|
110 |
+
logger.info(f"Nuevo estudiante registrado: {username}")
|
111 |
+
return True
|
112 |
+
|
113 |
+
logger.error(f"Error al crear estudiante: {username}")
|
114 |
+
return False
|
115 |
+
|
116 |
+
except Exception as e:
|
117 |
+
logger.error(f"Error al registrar estudiante: {str(e)}")
|
118 |
+
return False
|
119 |
+
|
120 |
+
def update_student_info(username, new_info):
|
121 |
+
"""Actualiza la información de un estudiante"""
|
122 |
+
try:
|
123 |
+
if 'password' in new_info:
|
124 |
+
new_info['password'] = hash_password(new_info['password'])
|
125 |
+
|
126 |
+
success = update_student_user(username, new_info)
|
127 |
+
if success:
|
128 |
+
logger.info(f"Información actualizada: {username}")
|
129 |
+
return True
|
130 |
+
|
131 |
+
logger.error(f"Error al actualizar: {username}")
|
132 |
+
return False
|
133 |
+
|
134 |
+
except Exception as e:
|
135 |
+
logger.error(f"Error en actualización: {str(e)}")
|
136 |
+
return False
|
137 |
+
|
138 |
+
def delete_student(username):
|
139 |
+
"""Elimina un estudiante"""
|
140 |
+
try:
|
141 |
+
success = delete_student_user(username)
|
142 |
+
if success:
|
143 |
+
logger.info(f"Estudiante eliminado: {username}")
|
144 |
+
return True
|
145 |
+
|
146 |
+
logger.error(f"Error al eliminar: {username}")
|
147 |
+
return False
|
148 |
+
|
149 |
+
except Exception as e:
|
150 |
+
logger.error(f"Error en eliminación: {str(e)}")
|
151 |
+
return False
|
152 |
+
|
153 |
+
def logout():
|
154 |
+
"""Cierra la sesión del usuario"""
|
155 |
+
try:
|
156 |
+
if 'session_id' in st.session_state and 'username' in st.session_state:
|
157 |
+
success = record_logout(
|
158 |
+
st.session_state.username,
|
159 |
+
st.session_state.session_id
|
160 |
+
)
|
161 |
+
if success:
|
162 |
+
logger.info(f"Sesión cerrada: {st.session_state.username}")
|
163 |
+
else:
|
164 |
+
logger.warning(f"Error al registrar cierre de sesión: {st.session_state.username}")
|
165 |
+
|
166 |
+
except Exception as e:
|
167 |
+
logger.error(f"Error en logout: {str(e)}")
|
168 |
+
finally:
|
169 |
+
st.session_state.clear()
|
170 |
+
|
171 |
+
def hash_password(password):
|
172 |
+
"""Hashea una contraseña"""
|
173 |
+
return bcrypt.hashpw(
|
174 |
+
password.encode('utf-8'),
|
175 |
+
bcrypt.gensalt()
|
176 |
+
).decode('utf-8')
|
177 |
+
|
178 |
+
def verify_password(stored_password, provided_password):
|
179 |
+
"""Verifica una contraseña"""
|
180 |
+
return bcrypt.checkpw(
|
181 |
+
provided_password.encode('utf-8'),
|
182 |
+
stored_password.encode('utf-8')
|
183 |
+
)
|
184 |
+
|
185 |
+
__all__ = [
|
186 |
+
'authenticate_user',
|
187 |
+
'authenticate_admin',
|
188 |
+
'authenticate_student',
|
189 |
+
'register_student',
|
190 |
+
'update_student_info',
|
191 |
+
'delete_student',
|
192 |
+
'logout',
|
193 |
+
'hash_password',
|
194 |
+
'verify_password'
|
195 |
+
]
|