lozanopastor commited on
Commit
450b116
·
verified ·
1 Parent(s): 27cafa5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -87
app.py CHANGED
@@ -19,27 +19,20 @@ css_style = """
19
  font-size: 24px;
20
  font-weight: bold;
21
  }
 
 
 
 
 
 
 
 
22
  .metadata-box {
23
  padding: 20px;
24
  background-color: #f0f2f6;
25
  border-radius: 10px;
26
  margin-bottom: 20px;
27
  }
28
- .metadata-title {
29
- font-size: 18px;
30
- color: #2e3b4e;
31
- margin-bottom: 10px;
32
- }
33
- button {
34
- height: 35px;
35
- width: 120px;
36
- font-size: 14px;
37
- background-color: #252850;
38
- color: white;
39
- border: none;
40
- border-radius: 5px;
41
- cursor: pointer;
42
- }
43
  .custom-input {
44
  font-size: 16px;
45
  padding: 10px;
@@ -49,6 +42,10 @@ css_style = """
49
  </style>
50
  """
51
 
 
 
 
 
52
  def get_pdf_text(pdf_docs):
53
  text = ""
54
  for pdf in pdf_docs:
@@ -67,35 +64,19 @@ def get_vector_store(text_chunks):
67
 
68
  def get_conversational_chain():
69
  prompt_template = """
70
- Responde la pregunta en español de la manera más detallada posible a partir del contexto proporcionado.
71
- Si la respuesta no está en el contexto, di "No disponible en el documento".
72
- Contexto:
73
- {context}
74
- Pregunta:
75
- {question}
76
- Respuesta:
77
- """
78
- model = ChatGroq(
79
- temperature=0.3,
80
- model_name="deepseek-r1-distill-llama-70b",
81
- groq_api_key=os.getenv("GROQ_API_KEY")
82
- )
83
- return load_qa_chain(model, chain_type="stuff",
84
- prompt=PromptTemplate(template=prompt_template,
85
- input_variables=["context", "question"]))
86
-
87
- def get_metadata_chain():
88
- prompt_template = """
89
- Responde ÚNICAMENTE con el dato solicitado usando el contexto. Máximo 5 palabras.
90
- Si no hay información, responde "No disponible".
91
  Contexto:
92
  {context}
 
93
  Pregunta:
94
  {question}
 
95
  Respuesta:
