fermaf's picture
Update app.py
d1fa53a
raw
history blame contribute delete
No virus
7.42 kB
#Paz Munidal
#mi aporte
#
# Crea una consultor público, al servicio de las personas, sobre las normas formales Chilenas, las que están publicadas oficialmente
# en la Biblioteca del Congreso Nacional (www.bcn.cl), quienes a través de sus deberes a la ciudadanía facilitan el accesso a la
# información a través de datos en XML, los que luego son alimentados a un modelo LLM (a una A.I.) para que diga cómo lo clasifica en
# en arreglos ordenados matematicamente, los que luego matematicamente pueden ser comparados con la pregunta hecha al ingreso de la
# consulta y obtener un patron mátématico medible que en el mundo de las ideas, represente la semantica de la pregunta y responder
# con la norma que se consulta, en lo que más sentido tenga.
#
# Esto tiene liciencia GNU GPLv3 <--- software libre y las was que hagai con él también lo deben ser 🤟 (for ever, sin trampas, maldidta rata!!🤗)!!!
# @fermaf
# Nostr: npub1fermafqdu9ghcmsflq9wdsfwhg3zf93e6n49204ch2ztf98utw6qmhavug
#
# (de acá en adelante con mis garabatos/comentarios incluidos xd, sin ellos no hubiese hecho la primera iteración!! 🤓 )
#
#(https://30days.streamlit.app/)
#pip install streamlit
import os
import streamlit as st
import xml.etree.ElementTree as ET
import requests
import re
import time
openai_api_key = os.getenv("OPENAI_API_KEY")
#st.write(openai_api_key)
#st.write("HOLASAS")
def extraer_texto(contenidoXML):
# Espacio de nombres del XML
namespaces = {'emas': 'http://www.leychile.cl/esquemas'}
#print(contenidoXML)
# Parsear el archivo XML
#arbol = ET.parse(ruta_a_archivo) #tambien se puede pasar la ruta a un archivo /home/hola/ds49.xml
#raiz = arbol.getroot()
raiz = ET.fromstring(contenidoXML) #forma de "parsear" un XML directo desde string
# Crear una lista para almacenar todos los textos
textos = []
# Buscar todos los elementos 'texto' en el espacio de nombres correcto
for texto in raiz.iter('{http://www.leychile.cl/esquemas}Texto'):
texto.text = texto.text.replace("\t", " ")
texto.text = re.sub(" +", " ", texto.text)
texto.text = texto.text.replace(".\n", ".@")
texto.text = texto.text.replace(":\n", ":@")
texto.text = texto.text.replace("\n", " ")
texto.text = texto.text.replace(".@", ".\n")
texto.text = texto.text.replace(":@", ":\n")
texto.text = texto.text.strip()+"\n"
textos.append(texto.text)
return textos
def obtener_contenido_url(url):
respuesta = requests.get(url)
contenido = respuesta.text
return contenido
st.header("Minvu Dijur")
st.subheader('Consulta en tu norma favorita 🔎')
########################################################
#######################################################
st.sidebar.image('./image/logos/minvu.png') # <--- Este es un caso de uso, para un Consultor con toda la normativa de un organo/servicio del Estado, como el MINVU (en este caso)
########################################################
########################################################
norma = st.sidebar.selectbox(
"Selecciona una norma",
('DS49 (V. y U.) de 2011', 'Ley 21.442 (Ley de copropiedad inmobiliaria)'))
#st.write(type(option))
if norma=='DS49 (V. y U.) de 2011':
placeholder="¿qué es una entidad patrocinante?"
url="https://www.leychile.cl/Consulta/obtxml?opt=7&idNorma=1039424"
else:
placeholder="¿qué pasa si no se reunieren los quórum para sesionar?"
url="https://www.leychile.cl/Consulta/obtxml?opt=7&idNorma=1174663"
question = st.text_input("haz una pregunta:",placeholder=placeholder)
######### FIN WEB ###########
#os.environ['OPENAI_API_KEY'] = openai_api_key
contenidoXML = obtener_contenido_url(url) #<--contiene el XML de la norma en texto
#st.write(url)
######################
#Normaliza eltexto XML para extraer texto
###############
textos = extraer_texto(contenidoXML)
#TEXTO normalizado COMPLETO DE LA NORMA en ascii (sin metadata)
texto='\n'.join(textos)
#i=i+1
#st.write("HOLA1")
from langchain.schema import Document
documento = [Document(page_content=texto, metadata={"nombre": "norma"})] #<---- del tipo <class 'langchain.schema.document.Document'>
#st.write(texto[:50])
#st.write("HOLA2")
from langchain.indexes import VectorstoreIndexCreator
#st.write(i)
index = VectorstoreIndexCreator().from_documents(documento)
#st.write("HOLA3")
#st.write(texto[:100])
###############
####MUESRRA Respuesta 1
if question:
respuesta=index.query(question)
st.write("👧 \n ",respuesta)
########################################
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size = 500, chunk_overlap = 100)
all_splits = text_splitter.split_documents(documento)
##
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
vectorstore = Chroma.from_documents(documents=all_splits,embedding=OpenAIEmbeddings(openai_api_key=openai_api_key))
##
if question:
docs = vectorstore.similarity_search(question)
##
#import logging
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
#logging.basicConfig()
#logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vectorstore.as_retriever(),
llm=ChatOpenAI(temperature=0))
if question:
unique_docs = retriever_from_llm.get_relevant_documents(query=question)
####
from langchain.prompts import ChatPromptTemplate
chat = ChatOpenAI(openai_api_key=openai_api_key,temperature=0,max_tokens=600)
#customer_style = """alta contenido de modismos chilenos \
#y usando lenguaje con mucho slang
#"""
#customer_style = """Muy formal y anticuado\
#y usando lenguaje rimbombante.
#"""
template_string = """En una lista, en la que cada elemento tiene el siguiente formato: \
Document("page_content" y "metadata"), responde usando exclusivamente la información contenida "page_content",\
a la siguiente pregunta: \
pregunta: ```{text}``` \n\n
Verifica que la respuesta cumpla con:
* Nunca mencionar tus fuentes de informacion, como decir "page_content" o elementos de la lista o documento.
* No citar normas ni articulos, pero si es necesesario solo usa la información de "paga_content", señalandor Tipo de norma, año y de quien es y/o el número de articulo.
* Tu respuesta puede ser hasta de 600 tokens.
Finalmente verifica que la respuesta SIEMPRE responda esta pregunta primordial:\n
{pregunta}. \n
Si no responde, en no mas de 25 palabras, pide ingresar una nueva preguenta.
"""
prompt_template = ChatPromptTemplate.from_template(template_string)
####MUESRRA Respuesta 2
if question:
customer_messages = prompt_template.format_messages(
#style=customer_style,
pregunta=question,
text=unique_docs)
respuesta2 = chat(customer_messages)
st.divider()
st.write("👨\n",respuesta2.content)