Darka001 commited on
Commit
9786944
·
verified ·
1 Parent(s): 8770cf5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +286 -0
app.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from gradio_calendar import Calendar
4
+
5
+
6
+ from langchain.embeddings.huggingface import HuggingFaceEmbeddings
7
+ from langchain_community.vectorstores import Chroma
8
+ from langchain_core.output_parsers import StrOutputParser
9
+ import torch
10
+ from transformers import (
11
+ AutoModelForCausalLM,
12
+ AutoTokenizer,
13
+ BitsAndBytesConfig,
14
+ pipeline
15
+ )
16
+
17
+
18
+ from langchain.text_splitter import CharacterTextSplitter
19
+ from langchain.document_transformers import Html2TextTransformer
20
+ from langchain.document_loaders import AsyncChromiumLoader
21
+
22
+ from langchain.embeddings.huggingface import HuggingFaceEmbeddings
23
+ from langchain.vectorstores import Chroma
24
+
25
+ from langchain.prompts import PromptTemplate
26
+ from langchain.llms import HuggingFacePipeline
27
+ from langchain.chains import LLMChain
28
+ from langchain_core.runnables import RunnablePassthrough, RunnableParallel
29
+ from langchain.prompts import ChatPromptTemplate
30
+ import re
31
+
32
+
33
+ instructor_embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large",
34
+ model_kwargs={"device": "cuda"})
35
+
36
+
37
+
38
+ model_name='SherlockAssistant/Mistral-7B-Instruct-Ukrainian'
39
+
40
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
41
+ tokenizer.pad_token = tokenizer.eos_token
42
+ tokenizer.padding_side = "right"
43
+
44
+
45
+ # Activate 4-bit precision base model loading
46
+ use_4bit = True
47
+
48
+ # Compute dtype for 4-bit base models
49
+ bnb_4bit_compute_dtype = "float16"
50
+
51
+ # Quantization type (fp4 or nf4)
52
+ bnb_4bit_quant_type = "nf4"
53
+
54
+ # Activate nested quantization for 4-bit base models (double quantization)
55
+ use_nested_quant = False
56
+
57
+
58
+ compute_dtype = getattr(torch, bnb_4bit_compute_dtype)
59
+
60
+ bnb_config = BitsAndBytesConfig(
61
+ load_in_4bit=use_4bit,
62
+ bnb_4bit_quant_type=bnb_4bit_quant_type,
63
+ bnb_4bit_compute_dtype=compute_dtype,
64
+ bnb_4bit_use_double_quant=use_nested_quant,
65
+ )
66
+
67
+ # Check GPU compatibility with bfloat16
68
+ if compute_dtype == torch.float16 and use_4bit:
69
+ major, _ = torch.cuda.get_device_capability()
70
+ if major >= 8:
71
+ print("=" * 80)
72
+ print("Your GPU supports bfloat16: accelerate training with bf16=True")
73
+ print("=" * 80)
74
+
75
+
76
+ model = AutoModelForCausalLM.from_pretrained(
77
+ model_name,
78
+ quantization_config=bnb_config,
79
+ )
80
+
81
+ text_generation_pipeline = pipeline(
82
+ model=model,
83
+ tokenizer=tokenizer,
84
+ task="text-generation",
85
+ temperature=0.01,
86
+ repetition_penalty=1.2,
87
+ return_full_text=True,
88
+ max_new_tokens=750, do_sample=True,
89
+ top_k=50, top_p=0.95
90
+ )
91
+ mistral_llm = HuggingFacePipeline(pipeline=text_generation_pipeline)
92
+ # # load chroma from disk
93
+ db3 = Chroma(persist_directory="/content/gdrive/MyDrive/diploma/all_emb/chroma/", embedding_function=instructor_embeddings)
94
+
95
+
96
+
97
+
98
+ retriever = db3.as_retriever(search_type="similarity_score_threshold",
99
+ search_kwargs={"score_threshold": .5,
100
+ "k": 20})
101
+
102
+ #retriever = db3.as_retriever(search_kwargs={"k":15})
103
+ # Get pre-written rag prompt
104
+ def format_docs(docs):
105
+ return "\n\n".join(doc.page_content for doc in docs)
106
+
107
+
108
+ template ="""" [INST] Ти асистент для надання відповідей з законодавства України. Використовуй лише вказаний нижче Context максимально точно. Описуй лише події простими словами без формальностей. Пиши чотири речення і будь максимально точним. Якщо контекст пустий - пиши "Я не маю релевантної інформації. Спробуйте ще".
109
+ Context: {context}
110
+ ### QUESTION:
111
+ {question}
112
+ [/INST]
113
+ """
114
+ prompt = PromptTemplate(
115
+ input_variables=["context", "question"],
116
+ template=template,
117
+ )
118
+
119
+ rag_chain_from_docs = (
120
+ RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))
121
+ | prompt
122
+ | mistral_llm
123
+ | StrOutputParser()
124
+ )
125
+
126
+ rag_chain_with_source = RunnableParallel(
127
+ {"context": retriever, "question": RunnablePassthrough()}
128
+ ).assign(answer=rag_chain_from_docs)
129
+
130
+
131
+
132
+ def format_result(result):
133
+ # Extract unique pairs of titles and video IDs from the context
134
+ unique_videos = set((doc.metadata['title'], doc.metadata['act_url']) for doc in result['context'])
135
+
136
+ # Create a plain text string where each title is followed by its URL
137
+ titles_with_links = [
138
+ unique_videos = set((doc.metadata['title'], doc.metadata['act_url']) for doc in result['context'])
139
+ f"{title}: {act_url}" for title, act_url in unique_videos
140
+ ]
141
+
142
+ # Join these entries with line breaks to form a clear list
143
+ titles_string = '\n'.join(titles_with_links)
144
+ titles_formatted = f"Використані закони:\n{titles_string}"
145
+
146
+ # Combine the answer from the result with the formatted list of video links
147
+ answer = result['answer']
148
+ response = f"{answer}\n\n{titles_formatted}"
149
+
150
+ return response
151
+
152
+
153
+
154
+ def generate_with_filters(message, subject_input, rubric, date_beg, date_end):
155
+ if date_beg == "2010-01-01" and date_end == "2025-01-01":
156
+ rag_chain_with_filters = RunnableParallel(
157
+ {"context": db3.as_retriever(search_type="mmr", search_kwargs={"k": 15,
158
+ "filter": {'$and': [{'subject': {
159
+ '$in': subject_input}}, {
160
+ 'rubric': {
161
+ '$in': rubric}}]}}),
162
+ "question": RunnablePassthrough()}
163
+ ).assign(answer=rag_chain_from_docs)
164
+ else:
165
+ rag_chain_with_filters = RunnableParallel(
166
+ {"context": db3.as_retriever(search_type="mmr", search_kwargs={"k": 15,
167
+ "filter": {'$and': [{'subject': {
168
+ '$in': subject_input}}, {
169
+ 'rubric': {
170
+ '$in': rubric}},"act_date": {"$gte": date_beg}, "act_date": {"$lte": date_end}] }}), "question": RunnablePassthrough()}
171
+ ).assign(answer=rag_chain_from_docs)
172
+ result = rag_chain_with_filters.invoke(message)
173
+ return result
174
+
175
+ def summarize_act(message, act_number):
176
+ template = """" [INST] Ти асистент для надання відповідей з законодавства України.На вхід ти отримав один закон, підсуму його простими словами, викинь формальності та стандартні фрази. Додай усі зміни, які згадуються і цьому документі і опиши їх трьома реченнями. Якщо контекст пустий - пиши "Я не маю релевантної інформації. Спробуйте ще".
177
+ Context: {context}
178
+ ### QUESTION:
179
+ {question}
180
+ [/INST]
181
+ """
182
+ prompt = PromptTemplate(
183
+ input_variables=["context", "question"],
184
+ template=template,
185
+ )
186
+
187
+ rag_chain_from_docs = (
188
+ RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))
189
+ | prompt
190
+ | mistral_llm
191
+ | StrOutputParser()
192
+ )
193
+
194
+ rag_chain_summarize = RunnableParallel(
195
+ {"context": db3.as_retriever( search_kwargs={"k": 150, "filter": {'act_number': {
196
+ '$eq': act_number}}}), "question": RunnablePassthrough()}
197
+ ).assign(answer=rag_chain_from_docs)
198
+ return rag_chain_summarize.invoke("")
199
+
200
+
201
+ def generate_answer(message, history, checkbox,subject_input, rubric, date_beg, date_end, act_number):
202
+ result = ""
203
+ if checkbox:
204
+ if act_number=="":
205
+ return "Будь ласка, введіть номер акту для отримання основної інформації з нього, або зніміть відповідний прапорець."
206
+ #result = summarize_act(message, act_number)
207
+ return "короткий опис"+act_number
208
+ if subject_input is None and rubric is None and date_beg == "2010-01-01" and date_end == "2025-01-01":
209
+ #result = rag_chain_with_source.invoke(message)
210
+ return "введені фільтри пусті"+message
211
+
212
+ else:
213
+ if subject_input is None or subject_input ==[]:
214
+ subject_input = ["Президент України", "Кабінет міністрів України", "Народний депутат України"]
215
+ if rubric is None or rubric== []:
216
+ rubric = ['Двосторонні міжнародні угоди', 'Багатосторонні міжнародні угоди',
217
+ 'Галузевий розвиток', 'Економічна політика',
218
+ 'Державне будівництво', 'Соціальна політика', 'Правова політика',
219
+ 'Безпека і оборона', 'Гуманітарна політика']
220
+ #result = geherate_with_filters(message)
221
+ return str(subject_input), str(rubric), date_beg, date_end
222
+
223
+ result['answer'] =result['answer'].split("[/INST]")[-1].strip()
224
+ formatted_results = format_result(result)
225
+ return formatted_results
226
+
227
+
228
+
229
+ def change_group(check_value):
230
+ if check_value :
231
+ return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
232
+ else:
233
+ return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=True),
234
+ gr.update(visible=False)]
235
+
236
+
237
+ with gr.Blocks(theme=gr.themes.Soft()) as demo :
238
+
239
+ with gr.Group() as group_components :
240
+ date_beg =Calendar(type="string", label="Почакова дата пошуку", info="Натисніть на значок календаря для вибору дати", render = False, value="2010-01-01")
241
+ date_end = Calendar(type="string", label="Кінцева дата пошуку", info="Натисніть на значок календаря для вибору дати", render = False, value="2025-01-01")
242
+
243
+ subject_input = gr.Dropdown(
244
+ ["Президент України", "Кабінет міністрів України", "Народний депутат України"], multiselect=True, label="Ініціатор", info="Виберіть ініціатора законопроєкту", render=False)
245
+ rubric = gr.Dropdown(['Двосторонні міжнародні угоди', 'Багатосторонні міжнародні угоди',
246
+ 'Галузевий розвиток', 'Економічна політика',
247
+ 'Державне будівництво', 'Соціальна політика', 'Правова політика',
248
+ 'Безпека і оборона', 'Гуманітарна політика'], multiselect=True, label='Тематика', info="Оберіть, яких галузей стосується законопроєкт", render=False)
249
+
250
+
251
+ act_number = gr.Textbox(label='Номер законодавчого акту', placeholder="Наприклад: 861-20 ",visible= False, render=False)
252
+
253
+
254
+ action_checkbox = gr.Checkbox(label="Хочу отримати підсумок одного документу", value=False, render=False)
255
+ action_checkbox.input(fn=change_group, inputs= [action_checkbox], outputs = [subject_input, date_beg, date_end, rubric, act_number])
256
+ gr.ChatInterface(
257
+
258
+ generate_answer,
259
+ chatbot=gr.Chatbot(height=400, render = False),
260
+ textbox = gr.Textbox(placeholder="Ввести питання", container=False, scale=7, render = False),
261
+ title="Законодавчий Помічник",
262
+ description="Спитай мене про будь-які регуляції в чинних законах України.",
263
+ # # examples=["мобілізація", "земельна реформа", "екологія"],
264
+
265
+ cache_examples=False,
266
+ retry_btn=None,
267
+ undo_btn=None,
268
+ clear_btn=None,
269
+ submit_btn="Спитати",
270
+ stop_btn=None,
271
+ additional_inputs=[
272
+ action_checkbox,
273
+ subject_input,
274
+ rubric,
275
+ date_beg,
276
+ date_end,
277
+ act_number ],
278
+ additional_inputs_accordion=gr.Accordion(open=False, label="Додаткові фільтри", render = False)
279
+
280
+ )
281
+
282
+
283
+ if __name__ == '__main__':
284
+ demo.launch(share = False)
285
+
286
+