timeki commited on
Commit
3240e5c
·
1 Parent(s): df26154

split ode in modules

Browse files
Files changed (1) hide show
  1. app.py +326 -332
app.py CHANGED
@@ -1,31 +1,22 @@
1
- from climateqa.engine.embeddings import get_embeddings_function
2
- embeddings_function = get_embeddings_function()
3
-
4
- from sentence_transformers import CrossEncoder
5
-
6
- import gradio as gr
7
- from gradio_modal import Modal
8
- import pandas as pd
9
- import numpy as np
10
  import os
 
11
  import time
12
  import re
13
- import json
14
-
15
- from gradio import ChatMessage
16
-
17
- from io import BytesIO
18
  import base64
19
-
20
  from datetime import datetime
21
- from azure.storage.fileshare import ShareServiceClient
22
-
23
- from utils import create_user_id
24
 
 
 
 
 
25
  from gradio_modal import Modal
 
 
26
 
27
-
28
- # ClimateQ&A imports
29
  from climateqa.engine.llm import get_llm
30
  from climateqa.engine.vectorstore import get_pinecone_vectorstore
31
  from climateqa.engine.reranker import get_reranker
@@ -33,12 +24,15 @@ from climateqa.sample_questions import QUESTIONS
33
  from climateqa.constants import POSSIBLE_REPORTS
34
  from climateqa.utils import get_image_from_azure_blob_storage
35
  from climateqa.engine.graph import make_graph_agent
36
- from climateqa.engine.embeddings import get_embeddings_function
37
  from climateqa.engine.chains.retrieve_papers import find_papers
38
-
39
- from front.utils import serialize_docs,process_figures
40
-
41
- from climateqa.event_handler import init_audience, handle_retrieved_documents, stream_answer,handle_retrieved_owid_graphs
 
 
 
 
42
 
43
  # Load environment variables in local mode
44
  try:
@@ -47,7 +41,6 @@ try:
47
  except Exception as e:
48
  pass
49
 
50
-
51
  # Set up Gradio Theme
