KGX3Demo / app.py
K1SysAdmin's picture
Update app.py
aa140ba verified
"""
Shared KGX3 API Endpoint – Calling KGX3 on PreprintWatch.com. Uploads research papers to the shared endpoint (secured with X-API-Key),
retrieves a signed temporary link, and sends it to the PreprintWatch KGX3 API. Output: JSON formatted Kuhnian Classification Report
"""
import gradio as gr
import requests, json, pathlib, mimetypes, re
# === CONFIGURATION ===
WP_UPLOAD_URL = "https://preprintwatch.com/wp-json/kgx3/v1/upload" # your WP REST route
WP_UPLOAD_KEY = "lmsijtadti7tiDD6750xNdN" # shared secret
API_ENDPOINT = "https://preprintwatch.com/wp-json/pw-kgx3/v1/submit" # KGX3 proxy
API_KEY = "sk-X1zY9wS3-vU4tQ0-rOjH5gK2fE7mN6" # internal KGX3 key
# === HELPERS ===
def upload_private_pdf(pdf_path: str) -> str:
"""Upload to WordPress secure uploader and return signed fetch URL."""
with open(pdf_path, "rb") as f:
r = requests.post(
WP_UPLOAD_URL,
headers={"X-API-Key": WP_UPLOAD_KEY},
files={"file": f},
timeout=60
)
r.raise_for_status()
data = r.json()
if "fetch_url" not in data:
raise RuntimeError(f"Upload failed: {data}")
return data["fetch_url"]
# === MAIN WORKFLOW ===
def call_kgx3(title, email, pdf_file, agreement):
if not agreement:
return "⚠️ You must accept the disclaimer before running KGX3.", ""
if not pdf_file:
return "Please select a PDF file.", ""
if not email or not re.match(r"[^@]+@[^@]+\.[^@]+", email):
return "A valid email address is required to run KGX3.", ""
pdf_path = pdf_file.name
if not pdf_path.lower().endswith(".pdf"):
return "Only PDF files are supported.", ""
# --- Upload to WP and get temporary signed URL ---
try:
file_url = upload_private_pdf(pdf_path)
except Exception as e:
return f"Upload error: {e}", ""
# --- Forward to KGX3 ---
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
payload = {"title": title or pathlib.Path(pdf_path).stem, "pdf_url": file_url, "email": email}
try:
resp = requests.post(API_ENDPOINT, headers=headers, json=payload, timeout=180)
try:
body = json.dumps(resp.json(), indent=2, ensure_ascii=False)
except Exception:
body = resp.text
return body, file_url
except requests.RequestException as e:
return f"Request error: {e}", file_url
# === STYLE (high-contrast Matrix aesthetic) ===
FUTURE_CSS = """
/* === UNIVERSAL RESET === */
html, body, .gradio-container, section, div, .form, .gr-block, .gr-panel, .gr-box, .gr-column, .gr-row, .container, .file-preview, .upload-box, .wrap-inner {
background-color: #000 !important;
color: #00ff99 !important;
font-family: 'Courier New', monospace !important;
box-sizing: border-box;
}
/* === GENERAL TEXT === */
* { color: #00ff99 !important; }
h1, h2, h3, label, .label {
font-weight: 700 !important;
text-transform: uppercase;
border-bottom: 1px solid #00ff99;
margin-bottom: 6px;
padding-bottom: 4px;
letter-spacing: 0.5px;
}
/* === CONTAINERS === */
.gr-box, .gr-panel, .gr-block, .gr-column, .gr-row, .form {
border: 1px solid #00ff99 !important;
border-radius: 6px;
background-color: #000 !important;
padding: 8px !important;
}
/* === INPUTS & TEXTAREAS === */
input, textarea, select {
background-color: #000 !important;
color: #00ff99 !important;
border: 1px solid #00ff99 !important;
border-radius: 4px;
padding: 6px 8px !important;
}
input:focus, textarea:focus {
outline: none !important;
border: 1px solid #00ffcc !important;
background-color: #001a10 !important;
}
::placeholder { color: #00ff99 !important; opacity: 0.6; }
/* === FILE UPLOAD === */
.upload-box, .file-preview, .wrap-inner, .file-preview-container {
background-color: #000 !important;
border: 2px solid #00ff99 !important;
border-radius: 6px !important;
padding: 10px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
transition: all 0.2s ease-in-out;
}
.upload-box:hover, .file-preview:hover {
background-color: #001a10 !important;
border-color: #00ffaa !important;
}
/* === BUTTONS === */
button {
background-color: #000 !important;
color: #00ff99 !important;
border: 2px solid #00ff99 !important;
border-radius: 4px;
text-transform: uppercase;
font-weight: 700;
letter-spacing: 0.5px;
padding: 8px 16px !important;
transition: all 0.15s ease-in-out;
}
button:hover {
background-color: #00ff99 !important;
color: #000 !important;
}
/* === OUTPUT / CODE AREA === */
pre, code, .cm-editor, .cm-content, .cm-line, .output-html, .output-markdown {
background-color: #000 !important;
color: #00ff99 !important;
border: 1px solid #00ff99 !important;
border-radius: 6px;
padding: 10px !important;
font-size: 0.9rem;
}
/* === CHECKBOX === */
input[type=checkbox] {
accent-color: #00ff99 !important;
transform: scale(1.2);
}
/* === SCROLLBARS === */
::-webkit-scrollbar { width: 8px; background: #000; }
::-webkit-scrollbar-thumb { background: #00ff99; border-radius: 4px; }
/* === FOOTER === */
footer, .footer, small {
color: #00ff99 !important;
opacity: 0.8;
text-align: center;
letter-spacing: 0.4px;
}
"""
# === BUILD INTERFACE ===
with gr.Blocks(css=FUTURE_CSS, title="KGX3 Research Analyzer") as demo:
gr.Markdown("""
# **KGX3 Engine**
Upload a scientific preprint PDF. The app sends it to the shared KGX3 API endpoint demonstrating the API function.
""")
# --- Disclaimer ---
gr.Markdown("""
### ⚠️ Disclaimer
By using this interface, you confirm that:
- You are responsible and accountable for the files you upload.
- All uploaded files are automatically deleted within **24 hours**.
- System logs of KGX3 activity are retained securely for **up to 60 days** for auditing.
- You must ensure that any material you upload is lawful, non-confidential, and free of third-party rights restrictions.
""")
agreement = gr.Checkbox(
label="I have read and accept full responsibility and accountability for the files I upload.",
value=False
)
# --- Layout ---
with gr.Row():
with gr.Column(scale=1):
title_box = gr.Textbox(label="Enter the paper title", placeholder="Enter or paste the paper title")
email_box = gr.Textbox(label="Email (required)", placeholder="you@example.com")
file_box = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
run_btn = gr.Button("Run KGX3", variant="primary")
with gr.Column(scale=1):
output_json = gr.Code(label="KGX3 Response", language="json")
output_url = gr.Textbox(label="Temporary PDF Link", interactive=False)
run_btn.click(call_kgx3,
inputs=[title_box, email_box, file_box, agreement],
outputs=[output_json, output_url])
gr.Markdown("<small>Built on Gradio • Thomas Kuhn Foundation © All rights reserved.</small>")
demo.launch()