DocUA commited on
Commit
c98d14c
·
1 Parent(s): 7d1496e

Add Antropic

Browse files
Files changed (1) hide show
  1. main.py +290 -137
main.py CHANGED
@@ -45,6 +45,7 @@ load_dotenv()
45
  aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID")
46
  aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
47
  openai_api_key = os.getenv("OPENAI_API_KEY")
 
48
 
49
  embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
50
  Settings.embed_model = embed_model
@@ -127,13 +128,11 @@ class ModelProvider(str, Enum):
127
 
128
  class ModelName(str, Enum):
129
  # OpenAI models
130
- GPT4 = "gpt-4"
131
- GPT4_TURBO = "gpt-4-turbo-preview"
132
- GPT4_MINI = "gpt-4o-mini"
133
  # Anthropic models
134
- CLAUDE3_SONNET = "claude-3-sonnet-20240229"
135
- CLAUDE3_OPUS = "claude-3-opus-20240229"
136
- CLAUDE3_HAIKU = "claude-3-haiku-20240307"
137
 
138
 
139
  class LLMAnalyzer:
@@ -142,9 +141,10 @@ class LLMAnalyzer:
142
  self.model_name = model_name
143
 
144
  if provider == ModelProvider.OPENAI:
145
- self.client = OpenAI(model=model_name) # Використовуємо LlamaOpenAI
146
  elif provider == ModelProvider.ANTHROPIC:
147
- self.client = Anthropic()
 
148
  else:
149
  raise ValueError(f"Unsupported provider: {provider}")
150
 
@@ -178,19 +178,26 @@ class LLMAnalyzer:
178
  return response.message.content
179
 
180
  async def _analyze_with_anthropic(self, prompt: str, response_schema: dict) -> str:
181
- response = await self.client.messages.create(
182
  model=self.model_name,
183
- temperature=0,
184
- system="Ти - кваліфікований юрист-аналітик, експерт з правових позицій Верховного Суду.",
185
- messages=[{"role": "user", "content": prompt}],
186
- response_format={"type": "json_schema", "schema": response_schema}
 
 
 
 
 
 
 
187
  )
188
  return response.content[0].text
189
 
190
 
191
  class PrecedentAnalysisWorkflow(Workflow):
192
  def __init__(self, provider: ModelProvider = ModelProvider.OPENAI,
193
- model_name: ModelName = ModelName.GPT4_MINI):
194
  super().__init__()
195
  self.analyzer = LLMAnalyzer(provider, model_name)
196
 
@@ -482,139 +489,291 @@ def generate_legal_position(court_decision_text, user_question):
482
  }
483
 
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  def create_gradio_interface():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
  with gr.Blocks() as app:
 
487
  gr.Markdown("# Аналізатор релевантних Правових Позицій Верховного Суду для нового судового рішення")
488
 
489
  with gr.Row():
490
  url_input = gr.Textbox(label="URL судового рішення:")
491
  question_input = gr.Textbox(label="Уточнююче питання для аналізу:")
492
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  with gr.Row():
494
  generate_position_button = gr.Button("Генерувати короткий зміст позиції суду")
495
  search_with_ai_button = gr.Button("Пошук із ШІ", interactive=False)
496
- # search_without_ai_button = gr.Button("Пошук без ШІ")
497
  analyze_button = gr.Button("Аналіз", interactive=False)
498
 
499
  position_output = gr.Markdown(label="Короткий зміст позиції суду за введеним рішенням")
500
  search_output = gr.Markdown(label="Результат пошуку")
501
  analysis_output = gr.Markdown(label="Результат аналізу")
502
 
503
- # Два об'єкти стану для зберігання legal_position_json та nodes
504
  state_lp_json = gr.State()
505
  state_nodes = gr.State()
506
 
