a
    +ͤhº                  	   @   s  d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	m
Z
mZmZmZmZmZ ddlmZ ddlZddlZddlZddlmZ ddlmZ ddlZddlZddlZddlZddlZeje Z!ej"e!dd	Z#ej"e!dd
Z$e	e%e#e$dZ&ee&dd e' Z(e)e( ddl*m+Z+ e&,e+ ddl-m.Z. e&,e. ej/0dde&_1ej/0ddej/0ddej/0ddej/0dde2ej/0dddddZ3ej/0ddZ4e2ej/0d d!Z5d"d# Z6d$d% Z7e&8d&d'd( Z9e&j8d)d*gd+d,d- Z:e&j8d.d*gd+d/d0 Z;d1d2 Z<d3d4 Z=e&j8d5d*gd+e=d6d7 Z>e&j8d5d8gd+e=d9d: Z?e&j8d;d8gd+e=d<d= Z@e&j8d>d8gd+e=d?d@ ZAe&j8d;dAgd+e=dBdC ZBe&j8d;dDgd+e=dEdF ZCe&j8dGd*gd+e=dHdI ZDe&j8dGd8gd+e=dJdK ZEe&j8dLd8gd+e=dMdN ZFe&j8dOd8gd+e=dPdQ ZGe&j8dLdDgd+e=dRdS ZHe&j8dTd8gd+e=dUdV ZIe&j8dWd8gd+e=dXdY ZJe&j8dWdAgd+e=dZd[ ZKe&8d\d]d^ ZLe&8d_e=d`da ZMe&8dbe=dcdd ZNe&8dee=dfdg ZOe&8dhe=didj ZPe&8dke=dldm ZQe&j8dnd*gd+dodp ZRe&8dqdrds ZSe%dtkreTdu eTdvejU  eTdweV   eTdxej/0dd  e7 reTdy neTdz e2ej/0d{d|ZWeTd}eW  ej/0d~dkZXe&jYdeWeXd dS )us   
app.py - Backend principal de Auris con Flask y MySQL
Sistema de autenticación con encriptación de contraseñas
    N)datetime	timedelta)Flaskrequestjsonifyrender_templatesend_from_directoryredirectmake_response)CORS)	PdfReader)secure_filenamefrontend	templatesstatic)template_folderstatic_folderT)supports_credentials)tts_bp)edge_tts_bp
SECRET_KEYzauris-secret-key-2025ZDB_HOST	localhostZDB_USERZmyadmonZDB_PASSWORDz
Quick25$$.ZDB_NAMEZAurisZDB_PORTZ3306utf8mb4)hostuserpassworddatabaseportcharset
autocommitJWT_SECRET_KEYzauris-jwt-secret-2025JWT_ACCESS_TOKEN_EXPIRESZ86400c               
   C   sH   zt jjf i t} | W S  t jjyB } zW Y d}~dS d}~0 0 dS )u'   Función para obtener conexión a MySQLN)mysql	connectorconnect	DB_CONFIGError)
connectione r)   /var/www/auris/app.pyget_db_connectionB   s
    r+   c               
   C   s   d} d}zzZt  } | s6W W |r&|  | r2|   dS |  }|   W W |rV|  | rb|   dS  tjjy } z(W Y d}~W |r|  | r|   dS d}~0 0 W |r|  | r|   n|r|  | r|   0 dS )z6Inicializar base de datos y crear tablas si no existenNFT)r+   closecursorcommitr"   r#   r&   )r'   r-   r(   r)   r)   r*   init_databaseJ   sD    
r/   z/api/test-dbc               
   C   s   t  } | rzT|  }|d | }|  |   tddtd d|rP|d ndddfW S  ty } z4| rz|   td	d
