File size: 7,113 Bytes
ffbd3ab
 
 
 
442f5c5
ffbd3ab
442f5c5
7a36cad
91b9b3a
 
 
ffbd3ab
 
91b9b3a
442f5c5
ffbd3ab
 
2faf678
 
 
 
 
442f5c5
ffbd3ab
 
91b9b3a
 
efd5730
d125af0
91b9b3a
7a36cad
 
91b9b3a
 
7a36cad
 
 
 
91b9b3a
7a36cad
 
2faf678
91b9b3a
2faf678
91b9b3a
 
 
 
 
 
 
 
 
7a36cad
 
 
d125af0
7a36cad
d125af0
91b9b3a
9fae22e
7a36cad
2faf678
 
 
 
 
 
91b9b3a
7a36cad
75d538d
 
91b9b3a
 
 
 
 
 
 
 
 
efd5730
 
 
 
91b9b3a
75d538d
442f5c5
91b9b3a
ffbd3ab
442f5c5
 
91b9b3a
9fae22e
442f5c5
 
 
 
91b9b3a
7a36cad
442f5c5
 
9607fc6
91b9b3a
 
 
9fae22e
442f5c5
 
91b9b3a
 
442f5c5
91b9b3a
7a36cad
442f5c5
91b9b3a
75d538d
2faf678
91b9b3a
ffbd3ab
442f5c5
 
ffbd3ab
442f5c5
91b9b3a
442f5c5
 
91b9b3a
442f5c5
 
91b9b3a
442f5c5
 
 
 
 
 
 
91b9b3a
442f5c5
 
75d538d
7a36cad
 
75d538d
2faf678
75d538d
91b9b3a
442f5c5
 
 
 
 
2faf678
7a36cad
2faf678
 
442f5c5
 
 
2faf678
7a36cad
2faf678
 
91b9b3a
442f5c5
 
7a36cad
 
 
 
91b9b3a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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"
 
@st.cache_resource
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