vecervantes89 commited on
Commit
3698f4a
·
verified ·
1 Parent(s): 34ffabd

Upload 3 files

Browse files
Files changed (3) hide show
  1. app3.py +138 -0
  2. requirements.txt +17 -0
  3. runtime.txt +1 -0
app3.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import pdfplumber
4
+ import gradio as gr
5
+ from openai import OpenAI
6
+ from huggingface_hub import hf_hub_download, list_repo_files
7
+ from dotenv import load_dotenv
8
+
9
+ # ------------------------------------------------------------
10
+ # CONFIGURACIÓN DEL CLIENTE OPENAI
11
+ # ------------------------------------------------------------
12
+ load_dotenv()
13
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
14
+
15
+ # ------------------------------------------------------------
16
+ # CONFIGURACIÓN DEL ASISTENTE
17
+ # ------------------------------------------------------------
18
+ system_prompt = """
19
+ Eres un Asistente de Inteligencia Artificial especializado en Auditoría Interna,
20
+ formado bajo las Normas Internacionales para la Práctica Profesional de la Auditoría Interna
21
+ emitidas por el IIA (Institute of Internal Auditors).
22
+
23
+ Tu función es apoyar a auditores internos en análisis, planeación, ejecución,
24
+ evaluación y documentación de auditorías, así como en la preparación para el
25
+ examen CIA (Certified Internal Auditor). Tus respuestas deben reflejar:
26
+ - Objetividad, integridad y confidencialidad.
27
+ - Los valores de Gentera: Responsabilidad, Empatía, Innovación y Transparencia.
28
+ - Lenguaje claro, profesional y humano.
29
+
30
+ Si la pregunta se relaciona con auditoría, control interno, riesgos o ética profesional,
31
+ responde con rigor técnico y ejemplos prácticos. Si se pide un resumen de un PDF,
32
+ integra el contenido del documento correspondiente.
33
+ """
34
+
35
+ # ------------------------------------------------------------
36
+ # CARGA DE PDFs DESDE HUGGING FACE (DATASET)
37
+ # ------------------------------------------------------------
38
+ REPO_ID = "vecervantes89/auditoria_interna_pdfs"
39
+ REPO_TYPE = "dataset" # <- ESTA LÍNEA ES CLAVE
40
+
41
+ def extract_pdf_text(local_path):
42
+ """Extrae texto completo de un archivo PDF."""
43
+ text_parts = []
44
+ with pdfplumber.open(local_path) as pdf:
45
+ for page in pdf.pages:
46
+ text_parts.append(page.extract_text() or "")
47
+ return "\n".join(text_parts)
48
+
49
+ def load_hf_pdfs_text(repo_id, repo_type="dataset"):
50
+ """Carga y concatena el texto de todos los PDFs del dataset en Hugging Face."""
51
+ try:
52
+ files = [f for f in list_repo_files(repo_id=repo_id, repo_type=repo_type) if f.lower().endswith(".pdf")]
53
+ except Exception as e:
54
+ print(f"[ERROR] No se pudo listar los archivos del repo '{repo_id}': {e}")
55
+ return {"files": [], "all_text": "", "by_name": {}}
56
+
57
+ entries = []
58
+ for f in files:
59
+ try:
60
+ local_path = hf_hub_download(repo_id=repo_id, filename=f, repo_type=repo_type)
61
+ text = extract_pdf_text(local_path)
62
+ entries.append({"name": f, "text": text})
63
+ print(f"[OK] Cargado {f}")
64
+ except Exception as e:
65
+ print(f"[ERROR] Falló la carga de {f}: {e}")
66
+
67
+ all_text = "\n\n".join(e["text"] for e in entries)
68
+ by_name = {e["name"]: e["text"] for e in entries}
69
+ print(f"[INFO] Se cargaron {len(entries)} PDFs correctamente desde {repo_id}.")
70
+ return {"files": entries, "all_text": all_text, "by_name": by_name}
71
+
72
+ HF_DOCS = load_hf_pdfs_text(REPO_ID, REPO_TYPE)
73
+
74
+ # ------------------------------------------------------------
75
+ # LÓGICA DEL CHAT
76
+ # ------------------------------------------------------------
77
+ def buscar_mejor_fragmento(pregunta, docs, max_chars=3000):
78
+ """Encuentra el fragmento más relevante de los PDFs para la pregunta."""
79
+ q = pregunta.lower()
80
+ for name, text in docs["by_name"].items():
81
+ if name.lower() in q:
82
+ return name, text[:max_chars]
83
+
84
+ tokens = [t for t in re.findall(r"[a-záéíóúüñ0-9]+", q) if len(t) > 2]
85
+ best_name, best_score, best_text = "", 0, ""
86
+ for e in docs["files"]:
87
+ score = sum(e["text"].lower().count(t) for t in tokens)
88
+ if score > best_score:
89
+ best_score, best_name, best_text = score, e["name"], e["text"]
90
+ return (best_name, best_text[:max_chars]) if best_score > 0 else ("", "")
91
+
92
+ def responder(mensaje, historial):
93
+ try:
94
+ nombre_pdf, fragmento = buscar_mejor_fragmento(mensaje, HF_DOCS)
95
+ if fragmento:
96
+ contexto = (
97
+ f"El siguiente texto proviene del documento '{nombre_pdf}'. "
98
+ "Úsalo para responder de manera clara, breve y profesional:\n\n"
99
+ f"{fragmento}\n\nPregunta del usuario:\n{mensaje}"
100
+ )
101
+ else:
102
+ contexto = mensaje
103
+
104
+ chat = client.chat.completions.create(
105
+ model="gpt-4o",
106
+ messages=[
107
+ {"role": "system", "content": system_prompt},
108
+ {"role": "user", "content": contexto},
109
+ ],
110
+ temperature=0.3,
111
+ )
112
+ respuesta = chat.choices[0].message.content
113
+ except Exception as e:
114
+ respuesta = f"⚠️ Error: {e}"
115
+
116
+ return "", historial + [[mensaje, respuesta]]
117
+
118
+
119
+ # ------------------------------------------------------------
120
+ # INTERFAZ VISUAL GRADIO
121
+ # ------------------------------------------------------------
122
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo:
123
+ gr.HTML("""
124
+ <div style="text-align:center; margin-bottom:20px;">
125
+ <img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" width="70" alt="Logo">
126
+ <h1 style="color:#003366;">Asistente IA de Auditoría Interna</h1>
127
+ <p style="font-size:15px;">Basado en GPT-4o y los valores del IIA y Gentera</p>
128
+ </div>
129
+ """)
130
+ chat = gr.Chatbot(label="Chat Asistente Auditoría")
131
+ msg = gr.Textbox(placeholder="Escribe tu consulta aquí...", label="Tu mensaje")
132
+ clear = gr.Button("🧹 Limpiar chat")
133
+ msg.submit(responder, [msg, chat], [msg, chat])
134
+ clear.click(lambda: None, None, chat)
135
+ gr.HTML("<p style='text-align:center; color:gray; font-size:12px;'>© 2025 Gentera AI · Desarrollado por Verónica Cervantes</p>")
136
+
137
+ demo.launch(server_name="127.0.0.1", server_port=7861, share=True)
138
+
requirements.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # UI
2
+ gradio==4.44.1
3
+
4
+ # OpenAI SDK (nuevo)
5
+ openai>=1.42.0,<2
6
+
7
+ # PDFs
8
+ pdfplumber==0.11.0
9
+ pillow>=10.4.0
10
+
11
+ # HF Hub para leer PDFs del dataset/space
12
+ huggingface_hub>=0.25.2,<1
13
+
14
+ # Utilidades
15
+ python-dotenv>=1.0.1
16
+ requests>=2.32.3
17
+
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.10