t| ddfW  Y d}~S d}~0 0 ntd	dddfS dS )u#   Probar conexión a la base de datoszSELECT 1successu   Conexión a MySQL exitosar   r   N)statusmessager   Z
test_queryresult   errorz"Error ejecutando query de prueba: r1   r2     u   Error de conexión a MySQL)	r+   r-   executefetchoner,   r   r%   	Exceptionstr)r'   r-   r3   r(   r)   r)   r*   test_db^   s@    
r<   z/api/registerPOST)methodsc               
      s^  zt d tj t fdddD s:tddidfW S  d  }  d	   } d
 }t| dk r|tddidfW S t|dk rtddidfW S d|vrtddidfW S d}d}z8zRt }|st d tddidfW W |r|	  |r|	  W S |
 }|d|| f | rdt d tddidfW W |rR|	  |r`|	  W S t|dt }|d| ||df |j}t d|  g d}|D ]\}}	|d|||	f q|  t d tdd |d!d"fW W |r|	  |r|	  W S  tjjyx }
 zFtdd#t|
 idfW  Y d}
~
W |r^|	  |rl|	  W S d}
~
0  ty }
 zFtdd$t|
 idfW  Y d}
~
W |r|	  |r|	  W S d}
~
0 0 W |r|	  |r|	  n|r|	  |r|	  0 W n@ tyX }
 z&tdd%t|
 idfW  Y d}
~
S d}
~
0 0 dS )&zRegistro de nuevos usuariosu&   📝 Procesando registro de usuario...c                 3   s   | ]}| v V  qd S Nr)   .0kdatar)   r*   	<genexpr>       zregister.<locals>.<genexpr>)nombre_usuariocorreo_electronico   contraseñar5   Faltan datos requeridos  rG   rH   rI      z5El nombre de usuario debe tener al menos 3 caracteres   u/   La contraseña debe tener al menos 6 caracteres@u   Correo electrónico inválidoNu"   ❌ Error de conexión en registro%   Error de conexión a la base de datosr7   zLSELECT id FROM Usuarios WHERE correo_electronico = %s OR nombre_usuario = %su   ❌ Usuario ya existezEl usuario o correo ya existei  utf-8u   
                INSERT INTO Usuarios (nombre_usuario, correo_electronico, contraseña) 
                VALUES (%s, %s, %s)
            u   ✅ Usuario creado con ID: ))tipo_vozmujer)velocidad_lecturaz1.0)u   tamaño_fuenteZmedium)contraste_altofalse)retroalimentacion_audiotrue
                    INSERT INTO Configuraciones_Usuario (usuario_id, nombre_configuracion, valor_configuracion) 
                    VALUES (%s, %s, %s)
                u$   ✅ Registro completado exitosamenter0   zUsuario registrado exitosamente)r1   r2   user_id   Error de base de datos: Error interno:    Error crítico: )printr   jsonallr   striplowerlenr+   r,   r-   r8   r9   bcrypthashpwencodegensaltdecode	lastrowidr.   r"   r#   r&   r;   r:   )rG   rH      contraseñar'   r-   Zhashed_passwordrY   Zdefault_configsZconfig_nameZconfig_valuer(   r)   rC   r*   register~   s    -
&&&
rk   z
/api/loginc               
      s  zXt j t fdddD s2tddidfW S  d   }  d }d	}d	}zzt }|stdd
idfW W |r|  |r|  W S |jdd}|	d| f |
 }|std tddidfW W |r|  |r|  W S t|d|d dsFtd tddidfW W |r4|  |rB|  W S |d t ttd d}tj|tdd}|	d|d f | }i }|D ]R}	|	d }
|	d }|
dv r| dk||
< n |
dkrt|||
< n|||
< qttdd ||d |d! |d |d" d#|d$}|jd%|d&d&d'd(d)d* |W W |rF|  |rT|  W S  tjjy } zFtdd+t| idfW  Y d	}~W |r|  |r|  W S d	}~0  ty } zFtdd,t| idfW  Y d	}~W |r|  |r|  W S d	}~0 0 W |r*|  |rX|  n|rH|  |rV|  0 W n@ ty } z&tdd-t| idfW  Y d	}~S d	}~0 0 d	S ).u   Autenticación de usuariosc                 3   s   | ]}| v V  qd S r?   r)   r@   rC   r)   r*   rE      rF   zlogin.<locals>.<genexpr>)rH   rI   r5   rJ   rK   rH   rI   NrO   r7   T
dictionaryz4SELECT * FROM Usuarios WHERE correo_electronico = %su   ❌ Usuario no encontradou   Credenciales inválidas  rP   u   ❌ Contraseña incorrectaid)seconds)rY   expHS256)	algorithmcSELECT nombre_configuracion, valor_configuracion FROM Configuraciones_Usuario WHERE usuario_id = %snombre_configuracionvalor_configuracionrT   rV   rW   rS   r0   zLogin exitosorG   foto_perfil)ro   rG   rH   rx   )r1   r2   tokenusuarioconfiguraciones
auth_tokenFLaxiQ /)httponlysecuresamesitemax_agepathr[   r\   r]   )r   r_   r`   r   ra   rb   r+   r,   r-   r8   r9   r^   rd   checkpwrf   r   utcnowr   r!   jwtr    fetchallfloatr
   