52
  theme = gr.themes.Base(
53
  primary_hue="blue",
@@ -55,8 +48,7 @@ theme = gr.themes.Base(
55
  font=[gr.themes.GoogleFont("Poppins"), "ui-sans-serif", "system-ui", "sans-serif"],
56
  )
57
 
58
-
59
-
60
  init_prompt = """
61
  Hello, I am ClimateQ&A, a conversational assistant designed to help you understand climate change and biodiversity loss. I will answer your questions by **sifting through the IPCC and IPBES scientific reports**.
62
 
@@ -72,15 +64,10 @@ Hello, I am ClimateQ&A, a conversational assistant designed to help you understa
72
  🛈 Information
73
  Please note that we log your questions for meta-analysis purposes, so avoid sharing any sensitive or personal information.
74
 
75
-
76
  What do you want to learn ?
77
  """
78
 
79
- system_template = {
80
- "role": "system",
81
- "content": init_prompt,
82
- }
83
-
84
  account_key = os.environ["BLOB_ACCOUNT_KEY"]
85
  if len(account_key) == 86:
86
  account_key += "=="
@@ -97,7 +84,7 @@ share_client = service.get_share_client(file_share_name)
97
 
98
  user_id = create_user_id()
99
 
100
-
101
  CITATION_LABEL = "BibTeX citation for ClimateQ&A"
102
  CITATION_TEXT = r"""@misc{climateqa,
103
  author={Théo Alves Da Costa, Timothée Bohe},
@@ -112,22 +99,32 @@ CITATION_TEXT = r"""@misc{climateqa,
112
  }
113
  """
114
 
115
-
116
-
117
  # Create vectorstore and retriever
118
- vectorstore = get_pinecone_vectorstore(embeddings_function, index_name = os.getenv("PINECONE_API_INDEX"))
119
- vectorstore_graphs = get_pinecone_vectorstore(embeddings_function, index_name = os.getenv("PINECONE_API_INDEX_OWID"), text_key="description")
 
120
 
121
- llm = get_llm(provider="openai",max_tokens = 1024,temperature = 0.0)
122
  reranker = get_reranker("nano")
123
 
124
  agent = make_graph_agent(llm=llm, vectorstore_ipcc=vectorstore, vectorstore_graphs=vectorstore_graphs, reranker=reranker)
125
 
 
126
  def update_config_modal_visibility(config_open):
127
  new_config_visibility_status = not config_open
128
  return gr.update(visible=new_config_visibility_status), new_config_visibility_status
129
 
130
- async def chat(query, history, audience, sources, reports, relevant_content_sources, search_only):
 
 
 
 
 
 
 
 
 
 
131
  """Process a chat query and return response with relevant sources and visualizations.
132
 
133
  Args:
@@ -155,7 +152,7 @@ async def chat(query, history, audience, sources, reports, relevant_content_sour
155
  audience_prompt = init_audience(audience)
156
  sources = sources or ["IPCC", "IPBES", "IPOS"]
157
  reports = reports or []
158
-
159
  # Prepare inputs for agent
160
  inputs = {
161
  "user_input": query,
@@ -164,7 +161,7 @@ async def chat(query, history, audience, sources, reports, relevant_content_sour
164
  "relevant_content_sources": relevant_content_sources,
165
  "search_only": search_only
166
  }
167
-
168
  # Get streaming events from agent
169
  result = agent.astream_events(inputs, version="v1")
170
 
@@ -267,7 +264,7 @@ async def chat(query, history, audience, sources, reports, relevant_content_sour
267
 
268
  yield history, docs_html, output_query, output_language, related_contents, graphs_html
269
 
270
-
271
  def save_feedback(feed: str, user_id):
272
  if len(feed) > 1:
273
  timestamp = str(datetime.now().timestamp())
@@ -280,9 +277,7 @@ def save_feedback(feed: str, user_id):
280
  log_on_azure(file, logs, share_client)
281
  return "Feedback submitted, thank you!"
282
 
283
-
284
-
285
-
286
  def log_on_azure(file, logs, share_client):
287
  logs = json.dumps(logs)
288
  file_client = share_client.get_file_client(file)
@@ -297,25 +292,6 @@ def log_on_azure(file, logs, share_client):
297
  # --------------------------------------------------------------------
298
 
299
 
300
- init_prompt = """
301
- Hello, I am ClimateQ&A, a conversational assistant designed to help you understand climate change and biodiversity loss. I will answer your questions by **sifting through the IPCC and IPBES scientific reports**.
302
-
303
- ❓ How to use
304
- - **Language**: You can ask me your questions in any language.
305
- - **Audience**: You can specify your audience (children, general public, experts) to get a more adapted answer.
306
- - **Sources**: You can choose to search in the IPCC or IPBES reports, or both.
307
- - **Relevant content sources**: You can choose to search for figures, papers, or graphs that can be relevant for your question.
308
-
309
- ⚠️ Limitations
310
- *Please note that the AI is not perfect and may sometimes give irrelevant answers. If you are not satisfied with the answer, please ask a more specific question or report your feedback to help us improve the system.*
311
-
312
- 🛈 Information
313
- Please note that we log your questions for meta-analysis purposes, so avoid sharing any sensitive or personal information.
314
-
315
-
316
- What do you want to learn ?
317
- """
318
-
319
 
320
  def vote(data: gr.LikeData):
321
  if data.liked:
@@ -331,6 +307,258 @@ def save_graph(saved_graphs_state, embedding, category):
331
  saved_graphs_state[category].append(embedding)
332
  return saved_graphs_state, gr.Button("Graph Saved")
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=theme, elem_id="main-component") as demo:
335
  # State variables
336
  chat_completed_state = gr.State(0)
@@ -342,57 +570,14 @@ with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=t
342
  with gr.Row(elem_id="chatbot-row"):
343
  # Left column - Chat interface
344
  with gr.Column(scale=2):
345
- chatbot = gr.Chatbot(
346
- value=[ChatMessage(role="assistant", content=init_prompt)],
347
- type="messages",
348
- show_copy_button=True,
349
- show_label=False,
350
- elem_id="chatbot",
351
- layout="panel",
352
- avatar_images=(None, "https://i.ibb.co/YNyd5W2/logo4.png"),
353
- max_height="80vh",
354
- height="100vh"
355
- )
356
-
357
- with gr.Row(elem_id="input-message"):
358
- textbox = gr.Textbox(
359
- placeholder="Ask me anything here!",
360
- show_label=False,
361
- scale=7,
362
- lines=1,
363
- interactive=True,
364
- elem_id="input-textbox"
365
- )
366
- config_button = gr.Button("", elem_id="config-button")
367
 
368
  # Right column - Content panels
369
  with gr.Column(scale=2, variant="panel", elem_id="right-panel"):
370
  with gr.Tabs(elem_id="right_panel_tab") as tabs:
371
  # Examples tab
372
  with gr.TabItem("Examples", elem_id="tab-examples", id=0):
373
- examples_hidden = gr.Textbox(visible=False)
374
- first_key = list(QUESTIONS.keys())[0]
375
- dropdown_samples = gr.Dropdown(
376
- choices=QUESTIONS.keys(),
377
- value=first_key,
378
- interactive=True,
379
- label="Select a category of sample questions",
380
- elem_id="dropdown-samples"
381
- )
382
-
383
- samples = []
384
- for i, key in enumerate(QUESTIONS.keys()):
385
- examples_visible = (i == 0)
386
- with gr.Row(visible=examples_visible) as group_examples:
387
- examples_questions = gr.Examples(
388
- examples=QUESTIONS[key],
389
- inputs=[examples_hidden],
390
- examples_per_page=8,
391
- run_on_click=False,
392
- elem_id=f"examples{i}",
393
- api_name=f"examples{i}"
394
- )
395
- samples.append(group_examples)
396
 
397
  # Sources tab
398
  with gr.Tab("Sources", elem_id="tab-sources", id=1) as tab_sources:
@@ -403,58 +588,11 @@ with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=t
403
  with gr.Tabs(elem_id="group-subtabs") as tabs_recommended_content:
404
  # Figures subtab
405
  with gr.Tab("Figures", elem_id="tab-figures", id=3) as tab_figures:
406
- sources_raw = gr.State()
407
-
408
- with Modal(visible=False, elem_id="modal_figure_galery") as figure_modal:
409
- gallery_component = gr.Gallery(
410
- object_fit='scale-down',
411
- elem_id="gallery-component",
412
- height="80vh"
413
- )
414
-
415
- show_full_size_figures = gr.Button(
416
- "Show figures in full size",
417
- elem_id="show-figures",
418
- interactive=True
419
- )
420
- show_full_size_figures.click(
421
- lambda: Modal(visible=True),
422
- None,
423
- figure_modal
424
- )
425
-
426
- figures_cards = gr.HTML(show_label=False, elem_id="sources-figures")
427
 
428
  # Papers subtab
429
  with gr.Tab("Papers", elem_id="tab-citations", id=4) as tab_papers:
430
- with gr.Accordion(
431
- visible=True,
432
- elem_id="papers-summary-popup",
433
- label="See summary of relevant papers",
434
- open=False
435
- ) as summary_popup:
436
- papers_summary = gr.Markdown("", visible=True, elem_id="papers-summary")
437
-
438
- with gr.Accordion(
439
- visible=True,
440
- elem_id="papers-relevant-popup",
441
- label="See relevant papers",
442
- open=False
443
- ) as relevant_popup:
444
- papers_html = gr.HTML(show_label=False, elem_id="papers-textbox")
445
-
446
- btn_citations_network = gr.Button("Explore papers citations network")
447
- with Modal(visible=False) as papers_modal:
448
- citations_network = gr.HTML(
449
- "<h3>Citations Network Graph</h3>",
450
- visible=True,
451
- elem_id="papers-citations-network"
452
- )
453
- btn_citations_network.click(
454
- lambda: Modal(visible=True),
455
- None,
456
- papers_modal
457
- )
458
 
459
  # Graphs subtab
460
  with gr.Tab("Graphs", elem_id="tab-graphs", id=5) as tab_graphs:
@@ -468,107 +606,12 @@ with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=t
468
  outputs=[graphs_container]
469
  )
470
 
471
- # Configuration modal
472
- with Modal(visible=False, elem_id="modal-config") as config_modal:
473
- gr.Markdown("Reminders: You can talk in any language, ClimateQ&A is multi-lingual!")
474
 
475
- dropdown_sources = gr.CheckboxGroup(
476
- choices=["IPCC", "IPBES", "IPOS"],
477
- label="Select source (by default search in all sources)",
478
- value=["IPCC"],
479
- interactive=True
480
- )
481
-
482
- dropdown_reports = gr.Dropdown(
483
- choices=POSSIBLE_REPORTS,
484
- label="Or select specific reports",
485
- multiselect=True,
486
- value=None,
487
- interactive=True
488
- )
489
-
490
- dropdown_external_sources = gr.CheckboxGroup(
491
- choices=["IPCC figures", "OpenAlex", "OurWorldInData"],
492
- label="Select database to search for relevant content",
493
- value=["IPCC figures"],
494
- interactive=True
495
- )
496
-
497
- search_only = gr.Checkbox(
498
- label="Search only for recommended content without chating",
499
- value=False,
500
- interactive=True,
501
- elem_id="checkbox-chat"
502
- )
503
-
504
- dropdown_audience = gr.Dropdown(
505
- choices=["Children", "General public", "Experts"],
506
- label="Select audience",
507
- value="Experts",
508
- interactive=True
509
- )
510
-
511
- after = gr.Slider(
512
- minimum=1950,
513
- maximum=2023,
514
- step=1,
515
- value=1960,
516
- label="Publication date",
517
- show_label=True,
518
- interactive=True,
519
- elem_id="date-papers",
520
- visible=False
521
- )
522
-
523
- output_query = gr.Textbox(
524
- label="Query used for retrieval",
525
- show_label=True,
526
- elem_id="reformulated-query",
527
- lines=2,
528
- interactive=False,
529
- visible=False
530
- )
531
-
532
- output_language = gr.Textbox(
533
- label="Language",
534
- show_label=True,
535
- elem_id="language",
536
- lines=1,
537
- interactive=False,
538
- visible=False
539
- )
540
-
541
- dropdown_external_sources.change(
542
- lambda x: gr.update(visible="OpenAlex" in x),
543
- inputs=[dropdown_external_sources],
544
- outputs=[after]
545
- )
546
-
547
- close_config_modal = gr.Button("Validate and Close", elem_id="close-config-modal")
548
- close_config_modal.click(
549
- fn=update_config_modal_visibility,
550
- inputs=[config_open],
551
- outputs=[config_modal, config_open]
552
- )
553
-
554
- config_button.click(
555
- fn=update_config_modal_visibility,
556
- inputs=[config_open],
557
- outputs=[config_modal, config_open]
558
- )
559
-
560
-
561
- #---------------------------------------------------------------------------------------
562
- # OTHER TABS
563
- #---------------------------------------------------------------------------------------
564
-
565
- with gr.Tab("About",elem_classes = "max-height other-tabs"):
566
  with gr.Row():
567
  with gr.Column(scale=1):
568
-
569
-
570
-
571
-
572
  gr.Markdown(
573
  """
574
  ### More info
@@ -578,8 +621,7 @@ with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=t
578
  ### Citation
579
  """
580
  )
581
- with gr.Accordion(CITATION_LABEL,elem_id="citation", open = False,):
582
- # # Display citation label and text)
583
  gr.Textbox(
584
  value=CITATION_TEXT,
585
  label="",
@@ -588,91 +630,43 @@ with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=t
588
  lines=len(CITATION_TEXT.split('\n')),
589
  )
590
 
591
-
592
-
593
- def start_chat(query,history,search_only):
594
- history = history + [ChatMessage(role="user", content=query)]
595
- if not search_only:
596
- return (gr.update(interactive = False),gr.update(selected=1),history)
597
- else:
598
- return (gr.update(interactive = False),gr.update(selected=2),history)
599
-
600
- def finish_chat():
601
- return gr.update(interactive = True,value = "")
602
 
603
- # Initialize visibility states
604
- summary_visible = False
605
- relevant_visible = False
606
-
607
- # Functions to toggle visibility
608
- def toggle_summary_visibility():
609
- global summary_visible
610
- summary_visible = not summary_visible
611
- return gr.update(visible=summary_visible)
612
-
613
- def toggle_relevant_visibility():
614
- global relevant_visible
615
- relevant_visible = not relevant_visible
616
- return gr.update(visible=relevant_visible)
617
-
618
-
619
- def change_completion_status(current_state):
620
- current_state = 1 - current_state
621
- return current_state
622
 
623
- def update_sources_number_display(sources_textbox, figures_cards, current_graphs, papers_html):
624
- sources_number = sources_textbox.count("<h2>")
625
- figures_number = figures_cards.count("<h2>")
626
- graphs_number = current_graphs.count("<iframe")
627
- papers_number = papers_html.count("<h2>")
628
- sources_notif_label = f"Sources ({sources_number})"
629
- figures_notif_label = f"Figures ({figures_number})"
630
- graphs_notif_label = f"Graphs ({graphs_number})"
631
- papers_notif_label = f"Papers ({papers_number})"
632
- recommended_content_notif_label = f"Recommended content ({figures_number + graphs_number + papers_number})"
633
-
634
- return gr.update(label = recommended_content_notif_label), gr.update(label = sources_notif_label), gr.update(label = figures_notif_label), gr.update(label = graphs_notif_label), gr.update(label = papers_notif_label)
635
 
636
  (textbox
637
- .submit(start_chat, [textbox,chatbot, search_only], [textbox,tabs,chatbot],queue = False,api_name = "start_chat_textbox")
638
- .then(chat, [textbox,chatbot,dropdown_audience, dropdown_sources,dropdown_reports, dropdown_external_sources, search_only] ,[chatbot,sources_textbox,output_query,output_language, sources_raw, current_graphs],concurrency_limit = 8,api_name = "chat_textbox")
639
- .then(finish_chat, None, [textbox],api_name = "finish_chat_textbox")
640
- # .then(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_sources, tab_figures, tab_graphs, tab_papers] )
641
  )
642
 
643
  (examples_hidden
644
- .change(start_chat, [examples_hidden,chatbot, search_only], [textbox,tabs,chatbot],queue = False,api_name = "start_chat_examples")
645
- .then(chat, [examples_hidden,chatbot,dropdown_audience, dropdown_sources,dropdown_reports, dropdown_external_sources, search_only] ,[chatbot,sources_textbox,output_query,output_language, sources_raw, current_graphs],concurrency_limit = 8,api_name = "chat_textbox")
646
- .then(finish_chat, None, [textbox],api_name = "finish_chat_examples")
647
- # .then(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_sources, tab_figures, tab_graphs, tab_papers] )
648
  )
649
 
650
-
651
- def change_sample_questions(key):
652
- index = list(QUESTIONS.keys()).index(key)
653
- visible_bools = [False] * len(samples)
654
- visible_bools[index] = True
655
- return [gr.update(visible=visible_bools[i]) for i in range(len(samples))]
656
-
657
-
658
  sources_raw.change(process_figures, inputs=[sources_raw], outputs=[figures_cards, gallery_component])
659
-
660
- # update sources numbers
661
- sources_textbox.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
662
- figures_cards.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
663
- current_graphs.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
664
- papers_html.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs,papers_html],[tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
665
 
666
- # other questions examples
667
- dropdown_samples.change(change_sample_questions,dropdown_samples,samples)
 
 
 
668
 
669
- # search for papers
670
- textbox.submit(find_papers,[textbox,after, dropdown_external_sources], [papers_html,citations_network,papers_summary])
671
- examples_hidden.change(find_papers,[examples_hidden,after,dropdown_external_sources], [papers_html,citations_network,papers_summary])
672
 
673
- # btn_summary.click(toggle_summary_visibility, outputs=summary_popup)
674
- # btn_relevant_papers.click(toggle_relevant_visibility, outputs=relevant_popup)
 
675
 
676
  demo.queue()
677
-
678
  demo.launch(ssr_mode=False)
 
1
+ # Import necessary libraries
 
 
 
 
 
 
 
 
2
  import os
3
+ import json
4
  import time
5
  import re
 
 
 
 
 
6
  import base64
 
7
  from datetime import datetime
8
+ from io import BytesIO
 
 
9
 
10
+ import numpy as np
11
+ import pandas as pd
12
+ import gradio as gr
13
+ from gradio import ChatMessage
14
  from gradio_modal import Modal
15
+ from sentence_transformers import CrossEncoder
16
+ from azure.storage.fileshare import ShareServiceClient
17
 
18
+ # Import custom modules
19
+ from climateqa.engine.embeddings import get_embeddings_function
20
  from climateqa.engine.llm import get_llm
21
  from climateqa.engine.vectorstore import get_pinecone_vectorstore
22
  from climateqa.engine.reranker import get_reranker
 
24
  from climateqa.constants import POSSIBLE_REPORTS
25
  from climateqa.utils import get_image_from_azure_blob_storage
26
  from climateqa.engine.graph import make_graph_agent
 
27
  from climateqa.engine.chains.retrieve_papers import find_papers
28
+ from front.utils import serialize_docs, process_figures
29
+ from climateqa.event_handler import (
30
+ init_audience,
31
+ handle_retrieved_documents,
32
+ stream_answer,
33
+ handle_retrieved_owid_graphs
34
+ )
35
+ from utils import create_user_id
36
 
37
  # Load environment variables in local mode
38
  try:
 
41
  except Exception as e:
42
  pass
43
 
 
44
  # Set up Gradio Theme
45
  theme = gr.themes.Base(
46
  primary_hue="blue",
 
48
  font=[gr.themes.GoogleFont("Poppins"), "ui-sans-serif", "system-ui", "sans-serif"],
49
  )
50
 
51
+ # Initialize prompt and system template
 
52
  init_prompt = """
53
  Hello, I am ClimateQ&A, a conversational assistant designed to help you understand climate change and biodiversity loss. I will answer your questions by **sifting through the IPCC and IPBES scientific reports**.
54
 
 
64
  🛈 Information
65
  Please note that we log your questions for meta-analysis purposes, so avoid sharing any sensitive or personal information.
66
 
 
67
  What do you want to learn ?
68
  """
69
 
70
+ # Azure Blob Storage credentials
 
 
 
 
71
  account_key = os.environ["BLOB_ACCOUNT_KEY"]
72
  if len(account_key) == 86:
73
  account_key += "=="
 
84
 
85
  user_id = create_user_id()
86
 
87
+ # Citation information
88
  CITATION_LABEL = "BibTeX citation for ClimateQ&A"
89
  CITATION_TEXT = r"""@misc{climateqa,
90
  author={Théo Alves Da Costa, Timothée Bohe},
 
99
  }
100
  """
101
 
 
 
102
  # Create vectorstore and retriever
103
+ embeddings_function = get_embeddings_function()
104
+ vectorstore = get_pinecone_vectorstore(embeddings_function, index_name=os.getenv("PINECONE_API_INDEX"))
105
+ vectorstore_graphs = get_pinecone_vectorstore(embeddings_function, index_name=os.getenv("PINECONE_API_INDEX_OWID"), text_key="description")
106
 
107
+ llm = get_llm(provider="openai", max_tokens=1024, temperature=0.0)
108
  reranker = get_reranker("nano")
109
 
110
  agent = make_graph_agent(llm=llm, vectorstore_ipcc=vectorstore, vectorstore_graphs=vectorstore_graphs, reranker=reranker)
111
 
112
+ # Function to update modal visibility
113
  def update_config_modal_visibility(config_open):
114
  new_config_visibility_status = not config_open
115
  return gr.update(visible=new_config_visibility_status), new_config_visibility_status
116
 
117
+ # Main chat function
118
+ # async def chat(query, history, audience, sources, reports, relevant_content_sources, search_only):
119
+ async def chat(
120
+ query: str,
121
+ history: list[ChatMessage],
122
+ audience: str,
123
+ sources: list[str],
124
+ reports: list[str],
125
+ relevant_content_sources: list[str],
126
+ search_only: bool
127
+ ) -> tuple[list, str, str, str, list, str]:
128
  """Process a chat query and return response with relevant sources and visualizations.
129
 
130
  Args:
 
152
  audience_prompt = init_audience(audience)
153
  sources = sources or ["IPCC", "IPBES", "IPOS"]
154
  reports = reports or []
155
+
156
  # Prepare inputs for agent
157
  inputs = {
158
  "user_input": query,
 
161
  "relevant_content_sources": relevant_content_sources,
162
  "search_only": search_only
163
  }
164
+
165
  # Get streaming events from agent
166
  result = agent.astream_events(inputs, version="v1")
167
 
 
264
 
265
  yield history, docs_html, output_query, output_language, related_contents, graphs_html
266
 
267
+ # Function to save feedback
268
  def save_feedback(feed: str, user_id):
269
  if len(feed) > 1:
270
  timestamp = str(datetime.now().timestamp())
 
277
  log_on_azure(file, logs, share_client)
278
  return "Feedback submitted, thank you!"
279
 
280
+ # Function to log data on Azure
 
 
281
  def log_on_azure(file, logs, share_client):
282
  logs = json.dumps(logs)
283
  file_client = share_client.get_file_client(file)
 
292
  # --------------------------------------------------------------------
293
 
294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
 
296
  def vote(data: gr.LikeData):
297
  if data.liked:
 
307
  saved_graphs_state[category].append(embedding)
308
  return saved_graphs_state, gr.Button("Graph Saved")
309
 
310
+
311
+ # Functions to toggle visibility
312
+ def toggle_summary_visibility():
313
+ global summary_visible
314
+ summary_visible = not summary_visible
315
+ return gr.update(visible=summary_visible)
316
+
317
+ def toggle_relevant_visibility():
318
+ global relevant_visible
319
+ relevant_visible = not relevant_visible
320
+ return gr.update(visible=relevant_visible)
321
+
322
+ def change_completion_status(current_state):
323
+ current_state = 1 - current_state
324
+ return current_state
325
+
326
+ def update_sources_number_display(sources_textbox, figures_cards, current_graphs, papers_html):
327
+ sources_number = sources_textbox.count("<h2>")
328
+ figures_number = figures_cards.count("<h2>")
329
+ graphs_number = current_graphs.count("<iframe")
330
+ papers_number = papers_html.count("<h2>")
331
+ sources_notif_label = f"Sources ({sources_number})"
332
+ figures_notif_label = f"Figures ({figures_number})"
333
+ graphs_notif_label = f"Graphs ({graphs_number})"
334
+ papers_notif_label = f"Papers ({papers_number})"
335
+ recommended_content_notif_label = f"Recommended content ({figures_number + graphs_number + papers_number})"
336
+
337
+ return gr.update(label=recommended_content_notif_label), gr.update(label=sources_notif_label), gr.update(label=figures_notif_label), gr.update(label=graphs_notif_label), gr.update(label=papers_notif_label)
338
+
339
+ def change_sample_questions(key):
340
+ index = list(QUESTIONS.keys()).index(key)
341
+ visible_bools = [False] * len(samples)
342
+ visible_bools[index] = True
343
+ return [gr.update(visible=visible_bools[i]) for i in range(len(samples))]
344
+
345
+
346
+
347
+ # Chat functions
348
+ def start_chat(query, history, search_only):
349
+ history = history + [ChatMessage(role="user", content=query)]
350
+ if not search_only:
351
+ return (gr.update(interactive=False), gr.update(selected=1), history)
352
+ else:
353
+ return (gr.update(interactive=False), gr.update(selected=2), history)
354
+
355
+ def finish_chat():
356
+ return gr.update(interactive=True, value="")
357
+
358
+ # Initialize visibility states
359
+ summary_visible = False
360
+ relevant_visible = False
361
+
362
+ # UI Layout Components
363
+ def create_chat_interface():
364
+ chatbot = gr.Chatbot(
365
+ value=[ChatMessage(role="assistant", content=init_prompt)],
366
+ type="messages",
367
+ show_copy_button=True,
368
+ show_label=False,
369
+ elem_id="chatbot",
370
+ layout="panel",
371
+ avatar_images=(None, "https://i.ibb.co/YNyd5W2/logo4.png"),
372
+ max_height="80vh",
373
+ height="100vh"
374
+ )
375
+
376
+ with gr.Row(elem_id="input-message"):
377
+
378
+ textbox = gr.Textbox(
379
+ placeholder="Ask me anything here!",
380
+ show_label=False,
381
+ scale=7,
382
+ lines=1,
383
+ interactive=True,
384
+ elem_id="input-textbox"
385
+ )
386
+
387
+ config_button = gr.Button("", elem_id="config-button")
388
+
389
+ return chatbot, textbox, config_button
390
+
391
+ def create_examples_tab():
392
+ examples_hidden = gr.Textbox(visible=False)
393
+ first_key = list(QUESTIONS.keys())[0]
394
+ dropdown_samples = gr.Dropdown(
395
+ choices=QUESTIONS.keys(),
396
+ value=first_key,
397
+ interactive=True,
398
+ label="Select a category of sample questions",
399
+ elem_id="dropdown-samples"
400
+ )
401
+
402
+ samples = []
403
+ for i, key in enumerate(QUESTIONS.keys()):
404
+ examples_visible = (i == 0)
405
+ with gr.Row(visible=examples_visible) as group_examples:
406
+ examples_questions = gr.Examples(
407
+ examples=QUESTIONS[key],
408
+ inputs=[examples_hidden],
409
+ examples_per_page=8,
410
+ run_on_click=False,
411
+ elem_id=f"examples{i}",
412
+ api_name=f"examples{i}"
413
+ )
414
+ samples.append(group_examples)
415
+
416
+ return examples_hidden, dropdown_samples, samples
417
+
418
+ def create_figures_tab():
419
+ sources_raw = gr.State()
420
+
421
+ with Modal(visible=False, elem_id="modal_figure_galery") as figure_modal:
422
+ gallery_component = gr.Gallery(
423
+ object_fit='scale-down',
424
+ elem_id="gallery-component",
425
+ height="80vh"
426
+ )
427
+
428
+ show_full_size_figures = gr.Button(
429
+ "Show figures in full size",
430
+ elem_id="show-figures",
431
+ interactive=True
432
+ )
433
+ show_full_size_figures.click(
434
+ lambda: Modal(visible=True),
435
+ None,
436
+ figure_modal
437
+ )
438
+
439
+ figures_cards = gr.HTML(show_label=False, elem_id="sources-figures")
440
+
441
+ return sources_raw, gallery_component, figures_cards, figure_modal
442
+
443
+ def create_papers_tab():
444
+ with gr.Accordion(
445
+ visible=True,
446
+ elem_id="papers-summary-popup",
447
+ label="See summary of relevant papers",
448
+ open=False
449
+ ) as summary_popup:
450
+ papers_summary = gr.Markdown("", visible=True, elem_id="papers-summary")
451
+
452
+ with gr.Accordion(
453
+ visible=True,
454
+ elem_id="papers-relevant-popup",
455
+ label="See relevant papers",
456
+ open=False
457
+ ) as relevant_popup:
458
+ papers_html = gr.HTML(show_label=False, elem_id="papers-textbox")
459
+
460
+ btn_citations_network = gr.Button("Explore papers citations network")
461
+ with Modal(visible=False) as papers_modal:
462
+ citations_network = gr.HTML(
463
+ "<h3>Citations Network Graph</h3>",
464
+ visible=True,
465
+ elem_id="papers-citations-network"
466
+ )
467
+ btn_citations_network.click(
468
+ lambda: Modal(visible=True),
469
+ None,
470
+ papers_modal
471
+ )
472
+
473
+ return papers_summary, papers_html, citations_network, papers_modal
474
+
475
+ def create_config_modal(config_open):
476
+ with Modal(visible=False, elem_id="modal-config") as config_modal:
477
+ gr.Markdown("Reminders: You can talk in any language, ClimateQ&A is multi-lingual!")
478
+
479
+ dropdown_sources = gr.CheckboxGroup(
480
+ choices=["IPCC", "IPBES", "IPOS"],
481
+ label="Select source (by default search in all sources)",
482
+ value=["IPCC"],
483
+ interactive=True
484
+ )
485
+
486
+ dropdown_reports = gr.Dropdown(
487
+ choices=POSSIBLE_REPORTS,
488
+ label="Or select specific reports",
489
+ multiselect=True,
490
+ value=None,
491
+ interactive=True
492
+ )
493
+
494
+ dropdown_external_sources = gr.CheckboxGroup(
495
+ choices=["IPCC figures", "OpenAlex", "OurWorldInData"],
496
+ label="Select database to search for relevant content",
497
+ value=["IPCC figures"],
498
+ interactive=True
499
+ )
500
+
501
+ search_only = gr.Checkbox(
502
+ label="Search only for recommended content without chating",
503
+ value=False,
504
+ interactive=True,
505
+ elem_id="checkbox-chat"
506
+ )
507
+
508
+ dropdown_audience = gr.Dropdown(
509
+ choices=["Children", "General public", "Experts"],
510
+ label="Select audience",
511
+ value="Experts",
512
+ interactive=True
513
+ )
514
+
515
+ after = gr.Slider(
516
+ minimum=1950,
517
+ maximum=2023,
518
+ step=1,
519
+ value=1960,
520
+ label="Publication date",
521
+ show_label=True,
522
+ interactive=True,
523
+ elem_id="date-papers",
524
+ visible=False
525
+ )
526
+
527
+ output_query = gr.Textbox(
528
+ label="Query used for retrieval",
529
+ show_label=True,
530
+ elem_id="reformulated-query",
531
+ lines=2,
532
+ interactive=False,
533
+ visible=False
534
+ )
535
+
536
+ output_language = gr.Textbox(
537
+ label="Language",
538
+ show_label=True,
539
+ elem_id="language",
540
+ lines=1,
541
+ interactive=False,
542
+ visible=False
543
+ )
544
+
545
+ dropdown_external_sources.change(
546
+ lambda x: gr.update(visible="OpenAlex" in x),
547
+ inputs=[dropdown_external_sources],
548
+ outputs=[after]
549
+ )
550
+
551
+ close_config_modal = gr.Button("Validate and Close", elem_id="close-config-modal")
552
+ close_config_modal.click(
553
+ fn=update_config_modal_visibility,
554
+ inputs=[config_open],
555
+ outputs=[config_modal, config_open]
556
+ )
557
+
558
+ return (config_modal, dropdown_sources, dropdown_reports, dropdown_external_sources,
559
+ search_only, dropdown_audience, after, output_query, output_language)
560
+
561
+ # Main UI Assembly
562
  with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=theme, elem_id="main-component") as demo:
563
  # State variables
564
  chat_completed_state = gr.State(0)
 
570
  with gr.Row(elem_id="chatbot-row"):
571
  # Left column - Chat interface
572
  with gr.Column(scale=2):
573
+ chatbot, textbox, config_button = create_chat_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
574
 
575
  # Right column - Content panels
576
  with gr.Column(scale=2, variant="panel", elem_id="right-panel"):
577
  with gr.Tabs(elem_id="right_panel_tab") as tabs:
578
  # Examples tab
579
  with gr.TabItem("Examples", elem_id="tab-examples", id=0):
580
+ examples_hidden, dropdown_samples, samples = create_examples_tab()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
 
582
  # Sources tab
583
  with gr.Tab("Sources", elem_id="tab-sources", id=1) as tab_sources:
 
588
  with gr.Tabs(elem_id="group-subtabs") as tabs_recommended_content:
589
  # Figures subtab
590
  with gr.Tab("Figures", elem_id="tab-figures", id=3) as tab_figures:
591
+ sources_raw, gallery_component, figures_cards, figure_modal = create_figures_tab()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
 
593
  # Papers subtab
594
  with gr.Tab("Papers", elem_id="tab-citations", id=4) as tab_papers:
595
+ papers_summary, papers_html, citations_network, papers_modal = create_papers_tab()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596
 
597
  # Graphs subtab
598
  with gr.Tab("Graphs", elem_id="tab-graphs", id=5) as tab_graphs:
 
606
  outputs=[graphs_container]
607
  )
608
 
609
+
 
 
610
 
611
+ # Other tabs
612
+ with gr.Tab("About", elem_classes="max-height other-tabs"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
  with gr.Row():
614
  with gr.Column(scale=1):
 
 
 
 
615
  gr.Markdown(
616
  """
617
  ### More info
 
621
  ### Citation
622
  """
623
  )
624
+ with gr.Accordion(CITATION_LABEL, elem_id="citation", open=False):
 
625
  gr.Textbox(
626
  value=CITATION_TEXT,
627
  label="",
 
630
  lines=len(CITATION_TEXT.split('\n')),
631
  )
632
 
633
+ # Event handlers
634
+ config_modal, dropdown_sources, dropdown_reports, dropdown_external_sources, search_only, dropdown_audience, after, output_query, output_language = create_config_modal(config_open)
 
 
 
 
 
 
 
 
 
635
 
636
+ config_button.click(
637
+ fn=update_config_modal_visibility,
638
+ inputs=[config_open],
639
+ outputs=[config_modal, config_open]
640
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
641
 
 
 
 
 
 
 
 
 
 
 
 
 
642
 
643
  (textbox
644
+ .submit(start_chat, [textbox, chatbot, search_only], [textbox, tabs, chatbot], queue=False, api_name="start_chat_textbox")
645
+ .then(chat, [textbox, chatbot, dropdown_audience, dropdown_sources, dropdown_reports, dropdown_external_sources, search_only], [chatbot, sources_textbox, output_query, output_language, sources_raw, current_graphs], concurrency_limit=8, api_name="chat_textbox")
646
+ .then(finish_chat, None, [textbox], api_name="finish_chat_textbox")
 
647
  )
648
 
649
  (examples_hidden
650
+ .change(start_chat, [examples_hidden, chatbot, search_only], [textbox, tabs, chatbot], queue=False, api_name="start_chat_examples")
651
+ .then(chat, [examples_hidden, chatbot, dropdown_audience, dropdown_sources, dropdown_reports, dropdown_external_sources, search_only], [chatbot, sources_textbox, output_query, output_language, sources_raw, current_graphs], concurrency_limit=8, api_name="chat_textbox")
652
+ .then(finish_chat, None, [textbox], api_name="finish_chat_examples")
 
653
  )
654
 
 
 
 
 
 
 
 
 
655
  sources_raw.change(process_figures, inputs=[sources_raw], outputs=[figures_cards, gallery_component])
 
 
 
 
 
 
656
 
657
+ # Update sources numbers
658
+ sources_textbox.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs, papers_html], [tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
659
+ figures_cards.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs, papers_html], [tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
660
+ current_graphs.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs, papers_html], [tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
661
+ papers_html.change(update_sources_number_display, [sources_textbox, figures_cards, current_graphs, papers_html], [tab_recommended_content, tab_sources, tab_figures, tab_graphs, tab_papers])
662
 
663
+ # Other questions examples
664
+ dropdown_samples.change(change_sample_questions, dropdown_samples, samples)
 
665
 
666
+ # Search for papers
667
+ textbox.submit(find_papers, [textbox, after, dropdown_external_sources], [papers_html, citations_network, papers_summary])
668
+ examples_hidden.change(find_papers, [examples_hidden, after, dropdown_external_sources], [papers_html, citations_network, papers_summary])
669
 
670
  demo.queue()
671
+
672
  demo.launch(ssr_mode=False)