507
- async def generate_position_action(url):
508
- try:
509
- court_decision_text = extract_court_decision_text(url)
510
- legal_position_json = generate_legal_position(court_decision_text, "")
511
- position_output_content = f"**Короткий зміст позиції суду за введеним рішенням:**\n *{legal_position_json['title']}*: \n{legal_position_json['text']} **Категорія:** \n{legal_position_json['category']} ({legal_position_json['proceeding']})\n\n"
512
- return position_output_content, legal_position_json
513
- except Exception as e:
514
- return f"Error during position generation: {str(e)}", None
515
-
516
- async def search_with_ai_action(legal_position_json):
517
- try:
518
- query_text = legal_position_json["title"] + ': ' + legal_position_json["text"] + ': ' + legal_position_json["proceeding"] + ': ' + legal_position_json["category"]
519
- nodes = await retriever_bm25.aretrieve(query_text)
520
-
521
- sources_output = "\n **Результати пошуку (наявні правові позиції ВСУ):** \n\n"
522
- for index, node in enumerate(nodes, start=1):
523
- source_title = node.node.metadata.get('title')
524
- doc_ids = node.node.metadata.get('doc_id')
525
- lp_ids = node.node.metadata.get('lp_id')
526
- links = get_links_html(doc_ids)
527
- links_lp = get_links_html_lp(lp_ids)
528
- sources_output += f"\n[{index}] *{source_title}* {links_lp} 👉 Score: {node.score} {links}\n"
529
-
530
- return sources_output, nodes
531
- except Exception as e:
532
- return f"Error during search: {str(e)}", None
533
-
534
- async def search_without_ai_action(url):
535
- try:
536
- court_decision_text = extract_court_decision_text(url)
537
- nodes = await retriever_bm25.aretrieve(court_decision_text)
538
-
539
- search_output_content = f"**Результати пошуку (наявні правові позиції ВСУ):** \n\n"
540
- for index, node in enumerate(nodes, start=1):
541
- source_title = node.node.metadata.get('title', 'Невідомий заголовок')
542
- doc_ids = node.node.metadata.get('doc_id')
543
- links = get_links_html(doc_ids)
544
- search_output_content += f"\n[{index}] *{source_title}* 👉 Score: {node.score} {links}\n"
545
-
546
- return search_output_content, nodes
547
- except Exception as e:
548
- return f"Error during search: {str(e)}", None
549
-
550
- async def analyze_action(legal_position_json, question, nodes):
551
- try:
552
- # Використання з OpenAI
553
- workflow = PrecedentAnalysisWorkflow(
554
- provider=ModelProvider.OPENAI,
555
- model_name=ModelName.GPT4_MINI
556
- )
557
-
558
- # # Використання з Anthropic
559
- # workflow_anthropic = PrecedentAnalysisWorkflow(
560
- # provider=ModelProvider.ANTHROPIC,
561
- # model_name=ModelName.CLAUDE3_SONNET
562
- # )
563
-
564
- # Формуємо єдиний текст запиту з legal_position_json
565
- query = (
566
- f"{legal_position_json['title']}: "
567
- f"{legal_position_json['text']}: "
568
- f"{legal_position_json['proceeding']}: "
569
- f"{legal_position_json['category']}"
570
- )
571
-
572
- # Запускаємо workflow і отримуємо текст аналізу
573
- response_text = await workflow.run(
574
- query=query,
575
- question=question,
576
- nodes=nodes
577
- )
578
-
579
- # Формуємо вивід
580
- output = f"**Аналіз ШІ:**\n{response_text}\n\n"
581
- output += "**Наявні в базі Правові Позицій Верховного Суду:**\n\n"
582
-
583
- # Розбиваємо текст відповіді на рядки
584
- analysis_lines = response_text.split('\n')
585
-
586
- # Проходимо по кожному рядку аналізу
587
- for line in analysis_lines:
588
- if line.startswith('* ['):
589
- # З кожного рядка отримуємо індекс
590
- index = line[3:line.index(']')] # Витягуємо індекс з "* [X]"
591
-
592
- # Знаходимо відповідний node за індексом
593
- node = nodes[int(index) - 1]
594
- source_node = node.node
595
-
596
- source_title = source_node.metadata.get('title', 'Невідомий заголовок')
597
- source_text_lp = node.text
598
- doc_ids = source_node.metadata.get('doc_id')
599
- lp_id = source_node.metadata.get('lp_id')
600
-
601
- links = get_links_html(doc_ids)
602
- links_lp = get_links_html_lp(lp_id)
603
-
604
- output += f"[{index}]: *{source_title}* | {source_text_lp} | {links_lp} | {links}\n\n"
605
-
606
- return output
607
-
608
- except Exception as e:
609
- return f"Error during analysis: {str(e)}"
610
-
611
- # Підключаємо функції до кнопок з оновленими входами та виходами
612
  generate_position_button.click(
613
  fn=generate_position_action,
614
  inputs=url_input,
615
  outputs=[position_output, state_lp_json]
616
- )
617
- generate_position_button.click(
618
  fn=lambda: gr.update(interactive=True),
619
  inputs=None,
620
  outputs=search_with_ai_button
@@ -624,30 +783,24 @@ def create_gradio_interface():
624
  fn=search_with_ai_action,
625
  inputs=state_lp_json,
626
  outputs=[search_output, state_nodes]
627
- )
628
- search_with_ai_button.click(
629
  fn=lambda: gr.update(interactive=True),
630
  inputs=None,
631
  outputs=analyze_button
632
  )
