""" 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("Built on Gradio • Thomas Kuhn Foundation © All rights reserved.") demo.launch()