96
  """
97
  model = ChatGroq(
98
- temperature=0.1,
99
  model_name="deepseek-r1-distill-llama-70b",
100
  groq_api_key=os.getenv("GROQ_API_KEY")
101
  )
@@ -103,9 +84,6 @@ def get_metadata_chain():
103
  prompt=PromptTemplate(template=prompt_template,
104
  input_variables=["context", "question"]))
105
 
106
- def eliminar_texto_entre_tags(texto):
107
- return re.sub(r'', '', texto, flags=re.DOTALL)
108
-
109
  def extract_metadata(vector_store):
110
  metadata_questions = {
111
  "title": "¿Cuál es el título principal del documento?",
@@ -114,7 +92,7 @@ def extract_metadata(vector_store):
114
  }
115
 
116
  metadata = {}
117
- chain = get_metadata_chain()
118
 
119
  for key, question in metadata_questions.items():
120
  docs = vector_store.similarity_search(question, k=2)
@@ -122,24 +100,32 @@ def extract_metadata(vector_store):
122
  {"input_documents": docs, "question": question},
123
  return_only_outputs=True
124
  )
125
- clean_response = eliminar_texto_entre_tags(response['output_text']).strip()
126
  metadata[key] = clean_response if clean_response else "No disponible"
127
 
128
  return metadata
129
 
130
- def user_input(user_question):
 
 
 
 
 
131
  if 'vector_store' not in st.session_state:
132
  st.error("Por favor carga un documento primero")
133
  return
134
 
 
135
  docs = st.session_state.vector_store.similarity_search(user_question)
136
- response = get_conversational_chain()(
137
- {"input_documents": docs, "question": user_question},
138
- return_only_outputs=True
139
- )
140
 
141
- clean_response = eliminar_texto_entre_tags(response['output_text'])
142
- st.markdown(f"### Respuesta:\n{clean_response}")
 
 
 
 
 
 
143
 
144
  def main():
145
  st.set_page_config(page_title="PDF Consultor 🔍", page_icon="🔍", layout="wide")
@@ -147,65 +133,79 @@ def main():
147
  st.markdown(css_style, unsafe_allow_html=True)
148
 
149
  # Sidebar - Carga de documentos
150
- st.sidebar.markdown('<p class="step-number">1 Subir archivos</p>', unsafe_allow_html=True)
151
- pdf_docs = st.sidebar.file_uploader(
152
- "Subir archivo PDF",
153
- accept_multiple_files=True,
154
- type=["pdf"],
155
- key="pdf_uploader"
156
- )
 
157
 
158
  # Procesamiento automático al cargar documentos
159
- if pdf_docs and (not st.session_state.get('processed') or st.sidebar.button("Re-procesar")):
160
  with st.spinner("Analizando documento..."):
161
  try:
162
- # Procesamiento de texto
163
  raw_text = get_pdf_text(pdf_docs)
164
  text_chunks = get_text_chunks(raw_text)
165
  vector_store = get_vector_store(text_chunks)
166
 
167
- # Extracción de metadatos
168
  st.session_state.metadata = extract_metadata(vector_store)
169
  st.session_state.vector_store = vector_store
170
  st.session_state.processed = True
171
 
 
 
172
  except Exception as e:
173
  st.error(f"Error procesando documento: {str(e)}")
174
 
175
  # Mostrar metadatos
176
  if 'metadata' in st.session_state:
177
  st.markdown("---")
178
- st.subheader("📄 Información del Documento")
 
 
 
 
 
179
 
180
- col1, col2, col3 = st.columns(3)
181
- with col1:
182
- st.markdown(f"**Título:** \n{st.session_state.metadata['title']}")
183
- with col2:
184
- st.markdown(f"**Entidad:** \n{st.session_state.metadata['entity']}")
185
- with col3:
186
- st.markdown(f"**Fecha de Implantación:** \n{st.session_state.metadata['date']}")
 
187
  st.markdown("---")
188
 
189
- # Interfaz de preguntas
190
- st.sidebar.markdown('<p class="step-number">2 Realizar consultas</p>', unsafe_allow_html=True)
191
-
192
- user_question = st.text_input(
193
- "Escribe tu pregunta sobre el documento:",
194
- placeholder="Ej: ¿Qué normativa regula este proceso?",
195
- key="question_input"
196
- )
197
-
198
- col1, col2 = st.columns(2)
199
- with col1:
200
- if st.button("📝 Resumen ejecutivo"):
201
- user_input("Genera un resumen ejecutivo de máximo 3 párrafos")
202
- with col2:
203
- if st.button("📅 Fechas clave"):
204
- user_input("Lista las fechas importantes mencionadas en el documento")
205
-
206
- if user_question:
207
- with st.spinner("Buscando respuesta..."):
208
- user_input(user_question)
 
 
 
 
 
 
209
 
210
  if __name__ == "__main__":
211
  main()
 
 
19
  font-size: 24px;
20
  font-weight: bold;
21
  }
22
+ .response-box {
23
+ padding: 20px;
24
+ background-color: #f8f9fa;
25
+ border-radius: 10px;
26
+ border-left: 5px solid #252850;
27
+ margin: 20px 0;
28
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
29
+ }
30
  .metadata-box {
31
  padding: 20px;
32
  background-color: #f0f2f6;
33
  border-radius: 10px;
34
  margin-bottom: 20px;
35
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  .custom-input {
37
  font-size: 16px;
38
  padding: 10px;
 
42
  </style>
43
  """
44
 
45
+ def eliminar_proceso_pensamiento(texto):
46
+ """Elimina todo contenido entre incluyendo las etiquetas"""
47
+ return re.sub(r'', '', texto, flags=re.DOTALL).strip()
48
+
49
  def get_pdf_text(pdf_docs):
50
  text = ""
51
  for pdf in pdf_docs:
 
64
 
65
  def get_conversational_chain():
66
  prompt_template = """
67
+ Responde en español exclusivamente con la información solicitada usando el contexto.
68
+ Formato: Respuesta directa sin prefijos. Si no hay información, di "No disponible".
69
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  Contexto:
71
  {context}
72
+
73
  Pregunta:
74
  {question}
75
+
76
  Respuesta:
77
  """
78
  model = ChatGroq(
79
+ temperature=0.2,
80
  model_name="deepseek-r1-distill-llama-70b",
81
  groq_api_key=os.getenv("GROQ_API_KEY")
82
  )
 
84
  prompt=PromptTemplate(template=prompt_template,
85
  input_variables=["context", "question"]))
86
 
 
 
 
87
  def extract_metadata(vector_store):
88
  metadata_questions = {
89
  "title": "¿Cuál es el título principal del documento?",
 
92
  }
93
 
94
  metadata = {}
95
+ chain = get_conversational_chain()
96
 
97
  for key, question in metadata_questions.items():
