| | import streamlit as st |
| | import os |
| | import torch |
| | from PIL import Image |
| | from transformers import AutoModelForCausalLM, AutoProcessor |
| |
|
| | |
| | |
| | |
| | |
| | config_dir = ".streamlit" |
| | if not os.path.exists(config_dir): |
| | os.makedirs(config_dir) |
| | with open(os.path.join(config_dir, "config.toml"), "w") as f: |
| | f.write("[server]\nenableXsrfProtection=false\nenableCORS=false\nmaxUploadSize=200\n") |
| |
|
| | |
| | |
| | |
| | st.set_page_config(page_title="SHINUI | Gemma AI", page_icon="✨", layout="wide") |
| |
|
| | @st.cache_resource |
| | def load_model(): |
| | model_id = "AarambhAI/gemma-like-multimodal-speech-vision-text" |
| | |
| | |
| | |
| | processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True) |
| | model = AutoModelForCausalLM.from_pretrained( |
| | model_id, |
| | torch_dtype=torch.float32, |
| | device_map="auto", |
| | trust_remote_code=True |
| | ) |
| | return model, processor |
| |
|
| | |
| | try: |
| | with st.spinner("Initializing Gemma Multimodal Model..."): |
| | model, processor = load_model() |
| | MODEL_LOADED = True |
| | except Exception as e: |
| | st.error(f"⚠️ Model Load Error: {e}") |
| | MODEL_LOADED = False |
| |
|
| | |
| | |
| | |
| | if 'page' not in st.session_state: st.session_state.page = 'landing' |
| | if 'logged_in' not in st.session_state: st.session_state.logged_in = False |
| | if 'user_email' not in st.session_state: st.session_state.user_email = "" |
| | if 'history' not in st.session_state: st.session_state.history = [] |
| | if 'result' not in st.session_state: st.session_state.result = None |
| |
|
| | |
| | |
| | |
| | def get_gemma_insight(input_type, content): |
| | if not MODEL_LOADED: |
| | return "Error: Model not loaded." |
| |
|
| | try: |
| | |
| | if input_type == "Image": |
| | text_prompt = "Analyze this medical image and list observations." |
| | |
| | |
| | inputs = processor(text=text_prompt, images=content, return_tensors="pt") |
| | |
| | |
| | with torch.no_grad(): |
| | output = model.generate(**inputs, max_new_tokens=200) |
| | |
| | return processor.batch_decode(output, skip_special_tokens=True)[0] |
| |
|
| | |
| | elif input_type == "Text": |
| | text_prompt = f"Medical analysis for: {content}" |
| | |
| | inputs = processor(text=text_prompt, return_tensors="pt") |
| | |
| | with torch.no_grad(): |
| | output = model.generate(**inputs, max_new_tokens=200) |
| | |
| | return processor.batch_decode(output, skip_special_tokens=True)[0] |
| |
|
| | except Exception as e: |
| | return f"⚠️ Processing Error: {str(e)}" |
| |
|
| | |
| | |
| | |
| | st.markdown(""" |
| | <style> |
| | @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;600;800&display=swap'); |
| | .stApp { |
| | background-color: #020617; |
| | background-image: radial-gradient(circle at 50% 0%, #1e293b 0%, #020617 70%); |
| | font-family: 'Plus Jakarta Sans', sans-serif; color: #f8fafc; |
| | } |
| | .shinui-card { |
| | background: rgba(30, 41, 59, 0.4); border: 1px solid rgba(148, 163, 184, 0.1); |
| | border-radius: 16px; padding: 25px; backdrop-filter: blur(12px); margin-bottom: 20px; |
| | } |
| | div.stButton > button { |
| | background: #38bdf8; color: #0f172a; border: none; font-weight: 700; |
| | padding: 12px 20px; border-radius: 8px; width: 100%; transition: all 0.3s; |
| | } |
| | div.stButton > button:hover { background: #ffffff; box-shadow: 0 0 20px rgba(56, 189, 248, 0.5); } |
| | #MainMenu, footer, header {visibility: hidden;} |
| | </style> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | |
| | |
| | def nav_to(page): |
| | st.session_state.page = page |
| | st.rerun() |
| |
|
| | def sign_out(): |
| | st.session_state.logged_in = False |
| | st.session_state.history = [] |
| | st.session_state.result = None |
| | st.session_state.user_email = "" |
| | nav_to('landing') |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | def show_landing(): |
| | c1, c2 = st.columns([1, 8]) |
| | with c1: st.markdown("### ✨ SHINUI") |
| | st.markdown("<br><br>", unsafe_allow_html=True) |
| | |
| | c1, c2 = st.columns([1.5, 1]) |
| | with c1: |
| | st.markdown(""" |
| | <h1 style='font-size: 4rem; line-height: 1.1; margin-bottom: 20px;'> |
| | Medical Intelligence.<br><span style='color:#38bdf8;'>Runs Locally.</span> |
| | </h1> |
| | <p style='font-size: 1.2rem; color: #94a3b8; margin-bottom: 40px;'> |
| | SHINUI runs the specialized Gemma Multimodal model for secure analysis. |
| | </p> |
| | """, unsafe_allow_html=True) |
| | b1, b2 = st.columns([1, 2]) |
| | with b1: |
| | if st.button("Sign In"): nav_to('login') |
| | with b2: |
| | if st.button("About SHINUI"): nav_to('about') |
| | |
| | with c2: |
| | st.markdown(""" |
| | <div class='shinui-card'> |
| | <h3>🧬 Gemma Multimodal</h3> |
| | <p style='color:#94a3b8;'>Vision, Text & Speech capable.</p> |
| | </div> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | def show_about(): |
| | if st.button("← Back Home"): nav_to('landing') |
| | st.markdown("<br>", unsafe_allow_html=True) |
| | st.markdown(""" |
| | <div class='shinui-card'> |
| | <h2 style='color:#38bdf8'>About SHINUI</h2> |
| | <p style='font-size:1.1rem; line-height:1.6'> |
| | SHINUI utilizes the <b>AarambhAI Gemma-like Multimodal</b> model. |
| | This model is unique because it understands images, text, and speech natively in a single architecture. |
| | </p> |
| | <hr style='border-color:#333'> |
| | <h3>Capabilities</h3> |
| | <ul> |
| | <li><b>Visual Diagnostics:</b> Reads medical images.</li> |
| | <li><b>Clinical Text:</b> Analyzes symptoms and notes.</li> |
| | </ul> |
| | </div> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | def show_login(): |
| | c1, c2, c3 = st.columns([1,1,1]) |
| | with c2: |
| | st.markdown("<br><br>", unsafe_allow_html=True) |
| | st.markdown("<div class='shinui-card' style='text-align:center;'><h2>Member Access</h2></div>", unsafe_allow_html=True) |
| | email = st.text_input("Email") |
| | password = st.text_input("Password", type="password") |
| | if st.button("Authenticate"): |
| | if email: |
| | st.session_state.logged_in = True |
| | st.session_state.user_email = email |
| | nav_to('dashboard') |
| | if st.button("Back"): nav_to('landing') |
| |
|
| | |
| | def show_dashboard(): |
| | with st.sidebar: |
| | st.markdown(f"### 👤 {st.session_state.user_email}") |
| | if st.button("About System"): nav_to('about_internal') |
| | st.markdown("---") |
| | st.write("HISTORY") |
| | if st.session_state.history: |
| | for h in reversed(st.session_state.history): |
| | st.markdown(f"<div style='font-size:0.8rem; padding:5px; border-left:2px solid #38bdf8; margin-bottom:5px;'>{h[:50]}...</div>", unsafe_allow_html=True) |
| | else: |
| | st.caption("No scans yet.") |
| | st.markdown("---") |
| | if st.button("Sign Out"): sign_out() |
| |
|
| | st.title("Gemma Interface") |
| | t1, t2 = st.tabs(["📷 Image Scan", "📝 Text Analysis"]) |
| |
|
| | |
| | with t1: |
| | st.markdown("<div class='shinui-card'>", unsafe_allow_html=True) |
| | img_file = st.file_uploader("Upload Medical Image", type=['png','jpg','jpeg']) |
| | if img_file and st.button("Analyze Visual"): |
| | if not MODEL_LOADED: |
| | st.error("Model failed to load (Check Space Logs).") |
| | else: |
| | image = Image.open(img_file) |
| | st.image(image, width=300) |
| | with st.spinner("Gemma Processing..."): |
| | res = get_gemma_insight("Image", image) |
| | st.session_state.result = res |
| | st.session_state.history.append(f"Image: {res[:30]}...") |
| | st.markdown("</div>", unsafe_allow_html=True) |
| |
|
| | |
| | with t2: |
| | st.markdown("<div class='shinui-card'>", unsafe_allow_html=True) |
| | txt = st.text_area("Clinical Notes / Symptoms") |
| | if txt and st.button("Analyze Notes"): |
| | if not MODEL_LOADED: |
| | st.error("Model failed to load.") |
| | else: |
| | with st.spinner("Gemma Processing..."): |
| | res = get_gemma_insight("Text", txt) |
| | st.session_state.result = res |
| | st.session_state.history.append(f"Text: {res[:30]}...") |
| | st.markdown("</div>", unsafe_allow_html=True) |
| |
|
| | if st.session_state.result: |
| | st.markdown(f""" |
| | <div class='shinui-card' style='border-left: 5px solid #38bdf8;'> |
| | <h3 style='margin-top:0; color:#38bdf8;'>Analysis Result</h3> |
| | <div style='white-space: pre-wrap; color: #e2e8f0; line-height: 1.6;'>{st.session_state.result}</div> |
| | </div> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | def show_about_internal(): |
| | with st.sidebar: |
| | if st.button("← Back"): nav_to('dashboard') |
| | st.markdown(""" |
| | <div class='shinui-card'> |
| | <h2 style='color:#38bdf8'>System Status</h2> |
| | <p><b>Model:</b> AarambhAI Gemma-like Multimodal</p> |
| | <p><b>Backend:</b> Local Transformers</p> |
| | </div> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | |
| | |
| | if st.session_state.page == 'landing': show_landing() |
| | elif st.session_state.page == 'about': show_about() |
| | elif st.session_state.page == 'login': show_login() |
| | elif st.session_state.page == 'dashboard': |
| | if st.session_state.logged_in: show_dashboard() |
| | else: nav_to('login') |
| | elif st.session_state.page == 'about_internal': |
| | if st.session_state.logged_in: show_about_internal() |
| | else: nav_to('login') |