set_cookier"   r#   r&   r;   r:   )rH   rj   r'   r-   rz   payloadry   configsr{   configkeyvalueresponser(   r)   rC   r*   login   s    ;3/


&&
r   c                 C   s\   zt j| tdgd}|d W S  t jy:   td Y d S  t jyV   td Y d S 0 d S )Nrr   )
algorithmsrY   u   ❌ Token expiradou   ❌ Token inválido)r   rh   r    ExpiredSignatureErrorr^   InvalidTokenError)ry   r   r)   r)   r*   verify_token#  s    
r   c                    s    fdd} j |_ |S )Nc                     s.  d }t jd}|rD|drD|dd  }td|d d  d nndt jv r|t jd}td|rn|d d nd	 d n6d
t jv rt jd
}td|r|d d nd	 d |std t jdv rtdS t	ddidfS t
|}|std t jdv r
tdS t	ddidfS |t _ | i |S )NAuthorizationzBearer    u   🔍 Token en Authorization:    z...r|   u   🔍 Token en cookie: Nonery   u   🔍 Token en query: u   ❌ No se encontró token)iniciomodo_visualmodo_auditivo
bibliotecaconfiguracionr~   r5   zToken requeridorn   u   ❌ Token inválido o expiradou   Token inválido)r   headersget
startswithr^   cookiesargsendpointr	   r   r   rY   )r   kwargsry   auth_headerrY   fr)   r*   decorated_function/  s0    
"
 
z)auth_required.<locals>.decorated_function)__name__)r   r   r)   r   r*   auth_required.  s    r   z/api/documentsc               
      s  t j t fdddD s,tddidfS  d  }  d  }t| d	k r`tdd
idfS t| dkr|tddidfS d}d}d}d}d}z<zht }|stddidfW W |r|  S |jdd}|	dt j
f | }|  i }	|D ]P}
|
d }|
d }|dv r&| dk|	|< q|dkr>t||	|< q||	|< q|	dd}|	dd}ztjd|||ddd}|  | }|d r2t| }|sd!t jdd"  }t d#}| d$| d%}tjtd&d'd(d)}tj|dd* tj||}|d+ }|d,rtjtd&|d-}tj |rt!"|| t#|d.}|$ }W d   n1 sz0    Y  zt%| W n4 t&y } zt'd/|  W Y d}~n
d}~0 0 nt'd0|  nVtj|dd1}|j(d2krH|j)}t#|d3}|*| W d   n1 s&0    Y  nt'd4|dd5  W n8 tj+j,y } zt'd6|  W Y d}~n
d}~0 0 | }|	d7t j
| ||||f |j-}|.  |rd8nd9}td d:| ||du|r|ndd;d<fW W |r|  S  t/j0j1y` } zDt'd=|  tdd>t2| idfW  Y d}~W |rV|  S d}~0  t&y } zDt'd?|  tdd@t2| idfW  Y d}~W |r|  S d}~0 0 W |r|  n|r|  0 dS )AzGuardar documento del usuarioc                 3   s   | ]}| v V  qd S r?   r)   r@   rC   r)   r*   rE   W  rF   z save_document.<locals>.<genexpr>)titulo	contenidor5   rJ   rK   r   r          El título no puede estar vacío2   )   El título no puede exceder 50 caracteresN
audio/mpegrO   r7   Trl   z
            SELECT nombre_configuracion, valor_configuracion
            FROM Configuraciones_Usuario
            WHERE usuario_id = %s
        ru   rv   rw   rW   rS   rQ   rR   g      ?z+http://localhost:5001/api/synthesize-speech)text
