Update app.py
Browse files
app.py
CHANGED
|
@@ -1,57 +1,136 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
|
|
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
-
|
| 26 |
-
if
|
| 27 |
-
|
| 28 |
-
auditor_display = f"<span style='color:green;font-weight:bold'>{auditor_answer}</span>"
|
| 29 |
else:
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
Rationale: {rationale}
|
| 40 |
-
</div>
|
| 41 |
-
"""
|
| 42 |
-
results.append(result)
|
| 43 |
-
|
| 44 |
-
return "<br>".join(results)
|
| 45 |
-
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
|
| 54 |
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
+
import re
|
| 4 |
|
| 5 |
+
# Mapping dictionary
|
| 6 |
+
mapping = {
|
| 7 |
+
"obs_commercial_purpose_commercial": "Commercial",
|
| 8 |
+
"obs_commercial_purpose_issue": "SIP",
|
| 9 |
+
"obs_environmental_politics_global": "Environmental Politics",
|
| 10 |
+
"obs_civil_social_rights_global": "Civil and Social Rights",
|
| 11 |
+
"obs_economy_global": "Economy",
|
| 12 |
+
"obs_security_foreign_policy_global": "Security and Foreign Policy",
|
| 13 |
+
"obs_political_values_global": "Political Values and Governance",
|
| 14 |
+
"obs_health_global": "Health",
|
| 15 |
+
"obs_immigration_global": "Immigration",
|
| 16 |
+
"obs_crime_global": "Crime",
|
| 17 |
+
"obs_guns_global": "Guns",
|
| 18 |
+
"obs_education_global": "Education",
|
| 19 |
+
}
|
| 20 |
|
| 21 |
+
def process_tags(tags):
|
| 22 |
+
if not isinstance(tags, str):
|
| 23 |
+
return ""
|
| 24 |
+
|
| 25 |
+
raw_tags = [t.strip() for t in tags.split(",") if t.strip()]
|
| 26 |
+
|
| 27 |
+
# Rule 1: If Commercial exists → only output Commercial
|
| 28 |
+
if "obs_commercial_purpose_commercial" in raw_tags:
|
| 29 |
+
return "Commercial"
|
| 30 |
+
|
| 31 |
+
# Otherwise map normally
|
| 32 |
+
mapped = []
|
| 33 |
+
sip_flag = False
|
| 34 |
+
for tag in raw_tags:
|
| 35 |
+
if tag == "obs_commercial_purpose_issue":
|
| 36 |
+
sip_flag = True # store SIP to add later
|
| 37 |
+
elif tag in mapping:
|
| 38 |
+
mapped.append(mapping[tag])
|
| 39 |
+
|
| 40 |
+
# Add SIP at the end if exists
|
| 41 |
+
if sip_flag:
|
| 42 |
+
mapped.append("SIP")
|
| 43 |
+
|
| 44 |
+
return ", ".join(mapped)
|
| 45 |
|
| 46 |
+
def highlight_matches(tm, auditor):
|
| 47 |
+
tm_tags = [t.strip() for t in tm.split(",") if t.strip()]
|
| 48 |
+
auditor_tags = [t.strip() for t in auditor.split(",") if t.strip()]
|
| 49 |
+
|
| 50 |
+
highlighted_tm = []
|
| 51 |
+
highlighted_auditor = []
|
| 52 |
|
| 53 |
+
for tag in tm_tags:
|
| 54 |
+
if tag in auditor_tags:
|
| 55 |
+
highlighted_tm.append(f'<span style="color: green; font-weight: bold">{tag}</span>')
|
|
|
|
| 56 |
else:
|
| 57 |
+
highlighted_tm.append(f'<span style="color: red; font-weight: bold">{tag}</span>')
|
| 58 |
+
|
| 59 |
+
for tag in auditor_tags:
|
| 60 |
+
if tag in tm_tags:
|
| 61 |
+
highlighted_auditor.append(f'<span style="color: green; font-weight: bold">{tag}</span>')
|
| 62 |
+
else:
|
| 63 |
+
highlighted_auditor.append(f'<span style="color: red; font-weight: bold">{tag}</span>')
|
| 64 |
+
|
| 65 |
+
return ", ".join(highlighted_tm), ", ".join(highlighted_auditor)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
+
def process_sheet(sheet_url):
|
| 68 |
+
# Convert Google Sheets share link to CSV export
|
| 69 |
+
match = re.search(r"/d/([a-zA-Z0-9-_]+)", sheet_url)
|
| 70 |
+
if not match:
|
| 71 |
+
return "❌ Invalid Google Sheets link."
|
| 72 |
+
|
| 73 |
+
sheet_id = match.group(1)
|
| 74 |
+
csv_url = f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=csv"
|
| 75 |
+
|
| 76 |
+
try:
|
| 77 |
+
df = pd.read_csv(csv_url)
|
| 78 |
+
except Exception as e:
|
| 79 |
+
return f"❌ Error reading sheet: {e}"
|
| 80 |
|
| 81 |
+
outputs = []
|
| 82 |
+
for _, row in df.iterrows():
|
| 83 |
+
name = row.get("Full Name", "")
|
| 84 |
+
job_id = row.get("job_id", "")
|
| 85 |
+
|
| 86 |
+
# TM (from R)
|
| 87 |
+
tm = process_tags(row.get("Combined", ""))
|
| 88 |
+
|
| 89 |
+
# Auditor: gather all AF–AW columns
|
| 90 |
+
auditor_tags = []
|
| 91 |
+
for col in df.columns:
|
| 92 |
+
if col.startswith("A"): # AF, AG, AH...
|
| 93 |
+
auditor_tags.append(str(row[col]))
|
| 94 |
+
auditor = process_tags(", ".join(auditor_tags))
|
| 95 |
+
|
| 96 |
+
# Rule: if both TM and Auditor are blank → NT
|
| 97 |
+
if not tm.strip():
|
| 98 |
+
tm = "NT"
|
| 99 |
+
if not auditor.strip():
|
| 100 |
+
auditor = "NT"
|
| 101 |
+
|
| 102 |
+
# Highlight matches/mismatches
|
| 103 |
+
tm_h, auditor_h = highlight_matches(tm, auditor)
|
| 104 |
+
|
| 105 |
+
# Column CC = rationale (fixed index approach)
|
| 106 |
+
rationale = ""
|
| 107 |
+
try:
|
| 108 |
+
rationale = row.iloc[80] # 0-based index for CC
|
| 109 |
+
except Exception:
|
| 110 |
+
pass
|
| 111 |
+
|
| 112 |
+
rationale_text = f"<br><br><b>Rationale:</b> {rationale}" if pd.notna(rationale) and str(rationale).strip() else ""
|
| 113 |
+
|
| 114 |
+
# Final formatted text (using HTML now)
|
| 115 |
+
text = f"""
|
| 116 |
+
<b>{name}</b><br>
|
| 117 |
+
job id: {job_id}<br>
|
| 118 |
+
<b>TM:</b> {tm_h}<br>
|
| 119 |
+
<b>Auditor:</b> {auditor_h}{rationale_text}
|
| 120 |
+
"""
|
| 121 |
+
|
| 122 |
+
outputs.append(text)
|
| 123 |
|
| 124 |
+
return "<hr><br>".join(outputs)
|
| 125 |
|
| 126 |
+
# Gradio App (switched output to HTML)
|
| 127 |
+
demo = gr.Interface(
|
| 128 |
+
fn=process_sheet,
|
| 129 |
+
inputs=gr.Textbox(label="Google Sheets Link", placeholder="Paste Google Sheets link here"),
|
| 130 |
+
outputs=gr.HTML(label="Formatted Output"),
|
| 131 |
+
title="Google Sheets Formatter",
|
| 132 |
+
description="Paste your Google Sheets link (make sure it's shared as 'Anyone with the link can view')."
|
| 133 |
+
)
|
| 134 |
|
| 135 |
+
if __name__ == "__main__":
|
| 136 |
+
demo.launch()
|