Spaces:
Sleeping
Sleeping
| """ | |
| Divination AI โ Modernized Gradio 6.x UI | |
| Cleaner, more immersive mystical oracle experience with better typography and layout. | |
| """ | |
| from __future__ import annotations | |
| import gradio as gr | |
| import model_runtime | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # THEME | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| THEME = gr.themes.Base( | |
| font=[gr.themes.GoogleFont("Cormorant Garamond"), "serif"], | |
| font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "monospace"], | |
| ).set( | |
| body_background_fill="#0a0812", | |
| block_background_fill="rgba(10,8,18,0.6)", | |
| button_primary_background_fill="#d4a444", | |
| button_primary_text_color="#0a0812", | |
| input_background_fill="rgba(26,15,46,0.6)", | |
| input_border_color="rgba(212,164,68,0.3)", | |
| ) | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # CSS | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| CSS = """ | |
| /* โโโ GLOBAL RESET & FULL-SCREEN LAYOUT โโโ */ | |
| @import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&900&display=swap'); | |
| html, body, gradio-app { | |
| height: 100%; | |
| margin: 0; | |
| overflow: hidden; | |
| } | |
| .gradio-container { | |
| max-width: 100% !important; | |
| padding: 0 !important; | |
| height: 100%; | |
| overflow-y: auto; | |
| } | |
| /* Remove Gradio dark mode artifacts */ | |
| .dark { filter: none !important; } | |
| /* โโโ MYSTICAL BACKGROUND โโโ */ | |
| body { | |
| background: radial-gradient(ellipse at center top, #1a0f2e 0%, #0a0812 60%, #000000 100%); | |
| background-attachment: fixed; | |
| position: relative; | |
| overflow-x: hidden; | |
| } | |
| /* Animated stars layer */ | |
| #stars-layer { | |
| position: fixed; | |
| inset: 0; | |
| background-image: | |
| radial-gradient(2px 2px at 20% 30%, rgba(255,255,255,0.8), transparent), | |
| radial-gradient(2px 2px at 80% 20%, rgba(255,255,255,0.6), transparent), | |
| radial-gradient(1px 1px at 50% 50%, rgba(255,255,255,0.5), transparent), | |
| radial-gradient(1px 1px at 30% 70%, rgba(255,255,255,0.7), transparent), | |
| radial-gradient(2px 2px at 70% 80%, rgba(255,255,255,0.6), transparent); | |
| background-size: 200% 200%, 200% 200%, 200% 200%, 200% 200%, 200% 200%; | |
| background-position: 0% 0%, 100% 100%, 50% 50%, 80% 20%, 20% 80%; | |
| animation: twinkle 8s ease-in-out infinite; | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| @keyframes twinkle { | |
| 0%, 100% { opacity: 0.4; } | |
| 50% { opacity: 0.8; } | |
| } | |
| /* โโโ TYPOGRAPHY โโโ */ | |
| .oracle-heading { | |
| font-family: 'Cinzel Decorative', serif; | |
| font-weight: 900; | |
| font-size: 3.5rem; | |
| background: linear-gradient(135deg, #d4a444 0%, #e8b956 50%, #d4a444 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| text-align: center; | |
| letter-spacing: 0.1em; | |
| text-shadow: 0 0 40px rgba(212,164,68,0.5); | |
| margin: 2rem 0 1rem 0; | |
| line-height: 1.2; | |
| } | |
| .oracle-subtitle { | |
| font-size: 1.4rem; | |
| color: rgba(232,226,244,0.9); | |
| text-align: center; | |
| font-style: italic; | |
| line-height: 1.7; | |
| margin-bottom: 3rem; | |
| } | |
| /* โโโ LAYOUT CONTAINERS โโโ */ | |
| #welcome-col, #chat-col, #results-col { | |
| padding: 40px 20px; | |
| min-height: 600px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| #welcome-col { | |
| max-width: 700px; | |
| margin: 0 auto; | |
| } | |
| #chat-col { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| } | |
| #results-col { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| /* โโโ ORACLE BUBBLE โโโ */ | |
| .oracle-scroll { | |
| background: rgba(10,8,18,0.85); | |
| border: 2px solid rgba(212,164,68,0.4); | |
| border-radius: 20px; | |
| padding: 40px 50px; | |
| margin: 0 0 2rem 0; | |
| backdrop-filter: blur(16px); | |
| box-shadow: 0 8px 40px rgba(0,0,0,0.6), | |
| 0 0 60px rgba(123,77,191,0.3), | |
| inset 0 1px 0 rgba(255,255,255,0.1); | |
| animation: oracleGlow 4s ease-in-out infinite; | |
| } | |
| @keyframes oracleGlow { | |
| 0%, 100% { | |
| box-shadow: 0 8px 40px rgba(0,0,0,0.6), | |
| 0 0 60px rgba(123,77,191,0.3), | |
| inset 0 1px 0 rgba(255,255,255,0.1); | |
| } | |
| 50% { | |
| box-shadow: 0 8px 40px rgba(0,0,0,0.6), | |
| 0 0 80px rgba(212,164,68,0.4), | |
| inset 0 1px 0 rgba(255,255,255,0.1); | |
| } | |
| } | |
| #oracle-bubble { | |
| font-size: 1.5rem; | |
| color: #e8e2f4; | |
| line-height: 1.9; | |
| min-height: 60px; | |
| } | |
| /* โโโ INPUT FIELD โโโ */ | |
| .input-parchment { | |
| width: 100%; | |
| max-width: 700px; | |
| margin: 0 auto; | |
| } | |
| #user-input textarea { | |
| background: rgba(26,15,46,0.7) !important; | |
| border: 2px solid rgba(212,164,68,0.3) !important; | |
| border-radius: 12px !important; | |
| color: #e8e2f4 !important; | |
| font-size: 1.3rem !important; | |
| padding: 20px 24px !important; | |
| font-family: 'Cormorant Garamond', serif !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| #user-input textarea:focus { | |
| border-color: #d4a444 !important; | |
| box-shadow: 0 0 30px rgba(212,164,68,0.4) !important; | |
| background: rgba(26,15,46,0.9) !important; | |
| } | |
| #user-input textarea::placeholder { | |
| color: rgba(232,226,244,0.4) !important; | |
| font-style: italic !important; | |
| } | |
| /* โโโ MYSTICAL BUTTONS โโโ */ | |
| .mystical-btn button { | |
| background: linear-gradient(135deg, #d4a444 0%, #b8832d 100%) !important; | |
| color: #0a0812 !important; | |
| border: none !important; | |
| border-radius: 12px !important; | |
| padding: 18px 50px !important; | |
| font-size: 1.2rem !important; | |
| font-weight: 700 !important; | |
| font-family: 'Cinzel Decorative', serif !important; | |
| letter-spacing: 0.08em !important; | |
| text-transform: uppercase !important; | |
| box-shadow: 0 6px 25px rgba(212,164,68,0.4) !important; | |
| transition: all 0.3s ease !important; | |
| cursor: pointer !important; | |
| } | |
| .mystical-btn button:hover { | |
| transform: translateY(-3px) !important; | |
| box-shadow: 0 10px 35px rgba(212,164,68,0.6) !important; | |
| background: linear-gradient(135deg, #e8b956 0%, #d4a444 100%) !important; | |
| } | |
| .mystical-btn button:active { | |
| transform: translateY(-1px) !important; | |
| } | |
| /* โโโ SCENARIO CARDS โโโ */ | |
| .scenarios-container { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); | |
| gap: 24px; | |
| margin: 3rem 0; | |
| width: 100%; | |
| } | |
| .scenario-card { | |
| background: rgba(10,8,18,0.9); | |
| border: 2px solid rgba(212,164,68,0.3); | |
| border-radius: 16px; | |
| padding: 35px 30px; | |
| backdrop-filter: blur(12px); | |
| transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); | |
| cursor: pointer; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .scenario-card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 4px; | |
| background: linear-gradient(90deg, transparent, currentColor, transparent); | |
| opacity: 0; | |
| transition: opacity 0.4s ease; | |
| } | |
| .scenario-card:hover::before { | |
| opacity: 1; | |
| } | |
| .scenario-card:hover { | |
| transform: translateY(-8px); | |
| border-color: #d4a444; | |
| box-shadow: 0 12px 40px rgba(212,164,68,0.3); | |
| } | |
| .scenario-card.momentum { | |
| border-left: 5px solid #d4a444; | |
| color: #d4a444; | |
| } | |
| .scenario-card.pivot { | |
| border-left: 5px solid #7b4dbf; | |
| color: #7b4dbf; | |
| } | |
| .scenario-card.leap { | |
| border-left: 5px solid #4db8a8; | |
| color: #4db8a8; | |
| } | |
| .scenario-card h3 { | |
| font-family: 'Cinzel Decorative', serif; | |
| font-size: 1.9rem; | |
| color: #d4a444; | |
| margin-bottom: 0.7rem; | |
| font-weight: 700; | |
| } | |
| .archetype { | |
| font-size: 1rem; | |
| color: currentColor; | |
| text-transform: uppercase; | |
| letter-spacing: 0.15em; | |
| margin-bottom: 1.2rem; | |
| opacity: 0.9; | |
| } | |
| .narrative { | |
| font-size: 1.15rem; | |
| color: #e8e2f4; | |
| line-height: 1.7; | |
| margin-bottom: 1.5rem; | |
| } | |
| .meta { | |
| font-size: 1rem; | |
| color: rgba(232,226,244,0.7); | |
| line-height: 1.6; | |
| } | |
| .meta strong { | |
| color: rgba(212,164,68,0.9); | |
| } | |
| /* โโโ REFLECTION TEXT โโโ */ | |
| #reflection-text { | |
| font-size: 1.5rem; | |
| color: #e8e2f4; | |
| line-height: 1.9; | |
| text-align: center; | |
| font-style: italic; | |
| margin: 3rem 0; | |
| padding: 40px; | |
| background: rgba(10,8,18,0.85); | |
| border: 2px solid rgba(212,164,68,0.3); | |
| border-radius: 20px; | |
| backdrop-filter: blur(12px); | |
| } | |
| #motivation-text { | |
| font-size: 1.4rem; | |
| color: rgba(232,226,244,0.9); | |
| line-height: 1.8; | |
| text-align: center; | |
| margin: 3rem 0; | |
| font-weight: 500; | |
| } | |
| /* โโโ DISCLAIMER โโโ */ | |
| #disclaimer { | |
| font-size: 0.9rem; | |
| color: rgba(232,226,244,0.5); | |
| text-align: center; | |
| line-height: 1.6; | |
| margin-top: 3rem; | |
| } | |
| /* โโโ MUTE BUTTON โโโ */ | |
| #mute-toggle { | |
| position: fixed; | |
| top: 24px; | |
| right: 24px; | |
| z-index: 1000; | |
| background: rgba(10,8,18,0.8) !important; | |
| border: 2px solid rgba(212,164,68,0.3) !important; | |
| border-radius: 50% !important; | |
| width: 56px !important; | |
| height: 56px !important; | |
| font-size: 1.6rem !important; | |
| cursor: pointer !important; | |
| transition: all 0.3s ease !important; | |
| backdrop-filter: blur(10px) !important; | |
| display: flex !important; | |
| align-items: center !important; | |
| justify-content: center !important; | |
| } | |
| #mute-toggle:hover { | |
| background: rgba(10,8,18,0.95) !important; | |
| border-color: #d4a444 !important; | |
| transform: scale(1.1) !important; | |
| } | |
| /* โโโ LOADING STATE โโโ */ | |
| #loading-screen { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 50vh; | |
| } | |
| #loading-text { | |
| font-family: 'Cinzel Decorative', serif; | |
| font-size: 1.8rem; | |
| color: #d4a444; | |
| text-shadow: 0 0 30px rgba(212,164,68,0.6); | |
| animation: pulse 2s ease-in-out infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 0.5; } | |
| 50% { opacity: 1; } | |
| } | |
| /* โโโ RESPONSIVE โโโ */ | |
| @media (max-width: 768px) { | |
| .oracle-heading { | |
| font-size: 2.5rem; | |
| } | |
| .oracle-subtitle { | |
| font-size: 1.1rem; | |
| } | |
| #oracle-bubble { | |
| font-size: 1.2rem; | |
| } | |
| .oracle-scroll { | |
| padding: 30px 25px; | |
| } | |
| .scenarios-container { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| """ | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # HEAD โ Audio + JS | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| HEAD = """ | |
| <script> | |
| // โโโ AUDIO ENGINE โโโ | |
| window.audioCtx = null; | |
| window.masterGain = null; | |
| window.audioMuted = false; | |
| window.startAmbient = function() { | |
| if (window.audioCtx) return; | |
| const ctx = new (window.AudioContext || window.webkitAudioContext)(); | |
| window.audioCtx = ctx; | |
| const master = ctx.createGain(); | |
| master.gain.value = 0.3; | |
| master.connect(ctx.destination); | |
| window.masterGain = master; | |
| // Ambient drone (A minor pentatonic mood) | |
| const osc1 = ctx.createOscillator(); | |
| const osc2 = ctx.createOscillator(); | |
| const osc3 = ctx.createOscillator(); | |
| osc1.type = 'sine'; | |
| osc2.type = 'triangle'; | |
| osc3.type = 'sine'; | |
| osc1.frequency.value = 110; // A2 | |
| osc2.frequency.value = 164.81; // E3 | |
| osc3.frequency.value = 220; // A3 | |
| const gain1 = ctx.createGain(); | |
| const gain2 = ctx.createGain(); | |
| const gain3 = ctx.createGain(); | |
| gain1.gain.value = 0.06; | |
| gain2.gain.value = 0.04; | |
| gain3.gain.value = 0.03; | |
| const filter = ctx.createBiquadFilter(); | |
| filter.type = 'lowpass'; | |
| filter.frequency.value = 800; | |
| osc1.connect(gain1); | |
| osc2.connect(gain2); | |
| osc3.connect(gain3); | |
| gain1.connect(filter); | |
| gain2.connect(filter); | |
| gain3.connect(filter); | |
| filter.connect(master); | |
| osc1.start(); | |
| osc2.start(); | |
| osc3.start(); | |
| }; | |
| window.toggleMute = function() { | |
| if (!window.masterGain) return; | |
| window.audioMuted = !window.audioMuted; | |
| window.masterGain.gain.linearRampToValueAtTime( | |
| window.audioMuted ? 0 : 0.3, | |
| window.audioCtx.currentTime + 0.3 | |
| ); | |
| const btn = document.getElementById('mute-toggle'); | |
| if (btn) btn.textContent = window.audioMuted ? '๐' : '๐'; | |
| }; | |
| // Remove dark mode class | |
| const observer = new MutationObserver(() => { | |
| document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); | |
| }); | |
| observer.observe(document.documentElement, { attributes: true, subtree: true, attributeFilter: ['class'] }); | |
| </script> | |
| """ | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # HELPERS | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| def render_scenario_cards(reading: dict) -> str: | |
| scenarios = reading.get("scenarios", []) | |
| html = '<div class="scenarios-container">' | |
| for s in scenarios: | |
| archetype = s.get("archetype", "").lower() | |
| html += f""" | |
| <div class="scenario-card {archetype}"> | |
| <h3>{s.get('title', '')}</h3> | |
| <div class="archetype">The Path of {s.get('archetype', '')}</div> | |
| <div class="narrative">{s.get('narrative', '').replace(chr(10), '<br>')}</div> | |
| <div class="meta"> | |
| <strong>First step:</strong> {s.get('first_step', '')}<br> | |
| <strong>Watch for:</strong> {s.get('watch_for', '')}<br> | |
| <strong>Tradeoff:</strong> {s.get('tradeoff', '')} | |
| </div> | |
| </div> | |
| """ | |
| html += '</div>' | |
| return html | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # APP | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| with gr.Blocks(title="Divination AI") as demo: | |
| state = gr.State(value={"messages": [], "intake_complete": False, "reading": None}) | |
| gr.HTML('<div id="stars-layer"></div>') | |
| gr.HTML('<button id="mute-toggle" onclick="window.toggleMute()">๐</button>') | |
| # โโ Welcome Screen โโ | |
| with gr.Column(visible=True, elem_id="welcome-col") as welcome_col: | |
| gr.HTML('<h1 class="oracle-heading">The Oracle of Paths</h1>') | |
| gr.HTML('<p class="oracle-subtitle">A glimpse into your possible futures,<br>grounded in the world as it is today.</p>') | |
| begin_btn = gr.Button("Begin Your Reading", elem_classes="mystical-btn") | |
| gr.HTML('<div id="disclaimer">This is an AI-powered reflection tool for entertainment and self-exploration.<br>Not a substitute for professional advice. Your future is shaped by your choices.</div>') | |
| # โโ Conversation Screen โโ | |
| with gr.Column(visible=False, elem_id="chat-col") as chat_col: | |
| oracle_bubble = gr.HTML('<div class="oracle-scroll"><div id="oracle-bubble">...</div></div>') | |
| with gr.Group(elem_classes="input-parchment"): | |
| user_input = gr.Textbox( | |
| placeholder="Speak your truth...", | |
| lines=3, | |
| show_label=False, | |
| elem_id="user-input", | |
| ) | |
| submit_btn = gr.Button("Send", elem_classes="mystical-btn") | |
| # โโ Results Screen โโ | |
| with gr.Column(visible=False, elem_id="results-col") as results_col: | |
| results_html = gr.HTML("") | |
| new_reading_btn = gr.Button("Begin New Reading", elem_classes="mystical-btn") | |
| # โโ Event Handlers โโ | |
| def do_begin(session): | |
| """Start first oracle question.""" | |
| try: | |
| result = model_runtime.intake(messages=[]) | |
| except model_runtime.BackendError as e: | |
| return ( | |
| session, | |
| f'<div class="oracle-scroll"><div id="oracle-bubble">The Oracle stirs but cannot yet speak... {e}</div></div>', | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| ) | |
| response = result["response"] | |
| session["messages"] = [{"role": "assistant", "content": response}] | |
| return ( | |
| session, | |
| f'<div class="oracle-scroll"><div id="oracle-bubble">{response}</div></div>', | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| ) | |
| def on_send(session, user_text): | |
| """Handle user message.""" | |
| if not user_text or not user_text.strip(): | |
| return (session, gr.update(), gr.update(), gr.update(), gr.update(), gr.update()) | |
| session["messages"].append({"role": "user", "content": user_text.strip()}) | |
| try: | |
| result = model_runtime.intake(session["messages"]) | |
| except model_runtime.BackendError as e: | |
| session["messages"].pop() | |
| return ( | |
| session, | |
| f'<div class="oracle-scroll"><div id="oracle-bubble">The connection wavers... {e}</div></div>', | |
| "", | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| gr.update(), | |
| ) | |
| response = result["response"] | |
| session["messages"].append({"role": "assistant", "content": response}) | |
| intake_complete = result.get("intake_complete", False) | |
| if not intake_complete: | |
| return ( | |
| session, | |
| f'<div class="oracle-scroll"><div id="oracle-bubble">{response}</div></div>', | |
| "", | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| gr.update(), | |
| ) | |
| # Intake complete โ generate reading | |
| try: | |
| gen_result = model_runtime.generate(session["messages"]) | |
| except model_runtime.BackendError as e: | |
| return ( | |
| session, | |
| gr.update(), | |
| "", | |
| gr.update(visible=False), | |
| gr.update(visible=True), | |
| f'<div id="reflection-text">The Oracle could not complete your reading: {e}</div>', | |
| ) | |
| reading = gen_result.get("reading", {}) | |
| session["reading"] = reading | |
| reflection = reading.get("reflection", "") | |
| cards_html = render_scenario_cards(reading) | |
| motivation = reading.get("motivation", "") | |
| full_results = ( | |
| f'<div id="reflection-text">{reflection}</div>' | |
| + cards_html | |
| + f'<div id="motivation-text">{motivation}</div>' | |
| ) | |
| return ( | |
| session, | |
| gr.update(), | |
| "", | |
| gr.update(visible=False), | |
| gr.update(visible=True), | |
| full_results, | |
| ) | |
| def on_new_reading(session): | |
| session = {"messages": [], "intake_complete": False, "reading": None} | |
| return ( | |
| session, | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| gr.update(visible=False), | |
| ) | |
| # โโ Event wiring โโ | |
| begin_btn.click( | |
| fn=do_begin, | |
| inputs=[state], | |
| outputs=[state, oracle_bubble, chat_col, welcome_col], | |
| js="() => { window.startAmbient(); }", | |
| ) | |
| submit_btn.click( | |
| fn=on_send, | |
| inputs=[state, user_input], | |
| outputs=[state, oracle_bubble, user_input, chat_col, results_col, results_html], | |
| ) | |
| user_input.submit( | |
| fn=on_send, | |
| inputs=[state, user_input], | |
| outputs=[state, oracle_bubble, user_input, chat_col, results_col, results_html], | |
| ) | |
| new_reading_btn.click( | |
| fn=on_new_reading, | |
| inputs=[state], | |
| outputs=[state, welcome_col, chat_col, results_col], | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue(default_concurrency_limit=5).launch( | |
| css=CSS, | |
| head=HEAD, | |
| theme=THEME, | |
| ssr_mode=False, | |
| ) | |