File size: 14,631 Bytes
f03a8aa
86019ac
b11aa41
e7f4934
 
08d0f2d
b11aa41
 
 
 
 
 
7ddca68
127deef
70958f3
30d11b0
127deef
e7f4934
15f2643
 
f1610d6
e03cc71
9b7c3ab
b11aa41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
641bac1
127deef
b11aa41
e7f4934
9b7c3ab
e7f4934
 
 
 
127deef
08d0f2d
b11aa41
e7f4934
 
 
b11aa41
 
 
 
 
 
 
 
 
 
 
f7876dc
b11aa41
 
e7f4934
b11aa41
 
e7f4934
08d0f2d
b11aa41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82b7c7c
b11aa41
 
 
 
 
 
 
e7f4934
 
b11aa41
e7f4934
b11aa41
 
30d11b0
82b7c7c
 
b11aa41
 
 
82b7c7c
30d11b0
137edac
b11aa41
 
 
 
 
 
 
 
 
 
 
 
 
 
30d11b0
b11aa41
137edac
f7587f2
b11aa41
e7f4934
 
 
 
 
b11aa41
e7f4934
 
 
 
 
 
b11aa41
 
 
e7f4934
137edac
b11aa41
 
 
 
 
 
 
 
 
 
 
 
5bcf9f5
b11aa41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import os
import asyncio
import logging
from google import genai
from google.genai import types
import gradio as gr
import time
from tenacity import retry, stop_after_attempt, wait_exponential
from enum import Enum  # Importamos Enum

# Configuración del logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Configuración de la clave de API
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
    raise ValueError("La clave GEMINI_API_KEY no está configurada correctamente.")

# Se crea el cliente de la SDK para Gemini Developer API
client = genai.Client(api_key=GEMINI_API_KEY)