voice_typespeed
   )r_   timeoutr0   Z
documento_   z%Y%m%d_%H%M%S_z.mp3r   r   assetsaudioexist_ok	audio_urlz/static/r~   rbu0   ⚠️ No se pudo eliminar el archivo temporal: u'   ⚠️ Archivo de audio no encontrado: )r   r4   wbu   ⚠️ Error en síntesis TTS: ZDesconocidou(   ⚠️ Error al llamar al servicio TTS: z
            INSERT INTO Documentos
            (usuario_id, titulo, contenido, archivo_audio, nombre_archivo, tipo_mime)
            VALUES (%s, %s, %s, %s, %s, %s)
        z	con audioz	sin audioz Documento guardado exitosamente )r1   r2   document_id	has_audioaudio_filenamerZ   u   ⚠️ Error de base de datos: r[   u   ⚠️ Error inesperado: r\   )3r   r_   r`   r   ra   rc   r+   r,   r-   r8   rY   r   rb   r   r   requestspostraise_for_statusr   uuiduuid4hexr   nowstrftimeosr   joinproject_rootmakedirsr   lstripexistsshutilcopy2openreadremover:   r^   status_codecontentwrite
exceptionsRequestExceptionri   r.   r"   r#   r&   r;   )r   r   archivo_audio_blobZnombre_archivo_audioZruta_archivo_audio	tipo_mimer'   Zcursor_configr   r{   r   r   r   r   r   Ztts_responseZtts_dataZtitulo_seguro	timestamp	audio_dirr   audio_file_path
audio_filer(   Zaudio_responser   r-   r   Zaudio_statusr)   rC   r*   save_documentQ  s    y


	(&,$&
&
r   GETc               
   C   st  d} d}zFzt  } | sDtddidfW W |r6|  | rB|   S | jdd}|dtjf | }|D ]4}|d r|d  |d< |d	 rl|d	  |d	< qltd
|ddfW W |r|  | r|   S  t	j
jy0 } zDtddt| idfW  Y d}~W |r|  | r&|   S d}~0 0 W |rB|  | rp|   n|r`|  | rn|   0 dS )zObtener documentos del usuarioNr5   rO   r7   Trl   aD  
            SELECT id, titulo, contenido, 
                   CASE WHEN archivo_audio IS NOT NULL THEN TRUE ELSE FALSE END as has_audio,
                   nombre_archivo, tipo_mime, creado_en, actualizado_en 
            FROM Documentos 
            WHERE usuario_id = %s 
            ORDER BY actualizado_en DESC
        	creado_enactualizado_enr0   )r1   	documentsr4   r[   r+   r   r,   r-   r8   r   rY   r   	isoformatr"   r#   r&   r;   )r'   r-   r   docr(   r)   r)   r*   get_user_documents  s^    	&
r   z /api/documents/<int:document_id>c              
   C   s  d}d}znzt  }|sDtddidfW W |r6|  |rB|  S |jdd}|d| tjf | }|stddid	fW W |r|  |r|  S |d
 r|d
  |d
< |d r|d  |d< td|ddfW W |r|  |r|  S  t	j
jyX } zDtddt| idfW  Y d}~W |r@|  |rN|  S d}~0 0 W |rj|  |r|  n|r|  |r|  0 dS )u    Obtener un documento específicoNr5   rO   r7   Trl   a&  
            SELECT id, titulo, contenido, 
                   CASE WHEN archivo_audio IS NOT NULL THEN TRUE ELSE FALSE END as has_audio,
                   nombre_archivo, tipo_mime, creado_en, actualizado_en 
            FROM Documentos 
            WHERE id = %s AND usuario_id = %s
        Documento no encontrado  r   r   r0   )r1   documentr4   r[   r+   r   r,   r-   r8   r   rY   r9   r   r"   r#   r&   r;   )r   r'   r-   r   r(   r)   r)   r*   get_document  sj     &
r   z&/api/documents/<int:document_id>/audioc              
   C   s@  d}d}zzt  }|sFtddidfW W |r8|  |rD|  S | }|d| tjf | }|stddidfW W |r|  |r|  S |\}}}|rtj	
