Refat81 commited on
Commit
e88e50c
·
verified ·
1 Parent(s): 965cf87

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -337
app.py CHANGED
@@ -1,363 +1,116 @@
1
- # app.py - COMPLETE Google OAuth Version with Backward Compatibility
2
  import streamlit as st
3
- import requests
4
- import json
5
- import hashlib
6
- import hmac
7
- import secrets
8
- from datetime import datetime, timedelta
9
- import urllib.parse
10
 
11
- # ============================================
12
- # SECURITY MODULES
13
- # ============================================
 
14
 
15
- class GoogleAuth:
16
- def __init__(self):
17
- # Load from secrets
18
- self.client_id = st.secrets["google"]["client_id"]
19
- self.client_secret = st.secrets["google"]["client_secret"]
20
- self.redirect_uri = "https://refat81-social-media-data-extractor-chatbot.hf.space/oauth_callback"
21
-
22
- # Google OAuth endpoints
23
- self.auth_url = "https://accounts.google.com/o/oauth2/v2/auth"
24
- self.token_url = "https://oauth2.googleapis.com/token"
25
- self.userinfo_url = "https://www.googleapis.com/oauth2/v3/userinfo"
26
-
27
- def get_login_url(self):
28
- """Generate Google login URL"""
29
- params = {
30
- "client_id": self.client_id,
31
- "redirect_uri": self.redirect_uri,
32
- "response_type": "code",
33
- "scope": "openid email profile",
34
- "access_type": "offline",
35
- "prompt": "consent",
36
- "state": secrets.token_urlsafe(16)
37
- }
38
-
39
- url = f"{self.auth_url}?{urllib.parse.urlencode(params)}"
40
- return url
41
 
42
- class SessionManager:
43
- def __init__(self):
44
- self.secret_key = st.secrets["session"]["secret_key"]
 
 
 
 
45
 
46
- def create_session(self, user_info):
47
- """Create secure session"""
48
- session_data = {
49
- "session_id": secrets.token_urlsafe(32),
50
- "user_id": user_info.get("sub"),
51
- "email": user_info.get("email"),
52
- "name": user_info.get("name", "User"),
53
- "picture": user_info.get("picture", ""),
54
- "created_at": datetime.now().isoformat(),
55
- "expires_at": (datetime.now() + timedelta(hours=2)).isoformat(),
56
- "last_activity": datetime.now().isoformat()
57
- }
58
-
59
- # Add role (admin if email in admin list)
60
- admin_emails = st.secrets.get("admin_users", {}).get("users", [])
61
- session_data["role"] = "admin" if session_data["email"] in admin_emails else "user"
62
-
63
- # Sign the session
64
- session_data["signature"] = self._sign_session(session_data)
65
- return session_data
66
 
67
- def _sign_session(self, session_data):
68
- """Create HMAC signature"""
69
- data_str = json.dumps(session_data, sort_keys=True)
70
- return hmac.new(
71
- self.secret_key.encode(),
72
- data_str.encode(),
73
- hashlib.sha256
74
- ).hexdigest()
75
 
76
- def verify_session(self, session_data):
77
- """Verify session is valid"""
78
- if not session_data:
79
- return False
80
 
81
- # Check expiration
82
- expires_at = datetime.fromisoformat(session_data.get("expires_at", "2000-01-01"))
83
- if datetime.now() > expires_at:
84
- return False
85
 
86
- # Verify signature
87
- signature = session_data.pop("signature", None)
88
- expected_signature = self._sign_session(session_data)
89
- session_data["signature"] = signature
90
 
91
- return hmac.compare_digest(signature, expected_signature)
92
-
93
- def update_activity(self, session_data):
94
- """Update last activity time"""
95
- session_data["last_activity"] = datetime.now().isoformat()
96
- session_data["signature"] = self._sign_session(session_data)
97
-
98
- # ============================================
99
- # OAUTH CALLBACK HANDLER (FIXED)
100
- # ============================================
101
-
102
- def handle_oauth_callback():
103
- """Handle OAuth callback - compatible with all Streamlit versions"""
104
- # Get query params (backward compatible)
105
- try:
106
- # Streamlit 1.28+ method
107
- query_params = st.query_params
108
- is_new_streamlit = True
109
- except AttributeError:
110
- # Streamlit <1.28 method
111
- query_params = st.experimental_get_query_params()
112
- is_new_streamlit = False
113
-
114
- if "code" in query_params:
115
- # Extract code (different format in old vs new API)
116
- if is_new_streamlit:
117
- code = query_params.get("code", "")
118
- else:
119
- code_list = query_params.get("code", [])
120
- code = code_list[0] if code_list else ""
121
 
