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

clean chat and style

Browse files
Files changed (2) hide show
  1. app.py +272 -271
  2. style.css +400 -487
app.py CHANGED
@@ -3,8 +3,6 @@ embeddings_function = get_embeddings_function()
3
 
4
  from sentence_transformers import CrossEncoder
5
 
6
- # reranker = CrossEncoder("mixedbread-ai/mxbai-rerank-xsmall-v1")
7
-
8
  import gradio as gr
9
  from gradio_modal import Modal
10
  import pandas as pd
@@ -16,8 +14,6 @@ import json
16
 
17
  from gradio import ChatMessage
18
 
19
- # from gradio_modal import Modal
20
-
21
  from io import BytesIO
22
  import base64
23
 
@@ -28,19 +24,13 @@ from utils import create_user_id
28
 
29
  from gradio_modal import Modal
30
 
31
- from PIL import Image
32
-
33
- from langchain_core.runnables.schema import StreamEvent
34
 
35
  # ClimateQ&A imports
36
  from climateqa.engine.llm import get_llm
37
  from climateqa.engine.vectorstore import get_pinecone_vectorstore
38
- # from climateqa.knowledge.retriever import ClimateQARetriever
39
  from climateqa.engine.reranker import get_reranker
40
- from climateqa.engine.embeddings import get_embeddings_function
41
- from climateqa.engine.chains.prompts import audience_prompts
42
  from climateqa.sample_questions import QUESTIONS
43
- from climateqa.constants import POSSIBLE_REPORTS, OWID_CATEGORIES
44
  from climateqa.utils import get_image_from_azure_blob_storage
45
  from climateqa.engine.graph import make_graph_agent
46
  from climateqa.engine.embeddings import get_embeddings_function
@@ -57,7 +47,6 @@ try:
57
  except Exception as e:
58
  pass
59
 
60
- import requests
61
 
62
  # Set up Gradio Theme
