File size: 7,418 Bytes
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f6426d5
db19a5e
 
f6426d5
 
 
db19a5e
 
c452148
db19a5e
d1fa53a
 
f6426d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c452148
db19a5e
 
c452148
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c452148
f6426d5
 
db19a5e
 
 
 
 
c452148
 
db19a5e
 
 
 
 
 
 
 
c452148
 
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f6426d5
db19a5e
 
 
 
 
 
 
 
 
 
f6426d5
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f6426d5
 
db19a5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#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)