122
- if not code:
123
- return
 
 
124
 
125
- with st.spinner("🔐 Authenticating..."):
126
- # Exchange code for tokens
127
- auth = GoogleAuth()
128
- token_url = "https://oauth2.googleapis.com/token"
129
- data = {
130
- "client_id": auth.client_id,
131
- "client_secret": auth.client_secret,
132
- "code": code,
133
- "redirect_uri": auth.redirect_uri,
134
- "grant_type": "authorization_code"
135
- }
136
-
137
- response = requests.post(token_url, data=data)
138
- tokens = response.json()
139
-
140
- if "access_token" in tokens:
141
- # Get user info
142
- headers = {"Authorization": f"Bearer {tokens['access_token']}"}
143
- user_response = requests.get(auth.userinfo_url, headers=headers)
144
- user_info = user_response.json()
145
-
146
- # Create session
147
- session_mgr = SessionManager()
148
- session_data = session_mgr.create_session(user_info)
149
- st.session_state.session = session_data
150
- st.session_state.authenticated = True
151
-
152
- # Clear URL parameters
153
- if is_new_streamlit:
154
- st.query_params.clear()
155
- else:
156
- st.experimental_set_query_params()
157
-
158
- st.rerun()
159
- else:
160
- st.error("❌ Authentication failed")
161
-
162
- def is_authenticated():
163
- """Check if user is authenticated"""
164
- if "session" not in st.session_state:
165
- return False
166
-
167
- session_mgr = SessionManager()
168
- return session_mgr.verify_session(st.session_state.session)
169
-
170
- # ============================================
171
- # PAGE FUNCTIONS
172
- # ============================================
173
-
174
- def login_page():
175
- """Display login page"""
176
- st.set_page_config(page_title="Login", page_icon="🔒", layout="centered")
177
-
178
- # Center content
179
- col1, col2, col3 = st.columns([1, 2, 1])
180
-
181
- with col2:
182
- st.image("https://cdn-icons-png.flaticon.com/512/2991/2991148.png", width=100)
183
- st.title("🔐 Social Media Data Extractor")
184
- st.markdown("---")
185
- st.markdown("### Welcome! Please login to continue")
186
 
187
- # Google Login Button
188
- auth = GoogleAuth()
189
- login_url = auth.get_login_url()
190
 
191
- st.markdown(f"""
192
- <a href="{login_url}" style="text-decoration: none;">
193
- <div style="
194
- background-color: #4285F4;
195
- color: white;
196
- padding: 12px 24px;
197
- border-radius: 4px;
198
- border: none;
199
- cursor: pointer;
200
- font-size: 16px;
201
- font-weight: 500;
202
- display: flex;
203
- align-items: center;
204
- justify-content: center;
205
- gap: 10px;
206
- margin: 20px 0;
207
- ">
208
- <img src="https://cdn-icons-png.flaticon.com/512/2991/2991148.png" width="20" height="20">
209
- Sign in with Google
210
- </div>
211
- </a>
212
- """, unsafe_allow_html=True)
213
 
214
- st.markdown("---")
215
- st.info("""
216
- **Why login is required:**
217
- - Securely store your extracted data
218
- - Prevent unauthorized access
219
- - Track your usage history
220
- - Personalized experience
221
  """)
222
-
223
- def main_app():
224
- """Main app after authentication"""
225
- st.set_page_config(
226
- page_title="Social Media Data Extractor",
227
- page_icon="🔍",
228
- layout="wide"
229
- )
230
 
231
- # Update session activity
232
- session_mgr = SessionManager()
233
- session_mgr.update_activity(st.session_state.session)
 
 
 
 
 
 
234
 
235
- user = st.session_state.session
 
236
 
237
- # Sidebar with user info
238
- with st.sidebar:
239
- if user.get("picture"):
240
- st.image(user["picture"], width=80)
241
- else:
242
- st.image("https://cdn-icons-png.flaticon.com/512/149/149071.png", width=80)
243
-
244
- st.write(f"**👤 {user['name']}**")
245
- st.write(f"📧 {user['email']}")
246
- st.write(f"🎭 Role: {user['role']}")
247
-
248
- st.markdown("---")
249
-
250
- if st.button("🚪 Logout", use_container_width=True):
251
- for key in list(st.session_state.keys()):
252
- del st.session_state[key]
253
- st.rerun()
254
 
