|
|
import gradio as gr |
|
|
import time |
|
|
import pandas as pd |
|
|
import asyncio |
|
|
from uuid import uuid4 |
|
|
from gradio_client import Client, handle_file |
|
|
from utils.retriever import retrieve_paragraphs |
|
|
from utils.generator import generate |
|
|
from utils.logger import ChatLogger |
|
|
from huggingface_hub import CommitScheduler |
|
|
import json |
|
|
import ast |
|
|
import os |
|
|
from pathlib import Path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSON_DATASET_DIR = Path("json_dataset") |
|
|
|
|
|
|
|
|
if not JSON_DATASET_DIR.exists(): |
|
|
try: |
|
|
JSON_DATASET_DIR.mkdir(parents=True, exist_ok=True) |
|
|
print(f"Created dataset directory at {JSON_DATASET_DIR}") |
|
|
except Exception as e: |
|
|
print(f"Error creating dataset directory: {str(e)}") |
|
|
raise |
|
|
else: |
|
|
print(f"Using existing dataset directory at {JSON_DATASET_DIR}") |
|
|
|
|
|
|
|
|
SPACES_LOG = os.environ.get("GINA_SPACES_LOG") |
|
|
if not SPACES_LOG: |
|
|
print("Warning: GINA_SPACES_LOG not found in environment, using local storage only") |
|
|
|
|
|
|
|
|
scheduler = CommitScheduler( |
|
|
repo_id="GIZ/spaces_logs", |
|
|
repo_type="dataset", |
|
|
folder_path=JSON_DATASET_DIR, |
|
|
path_in_repo="gina_chatbot", |
|
|
token=SPACES_LOG if SPACES_LOG else None, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
chat_logger = ChatLogger(scheduler = scheduler ) |
|
|
|
|
|
|
|
|
SAMPLE_QUESTIONS = { |
|
|
"Fundamentos y tendencias internacionales de EC": [ |
|
|
"¿Cómo se diferencia el modelo de economía circular del modelo lineal tradicional de 'tomar, hacer, desechar'?", |
|
|
"¿Cuáles son algunos de los principios clave de la economía circular y cómo se aplican en la práctica?", |
|
|
"¿Podrías dar ejemplos de industrias o empresas que estén implementando con éxito prácticas de economía circular?" |
|
|
], |
|
|
"EC en Colombia": [ |
|
|
"¿Qué políticas y normativas vigentes en Colombia impulsan la adopción de la economía circular?", |
|
|
"¿Cómo pueden las regulaciones colombianas incentivar la innovación en el ecodiseño y la gestión de residuos?", |
|
|
"¿Qué papel tienen los instrumentos económicos y fiscales en la promoción de la circularidad en el sector productivo de Colombia?"] |
|
|
} |
|
|
|
|
|
|
|
|
geojson_analysis_cache = {} |
|
|
|
|
|
|
|
|
def start_chat(query, history): |
|
|
"""Start a new chat interaction""" |
|
|
history = history + [(query, None)] |
|
|
return gr.update(interactive=False), gr.update(selected=1), history |
|
|
|
|
|
def finish_chat(): |
|
|
"""Finish chat and reset input""" |
|
|
return gr.update(interactive=True, value="") |
|
|
|
|
|
def make_html_source(source,i): |
|
|
""" |
|
|
takes the text and converts it into html format for display in "source" side tab |
|
|
""" |
|
|
meta = source['answer_metadata'] |
|
|
content = source['answer'].strip() |
|
|
|
|
|
name = meta['filename'] |
|
|
card = f""" |
|
|
<div class="card" id="doc{i}"> |
|
|
<div class="card-content"> |
|
|
<h2>Doc {i} - {meta['filename']} - Page {int(meta['page'])}</h2> |
|
|
<p>{content}</p> |
|
|
</div> |
|
|
<div class="card-footer"> |
|
|
<span>{name}</span> |
|
|
<a href="{meta['filename']}#page={int(meta['page'])}" target="_blank" class="pdf-link"> |
|
|
<span role="img" aria-label="Open PDF">🔗</span> |
|
|
</a> |
|
|
</div> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
return card |
|
|
|
|
|
BEGINNING_TEXT = "**Respuesta generada mediante inteligencia artificíal:** \n\n" |
|
|
async def chat_response(query, history, category, request=None): |
|
|
"""Generate chat response based on method and inputs""" |
|
|
|
|
|
try: |
|
|
retrieved_paragraphs = retrieve_paragraphs(query, category) |
|
|
context_retrieved = ast.literal_eval(retrieved_paragraphs) |
|
|
|
|
|
|
|
|
context_retrieved_formatted = "||".join(doc['answer'] for doc in context_retrieved) |
|
|
context_retrieved_lst = [doc['answer'] for doc in context_retrieved] |
|
|
|
|
|
|
|
|
docs_html = [] |
|
|
for i, d in enumerate(context_retrieved, 1): |
|
|
docs_html.append(make_html_source(d, i)) |
|
|
docs_html = "".join(docs_html) |
|
|
|
|
|
|
|
|
response = await generate(query=query, context=context_retrieved_lst) |
|
|
|
|
|
|
|
|
response_with_disclaimer = BEGINNING_TEXT + response |
|
|
|
|
|
try: |
|
|
chat_logger.log( |
|
|
query=query, |
|
|
answer=response, |
|
|
retrieved_content=context_retrieved_lst, |
|
|
request=request |
|
|
) |
|
|
except Exception as e: |
|
|
print(f"Logging error: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
displayed_response = "" |
|
|
for i, char in enumerate(response_with_disclaimer): |
|
|
displayed_response += char |
|
|
history[-1] = (query, displayed_response) |
|
|
yield history, docs_html |
|
|
|
|
|
if i % 3 == 0: |
|
|
await asyncio.sleep(0.02) |
|
|
|
|
|
except Exception as e: |
|
|
error_message = f"Error processing request: {str(e)}" |
|
|
history[-1] = (query, error_message) |
|
|
yield history, "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def toggle_search_method(method): |
|
|
"""Toggle between GeoJSON upload and country selection""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
gr.update(visible=True), |
|
|
gr.update(), |
|
|
) |
|
|
|
|
|
def change_sample_questions(key): |
|
|
"""Update visible examples based on selected category""" |
|
|
keys = list(SAMPLE_QUESTIONS.keys()) |
|
|
index = keys.index(key) |
|
|
visible_bools = [False] * len(keys) |
|
|
visible_bools[index] = True |
|
|
return [gr.update(visible=visible_bools[i]) for i in range(len(keys))] |
|
|
|
|
|
|
|
|
theme = gr.themes.Base( |
|
|
primary_hue="green", |
|
|
secondary_hue="blue", |
|
|
font=[gr.themes.GoogleFont("Poppins"), "ui-sans-serif", "system-ui", "sans-serif"], |
|
|
text_size=gr.themes.utils.sizes.text_sm, |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
init_prompt = """ |
|
|
Hola, soy Gina, una asistente conversacional con IA diseñada para ayudarte a comprender conceptos y ayudarte con el tema de la Economía Circular. Responderé a tus preguntas usando la base de datos de documentos sobre economía circular. |
|
|
💡 **Cómo usarla (pestañas a la derecha)** |
|
|
|
|
|
**Enfoque:** Selecciona la sección de informes/documentos. |
|
|
**Ejemplos:** Selecciona entre ejemplos de preguntas de diferentes categorías. |
|
|
**Fuentes:** Consulta las fuentes de contenido utilizadas para generar las respuestas para la verificación de datos. |
|
|
⚠️ Para conocer las limitaciones e información sobre la recopilación de datos, consulta la pestaña "Aviso legal" |
|
|
""" |
|
|
|
|
|
with gr.Blocks(title="Gina Bot", theme=theme, css="style.css") as demo: |
|
|
|
|
|
|
|
|
with gr.Tab("Gina Bot"): |
|
|
with gr.Row(): |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
chatbot = gr.Chatbot( |
|
|
value=[(None, init_prompt)], |
|
|
show_copy_button=True, |
|
|
show_label=False, |
|
|
layout="panel", |
|
|
avatar_images=(None, "chatbot_icon_2.png"), |
|
|
height="auto" |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Column(): |
|
|
with gr.Row(visible=False) as feedback_row: |
|
|
gr.Markdown("¿Te ha sido útil esta respuesta?") |
|
|
with gr.Row(): |
|
|
okay_btn = gr.Button("👍 De acuerdo", size="sm") |
|
|
not_okay_btn = gr.Button("👎 No según lo esperado", size="sm") |
|
|
feedback_thanks = gr.Markdown("Gracias por los comentarios.", visible=False) |
|
|
|
|
|
|
|
|
with gr.Row(): |
|
|
textbox = gr.Textbox( |
|
|
placeholder="Pregúntame cualquier cosa sobre Economía Circular", |
|
|
show_label=False, |
|
|
scale=7, |
|
|
lines=1, |
|
|
interactive=True |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Column(scale=1, variant="panel"): |
|
|
with gr.Tabs() as tabs: |
|
|
|
|
|
|
|
|
with gr.Tab("Fuentes de datos", id=2): |
|
|
with gr.Group(visible=True) as reports_section: |
|
|
dropdown_category = gr.Dropdown( |
|
|
["Fundamentos y tendencias internacionales de EC", "Financiamiento en EC", "EC en Colombia"], |
|
|
|
|
|
label="Especifica tu área de interés", |
|
|
multiselect =True, |
|
|
value=["Fundamentos y tendencias internacionales de EC", "Financiamiento en EC", "EC en Colombia"], |
|
|
interactive=True, |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Tab("Ejemplos", id=0): |
|
|
examples_hidden = gr.Textbox(visible=False) |
|
|
|
|
|
first_key = list(SAMPLE_QUESTIONS.keys())[0] |
|
|
dropdown_samples = gr.Dropdown( |
|
|
SAMPLE_QUESTIONS.keys(), |
|
|
value=first_key, |
|
|
interactive=True, |
|
|
show_label=True, |
|
|
label="Seleccione una categoría de preguntas de muestra." |
|
|
) |
|
|
|
|
|
|
|
|
sample_groups = [] |
|
|
for i, (key, questions) in enumerate(SAMPLE_QUESTIONS.items()): |
|
|
examples_visible = True if i == 0 else False |
|
|
with gr.Row(visible=examples_visible) as group_examples: |
|
|
gr.Examples( |
|
|
questions, |
|
|
[examples_hidden], |
|
|
examples_per_page=8, |
|
|
run_on_click=False, |
|
|
) |
|
|
sample_groups.append(group_examples) |
|
|
|
|
|
|
|
|
with gr.Tab("Fuentes", id=1, elem_id="sources-textbox"): |
|
|
sources_textbox = gr.HTML( |
|
|
show_label=False, |
|
|
value="Los documentos originales aparecerán aquí después de que hagas una pregunta..." |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Tab("Orientacion"): |
|
|
gr.Markdown(""" |
|
|
#### Welcome to Gina Q&A! |
|
|
|
|
|
This AI-powered assistant helps you understand Circular Economy. |
|
|
|
|
|
## 💬 How to Ask Effective Questions |
|
|
|
|
|
| ❌ Less Effective | ✅ More Effective | |
|
|
|------------------|-------------------| |
|
|
| "What is economy?" | "What are impact of circular economy on businesses?" | |
|
|
| "Tell me about compliance" | "What are country guidelines on circular economy" | |
|
|
| "Show me data" | "What is the trend on waste and how circular economy is helping in resolving this?" | |
|
|
|
|
|
## 🔍 Using Data Sources |
|
|
|
|
|
**Talk to Reports:** Select reports sections "Trend and fundamentals", "Financing Mechanisms", "Country Resource" |
|
|
|
|
|
## ⭐ Best Practices |
|
|
|
|
|
- Be specific about regions, commodities, or time periods |
|
|
- Ask one question at a time for clearer answers |
|
|
- Use follow-up questions to explore topics deeper |
|
|
- Provide context when possible |
|
|
""") |
|
|
|
|
|
|
|
|
with gr.Tab("sobre Gina"): |
|
|
gr.Markdown(""" |
|
|
## About Gina Q&A |
|
|
|
|
|
The **Circular Economy** places some obligations on the manufacturers and business. |
|
|
|
|
|
This AI-powered tool helps stakeholders: |
|
|
- Understand circular Economy concepts and regulations |
|
|
- Assess supply chain issues |
|
|
- Navigate complex regulatory landscapes |
|
|
|
|
|
**Developed by GIZ** for project in Colombia to enhance accessibility and understanding of circular Economy requirements |
|
|
through advanced AI and geographic data processing capabilities. |
|
|
|
|
|
### Key Features: |
|
|
- Country-specific compliance guidance |
|
|
- Real-time question answering with source citations |
|
|
- User-friendly interface for complex regulatory information |
|
|
""") |
|
|
|
|
|
|
|
|
with gr.Tab("Disclaimer"): |
|
|
gr.Markdown(""" |
|
|
## Important Disclaimers |
|
|
|
|
|
⚠️ **Scope & Limitations:** |
|
|
- This tool is designed for Circular Economy assistance and geographic data analysis |
|
|
- Responses should not be considered official legal or compliance advice |
|
|
- Always consult qualified professionals for official compliance decisions |
|
|
|
|
|
⚠️ **Data & Privacy:** |
|
|
- We collect usage statistics to improve the tool. |
|
|
- No personal data is collected when using this tool. |
|
|
|
|
|
⚠️ **AI Limitations:** |
|
|
- Responses are AI-generated and may contain inaccuracies |
|
|
- The tool is a prototype under continuous development |
|
|
- Always verify important information with authoritative sources |
|
|
|
|
|
**Data Collection:** We collect questions, answers, feedback, and anonymized usage statistics |
|
|
to improve tool performance based on legitimate interest in service enhancement. |
|
|
|
|
|
By using this chatbot, you agree to these terms and acknowledge that you are solely responsible for any reliance on or actions taken based on its responses. |
|
|
|
|
|
**Technical Information**: User can read more about the technical information about the tool in [Readme](https://huggingface.co/spaces/GIZ/gina/blob/main/README.md) of this tool. |
|
|
|
|
|
This is just a prototype and being tested and worked upon, so its 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. |
|
|
|
|
|
""") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
textbox.submit( |
|
|
start_chat, |
|
|
[textbox, chatbot], |
|
|
[textbox, tabs, chatbot], |
|
|
queue=False |
|
|
).then( |
|
|
chat_response, |
|
|
[textbox, chatbot, dropdown_category], |
|
|
[chatbot, sources_textbox] |
|
|
).then( |
|
|
lambda: gr.update(visible=True), |
|
|
outputs=[feedback_row] |
|
|
).then( |
|
|
finish_chat, |
|
|
outputs=[textbox] |
|
|
) |
|
|
|
|
|
|
|
|
examples_hidden.change( |
|
|
start_chat, |
|
|
[examples_hidden, chatbot], |
|
|
[textbox, tabs, chatbot], |
|
|
queue=False |
|
|
).then( |
|
|
chat_response, |
|
|
[examples_hidden, chatbot, dropdown_category], |
|
|
[chatbot, sources_textbox] |
|
|
).then( |
|
|
lambda: gr.update(visible=True), |
|
|
outputs=[feedback_row] |
|
|
).then( |
|
|
finish_chat, |
|
|
outputs=[textbox] |
|
|
) |
|
|
|
|
|
|
|
|
dropdown_samples.change( |
|
|
change_sample_questions, |
|
|
[dropdown_samples], |
|
|
sample_groups |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_feedback(feedback): |
|
|
try: |
|
|
|
|
|
if chatbot.value: |
|
|
last_query = chatbot.value[-1][0] |
|
|
last_response = chatbot.value[-1][1] |
|
|
|
|
|
|
|
|
chat_logger.log( |
|
|
query=last_query, |
|
|
answer=last_response, |
|
|
retrieved_content=[], |
|
|
feedback=feedback |
|
|
) |
|
|
except Exception as e: |
|
|
print(f"Feedback logging error: {str(e)}") |
|
|
return gr.update(visible=False), gr.update(visible=True) |
|
|
|
|
|
okay_btn.click( |
|
|
lambda: handle_feedback("positive"), |
|
|
outputs=[feedback_row, feedback_thanks] |
|
|
) |
|
|
|
|
|
not_okay_btn.click( |
|
|
lambda: handle_feedback("negative"), |
|
|
outputs=[feedback_row, feedback_thanks] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |
|
|
|