98
  docs = vector_store.similarity_search(question, k=2)
 
100
  {"input_documents": docs, "question": question},
101
  return_only_outputs=True
102
  )
103
+ clean_response = eliminar_proceso_pensamiento(response['output_text'])
104
  metadata[key] = clean_response if clean_response else "No disponible"
105
 
106
  return metadata
107
 
108
+ def mostrar_respuesta(texto):
109
+ """Muestra la respuesta formateada en un contenedor especial"""
110
+ with st.container():
111
+ st.markdown(f'<div class="response-box">{texto}</div>', unsafe_allow_html=True)
112
+
113
+ def procesar_consulta(user_question):
114
  if 'vector_store' not in st.session_state:
115
  st.error("Por favor carga un documento primero")
116
  return
117
 
118
+ chain = get_conversational_chain()
119
  docs = st.session_state.vector_store.similarity_search(user_question)
 
 
 
 
120
 
121
+ with st.spinner("Analizando documento..."):
122
+ response = chain(
123
+ {"input_documents": docs, "question": user_question},
124
+ return_only_outputs=True
125
+ )
126
+
127
+ respuesta_final = eliminar_proceso_pensamiento(response['output_text'])
128
+ mostrar_respuesta(respuesta_final)
129
 
130
  def main():
131
  st.set_page_config(page_title="PDF Consultor 🔍", page_icon="🔍", layout="wide")
 
133
  st.markdown(css_style, unsafe_allow_html=True)
134
 
135
  # Sidebar - Carga de documentos
136
+ with st.sidebar:
137
+ st.markdown('<p class="step-number">1 Subir archivos</p>', unsafe_allow_html=True)
138
+ pdf_docs = st.file_uploader(
139
+ "Subir PDF(s)",
140
+ accept_multiple_files=True,
141
+ type=["pdf"],
142
+ label_visibility="collapsed"
143
+ )
144
 
145
  # Procesamiento automático al cargar documentos
146
+ if pdf_docs and not st.session_state.get('processed'):
147
  with st.spinner("Analizando documento..."):
148
  try:
 
149
  raw_text = get_pdf_text(pdf_docs)
150
  text_chunks = get_text_chunks(raw_text)
151
  vector_store = get_vector_store(text_chunks)
152
 
 
153
  st.session_state.metadata = extract_metadata(vector_store)
154
  st.session_state.vector_store = vector_store
155
  st.session_state.processed = True
156
 
157
+ st.rerun()
158
+
159
  except Exception as e:
160
  st.error(f"Error procesando documento: {str(e)}")
161
 
162
  # Mostrar metadatos
163
  if 'metadata' in st.session_state:
164
  st.markdown("---")
165
+ cols = st.columns(3)
166
+ campos = [
167
+ ("📄 Título", "title"),
168
+ ("🏛️ Entidad", "entity"),
169
+ ("📅 Fecha Implantación", "date")
170
+ ]
171
 
172
+ for col, (icono, key) in zip(cols, campos):
173
+ with col:
174
+ st.markdown(f"""
175
+ <div class="metadata-box">
176
+ <div class="metadata-title">{icono}</div>
177
+ {st.session_state.metadata[key]}
178
+ </div>
179
+ """, unsafe_allow_html=True)
180
  st.markdown("---")
181
 
182
+ # Interfaz de consultas
183
+ with st.form("consulta_form"):
184
+ col1, col2 = st.columns([5, 1])
185
+ with col1:
186
+ user_question = st.text_input(
187
+ "Escribe tu pregunta:",
188
+ placeholder="Ej: ¿Qué normativa regula este proceso?",
189
+ label_visibility="collapsed"
190
+ )
191
+ with col2:
192
+ st.markdown("<br>", unsafe_allow_html=True)
193
+ enviar = st.form_submit_button("Enviar ")
194
+
195
+ botones_rapidos = st.columns(3)
196
+ with botones_rapidos[0]:
197
+ if st.form_submit_button("📝 Resumen ejecutivo"):
198
+ user_question = "Genera un resumen ejecutivo de máximo 3 párrafos"
199
+ with botones_rapidos[1]:
200
+ if st.form_submit_button("🏛️ Entidad relacionada"):
201
+ user_question = "¿A qué organización o entidad pertenece este documento?"
202
+ with botones_rapidos[2]:
203
+ if st.form_submit_button("📅 Fechas clave"):
204
+ user_question = "Lista las fechas importantes mencionadas en orden cronológico"
205
+
206
+ if user_question and enviar:
207
+ procesar_consulta(user_question)
208
 
209
  if __name__ == "__main__":
210
  main()
211
+