255
- # Main content - YOUR ORIGINAL DASHBOARD
256
- st.markdown("""
257
- <style>
258
- .stApp { background-color: #0e1117; color: white; }
259
- .main-header { background: linear-gradient(135deg, #1a2a6c, #b21f1f); color: white; padding: 2rem; border-radius: 10px; text-align: center; margin-bottom: 2rem; }
260
- .platform-card { background-color: #262730; padding: 1.5rem; border-radius: 10px; border-left: 4px solid; margin: 1rem 0; height: 280px; }
261
- .linkedin-card { border-left-color: #0077B5; }
262
- .facebook-card { border-left-color: #1877F2; }
263
- .facebook-pro-card { border-left-color: #FF6B35; }
264
- .feature-list { margin: 1rem 0; padding-left: 1.5rem; flex-grow: 1; }
265
- .api-key-section { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 1.5rem; border-radius: 10px; margin-bottom: 2rem; }
266
- </style>
267
- """, unsafe_allow_html=True)
268
-
269
- # Header
270
  st.markdown(f"""
271
- <div class="main-header">
272
- <h1 style="margin:0;">🔍 Social Media Data Extractor</h1>
273
- <p style="margin:0; opacity: 0.9;">Welcome back, {user['name']}! 👋</p>
274
- </div>
275
- """, unsafe_allow_html=True)
276
-
277
- # Platform selection
278
- st.markdown("## 🚀 Launch Extractors")
279
-
280
- col1, col2, col3 = st.columns(3)
281
-
282
- with col1:
283
- st.markdown("""
284
- <div class="platform-card linkedin-card">
285
- <h3>💼 LinkedIn Extractor</h3>
286
- <ul class="feature-list">
287
- <li>No login required</li>
288
- <li>Profile, company, and post analysis</li>
289
- <li>Quick data extraction</li>
290
- <li>AI-powered insights</li>
291
- <li>100% Free</li>
292
- </ul>
293
  </div>
294
- """, unsafe_allow_html=True)
295
-
296
- if st.button("🚀 Launch LinkedIn Extractor", key="linkedin_btn", use_container_width=True):
297
- st.switch_page("pages/linkedin_extractor.py")
298
-
299
- with col2:
300
- st.markdown("""
301
- <div class="platform-card facebook-card">
302
- <h3>📘 Facebook Extractor</h3>
303
- <ul class="feature-list">
304
- <li>Manual login required</li>
305
- <li>Group post extraction</li>
306
- <li>Works with private groups</li>
307
- <li>AI conversation analysis</li>
308
- <li>100% Free</li>
309
- </ul>
310
- </div>
311
- """, unsafe_allow_html=True)
312
-
313
- if st.button("🚀 Launch Facebook Extractor", key="facebook_btn", use_container_width=True):
314
- st.switch_page("pages/facebook_extractor.py")
315
-
316
- with col3:
317
- st.markdown("""
318
- <div class="platform-card facebook-pro-card">
319
- <h3>🔥 Facebook Extractor 2.0</h3>
320
- <ul class="feature-list">
321
- <li>Enhanced Facebook data extraction</li>
322
- <li>More powerful algorithms</li>
323
- <li>Faster processing speed</li>
324
- <li>Advanced AI analysis</li>
325
- <li>100% Free</li>
326
- </ul>
327
- </div>
328
- """, unsafe_allow_html=True)
329
-
330
- if st.button("🚀 Launch Facebook Extractor 2.0", key="facebook_pro_btn", use_container_width=True):
331
- st.switch_page("pages/facebook_extractor_pro.py")
332
-
333
- # Instructions
334
- with st.expander("📋 How to Use", expanded=True):
335
- st.markdown(f"""
336
- 1. **Click any extractor to launch**
337
- 2. **For LinkedIn:** Enter any LinkedIn URL
338
- 3. **For Facebook:** Public data extraction available
339
- 4. **AI Analysis:** Chat with extracted data
340
-
341
- **Note:** All extractors are 100% free and require no local setup.
342
-
343
- **Logged in as:** {user['email']}
344
- **Session expires:** {datetime.fromisoformat(user['expires_at']).strftime('%I:%M %p')}
345
- """)
346
-
347
- # ============================================
348
- # MAIN APP ROUTING
349
- # ============================================
350
-
351
- def main():
352
- """Main routing function"""
353
- # Handle OAuth callback if coming from Google
354
- handle_oauth_callback()
355
 
356
- # Check authentication
357
- if not is_authenticated():
358
- login_page()
359
- else:
360
- main_app()
361
 
362
  if __name__ == "__main__":
363
  main()
 
