Spaces:
Running
Running
| import streamlit as st | |
| from transformers import pipeline | |
| import pandas as pd | |
| from datetime import datetime | |
| import time | |
| import plotly.graph_objects as go | |
| import json | |
| import os | |
| import gspread | |
| from google.oauth2.service_account import Credentials | |
| # --- PAGE CONFIG --- | |
| st.set_page_config(page_title="Sentiment Analyzer AI | Bilingual Engine", page_icon="π", layout="wide") | |
| # --- PROFESSIONAL NEUMORPHIC / GLASS CSS --- | |
| st.markdown(""" | |
| <style> | |
| .stApp { background: linear-gradient(135deg, #12141d 0%, #1a1c2c 100%); color: #ffffff; } | |
| div[data-baseweb="input"] { background: rgba(255, 255, 255, 0.05) !important; backdrop-filter: blur(10px) !important; border-radius: 15px !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; padding: 5px !important; } | |
| .glass-card { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.1); padding: 30px; margin-top: 20px; margin-bottom: 25px; transition: 0.4s ease; } | |
| .stButton>button { background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%); color: white; border: none; border-radius: 12px; font-weight: 600; letter-spacing: 0.5px; height: 3rem; transition: all 0.3s ease; } | |
| .stButton>button:hover { box-shadow: 0 0 20px rgba(79, 172, 254, 0.4); transform: scale(1.02); } | |
| [data-testid="stMetricValue"] { color: #00f2fe; font-weight: 800; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- GOOGLE SHEETS CONNECTION (gspread - works in Docker) --- | |
| def get_connection(): | |
| try: | |
| # Docker Spaces inject secrets as ENV VARS | |
| json_secrets = os.environ.get("GSHEETS_JSON") | |
| sheet_url = os.environ.get("GSHEETS_URL") | |
| # Fallback for local development | |
| if not json_secrets: | |
| json_secrets = st.secrets.get("GSHEETS_JSON") | |
| if not sheet_url: | |
| sheet_url = st.secrets.get("GSHEETS_URL") | |
| if not json_secrets or not sheet_url: | |
| st.error("β Secrets not found. Please add GSHEETS_JSON and GSHEETS_URL in Space Settings β Secrets.") | |
| st.stop() | |
| creds_dict = json.loads(json_secrets) | |
| scopes = [ | |
| "https://spreadsheets.google.com/feeds", | |
| "https://www.googleapis.com/auth/drive" | |
| ] | |
| creds = Credentials.from_service_account_info(creds_dict, scopes=scopes) | |
| client = gspread.authorize(creds) | |
| sheet = client.open_by_url(sheet_url).worksheet("Sheet1") | |
| return sheet, sheet_url | |
| except json.JSONDecodeError: | |
| st.error("β GSHEETS_JSON is not valid JSON. Please re-paste your service account key.") | |
| st.stop() | |
| except Exception as e: | |
| st.error(f"β Connection Failed: {e}") | |
| st.stop() | |
| # --- INITIALIZATION --- | |
| if 'conn' not in st.session_state or 'url' not in st.session_state: | |
| conn, GSHEETS_URL = get_connection() | |
| st.session_state.conn = conn | |
| st.session_state.url = GSHEETS_URL | |
| else: | |
| conn = st.session_state.conn | |
| GSHEETS_URL = st.session_state.url | |
| # --- SAVE TO GOOGLE SHEETS --- | |
| def save_to_cloud(text, ai_label, ai_score, corrected_label=None): | |
| try: | |
| sheet = st.session_state.conn | |
| new_row = [ | |
| datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | |
| text, | |
| ai_label, | |
| f"{ai_score:.2%}", | |
| corrected_label if corrected_label else "N/A" | |
| ] | |
| sheet.append_row(new_row) | |
| return True | |
| except Exception as e: | |
| st.error(f"Cloud Save Failed: {e}") | |
| return False | |
| # --- MODEL ENGINE --- | |
| MODEL_PATH = "SumedhGajbhiye/Sentiment-Analyzer" | |
| def load_engine(path): | |
| return pipeline("sentiment-analysis", model=path, tokenizer=path) | |
| # --- UI LAYOUT --- | |
| col_h1, col_h2 = st.columns([3, 1]) | |
| with col_h1: | |
| st.title("Sentiment Analyzer") | |
| st.caption("Advanced Bilingual Sentiment Analysis for English, Hindi & Hinglish") | |
| # --- SIDEBAR STATS --- | |
| with st.sidebar: | |
| st.markdown("### π οΈ ENGINE STATUS") | |
| try: | |
| sheet = st.session_state.conn | |
| all_rows = sheet.get_all_records() | |
| df_log = pd.DataFrame(all_rows) | |
| st.metric("Total Ingested", len(df_log)) | |
| st.divider() | |
| st.download_button("π€ Export Dataset", df_log.to_csv(index=False), "engine_feedback.csv", "text/csv") | |
| except Exception: | |
| df_log = pd.DataFrame() | |
| st.info("Engine is connecting to cloud...") | |
| # --- MAIN LOGIC --- | |
| classifier = load_engine(MODEL_PATH) | |
| if classifier: | |
| user_input = st.text_input("QUERY INPUT:", placeholder="Enter sentence...", key="main_input", label_visibility="collapsed") | |
| if user_input: | |
| with st.status("Initializing Neural Weights...", expanded=False) as status: | |
| time.sleep(0.4) | |
| result = classifier(user_input)[0] | |
| status.update(label="Analysis Complete", state="complete", expanded=False) | |
| label = result['label'] | |
| score = result['score'] | |
| emoji_map = {"Positive": "π’", "Neutral": "π‘", "Negative": "π΄"} | |
| color = "#00ff88" if "POS" in label.upper() else "#ff4b4b" if "NEG" in label.upper() else "#ffaa00" | |
| st.markdown(f''' | |
| <div class="glass-card"> | |
| <h4 style="color: #888; margin:0;">CLASSIFICATION RESULT</h4> | |
| <h1 style="color: {color}; margin:0; font-size: 3.5rem;">{label} {emoji_map.get(label, "")}</h1> | |
| <p style="color: #aaa; margin-top: 10px;">Deep linguistic scan detected {label.lower()} intent with {score:.1%} confidence.</p> | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| col_chart, col_feed = st.columns([1, 2]) | |
| with col_chart: | |
| fig = go.Figure(go.Indicator( | |
| mode="gauge+number", value=score * 100, | |
| gauge={'axis': {'range': [None, 100]}, 'bar': {'color': color}, 'bgcolor': "rgba(0,0,0,0)"} | |
| )) | |
| fig.update_layout(height=280, margin=dict(t=50, b=50, l=40, r=40), paper_bgcolor='rgba(0,0,0,0)', font={'color': "#fff"}) | |
| st.plotly_chart(fig, use_container_width=True) | |
| with col_feed: | |
| st.markdown("### βοΈ HUMAN VERIFICATION") | |
| c1, c2 = st.columns(2) | |
| with c1: | |
| if st.button("CONFIRM ACCURACY"): | |
| if save_to_cloud(user_input, label, score): | |
| st.toast("β Logic logged to cloud database.") | |
| time.sleep(1.0) | |
| st.rerun() | |
| with c2: | |
| correction = st.selectbox("OVERRIDE LABEL:", ["Positive", "Neutral", "Negative"]) | |
| if st.button("FORCE UPDATE ENGINE"): | |
| if save_to_cloud(user_input, label, score, corrected_label=correction): | |
| st.toast(f"β Engine forced to {correction}") | |
| time.sleep(1.0) | |
| st.rerun() | |
| # --- RECENT LOGS --- | |
| try: | |
| if not df_log.empty: | |
| with st.expander("π VIEW SYSTEM LOGS"): | |
| st.dataframe(df_log.tail(10), use_container_width=True) | |
| except Exception: | |
| pass | |