tdd	d
d|}tj	|rttj	
tdd	d
d||pdddW W |r|  |r|  S |rlddlm} |||p,dd|p6d dddd}	|	W W |r\|  |rj|  S tddidfW W |r|  |r|  S  tjjy }
 zDtddt|
 idfW  Y d}
~
W |r|  |r|  S d}
~
0 0 W |r|  |r<|  n|r,|  |r:|  0 dS )u,   Obtener el audio de un documento específicoNr5   rO   r7   z
            SELECT nombre_archivo, tipo_mime, archivo_audio
            FROM Documentos 
            WHERE id = %s AND usuario_id = %s AND (nombre_archivo IS NOT NULL OR archivo_audio IS NOT NULL)
        Audio no encontrador   r   r   r   r   r   F)mimetypeas_attachmentr   Responsezinline; filename="z	audio.mp3"public, max-age=3600zContent-DispositionzCache-Controlr   r   Audio no disponibler[   )r+   r   r,   r-   r8   r   rY   r9   r   r   r   r   r   r   flaskr   r"   r#   r&   r;   )r   r'   r-   r3   Znombre_archivor   archivo_audior   r   r   r(   r)   r)   r*   get_document_audioE  s    /!
&
r   PUTc           	   
   C   s  t j}|stddidfS d}d}zzt }|s`tddidfW W |rR|  |r^|  S | }|d| t jf | stddid	fW W |r|  |r|  S g }g }d
|v rZ|d
 	 }t
|dk rtddidfW W |r|  |r|  S t
|dkrFtddidfW W |r6|  |rD|  S |d || d|v r||d ||d  d|v r|d ||d  |stddidfW W |r|  |r|  S ||  |t j dd| d}||| |  tddddfW W |r2|  |r@|  S  tjjy } zDtddt| idfW  Y d}~W |r|  |r|  S d}~0 0 W |r|  |r|  n|r|  |r|  0 dS )z Actualizar documento del usuarior5   zNo se proporcionaron datosrK   NrO   r7   z;SELECT id FROM Documentos WHERE id = %s AND usuario_id = %sr   r   r   r   r   r   r   ztitulo = %sr   zcontenido = %sr   zarchivo_audio = %szNo hay campos para actualizarzUPDATE Documentos SET z, z" WHERE id = %s AND usuario_id = %sr0   z"Documento actualizado exitosamenter6   r4   r[   )r   r_   r   r+   r,   r-   r8   rY   r9   ra   rc   appendr   r.   r"   r#   r&   r;   )	r   rD   r'   r-   Zupdate_fieldsvaluesr   queryr(   r)   r)   r*   update_document  s    1)
 






&
r   DELETEc              
   C   sn  d}d}z@zt  }|sDtddidfW W |r6|  |rB|  S | }|d| tjf |jdkrtddidfW W |r|  |r|  S |  td	d
ddfW W |r|  |r|  S  t	j
jy* } zDtddt| idfW  Y d}~W |r|  |r |  S d}~0 0 W |r<|  |rj|  n|rZ|  |rh|  0 dS )zEliminar documento del usuarioNr5   rO   r7   z8DELETE FROM Documentos WHERE id = %s AND usuario_id = %sr   r   r   r0   z Documento eliminado exitosamenter6   r4   r[   r+   r   r,   r-   r8   r   rY   rowcountr.   r"   r#   r&   r;   )r   r'   r-   r(   r)   r)   r*   delete_document  sb    
&
r  z/api/audio-transcriptionsc               
   C   s  t jd} t jd}| r |s0tddidfS |  } | }t| dk r\tddidfS t| dkrxtdd	idfS t jd
}d }|rt|  d}tj	
d|}tjtj	|dd || d }d }zz^t }| }|dt j||| f |  tddddfW W |r"|  |r0|  S  tjjy } zDtddt| idfW  Y d }~W |rz|  |r|  S d }~0 0 W |r|  |r|  n|r|  |r|  0 d S )Nr   texto_transcritor5   u3   Faltan datos requeridos: título o texto transcritorK   r   r      u*   El título no puede exceder 255 caracteresr   z.webmzfrontend/static/assets/audiosTr   z
            INSERT INTO Audio_a_Texto (usuario_id, archivo_audio, texto_transcrito, nombre_transcripcion)
            VALUES (%s, %s, %s, %s)
        r0   u$   Transcripción guardada exitosamenter6   rZ   r[   r7   )r   formr   r   ra   rc   filesr   r   r   r   r   dirnamesaver+   r-   r8   rY   r.   r,   r"   r#   r&   r;   )r   r  r   Z
audio_pathr   r'   r-   r(   r)   r)   r*   save_audio_transcription  s^    
&
r  c               
   C   st  d} d}zFzt  } | sDtddidfW W |r6|  | rB|   S | jdd}|dtjf | }|D ]4}|d r|d  |d< |d	 rl|d	  |d	< qltd
|ddfW W |r|  | r|   S  t	j
jy0 } zDtddt| idfW  Y d}~W |r|  | r&|   S d}~0 0 W |rB|  | rp|   n|r`|  | rn|   0 dS )z,Obtener transcripciones de audio del usuarioNr5   rO   r7   Trl   z
            SELECT id, nombre_transcripcion, creado_en, actualizado_en
            FROM Audio_a_Texto
            WHERE usuario_id = %s
            ORDER BY actualizado_en DESC
        r   r   r0   )r1   transcriptionsr4   r[   r   )r'   r-   r  transr(   r)   r)   r*   get_user_audio_transcriptions  s^    &