63
  theme = gr.themes.Base(
@@ -68,7 +57,24 @@ theme = gr.themes.Base(
68
 
69
 
70
 
71
- init_prompt = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  system_template = {
74
  "role": "system",
@@ -122,27 +128,49 @@ def update_config_modal_visibility(config_open):
122
  return gr.update(visible=new_config_visibility_status), new_config_visibility_status
123
 
124
  async def chat(query, history, audience, sources, reports, relevant_content_sources, search_only):
125
- """taking a query and a message history, use a pipeline (reformulation, retriever, answering) to yield a tuple of:
126
- (messages in gradio format, messages in langchain format, source documents)"""
127
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  date_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
129
  print(f">> NEW QUESTION ({date_now}) : {query}")
130
 
131
  audience_prompt = init_audience(audience)
132
-
133
- # Prepare default values
134
- if sources is None or len(sources) == 0:
135
- sources = ["IPCC", "IPBES", "IPOS"]
136
-
137
- if reports is None or len(reports) == 0:
138
- reports = []
139
 
140
- inputs = {"user_input": query,"audience": audience_prompt,"sources_input":sources, "relevant_content_sources" : relevant_content_sources, "search_only": search_only}
141
- result = agent.astream_events(inputs,version = "v1")
142
-
 
 
 
 
 
 
 
 
143
 
 
144
  docs = []
145
- used_figures=[]
146
  related_contents = []
147
  docs_html = ""
148
  output_query = ""
@@ -151,79 +179,91 @@ async def chat(query, history, audience, sources, reports, relevant_content_sour
151
  start_streaming = False
152
  graphs_html = ""
153
  figures = '<div class="figures-container"><p></p> </div>'
 
 
154
 
 
155
  steps_display = {
156
- "categorize_intent":("🔄️ Analyzing user message",True),
157
- "transform_query":("🔄️ Thinking step by step to answer the question",True),
158
- "retrieve_documents":("🔄️ Searching in the knowledge base",False),
159
  }
160
-
161
- used_documents = []
162
- answer_message_content = ""
163
  try:
 
164
  async for event in result:
165
  if "langgraph_node" in event["metadata"]:
166
  node = event["metadata"]["langgraph_node"]
167
 
168
- if event["event"] == "on_chain_end" and event["name"] == "retrieve_documents" :# when documents are retrieved
169
- docs, docs_html, history, used_documents, related_contents = handle_retrieved_documents(event, history, used_documents)
170
-
171
- elif event["event"] == "on_chain_end" and node == "categorize_intent" and event["name"] == "_write": # when the query is transformed
172
-
 
 
 
 
 
173
  intent = event["data"]["output"]["intent"]
174
- if "language" in event["data"]["output"]:
175
- output_language = event["data"]["output"]["language"]
176
- else :
177
- output_language = "English"
178
- history[-1].content = f"Language identified : {output_language} \n Intent identified : {intent}"
179
-
180
-
181
- elif event["name"] in steps_display.keys() and event["event"] == "on_chain_start": #display steps
182
  event_description, display_output = steps_display[node]
183
- if not hasattr(history[-1], 'metadata') or history[-1].metadata["title"] != event_description: # if a new step begins
184
- history.append(ChatMessage(role="assistant", content = "", metadata={'title' :event_description}))
185
-
186
- elif event["name"] != "transform_query" and event["event"] == "on_chat_model_stream" and node in ["answer_rag", "answer_search","answer_chitchat"]:# if streaming answer
187
- history, start_streaming, answer_message_content = stream_answer(history, event, start_streaming, answer_message_content)
 
 
 
 
 
 
 
 
 
 
188
 
 
189
  elif event["name"] in ["retrieve_graphs", "retrieve_graphs_ai"] and event["event"] == "on_chain_end":
190
  graphs_html = handle_retrieved_owid_graphs(event, graphs_html)
191
 
 
 
 
 
 
192
 
193
- if event["name"] == "transform_query" and event["event"] =="on_chain_end":
194
- if hasattr(history[-1],"content"):
195
- history[-1].content += "Decompose question into sub-questions: \n\n - " + "\n - ".join([q["question"] for q in event["data"]["output"]["remaining_questions"]])
196
-
197
- if event["name"] == "categorize_intent" and event["event"] == "on_chain_start":
198
- print("X")
199
-
200
- yield history, docs_html, output_query, output_language, related_contents , graphs_html, #,output_query,output_keywords
201
-
202
- except Exception as e:
203
- print(event, "has failed")
204
- raise gr.Error(f"{e}")
205
 
 
 
 
206
 
207
  try:
208
- # Log answer on Azure Blob Storage
209
  if os.getenv("GRADIO_ENV") != "local":
210
  timestamp = str(datetime.now().timestamp())
211
- file = timestamp + ".json"
212
  prompt = history[1]["content"]
213
  logs = {
214
  "user_id": str(user_id),
215
  "prompt": prompt,
216
  "query": prompt,
217
- "question":output_query,
218
- "sources":sources,
219
- "docs":serialize_docs(docs),
220
  "answer": history[-1].content,
221
  "time": timestamp,
222
  }
223
- log_on_azure(file, logs, share_client)
224
  except Exception as e:
225
  print(f"Error logging on Azure Blob Storage: {e}")
226
- raise gr.Error(f"ClimateQ&A Error: {str(e)[:100]} - The error has been noted, try another question and if the error remains, you can contact us :)")
 
227
 
228
  yield history, docs_html, output_query, output_language, related_contents, graphs_html
229
 
@@ -291,275 +331,236 @@ def save_graph(saved_graphs_state, embedding, category):
291
  saved_graphs_state[category].append(embedding)
292
  return saved_graphs_state, gr.Button("Graph Saved")
293
 
294
-
295
-
296
- with gr.Blocks(title="Climate Q&A", css_paths=os.getcwd()+ "/style.css", theme=theme,elem_id = "main-component") as demo:
297
  chat_completed_state = gr.State(0)
298
  current_graphs = gr.State([])
299
  saved_graphs = gr.State({})
300
  config_open = gr.State(False)
301
 
302
-
303
  with gr.Tab("ClimateQ&A"):
304
-
305
  with gr.Row(elem_id="chatbot-row"):
 
306
  with gr.Column(scale=2):
307
  chatbot = gr.Chatbot(
308
- value = [ChatMessage(role="assistant", content=init_prompt)],
309
- type = "messages",
310
  show_copy_button=True,
311
- show_label = False,
312
  elem_id="chatbot",
313
- layout = "panel",
314
- avatar_images = (None,"https://i.ibb.co/YNyd5W2/logo4.png"),
315
  max_height="80vh",
316
  height="100vh"
317
  )
318
-
319
- # bot.like(vote,None,None)
320
-
321
-
322
-
323
- with gr.Row(elem_id = "input-message"):
324
- textbox=gr.Textbox(placeholder="Ask me anything here!",show_label=False,scale=7,lines = 1,interactive = True,elem_id="input-textbox")
325
-
326
- config_button = gr.Button("",elem_id="config-button")
327
- # config_checkbox_button = gr.Checkbox(label = '⚙️', value="show",visible=True, interactive=True, elem_id="checkbox-config")
328
-
329
-
330
-
331
- with gr.Column(scale=2, variant="panel",elem_id = "right-panel"):
332
 
333
-
334
- with gr.Tabs(elem_id = "right_panel_tab") as tabs:
335
- with gr.TabItem("Examples",elem_id = "tab-examples",id = 0):
336
-
337
- examples_hidden = gr.Textbox(visible = False)
 
 
 
 
 
 
 
 
 
 
 
 
338
  first_key = list(QUESTIONS.keys())[0]
339
- dropdown_samples = gr.Dropdown(QUESTIONS.keys(),value = first_key,interactive = True,show_label = True,label = "Select a category of sample questions",elem_id = "dropdown-samples")
 
 
 
 
 
 
340
 
341
  samples = []
342
- for i,key in enumerate(QUESTIONS.keys()):
343
-
344
- examples_visible = True if i == 0 else False
345
-
346
- with gr.Row(visible = examples_visible) as group_examples:
347
-
348
  examples_questions = gr.Examples(
349
- QUESTIONS[key],
350
- [examples_hidden],
351
  examples_per_page=8,
352
  run_on_click=False,
353
  elem_id=f"examples{i}",
354
- api_name=f"examples{i}",
355
- # label = "Click on the example question or enter your own",
356
- # cache_examples=True,
357
  )
358
-
359
  samples.append(group_examples)
360
-
361
- # with gr.Tab("Configuration", id = 10, ) as tab_config:
362
- # # gr.Markdown("Reminders: You can talk in any language, ClimateQ&A is multi-lingual!")
363
 
364
- # pass
365
-
366
- # with gr.Row():
367
-
368
- # dropdown_sources = gr.CheckboxGroup(
369
- # ["IPCC", "IPBES","IPOS"],
370
- # label="Select source",
371
- # value=["IPCC"],
372
- # interactive=True,
373
- # )
374
- # dropdown_external_sources = gr.CheckboxGroup(
375
- # ["IPCC figures","OpenAlex", "OurWorldInData"],
376
- # label="Select database to search for relevant content",
377
- # value=["IPCC figures"],
378
- # interactive=True,
379
- # )
380
-
381
- # dropdown_reports = gr.Dropdown(
382
- # POSSIBLE_REPORTS,
383
- # label="Or select specific reports",
384
- # multiselect=True,
385
- # value=None,
386
- # interactive=True,
387
- # )
388
-
389
- # search_only = gr.Checkbox(label="Search only without chating", value=False, interactive=True, elem_id="checkbox-chat")
390
-
391
-
392
- # dropdown_audience = gr.Dropdown(
393
- # ["Children","General public","Experts"],
394
- # label="Select audience",
395
- # value="Experts",
396
- # interactive=True,
397
- # )
398
-
399
-
400
- # after = gr.Slider(minimum=1950,maximum=2023,step=1,value=1960,label="Publication date",show_label=True,interactive=True,elem_id="date-papers", visible=False)
401
-
402
-
403
- # output_query = gr.Textbox(label="Query used for retrieval",show_label = True,elem_id = "reformulated-query",lines = 2,interactive = False, visible= False)
404
- # output_language = gr.Textbox(label="Language",show_label = True,elem_id = "language",lines = 1,interactive = False, visible= False)
405
-
406
-
407
- # dropdown_external_sources.change(lambda x: gr.update(visible = True ) if "OpenAlex" in x else gr.update(visible=False) , inputs=[dropdown_external_sources], outputs=[after])
408
- # # dropdown_external_sources.change(lambda x: gr.update(visible = True ) if "OpenAlex" in x else gr.update(visible=False) , inputs=[dropdown_external_sources], outputs=[after], visible=True)
409
-
410
-
411
- with gr.Tab("Sources",elem_id = "tab-sources",id = 1) as tab_sources:
412
  sources_textbox = gr.HTML(show_label=False, elem_id="sources-textbox")
413
-
414
-
415
-
416
- with gr.Tab("Recommended content", elem_id="tab-recommended_content",id=2) as tab_recommended_content:
417
- with gr.Tabs(elem_id = "group-subtabs") as tabs_recommended_content:
418
-
419
- with gr.Tab("Figures",elem_id = "tab-figures",id = 3) as tab_figures:
420
  sources_raw = gr.State()
421
 
422
  with Modal(visible=False, elem_id="modal_figure_galery") as figure_modal:
423
- gallery_component = gr.Gallery(object_fit='scale-down',elem_id="gallery-component", height="80vh")
 
 
 
 
424
 
425
- show_full_size_figures = gr.Button("Show figures in full size",elem_id="show-figures",interactive=True)
426
- show_full_size_figures.click(lambda : Modal(visible=True),None,figure_modal)
 
 
 
 
 
 
 
 
427
 
428
  figures_cards = gr.HTML(show_label=False, elem_id="sources-figures")
429
 
430
-
431
-
432
- with gr.Tab("Papers",elem_id = "tab-citations",id = 4) as tab_papers:
433
- # btn_summary = gr.Button("Summary")
434
- # Fenêtre simulée pour le Summary
435
- with gr.Accordion(visible=True, elem_id="papers-summary-popup", label= "See summary of relevant papers", open= False) as summary_popup:
 
 
436
  papers_summary = gr.Markdown("", visible=True, elem_id="papers-summary")
437
 
438
- # btn_relevant_papers = gr.Button("Relevant papers")
439
- # Fenêtre simulée pour les Relevant Papers
440
- with gr.Accordion(visible=True, elem_id="papers-relevant-popup",label= "See relevant papers", open= False) as relevant_popup:
 
 
 
441
  papers_html = gr.HTML(show_label=False, elem_id="papers-textbox")
442
 
443
  btn_citations_network = gr.Button("Explore papers citations network")
444
- # Fenêtre simulée pour le Citations Network
445
  with Modal(visible=False) as papers_modal:
446
- citations_network = gr.HTML("<h3>Citations Network Graph</h3>", visible=True, elem_id="papers-citations-network")
447
- btn_citations_network.click(lambda: Modal(visible=True), None, papers_modal)
448
-
449
-
450
-
 
 
 
 
 
 
 
451
  with gr.Tab("Graphs", elem_id="tab-graphs", id=5) as tab_graphs:
452
-
453
- graphs_container = gr.HTML("<h2>There are no graphs to be displayed at the moment. Try asking another question.</h2>",elem_id="graphs-container")
454
- current_graphs.change(lambda x : x, inputs=[current_graphs], outputs=[graphs_container])
455
-
456
- with Modal(visible=False,elem_id="modal-config") as config_modal:
 
 
 
 
 
 
 
457
  gr.Markdown("Reminders: You can talk in any language, ClimateQ&A is multi-lingual!")
458
 
459
-
460
- # with gr.Row():
461
-
462
  dropdown_sources = gr.CheckboxGroup(
463
- ["IPCC", "IPBES","IPOS"],
464
  label="Select source (by default search in all sources)",
465
  value=["IPCC"],
466
- interactive=True,
467
  )
468
-
469
  dropdown_reports = gr.Dropdown(
470
- POSSIBLE_REPORTS,
471
  label="Or select specific reports",
472
  multiselect=True,
473
  value=None,
474
- interactive=True,
475
  )
476
-
477
  dropdown_external_sources = gr.CheckboxGroup(
478
- ["IPCC figures","OpenAlex", "OurWorldInData"],
479
- label="Select database to search for relevant content",
480
  value=["IPCC figures"],
481
- interactive=True,
482
  )
483
 
484
- search_only = gr.Checkbox(label="Search only for recommended content without chating", value=False, interactive=True, elem_id="checkbox-chat")
485
-
 
 
 
 
486
 
487
  dropdown_audience = gr.Dropdown(
488
- ["Children","General public","Experts"],
489
  label="Select audience",
490
  value="Experts",
491
- interactive=True,
492
  )
493
-
494
-
495
- after = gr.Slider(minimum=1950,maximum=2023,step=1,value=1960,label="Publication date",show_label=True,interactive=True,elem_id="date-papers", visible=False)
496
-
497
-
498
- output_query = gr.Textbox(label="Query used for retrieval",show_label = True,elem_id = "reformulated-query",lines = 2,interactive = False, visible= False)
499
- output_language = gr.Textbox(label="Language",show_label = True,elem_id = "language",lines = 1,interactive = False, visible= False)
500
-
501
-
502
- dropdown_external_sources.change(lambda x: gr.update(visible = True ) if "OpenAlex" in x else gr.update(visible=False) , inputs=[dropdown_external_sources], outputs=[after])
503
-
504
- close_config_modal = gr.Button("Validate and Close",elem_id="close-config-modal")
505
- close_config_modal.click(fn=update_config_modal_visibility, inputs=[config_open], outputs=[config_modal, config_open])
506
- # dropdown_external_sources.change(lambda x: gr.update(visible = True ) if "OpenAlex" in x else gr.update(visible=False) , inputs=[dropdown_external_sources], outputs=[after], visible=True)
507
-
508
-
509
-
510
- config_button.click(fn=update_config_modal_visibility, inputs=[config_open], outputs=[config_modal, config_open])
511
-
512
- # with gr.Tab("OECD",elem_id = "tab-oecd",id = 6):
513
- # oecd_indicator = "RIVER_FLOOD_RP100_POP_SH"
514
- # oecd_topic = "climate"
515
- # oecd_latitude = "46.8332"
516
- # oecd_longitude = "5.3725"
517
- # oecd_zoom = "5.6442"
518
- # # Create the HTML content with the iframe
519
- # iframe_html = f"""
520
- # <iframe src="https://localdataportal.oecd.org/maps.html?indicator={oecd_indicator}&topic={oecd_topic}&latitude={oecd_latitude}&longitude={oecd_longitude}&zoom={oecd_zoom}"
521
- # width="100%" height="600" frameborder="0" style="border:0;" allowfullscreen></iframe>
522
- # """
523
- # oecd_textbox = gr.HTML(iframe_html, show_label=False, elem_id="oecd-textbox")
524
-
525
-
526
 
 
 
 
 
 
 
 
 
 
 
 
527
 
528
- #---------------------------------------------------------------------------------------
529
- # OTHER TABS
530
- #---------------------------------------------------------------------------------------
531
-
532
- # with gr.Tab("Settings",elem_id = "tab-config",id = 2):
533
-
534
- # gr.Markdown("Reminder: You can talk in any language, ClimateQ&A is multi-lingual!")
535
-
536
 
537
- # dropdown_sources = gr.CheckboxGroup(
538
- # ["IPCC", "IPBES","IPOS", "OpenAlex"],
539
- # label="Select source",
540
- # value=["IPCC"],
541
- # interactive=True,
542
- # )
 
 
543
 
544
- # dropdown_reports = gr.Dropdown(
545
- # POSSIBLE_REPORTS,
546
- # label="Or select specific reports",
547
- # multiselect=True,
548
- # value=None,
549
- # interactive=True,
550
- # )
551
 
552
- # dropdown_audience = gr.Dropdown(
553
- # ["Children","General public","Experts"],
554
- # label="Select audience",
555
- # value="Experts",
556
- # interactive=True,
557
- # )
558
 
 
 
 
 
 
559
 
560
- # output_query = gr.Textbox(label="Query used for retrieval",show_label = True,elem_id = "reformulated-query",lines = 2,interactive = False)
561
- # output_language = gr.Textbox(label="Language",show_label = True,elem_id = "language",lines = 1,interactive = False)
562
 
 
 
 
563
 
564
  with gr.Tab("About",elem_classes = "max-height other-tabs"):
565
  with gr.Row():
 
3
 
4
  from sentence_transformers import CrossEncoder
5
 
 
 
6
  import gradio as gr
7
  from gradio_modal import Modal
8
  import pandas as pd
 
14
 
15
  from gradio import ChatMessage
16
 
 
 
17
  from io import BytesIO
18
  import base64
19
 
 
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
 
 
32
  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
 
47
  except Exception as e:
48
  pass
49
 
 
50
 
51
  # Set up Gradio Theme
52
  theme = gr.themes.Base(
 
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
+
63
+ ❓ How to use
64
+ - **Language**: You can ask me your questions in any language.
65
+ - **Audience**: You can specify your audience (children, general public, experts) to get a more adapted answer.
66
+ - **Sources**: You can choose to search in the IPCC or IPBES reports, or both.
67
+ - **Relevant content sources**: You can choose to search for figures, papers, or graphs that can be relevant for your question.
68
+
69
+ ⚠️ Limitations
70
+ *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.*
71
+
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",
 
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:
134
+ query (str): The user's question
135
+ history (list): Chat message history
136
+ audience (str): Target audience type
137
+ sources (list): Knowledge base sources to search
138
+ reports (list): Specific reports to search within sources
139
+ relevant_content_sources (list): Types of content to retrieve (figures, papers, etc)
140
+ search_only (bool): Whether to only search without generating answer
141
+
142
+ Yields:
143
+ tuple: Contains:
144
+ - history: Updated chat history
145
+ - docs_html: HTML of retrieved documents
146
+ - output_query: Processed query
147
+ - output_language: Detected language
148
+ - related_contents: Related content
149
+ - graphs_html: HTML of relevant graphs
150
+ """
151
+ # Log incoming question
152
  date_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
153
  print(f">> NEW QUESTION ({date_now}) : {query}")
154
 
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,
162
+ "audience": audience_prompt,
163
+ "sources_input": sources,
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
 
171
+ # Initialize state variables
172
  docs = []
173
+ used_figures = []
174
  related_contents = []
175
  docs_html = ""
176
  output_query = ""
 
179
  start_streaming = False
180
  graphs_html = ""
181
  figures = '<div class="figures-container"><p></p> </div>'
182
+ used_documents = []
183
+ answer_message_content = ""
184
 
185
+ # Define processing steps
186
  steps_display = {
187
+ "categorize_intent": ("🔄️ Analyzing user message", True),
188
+ "transform_query": ("🔄️ Thinking step by step to answer the question", True),
189
+ "retrieve_documents": ("🔄️ Searching in the knowledge base", False),
190
  }
191
+
 
 
192
  try:
193
+ # Process streaming events
194
  async for event in result:
195
  if "langgraph_node" in event["metadata"]:
196
  node = event["metadata"]["langgraph_node"]
197
 
198
+ # Handle document retrieval
199
+ if event["event"] == "on_chain_end" and event["name"] == "retrieve_documents":
200
+ docs, docs_html, history, used_documents, related_contents = handle_retrieved_documents(
201
+ event, history, used_documents
202
+ )
203
+
204
+ # Handle intent categorization
205
+ elif (event["event"] == "on_chain_end" and
206
+ node == "categorize_intent" and
207
+ event["name"] == "_write"):
208
  intent = event["data"]["output"]["intent"]
209
+ output_language = event["data"]["output"].get("language", "English")
210
+ history[-1].content = f"Language identified: {output_language}\nIntent identified: {intent}"
211
+
212
+ # Handle processing steps display
213
+ elif event["name"] in steps_display and event["event"] == "on_chain_start":
 
 
 
214
  event_description, display_output = steps_display[node]
215
+ if (not hasattr(history[-1], 'metadata') or
216
+ history[-1].metadata["title"] != event_description):
217
+ history.append(ChatMessage(
218
+ role="assistant",
219
+ content="",
220
+ metadata={'title': event_description}
221
+ ))
222
+
223
+ # Handle answer streaming
224
+ elif (event["name"] != "transform_query" and
225
+ event["event"] == "on_chat_model_stream" and
226
+ node in ["answer_rag", "answer_search", "answer_chitchat"]):
227
+ history, start_streaming, answer_message_content = stream_answer(
228
+ history, event, start_streaming, answer_message_content
229
+ )
230
 
231
+ # Handle graph retrieval
232
  elif event["name"] in ["retrieve_graphs", "retrieve_graphs_ai"] and event["event"] == "on_chain_end":
233
  graphs_html = handle_retrieved_owid_graphs(event, graphs_html)
234
 
235
+ # Handle query transformation
236
+ if event["name"] == "transform_query" and event["event"] == "on_chain_end":
237
+ if hasattr(history[-1], "content"):
238
+ sub_questions = [q["question"] for q in event["data"]["output"]["remaining_questions"]]
239
+ history[-1].content += "Decompose question into sub-questions:\n\n - " + "\n - ".join(sub_questions)
240
 
241
+ yield history, docs_html, output_query, output_language, related_contents, graphs_html #,output_query,output_keywords
 
 
 
 
 
 
 
 
 
 
 
242
 
243
+ except Exception as e:
244
+ print(f"Event {event} has failed")
245
+ raise gr.Error(str(e))
246
 
247
  try:
248
+ # Log interaction to Azure if not in local environment
249
  if os.getenv("GRADIO_ENV") != "local":
250
  timestamp = str(datetime.now().timestamp())
 
251
  prompt = history[1]["content"]
252
  logs = {
253
  "user_id": str(user_id),
254
  "prompt": prompt,
255
  "query": prompt,
256
+ "question": output_query,
257
+ "sources": sources,
258
+ "docs": serialize_docs(docs),
259
  "answer": history[-1].content,
260
  "time": timestamp,
261
  }
262
+ log_on_azure(f"{timestamp}.json", logs, share_client)
263
  except Exception as e:
264
  print(f"Error logging on Azure Blob Storage: {e}")
265
+ error_msg = f"ClimateQ&A Error: {str(e)[:100]} - The error has been noted, try another question and if the error remains, you can contact us :)"
266
+ raise gr.Error(error_msg)
267
 
268
  yield history, docs_html, output_query, output_language, related_contents, graphs_html
269
 
 
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)
337
  current_graphs = gr.State([])
338
  saved_graphs = gr.State({})
339
  config_open = gr.State(False)
340
 
 
341
  with gr.Tab("ClimateQ&A"):
 
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:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  sources_textbox = gr.HTML(show_label=False, elem_id="sources-textbox")
400
+
401
+ # Recommended content tab
402
+ with gr.Tab("Recommended content", elem_id="tab-recommended_content", id=2) as tab_recommended_content:
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:
461
+ graphs_container = gr.HTML(
462
+ "<h2>There are no graphs to be displayed at the moment. Try asking another question.</h2>",
463
+ elem_id="graphs-container"
464
+ )
465
+ current_graphs.change(
466
+ lambda x: x,
467
+ inputs=[current_graphs],
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():
style.css CHANGED
@@ -1,89 +1,134 @@
1
-
2
  /* :root {
3
  --user-image: url('https://ih1.redbubble.net/image.4776899543.6215/st,small,507x507-pad,600x600,f8f8f8.jpg');
4
- } */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- #tab-recommended_content{
7
- padding-top: 0px;
8
- padding-left : 0px;
9
- padding-right: 0px;
10
  }
 
11
  #group-subtabs {
12
- /* display: block; */
13
- width: 100%; /* Ensures the parent uses the full width */
14
- position : sticky;
15
  }
16
 
17
  #group-subtabs .tab-container {
18
  display: flex;
19
  text-align: center;
20
- width: 100%; /* Ensures the tabs span the full width */
21
  }
22
 
23
  #group-subtabs .tab-container button {
24
- flex: 1; /* Makes each button take equal width */
25
  }
26
 
 
 
 
27
 
28
- #papers-summary-popup button span{
29
- /* make label of accordio in bold, center, and bigger */
30
- font-size: 16px;
31
  font-weight: bold;
32
- text-align: center;
 
33
 
 
 
34
  }
35
 
36
- #papers-relevant-popup span{
37
- /* make label of accordio in bold, center, and bigger */
38
- font-size: 16px;
39
- font-weight: bold;
40
- text-align: center;
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
43
 
 
 
 
44
 
45
- #tab-citations .button{
46
- padding: 12px 16px;
47
- font-size: 16px;
48
  font-weight: bold;
49
- cursor: pointer;
50
- border: none;
51
- outline: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  text-align: left;
53
- transition: background-color 0.3s ease;
54
  }
55
 
 
 
 
56
 
57
- .gradio-container {
58
- width: 100%!important;
59
- max-width: 100% !important;
60
  }
61
 
62
- /* fix for huggingface infinite growth*/
63
- main.flex.flex-1.flex-col {
64
- max-height: 95vh !important;
65
  }
66
 
67
- button#show-figures{
68
- /* Base styles */
69
- background-color: #f5f5f5;
70
- border: 1px solid #e0e0e0;
71
- border-radius: 4px;
72
- color: #333333;
73
- cursor: pointer;
74
- width: 100%;
75
- text-align: center;
76
  }
77
 
78
- .avatar-container.svelte-1x5p6hu:not(.thumbnail-item) img {
79
- width: 100%;
80
- height: 100%;
81
- object-fit: cover;
82
- border-radius: 50%;
83
- padding: 0px;
84
- margin: 0px;
85
  }
86
 
 
87
  .warning-box {
88
  background-color: #fff3cd;
89
  border: 1px solid #ffeeba;
@@ -93,32 +138,20 @@ button#show-figures{
93
  color: #856404;
94
  display: inline-block;
95
  margin-bottom: 15px;
96
- }
97
-
98
 
99
  .tip-box {
100
  background-color: #f0f9ff;
101
  border: 1px solid #80d4fa;
102
  border-radius: 4px;
103
- margin-top:20px;
104
  padding: 15px 20px;
105
  font-size: 14px;
106
  display: inline-block;
107
- margin-bottom: 15px;
108
  width: auto;
109
- color:black !important;
110
- }
111
-
112
- body.dark .warning-box * {
113
- color:black !important;
114
  }
115
 
116
-
117
- body.dark .tip-box * {
118
- color:black !important;
119
- }
120
-
121
-
122
  .tip-box-title {
123
  font-weight: bold;
124
  font-size: 14px;
@@ -130,116 +163,128 @@ body.dark .tip-box * {
130
  margin-right: 5px;
131
  }
132
 
133
- .gr-box {border-color: #d6c37c}
134
-
135
- #hidden-message{
136
- display:none;
 
 
 
 
 
 
 
137
  }
138
 
139
- .message{
140
- font-size:14px !important;
141
-
142
- }
143
- .card-content img {
144
- display: block;
145
- margin: auto;
146
- max-width: 100%; /* Ensures the image is responsive */
147
- height: auto;
148
  }
149
 
150
- a {
151
- text-decoration: none;
152
- color: inherit;
 
 
 
 
153
  }
154
 
155
- .doc-ref sup{
156
- color:#dc2626!important;
157
- /* margin-right:1px; */
158
  }
159
 
 
 
 
 
160
 
161
- .card {
162
- background-color: white;
163
- border-radius: 10px;
164
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
165
- overflow: hidden;
166
- display: flex;
167
- flex-direction: column;
168
- margin:20px;
169
  }
170
 
171
- .card-content {
172
- padding: 20px;
 
 
173
  }
174
 
175
- .card-content h2 {
176
- font-size: 14px !important;
177
- font-weight: bold;
178
- margin-bottom: 10px;
179
- margin-top:0px !important;
180
- color:#dc2626!important;;
181
  }
182
 
183
- .card-content p {
184
- font-size: 12px;
185
- margin-bottom: 0;
 
 
186
  }
187
 
188
- .card-footer {
189
- background-color: #f4f4f4;
190
- font-size: 10px;
191
  padding: 10px;
 
 
192
  display: flex;
193
- justify-content: space-between;
194
  align-items: center;
 
 
195
  }
196
 
197
- .card-footer span {
198
- flex-grow: 1;
199
- text-align: left;
200
- color: #999 !important;
 
 
 
 
 
201
  }
202
 
203
- .pdf-link {
204
- display: inline-flex;
205
- align-items: center;
206
- margin-left: auto;
207
- text-decoration: none!important;
208
- font-size: 14px;
 
 
 
209
  }
210
 
211
-
212
-
213
- .message.user{
214
- /* background-color:#7494b0 !important; */
215
- border:none;
216
- /* color:white!important; */
217
  }
218
 
219
- .message.bot{
220
- /* background-color:#f2f2f7 !important; */
221
- border:none;
222
  }
223
 
224
-
225
- label.selected{
226
- background: #93c5fd !important;
227
  }
228
 
229
- #submit-button{
230
- padding:0px !important;
231
  }
232
 
233
- #modal-config .block.modal-block.padded {
234
- padding-top: 25px;
235
- height: 100vh;
236
-
237
- }
238
- #modal-config .modal-container{
239
- margin: 0px;
240
- padding: 0px;
241
  }
242
- /* Modal styles */
 
243
  #modal-config {
244
  position: fixed;
245
  top: 0;
@@ -252,28 +297,23 @@ label.selected{
252
  padding: 15px;
253
  transform: none;
254
  }
255
- #modal-config .close{
256
- display: none;
 
 
257
  }
258
 
259
- /* Push main content to the right when modal is open */
260
- /* .modal ~ * {
261
- margin-left: 300px;
262
- transition: margin-left 0.3s ease;
263
- } */
264
 
265
- #modal-config .modal .wrap ul{
266
- position:static;
267
- top: 100%;
268
- left: 0;
269
- /* min-height: 100px; */
270
- height: 100%;
271
- /* margin-top: 0; */
272
- z-index: 9999;
273
- pointer-events: auto;
274
- height: 200px;
275
  }
276
- #config-button{
 
 
277
  background: none;
278
  border: none;
279
  padding: 8px;
@@ -296,155 +336,231 @@ label.selected{
296
  background-color: rgba(0, 0, 0, 0.1);
297
  }
298
 
299
- #checkbox-config{
300
- display: block;
301
- position: absolute;
302
- background: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  border: none;
304
- padding: 8px;
 
 
 
 
 
 
 
 
 
 
305
  cursor: pointer;
306
- width: 40px;
307
- height: 40px;
308
- display: flex;
309
- align-items: center;
310
- justify-content: center;
311
- border-radius: 50%;
312
- transition: background-color 0.2s;
313
- font-size: 20px;
314
  text-align: center;
315
  }
316
- #checkbox-config:checked{
317
- display: block;
 
 
318
  }
319
 
 
 
 
 
320
 
 
 
 
 
321
 
322
- @media screen and (min-width: 1024px) {
323
- /* Additional style for scrollable tab content */
324
- /* div#tab-recommended_content {
325
- overflow-y: auto;
326
- max-height: 80vh;
327
- } */
328
 
329
- .gradio-container {
330
- max-height: calc(100vh - 190px) !important;
331
- overflow: hidden;
332
- }
333
- /* div#chatbot{
334
- height:calc(100vh - 170px) !important;
335
- max-height:calc(100vh - 170px) !important;
336
 
337
- } */
 
 
 
 
338
 
 
 
 
 
339
 
340
-
341
- div#tab-examples{
342
- height:calc(100vh - 190px) !important;
343
- overflow-y: scroll !important;
344
- /* overflow-y: auto; */
345
- }
346
 
347
- div#sources-textbox{
348
- height:calc(100vh - 190px) !important;
349
- overflow-y: scroll !important;
350
- /* overflow-y: auto !important; */
351
- }
352
- div#graphs-container{
353
- height:calc(100vh - 210px) !important;
354
- overflow-y: scroll !important;
355
- }
356
 
357
- div#sources-figures{
358
- height:calc(100vh - 300px) !important;
359
- max-height: 90vh !important;
360
- overflow-y: scroll !important;
361
- }
362
 
363
- div#graphs-container{
364
- height:calc(100vh - 300px) !important;
365
- max-height: 90vh !important;
366
- overflow-y: scroll !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  }
368
 
369
- div#tab-citations{
370
- height:calc(100vh - 300px) !important;
371
- max-height: 90vh !important;
 
372
  overflow-y: scroll !important;
373
  }
374
 
375
- div#tab-config{
376
- height:calc(100vh - 190px) !important;
 
 
 
377
  overflow-y: scroll !important;
378
- /* overflow-y: auto !important; */
379
  }
380
 
381
- /* Force container to respect height limits */
382
- .main-component{
383
- contain: size layout;
384
- overflow: hidden;
385
  }
386
 
387
-
388
- div#chatbot-row{
389
- max-height:calc(100vh - 90px) !important;
390
  }
391
- /*
392
 
393
-
394
- .max-height{
395
- height:calc(100vh - 90px) !important;
396
- max-height:calc(100vh - 90px) !important;
397
  overflow-y: auto;
 
398
  }
399
- */
400
-
401
  }
402
 
403
- footer {
404
- visibility: hidden;
405
- display:none !important;
406
- }
407
-
408
-
409
  @media screen and (max-width: 767px) {
410
- /* Your mobile-specific styles go here */
411
-
412
- div#chatbot{
413
- height:500px !important;
414
  }
415
 
416
- #submit-button{
417
- padding:0px !important;
418
  min-width: 80px;
419
  }
420
 
421
- /* This will hide all list items */
422
  div.tab-nav button {
423
  display: none !important;
424
  }
425
 
426
- /* This will show only the first list item */
427
- div.tab-nav button:first-child {
428
- display: block !important;
429
- }
430
-
431
- /* This will show only the first list item */
432
  div.tab-nav button:nth-child(2) {
433
  display: block !important;
434
  }
435
-
436
- #right-panel button{
437
  display: block !important;
438
  }
439
 
440
- /* ... add other mobile-specific styles ... */
 
 
 
 
 
 
 
 
441
  }
442
 
 
443
  @media (prefers-color-scheme: dark) {
444
- .card{
445
  background-color: #374151;
446
  }
447
- .card-image > .card-content{
 
448
  background-color: rgb(55, 65, 81) !important;
449
  }
450
 
@@ -452,251 +568,48 @@ footer {
452
  background-color: #404652;
453
  }
454
 
455
- .container > .wrap{
456
  background-color: #374151 !important;
457
- color:white !important;
458
  }
459
- .card-content h2{
460
- color:#e7754f !important;
461
- }
462
- .doc-ref sup{
463
- color:rgb(235 109 35)!important;
464
- /* margin-right:1px; */
465
  }
 
466
  .card-footer span {
467
- color:white !important;
468
  }
469
-
470
- }
471
-
472
-
473
- .doc-ref{
474
- color:#dc2626!important;
475
- margin-right:1px;
476
- }
477
-
478
- .tabitem{
479
- border:none !important;
480
- }
481
-
482
- .other-tabs > div{
483
- padding-left:40px;
484
- padding-right:40px;
485
- padding-top:10px;
486
- }
487
 
488
- .gallery-item > div{
489
- white-space: normal !important; /* Allow the text to wrap */
490
- word-break: break-word !important; /* Break words to prevent overflow */
491
- overflow-wrap: break-word !important; /* Break long words if necessary */
492
- }
493
-
494
- span.chatbot > p > img{
495
- margin-top:40px !important;
496
- max-height: none !important;
497
- max-width: 80% !important;
498
- border-radius:0px !important;
499
- }
500
-
501
-
502
- .chatbot-caption{
503
- font-size:11px;
504
- font-style:italic;
505
- color:#508094;
506
- }
507
-
508
- .ai-generated{
509
- font-size:11px!important;
510
- font-style:italic;
511
- color:#73b8d4 !important;
512
- }
513
-
514
- .card-image > .card-content{
515
- background-color:#f1f7fa;
516
- }
517
-
518
-
519
-
520
- .tab-nav > button.selected{
521
- color:#4b8ec3;
522
- font-weight:bold;
523
- border:none;
524
- }
525
-
526
- .tab-nav{
527
- border:none !important;
528
- }
529
-
530
- #input-textbox > label > textarea{
531
- border-radius:40px;
532
- padding-left:30px;
533
- resize:none;
534
- }
535
-
536
- #input-message > div{
537
- border:none;
538
- }
539
-
540
- #dropdown-samples{
541
-
542
- background:none !important;
543
-
544
- }
545
-
546
- #dropdown-samples > .container > .wrap{
547
- background-color:white;
548
- }
549
-
550
-
551
- #tab-examples > div > .form{
552
- border:none;
553
- background:none !important;
554
- }
555
 
556
- .a-doc-ref{
557
- text-decoration: none !important;
 
558
  }
559
 
560
-
561
- .dropdown {
562
- position: relative;
563
- display:inline-block;
564
- margin-bottom: 10px;
565
- }
566
-
567
- .dropdown-toggle {
568
- background-color: #f2f2f2;
569
- color: black;
570
- padding: 10px;
571
- font-size: 16px;
572
- cursor: pointer;
573
- display: block;
574
- width: 400px; /* Adjust width as needed */
575
- position: relative;
576
- display: flex;
577
- align-items: center; /* Vertically center the contents */
578
- justify-content: left;
579
- }
580
-
581
- .dropdown-toggle .caret {
582
- content: "";
583
- position: absolute;
584
- right: 10px;
585
- top: 50%;
586
- border-left: 5px solid transparent;
587
- border-right: 5px solid transparent;
588
- border-top: 5px solid black;
589
- transform: translateY(-50%);
590
- }
591
-
592
- input[type="checkbox"] {
593
- display: none !important;
594
- }
595
-
596
- input[type="checkbox"]:checked + .dropdown-content {
597
  display: block;
598
- }
599
-
600
- #checkbox-chat input[type="checkbox"] {
601
- display: flex !important;
602
- }
603
-
604
- .dropdown-content {
605
- display: none;
606
  position: absolute;
607
- background-color: #f9f9f9;
608
- min-width: 300px;
609
- box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
610
- z-index: 1;
611
- padding: 12px;
612
- border: 1px solid #ccc;
613
- }
614
-
615
- input[type="checkbox"]:checked + .dropdown-toggle + .dropdown-content {
616
- display: block;
617
- }
618
-
619
- input[type="checkbox"]:checked + .dropdown-toggle .caret {
620
- border-top: 0;
621
- border-bottom: 5px solid black;
622
- }
623
-
624
- .loader {
625
- border: 1px solid #d0d0d0 !important; /* Light grey background */
626
- border-top: 1px solid #db3434 !important; /* Blue color */
627
- border-right: 1px solid #3498db !important; /* Blue color */
628
  border-radius: 50%;
629
- width: 20px;
630
- height: 20px;
631
- animation: spin 2s linear infinite;
632
- display:inline-block;
633
- margin-right:10px !important;
634
- }
635
-
636
- .checkmark{
637
- color:green !important;
638
- font-size:18px;
639
- margin-right:10px !important;
640
- }
641
-
642
- @keyframes spin {
643
- 0% { transform: rotate(0deg); }
644
- 100% { transform: rotate(360deg); }
645
- }
646
-
647
-
648
- .relevancy-score{
649
- margin-top:10px !important;
650
- font-size:10px !important;
651
- font-style:italic;
652
- }
653
-
654
- .score-green{
655
- color:green !important;
656
- }
657
-
658
- .score-orange{
659
- color:orange !important;
660
- }
661
-
662
- .score-red{
663
- color:red !important;
664
- }
665
-
666
- /* Mobile specific adjustments */
667
- @media screen and (max-width: 767px) {
668
- div#tab-recommended_content {
669
- max-height: 50vh; /* Reduce height for smaller screens */
670
- overflow-y: auto;
671
- }
672
- }
673
-
674
- /* Additional style for scrollable tab content */
675
- div#tab-saved-graphs {
676
- overflow-y: auto; /* Enable vertical scrolling */
677
- max-height: 80vh; /* Adjust height as needed */
678
- }
679
-
680
- /* Mobile specific adjustments */
681
- @media screen and (max-width: 767px) {
682
- div#tab-saved-graphs {
683
- max-height: 50vh; /* Reduce height for smaller screens */
684
- overflow-y: auto;
685
- }
686
- }
687
- .message-buttons-left.panel.message-buttons.with-avatar {
688
- display: none;
689
- }
690
-
691
-
692
- /* Specific fixes for Hugging Face Space iframe */
693
- .h-full {
694
- height: auto !important;
695
- min-height: 0 !important;
696
  }
697
 
698
- .space-content {
699
- height: auto !important;
700
- max-height: 100vh !important;
701
- overflow: hidden;
702
  }
 
1
+ /* Root Variables */
2
  /* :root {
3
  --user-image: url('https://ih1.redbubble.net/image.4776899543.6215/st,small,507x507-pad,600x600,f8f8f8.jpg');
4
+ } */
5
+
6
+ /* Layout & Container Styles */
7
+ .gradio-container {
8
+ width: 100% !important;
9
+ max-width: 100% !important;
10
+ }
11
+
12
+ main.flex.flex-1.flex-col {
13
+ max-height: 95vh !important;
14
+ }
15
+
16
+ .main-component {
17
+ contain: size layout;
18
+ overflow: hidden;
19
+ }
20
 
21
+ /* Tab Styles */
22
+ #tab-recommended_content {
23
+ padding: 0;
 
24
  }
25
+
26
  #group-subtabs {
27
+ width: 100%;
28
+ position: sticky;
 
29
  }
30
 
31
  #group-subtabs .tab-container {
32
  display: flex;
33
  text-align: center;
34
+ width: 100%;
35
  }
36
 
37
  #group-subtabs .tab-container button {
38
+ flex: 1;
39
  }
40
 
41
+ .tab-nav {
42
+ border: none !important;
43
+ }
44
 
45
+ .tab-nav > button.selected {
46
+ color: #4b8ec3;
 
47
  font-weight: bold;
48
+ border: none;
49
+ }
50
 
51
+ .tabitem {
52
+ border: none !important;
53
  }
54
 
55
+ .other-tabs > div {
56
+ padding: 40px 40px 10px;
 
 
 
57
  }
58
 
59
+ /* Card Styles */
60
+ .card {
61
+ background-color: white;
62
+ border-radius: 10px;
63
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
64
+ overflow: hidden;
65
+ display: flex;
66
+ flex-direction: column;
67
+ margin: 20px;
68
+ }
69
 
70
+ .card-content {
71
+ padding: 20px;
72
+ }
73
 
74
+ .card-content h2 {
75
+ font-size: 14px !important;
 
76
  font-weight: bold;
77
+ margin: 0 0 10px !important;
78
+ color: #dc2626 !important;
79
+ }
80
+
81
+ .card-content p {
82
+ font-size: 12px;
83
+ margin-bottom: 0;
84
+ }
85
+
86
+ .card-content img {
87
+ display: block;
88
+ margin: auto;
89
+ max-width: 100%;
90
+ height: auto;
91
+ }
92
+
93
+ .card-footer {
94
+ background-color: #f4f4f4;
95
+ font-size: 10px;
96
+ padding: 10px;
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: center;
100
+ }
101
+
102
+ .card-footer span {
103
+ flex-grow: 1;
104
  text-align: left;
105
+ color: #999 !important;
106
  }
107
 
108
+ .card-image > .card-content {
109
+ background-color: #f1f7fa;
110
+ }
111
 
112
+ /* Message & Chat Styles */
113
+ .message {
114
+ font-size: 14px !important;
115
  }
116
 
117
+ .message.user, .message.bot {
118
+ border: none;
 
119
  }
120
 
121
+ #input-textbox > label > textarea {
122
+ border-radius: 40px;
123
+ padding-left: 30px;
124
+ resize: none;
 
 
 
 
 
125
  }
126
 
127
+ #input-message > div {
128
+ border: none;
 
 
 
 
 
129
  }
130
 
131
+ /* Alert Boxes */
132
  .warning-box {
133
  background-color: #fff3cd;
134
  border: 1px solid #ffeeba;
 
138
  color: #856404;
139
  display: inline-block;
140
  margin-bottom: 15px;
141
+ }
 
142
 
143
  .tip-box {
144
  background-color: #f0f9ff;
145
  border: 1px solid #80d4fa;
146
  border-radius: 4px;
147
+ margin: 20px 0 15px;
148
  padding: 15px 20px;
149
  font-size: 14px;
150
  display: inline-block;
 
151
  width: auto;
152
+ color: black !important;
 
 
 
 
153
  }
154
 
 
 
 
 
 
 
155
  .tip-box-title {
156
  font-weight: bold;
157
  font-size: 14px;
 
163
  margin-right: 5px;
164
  }
165
 
166
+ /* Loader Animation */
167
+ .loader {
168
+ border: 1px solid #d0d0d0 !important;
169
+ border-top: 1px solid #db3434 !important;
170
+ border-right: 1px solid #3498db !important;
171
+ border-radius: 50%;
172
+ width: 20px;
173
+ height: 20px;
174
+ animation: spin 2s linear infinite;
175
+ display: inline-block;
176
+ margin-right: 10px !important;
177
  }
178
 
179
+ @keyframes spin {
180
+ 0% { transform: rotate(0deg); }
181
+ 100% { transform: rotate(360deg); }
 
 
 
 
 
 
182
  }
183
 
184
+ /* PDF Link Styles */
185
+ .pdf-link {
186
+ display: inline-flex;
187
+ align-items: center;
188
+ margin-left: auto;
189
+ text-decoration: none!important;
190
+ font-size: 14px;
191
  }
192
 
193
+ /* Document Reference Styles */
194
+ .doc-ref sup {
195
+ color: #dc2626!important;
196
  }
197
 
198
+ .doc-ref {
199
+ color: #dc2626!important;
200
+ margin-right: 1px;
201
+ }
202
 
203
+ /* Chatbot & Image Styles */
204
+ span.chatbot > p > img {
205
+ margin-top: 40px !important;
206
+ max-height: none !important;
207
+ max-width: 80% !important;
208
+ border-radius: 0px !important;
 
 
209
  }
210
 
211
+ .chatbot-caption {
212
+ font-size: 11px;
213
+ font-style: italic;
214
+ color: #508094;
215
  }
216
 
217
+ .ai-generated {
218
+ font-size: 11px!important;
219
+ font-style: italic;
220
+ color: #73b8d4 !important;
 
 
221
  }
222
 
223
+ /* Dropdown Styles */
224
+ .dropdown {
225
+ position: relative;
226
+ display: inline-block;
227
+ margin-bottom: 10px;
228
  }
229
 
230
+ .dropdown-toggle {
231
+ background-color: #f2f2f2;
232
+ color: black;
233
  padding: 10px;
234
+ font-size: 16px;
235
+ cursor: pointer;
236
  display: flex;
237
+ width: 400px;
238
  align-items: center;
239
+ justify-content: left;
240
+ position: relative;
241
  }
242
 
243
+ .dropdown-toggle .caret {
244
+ content: "";
245
+ position: absolute;
246
+ right: 10px;
247
+ top: 50%;
248
+ border-left: 5px solid transparent;
249
+ border-right: 5px solid transparent;
250
+ border-top: 5px solid black;
251
+ transform: translateY(-50%);
252
  }
253
 
254
+ .dropdown-content {
255
+ display: none;
256
+ position: absolute;
257
+ background-color: #f9f9f9;
258
+ min-width: 300px;
259
+ box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
260
+ z-index: 1;
261
+ padding: 12px;
262
+ border: 1px solid #ccc;
263
  }
264
 
265
+ /* Checkbox Styles */
266
+ input[type="checkbox"] {
267
+ display: none !important;
 
 
 
268
  }
269
 
270
+ #checkbox-chat input[type="checkbox"] {
271
+ display: flex !important;
 
272
  }
273
 
274
+ input[type="checkbox"]:checked + .dropdown-content {
275
+ display: block;
 
276
  }
277
 
278
+ input[type="checkbox"]:checked + .dropdown-toggle + .dropdown-content {
279
+ display: block;
280
  }
281
 
282
+ input[type="checkbox"]:checked + .dropdown-toggle .caret {
283
+ border-top: 0;
284
+ border-bottom: 5px solid black;
 
 
 
 
 
285
  }
286
+
287
+ /* Modal Styles */
288
  #modal-config {
289
  position: fixed;
290
  top: 0;
 
297
  padding: 15px;
298
  transform: none;
299
  }
300
+
301
+ #modal-config .block.modal-block.padded {
302
+ padding-top: 25px;
303
+ height: 100vh;
304
  }
305
 
306
+ #modal-config .modal-container {
307
+ margin: 0px;
308
+ padding: 0px;
309
+ }
 
310
 
311
+ #modal-config .close {
312
+ display: none;
 
 
 
 
 
 
 
 
313
  }
314
+
315
+ /* Config Button Styles */
316
+ #config-button {
317
  background: none;
318
  border: none;
319
  padding: 8px;
 
336
  background-color: rgba(0, 0, 0, 0.1);
337
  }
338
 
339
+ /* Relevancy Score Styles */
340
+ .relevancy-score {
341
+ margin-top: 10px !important;
342
+ font-size: 10px !important;
343
+ font-style: italic;
344
+ }
345
+
346
+ .score-green {
347
+ color: green !important;
348
+ }
349
+
350
+ .score-orange {
351
+ color: orange !important;
352
+ }
353
+
354
+ .score-red {
355
+ color: red !important;
356
+ }
357
+
358
+ /* Gallery Styles */
359
+ .gallery-item > div {
360
+ white-space: normal !important;
361
+ word-break: break-word !important;
362
+ overflow-wrap: break-word !important;
363
+ }
364
+
365
+ /* Avatar Styles */
366
+ .avatar-container.svelte-1x5p6hu:not(.thumbnail-item) img {
367
+ width: 100%;
368
+ height: 100%;
369
+ object-fit: cover;
370
+ border-radius: 50%;
371
+ padding: 0px;
372
+ margin: 0px;
373
+ }
374
+
375
+ /* Message Button Styles */
376
+ .message-buttons-left.panel.message-buttons.with-avatar {
377
+ display: none;
378
+ }
379
+
380
+ /* Checkmark Styles */
381
+ .checkmark {
382
+ color: green !important;
383
+ font-size: 18px;
384
+ margin-right: 10px !important;
385
+ }
386
+
387
+ /* Papers Summary & Relevant Popup Styles */
388
+ #papers-summary-popup button span,
389
+ #papers-relevant-popup span {
390
+ font-size: 16px;
391
+ font-weight: bold;
392
+ text-align: center;
393
+ }
394
+
395
+ /* Citations Tab Button Style */
396
+ #tab-citations .button {
397
+ padding: 12px 16px;
398
+ font-size: 16px;
399
+ font-weight: bold;
400
+ cursor: pointer;
401
  border: none;
402
+ outline: none;
403
+ text-align: left;
404
+ transition: background-color 0.3s ease;
405
+ }
406
+
407
+ /* Show Figures Button Style */
408
+ button#show-figures {
409
+ background-color: #f5f5f5;
410
+ border: 1px solid #e0e0e0;
411
+ border-radius: 4px;
412
+ color: #333333;
413
  cursor: pointer;
414
+ width: 100%;
 
 
 
 
 
 
 
415
  text-align: center;
416
  }
417
+
418
+ /* Gradio Box Style */
419
+ .gr-box {
420
+ border-color: #d6c37c;
421
  }
422
 
423
+ /* Hidden Message Style */
424
+ #hidden-message {
425
+ display: none;
426
+ }
427
 
428
+ /* Label Selected Style */
429
+ label.selected {
430
+ background: #93c5fd !important;
431
+ }
432
 
433
+ /* Submit Button Style */
434
+ #submit-button {
435
+ padding: 0px !important;
436
+ }
 
 
437
 
438
+ /* Hugging Face Space Fixes */
439
+ .h-full {
440
+ height: auto !important;
441
+ min-height: 0 !important;
442
+ }
 
 
443
 
444
+ .space-content {
445
+ height: auto !important;
446
+ max-height: 100vh !important;
447
+ overflow: hidden;
448
+ }
449
 
450
+ /* Dropdown Samples Style */
451
+ #dropdown-samples {
452
+ background: none !important;
453
+ }
454
 
455
+ #dropdown-samples > .container > .wrap {
456
+ background-color: white;
457
+ }
 
 
 
458
 
459
+ /* Tab Examples Form Style */
460
+ #tab-examples > div > .form {
461
+ border: none;
462
+ background: none !important;
463
+ }
 
 
 
 
464
 
465
+ /* Utility Classes */
466
+ .hidden {
467
+ display: none !important;
468
+ }
 
469
 
470
+ footer {
471
+ display: none !important;
472
+ visibility: hidden;
473
+ }
474
+
475
+ a {
476
+ text-decoration: none;
477
+ color: inherit;
478
+ }
479
+
480
+ .a-doc-ref {
481
+ text-decoration: none !important;
482
+ }
483
+
484
+ /* Media Queries */
485
+ /* Desktop Media Query */
486
+ @media screen and (min-width: 1024px) {
487
+ .gradio-container {
488
+ max-height: calc(100vh - 190px) !important;
489
+ overflow: hidden;
490
  }
491
 
492
+ div#tab-examples,
493
+ div#sources-textbox,
494
+ div#tab-config {
495
+ height: calc(100vh - 190px) !important;
496
  overflow-y: scroll !important;
497
  }
498
 
499
+ div#sources-figures,
500
+ div#graphs-container,
501
+ div#tab-citations {
502
+ height: calc(100vh - 300px) !important;
503
+ max-height: 90vh !important;
504
  overflow-y: scroll !important;
 
505
  }
506
 
507
+ div#chatbot-row {
508
+ max-height: calc(100vh - 90px) !important;
 
 
509
  }
510
 
511
+ div#graphs-container {
512
+ height: calc(100vh - 210px) !important;
513
+ overflow-y: scroll !important;
514
  }
 
515
 
516
+ div#tab-saved-graphs {
 
 
 
517
  overflow-y: auto;
518
+ max-height: 80vh;
519
  }
 
 
520
  }
521
 
522
+ /* Mobile Media Query */
 
 
 
 
 
523
  @media screen and (max-width: 767px) {
524
+ div#chatbot {
525
+ height: 500px !important;
 
 
526
  }
527
 
528
+ #submit-button {
529
+ padding: 0 !important;
530
  min-width: 80px;
531
  }
532
 
 
533
  div.tab-nav button {
534
  display: none !important;
535
  }
536
 
537
+ div.tab-nav button:first-child,
 
 
 
 
 
538
  div.tab-nav button:nth-child(2) {
539
  display: block !important;
540
  }
541
+
542
+ #right-panel button {
543
  display: block !important;
544
  }
545
 
546
+ div#tab-recommended_content {
547
+ max-height: 50vh;
548
+ overflow-y: auto;
549
+ }
550
+
551
+ div#tab-saved-graphs {
552
+ max-height: 50vh;
553
+ overflow-y: auto;
554
+ }
555
  }
556
 
557
+ /* Dark Mode */
558
  @media (prefers-color-scheme: dark) {
559
+ .card {
560
  background-color: #374151;
561
  }
562
+
563
+ .card-image > .card-content {
564
  background-color: rgb(55, 65, 81) !important;
565
  }
566
 
 
568
  background-color: #404652;
569
  }
570
 
571
+ .container > .wrap {
572
  background-color: #374151 !important;
573
+ color: white !important;
574
  }
575
+
576
+ .card-content h2 {
577
+ color: #e7754f !important;
 
 
 
578
  }
579
+
580
  .card-footer span {
581
+ color: white !important;
582
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
 
584
+ body.dark .warning-box *,
585
+ body.dark .tip-box * {
586
+ color: black !important;
587
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
 
589
+ .doc-ref sup {
590
+ color: rgb(235 109 35)!important;
591
+ }
592
  }
593
 
594
+ /* Checkbox Config Style */
595
+ #checkbox-config {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596
  display: block;
 
 
 
 
 
 
 
 
597
  position: absolute;
598
+ background: none;
599
+ border: none;
600
+ padding: 8px;
601
+ cursor: pointer;
602
+ width: 40px;
603
+ height: 40px;
604
+ display: flex;
605
+ align-items: center;
606
+ justify-content: center;
 
 
 
 
 
 
 
 
 
 
 
 
607
  border-radius: 50%;
608
+ transition: background-color 0.2s;
609
+ font-size: 20px;
610
+ text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
  }
612
 
613
+ #checkbox-config:checked {
614
+ display: block;
 
 
615
  }