AIdeaText commited on
Commit
9484d0f
1 Parent(s): 6d35e8c

Create database/database.py

Browse files
Files changed (1) hide show
  1. modules/database/database.py +392 -0
modules/database/database.py ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # database.py
2
+ import logging
3
+ import os
4
+ from azure.cosmos import CosmosClient
5
+ from azure.cosmos.exceptions import CosmosHttpResponseError
6
+ from pymongo import MongoClient
7
+ import certifi
8
+ from datetime import datetime
9
+ import io
10
+ import base64
11
+ import matplotlib.pyplot as plt
12
+ from matplotlib.figure import Figure
13
+ import bcrypt
14
+ print(f"Bcrypt version: {bcrypt.__version__}")
15
+ import uuid
16
+
17
+ logging.basicConfig(level=logging.DEBUG)
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Variables globales para Cosmos DB SQL API
21
+ application_requests_container = None
22
+ cosmos_client = None
23
+ user_database = None
24
+ user_container = None
25
+
26
+ # Variables globales para Cosmos DB MongoDB API
27
+ mongo_client = None
28
+ mongo_db = None
29
+ analysis_collection = None
30
+ chat_collection = None # Nueva variable global
31
+
32
+
33
+ #####################################################################################33
34
+ def initialize_database_connections():
35
+ try:
36
+ print("Iniciando conexión a MongoDB")
37
+ mongodb_success = initialize_mongodb_connection()
38
+ print(f"Conexión a MongoDB: {'exitosa' if mongodb_success else 'fallida'}")
39
+ except Exception as e:
40
+ print(f"Error al conectar con MongoDB: {str(e)}")
41
+ mongodb_success = False
42
+
43
+ try:
44
+ print("Iniciando conexión a Cosmos DB SQL API")
45
+ sql_success = initialize_cosmos_sql_connection()
46
+ print(f"Conexión a Cosmos DB SQL API: {'exitosa' if sql_success else 'fallida'}")
47
+ except Exception as e:
48
+ print(f"Error al conectar con Cosmos DB SQL API: {str(e)}")
49
+ sql_success = False
50
+
51
+ return {
52
+ "mongodb": mongodb_success,
53
+ "cosmos_sql": sql_success
54
+ }
55
+
56
+ #####################################################################################33
57
+ def initialize_cosmos_sql_connection():
58
+ global cosmos_client, user_database, user_container, application_requests_container
59
+ logger.info("Initializing Cosmos DB SQL API connection")
60
+ try:
61
+ cosmos_endpoint = os.environ.get("COSMOS_ENDPOINT")
62
+ cosmos_key = os.environ.get("COSMOS_KEY")
63
+ logger.info(f"Cosmos Endpoint: {cosmos_endpoint}")
64
+ logger.info(f"Cosmos Key: {'*' * len(cosmos_key) if cosmos_key else 'Not set'}")
65
+
66
+ if not cosmos_endpoint or not cosmos_key:
67
+ logger.error("COSMOS_ENDPOINT or COSMOS_KEY environment variables are not set")
68
+ raise ValueError("Las variables de entorno COSMOS_ENDPOINT y COSMOS_KEY deben estar configuradas")
69
+
70
+ cosmos_client = CosmosClient(cosmos_endpoint, cosmos_key)
71
+ user_database = cosmos_client.get_database_client("user_database")
72
+ user_container = user_database.get_container_client("users")
73
+ application_requests_container = user_database.get_container_client("application_requests")
74
+
75
+ logger.info(f"user_container initialized: {user_container is not None}")
76
+ logger.info(f"application_requests_container initialized: {application_requests_container is not None}")
77
+
78
+ logger.info("Conexión a Cosmos DB SQL API exitosa")
79
+ return True
80
+ except Exception as e:
81
+ logger.error(f"Error al conectar con Cosmos DB SQL API: {str(e)}", exc_info=True)
82
+ return False
83
+
84
+ ############################################################################################3
85
+ def initialize_mongodb_connection():
86
+ global mongo_client, mongo_db, analysis_collection, chat_collection
87
+ try:
88
+ cosmos_mongodb_connection_string = os.getenv("MONGODB_CONNECTION_STRING")
89
+ if not cosmos_mongodb_connection_string:
90
+ logger.error("La variable de entorno MONGODB_CONNECTION_STRING no está configurada")
91
+ return False
92
+
93
+ mongo_client = MongoClient(cosmos_mongodb_connection_string,
94
+ tls=True,
95
+ tlsCAFile=certifi.where(),
96
+ retryWrites=False,
97
+ serverSelectionTimeoutMS=5000,
98
+ connectTimeoutMS=10000,
99
+ socketTimeoutMS=10000)
100
+
101
+ mongo_client.admin.command('ping')
102
+
103
+ mongo_db = mongo_client['aideatext_db']
104
+ analysis_collection = mongo_db['text_analysis']
105
+ chat_collection = mongo_db['chat_history'] # Inicializar la nueva colección
106
+
107
+ # Verificar la conexión
108
+ mongo_client.admin.command('ping')
109
+
110
+ logger.info("Conexión a Cosmos DB MongoDB API exitosa")
111
+ return True
112
+ except Exception as e:
113
+ logger.error(f"Error al conectar con Cosmos DB MongoDB API: {str(e)}", exc_info=True)
114
+ return False
115
+
116
+ #######################################################################################################
117
+ def create_user(username, password, role):
118
+ global user_container
119
+ try:
120
+ print(f"Attempting to create user: {username} with role: {role}")
121
+ if user_container is None:
122
+ print("Error: user_container is None. Attempting to reinitialize connection.")
123
+ if not initialize_cosmos_sql_connection():
124
+ raise Exception("Failed to initialize SQL connection")
125
+
126
+ hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
127
+ print(f"Password hashed successfully for user: {username}")
128
+ user_data = {
129
+ 'id': username,
130
+ 'password': hashed_password,
131
+ 'role': role,
132
+ 'created_at': datetime.utcnow().isoformat()
133
+ }
134
+ user_container.create_item(body=user_data)
135
+ print(f"Usuario {role} creado: {username}") # Log para depuración
136
+ return True
137
+ except Exception as e:
138
+ print(f"Detailed error in create_user: {str(e)}")
139
+ return False
140
+
141
+ #######################################################################################################
142
+ def create_admin_user(username, password):
143
+ return create_user(username, password, 'Administrador')
144
+
145
+ #######################################################################################################
146
+ def create_student_user(username, password):
147
+ return create_user(username, password, 'Estudiante')
148
+
149
+ #######################################################################################################
150
+ # Funciones para Cosmos DB SQL API (manejo de usuarios)
151
+ def get_user(username):
152
+ try:
153
+ query = f"SELECT * FROM c WHERE c.id = '{username}'"
154
+ items = list(user_container.query_items(query=query, enable_cross_partition_query=True))
155
+ user = items[0] if items else None
156
+ if user:
157
+ print(f"Usuario encontrado: {username}, Rol: {user.get('role')}") # Log añadido
158
+ else:
159
+ print(f"Usuario no encontrado: {username}") # Log añadido
160
+ return user
161
+ except Exception as e:
162
+ print(f"Error al obtener usuario {username}: {str(e)}")
163
+ return None
164
+
165
+ #######################################################################################################
166
+ def store_application_request(name, email, institution, role, reason):
167
+ global application_requests_container
168
+ logger.info("Entering store_application_request function")
169
+ try:
170
+ logger.info("Checking application_requests_container")
171
+ if application_requests_container is None:
172
+ logger.error("application_requests_container is not initialized")
173
+ return False
174
+
175
+ logger.info("Creating application request document")
176
+ application_request = {
177
+ "id": str(uuid.uuid4()),
178
+ "name": name,
179
+ "email": email,
180
+ "institution": institution,
181
+ "role": role,
182
+ "reason": reason,
183
+ "requestDate": datetime.utcnow().isoformat()
184
+ }
185
+
186
+ logger.info(f"Attempting to store document: {application_request}")
187
+ application_requests_container.create_item(body=application_request)
188
+ logger.info(f"Application request stored for email: {email}")
189
+ return True
190
+ except Exception as e:
191
+ logger.error(f"Error storing application request: {str(e)}")
192
+ return False
193
+
194
+ #######################################################################################################
195
+ def store_morphosyntax_result(username, text, repeated_words, arc_diagrams, pos_analysis, morphological_analysis, sentence_structure):
196
+ if analysis_collection is None:
197
+ logger.error("La conexión a MongoDB no está inicializada")
198
+ return False
199
+
200
+ try:
201
+ word_count = {}
202
+ for word, color in repeated_words.items():
203
+ category = color # Asumiendo que 'color' es la categoría gramatical
204
+ word_count[category] = word_count.get(category, 0) + 1
205
+
206
+ analysis_document = {
207
+ 'username': username,
208
+ 'timestamp': datetime.utcnow(),
209
+ 'text': text,
210
+ 'word_count': word_count,
211
+ 'arc_diagrams': arc_diagrams,
212
+ 'pos_analysis': pos_analysis,
213
+ 'morphological_analysis': morphological_analysis,
214
+ 'sentence_structure': sentence_structure
215
+ }
216
+
217
+ result = analysis_collection.insert_one(analysis_document)
218
+ logger.info(f"Análisis guardado con ID: {result.inserted_id} para el usuario: {username}")
219
+ return True
220
+ except Exception as e:
221
+ logger.error(f"Error al guardar el análisis para el usuario {username}: {str(e)}")
222
+ return False
223
+
224
+ ################################################################################################################
225
+ def store_semantic_result(username, text, analysis_result):
226
+ if analysis_collection is None:
227
+ logger.error("La conexión a MongoDB no está inicializada")
228
+ return False
229
+ try:
230
+ buf = io.BytesIO()
231
+ analysis_result['relations_graph'].savefig(buf, format='png')
232
+ buf.seek(0)
233
+ img_str = base64.b64encode(buf.getvalue()).decode('utf-8')
234
+ analysis_document = {
235
+ 'username': username,
236
+ 'timestamp': datetime.utcnow(),
237
+ 'text': text,
238
+ 'entities': analysis_result['entities'],
239
+ 'key_concepts': analysis_result['key_concepts'],
240
+ 'network_diagram': img_str, # Cambiado de 'relations_graph' a 'network_diagram'
241
+ 'analysis_type': 'semantic'
242
+ }
243
+ result = analysis_collection.insert_one(analysis_document)
244
+ logger.info(f"Análisis semántico guardado con ID: {result.inserted_id} para el usuario: {username}")
245
+ logger.info(f"Longitud de la imagen guardada: {len(img_str)}")
246
+ return True
247
+ except Exception as e:
248
+ logger.error(f"Error al guardar el análisis semántico para el usuario {username}: {str(e)}")
249
+ return False
250
+
251
+ ###############################################################################################################
252
+
253
+ def store_discourse_analysis_result(username, text1, text2, graph1, graph2):
254
+ try:
255
+ # Crear una nueva figura combinada
256
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
257
+
258
+ # Añadir la primera imagen con título
259
+ ax1.imshow(graph1.get_figure().canvas.renderer.buffer_rgba())
260
+ ax1.set_title("Documento Patrón: Relaciones semánticas relevantes")
261
+ ax1.axis('off')
262
+
263
+ # Añadir la segunda imagen con título
264
+ ax2.imshow(graph2.get_figure().canvas.renderer.buffer_rgba())
265
+ ax2.set_title("Documento Comparado con el documento patrón: Relaciones semánticas relevantes")
266
+ ax2.axis('off')
267
+
268
+ # Ajustar el diseño
269
+ plt.tight_layout()
270
+
271
+ # Convertir la figura combinada a una imagen base64
272
+ buf = io.BytesIO()
273
+ fig.savefig(buf, format='png')
274
+ buf.seek(0)
275
+ img_str = base64.b64encode(buf.getvalue()).decode('utf-8')
276
+
277
+ # Cerrar las figuras para liberar memoria
278
+ plt.close(fig)
279
+ plt.close(graph1.get_figure())
280
+ plt.close(graph2.get_figure())
281
+
282
+ analysis_document = {
283
+ 'username': username,
284
+ 'timestamp': datetime.utcnow(),
285
+ 'text1': text1,
286
+ 'text2': text2,
287
+ 'combined_graph': img_str,
288
+ 'analysis_type': 'discourse'
289
+ }
290
+
291
+ result = analysis_collection.insert_one(analysis_document)
292
+
293
+ logger.info(f"Análisis discursivo guardado con ID: {result.inserted_id} para el usuario: {username}")
294
+ return True
295
+ except Exception as e:
296
+ logger.error(f"Error al guardar el análisis discursivo para el usuario {username}: {str(e)}")
297
+ return False
298
+
299
+ ###############################################################################################################
300
+ def store_chat_history(username, messages):
301
+ try:
302
+ logger.info(f"Attempting to save chat history for user: {username}")
303
+ logger.debug(f"Messages to save: {messages}")
304
+
305
+ chat_document = {
306
+ 'username': username,
307
+ 'timestamp': datetime.utcnow(),
308
+ 'messages': messages
309
+ }
310
+ result = chat_collection.insert_one(chat_document)
311
+ logger.info(f"Chat history saved with ID: {result.inserted_id} for user: {username}")
312
+ logger.debug(f"Chat content: {messages}")
313
+ return True
314
+ except Exception as e:
315
+ logger.error(f"Error saving chat history for user {username}: {str(e)}")
316
+ return False
317
+
318
+ #######################################################################################################
319
+ def get_student_data(username):
320
+ if analysis_collection is None or chat_collection is None:
321
+ logger.error("La conexión a MongoDB no está inicializada")
322
+ return None
323
+
324
+ formatted_data = {
325
+ "username": username,
326
+ "entries": [],
327
+ "entries_count": 0,
328
+ "word_count": {},
329
+ "semantic_analyses": [],
330
+ "discourse_analyses": [],
331
+ "chat_history": []
332
+ }
333
+
334
+ try:
335
+ logger.info(f"Buscando datos de análisis para el usuario: {username}")
336
+ cursor = analysis_collection.find({"username": username})
337
+
338
+ for entry in cursor:
339
+ formatted_entry = {
340
+ "timestamp": entry.get("timestamp", datetime.utcnow()),
341
+ "text": entry.get("text", ""),
342
+ "analysis_type": entry.get("analysis_type", "morphosyntax")
343
+ }
344
+
345
+ if formatted_entry["analysis_type"] == "morphosyntax":
346
+ formatted_entry.update({
347
+ "word_count": entry.get("word_count", {}),
348
+ "arc_diagrams": entry.get("arc_diagrams", [])
349
+ })
350
+ for category, count in formatted_entry["word_count"].items():
351
+ formatted_data["word_count"][category] = formatted_data["word_count"].get(category, 0) + count
352
+
353
+ elif formatted_entry["analysis_type"] == "semantic":
354
+ formatted_entry["network_diagram"] = entry.get("network_diagram", "")
355
+ formatted_data["semantic_analyses"].append(formatted_entry)
356
+
357
+ elif formatted_entry["analysis_type"] == "discourse":
358
+ formatted_entry.update({
359
+ "text1": entry.get("text1", ""),
360
+ "text2": entry.get("text2", ""),
361
+ "combined_graph": entry.get("combined_graph", "")
362
+ })
363
+ formatted_data["discourse_analyses"].append(formatted_entry)
364
+
365
+ formatted_data["entries"].append(formatted_entry)
366
+
367
+ formatted_data["entries_count"] = len(formatted_data["entries"])
368
+ formatted_data["entries"].sort(key=lambda x: x["timestamp"], reverse=True)
369
+
370
+ for entry in formatted_data["entries"]:
371
+ entry["timestamp"] = entry["timestamp"].isoformat()
372
+
373
+ except Exception as e:
374
+ logger.error(f"Error al obtener datos de análisis del estudiante {username}: {str(e)}")
375
+
376
+ try:
377
+ logger.info(f"Buscando historial de chat para el usuario: {username}")
378
+ chat_cursor = chat_collection.find({"username": username})
379
+ for chat in chat_cursor:
380
+ formatted_chat = {
381
+ "timestamp": chat["timestamp"].isoformat(),
382
+ "messages": chat["messages"]
383
+ }
384
+ formatted_data["chat_history"].append(formatted_chat)
385
+
386
+ formatted_data["chat_history"].sort(key=lambda x: x["timestamp"], reverse=True)
387
+
388
+ except Exception as e:
389
+ logger.error(f"Error al obtener historial de chat del estudiante {username}: {str(e)}")
390
+
391
+ logger.info(f"Datos formateados para {username}: {formatted_data}")
392
+ return formatted_data