AIdeaText commited on
Commit
24060c9
·
verified ·
1 Parent(s): 88f1e80

Upload 281 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +16 -0
  2. src/assets/img/AIdeaTextCard.jpg +3 -0
  3. src/assets/img/AIdeaText_Logo_vectores.png +3 -0
  4. src/assets/img/ALPHA_Startup Badges.png +3 -0
  5. src/assets/img/Ico-20x20.ico +0 -0
  6. src/assets/img/Logo20x20.png +0 -0
  7. src/assets/img/Logo24x24.png +0 -0
  8. src/assets/img/Logo32x32.png +0 -0
  9. src/assets/img/Logo40x40.png +0 -0
  10. src/assets/img/Logo48x48.png +0 -0
  11. src/assets/img/Logo64x64.png +0 -0
  12. src/assets/img/Logo_100x100.png +0 -0
  13. src/assets/img/Logo_300x300.png +0 -0
  14. src/assets/img/Mesa de trabajo 1png 0.3.png +0 -0
  15. src/assets/img/aideaText-ICO.png +0 -0
  16. src/assets/img/aideaText-Logo-32x32.png +0 -0
  17. src/assets/img/aideaText_icon.ico +0 -0
  18. src/assets/img/aideaText_logo.png +0 -0
  19. src/assets/img/assets_img_logo_92x92.ico +3 -0
  20. src/assets/img/logo120x120.png +0 -0
  21. src/assets/img/logo_92x92.jpg +0 -0
  22. src/assets/img/logo_92x92.png +0 -0
  23. src/assets/img/socialmedia/AIdeaTextCard.jpg +3 -0
  24. src/assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg +3 -0
  25. src/assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg +3 -0
  26. src/assets/img/socialmedia/_MG_2535.jpg +3 -0
  27. src/assets/img/socialmedia/_MG_2585.jpg +3 -0
  28. src/assets/img/socialmedia/_MG_2587.jpg +3 -0
  29. src/assets/img/socialmedia/_MG_2590.jpg +3 -0
  30. src/assets/img/socialmedia/_MG_2678.jpg +3 -0
  31. src/assets/img/socialmedia/_MG_2727.jpg +3 -0
  32. src/assets/img/socialmedia/_MG_2735.jpg +3 -0
  33. src/assets/img/socialmedia/_MG_2790.jpg +3 -0
  34. src/assets/img/socialmedia/_MG_2845.JPG +3 -0
  35. src/assets/img/socialmedia/txt.txt +1 -0
  36. src/assets/img/text.txt +0 -0
  37. src/modules/23-7-2024_auth.py +135 -0
  38. src/modules/23-7-2024_ui.py +344 -0
  39. src/modules/__init__.py +319 -0
  40. src/modules/__init__Old-V3.py +180 -0
  41. src/modules/__pycache__/__init__.cpython-311.pyc +0 -0
  42. src/modules/admin/__init__.py +0 -0
  43. src/modules/admin/__pycache__/__init__.cpython-311.pyc +0 -0
  44. src/modules/admin/__pycache__/admin_ui.cpython-311.pyc +0 -0
  45. src/modules/admin/admin_ui.py +250 -0
  46. src/modules/admin/txt.txt +0 -0
  47. src/modules/auth/__init__.py +0 -0
  48. src/modules/auth/__pycache__/__init__.cpython-311.pyc +0 -0
  49. src/modules/auth/__pycache__/auth.cpython-311.pyc +0 -0
  50. 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

  • SHA256: 7a2728751bd949172ae2a2980a34f77931f3bb9f3d5843a479c2275b1316272e
  • Pointer size: 131 Bytes
  • Size of remote file: 268 kB
src/assets/img/AIdeaText_Logo_vectores.png ADDED

Git LFS Details

  • SHA256: 49e82e34b75e707b9fb46563347c64570aa7360a33adc3b18f82e7969f448917
  • Pointer size: 132 Bytes
  • Size of remote file: 1.01 MB