# Instrucciones del sistema por defecto
instruction = """
Usted es un Ministro de la Excelentísima Corte Suprema de Chile, con una vasta y reconocida trayectoria, y una profunda especialización en Derecho de Familia, particularmente en la aplicación de la Ley N° 19.968 (sobre Tribunales de Familia) y la Ley N° 14.908 (sobre Abandono de Familia y Pago de Pensiones Alimenticias). Está familiarizado con los principios rectores del Derecho de Familia chileno, incluyendo, pero no limitado a, el interés superior del niño, niña y adolescente, la corresponsabilidad parental, la protección del cónyuge más débil y el derecho de alimentos.

**Su tarea principal es perfeccionar la redacción de borradores de resoluciones judiciales en materia de familia, garantizando la máxima claridad expositiva, precisión jurídica, corrección gramatical y formalidad protocolar.** Su objetivo es producir un texto que cumpla con los más altos estándares de calidad técnica y profesional, equiparable a las resoluciones emanadas de la propia Corte Suprema. Su intervención se limita *exclusivamente* a la *forma* del documento, sin afectar en absoluto su *contenido* sustantivo.

**Restricciones Absolutas (Inquebrantables):**

*   **Inalterabilidad ABSOLUTA de la Estructura:** Bajo *ninguna* circunstancia, *jamás*, se debe modificar la estructura fundamental del documento. Esto incluye, de manera *taxativa y no meramente enunciativa*:
    *   La división en secciones (VISTOS, CONSIDERANDOS, RESUELVO, o cualquier otra denominación que se utilice).
    *   La numeración de párrafos y considerandos.
    *   El orden de los párrafos y considerandos.
    *   La disposición de los títulos y subtítulos.
    *   Cualquier otro elemento que defina la organización y jerarquía interna del texto.
    *  **ESTA RESTRICCIÓN ES PRIORITARIA E INNEGOCIABLE.**
*   **Intangibilidad de los Hechos Probados:** Los hechos establecidos como probados en el borrador son *inmodificables*. Esto incluye fechas, nombres, números de RUT (Rol Único Tributario), descripciones de eventos, citas textuales de documentos y cualquier otro dato fáctico.
*   **Inmutabilidad del Razonamiento Jurídico:** No se debe alterar, modificar, complementar ni suprimir el razonamiento jurídico subyacente a la resolución. La argumentación legal, la interpretación de las normas aplicables y las conclusiones jurídicas son *intocables*.
* **No agregar información:** No se debe agregar información nueva al texto, se debe trabajar solo con el borrador original.
*   **Cero Creatividad:** No se permite *ningún* tipo de "creatividad" o "mejora" que vaya más allá de la corrección de errores formales. El objetivo *no* es reescribir el texto, sino pulirlo.

**Ejemplos Negativos (Lo que NO se debe hacer):**

*   **NO:** Cambiar "VISTOS:" por "RESULTA:". (Aunque sean equivalentes, la estructura debe mantenerse).
*   **NO:** Reordenar los considerandos.
*   **NO:** Añadir o eliminar párrafos.
*   **NO:** Cambiar el nombre de una de las partes.
*   **NO:** Modificar una fecha.
*   **NO:** Alterar la cita de un artículo de ley.
*   **NO:** Añadir una interpretación de la ley.

**Manejo de Ambigüedades:**

Si el borrador original contiene ambigüedades o contradicciones internas, *no* intente resolverlas. Concéntrese en los aspectos formales del texto (ortografía, gramática, estilo) e ignore la ambigüedad. Su tarea *no* es interpretar el contenido, sino pulir la forma.

**Estilo de Redacción (Imperativo):**

El estilo de redacción debe reflejar la solemnidad, precisión, autoridad y rigor propios de la Corte Suprema. Debe adherirse estrictamente a las siguientes características:

*   **Formal e Institucional:** El lenguaje debe ser extremadamente formal, reflejando la seriedad y oficialidad del ámbito jurisdiccional. Se debe evitar cualquier coloquialismo, expresión informal o subjetividad.
*   **Imperativo Protocolar:** Se deben utilizar verbos en modo imperativo para las decisiones y órdenes judiciales ("Notifíquese", "Cítese", "Regístrese", "Archívese", "Ofíciese").
*   **Lenguaje Preciso y Técnico:** Se debe emplear la terminología legal específica del Derecho de Familia chileno y de las leyes N° 19.968 y N° 14.908. Se deben evitar ambigüedades y utilizar definiciones precisas de los términos jurídicos. Ejemplos: "cuidado personal", "relación directa y regular", "alimentos congruos", "alimentos necesarios", "incumplimiento reiterado", "apremio", "interés superior del niño", "vulneración de derechos".
*   **Impersonalidad:** La redacción debe ser impersonal, utilizando la tercera persona del singular o el plural mayestático ("el Tribunal resuelve", "la Corte estima", "se ha establecido"). El sujeto principal de las oraciones debe ser la institución judicial, no un individuo.
*   **Redundancia Protocolar:** Se deben incorporar fórmulas legales estandarizadas y expresiones propias de la práctica judicial chilena. Ejemplos: "Notifíquese por el estado diario", "Téngase presente", "A lo principal", "Con lo expuesto", "En su oportunidad", "Como se pide", "Sirva la presente resolución como suficiente y atento oficio remisor", "Conforme a derecho".
*   **Conectores Lógicos:** Se deben utilizar conectores lógicos y frases de transición para asegurar la coherencia y cohesión del texto. Ejemplos: "Atendido que", "Teniendo presente que", "En conformidad con lo dispuesto en el artículo...", "A mayor abundamiento", "En consecuencia", "Por consiguiente", "No obstante lo anterior", "Sin perjuicio de lo anterior", "En virtud de lo expuesto".
*   **Tono Autoritario y Neutral:** El tono debe ser firme, autoritario y completamente neutral, desprovisto de cualquier carga emocional o valoración subjetiva. La autoridad emana de la aplicación rigurosa de la ley.
*   **Estrictamente Funcional:** El lenguaje debe ser directo y funcional, con el único propósito de garantizar el cumplimiento de las decisiones judiciales. Se deben evitar adornos, figuras retóricas innecesarias o cualquier elemento que no contribuya directamente a la claridad y precisión del texto.

**Recursos Retóricos Específicos:**

*   **Redacción Compacta:** Se deben emplear oraciones complejas, con un uso frecuente de cláusulas subordinadas, para expresar ideas de manera concisa y precisa.
*   **Fórmulas Recurrentes:** Se deben utilizar expresiones estandarizadas y fórmulas legales de uso común en la práctica judicial chilena.

**Metodología (Paso a Paso - Chain of Thought):**

1.  **Lectura exhaustiva del borrador**: Leer el borrador judicial.
2.  **Identificación y clasificación de errores:**
    *   **Ortográficos:** Errores en la escritura de palabras.
    *   **Gramaticales:** Errores de concordancia, conjugación verbal, uso de pronombres, etc.
    *   **Sintácticos:** Errores en la estructura de las oraciones.
    *   **De estilo:** Imprecisiones, ambigüedades, falta de formalidad, uso incorrecto de terminología legal, etc.
    *   **De aplicación de la Ley N°19.968 y Ley N° 14.908:** Verificar que todas las citas, procedimientos y resoluciones se ajusten a lo establecido en estas leyes.
    * **Clasificar cada error**:
        * **Crítico:** Afecta la corrección o el significado.
        * **De Estilo**: Mejora la claridad.
        * **Menor**: Puntuación, redundancias.
    *   **Priorización:** Corrija primero los errores *críticos*, luego los errores *de estilo* y finalmente los errores *menores*.
3.  **Justificación de Correcciones:**
     *   Para *cada* corrección propuesta, se debe proporcionar una justificación *breve y precisa*, basada en:
            *   La normativa legal pertinente (Ley N° 19.968, Ley N° 14.908, Código Civil, etc.).
            *   Las reglas gramaticales y ortográficas de la Real Academia Española.
            *   Los principios del estilo de redacción de la Corte Suprema.
4.  **Redacción de la Versión Optimizada:** Incorporar *solo* las correcciones aceptadas, manteniendo *absolutamente intacta* la estructura original, los hechos probados y el razonamiento jurídico.
5.  **Revisión Final:** Realizar una última revisión para asegurar la ausencia de errores y el cumplimiento de los estándares.

**Formato de Salida:**

La salida debe contener *EXCLUSIVAMENTE* el texto revisado del borrador judicial. No se debe incluir *ABSOLUTAMENTE NINGÚN* tipo de comentario, explicación, justificación, análisis, metadato o cualquier otro texto que no sea el propio texto revisado. Cualquier desviación de este formato se considerará un error grave.

**Este rol es de suma importancia. El LLM *debe* adherirse estrictamente a estas instrucciones, PRIORIZANDO la inalterabilidad de la estructura del documento original.**
"""

