| import gradio as gr |
| from huggingface_hub import InferenceClient |
| import os |
|
|
| HF_TOKEN = os.environ.get("HF_TOKEN", "") |
|
|
| client = InferenceClient( |
| model="mistralai/Mistral-7B-Instruct-v0.3", |
| token=HF_TOKEN, |
| ) |
|
|
| OCEANUS_SYSTEM = """You are OCEANUS β the AI Oracle of the Deep, trained on all marine science, oceanography, and underwater exploration data. |
| |
| Your knowledge spans: |
| π All 5 ocean zones: Sunlit (0-200m), Twilight (200-1000m), Midnight (1000-4000m), Abyssal (4000-6000m), Hadal (6000-11000m) |
| π Marine biology: species taxonomy, bioluminescence, deep-sea adaptations, food webs |
| βοΈ Ocean chemistry: salinity, thermoclines, oxygen minimum zones, hydrothermal vent chemistry |
| πΊοΈ Geology: mid-ocean ridges, trenches (Mariana, Puerto Rico, Java), underwater volcanoes |
| π‘οΈ Physics: pressure (1 atm per 10m), temperature inversions, thermohaline circulation |
| π¬ Historic missions: Alvin, Deepsea Challenger, Nereus, Kaiko |
| |
| Respond with scientific precision but a dramatic explorer's tone. Include measurements, species names, Latin taxonomy. Use emojis. Always end with one π€― MIND-BLOWING FACT. Keep under 280 words.""" |
|
|
| INITIAL_MSG = [{"role": "assistant", "content": "π **OCEANUS ONLINE** β AI Oracle of the Deep, powered by Mistral-7B (free). Select a zone in the 3D viewer above, then ask me anything about the ocean.\n\nπ€Ώ Where shall we dive first?"}] |
|
|
|
|
| def build_prompt(message: str, history: list, zone: str, ocean: str) -> str: |
| context = "" |
| if zone: context += f" [Exploring: {zone}]" |
| if ocean: context += f" [Ocean: {ocean}]" |
|
|
| prompt = f"<s>[INST] <<SYS>>\n{OCEANUS_SYSTEM}\n<</SYS>>\n\n" |
| for msg in history[-8:]: |
| role = msg["role"] |
| content = msg["content"] |
| if role == "user": |
| prompt += f"{content} [/INST] " |
| else: |
| prompt += f"{content} </s><s>[INST] " |
| prompt += f"{message}{context} [/INST]" |
| return prompt |
|
|
|
|
| def chat_with_oceanus(message: str, history: list, zone: str, ocean: str): |
| if not message.strip(): |
| return "", history |
|
|
| prompt = build_prompt(message, history, zone, ocean) |
|
|
| try: |
| response = client.text_generation( |
| prompt, |
| max_new_tokens=400, |
| temperature=0.7, |
| repetition_penalty=1.1, |
| do_sample=True, |
| stop_sequences=["</s>", "[INST]"], |
| ) |
| reply = response.strip() or "β οΈ Signal lost. Please retry." |
| except Exception as e: |
| reply = f"β οΈ OCEANUS disrupted: {str(e)}\n\nEnsure HF_TOKEN is set in Space secrets." |
|
|
| history.append({"role": "user", "content": message}) |
| history.append({"role": "assistant", "content": reply}) |
| return "", history |
|
|
|
|
| def quick_ask(question: str, history: list, zone: str, ocean: str): |
| return chat_with_oceanus(question, history, zone, ocean) |
|
|
|
|
| def get_zone_info(zone: str) -> str: |
| data = { |
| "Sunlit Zone (0-200m)": "βοΈ **SUNLIT ZONE** | 0β200m | 4β30Β°C | 1β20 atm\nHome to 90% of all marine life. Photosynthesis drives the base of all ocean food chains.", |
| "Twilight Zone (200-1000m)": "π **TWILIGHT ZONE** | 200β1,000m | 4β20Β°C | 20β100 atm\nOnly 1% sunlight here. Creatures perform daily vertical migrations of hundreds of meters.", |
| "Midnight Zone (1000-4000m)": "π **MIDNIGHT ZONE** | 1,000β4,000m | 2β4Β°C | 100β400 atm\nAbsolute darkness. 76% of deep-sea fish produce their own bioluminescent light.", |
| "Abyssal Zone (4000-6000m)": "β« **ABYSSAL ZONE** | 4,000β6,000m | 0β3Β°C | 400β600 atm\nCovers 60% of Earth's surface. Home to hydrothermal vents with chemosynthetic life.", |
| "Hadal Zone (6000-11000m)": "π **HADAL ZONE** | 6,000β11,000m | 1β4Β°C | 600β1,086 atm\nMariana Trench (10,935m) β pressure is 1,086Γ surface. Life still thrives here.", |
| } |
| return data.get(zone, "Select a zone to begin your descent...") |
|
|
|
|
| THREE_JS_HTML = """ |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&display=swap'); |
| * { margin:0; padding:0; box-sizing:border-box; } |
| body { background:#000408; font-family:'Share Tech Mono',monospace; overflow:hidden; color:#00ffcc; } |
| #cc { position:relative; width:100%; height:560px; overflow:hidden; } |
| #tc { width:100%!important; height:100%!important; display:block; } |
| .hud { position:absolute; pointer-events:none; font-family:'Share Tech Mono',monospace; font-size:11px; letter-spacing:1px; text-transform:uppercase; } |
| #htl { top:16px; left:16px; color:#00ffcc; } |
| #htr { top:16px; right:16px; text-align:right; color:#00d4ff; } |
| #hbl { bottom:64px; left:16px; color:#7fff00; } |
| #hbr { bottom:64px; right:16px; text-align:right; color:#ff6b35; } |
| .hv { font-size:16px; font-family:'Orbitron',sans-serif; font-weight:700; display:block; } |
| .hl { font-size:9px; opacity:.6; display:block; margin-bottom:5px; } |
| #sl { position:absolute; top:0; left:0; right:0; bottom:0; background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,255,204,.012) 2px,rgba(0,255,204,.012) 4px); pointer-events:none; z-index:10; } |
| .corner { position:absolute; width:36px; height:36px; pointer-events:none; z-index:5; } |
| .c1 { top:8px; left:8px; border-top:2px solid #00ffcc; border-left:2px solid #00ffcc; } |
| .c2 { top:8px; right:8px; border-top:2px solid #00ffcc; border-right:2px solid #00ffcc; } |
| .c3 { bottom:8px; left:8px; border-bottom:2px solid #00ffcc; border-left:2px solid #00ffcc; } |
| .c4 { bottom:8px; right:8px; border-bottom:2px solid #00ffcc; border-right:2px solid #00ffcc; } |
| #th { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; pointer-events:none; z-index:15; transition:opacity 1.2s; } |
| #th h1 { font-family:'Orbitron',sans-serif; font-size:clamp(22px,4vw,46px); font-weight:900; color:#00ffcc; text-shadow:0 0 40px #00ffcc; letter-spacing:8px; animation:glow 3s ease-in-out infinite; } |
| #th p { font-size:10px; color:rgba(0,255,204,.55); letter-spacing:4px; margin-top:6px; } |
| @keyframes glow { 0%,100%{text-shadow:0 0 40px #00ffcc} 50%{text-shadow:0 0 80px #00ffcc,0 0 160px rgba(0,255,204,.4)} } |
| #zc { position:absolute; left:50%; bottom:12px; transform:translateX(-50%); display:flex; gap:7px; z-index:20; pointer-events:all; } |
| .zb { background:rgba(0,20,40,.85); border:1px solid; color:inherit; font-family:'Share Tech Mono',monospace; font-size:9px; letter-spacing:1px; padding:5px 9px; cursor:pointer; text-transform:uppercase; transition:all .3s; backdrop-filter:blur(4px); } |
| .zb:hover,.zb.active { background:rgba(0,255,204,.18); box-shadow:0 0 10px currentColor; } |
| .z0{color:#fff176;border-color:#fff176} .z1{color:#80cbc4;border-color:#80cbc4} .z2{color:#5c6bc0;border-color:#5c6bc0} .z3{color:#00ffcc;border-color:#00ffcc} .z4{color:#ff6b35;border-color:#ff6b35} |
| #sb { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#00ffcc; font-family:'Orbitron',sans-serif; font-size:11px; letter-spacing:3px; text-align:center; pointer-events:none; opacity:0; transition:opacity .5s; text-shadow:0 0 20px #00ffcc; z-index:20; } |
| #sb.show { opacity:1; } |
| #db { position:absolute; right:14px; top:50%; transform:translateY(-50%); width:5px; height:180px; background:rgba(0,255,204,.1); border:1px solid rgba(0,255,204,.3); pointer-events:none; z-index:10; } |
| #df { position:absolute; bottom:0; width:100%; background:linear-gradient(to top,#ff6b35,#5c6bc0,#00ffcc); transition:height 1s ease; } |
| #ld { position:absolute; top:0; left:0; right:0; bottom:0; display:flex; align-items:center; justify-content:center; background:#000408; z-index:100; flex-direction:column; gap:14px; transition:opacity 1s; } |
| #ld.fade { opacity:0; pointer-events:none; } |
| .lt { font-family:'Orbitron',sans-serif; color:#00ffcc; font-size:13px; letter-spacing:5px; animation:blink .9s step-end infinite; } |
| @keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} } |
| .lb { width:180px; height:2px; background:rgba(0,255,204,.15); overflow:hidden; } |
| .lf { height:100%; background:#00ffcc; animation:lp 2.2s ease-in-out forwards; box-shadow:0 0 8px #00ffcc; } |
| @keyframes lp { 0%{width:0%} 100%{width:100%} } |
| </style> |
| </head> |
| <body> |
| <div id="ld"><div class="lt">INITIALIZING OCEANUS ARRAY</div><div class="lb"><div class="lf"></div></div></div> |
| <div id="cc"> |
| <canvas id="tc"></canvas> |
| <div id="sl"></div> |
| <div class="corner c1"></div><div class="corner c2"></div><div class="corner c3"></div><div class="corner c4"></div> |
| <div id="th"><h1>OCEANUS</h1><p>GOD'S EYE β AR DEEP OCEAN EXPLORER</p></div> |
| <div class="hud" id="htl"> |
| <span class="hl">SYS STATUS</span><span class="hv" style="font-size:12px;color:#7fff00">β ONLINE</span><br> |
| <span class="hl">SONAR</span><span class="hv" style="font-size:12px" id="sv">ACTIVE</span><br> |
| <span class="hl">ZONE</span><span class="hv" style="font-size:12px" id="zd">SURFACE</span> |
| </div> |
| <div class="hud" id="htr"> |
| <span class="hl">DEPTH</span><span class="hv" id="dv">0 m</span><br> |
| <span class="hl">PRESSURE</span><span class="hv" id="pv">1 atm</span><br> |
| <span class="hl">TEMP</span><span class="hv" id="tv">28Β°C</span> |
| </div> |
| <div class="hud" id="hbl"> |
| <span class="hl">SPECIES DETECTED</span><span class="hv" id="spv" style="font-size:11px">SCANNING...</span><br> |
| <span class="hl">BIOLUMINESCENCE</span><span class="hv" id="bv">0%</span> |
| </div> |
| <div class="hud" id="hbr"> |
| <span class="hl">OCEAN COVERAGE</span><span class="hv">70.9%</span><br> |
| <span class="hl">UNMAPPED</span><span class="hv" style="color:#ff6b35">~80%</span> |
| </div> |
| <div id="db"><div id="df" style="height:5%"></div></div> |
| <div id="sb">DIVING...</div> |
| <div id="zc"> |
| <button class="zb z0 active" onclick="setZone(0)">β SUNLIT</button> |
| <button class="zb z1" onclick="setZone(1)">π TWILIGHT</button> |
| <button class="zb z2" onclick="setZone(2)">π MIDNIGHT</button> |
| <button class="zb z3" onclick="setZone(3)">β« ABYSSAL</button> |
| <button class="zb z4" onclick="setZone(4)">π HADAL</button> |
| </div> |
| </div> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
| <script> |
| const ZONES=[ |
| {name:'SUNLIT', depth:100, pressure:10, temp:24, color:0x006994,fog:0x0099cc,fogD:.05,bio:5, sp:'Blue Whale Β· Manta Ray Β· Tuna'}, |
| {name:'TWILIGHT',depth:600, pressure:60, temp:12, color:0x003366,fog:0x001a4d,fogD:.08,bio:30,sp:'Giant Squid Β· Lanternfish Β· Hatchetfish'}, |
| {name:'MIDNIGHT',depth:2500, pressure:250, temp:3, color:0x000d1a,fog:0x000814,fogD:.13,bio:76,sp:'Anglerfish Β· Fangtooth Β· Viperfish'}, |
| {name:'ABYSSAL', depth:5000, pressure:500, temp:2, color:0x000408,fog:0x000204,fogD:.17,bio:60,sp:'Sea Cucumber Β· Tripod Fish Β· Xenophyophore'}, |
| {name:'HADAL', depth:10935,pressure:1086,temp:1.5,color:0x000000,fog:0x000000,fogD:.23,bio:20,sp:'Amphipods Β· Snailfish Β· Polychaete Worms'}, |
| ]; |
| let scene,camera,renderer,ocean,particles,bubbles,creatures=[],clock,titleFaded=false; |
| |
| function init(){ |
| const canvas=document.getElementById('tc'),cont=document.getElementById('cc'); |
| renderer=new THREE.WebGLRenderer({canvas,antialias:true}); |
| renderer.setPixelRatio(Math.min(devicePixelRatio,2)); |
| renderer.setSize(cont.clientWidth,cont.clientHeight); |
| renderer.setClearColor(0x001a3d,1); |
| scene=new THREE.Scene(); |
| scene.fog=new THREE.FogExp2(0x001a3d,.05); |
| clock=new THREE.Clock(); |
| camera=new THREE.PerspectiveCamera(60,cont.clientWidth/cont.clientHeight,.1,1000); |
| camera.position.set(0,8,16); camera.lookAt(0,0,0); |
| buildAll(); addLights(); |
| window.addEventListener('resize',onResize); |
| setTimeout(()=>{document.getElementById('ld').classList.add('fade');setTimeout(()=>{const l=document.getElementById('ld');if(l)l.remove();},1000);},2400); |
| animate(); |
| } |
| |
| function buildAll(){ |
| // Ocean surface |
| const og=new THREE.PlaneGeometry(60,60,80,80); |
| const om=new THREE.MeshPhongMaterial({color:0x006994,emissive:0x001133,transparent:true,opacity:.85,shininess:120}); |
| ocean=new THREE.Mesh(og,om); ocean.rotation.x=-Math.PI/2; scene.add(ocean); |
| // Floor |
| const fg=new THREE.PlaneGeometry(60,60,20,20); |
| const fm=new THREE.MeshPhongMaterial({color:0x1a0a00,emissive:0x050200}); |
| const fl=new THREE.Mesh(fg,fm); fl.rotation.x=-Math.PI/2; fl.position.y=-10; scene.add(fl); |
| // Grid |
| const gg=new THREE.PlaneGeometry(60,60,40,40); |
| const gm=new THREE.MeshBasicMaterial({color:0x00ffcc,wireframe:true,transparent:true,opacity:.06}); |
| const gr2=new THREE.Mesh(gg,gm); gr2.rotation.x=-Math.PI/2; gr2.position.y=-4.9; scene.add(gr2); |
| // Vents |
| for(let i=0;i<6;i++){ |
| const v=new THREE.Mesh(new THREE.CylinderGeometry(.05,.22,4,8),new THREE.MeshPhongMaterial({color:0x333333,emissive:0x110500})); |
| v.position.set((Math.random()-.5)*22,-8,(Math.random()-.5)*22); scene.add(v); |
| const s=new THREE.Mesh(new THREE.SphereGeometry(.3,8,8),new THREE.MeshBasicMaterial({color:0xff4400,transparent:true,opacity:.65})); |
| s.position.copy(v.position); s.position.y=-6.4; scene.add(s); |
| } |
| // Coral |
| const cc=[0x00ff80,0xff6060,0xffaa00,0x8080ff,0xff80ff]; |
| for(let i=0;i<24;i++){ |
| const h=.3+Math.random()*1.8; |
| const c=new THREE.Mesh(new THREE.ConeGeometry(.08+Math.random()*.22,h,6),new THREE.MeshPhongMaterial({color:cc[Math.floor(Math.random()*cc.length)],emissive:0x110011,transparent:true,opacity:.9})); |
| c.position.set((Math.random()-.5)*28,-9.5+h/2,(Math.random()-.5)*28); |
| c.rotation.y=Math.random()*Math.PI; c.rotation.z=(Math.random()-.5)*.3; scene.add(c); |
| } |
| // Particles |
| const N=3000,pg=new THREE.BufferGeometry(),pp=new Float32Array(N*3),pc=new Float32Array(N*3); |
| for(let i=0;i<N;i++){pp[i*3]=(Math.random()-.5)*40;pp[i*3+1]=-10+Math.random()*14;pp[i*3+2]=(Math.random()-.5)*40;const c=Math.random();pc[i*3]=c*.1;pc[i*3+1]=c*.8+.2;pc[i*3+2]=c*.6+.4;} |
| pg.setAttribute('position',new THREE.BufferAttribute(pp,3)); pg.setAttribute('color',new THREE.BufferAttribute(pc,3)); |
| particles=new THREE.Points(pg,new THREE.PointsMaterial({size:.06,vertexColors:true,transparent:true,opacity:.8})); scene.add(particles); |
| // Bubbles |
| const BN=220,bg=new THREE.BufferGeometry(),bp=new Float32Array(BN*3); |
| for(let i=0;i<BN;i++){bp[i*3]=(Math.random()-.5)*28;bp[i*3+1]=-10+Math.random()*13;bp[i*3+2]=(Math.random()-.5)*28;} |
| bg.setAttribute('position',new THREE.BufferAttribute(bp,3)); |
| bubbles=new THREE.Points(bg,new THREE.PointsMaterial({size:.13,color:0xaaddff,transparent:true,opacity:.4})); scene.add(bubbles); |
| // Creatures |
| for(let i=0;i<32;i++){ |
| const m=new THREE.Mesh(new THREE.OctahedronGeometry(.15+Math.random()*.3,0),new THREE.MeshBasicMaterial({color:Math.random()>.5?0x00ffcc:0x7fff00,wireframe:true,transparent:true,opacity:.6})); |
| m.position.set((Math.random()-.5)*18,-8+Math.random()*9,(Math.random()-.5)*18); |
| m.userData={spd:.01+Math.random()*.03,r:2+Math.random()*5,a:Math.random()*Math.PI*2,sy:m.position.y}; |
| scene.add(m); creatures.push(m); |
| } |
| } |
| |
| function addLights(){ |
| scene.add(new THREE.AmbientLight(0x001a2e,2)); |
| const sun=new THREE.DirectionalLight(0x4488cc,1.5); sun.position.set(10,20,10); scene.add(sun); |
| [[0x00ffcc,0],[0x0088ff,1],[0x00ff44,2]].forEach(([c,i])=>{ |
| const l=new THREE.PointLight(c,2,12); l.position.set(Math.cos(i*2.1)*8,-5+i*2,Math.sin(i*2.1)*8); scene.add(l); |
| }); |
| } |
| |
| function animate(){ |
| requestAnimationFrame(animate); |
| const t=clock.getElapsedTime(); |
| if(ocean){const p=ocean.geometry.attributes.position;for(let i=0;i<p.count;i++)p.setZ(i,Math.sin(p.getX(i)*.5+t)*.22+Math.cos(p.getY(i)*.5+t*.8)*.16);p.needsUpdate=true;} |
| if(particles){const p=particles.geometry.attributes.position;for(let i=0;i<p.count;i++){let y=p.getY(i)+.002;if(y>2)y=-10;p.setY(i,y);p.setX(i,p.getX(i)+Math.sin(t+i)*.001);}p.needsUpdate=true;particles.rotation.y=t*.005;} |
| if(bubbles){const p=bubbles.geometry.attributes.position;for(let i=0;i<p.count;i++){let y=p.getY(i)+.014+Math.random()*.01;if(y>2)y=-10;p.setY(i,y);}p.needsUpdate=true;} |
| creatures.forEach(c=>{c.userData.a+=c.userData.spd;c.position.x=Math.cos(c.userData.a)*c.userData.r;c.position.z=Math.sin(c.userData.a)*c.userData.r;c.position.y=c.userData.sy+Math.sin(t*.5+c.userData.a)*.5;c.rotation.x=t*.5;c.rotation.y=c.userData.a;}); |
| camera.position.x=Math.sin(t*.05)*18; camera.position.z=Math.cos(t*.05)*18; camera.position.y=6+Math.sin(t*.03)*2; camera.lookAt(0,-2,0); |
| renderer.render(scene,camera); |
| } |
| |
| function setZone(idx){ |
| const z=ZONES[idx]; |
| document.getElementById('dv').textContent=z.depth.toLocaleString()+' m'; |
| document.getElementById('pv').textContent=z.pressure.toLocaleString()+' atm'; |
| document.getElementById('tv').textContent=z.temp+'Β°C'; |
| document.getElementById('spv').textContent=z.sp; |
| document.getElementById('bv').textContent=z.bio+'%'; |
| document.getElementById('zd').textContent=z.name; |
| document.getElementById('df').style.height=((idx+1)*18)+'%'; |
| scene.fog.color.setHex(z.fog); scene.fog.density=z.fogD; |
| ocean.material.color.setHex(z.color); ocean.material.opacity=Math.max(.3,.85-idx*.12); |
| renderer.setClearColor(z.fog,1); |
| const s=document.getElementById('sb'); |
| s.textContent=`DIVING TO ${z.name} β ${z.depth.toLocaleString()}m`; |
| s.classList.add('show'); setTimeout(()=>s.classList.remove('show'),2500); |
| if(!titleFaded){document.getElementById('th').style.opacity='0';titleFaded=true;} |
| document.querySelectorAll('.zb').forEach((b,i)=>b.classList.toggle('active',i===idx)); |
| } |
| |
| function onResize(){const c=document.getElementById('cc');camera.aspect=c.clientWidth/c.clientHeight;camera.updateProjectionMatrix();renderer.setSize(c.clientWidth,c.clientHeight);} |
| |
| window.addEventListener('load',init); |
| setInterval(()=>{const e=document.getElementById('sv');if(e)e.textContent=new Date().toUTCString().slice(17,25)+' UTC';},1000); |
| </script> |
| </body> |
| </html> |
| """ |
|
|
| CSS = """ |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&display=swap'); |
| body, .gradio-container { background:#000408!important; color:#00ffcc!important; font-family:'Share Tech Mono',monospace!important; } |
| .oceanus-header { background:linear-gradient(135deg,#000408,#001a2e); border-bottom:1px solid #00ffcc33; padding:14px 24px; text-align:center; } |
| .oceanus-title { font-family:'Orbitron',sans-serif; font-size:26px; font-weight:900; color:#00ffcc; text-shadow:0 0 30px #00ffcc; letter-spacing:7px; margin:0; } |
| .oceanus-sub { font-size:10px; color:rgba(0,255,204,.5); letter-spacing:4px; margin-top:4px; } |
| .gr-panel { background:#000408!important; border:1px solid #00ffcc22!important; border-radius:0!important; } |
| textarea, input { background:#000d1a!important; border:1px solid #00ffcc44!important; color:#00ffcc!important; font-family:'Share Tech Mono',monospace!important; border-radius:0!important; } |
| label, .label-wrap { color:#00ffcc88!important; font-size:10px!important; letter-spacing:2px!important; text-transform:uppercase!important; } |
| .gr-button { border-radius:0!important; font-family:'Share Tech Mono',monospace!important; letter-spacing:2px!important; } |
| .gr-button-primary { background:linear-gradient(135deg,#00ffcc22,#00ffcc44)!important; border:1px solid #00ffcc!important; color:#00ffcc!important; } |
| .gr-button-primary:hover { background:rgba(0,255,204,.3)!important; box-shadow:0 0 14px #00ffcc88!important; } |
| .gr-button-secondary { background:#000d1a!important; border:1px solid #00ffcc33!important; color:#00ffcc99!important; font-size:11px!important; } |
| .gr-button-secondary:hover { border-color:#00ffcc!important; color:#00ffcc!important; } |
| footer { display:none!important; } |
| """ |
|
|
| ZONE_CHOICES = ["Sunlit Zone (0-200m)","Twilight Zone (200-1000m)","Midnight Zone (1000-4000m)","Abyssal Zone (4000-6000m)","Hadal Zone (6000-11000m)"] |
| OCEAN_CHOICES = ["Pacific Ocean β Largest & Deepest","Atlantic Ocean β Mid-Atlantic Ridge","Indian Ocean β Warm Currents","Arctic Ocean β Permanent Ice Cap","Southern Ocean β Circumpolar Current"] |
| QUICK_Q = ["π¦ What lives in the Twilight Zone?","π‘ How does bioluminescence work?","π What lives near hydrothermal vents?","ποΈ Describe the Mariana Trench","π How do whales dive so deep?","π¬ Most bizarre Midnight Zone creature?"] |
|
|
| with gr.Blocks(title="OCEANUS β AR Ocean Explorer") as demo: |
| gr.HTML('<div class="oceanus-header"><p class="oceanus-title">β OCEANUS</p><p class="oceanus-sub">GOD\'S EYE β AR DEEP OCEAN EXPLORER Β· FREE Β· POWERED BY MISTRAL AI</p></div>') |
| gr.HTML(THREE_JS_HTML) |
| gr.HTML("<div style='height:14px'></div>") |
|
|
| with gr.Row(): |
| with gr.Column(scale=3): |
| gr.HTML("<p style='font-family:Orbitron,sans-serif;color:#00ffcc;font-size:13px;letter-spacing:3px;margin-bottom:8px;'>π§ OCEANUS AI ORACLE</p>") |
| |
| chatbot = gr.Chatbot( |
| label="", |
| height=400, |
| show_label=False, |
| value=INITIAL_MSG, |
| ) |
| with gr.Row(): |
| msg = gr.Textbox(placeholder="Ask OCEANUS... e.g. 'What lives at 10,000 meters?'", show_label=False, scale=5, lines=1) |
| btn = gr.Button("βΆ TRANSMIT", scale=1, variant="primary") |
|
|
| with gr.Column(scale=1): |
| gr.HTML("<p style='font-family:Orbitron,sans-serif;color:#00ffcc;font-size:11px;letter-spacing:3px;margin-bottom:8px;'>π‘ DIVE CONTROLS</p>") |
| zone_dd = gr.Dropdown(ZONE_CHOICES, value=ZONE_CHOICES[0], label="ACTIVE ZONE") |
| ocean_dd = gr.Dropdown(OCEAN_CHOICES, value=OCEAN_CHOICES[0], label="OCEAN REGION") |
| zone_md = gr.Markdown(get_zone_info(ZONE_CHOICES[0])) |
| gr.HTML("<p style='font-family:Orbitron,sans-serif;color:#00ffcc88;font-size:10px;letter-spacing:2px;margin:12px 0 8px;'>QUICK TRANSMISSIONS</p>") |
| for q in QUICK_Q: |
| gr.Button(q, size="sm", variant="secondary").click( |
| fn=lambda h, z, o, _q=q: quick_ask(_q, h, z, o), |
| inputs=[chatbot, zone_dd, ocean_dd], |
| outputs=[msg, chatbot], |
| ) |
|
|
| zone_dd.change(fn=get_zone_info, inputs=zone_dd, outputs=zone_md) |
| btn.click(fn=chat_with_oceanus, inputs=[msg, chatbot, zone_dd, ocean_dd], outputs=[msg, chatbot]) |
| msg.submit(fn=chat_with_oceanus, inputs=[msg, chatbot, zone_dd, ocean_dd], outputs=[msg, chatbot]) |
|
|
| demo.launch(css=CSS) |
|
|