benedictturner's picture
Update app.py
4e37f7c verified
import os
import gradio as gr
from gradio_client import Client
import json, datetime
import gspread
from google.oauth2.service_account import Credentials
import time
# === Load Google service account credentials from HF secret ===
# === Google Sheets Setup ===
SHEET_ID = "1O0pRqNDp-MkTGfASVwQPSZPLocLJTSOFbx0bjMzkJQg"
def _get_worksheet():
"""Authorise Google Sheets once and cache worksheet."""
creds_json = os.environ.get("GOOGLE_CREDS")
if not creds_json:
raise RuntimeError("Missing GOOGLE_CREDS secret in Hugging Face Space")
creds_dict = json.loads(creds_json)
scopes = ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive"]
creds = Credentials.from_service_account_info(creds_dict, scopes=scopes)
gc = gspread.authorize(creds)
return gc.open_by_key(SHEET_ID).sheet1 # First worksheet
# Cache the worksheet object so we don't re-auth every call
print("Loading worksheet")
worksheet = _get_worksheet()
print("worksheet loaded")
def log_interaction(question: str, response: str, routing: str, aura: str, latency: float):
"""
Append a row to Google Sheet with:
Question | Response | Routing | AURA | Latency (s)
"""
try:
worksheet.append_row([
question,
response,
routing,
aura,
f"{latency:.2f}"
])
except Exception as e:
print(f"⚠️ Logging failed: {e}")
# === Backend config ===
BACKEND_URL = os.environ.get("BACKEND_URL")
TOKEN = os.environ.get("HF_PRIVATE_SPACE_TOKEN")
# Single shared client (Space process persists across requests)
client = Client(BACKEND_URL, hf_token=TOKEN)
def respond(message: str, history: list | None):
"""Proxy to private Space /chat endpoint and mirror outputs.
Returns (chat_history, internal_routing_md, aura_md)
"""
try:
t0 = time.perf_counter()
chat, md1, md2 = client.predict(
message=message,
history=history or [],
api_name="/chat",
)
bot_response = chat[-1][1] if chat else ""
md1 = md1 or ""
md2 = md2 or ""
latency = time.perf_counter() - t0
# ✅ Log cleanly
try:
print("attempting log")
log_interaction(message, bot_response, md1, md2, latency)
print("success")
except Exception as e:
print(f"Failed to log: {e}")
return chat, md1, md2
except Exception as e:
chat = (history or []) + [(message, f"⚠️ Backend error: {e}")]
return chat, "", ""
def clear_all():
"""Call backend /clear and propagate cleared state.
Fallback to local clear if backend clear fails.
"""
try:
chat, md1, md2 = client.predict(api_name="/clear")
return chat or [], (md1 or ""), (md2 or "")
except Exception:
return [], "", ""
with gr.Blocks(fill_height=True, theme=gr.themes.Soft()) as demo:
gr.Markdown("# Project Nightingale - Due Diligence Explorer (Public Proxy)")
gr.Markdown(
"""
**10.10.25 1700 BST: BT running evals for christopher with additional questions - please message me if you wish to run additional queries as don't want to mess up the latency**
**I will take down this notice as soon as I have finished**
Ask a question — we will:
1. Select sources intelligently with our internal routing agent
2. Search the indexed guideline data using our **G-PRISM** retrieval pipeline
3. Internally verify responses with the **AURA** adversarial critical evaluator mechanism
"""
)
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(
label="Clinical Knowledge Chat (G-PRISM Retrieval)",
height=500,
render_markdown=True,
sanitize_html=False,
)
with gr.Row():
user_in = gr.Textbox(placeholder="Type your question…", scale=4)
send_btn = gr.Button("Send", scale=1, variant="primary")
clear_btn = gr.Button("Clear Chat")
with gr.Column(scale=2):
with gr.Group():
gr.Markdown("## Intelligent source selection (Internal Routing)")
spec_box = gr.Markdown(value="")
with gr.Group():
gr.Markdown("## Critical Appraisal (AURA)")
critical_box = gr.Markdown(value="")
# Wire events
user_in.submit(respond, inputs=[user_in, chatbot], outputs=[chatbot, spec_box, critical_box])
send_btn.click(respond, inputs=[user_in, chatbot], outputs=[chatbot, spec_box, critical_box])
# Clear input after sending
user_in.submit(lambda: "", None, user_in)
send_btn.click(lambda: "", None, user_in)
# Clear everything
clear_btn.click(clear_all, outputs=[chatbot, spec_box, critical_box])
if __name__ == "__main__":
demo.launch()