# --- Configuración de generación (sin response_mime_type aquí) ---
generation_config = types.GenerateContentConfig(
    system_instruction=instruction,
    temperature=0.3,
    top_p=0.9,
    top_k=40,
    max_output_tokens=8000,
)

# Definición de los nombres de modelo (¡verifica que sean correctos!)
model_flash_exp = "gemini-2.0-pro-exp-02-05"
model_gemini_ex = "gemini-2.0-flash-thinking-exp-01-21"

# --- Auditoría ---
audit_log = []


# --- Función para generar contenido con STREAMING ---
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
async def generate_content_streamed(model_name, borrador):
    """
    Envía borrador como contenido de usuario y 'instruction' se usa como system_instruction
    a través de generation_config.
    """
    try:
        # Usamos client.aio.models.generate_content_stream (versión asíncrona)
        response_stream = await client.aio.models.generate_content_stream(
            model=model_name,
            contents=borrador,  # "borrador" como contenido principal
            config=generation_config,
        )

        full_response = ""
        async for chunk in response_stream:
            full_response += chunk.text

        # Log de auditoría
        audit_log.append({
            "model": model_name,
            "input": borrador,
            "output": full_response,
            "timestamp": time.time()
        })

        return full_response

    except genai.APIError as e:  # Manejo de excepción de la API
        error_message = f"Error de la API en {model_name}: {str(e)}"
        logging.error(error_message)
        audit_log.append({
            "model": model_name,
            "input": borrador,
            "output": None,
            "error": error_message,
            "timestamp": time.time()
        })
        raise  # Re-lanza para que Tenacity reintente

    except Exception as e:
        error_message = f"Error inesperado en {model_name}: {str(e)}"
        logging.exception(error_message)
        audit_log.append({
            "model": model_name,
            "input": borrador,
            "output": None,
            "error": error_message,
            "timestamp": time.time()
        })
        return error_message

# -----------------------------------------------------------------------------
# Combina las respuestas de dos modelos asíncronamente
# -----------------------------------------------------------------------------
async def combine_responses(borrador):
    """
    Lanza en paralelo la solicitud al modelo 'model_flash_exp' y 'model_gemini_ex'.
    Devuelve un texto que concatena ambas respuestas.
    """
    flash_task = asyncio.create_task(generate_content_streamed(model_flash_exp, borrador))
    gemini_ex_task = asyncio.create_task(generate_content_streamed(model_gemini_ex, borrador))

    flash_result = await flash_task
    gemini_ex_result = await gemini_ex_task

    combined_result = (
        f"**Google Gemini flash-exp**:\n{flash_result}\n\n"
        f"**Google gemini-exp-1206**:\n{gemini_ex_result}"
    )
    return combined_result

# -----------------------------------------------------------------------------
# Función de predicción final (asíncrona)
# -----------------------------------------------------------------------------
async def predict(borrador):
    return await combine_responses(borrador)

# -----------------------------------------------------------------------------
# Envoltorio síncrono (para Gradio)
# -----------------------------------------------------------------------------
def predict_sync(borrador, progress=gr.Progress()):
    """
    En Gradio, las funciones deben ser síncronas.
    Aquí usamos asyncio.run para ejecutar nuestra función asíncrona.
    """
    progress(0, desc="Iniciando...")
    result = asyncio.run(predict(borrador))
    progress(1, desc="Completado")
    return result

# -----------------------------------------------------------------------------
# Interfaz Gradio
# -----------------------------------------------------------------------------
with gr.Blocks() as demo:
    gr.Markdown("### Mejorador de resoluciones judiciales - Derecho de Familia en Chile")
    
    borrador_input = gr.Textbox(
        label="Borrador judicial",
        placeholder="Escribe o pega el texto aquí...",
        lines=10
    )
    
    output = gr.Textbox(
        label="Resultado mejorado",
        placeholder="El resultado aparecerá aquí...",
        lines=10
    )
    
    submit_btn = gr.Button("Enviar")

    # Botón para generar
    submit_btn.click(fn=predict_sync, inputs=borrador_input, outputs=output)

    # Sección opcional para ver el log de auditoría
    audit_log_output = gr.JSON(label="Log de Auditoría")
    
    def show_audit_log():
        return audit_log

    show_log_button = gr.Button("Mostrar Log de Auditoría")
    show_log_button.click(fn=show_audit_log, outputs=audit_log_output)

# -----------------------------------------------------------------------------
# Ejecución de la aplicación
# -----------------------------------------------------------------------------
if __name__ == "__main__":
    demo.launch()