|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
import io |
|
|
import gc |
|
|
import time |
|
|
import warnings |
|
|
import pandas as pd |
|
|
import gradio as gr |
|
|
from typing import Dict |
|
|
from contextlib import redirect_stdout, redirect_stderr |
|
|
|
|
|
|
|
|
from crewai import Agent, Task, Crew |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") |
|
|
if not OPENAI_API_KEY: |
|
|
raise ValueError("OPENAI_API_KEY environment variable is required") |
|
|
|
|
|
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY |
|
|
os.environ["USER_AGENT"] = os.getenv("USER_AGENT", "ConsensusApp") |
|
|
os.environ['CREWAI_DO_NOT_TELEMETRY'] = 'true' |
|
|
os.environ['CREWAI_SHARE_CREW'] = 'false' |
|
|
|
|
|
|
|
|
warnings.filterwarnings("ignore", category=UserWarning, module="crewai") |
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PARTY_TO_ORIENTATION = { |
|
|
"FDP": "RIGHT", "jf": "RIGHT", "CVP": "CENTER", "Grüne": "LEFT", "SVP": "RIGHT", |
|
|
"PdA": "LEFT", "SP": "LEFT", "glp": "CENTER", "JUSO": "LEFT", "BDP": "CENTER", |
|
|
"JG": "RIGHT", "JSVP": "RIGHT", "EDU": "RIGHT", "Piraten": "CENTER", |
|
|
"jglp": "CENTER", "EVP": "CENTER", "JCVP": "CENTER", "jevp": "CENTER", |
|
|
"JBDP": "CENTER", "Die": "CENTER", "JFS": "RIGHT", "SD": "RIGHT", "JM": "CENTER" |
|
|
} |
|
|
|
|
|
|
|
|
LLM_BASE = "gpt-4o-mini" |
|
|
LLM_SUPERVISOR = "gpt-4o-mini" |
|
|
LLM_DIRECTOR = "gpt-4o-mini" |
|
|
|
|
|
def get_majority_decision_groups(df: pd.DataFrame) -> Dict: |
|
|
""" |
|
|
Calcula decisiones por mayoría y porcentajes (FAVOR/AGAINST) por: |
|
|
- language |
|
|
- party_reply |
|
|
- orientación (derivada de party_reply via PARTY_TO_ORIENTATION) |
|
|
- FINAL_MAJORITY global |
|
|
""" |
|
|
result = {} |
|
|
|
|
|
def calc_decision_and_percentages(series): |
|
|
total = len(series) |
|
|
favor_count = (series == 'FAVOR').sum() |
|
|
against_count = (series == 'AGAINST').sum() |
|
|
if favor_count > against_count: |
|
|
decision = 'FAVOR' |
|
|
elif against_count > favor_count: |
|
|
decision = 'AGAINST' |
|
|
else: |
|
|
decision = 'AMBIGUOUS' |
|
|
favor_pct = round((favor_count / total) * 100, 2) if total else 0.0 |
|
|
against_pct = round((against_count / total) * 100, 2) if total else 0.0 |
|
|
return {"decision": decision, "percent_favor": favor_pct, "percent_against": against_pct} |
|
|
|
|
|
|
|
|
for lang, group in df.groupby('language')['label']: |
|
|
result[lang] = calc_decision_and_percentages(group) |
|
|
|
|
|
|
|
|
for party, group in df.groupby('party_reply')['label']: |
|
|
result[party] = calc_decision_and_percentages(group) |
|
|
|
|
|
|
|
|
df_or = df.copy() |
|
|
df_or['orientation'] = df_or['party_reply'].map(PARTY_TO_ORIENTATION) |
|
|
df_or = df_or.dropna(subset=['orientation']) |
|
|
if not df_or.empty: |
|
|
for orient, group in df_or.groupby('orientation')['label']: |
|
|
result[f"{orient}_MAJORITY"] = calc_decision_and_percentages(group) |
|
|
|
|
|
|
|
|
result['FINAL_MAJORITY'] = calc_decision_and_percentages(df['label']) |
|
|
return result |
|
|
|
|
|
|
|
|
def _silent_kickoff(crew: Crew): |
|
|
buf_out, buf_err = io.StringIO(), io.StringIO() |
|
|
with redirect_stdout(buf_out), redirect_stderr(buf_err): |
|
|
return crew.kickoff() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DemocraticConsensusCrewAI: |
|
|
def __init__(self, question: str = ""): |
|
|
self.question = question |
|
|
self.results = {"base_agents": {}, "supervisors": {}, "director": ""} |
|
|
|
|
|
|
|
|
self.base_agent = Agent( |
|
|
role="Democratic Base Representative", |
|
|
goal="Generate democratic consensus for any given group of opinions, weighting all perspectives equally.", |
|
|
backstory=("You are a neutral representative. Given any group's opinions and a majority decision, " |
|
|
"you craft a fair, balanced consensus that aligns with that majority, acknowledging minorities as nuances."), |
|
|
verbose=False, |
|
|
allow_delegation=False, |
|
|
llm=LLM_BASE |
|
|
) |
|
|
self.supervisor_agent = Agent( |
|
|
role="Democratic Supervisor", |
|
|
goal="Refine and consolidate consensuses for a language or an orientation umbrella.", |
|
|
backstory=("You refine base consensuses for a given umbrella (language or orientation), " |
|
|
"keeping the specified majority as the core, integrating minority views as exceptions."), |
|
|
verbose=False, |
|
|
allow_delegation=False, |
|
|
llm=LLM_SUPERVISOR |
|
|
) |
|
|
self.director_agent = Agent( |
|
|
role="Digital President - Final Decision Maker", |
|
|
goal="Synthesize all supervisor consensuses into a final consensus that aligns with the absolute majority.", |
|
|
backstory=("You aggregate all umbrellas and issue a final democratic position respecting the global majority."), |
|
|
verbose=False, |
|
|
allow_delegation=False, |
|
|
llm=LLM_DIRECTOR |
|
|
) |
|
|
|
|
|
|
|
|
def create_base_tasks(self, large_strings_by_language: Dict, large_strings_by_party: Dict, majorities_decision: Dict): |
|
|
tasks = [] |
|
|
|
|
|
for language, opinions_text in large_strings_by_language.items(): |
|
|
maj = majorities_decision.get(language, {}).get('decision', 'AMBIGUOUS') |
|
|
t = Task( |
|
|
description=f""" |
|
|
MANDATORY INSTRUCTION: The consensus you generate MUST be based around the MAJORITY DECISION: {maj} |
|
|
|
|
|
Analyze the following {language} language opinions to answer the question: '{self.question}' |
|
|
|
|
|
{opinions_text} |
|
|
|
|
|
CRITICAL REQUIREMENTS: |
|
|
1. Align with the majority decision: {maj} |
|
|
2. Treat it as non-negotiable core. |
|
|
3. Include minority views as implementation nuances. |
|
|
4. Keep the final stance supporting {maj}. |
|
|
|
|
|
Return only the final consensus text that supports {maj}. |
|
|
""".strip(), |
|
|
agent=self.base_agent, |
|
|
expected_output=f"[BASE][LANG={language}][MAJ={maj}]" |
|
|
) |
|
|
tasks.append(t) |
|
|
|
|
|
|
|
|
for party, opinions_text in large_strings_by_party.items(): |
|
|
maj = majorities_decision.get(party, {}).get('decision', 'AMBIGUOUS') |
|
|
t = Task( |
|
|
description=f""" |
|
|
MANDATORY INSTRUCTION: The consensus you generate MUST be based around the MAJORITY DECISION: {maj} |
|
|
|
|
|
Analyze the following {party} party opinions to answer the question: '{self.question}' |
|
|
|
|
|
{opinions_text} |
|
|
|
|
|
CRITICAL REQUIREMENTS: |
|
|
1. Align with the majority decision: {maj} |
|
|
2. Treat it as non-negotiable core. |
|
|
3. Include minority views as implementation nuances. |
|
|
4. Keep the final stance supporting {maj}. |
|
|
|
|
|
Return only the final consensus text that supports {maj}. |
|
|
""".strip(), |
|
|
agent=self.base_agent, |
|
|
expected_output=f"[BASE][PARTY={party}][MAJ={maj}]" |
|
|
) |
|
|
tasks.append(t) |
|
|
return tasks |
|
|
|
|
|
def create_supervisor_tasks(self, base_results: Dict, majorities_decision: Dict): |
|
|
tasks = [] |
|
|
|
|
|
for lang in ["German", "French", "Italian"]: |
|
|
key = ('LANGUAGE', lang) |
|
|
if key in base_results: |
|
|
maj = majorities_decision.get(lang, {}).get('decision', 'AMBIGUOUS') |
|
|
t = Task( |
|
|
description=f""" |
|
|
MANDATORY INSTRUCTION: Your refined consensus MUST be based around the MAJORITY DECISION: {maj} |
|
|
|
|
|
Refine and consolidate the democratic consensus for {lang} language regarding: '{self.question}' |
|
|
|
|
|
{base_results[key]} |
|
|
|
|
|
CRITICAL REQUIREMENTS: |
|
|
1. Strengthen alignment with {maj}. |
|
|
2. Minority views only as exceptions or details. |
|
|
3. Return text in English (<= 150 tokens). |
|
|
|
|
|
Return only the refined consensus in English supporting {maj}. |
|
|
""".strip(), |
|
|
agent=self.supervisor_agent, |
|
|
expected_output=f"[SUPERVISOR][LANG={lang}][MAJ={maj}]" |
|
|
) |
|
|
tasks.append(t) |
|
|
|
|
|
|
|
|
orientation_consensuses = {"LEFT": [], "CENTER": [], "RIGHT": []} |
|
|
for (kind, name), consensus in base_results.items(): |
|
|
if kind == 'PARTY' and name in PARTY_TO_ORIENTATION: |
|
|
orientation_consensuses[PARTY_TO_ORIENTATION[name]].append(consensus) |
|
|
|
|
|
for orientation in ["LEFT", "CENTER", "RIGHT"]: |
|
|
if orientation_consensuses[orientation]: |
|
|
combined = "\n\n".join([f"Consensus {i+1}: {c}" for i, c in enumerate(orientation_consensuses[orientation], 1)]) |
|
|
maj = majorities_decision.get(f"{orientation}_MAJORITY", {}).get('decision', 'AMBIGUOUS') |
|
|
t = Task( |
|
|
description=f""" |
|
|
MANDATORY INSTRUCTION: Your unified consensus MUST be based around the MAJORITY DECISION: {maj} |
|
|
|
|
|
Create a unified democratic consensus for {orientation} orientation regarding: '{self.question}' |
|
|
|
|
|
{combined} |
|
|
|
|
|
CRITICAL REQUIREMENTS: |
|
|
1. Align around {maj}. |
|
|
2. Merge party consensuses with {maj} as core. |
|
|
3. Return text in English (<= 150 tokens). |
|
|
|
|
|
Return only the meta-consensus in English supporting {maj}. |
|
|
""".strip(), |
|
|
agent=self.supervisor_agent, |
|
|
expected_output=f"[SUPERVISOR][ORIENT={orientation}][MAJ={maj}]" |
|
|
) |
|
|
tasks.append(t) |
|
|
return tasks |
|
|
|
|
|
def create_director_task(self, supervisor_results: Dict, majorities_decision: Dict): |
|
|
all_consensuses = "\n\n".join([f"{k}: {v}" for k, v in supervisor_results.items()]) |
|
|
final_majority = majorities_decision.get('FINAL_MAJORITY', {}).get('decision', 'AMBIGUOUS') |
|
|
t = Task( |
|
|
description=f""" |
|
|
SUPREME MANDATORY INSTRUCTION: Your FINAL consensus MUST be based around the ABSOLUTE MAJORITY DECISION: {final_majority} |
|
|
|
|
|
As Digital President, synthesize the FINAL DEMOCRATIC CONSENSUS for the question: '{self.question}' |
|
|
|
|
|
Representative consensuses: |
|
|
{all_consensuses} |
|
|
|
|
|
CRITICAL REQUIREMENTS: |
|
|
1. Align strictly with {final_majority}. |
|
|
2. Integrate minorities only as nuances. |
|
|
3. <= 150 tokens. |
|
|
|
|
|
Return only the final consensus supporting {final_majority}. |
|
|
""".strip(), |
|
|
agent=self.director_agent, |
|
|
expected_output=f"[DIRECTOR][MAJ={final_majority}]" |
|
|
) |
|
|
return t |
|
|
|
|
|
def run_democratic_consensus_system(self, large_strings_by_language: Dict, large_strings_by_party: Dict, majorities_decision: Dict = {}) -> Dict: |
|
|
|
|
|
base_tasks = self.create_base_tasks(large_strings_by_language, large_strings_by_party, majorities_decision) |
|
|
base_results = {} |
|
|
if base_tasks: |
|
|
base_crew = Crew(agents=[self.base_agent], tasks=base_tasks, verbose=0, share_crew=False) |
|
|
base_out = _silent_kickoff(base_crew) |
|
|
for i, task in enumerate(base_tasks): |
|
|
raw = base_out.tasks_output[i].raw if i < len(base_out.tasks_output) else "" |
|
|
tag = task.expected_output |
|
|
if "[LANG=" in tag: |
|
|
lang = tag.split("[LANG=")[1].split("]")[0] |
|
|
base_results[('LANGUAGE', lang)] = raw |
|
|
elif "[PARTY=" in tag: |
|
|
party = tag.split("[PARTY=")[1].split("]")[0] |
|
|
base_results[('PARTY', party)] = raw |
|
|
self.results["base_agents"] = base_results |
|
|
|
|
|
|
|
|
supervisor_tasks = self.create_supervisor_tasks(base_results, majorities_decision) |
|
|
supervisor_results = {} |
|
|
if supervisor_tasks: |
|
|
sup_crew = Crew(agents=[self.supervisor_agent], tasks=supervisor_tasks, verbose=0, share_crew=False) |
|
|
sup_out = _silent_kickoff(sup_crew) |
|
|
for i, task in enumerate(supervisor_tasks): |
|
|
raw = sup_out.tasks_output[i].raw if i < len(sup_out.tasks_output) else "" |
|
|
tag = task.expected_output |
|
|
if "[LANG=" in tag: |
|
|
lang = tag.split("[LANG=")[1].split("]")[0] |
|
|
supervisor_results[('LANGUAGE', lang)] = raw |
|
|
elif "[ORIENT=" in tag: |
|
|
orient = tag.split("[ORIENT=")[1].split("]")[0] |
|
|
supervisor_results[('ORIENTATION', orient)] = raw |
|
|
self.results["supervisors"] = supervisor_results |
|
|
|
|
|
|
|
|
director_task = self.create_director_task(supervisor_results, majorities_decision) |
|
|
dir_crew = Crew(agents=[self.director_agent], tasks=[director_task], verbose=0, share_crew=False) |
|
|
dir_out = _silent_kickoff(dir_crew) |
|
|
final_consensus = dir_out.tasks_output[0].raw if dir_out.tasks_output else "No final consensus generated" |
|
|
self.results["director"] = final_consensus |
|
|
|
|
|
|
|
|
gc.collect() |
|
|
return self.results |
|
|
|
|
|
|
|
|
def run_democratic_consensus_system(large_strings_by_language: Dict, large_strings_by_party: Dict, question: str = "", majorities_decision: Dict = {}) -> Dict: |
|
|
system = DemocraticConsensusCrewAI(question=question) |
|
|
return system.run_democratic_consensus_system(large_strings_by_language, large_strings_by_party, majorities_decision) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_excel_and_generate_consensus(excel_file_path): |
|
|
""" |
|
|
Lee el Excel subido, calcula mayorías, corre el sistema de consenso y |
|
|
devuelve los textos + porcentajes para mostrarlos en la UI. |
|
|
Se espera que el Excel tenga: ['language', 'party_reply', 'label', 'comment']. |
|
|
""" |
|
|
if not excel_file_path: |
|
|
return ("Error: No file uploaded", "", "", "", "", "", "", "", "", |
|
|
"", "", "", "", "", "", "") |
|
|
|
|
|
try: |
|
|
df = pd.read_excel(excel_file_path) |
|
|
|
|
|
|
|
|
required = {'language', 'party_reply', 'label', 'comment'} |
|
|
missing = list(required - set(df.columns)) |
|
|
if missing: |
|
|
return (f"Error: Missing required columns: {missing}", "", "", "", "", "", "", "", "", |
|
|
"", "", "", "", "", "", "") |
|
|
|
|
|
|
|
|
if 'question_y' in df.columns and df['question_y'].dropna().size: |
|
|
question = str(df['question_y'].dropna().iloc[0]) |
|
|
elif 'question' in df.columns and df['question'].dropna().size: |
|
|
question = str(df['question'].dropna().iloc[0]) |
|
|
else: |
|
|
question = "Question not found in Excel" |
|
|
|
|
|
|
|
|
large_strings_by_language = ( |
|
|
df.groupby("language")["comment"] |
|
|
.apply(lambda g: "'; ".join([f"Opinion {i+1}: '{c}" for i, c in enumerate(g.dropna().astype(str))])) |
|
|
.to_dict() |
|
|
) |
|
|
large_strings_by_party = ( |
|
|
df.groupby("party_reply")["comment"] |
|
|
.apply(lambda g: "'; ".join([f"Opinion {i+1}: '{c}" for i, c in enumerate(g.dropna().astype(str))])) |
|
|
.to_dict() |
|
|
) |
|
|
|
|
|
|
|
|
majorities_decision = get_majority_decision_groups(df) |
|
|
|
|
|
|
|
|
results = run_democratic_consensus_system( |
|
|
large_strings_by_language, |
|
|
large_strings_by_party, |
|
|
question, |
|
|
majorities_decision |
|
|
) |
|
|
|
|
|
|
|
|
german = results['supervisors'].get(('LANGUAGE', 'German'), "No consensus data") |
|
|
french = results['supervisors'].get(('LANGUAGE', 'French'), "No consensus data") |
|
|
italian = results['supervisors'].get(('LANGUAGE', 'Italian'), "No consensus data") |
|
|
|
|
|
left = results['supervisors'].get(('ORIENTATION', 'LEFT'), "No consensus data") |
|
|
center = results['supervisors'].get(('ORIENTATION', 'CENTER'), "No consensus data") |
|
|
right = results['supervisors'].get(('ORIENTATION', 'RIGHT'), "No consensus data") |
|
|
|
|
|
final = results.get('director', "No consensus data") |
|
|
|
|
|
|
|
|
german_percentage = f"{majorities_decision.get('German', {}).get('percent_favor', 0):.1f}%" |
|
|
french_percentage = f"{majorities_decision.get('French', {}).get('percent_favor', 0):.1f}%" |
|
|
italian_percentage = f"{majorities_decision.get('Italian', {}).get('percent_favor', 0):.1f}%" |
|
|
left_percentage = f"{majorities_decision.get('LEFT_MAJORITY', {}).get('percent_favor', 0):.1f}%" |
|
|
center_percentage = f"{majorities_decision.get('CENTER_MAJORITY', {}).get('percent_favor', 0):.1f}%" |
|
|
right_percentage = f"{majorities_decision.get('RIGHT_MAJORITY', {}).get('percent_favor', 0):.1f}%" |
|
|
final_percentage = f"{majorities_decision.get('FINAL_MAJORITY', {}).get('percent_favor', 0):.1f}%" |
|
|
|
|
|
status = f"Success: Consensus statements generated from {os.path.basename(excel_file_path)}" |
|
|
|
|
|
return (status, question, german, french, italian, left, center, right, final, |
|
|
german_percentage, french_percentage, italian_percentage, |
|
|
left_percentage, center_percentage, right_percentage, final_percentage) |
|
|
|
|
|
except Exception as e: |
|
|
return (f"Error processing file: {e}", "", "", "", "", "", "", "", "", |
|
|
"", "", "", "", "", "", "") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_consensus_app(): |
|
|
with gr.Blocks( |
|
|
title="🏛️ Consensus Statements", |
|
|
theme=gr.themes.Base(), |
|
|
css=""" |
|
|
/* Estilos de banderas */ |
|
|
.flag-container { display: flex; justify-content: center; align-items: center; gap: 15px; margin-bottom: 10px; } |
|
|
.flag-image { width: 50px; height: auto; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } |
|
|
|
|
|
/* Estilos de las cajas de consenso */ |
|
|
.consensus-box { padding: 15px; border-radius: 15px; margin: 10px; min-height: 300px; max-height: 500px; |
|
|
overflow-y: auto; word-wrap: break-word; display: flex; align-items: flex-start; justify-content: center; |
|
|
text-align: center; font-family: 'Georgia', 'Times New Roman', serif; font-weight: normal; } |
|
|
.consensus-box-content { font-size: 1.0em; line-height: 1.4; padding: 5px; width: 100%; } |
|
|
|
|
|
.consensus-box-german { background: linear-gradient(135deg, #FFB6C1, #FFC0CB); color: #333333; } |
|
|
.consensus-box-french { background: linear-gradient(135deg, #E6E6FA, #DDA0DD); color: #333333; } |
|
|
.consensus-box-italian { background: linear-gradient(135deg, #F0E68C, #F5DEB3); color: #333333; } |
|
|
.consensus-box-left { background: linear-gradient(135deg, #98FB98, #90EE90); color: #333333; } |
|
|
.consensus-box-center { background: linear-gradient(135deg, #87CEEB, #B0E0E6); color: #333333; } |
|
|
.consensus-box-right { background: linear-gradient(135deg, #FFDAB9, #FFE4B5); color: #333333; } |
|
|
|
|
|
/* Estilo para la caja del consenso final */ |
|
|
.final-consensus-box { background: linear-gradient(135deg, #A5D6A7, #66BB6A); color: #333333; padding: 30px; border-radius: 15px; |
|
|
margin: 20px 0; box-shadow: 0 6px 10px rgba(0,0,0,0.15); min-height: 150px; max-height: 400px; overflow-y: auto; |
|
|
display: flex; align-items: flex-start; justify-content: center; text-align: center; font-family: 'Georgia', 'Times New Roman', serif; |
|
|
font-weight: normal; font-size: 1.1em; } |
|
|
|
|
|
.question-header { background: linear-gradient(135deg, #1e3a5f, #2d5a87); color: white; padding: 15px; border-radius: 10px; |
|
|
text-align: center; margin-bottom: 20px; font-family: 'Georgia', 'Times New Roman', serif; font-weight: normal; } |
|
|
|
|
|
.upload-section { text-align: center; margin: 20px 0; } |
|
|
.gradio-container { font-family: 'Georgia', 'Times New Roman', serif; } |
|
|
|
|
|
/* Botón personalizado */ |
|
|
.custom-button-color { background-color: #2e8b57 !important; color: #ffffff !important; border-color: #2e8b57 !important; } |
|
|
""" |
|
|
) as demo: |
|
|
|
|
|
gr.HTML(""" |
|
|
<div class="flag-container"> |
|
|
<img src="https://upload.wikimedia.org/wikipedia/commons/b/ba/Flag_of_Germany.svg" class="flag-image" alt="German Flag"> |
|
|
<img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Flag_of_France.svg" class="flag-image" alt="French Flag"> |
|
|
<img src="https://upload.wikimedia.org/wikipedia/commons/0/03/Flag_of_Italy.svg" class="flag-image" alt="Italian Flag"> |
|
|
</div> |
|
|
<h1 style='text-align: center; font-size: 1.8em; margin-bottom: 15px;'>Consensus Statements</h1> |
|
|
""") |
|
|
|
|
|
|
|
|
with gr.Row(elem_classes=["upload-section"]): |
|
|
with gr.Column(): |
|
|
excel_input = gr.File(label="📊 UPLOAD EXCEL HERE!", file_types=[".xlsx", ".xls"], type="filepath") |
|
|
process_btn = gr.Button("🚀 Generate Consensus", elem_classes=["custom-button-color"], size="lg") |
|
|
|
|
|
status_output = gr.Textbox(label="Status", interactive=False, value="Ready to process Excel file...") |
|
|
question_display = gr.HTML(value='<div class="question-header">Upload an Excel file to see the question here</div>', |
|
|
elem_classes=["question-header"]) |
|
|
|
|
|
|
|
|
all_data = gr.State() |
|
|
|
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
german_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>German-speaking cantons<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-german"] |
|
|
) |
|
|
with gr.Column(): |
|
|
french_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>French-speaking cantons<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-french"] |
|
|
) |
|
|
with gr.Column(): |
|
|
italian_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>Italian-speaking cantons<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-italian"] |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
left_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>LEFT<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-left"] |
|
|
) |
|
|
with gr.Column(): |
|
|
center_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>CENTER<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-center"] |
|
|
) |
|
|
with gr.Column(): |
|
|
right_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">Consensus Statement:<br>RIGHT<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["consensus-box", "consensus-box-right"] |
|
|
) |
|
|
|
|
|
final_output = gr.HTML( |
|
|
value='<div class="consensus-box-content">FINAL - CONSENSUS STATEMENT:<br><br>Upload Excel file to see results<br><b>SUPPORTING THIS DECISION: --</b></div>', |
|
|
elem_classes=["final-consensus-box"] |
|
|
) |
|
|
|
|
|
|
|
|
def process_and_store_data(excel_file_path): |
|
|
data = process_excel_and_generate_consensus(excel_file_path) |
|
|
return data, data |
|
|
|
|
|
def update_display(data): |
|
|
if not data: |
|
|
return ("Error processing file", "", "", "", "", "", "", "", "") |
|
|
(status, question, german, french, italian, left, center, right, final, |
|
|
german_percentage, french_percentage, italian_percentage, |
|
|
left_percentage, center_percentage, right_percentage, final_percentage) = data |
|
|
|
|
|
question_html = f'<div class="question-header">Question: {question}</div>' |
|
|
german_html = f'<div class="consensus-box-content">Consensus Statement:<br>German-speaking cantons<br><br>{german}<br><b>SUPPORTING THIS DECISION: {german_percentage}</b></div>' |
|
|
french_html = f'<div class="consensus-box-content">Consensus Statement:<br>French-speaking cantons<br><br>{french}<br><b>SUPPORTING THIS DECISION: {french_percentage}</b></div>' |
|
|
italian_html = f'<div class="consensus-box-content">Consensus Statement:<br>Italian-speaking cantons<br><br>{italian}<br><b>SUPPORTING THIS DECISION: {italian_percentage}</b></div>' |
|
|
left_html = f'<div class="consensus-box-content">Consensus Statement:<br>LEFT<br><br>{left}<br><b>SUPPORTING THIS DECISION: {left_percentage}</b></div>' |
|
|
center_html = f'<div class="consensus-box-content">Consensus Statement:<br>CENTER<br><br>{center}<br><b>SUPPORTING THIS DECISION: {center_percentage}</b></div>' |
|
|
right_html = f'<div class="consensus-box-content">Consensus Statement:<br>RIGHT<br><br>{right}<br><b>SUPPORTING THIS DECISION: {right_percentage}</b></div>' |
|
|
final_html = f'<div class="consensus-box-content">FINAL - CONSENSUS STATEMENT:<br><br>{final}<br><b>SUPPORTING THIS DECISION: {final_percentage}</b></div>' |
|
|
|
|
|
return (status, question_html, german_html, french_html, italian_html, |
|
|
left_html, center_html, right_html, final_html) |
|
|
|
|
|
|
|
|
process_btn.click( |
|
|
fn=process_and_store_data, |
|
|
inputs=[excel_input], |
|
|
outputs=[all_data, all_data] |
|
|
).then( |
|
|
fn=update_display, |
|
|
inputs=[all_data], |
|
|
outputs=[status_output, question_display, german_output, french_output, italian_output, |
|
|
left_output, center_output, right_output, final_output] |
|
|
) |
|
|
|
|
|
return demo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
app = create_consensus_app() |
|
|
|
|
|
|
|
|
is_spaces = os.getenv("SPACE_ID") is not None |
|
|
|
|
|
if is_spaces: |
|
|
|
|
|
app.launch( |
|
|
share=False, |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
debug=False, |
|
|
inbrowser=False |
|
|
) |
|
|
else: |
|
|
|
|
|
app.launch( |
|
|
share=True, |
|
|
server_name="127.0.0.1", |
|
|
server_port=None, |
|
|
debug=True, |
|
|
inbrowser=True |
|
|
) |
|
|
|