633
 
634
- # search_without_ai_button.click(
635
- # fn=search_without_ai_action,
636
- # inputs=url_input,
637
- # outputs=[search_output, state_nodes]
638
- # )
639
- # search_without_ai_button.click(
640
- # fn=lambda: gr.update(interactive=True),
641
- # inputs=None,
642
- # outputs=analyze_button
643
- # )
644
-
645
  analyze_button.click(
646
  fn=analyze_action,
647
- inputs=[state_lp_json, question_input, state_nodes],
648
  outputs=analysis_output
649
  )
650
 
 
 
 
 
 
 
651
  return app
652
 
653
  if __name__ == "__main__":
 
45
  aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID")
46
  aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY")
47
  openai_api_key = os.getenv("OPENAI_API_KEY")
48
+ anthropic_api_key=os.getenv("ANTHROPIC_API_KEY")
49
 
50
  embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
51
  Settings.embed_model = embed_model
 
128
 
129
  class ModelName(str, Enum):
130
  # OpenAI models
131
+ GPT4o = "gpt-4o"
132
+ GPT4o_MINI = "gpt-4o-mini"
 
133
  # Anthropic models
134
+ CLAUDE3_5_SONNET = "claude-3-5-sonnet-latest"
135
+ CLAUDE3_5_HAIKU = "claude-3-5-haiku-latest"
 
136
 
137
 
138
  class LLMAnalyzer:
 
141
  self.model_name = model_name
142
 
143
  if provider == ModelProvider.OPENAI:
144
+ self.client = OpenAI(model=model_name)
145
  elif provider == ModelProvider.ANTHROPIC:
146
+ # Додаємо API ключ при ініціалізації
147
+ self.client = Anthropic(api_key=anthropic_api_key)
148
  else:
149
  raise ValueError(f"Unsupported provider: {provider}")
150
 
 
178
  return response.message.content
179
 
180
  async def _analyze_with_anthropic(self, prompt: str, response_schema: dict) -> str:
181
+ response = self.client.messages.create( # Прибрали await
182
  model=self.model_name,
183
+ max_tokens=2000,
184
+ messages=[
185
+ {
186
+ "role": "assistant",
187
+ "content": "Ти - кваліфікований юрист-аналітик, експерт з правових позицій Верховного Суду."
188
+ },
189
+ {
190
+ "role": "user",
191
+ "content": prompt
192
+ }
193
+ ]
194
  )
195
  return response.content[0].text
196
 
197
 
198
  class PrecedentAnalysisWorkflow(Workflow):
199
  def __init__(self, provider: ModelProvider = ModelProvider.OPENAI,
200
+ model_name: ModelName = ModelName.GPT4o_MINI):
201
  super().__init__()
202
  self.analyzer = LLMAnalyzer(provider, model_name)
203
 
 
489
  }
490
 
491
 