r  z0/api/audio-transcriptions/<int:transcription_id>c              
   C   s  d}d}znzt  }|sDtddidfW W |r6|  |rB|  S |jdd}|d| tjf | }|stddid	fW W |r|  |r|  S |d
 r|d
  |d
< |d r|d  |d< td|ddfW W |r|  |r|  S  t	j
jyX } zDtddt| idfW  Y d}~W |r@|  |rN|  S d}~0 0 W |rj|  |r|  n|r|  |r|  0 dS )u&   Obtener una transcripción específicaNr5   rO   r7   Trl   z
            SELECT id, nombre_transcripcion, texto_transcrito, creado_en, actualizado_en
            FROM Audio_a_Texto
            WHERE id = %s AND usuario_id = %s
           Transcripción no encontradar   r   r   r0   )r1   transcriptionr4   r[   r   )transcription_idr'   r-   r  r(   r)   r)   r*   get_audio_transcriptionF  sj    &
r  z6/api/audio-transcriptions/<int:transcription_id>/audioc              
   C   s  d}d}zzt  }|sFtddidfW W |r8|  |rD|  S | }|d| tjf | }|stddidfW W |r|  |r|  S |d }|rdd	lm	} ||d
d|  dddd}|W W |r|  |r|  S tddidfW W |r|  |r|  S  t
jjy| } zDtddt| idfW  Y d}~W |rd|  |rr|  S d}~0 0 W |r|  |r|  n|r|  |r|  0 dS )u2   Obtener el audio de una transcripción específicaNr5   rO   r7   zw
            SELECT archivo_audio
            FROM Audio_a_Texto
            WHERE id = %s AND usuario_id = %s
        r   r   r   r   r   zinline; filename="audio_z.mp3"r   r   r   r   r[   )r+   r   r,   r-   r8   r   rY   r9   r   r   r"   r#   r&   r;   )r  r'   r-   r3   r   r   r   r(   r)   r)   r*   get_audio_transcription_audior  sx    #
&
r  c              
   C   sn  d}d}z@zt  }|sDtddidfW W |r6|  |rB|  S | }|d| tjf |jdkrtddidfW W |r|  |r|  S |  td	d
ddfW W |r|  |r|  S  t	j
jy* } zDtddt| idfW  Y d}~W |r|  |r |  S d}~0 0 W |r<|  |rj|  n|rZ|  |rh|  0 dS )u'   Eliminar una transcripción del usuarioNr5   rO   r7   z;DELETE FROM Audio_a_Texto WHERE id = %s AND usuario_id = %sr   r  r   r0   u%   Transcripción eliminada exitosamenter6   r4   r[   r  )r  r'   r-   r(   r)   r)   r*   delete_audio_transcription  sb    
&
r  z/api/library-itemsc               
   C   s  d } d }z:t  } | s(tddidfW S | jdd}|dtjf | }|dtjf | }|D ]L}d|d	< t|d
 |d