1
+ # app.py - WORKING VERSION WITH ERROR HANDLING
2
  import streamlit as st
3
+ import os
4
+ import sys
 
 
 
 
 
5
 
6
+ # Debug: Force print to see what's happening
7
+ print("=== STARTING APP ===", file=sys.stderr)
8
+ print(f"Current directory: {os.getcwd()}", file=sys.stderr)
9
+ print(f"Files: {os.listdir('.')}", file=sys.stderr)
10
 
11
+ # Check for .streamlit folder
12
+ if os.path.exists('.streamlit'):
13
+ print(f".streamlit contents: {os.listdir('.streamlit')}", file=sys.stderr)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # Simple app that works even without secrets
16
+ def main():
17
+ st.set_page_config(
18
+ page_title="Social Media Data Extractor",
19
+ page_icon="🔍",
20
+ layout="wide"
21
+ )
22
 
23
+ # Try to load secrets
24
+ try:
25
+ # This will fail if secrets aren't loaded
26
+ test = st.secrets
27
+ print(f"Secrets loaded: {list(test.keys())}", file=sys.stderr)
28
+ secrets_loaded = True
29
+ except:
30
+ print("Secrets NOT loaded", file=sys.stderr)
31
+ secrets_loaded = False
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ # Header
34
+ st.title("🔐 Social Media Data Extractor")
35
+ st.markdown("---")
 
 
 
 
 
36
 
37
+ if not secrets_loaded:
38
+ st.error("""
39
+ ⚠️ **Configuration Error - Secrets Not Loaded**
 
40
 
41
+ **Please check:**
 
 
 
42
 
43
+ 1. **HuggingFace Secrets** are configured in Space Settings
44
+ 2. Secret name is exactly: `STREAMLIT_SECRETS_TOML`
45
+ 3. The secret contains valid TOML format
 
46
 
47
+ **To fix this:**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ 1. Go to your Space: https://huggingface.co/spaces/Refat81/Social_Media_Data_Extractor_Chatbot/settings
50
+ 2. Click "Repository secrets"
51
+ 3. Add a secret named: `STREAMLIT_SECRETS_TOML`
52
+ 4. Paste this (with your actual values):
53
 
54
+ ```toml
55
+ [google]
56
+ client_id = "your-client-id.apps.googleusercontent.com"
57
+ client_secret = "your-client-secret"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ [session]
60
+ secret_key = "LXr9Q2v8bPp1Yt6zMk5w7x0aS3dFg4hJ7n8cV2bN5m8q9T1y3U6i0o"
 
61
 
62
+ [api_keys]
63
+ huggingface_token = "your-hf-token"
64
+ ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ 5. Click "Save"
67
+ 6. Restart the Space
 
 
 
 
 
68
  """)
69
+ return
 
 
 
 
 
 
 
70
 
71
+ # If secrets are loaded, check if Google OAuth is configured
72
+ try:
73
+ client_id = st.secrets["google"]["client_id"]
74
+ if client_id == "placeholder-client-id":
75
+ st.warning("⚠️ Using placeholder credentials. Please add real Google OAuth credentials.")
76
+ return
77
+ except:
78
+ st.error("Google OAuth not configured in secrets")
79
+ return
80
 
81
+ # Show login button
82
+ st.markdown("### Welcome! Please login to continue")
83
 
84
+ # Create login URL
85
+ redirect_uri = "https://refat81-social-media-data-extractor-chatbot.hf.space/oauth_callback"
86
+ login_url = f"https://accounts.google.com/o/oauth2/v2/auth?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=openid%20email%20profile&access_type=offline&prompt=consent"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  st.markdown(f"""
89
+ <a href="{login_url}" target="_self">
90
+ <div style="
91
+ background-color: #4285F4;
92
+ color: white;
93
+ padding: 15px 30px;
94
+ border-radius: 8px;
95
+ border: none;
96
+ cursor: pointer;
97
+ font-size: 16px;
98
+ font-weight: 500;
99
+ text-align: center;
100
+ margin: 20px 0;
101
+ display: inline-block;
102
+ ">
103
+ <img src="https://cdn-icons-png.flaticon.com/512/2991/2991148.png" width="20" height="20" style="vertical-align: middle; margin-right: 10px;">
104
+ Sign in with Google
 
 
 
 
 
 
105
  </div>
106
+ </a>
107
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
+ st.markdown("---")
110
+ st.info("""
111
+ **Note:** First-time login might show "App not verified" warning.
112
+ Click "Continue" to proceed (this is normal for testing).
113
+ """)
114
 
115
  if __name__ == "__main__":
116
  main()