Spaces:
Running
Running
Edit JSON format answer
Browse files- main.py +80 -31
- prompts.py +18 -103
main.py
CHANGED
@@ -33,7 +33,7 @@ from llama_index.core.schema import NodeWithScore
|
|
33 |
from llama_index.core.prompts import PromptTemplate
|
34 |
from llama_index.core.response_synthesizers import ResponseMode, get_response_synthesizer
|
35 |
|
36 |
-
from prompts import
|
37 |
|
38 |
|
39 |
from dotenv import load_dotenv
|
@@ -98,7 +98,7 @@ def download_s3_folder(bucket_name, prefix, local_dir):
|
|
98 |
print(f"Завантажено: {s3_key} -> {local_file_path}")
|
99 |
|
100 |
# Завантаження всього вмісту папки `Save_Index` з S3 у локальну директорію `Save_Index_Local`
|
101 |
-
download_s3_folder(BUCKET_NAME, PREFIX_RETRIEVER, LOCAL_DIR)
|
102 |
|
103 |
|
104 |
|
@@ -117,40 +117,89 @@ state_nodes = gr.State()
|
|
117 |
|
118 |
class CitationQueryEngineWorkflow(Workflow):
|
119 |
@step
|
120 |
-
async def
|
121 |
-
query = ev.get("query")
|
122 |
-
question = ev.get("question")
|
123 |
-
nodes = ev.get("nodes") #
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
-
|
126 |
-
|
|
|
|
|
|
|
|
|
127 |
|
128 |
-
|
129 |
-
|
|
|
|
|
130 |
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
else:
|
135 |
-
# Якщо nodes не передані, не виконуємо додатковий пошук
|
136 |
-
return None
|
137 |
-
|
138 |
-
@step
|
139 |
-
async def synthesize(self, ctx: Context, ev: RetrieverEvent) -> StopEvent:
|
140 |
-
query = await ctx.get("query", default=None)
|
141 |
-
question = await ctx.get("question", default=None)
|
142 |
-
llm_answer = OpenAI(model="gpt-4o-mini", temperature=0)
|
143 |
-
|
144 |
-
synthesizer = get_response_synthesizer(
|
145 |
-
llm=llm_answer,
|
146 |
-
text_qa_template=CITATION_QA_TEMPLATE,
|
147 |
-
refine_template=CITATION_REFINE_TEMPLATE,
|
148 |
-
response_mode=ResponseMode.COMPACT,
|
149 |
-
use_async=True,
|
150 |
)
|
151 |
|
152 |
-
|
153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
|
155 |
|
156 |
def parse_doc_ids(doc_ids):
|
|
|
33 |
from llama_index.core.prompts import PromptTemplate
|
34 |
from llama_index.core.response_synthesizers import ResponseMode, get_response_synthesizer
|
35 |
|
36 |
+
from prompts import PRECEDENT_ANALYSIS_TEMPLATE
|
37 |
|
38 |
|
39 |
from dotenv import load_dotenv
|
|
|
98 |
print(f"Завантажено: {s3_key} -> {local_file_path}")
|
99 |
|
100 |
# Завантаження всього вмісту папки `Save_Index` з S3 у локальну директорію `Save_Index_Local`
|
101 |
+
# download_s3_folder(BUCKET_NAME, PREFIX_RETRIEVER, LOCAL_DIR) # !!! тимчасово відключено
|
102 |
|
103 |
|
104 |
|
|
|
117 |
|
118 |
class CitationQueryEngineWorkflow(Workflow):
|
119 |
@step
|
120 |
+
async def analyze(self, ctx: Context, ev: StartEvent) -> StopEvent:
|
121 |
+
query = ev.get("query") # нове рішення
|
122 |
+
question = ev.get("question") # уточнююче питання
|
123 |
+
nodes = ev.get("nodes") # знайдені правові позиції
|
124 |
+
|
125 |
+
if not all([query, nodes]):
|
126 |
+
return StopEvent(result="Недостатньо даних для аналізу. Необхідні нове рішення та правові позиції.")
|
127 |
+
|
128 |
+
llm = OpenAI(model="gpt-4o-mini", temperature=0)
|
129 |
+
|
130 |
+
# Підготовка контексту та збір ID правових позицій
|
131 |
+
context_parts = []
|
132 |
+
all_lp_ids = []
|
133 |
+
|
134 |
+
for i, node in enumerate(nodes, 1):
|
135 |
+
# Отримуємо текст з node.node якщо це NodeWithScore
|
136 |
+
node_text = node.node.text if hasattr(node, 'node') else node.text
|
137 |
+
# Отримуємо metadata з node.node якщо це NodeWithScore
|
138 |
+
metadata = node.node.metadata if hasattr(node, 'node') else node.metadata
|
139 |
+
|
140 |
+
lp_id = metadata.get('lp_id', f'unknown_{i}')
|
141 |
+
all_lp_ids.append(lp_id)
|
142 |
+
|
143 |
+
context_parts.append(f"Source {lp_id}:\n{node_text}")
|
144 |
+
|
145 |
+
context_str = "\n\n".join(context_parts)
|
146 |
+
|
147 |
+
response_format = {
|
148 |
+
"type": "json_schema",
|
149 |
+
"json_schema": {
|
150 |
+
"name": "relevant_positions_schema",
|
151 |
+
"schema": {
|
152 |
+
"type": "object",
|
153 |
+
"properties": {
|
154 |
+
"relevant_positions": {
|
155 |
+
"type": "array",
|
156 |
+
"items": {
|
157 |
+
"type": "object",
|
158 |
+
"properties": {
|
159 |
+
"lp_id": {"type": "string"},
|
160 |
+
"description": {"type": "string"}
|
161 |
+
},
|
162 |
+
"required": ["lp_id", "description"]
|
163 |
+
}
|
164 |
+
}
|
165 |
+
},
|
166 |
+
"required": ["relevant_positions"]
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
|
171 |
+
# Формування промпту та отримання відповіді
|
172 |
+
prompt = PRECEDENT_ANALYSIS_TEMPLATE.format(
|
173 |
+
query=query,
|
174 |
+
question=question if question else "Загальний аналіз релевантності",
|
175 |
+
context_str=context_str
|
176 |
+
)
|
177 |
|
178 |
+
messages = [
|
179 |
+
ChatMessage(role="system", content="Ти - кваліфікований юрист-аналітик."),
|
180 |
+
ChatMessage(role="user", content=prompt)
|
181 |
+
]
|
182 |
|
183 |
+
response = llm.chat(
|
184 |
+
messages=messages,
|
185 |
+
response_format=response_format
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
)
|
187 |
|
188 |
+
try:
|
189 |
+
parsed_response = json.loads(response.message.content)
|
190 |
+
if "relevant_positions" in parsed_response:
|
191 |
+
return StopEvent(result=parsed_response)
|
192 |
+
else:
|
193 |
+
return StopEvent(result={
|
194 |
+
"error": "Missing required fields in response",
|
195 |
+
"content": response.message.content
|
196 |
+
})
|
197 |
+
|
198 |
+
except json.JSONDecodeError:
|
199 |
+
return StopEvent(result={
|
200 |
+
"error": "Error parsing response",
|
201 |
+
"content": response.message.content
|
202 |
+
})
|
203 |
|
204 |
|
205 |
def parse_doc_ids(doc_ids):
|
prompts.py
CHANGED
@@ -1,108 +1,23 @@
|
|
1 |
from llama_index.core.prompts import PromptTemplate
|
2 |
|
3 |
-
CITATION_QA_TEMPLATE = PromptTemplate(
|
4 |
-
"Будь ласка, надайте відповідь, базуючись виключно на наданих правових позиціях Верховного Суду. "
|
5 |
-
"При посиланні на інформацію з джерела цитуйте відповідне джерело в кінці тексту, використовуючи його номер у квадратних дужках: [lp_id]. "
|
6 |
-
"Кожна відповідь повинна містити щонайменше одне посилання на джерело. "
|
7 |
-
"Цитуйте джерело лише тоді, коли ви явно на нього посилаєтеся. "
|
8 |
-
"Якщо жодне з джерел не є корисним, зазначте це. "
|
9 |
-
"Приклад:\n"
|
10 |
-
"Source 1:\n"
|
11 |
-
"Суд постановив, що договірні зобов’язання мають виконуватись, навіть якщо умови є нечіткими.\n"
|
12 |
-
"Source 2:\n"
|
13 |
-
"У випадку непередбачених обставин, договори можуть бути анульовані за певних умов.\n"
|
14 |
-
"Запит: Чи може договір бути анульований через непередбачені обставини?\n"
|
15 |
-
"Відповідь: Договір може бути анульований за певних умов у разі настання непередбачених обставин [2].\n"
|
16 |
-
"Тепер ваша черга. Нижче наведено кілька пронумерованих правових позицій:"
|
17 |
-
"\n------\n"
|
18 |
-
"{context_str}"
|
19 |
-
"\n------\n"
|
20 |
-
"Запит: {query_str}\n"
|
21 |
-
"Відповідь: "
|
22 |
-
)
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
"
|
28 |
-
"
|
29 |
-
"
|
30 |
-
"
|
31 |
-
"Якщо жодне з джерел не є корисним, зазначте це. "
|
32 |
-
"Приклад:\n"
|
33 |
-
"Source 1:\n"
|
34 |
-
"Суд постановив, що договірні зобов’язання мають виконуватись, навіть якщо умови є нечіткими.\n"
|
35 |
-
"Source 2:\n"
|
36 |
-
"У випадку непередбачених обставин, договори можуть бути анульовані за певних умов.\n"
|
37 |
-
"Запит: Чи може договір бути анульований через непередбачені обставини?\n"
|
38 |
-
"Існуюча відповідь: Договір може бути анульований за певних умов у разі настання непередбачених обставин [2].\n"
|
39 |
-
"Тепер ваша черга. "
|
40 |
-
"Ми надали існуючу відповідь: {existing_answer}"
|
41 |
-
"Нижче наведено кілька пронумерованих правових позицій. "
|
42 |
-
"Використовуйте їх для уточнення існуючої відповіді. "
|
43 |
-
"Якщо надані правові джерела не є корисними, повторіть існуючу відповідь."
|
44 |
-
"\nПочинайте уточнення!"
|
45 |
-
"\n------\n"
|
46 |
-
"{context_msg}"
|
47 |
"\n------\n"
|
48 |
-
"
|
49 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
)
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
# CITATION_QA_TEMPLATE = PromptTemplate(
|
55 |
-
# "You are a qualified lawyer. "
|
56 |
-
# "Please provide a legal analysis based solely on the provided legal precedents and positions. "
|
57 |
-
# "When referencing a legal precedent or position, "
|
58 |
-
# "cite the appropriate source(s) using their corresponding numbers. "
|
59 |
-
# "Every answer should include at least one legal source citation relevant to the query. "
|
60 |
-
# "Only cite a source when you are explicitly referencing it. "
|
61 |
-
# "If none of the legal precedents or positions are helpful, you should indicate that. "
|
62 |
-
# "Use only the Ukrainian language to answer. "
|
63 |
-
# "For example:\n"
|
64 |
-
# "Source 1:\n"
|
65 |
-
# "The court ruled that contractual obligations must be fulfilled even if the terms are vague.\n"
|
66 |
-
# "Source 2:\n"
|
67 |
-
# "In case of unforeseen circumstances, contracts may be voided under certain conditions.\n"
|
68 |
-
# "Query: Can a contract be voided due to unforeseen circumstances?\n"
|
69 |
-
# "Answer: A contract may be voided under certain conditions if unforeseen circumstances arise [2]. "
|
70 |
-
# "Now it's your turn. Below are several numbered legal sources and precedents (legal positions):"
|
71 |
-
# "\n------\n"
|
72 |
-
# "{context_str}"
|
73 |
-
# "\n------\n"
|
74 |
-
# "New legal issue: {query_str}\n"
|
75 |
-
# "User question: {question}\n"
|
76 |
-
# "Answer: "
|
77 |
-
# )
|
78 |
-
|
79 |
-
|
80 |
-
# CITATION_REFINE_TEMPLATE = PromptTemplate(
|
81 |
-
# "You are a qualified lawyer. "
|
82 |
-
# "Please refine the legal analysis based solely on the provided legal precedents and positions. "
|
83 |
-
# "When referencing a legal precedent or position, "
|
84 |
-
# "cite the appropriate source(s) using their corresponding numbers. "
|
85 |
-
# "Every refined answer should include at least one relevant legal source citation. "
|
86 |
-
# "Only cite a source when you are explicitly referencing it. "
|
87 |
-
# "If none of the legal precedents or positions are helpful, you should repeat the existing answer. "
|
88 |
-
# "Use only the Ukrainian language to answer."
|
89 |
-
# "For example:\n"
|
90 |
-
# "Source 1:\n"
|
91 |
-
# "The court ruled that contractual obligations must be fulfilled even if the terms are vague.\n"
|
92 |
-
# "Source 2:\n"
|
93 |
-
# "In case of unforeseen circumstances, contracts may be voided under certain conditions.\n"
|
94 |
-
# "Query: Can a contract be voided due to unforeseen circumstances?\n"
|
95 |
-
# "Existing answer: A contract may be voided under certain conditions if unforeseen circumstances arise [2].\n"
|
96 |
-
# "Now it's your turn. "
|
97 |
-
# "We have provided an existing legal analysis: {existing_answer}"
|
98 |
-
# "Below are several numbered legal sources and precedents. "
|
99 |
-
# "Use them to refine the existing legal answer. "
|
100 |
-
# "If the provided legal sources are not helpful, you will repeat the existing answer."
|
101 |
-
# "\nBegin refining!"
|
102 |
-
# "\n------\n"
|
103 |
-
# "{context_msg}"
|
104 |
-
# "\n------\n"
|
105 |
-
# "New legal issue: {query_str}\n"
|
106 |
-
# "User question: {question}\n"
|
107 |
-
# "Answer: "
|
108 |
-
# )
|
|
|
1 |
from llama_index.core.prompts import PromptTemplate
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
PRECEDENT_ANALYSIS_TEMPLATE = PromptTemplate(
|
5 |
+
"Дій як кваліфікований юрист. Проаналізуй правові позиції Верховного Суду та порівняй їх з новим рішенням.\n\n"
|
6 |
+
"1. Нове рішення:\n{query}\n\n"
|
7 |
+
"2. Уточнююче питання:\n{question}\n\n"
|
8 |
+
"3. Правові позиції для аналізу:\n"
|
9 |
+
"------\n"
|
10 |
+
"{context_str}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
"\n------\n"
|
12 |
+
"На основі аналізу створи список релевантних правових позицій. "
|
13 |
+
"Кожна позиція повинна містити ID та короткий опис її суті. "
|
14 |
+
"Результат надай у такому форматі JSON:\n\n"
|
15 |
+
"{{\n"
|
16 |
+
" \"relevant_positions\": [\n"
|
17 |
+
" {{\n"
|
18 |
+
" \"lp_id\": \"ID позиції\",\n"
|
19 |
+
" \"description\": \"Короткий опис суті правової позиції\"\n"
|
20 |
+
" }}\n"
|
21 |
+
" ]\n"
|
22 |
+
"}}"
|
23 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|