< |d r|d  |d< |d rh|d  |d< qh|D ]\}d|d	< t|d |d
< |d pd|d< |d r|d  |d< |d r|d  |d< q|| }|j	dd dd td|ddfW S  t
y } z&tddt| idfW  Y d }~S d }~0 0 d S )Nr5   rO   r7   Trl   u  
            SELECT 
                id, 
                titulo, 
                contenido, 
                creado_en, 
                actualizado_en,
                archivo_audio IS NOT NULL as has_audio,  -- ✅ Corregido: no existe has_audio
                nombre_archivo
            FROM documentos
            WHERE usuario_id = %s
            ORDER BY actualizado_en DESC
        aX  
            SELECT 
                id, 
                nombre_transcripcion as titulo, 
                texto_transcrito as contenido, 
                creado_en, 
                actualizado_en, 
                archivo_audio
            FROM Audio_a_Texto
            WHERE usuario_id = %s
            ORDER BY actualizado_en DESC
        Z	documentoZtipor   r   r   Ztranscripcionr   r   u   Sin títuloc                 S   s   | d S )Nr   r)   )xr)   r)   r*   <lambda>  rF   z#get_library_items.<locals>.<lambda>)r   reverser0   )r1   itemsr4   zError interno del servidor: )r+   r   r-   r8   r   rY   r   boolr   sortr:   r;   )r'   r-   Z
documentosZtranscripcionesr   r  Z	all_itemsr(   r)   r)   r*   get_library_items  sP    r  z/api/user/configc            	   
   C   s  d} d}z~zt  } | sDtddidfW W |r6|  | rB|   S | jdd}|dtjf | }|dtjf | }i }|D ]L}|d	 }|d
 }|dv r|	 dk||< q|dkrt
|||< q|||< qtd||ddfW W |r|  | r|   S  tjjyh } zDtddt| idfW  Y d}~W |rP|  | r^|   S d}~0 0 W |rz|  | r|   n|r|  | r|   0 dS )u"   Obtener configuración del usuarioNr5   rO   r7   Trl   zVSELECT id, nombre_usuario, correo_electronico, foto_perfil FROM Usuarios WHERE id = %srt   ru   rv   rw   rW   rS   r0   )r1   rz   r{   r4   r[   )r+   r   r,   r-   r8   r   rY   r9   r   rb   r   r"   r#   r&   r;   )	r'   r-   rz   r   r{   r   r   r   r(   r)   r)   r*   get_user_config  sh    #
	&
r  c               
   C   s  t j} d}d}znzt }|sJtddidfW W |r<|  |rH|  S | }|  D ]l\}}t|trz|rtdnd}nt	|}|
dt j|f | r|
d|t j|f qZ|
d	t j||f qZ|  td
dddfW W |r|  |r|  S  tjjy^ } zDtddt	| idfW  Y d}~W |rF|  |rT|  S d}~0 0 W |rp|  |r|  n|r|  |r|  0 dS )u%   Actualizar configuración del usuarioNr5   rO   r7   rW   rU   zZSELECT id FROM Configuraciones_Usuario WHERE usuario_id = %s AND nombre_configuracion = %sz
                    UPDATE Configuraciones_Usuario 
                    SET valor_configuracion = %s 
                    WHERE usuario_id = %s AND nombre_configuracion = %s
                rX   r0   u'   Configuración actualizada exitosamenter6   r4   r[   )r   r_   r+   r   r,   r-   r  
isinstancer  r;   r8   rY   r9   r.   r"   r#   r&   )rD   r'   r-   r   r   Z	str_valuer(   r)   r)   r*   update_user_configB  sl    (


&
r  r~   c               
   C   s\   zt d tdW S  tyV }  z,t d|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u   Página de loginu"   🏠 Accediendo a página de loginz
