contact / app.py
nalanda-data's picture
Remove Book a call mailto from thank-you message
c1ef35a verified
Raw
History Blame Contribute Delete
8.33 kB
"""Nalandadata — contact / data-licensing lead form.
A Gradio Space that captures licensing enquiries and appends each one as a row to
the PRIVATE Nalandadata/leads dataset.
Auth: reads a write-scoped token from the Space secret HF_WRITE_TOKEN.
"""
import os
import io
import csv
import datetime
import gradio as gr
from huggingface_hub import HfApi, hf_hub_download
LEADS_REPO = "Nalandadata/leads"
LEADS_FILE = "leads.csv"
TOKEN = os.environ.get("HF_WRITE_TOKEN") # set as a Space secret
SITE = "https://nalandadata.ai/?utm_source=huggingface&utm_medium=contact_space&utm_campaign=lead_form"
DATASETS = [
"NalandaJEENEETBench",
"nalanda-image-qa",
"DrishtiTable",
"Other / custom data",
]
COLUMNS = ["timestamp", "name", "email", "organization", "role",
"use_case", "datasets_of_interest", "message", "source"]
api = HfApi(token=TOKEN)
def _valid_email(e):
return isinstance(e, str) and "@" in e and "." in e.split("@")[-1] and len(e) >= 6
def submit(name, email, organization, role, use_case, datasets, message):
if not name or not name.strip():
return gr.update(value="⚠️ Please enter your name.", visible=True)
if not _valid_email(email):
return gr.update(value="⚠️ Please enter a valid work email.", visible=True)
if not organization or not organization.strip():
return gr.update(value="⚠️ Please enter your organization.", visible=True)
if not TOKEN:
return gr.update(
value="⚠️ The form is not yet configured (missing write token). "
"Please email info@nalandadata.ai directly.", visible=True)
row = {
"timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds"),
"name": name.strip(),
"email": email.strip(),
"organization": organization.strip(),
"role": (role or "").strip(),
"use_case": (use_case or "").strip(),
"datasets_of_interest": "|".join(datasets or []),
"message": (message or "").strip().replace("\r", " ").replace("\n", " "),
"source": "contact-space",
}
try:
# download current leads.csv, append, re-upload
try:
path = hf_hub_download(LEADS_REPO, LEADS_FILE, repo_type="dataset", token=TOKEN)
with open(path, encoding="utf-8") as f:
existing = f.read()
except Exception:
existing = ",".join(COLUMNS) + "\n"
buf = io.StringIO()
buf.write(existing if existing.endswith("\n") else existing + "\n")
w = csv.writer(buf)
w.writerow([row[c] for c in COLUMNS])
data = buf.getvalue().encode("utf-8")
api.upload_file(
path_or_fileobj=data,
path_in_repo=LEADS_FILE,
repo_id=LEADS_REPO,
repo_type="dataset",
commit_message=f"New lead: {row['organization']} ({row['timestamp']})",
)
except Exception as e:
return gr.update(
value=f"⚠️ Couldn't record your enquiry automatically ({type(e).__name__}). "
f"Please email info@nalandadata.ai and we'll respond quickly.",
visible=True)
return gr.update(
value=(f"✅ **Thank you, {row['name']}!** Your enquiry has been received.\n\n"
f"We'll reply to **{row['email']}** shortly. "
f"In the meantime, explore more at [nalandadata.ai]({SITE})."),
visible=True)
# Theme aligned to Nalandadata/nalanda-live-demos (dark + gold)
THEME_CSS = """
:root{
--bg:#0c0c0e; --panel:#141417; --panel2:#1b1b20; --line:#2a2a31;
--ink:#ece7da; --sub:#9d958a; --gold:#d8b65a; --gold2:#f0d488;
--ok:#7bd88f; --err:#e08a8a;
}
.gradio-container, .gradio-container *{
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif !important;
-webkit-font-smoothing:antialiased;
}
.gradio-container{
max-width:860px !important; margin:0 auto !important;
background:radial-gradient(1200px 600px at 50% -10%, #16161b 0%, var(--bg) 60%) !important;
color:var(--ink) !important;
}
/* surrounding chrome */
body, gradio-app{ background:var(--bg) !important; }
#nd-hero{ text-align:center; padding:34px 16px 6px; }
#nd-hero .brand{
font-size:13px; letter-spacing:.32em; text-transform:uppercase;
color:var(--gold); font-weight:600;
}
#nd-hero h1{
font-size:30px; font-weight:700; letter-spacing:-.01em;
margin:8px 0 6px; color:var(--ink);
}
#nd-hero p{
color:var(--sub); font-size:14.5px; line-height:1.55;
max-width:560px; margin:0 auto;
}
/* form card */
.gradio-container .block, .gradio-container .form{
background:var(--panel) !important; border:1px solid var(--line) !important;
border-radius:14px !important;
}
.gradio-container label span, .gradio-container .gr-box label span{
color:var(--sub) !important; font-weight:600 !important; font-size:13px !important;
}
.gradio-container input[type=text], .gradio-container textarea,
.gradio-container input:not([type=checkbox]){
background:var(--panel2) !important; border:1px solid var(--line) !important;
color:var(--ink) !important; border-radius:10px !important; font-size:15px !important;
}
.gradio-container input:focus, .gradio-container textarea:focus{
outline:none !important; border-color:var(--gold) !important; box-shadow:none !important;
}
/* checkboxes */
.gradio-container .gr-check-radio, .gradio-container [data-testid="checkbox-group"] label{
color:var(--ink) !important;
}
.gradio-container input[type=checkbox]:checked{ accent-color:var(--gold) !important; }
/* primary button -> gold gradient */
.gradio-container button.primary, .gradio-container .primary{
background:linear-gradient(180deg,var(--gold2),var(--gold)) !important;
color:#1a1407 !important; border:none !important; font-weight:700 !important;
border-radius:10px !important;
}
.gradio-container button.primary:hover{ filter:brightness(1.05); }
/* result markdown */
#nd-result, #nd-result *{ color:var(--ink) !important; }
#nd-result a{ color:var(--gold) !important; }
#nd-footer{ text-align:center; margin-top:18px; font-size:12.5px; color:var(--sub); }
#nd-footer a{ color:var(--gold); text-decoration:none; font-weight:500; }
#nd-footer a:hover{ text-decoration:underline; }
"""
INTRO = """
<div id="nd-hero">
<div class="brand">Nalandadata</div>
<h1>Work with us</h1>
<p>
We license verified, curriculum-aligned Indian STEM data for AI training,
post-training, and evaluation — JEE/NEET reasoning, scientific multimodal QA,
and annotated document tables. Tell us what you're building and we'll get
back to you with access and licensing options.
</p>
</div>
"""
with gr.Blocks(title="Contact Nalandadata",
css=THEME_CSS,
theme=gr.themes.Base(
primary_hue="yellow", secondary_hue="stone",
neutral_hue="stone",
font=["-apple-system", "BlinkMacSystemFont", "Segoe UI", "sans-serif"],
)) as demo:
gr.HTML(INTRO)
with gr.Row():
with gr.Column():
name = gr.Textbox(label="Name *", placeholder="Your full name")
email = gr.Textbox(label="Work email *", placeholder="you@company.com")
organization = gr.Textbox(label="Organization *", placeholder="Company / institution")
role = gr.Textbox(label="Role (optional)", placeholder="e.g. ML Lead, Researcher")
with gr.Column():
datasets = gr.CheckboxGroup(DATASETS, label="Datasets of interest")
use_case = gr.Textbox(label="Use case", placeholder="How do you plan to use the data/models?")
message = gr.Textbox(label="Message", lines=3, placeholder="Anything else we should know?")
submit_btn = gr.Button("Send enquiry", variant="primary")
result = gr.Markdown(visible=False, elem_id="nd-result")
submit_btn.click(
submit,
inputs=[name, email, organization, role, use_case, datasets, message],
outputs=result,
)
gr.HTML(
f'<div id="nd-footer" style="text-align:center;margin-top:16px;">'
f'Prefer email? <a href="mailto:info@nalandadata.ai">info@nalandadata.ai</a> · '
f'<a href="{SITE}" target="_blank">nalandadata.ai</a></div>'
)
if __name__ == "__main__":
demo.launch()