492
+ # def create_gradio_interface():
493
+ # with gr.Blocks() as app:
494
+ # gr.Markdown("# Аналізатор релевантних Правових Позицій Верховного Суду для нового судового рішення")
495
+ #
496
+ # with gr.Row():
497
+ # url_input = gr.Textbox(label="URL судового рішення:")
498
+ # question_input = gr.Textbox(label="Уточнююче питання для аналізу:")
499
+ #
500
+ # with gr.Row():
501
+ # generate_position_button = gr.Button("Генерувати короткий зміст позиції суду")
502
+ # search_with_ai_button = gr.Button("Пошук із ШІ", interactive=False)
503
+ # # search_without_ai_button = gr.Button("Пошук без ШІ")
504
+ # analyze_button = gr.Button("Аналіз", interactive=False)
505
+ #
506
+ # position_output = gr.Markdown(label="Короткий зміст позиції суду за введеним рішенням")
507
+ # search_output = gr.Markdown(label="Результат пошуку")
508
+ # analysis_output = gr.Markdown(label="Результат аналізу")
509
+ #
510
+ # # Два об'єкти стану для зберігання legal_position_json та nodes
511
+ # state_lp_json = gr.State()
512
+ # state_nodes = gr.State()
513
+ #
514
+ # async def generate_position_action(url):
515
+ # try:
516
+ # court_decision_text = extract_court_decision_text(url)
517
+ # legal_position_json = generate_legal_position(court_decision_text, "")
518
+ # position_output_content = f"**Короткий зміст позиції суду за введеним рішенням:**\n *{legal_position_json['title']}*: \n{legal_position_json['text']} **Категорія:** \n{legal_position_json['category']} ({legal_position_json['proceeding']})\n\n"
519
+ # return position_output_content, legal_position_json
520
+ # except Exception as e:
521
+ # return f"Error during position generation: {str(e)}", None
522
+ #
523
+ # async def search_with_ai_action(legal_position_json):
524
+ # try:
525
+ # query_text = legal_position_json["title"] + ': ' + legal_position_json["text"] + ': ' + legal_position_json["proceeding"] + ': ' + legal_position_json["category"]
526
+ # nodes = await retriever_bm25.aretrieve(query_text)
527
+ #
528
+ # sources_output = "\n **Результати пошуку (наявні правові позиції ВСУ):** \n\n"
529
+ # for index, node in enumerate(nodes, start=1):
530
+ # source_title = node.node.metadata.get('title')
531
+ # doc_ids = node.node.metadata.get('doc_id')
532
+ # lp_ids = node.node.metadata.get('lp_id')
533
+ # links = get_links_html(doc_ids)
534
+ # links_lp = get_links_html_lp(lp_ids)
535
+ # sources_output += f"\n[{index}] *{source_title}* {links_lp} 👉 Score: {node.score} {links}\n"
536
+ #
537
+ # return sources_output, nodes
538
+ # except Exception as e:
539
+ # return f"Error during search: {str(e)}", None
540
+ #
541
+ # async def search_without_ai_action(url):
542
+ # try:
543
+ # court_decision_text = extract_court_decision_text(url)
544
+ # nodes = await retriever_bm25.aretrieve(court_decision_text)
545
+ #
546
+ # search_output_content = f"**Результати пошуку (наявні правові позиції ВСУ):** \n\n"
547
+ # for index, node in enumerate(nodes, start=1):
548
+ # source_title = node.node.metadata.get('title', 'Невідомий заголовок')
549
+ # doc_ids = node.node.metadata.get('doc_id')
550
+ # links = get_links_html(doc_ids)
551
+ # search_output_content += f"\n[{index}] *{source_title}* 👉 Score: {node.score} {links}\n"
552
+ #
553
+ # return search_output_content, nodes
554
+ # except Exception as e:
555
+ # return f"Error during search: {str(e)}", None
556
+ #
557
+ # async def analyze_action(legal_position_json, question, nodes):
558
+ # try:
559
+ # # Використання з OpenAI
560
+ # workflow = PrecedentAnalysisWorkflow(
561
+ # provider=ModelProvider.OPENAI,
562
+ # model_name=ModelName.GPT4_MINI
563
+ # )
564
+ #
565
+ # # # Використання з Anthropic
566
+ # # workflow_anthropic = PrecedentAnalysisWorkflow(
567
+ # # provider=ModelProvider.ANTHROPIC,
568
+ # # model_name=ModelName.CLAUDE3_SONNET
569
+ # # )
570
+ #
571
+ # # Формуємо єдиний текст запиту з legal_position_json
572
+ # query = (
573
+ # f"{legal_position_json['title']}: "
574
+ # f"{legal_position_json['text']}: "
575
+ # f"{legal_position_json['proceeding']}: "
576
+ # f"{legal_position_json['category']}"
577
+ # )
578
+ #
579
+ # # Запускаємо workflow і отримуємо текст аналізу
580
+ # response_text = await workflow.run(
581
+ # query=query,
582
+ # question=question,
583
+ # nodes=nodes
584
+ # )
585
+ #
586
+ # # Формуємо вивід
587
+ # output = f"**Аналіз ШІ:**\n{response_text}\n\n"
588
+ # output += "**Наявні в базі Правові Позицій Верховного Суду:**\n\n"
589
+ #
590
+ # # Розбиваємо текст відповіді на рядки
591
+ # analysis_lines = response_text.split('\n')
592
+ #
593
+ # # Проходимо по кожному рядку аналізу
594
+ # for line in analysis_lines:
595
+ # if line.startswith('* ['):
596
+ # # З кожного рядка отримуємо індекс
597
+ # index = line[3:line.index(']')] # Витягуємо індекс з "* [X]"
598
+ #
599
+ # # Знаходимо відповідний node за індексом
600
+ # node = nodes[int(index) - 1]
601
+ # source_node = node.node
602
+ #
603
+ # source_title = source_node.metadata.get('title', 'Невідомий заголовок')
604
+ # source_text_lp = node.text
605
+ # doc_ids = source_node.metadata.get('doc_id')
606
+ # lp_id = source_node.metadata.get('lp_id')
607
+ #
608
+ # links = get_links_html(doc_ids)
609
+ # links_lp = get_links_html_lp(lp_id)
610
+ #
611
+ # output += f"[{index}]: *{source_title}* | {source_text_lp} | {links_lp} | {links}\n\n"
612
+ #
613
+ # return output
614
+ #
615
+ # except Exception as e:
616
+ # return f"Error during analysis: {str(e)}"
617
+ #
618
+ # # Підключаємо функції до кнопок з оновленими входами та виходами
619
+ # generate_position_button.click(
620
+ # fn=generate_position_action,
621
+ # inputs=url_input,
622
+ # outputs=[position_output, state_lp_json]
623
+ # )
624
+ # generate_position_button.click(
625
+ # fn=lambda: gr.update(interactive=True),
626
+ # inputs=None,
627
+ # outputs=search_with_ai_button
628
+ # )
629
+ #
630
+ # search_with_ai_button.click(
631
+ # fn=search_with_ai_action,
632
+ # inputs=state_lp_json,
633
+ # outputs=[search_output, state_nodes]
634
+ # )
635
+ # search_with_ai_button.click(
636
+ # fn=lambda: gr.update(interactive=True),
637
+ # inputs=None,
638
+ # outputs=analyze_button
639
+ # )
640
+ #
641
+ # # search_without_ai_button.click(
642
+ # # fn=search_without_ai_action,
643
+ # # inputs=url_input,
644
+ # # outputs=[search_output, state_nodes]
645
+ # # )
646
+ # # search_without_ai_button.click(
647
+ # # fn=lambda: gr.update(interactive=True),
648
+ # # inputs=None,
649
+ # # outputs=analyze_button
650
+ # # )
651
+ #
652
+ # analyze_button.click(
653
+ # fn=analyze_action,
654
+ # inputs=[state_lp_json, question_input, state_nodes],
655
+ # outputs=analysis_output
656
+ # )
657
+ #
658
+ # return app
659
+
660
  def create_gradio_interface():