src/assets/img/ALPHA_Startup Badges.png ADDED

Git LFS Details

  • SHA256: f55cb163a87ef69660185da4654e796edd66f30ac85a0db7c8f172fca8b02b09
  • Pointer size: 131 Bytes
  • Size of remote file: 602 kB
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

  • SHA256: d2a957f8116c5f5658526a763b5280aaf589e9b57aea3ab59ac8fd683d374ef3
  • Pointer size: 131 Bytes
  • Size of remote file: 372 kB
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

  • SHA256: 7a2728751bd949172ae2a2980a34f77931f3bb9f3d5843a479c2275b1316272e
  • Pointer size: 131 Bytes
  • Size of remote file: 268 kB
src/assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg ADDED

Git LFS Details

  • SHA256: b24221fd528714afc31c87ee586ed3d173eb0767f1755decf5f192946f96743c
  • Pointer size: 131 Bytes
  • Size of remote file: 245 kB
src/assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg ADDED

Git LFS Details

  • SHA256: 5733fa2fe5d1d76f9a01f7346536dd7ecd6e5f223006386a81b3188bcfa985bb
  • Pointer size: 131 Bytes
  • Size of remote file: 289 kB
src/assets/img/socialmedia/_MG_2535.jpg ADDED

Git LFS Details

  • SHA256: a94188b158e88ff1cec1db6b39a6d28e564c77f685e7c076a7f3b76dffa0fe19
  • Pointer size: 131 Bytes
  • Size of remote file: 328 kB
src/assets/img/socialmedia/_MG_2585.jpg ADDED

Git LFS Details

  • SHA256: 8997c5e41a528400b818088548162c2c13315ceb87803148af64dd9932207838
  • Pointer size: 131 Bytes
  • Size of remote file: 336 kB
src/assets/img/socialmedia/_MG_2587.jpg ADDED

Git LFS Details

  • SHA256: def2e98c90c7c55aa8ee7b2ee31b81ca3c950fd12149e1c23742c236aad85ee9
  • Pointer size: 131 Bytes
  • Size of remote file: 331 kB
src/assets/img/socialmedia/_MG_2590.jpg ADDED

Git LFS Details

  • SHA256: 128dd26ddb18fe0008818f78535305b79fc4c258a123db4076cd2f9b67c1ae3d
  • Pointer size: 131 Bytes
  • Size of remote file: 332 kB
src/assets/img/socialmedia/_MG_2678.jpg ADDED

Git LFS Details

  • SHA256: 5bdf2d4d2ddc6d974c2a9b21d44c24a3b98b952e31032df83b60e6ebde61c836
  • Pointer size: 131 Bytes
  • Size of remote file: 335 kB
src/assets/img/socialmedia/_MG_2727.jpg ADDED

Git LFS Details

  • SHA256: c2d4a162817cbebba5738f564a92a48546f5208877152cf0545962f74c3f495e
  • Pointer size: 131 Bytes
  • Size of remote file: 336 kB
src/assets/img/socialmedia/_MG_2735.jpg ADDED

Git LFS Details

  • SHA256: 527d01d3e09061d1a77513b75b55bcceb2840dbc8631e85b9542b7aaa9a85841
  • Pointer size: 131 Bytes
  • Size of remote file: 331 kB
src/assets/img/socialmedia/_MG_2790.jpg ADDED

Git LFS Details

  • SHA256: 21bcc1b99cf3d1ab4ab6d480ffeb3867ee4ef17a18d8e1873e3ea46cc548722b
  • Pointer size: 131 Bytes
  • Size of remote file: 340 kB
src/assets/img/socialmedia/_MG_2845.JPG ADDED

Git LFS Details

  • SHA256: ad3a77f44abe700d87e36e3125890aeb29a2194f8ef006fc895c8eff49eeed8a
  • Pointer size: 131 Bytes
  • Size of remote file: 347 kB
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
+ ]