ahmertalal commited on
Commit
8ae67d7
·
verified ·
1 Parent(s): 36f2ba5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +127 -31
src/streamlit_app.py CHANGED
@@ -1,9 +1,11 @@
1
  import streamlit as st
2
  import requests
3
  import time
 
 
4
 
5
- # Hugging Face API key from secrets
6
- API_KEY = st.secrets["API_KEY"]
7
  HEADERS = {"Authorization": f"Bearer {API_KEY}"}
8
 
9
  API_URLS = {
@@ -11,48 +13,142 @@ API_URLS = {
11
  "Sentiment": "https://api-inference.huggingface.co/models/finiteautomata/bertweet-base-sentiment-analysis"
12
  }
13
 
 
14
  def query(api_url, payload):
 
15
  try:
16
- res = requests.post(api_url, headers=HEADERS, json=payload, timeout=60)
17
- if res.status_code != 200:
18
- return {"error": f"HTTP {res.status_code}: {res.text}"}
19
- return res.json()
20
- except Exception as e:
21
- return {"error": str(e)}
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  st.set_page_config(page_title="NLP Toolkit", page_icon="🧠", layout="centered")
24
- st.title("🧠 AI NLP Toolkit")
25
- st.write("Summarization & Sentiment Analysis using Hugging Face APIs 🚀")
26
 
27
  tab1, tab2 = st.tabs(["📄 Summarizer", "📝 Sentiment Analysis"])
28
 
 
29
  with tab1:
30
- text = st.text_area("Enter text to summarize:", height=200)
31
- if st.button("Summarize"):
32
  if not text.strip():
33
- st.warning("Please enter some text.")
34
  else:
35
  with st.spinner("Generating summary..."):
36
- time.sleep(1)
37
- res = query(API_URLS["Summarizer"], {"inputs": text})
38
- if "error" in res:
39
- st.error(res["error"])
 
 
 
40
  else:
41
- st.success(" Summary Generated")
42
- st.write(res[0]['summary_text'])
43
 
 
44
  with tab2:
45
- text = st.text_area("Enter text for sentiment analysis:", height=200, key="sent_text")
46
- if st.button("Analyze Sentiment"):
47
- if not text.strip():
48
- st.warning("Please enter some text.")
49
  else:
50
- with st.spinner("Analyzing sentiment..."):
51
- time.sleep(1)
52
- res = query(API_URLS["Sentiment"], {"inputs": text})
53
- if "error" in res:
54
- st.error(res["error"])
55
  else:
56
- st.success("✅ Sentiment Analysis Complete")
57
- for item in res[0]:
58
- st.write(f"**{item['label']}** {item['score']:.2f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import requests
3
  import time
4
+ import re
5
+ import pandas as pd
6
 
7
+ # ==== CONFIG ====
8
+ API_KEY = st.secrets["API_KEY"] # Reads from Hugging Face / .streamlit/secrets.toml
9
  HEADERS = {"Authorization": f"Bearer {API_KEY}"}
10
 
11
  API_URLS = {
 
13
  "Sentiment": "https://api-inference.huggingface.co/models/finiteautomata/bertweet-base-sentiment-analysis"
14
  }
15
 
16
+ # ==== HELPERS ====
17
  def query(api_url, payload):
18
+ """Call Hugging Face inference API and return JSON or {'error':...}"""
19
  try:
20
+ resp = requests.post(api_url, headers=HEADERS, json=payload, timeout=60)
21
+ if resp.status_code != 200:
22
+ return {"error": f"HTTP {resp.status_code}: {resp.text}"}
23
+ return resp.json()
24
+ except requests.exceptions.RequestException as e:
25
+ return {"error": f"Request failed: {e}"}
26
 
27
+ def split_sentences(text: str):
28
+ """
29
+ Split text into sentences/phrases by ., ?, !, ;, :, comma and newlines.
30
+ Keeps things simple and avoids external tokenizers.
31
+ """
32
+ # Split on end punctuation + whitespace, OR on newline, OR on comma followed by space
33
+ parts = re.split(r'(?<=[.!?;:])\s+|\n+|(?<=,)\s+', text.strip())
34
+ # Filter empties and strip
35
+ return [p.strip() for p in parts if p and p.strip()]
36
+
37
+ def extract_scores_from_api_response(res):
38
+ """
39
+ Accepts HF response shapes like:
40
+ - [{'label': 'NEG', 'score': 0.86}, ...] OR
41
+ - [[{'label': 'NEG','score':...}, ...]] (nested list)
42
+ Returns a dict with numeric neg, neu, pos (floats 0..1) or None on unexpected.
43
+ """
44
+ sentiments = None
45
+ if isinstance(res, list):
46
+ # nested list (common with some HF endpoints)
47
+ if len(res) > 0 and isinstance(res[0], list):
48
+ sentiments = res[0]
49
+ # flat list
50
+ elif len(res) > 0 and isinstance(res[0], dict):
51
+ sentiments = res
52
+ if sentiments is None:
53
+ return None
54
+
55
+ neg = neu = pos = 0.0
56
+ for item in sentiments:
57
+ lab = item.get("label", "").upper()
58
+ sc = float(item.get("score", 0) or 0)
59
+ if "NEG" in lab:
60
+ neg = sc
61
+ elif "NEU" in lab:
62
+ neu = sc
63
+ elif "POS" in lab:
64
+ pos = sc
65
+ return {"neg": neg, "neu": neu, "pos": pos}
66
+
67
+ # ==== STREAMLIT UI ====
68
  st.set_page_config(page_title="NLP Toolkit", page_icon="🧠", layout="centered")
69
+ st.markdown("<h1 style='text-align: center; color: cyan;'>🧠 AI NLP Toolkit</h1>", unsafe_allow_html=True)
70
+ st.write("Summarization & sentence-wise Sentiment Analysis.")
71
 
72
  tab1, tab2 = st.tabs(["📄 Summarizer", "📝 Sentiment Analysis"])
73
 
74
+ # --- Summarizer (unchanged) ---
75
  with tab1:
76
+ text = st.text_area("Enter text to summarize:", height=220)
77
+ if st.button("Summarize📝"):
78
  if not text.strip():
79
+ st.warning("Please enter text.")
80
  else:
81
  with st.spinner("Generating summary..."):
82
+ time.sleep(0.8)
83
+ out = query(API_URLS["Summarizer"], {"inputs": text})
84
+ if "error" in out:
85
+ st.error(out["error"])
86
+ elif isinstance(out, list) and "summary_text" in out[0]:
87
+ st.success("Summary ready")
88
+ st.write(out[0]["summary_text"])
89
  else:
90
+ st.error("Unexpected response from summarizer.")
 
91
 
92
+ # --- Sentiment Analysis (sentence-wise, table + average) ---
93
  with tab2:
94
+ text_sent = st.text_area("Enter text for sentiment analysis:", height=220, key="sent_text2")
95
+ if st.button("Analyze Sentiment🧠"):
96
+ if not text_sent.strip():
97
+ st.warning("Please enter text.")
98
  else:
99
+ sentences = split_sentences(text_sent)
100
+ if len(sentences) == 0:
101
+ st.warning("No sentences found after splitting.")
 
 
102
  else:
103
+ rows = []
104
+ total_neg = total_neu = total_pos = 0.0
105
+ error_happened = False
106
+
107
+ with st.spinner("Analyzing sentences..."):
108
+ time.sleep(0.5)
109
+ for i, s in enumerate(sentences, start=1):
110
+ res = query(API_URLS["Sentiment"], {"inputs": s})
111
+ if isinstance(res, dict) and "error" in res:
112
+ st.error(f"API error for sentence {i}: {res['error']}")
113
+ error_happened = True
114
+ break
115
+
116
+ scores = extract_scores_from_api_response(res)
117
+ if scores is None:
118
+ st.error(f"Unexpected response format for sentence {i}.")
119
+ error_happened = True
120
+ break
121
+
122
+ neg_pct = round(scores["neg"] * 100)
123
+ neu_pct = round(scores["neu"] * 100)
124
+ pos_pct = round(scores["pos"] * 100)
125
+
126
+ rows.append({
127
+ "#": i,
128
+ "Sentence": f'"{s}"',
129
+ "Negative": f"{neg_pct}%",
130
+ "Neutral": f"{neu_pct}%",
131
+ "Positive": f"{pos_pct}%"
132
+ })
133
+
134
+ total_neg += scores["neg"]
135
+ total_neu += scores["neu"]
136
+ total_pos += scores["pos"]
137
+
138
+ if not error_happened:
139
+ n = len(sentences)
140
+ avg_neg = round((total_neg / n) * 100)
141
+ avg_neu = round((total_neu / n) * 100)
142
+ avg_pos = round((total_pos / n) * 100)
143
+
144
+ # Append average row
145
+ rows.append({
146
+ "#": "Avg",
147
+ "Sentence": "—",
148
+ "Negative": f"{avg_neg}%",
149
+ "Neutral": f"{avg_neu}%",
150
+ "Positive": f"{avg_pos}%"
151
+ })
152
+
153
+ df = pd.DataFrame(rows, columns=["#", "Sentence", "Negative", "Neutral", "Positive"])
154
+ st.table(df)