661
+ async def generate_position_action(url):
662
+ try:
663
+ court_decision_text = extract_court_decision_text(url)
664
+ legal_position_json = generate_legal_position(court_decision_text, "")
665
+ position_output_content = f"**Короткий зміст позиції суду за введеним рішенням:**\n *{legal_position_json['title']}*: \n{legal_position_json['text']} **Категорія:** \n{legal_position_json['category']} ({legal_position_json['proceeding']})\n\n"
666
+ return position_output_content, legal_position_json
667
+ except Exception as e:
668
+ return f"Error during position generation: {str(e)}", None
669
+
670
+ async def search_with_ai_action(legal_position_json):
671
+ try:
672
+ query_text = legal_position_json["title"] + ': ' + legal_position_json["text"] + ': ' + legal_position_json["proceeding"] + ': ' + legal_position_json["category"]
673
+ nodes = await retriever_bm25.aretrieve(query_text)
674
+
675
+ sources_output = "\n **Результати пошуку (наявні правові позиції ВСУ):** \n\n"
676
+ for index, node in enumerate(nodes, start=1):
677
+ source_title = node.node.metadata.get('title')
678
+ doc_ids = node.node.metadata.get('doc_id')
679
+ lp_ids = node.node.metadata.get('lp_id')
680
+ links = get_links_html(doc_ids)
681
+ links_lp = get_links_html_lp(lp_ids)
682
+ sources_output += f"\n[{index}] *{source_title}* {links_lp} 👉 Score: {node.score} {links}\n"
683
+
684
+ return sources_output, nodes
685
+ except Exception as e:
686
+ return f"Error during search: {str(e)}", None
687
+
688
+ async def analyze_action(legal_position_json, question, nodes, provider, model_name):
689
+ try:
690
+ workflow = PrecedentAnalysisWorkflow(
691
+ provider=ModelProvider(provider),
692
+ model_name=ModelName(model_name)
693
+ )
694
+
695
+ query = (
696
+ f"{legal_position_json['title']}: "
697
+ f"{legal_position_json['text']}: "
698
+ f"{legal_position_json['proceeding']}: "
699
+ f"{legal_position_json['category']}"
700
+ )
701
+
702
+ response_text = await workflow.run(
703
+ query=query,
704
+ question=question,
705
+ nodes=nodes
706
+ )
707
+
708
+ output = f"**Аналіз ШІ (модель: {model_name}):**\n{response_text}\n\n"
709
+ output += "**Наявні в базі Правові Позицій Верховного Суду:**\n\n"
710
+
711
+ analysis_lines = response_text.split('\n')
712
+ for line in analysis_lines:
713
+ if line.startswith('* ['):
714
+ index = line[3:line.index(']')]
715
+ node = nodes[int(index) - 1]
716
+ source_node = node.node
717
+
718
+ source_title = source_node.metadata.get('title', 'Невідомий заголовок')
719
+ source_text_lp = node.text
720
+ doc_ids = source_node.metadata.get('doc_id')
721
+ lp_id = source_node.metadata.get('lp_id')
722
+
723
+ links = get_links_html(doc_ids)
724
+ links_lp = get_links_html_lp(lp_id)
725
+
726
+ output += f"[{index}]: *{source_title}* | {source_text_lp} | {links_lp} | {links}\n\n"
727
+
728
+ return output
729
+
730
+ except Exception as e:
731
+ return f"Error during analysis: {str(e)}"
732
+
733
+ def update_model_choices(provider):
734
+ if provider == ModelProvider.OPENAI.value:
735
+ return gr.Dropdown(choices=[m.value for m in ModelName if m.value.startswith("gpt")])
736
+ else:
737
+ return gr.Dropdown(choices=[m.value for m in ModelName if m.value.startswith("claude")])
738
+
739
  with gr.Blocks() as app:
740
+ # Далі ваш код інтерфейсу...
741
  gr.Markdown("# Аналізатор релевантних Правових Позицій Верховного Суду для нового судового рішення")
742
 
743
  with gr.Row():
744
  url_input = gr.Textbox(label="URL судового рішення:")
745
  question_input = gr.Textbox(label="Уточнююче питання для аналізу:")
746
 
747
+ with gr.Row():
748
+ provider_dropdown = gr.Dropdown(
749
+ choices=[p.value for p in ModelProvider],
750
+ value=ModelProvider.OPENAI.value,
751
+ label="Провайдер AI",
752
+ )
753
+ model_dropdown = gr.Dropdown(
754
+ choices=[m.value for m in ModelName if m.value.startswith("gpt")],
755
+ value=ModelName.GPT4o_MINI.value,
756
+ label="Модель",
757
+ )
758
+
759
  with gr.Row():
760
  generate_position_button = gr.Button("Генерувати короткий зміст позиції суду")
761
  search_with_ai_button = gr.Button("Пошук із ШІ", interactive=False)
 
762
  analyze_button = gr.Button("Аналіз", interactive=False)
763
 
764
  position_output = gr.Markdown(label="Короткий зміст позиції суду за введеним рішенням")
765
  search_output = gr.Markdown(label="Результат пошуку")
766
  analysis_output = gr.Markdown(label="Результат аналізу")
767
 
 
768
  state_lp_json = gr.State()
769
  state_nodes = gr.State()
770
 
771
+ # Підключення функцій до кнопок
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
772
  generate_position_button.click(
773
  fn=generate_position_action,
774
  inputs=url_input,
775
  outputs=[position_output, state_lp_json]
776
+ ).then(
 
777
  fn=lambda: gr.update(interactive=True),
778
  inputs=None,
779
  outputs=search_with_ai_button
 
783
  fn=search_with_ai_action,
784
  inputs=state_lp_json,
785
  outputs=[search_output, state_nodes]
786
+ ).then(
 
787
  fn=lambda: gr.update(interactive=True),
788
  inputs=None,
789
  outputs=analyze_button
790
  )
791
 
 
 
 
 
 
 
 
 
 
 
 
792
  analyze_button.click(
793
  fn=analyze_action,
794
+ inputs=[state_lp_json, question_input, state_nodes, provider_dropdown, model_dropdown],
795
  outputs=analysis_output
796
  )
797
 
798
+ provider_dropdown.change(
799
+ fn=update_model_choices,
800
+ inputs=provider_dropdown,
801
+ outputs=model_dropdown
802
+ )
803
+
804
  return app
805
 
806
  if __name__ == "__main__":