login.htmlu(   ❌ Error cargando template login.html: u.   Error: No se pudo cargar la página de login. r7   N)r^   r   r:   r;   r(   r)   r)   r*   index|  s    
r   z/modo_visualc               
   C   sT   z
t dW S  tyN }  z,td|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u$   Página del asistente en modo visualzModo_Visual.htmlu.   ❌ Error cargando template Modo_Visual.html: %   Error: No se pudo cargar la página. r7   Nr   r:   r^   r;   r  r)   r)   r*   r     s
    
r   z/modo_auditivoc               
   C   sT   z
t dW S  tyN }  z,td|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u&   Página del asistente en modo auditivozModo_Auditivo.htmlu0   ❌ Error cargando template Modo_Auditivo.html: r!  r7   Nr"  r  r)   r)   r*   r     s
    
r   z/bibliotecac               
   C   sT   z
t dW S  tyN }  z,td|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u$   Página de la biblioteca de recursoszlibrary.htmlu*   ❌ Error cargando template library.html: r!  r7   Nr"  r  r)   r)   r*   r     s
    
r   z/configuracionc               
   C   sT   z
t dW S  tyN }  z,td|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u   Página de configuraciónzconfig.htmlu)   ❌ Error cargando template config.html: r!  r7   Nr"  r  r)   r)   r*   r     s
    
r   z/inicioc               
   C   sT   z
t dW S  tyN }  z,td|   dt|  dfW  Y d} ~ S d} ~ 0 0 dS )u$   Página principal después del loginz
index.htmlu(   ❌ Error cargando template index.html: r!  r7   Nr"  r  r)   r)   r*   r     s
    
r   z/leer-archivoc               
   C   s<  dt jvrtddidfS t jd } | jdkr>tddidfS | j }z|drd|  d}n|d	r| d
 t	d
}d}|j
D ]}|| 7 }qtd
 n<|dr| d td}td ntddidfW S td| j|ddfW S  ty6 } z"tdd| idfW  Y d}~S d}~0 0 dS )z"Leer contenido de archivos subidosfiler5   u%   No se ha seleccionado ningún archivorK    u   Archivo vacíoz.txtrP   z.pdfztemp.pdfz.docxz	temp.docxz,Formato no soportado. Usa .txt, .pdf o .docxr0   )r1   ZnombreZtextor4   zError al leer el archivo: r7   N)r   r  r   filenamerb   endswithr   rh   r
  r   pagesextract_textr   r   docx2txtprocessr:   )Zarchivor%  r   readerpager(   r)   r)   r*   leer_archivo  s<    










r-  z/healthc               
   C   sR   t  } | rdnd}| r|   tdt  |tttj	
ttj	
tddfS )zHealth check endpoint	connecteddisconnectedZhealthy)r1   r   r   Ztemplates_dir
static_dirZtemplates_existsZstatic_existsr4   )r+   r,   r   r   r   r   template_dirr0  r   r   r   )r'   Z	db_statusr)   r)   r*   health_check  s    


r2  __main__u#   🚀 Iniciando aplicación Auris...u   🌍 Python: u   🌍 Directorio de trabajo: u#   🌍 Variables de entorno DB: HOST=u,   ✅ Base de datos inicializada correctamenteu:   ⚠️ Error al inicializar base de datos - continuando...ZPORTi  u&   🌐 Servidor ejecutándose en puerto Z	FLASK_ENVZdevelopmentz0.0.0.0)r   r   debug)Z__doc__r   sysr_   mysql.connectorr"   r   r   r   r   r   r   r   r   r	   r
   
flask_corsr   rd   r   r)  PyPDF2r   Zwerkzeug.utilsr   base64r   r   r   asyncior   r	  __file__r   r   r1  r0  r   appnew_event_looploopset_event_loopZbackend.routes.tts_routesr   register_blueprintZbackend.routes.edge_tts_routesr   environr   
secret_keyintr%   r    r!   r+   r/   router<   rk   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r  r  r   r   r   r   r   r   r-  r2  r^   versiongetcwdr   Z
debug_moderunr)   r)   r)   r*   <module>   s   $




O
T# +,;B!0)*/!I/8
	

*


