DocUA commited on
Commit
98000f7
·
1 Parent(s): 21c8728

Edit JSON format answer

Browse files
Files changed (2) hide show
  1. main.py +80 -31
  2. 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 CITATION_QA_TEMPLATE, CITATION_REFINE_TEMPLATE
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 retrieve(self, ctx: Context, ev: StartEvent) -> Union[RetrieverEvent, None]:
121
- query = ev.get("query")
122
- question = ev.get("question")
123
- nodes = ev.get("nodes") # Отримуємо nodes з події
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- if not query:
126
- return None
 
 
 
 
127
 
128
- await ctx.set("query", query)
129
- await ctx.set("question", question)
 
 
130
 
131
- if nodes is not None:
132
- # Використовуємо передані nodes
133
- return RetrieverEvent(nodes=nodes)
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
- response = await synthesizer.asynthesize(query=query, question=question, nodes=ev.nodes)
153
- return StopEvent(result=response)
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- CITATION_REFINE_TEMPLATE = PromptTemplate(
27
- "Будь ласка, надайте відповідь, базуючись виключно на наданих правових позиціях Верховного Суду. "
28
- "При посиланні на інформацію з джерела, цитуйте відповідне джерело, використовуючи його номер у квадратних дужках: [lp_id]. "
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
- "Запит: {query_str}\n"
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
  )