Refat81 commited on
Commit
2238e58
Β·
verified Β·
1 Parent(s): 247c0ad

Create facebook_extractor_pro.py

Browse files
Files changed (1) hide show
  1. pages/facebook_extractor_pro.py +581 -0
pages/facebook_extractor_pro.py ADDED
@@ -0,0 +1,581 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # let_deploy.py
2
+ import streamlit as st
3
+ import time
4
+ from bs4 import BeautifulSoup
5
+ from langchain_text_splitters import CharacterTextSplitter
6
+ from langchain_community.embeddings import HuggingFaceEmbeddings
7
+ from langchain_community.vectorstores import FAISS
8
+ from langchain.memory import ConversationBufferMemory
9
+ from langchain.chains import ConversationalRetrievalChain
10
+ from langchain_core.documents import Document
11
+ from langchain_community.llms import HuggingFaceHub
12
+ import re
13
+ import requests
14
+ import os
15
+ from datetime import datetime
16
+ from typing import List
17
+ import logging
18
+
19
+ # Configure logging
20
+ logging.basicConfig(level=logging.INFO)
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # Page configuration
24
+ st.set_page_config(
25
+ page_title="Facebook Extractor 2.0",
26
+ page_icon="πŸ“˜",
27
+ layout="wide"
28
+ )
29
+
30
+ # Custom CSS
31
+ st.markdown("""
32
+ <style>
33
+ .stApp {
34
+ background-color: #0e1117;
35
+ color: white;
36
+ }
37
+ .main-header {
38
+ background: linear-gradient(135deg, #FF6B35, #FF8E53);
39
+ color: white;
40
+ padding: 2rem;
41
+ border-radius: 10px;
42
+ margin-bottom: 2rem;
43
+ text-align: center;
44
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
45
+ }
46
+ .feature-card {
47
+ background: #1e1e1e;
48
+ padding: 1.5rem;
49
+ border-radius: 10px;
50
+ border-left: 4px solid #FF6B35;
51
+ margin: 1rem 0;
52
+ }
53
+ .status-indicator {
54
+ padding: 0.5rem 1rem;
55
+ border-radius: 20px;
56
+ font-weight: bold;
57
+ text-align: center;
58
+ }
59
+ .status-success {
60
+ background: #10b981;
61
+ color: white;
62
+ }
63
+ .status-warning {
64
+ background: #f59e0b;
65
+ color: white;
66
+ }
67
+ .status-error {
68
+ background: #ef4444;
69
+ color: white;
70
+ }
71
+ .chat-message {
72
+ padding: 1rem;
73
+ border-radius: 10px;
74
+ margin: 0.5rem 0;
75
+ }
76
+ .user-message {
77
+ background: #1e40af;
78
+ color: white;
79
+ }
80
+ .assistant-message {
81
+ background: #374151;
82
+ color: white;
83
+ }
84
+ </style>
85
+ """, unsafe_allow_html=True)
86
+
87
+ def get_embeddings():
88
+ """Initialize HuggingFace embeddings"""
89
+ try:
90
+ embeddings = HuggingFaceEmbeddings(
91
+ model_name="sentence-transformers/all-MiniLM-L6-v2"
92
+ )
93
+ return embeddings
94
+ except Exception as e:
95
+ st.error(f"❌ Failed to load embeddings: {e}")
96
+ return None
97
+
98
+ def get_llm():
99
+ """Initialize HuggingFace LLM"""
100
+ try:
101
+ api_key = os.getenv('HUGGINGFACEHUB_API_TOKEN')
102
+ if not api_key:
103
+ st.error("❌ HuggingFace API Key not found in environment variables")
104
+ return None
105
+
106
+ llm = HuggingFaceHub(
107
+ repo_id="google/flan-t5-large",
108
+ huggingfacehub_api_token=api_key,
109
+ model_kwargs={
110
+ "temperature": 0.7,
111
+ "max_length": 512,
112
+ "top_p": 0.9,
113
+ "top_k": 50
114
+ }
115
+ )
116
+ return llm
117
+ except Exception as e:
118
+ st.error(f"❌ HuggingFace error: {e}")
119
+ return None
120
+
121
+ class FacebookDataExtractor:
122
+ """Enhanced Facebook data extractor using requests only"""
123
+
124
+ def __init__(self):
125
+ self.session = requests.Session()
126
+ self.setup_session()
127
+
128
+ def setup_session(self):
129
+ """Setup requests session with headers"""
130
+ self.session.headers.update({
131
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
132
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
133
+ 'Accept-Language': 'en-US,en;q=0.5',
134
+ 'Accept-Encoding': 'gzip, deflate, br',
135
+ 'DNT': '1',
136
+ 'Connection': 'keep-alive',
137
+ 'Upgrade-Insecure-Requests': '1',
138
+ })
139
+
140
+ def extract_public_data(self, url: str, data_type: str) -> dict:
141
+ """Extract public data from Facebook URLs"""
142
+ try:
143
+ st.info(f"🌐 Accessing: {url}")
144
+
145
+ response = self.session.get(url, timeout=15)
146
+
147
+ if response.status_code != 200:
148
+ return {
149
+ "error": f"Failed to access page (Status: {response.status_code})",
150
+ "status": "error"
151
+ }
152
+
153
+ soup = BeautifulSoup(response.text, 'html.parser')
154
+
155
+ # Remove scripts and styles
156
+ for script in soup(["script", "style", "meta", "link"]):
157
+ script.decompose()
158
+
159
+ # Extract meaningful text
160
+ text = soup.get_text()
161
+ lines = (line.strip() for line in text.splitlines())
162
+ chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
163
+ clean_text = ' '.join(chunk for chunk in chunks if chunk)
164
+
165
+ # Extract page title
166
+ title = soup.find('title')
167
+ page_title = title.text.strip() if title else "Unknown"
168
+
169
+ # Extract meta description
170
+ meta_desc = soup.find('meta', attrs={'name': 'description'})
171
+ description = meta_desc['content'] if meta_desc else ""
172
+
173
+ # Extract Open Graph data
174
+ og_title = soup.find('meta', property='og:title')
175
+ og_description = soup.find('meta', property='og:description')
176
+ og_image = soup.find('meta', property='og:image')
177
+
178
+ # Structure the extracted data
179
+ extracted_data = {
180
+ "page_info": {
181
+ "title": page_title,
182
+ "description": description,
183
+ "og_title": og_title['content'] if og_title else "",
184
+ "og_description": og_description['content'] if og_description else "",
185
+ "og_image": og_image['content'] if og_image else "",
186
+ "url": url
187
+ },
188
+ "content_blocks": self._extract_content_blocks(clean_text),
189
+ "extraction_time": datetime.now().isoformat(),
190
+ "data_type": data_type,
191
+ "status": "success"
192
+ }
193
+
194
+ return extracted_data
195
+
196
+ except requests.exceptions.Timeout:
197
+ return {"error": "Request timed out", "status": "error"}
198
+ except requests.exceptions.ConnectionError:
199
+ return {"error": "Connection failed", "status": "error"}
200
+ except Exception as e:
201
+ logger.error(f"Extraction error: {str(e)}")
202
+ return {"error": f"Extraction failed: {str(e)}", "status": "error"}
203
+
204
+ def _extract_content_blocks(self, text: str) -> List[dict]:
205
+ """Extract meaningful content blocks from text"""
206
+ blocks = []
207
+
208
+ # Split into paragraphs/sentences
209
+ paragraphs = [p.strip() for p in text.split('.') if p.strip()]
210
+
211
+ for i, paragraph in enumerate(paragraphs[:20]): # Limit to first 20 paragraphs
212
+ if len(paragraph) > 30: # Only include substantial content
213
+ block = {
214
+ "id": i + 1,
215
+ "content": paragraph,
216
+ "length": len(paragraph),
217
+ "word_count": len(paragraph.split())
218
+ }
219
+ blocks.append(block)
220
+
221
+ return blocks
222
+
223
+ def analyze_facebook_url(self, url: str) -> str:
224
+ """Analyze Facebook URL and return structured information"""
225
+ url_lower = url.lower()
226
+
227
+ if 'groups' in url_lower:
228
+ return "Facebook Group (Limited access - requires login)"
229
+ elif 'pages' in url_lower:
230
+ return "Facebook Page (Public data accessible)"
231
+ elif 'events' in url_lower:
232
+ return "Facebook Event (Limited access)"
233
+ elif 'profile' in url_lower or 'user' in url_lower:
234
+ return "Facebook Profile (Limited access - requires login)"
235
+ else:
236
+ return "Facebook Content (General)"
237
+
238
+ def process_extracted_data(extracted_data: dict):
239
+ """Process extracted data for chatbot"""
240
+ if not extracted_data or extracted_data.get("status") != "success":
241
+ return None, []
242
+
243
+ # Combine all content into a single text
244
+ all_text = f"Page Title: {extracted_data['page_info']['title']}\n\n"
245
+
246
+ if extracted_data['page_info']['description']:
247
+ all_text += f"Description: {extracted_data['page_info']['description']}\n\n"
248
+
249
+ if extracted_data['page_info']['og_description']:
250
+ all_text += f"OpenGraph Description: {extracted_data['page_info']['og_description']}\n\n"
251
+
252
+ all_text += f"Data Type: {extracted_data['data_type']}\n"
253
+ all_text += f"Extraction Time: {extracted_data['extraction_time']}\n"
254
+ all_text += f"Content Blocks: {len(extracted_data['content_blocks'])}\n\n"
255
+
256
+ # Add content blocks
257
+ for i, block in enumerate(extracted_data['content_blocks']):
258
+ all_text += f"--- Content Block {i+1} ---\n"
259
+ all_text += f"Words: {block['word_count']} | Characters: {block['length']}\n"
260
+ all_text += f"Content: {block['content']}\n\n"
261
+
262
+ # Split into chunks
263
+ splitter = CharacterTextSplitter(
264
+ separator="\n",
265
+ chunk_size=800,
266
+ chunk_overlap=150,
267
+ length_function=len
268
+ )
269
+
270
+ chunks = splitter.split_text(all_text)
271
+ documents = [Document(page_content=chunk) for chunk in chunks]
272
+
273
+ # Create vector store
274
+ try:
275
+ embeddings = get_embeddings()
276
+ if embeddings is None:
277
+ return None, []
278
+ vectorstore = FAISS.from_documents(documents, embeddings)
279
+ return vectorstore, chunks
280
+ except Exception as e:
281
+ st.error(f"Vector store creation failed: {e}")
282
+ return None, []
283
+
284
+ def create_chatbot(vectorstore):
285
+ """Create conversational chatbot"""
286
+ try:
287
+ llm = get_llm()
288
+ if llm is None:
289
+ return None
290
+
291
+ memory = ConversationBufferMemory(
292
+ memory_key="chat_history",
293
+ return_messages=True,
294
+ output_key="answer"
295
+ )
296
+
297
+ chain = ConversationalRetrievalChain.from_llm(
298
+ llm=llm,
299
+ retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
300
+ memory=memory,
301
+ return_source_documents=True,
302
+ output_key="answer"
303
+ )
304
+ return chain
305
+ except Exception as e:
306
+ st.error(f"Failed to create chatbot: {str(e)}")
307
+ return None
308
+
309
+ def clear_chat_history():
310
+ """Clear chat history while keeping extracted data"""
311
+ if "vectorstore" in st.session_state and st.session_state.vectorstore:
312
+ st.session_state.chatbot = create_chatbot(st.session_state.vectorstore)
313
+ st.session_state.chat_history = []
314
+ st.success("πŸ”„ Chat history cleared! Starting fresh conversation.")
315
+
316
+ def display_status_indicator(status: str, message: str):
317
+ """Display status indicator"""
318
+ status_class = {
319
+ "success": "status-success",
320
+ "warning": "status-warning",
321
+ "error": "status-error"
322
+ }.get(status, "status-warning")
323
+
324
+ st.markdown(f"""
325
+ <div class="status-indicator {status_class}">
326
+ {message}
327
+ </div>
328
+ """, unsafe_allow_html=True)
329
+
330
+ def main():
331
+ """Main application function"""
332
+
333
+ # Header
334
+ st.markdown("""
335
+ <div class="main-header">
336
+ <h1 style="margin:0; font-size: 2.5rem;">πŸ”₯ Facebook Extractor 2.0</h1>
337
+ <p style="margin:0; opacity: 0.9; font-size: 1.2rem;">Enhanced Version - AI-Powered Analysis</p>
338
+ </div>
339
+ """, unsafe_allow_html=True)
340
+
341
+ # Navigation
342
+ col1, col2 = st.columns([1, 4])
343
+ with col1:
344
+ if st.button("← Back to Main", use_container_width=True):
345
+ st.switch_page("app.py")
346
+
347
+ # Check API key
348
+ if not os.getenv('HUGGINGFACEHUB_API_TOKEN'):
349
+ st.error("""
350
+ ❌ HuggingFace API Key not configured!
351
+
352
+ Please add your API key to Hugging Face Space settings:
353
+ 1. Go to your Space Settings
354
+ 2. Click "Repository Secrets"
355
+ 3. Add: `HUGGINGFACEHUB_API_TOKEN = "your_token_here"`
356
+ 4. Restart the Space
357
+ """)
358
+ return
359
+
360
+ # Initialize session state
361
+ if "extractor" not in st.session_state:
362
+ st.session_state.extractor = FacebookDataExtractor()
363
+ if "extracted_data" not in st.session_state:
364
+ st.session_state.extracted_data = None
365
+ if "vectorstore" not in st.session_state:
366
+ st.session_state.vectorstore = None
367
+ if "chatbot" not in st.session_state:
368
+ st.session_state.chatbot = None
369
+ if "chat_history" not in st.session_state:
370
+ st.session_state.chat_history = []
371
+ if "processing" not in st.session_state:
372
+ st.session_state.processing = False
373
+
374
+ # Sidebar
375
+ with st.sidebar:
376
+ st.markdown("### βš™οΈ Configuration")
377
+
378
+ # URL input
379
+ st.subheader("πŸ”— Facebook URL")
380
+ facebook_url = st.text_input(
381
+ "Enter Facebook URL",
382
+ placeholder="https://www.facebook.com/username/...",
383
+ help="Enter public Facebook URL (pages work best)"
384
+ )
385
+
386
+ # Data type selection
387
+ data_type = st.selectbox(
388
+ "Content Type",
389
+ ["page", "group", "profile", "event", "post"],
390
+ help="Select the type of Facebook content"
391
+ )
392
+
393
+ # Extraction settings
394
+ st.subheader("πŸ”§ Settings")
395
+ analyze_depth = st.select_slider(
396
+ "Analysis Depth",
397
+ options=["Basic", "Standard", "Detailed"],
398
+ value="Standard"
399
+ )
400
+
401
+ # Extract button
402
+ if st.button("πŸš€ Extract & Analyze", type="primary", use_container_width=True):
403
+ if not facebook_url.strip():
404
+ st.warning("⚠️ Please enter a Facebook URL")
405
+ elif not facebook_url.startswith('https://www.facebook.com/'):
406
+ st.error("❌ Please enter a valid Facebook URL")
407
+ else:
408
+ st.session_state.processing = True
409
+ with st.spinner("πŸ”„ Extracting data from Facebook..."):
410
+ extracted_data = st.session_state.extractor.extract_public_data(facebook_url, data_type)
411
+
412
+ if extracted_data.get("status") == "success":
413
+ st.session_state.extracted_data = extracted_data
414
+
415
+ # Process for chatbot
416
+ vectorstore, chunks = process_extracted_data(extracted_data)
417
+ if vectorstore:
418
+ st.session_state.vectorstore = vectorstore
419
+ st.session_state.chatbot = create_chatbot(vectorstore)
420
+ st.session_state.chat_history = []
421
+ st.success(f"βœ… Successfully processed {len(chunks)} content chunks!")
422
+ else:
423
+ st.error("❌ Failed to process extracted data")
424
+ else:
425
+ error_msg = extracted_data.get("error", "Unknown error occurred")
426
+ st.error(f"❌ Extraction failed: {error_msg}")
427
+
428
+ st.session_state.processing = False
429
+
430
+ # Chat management
431
+ if st.session_state.chatbot and st.session_state.extracted_data:
432
+ st.markdown("---")
433
+ st.subheader("πŸ’¬ Chat Management")
434
+ if st.button("πŸ—‘οΈ Clear Chat History", type="secondary", use_container_width=True):
435
+ clear_chat_history()
436
+
437
+ # Main content area
438
+ col1, col2 = st.columns([1, 1])
439
+
440
+ with col1:
441
+ st.markdown("### πŸ“Š Extraction Results")
442
+
443
+ if st.session_state.processing:
444
+ display_status_indicator("warning", "πŸ”„ Processing...")
445
+ st.info("Extracting data from Facebook. This may take a few seconds.")
446
+
447
+ elif st.session_state.extracted_data:
448
+ data = st.session_state.extracted_data
449
+ page_info = data['page_info']
450
+ content_blocks = data['content_blocks']
451
+
452
+ display_status_indicator("success", "βœ… Extraction Complete")
453
+
454
+ # Display page info
455
+ st.markdown("#### 🏷️ Page Information")
456
+ st.write(f"**Title:** {page_info['title']}")
457
+
458
+ if page_info['description']:
459
+ st.write(f"**Description:** {page_info['description'][:200]}...")
460
+
461
+ if page_info['og_description']:
462
+ st.write(f"**OG Description:** {page_info['og_description'][:200]}...")
463
+
464
+ st.write(f"**URL:** {page_info['url']}")
465
+ st.write(f"**Data Type:** {data['data_type'].title()}")
466
+ st.write(f"**Content Blocks:** {len(content_blocks)}")
467
+ st.write(f"**Extraction Time:** {data['extraction_time'][:19]}")
468
+
469
+ # Display sample content
470
+ st.markdown("#### πŸ“ Sample Content")
471
+ for i, block in enumerate(content_blocks[:3]):
472
+ with st.expander(f"Content Block {i+1} ({block['word_count']} words)"):
473
+ st.write(block['content'])
474
+
475
+ if len(content_blocks) > 3:
476
+ st.info(f"πŸ“„ And {len(content_blocks) - 3} more content blocks...")
477
+
478
+ else:
479
+ display_status_indicator("warning", "⏳ Ready for Extraction")
480
+ st.info("""
481
+ **To get started:**
482
+ 1. Enter a Facebook URL in the sidebar
483
+ 2. Select content type
484
+ 3. Click "Extract & Analyze"
485
+
486
+ **Supported URLs:**
487
+ - 🏒 Facebook Pages (best results)
488
+ - πŸ“˜ Public Groups (limited)
489
+ - πŸ‘€ Public Profiles (limited)
490
+ - πŸŽ‰ Events (limited)
491
+ - πŸ“ Posts (limited)
492
+
493
+ **Note:** This version extracts public data only.
494
+ Private content requires manual login (available in local deployment).
495
+ """)
496
+
497
+ with col2:
498
+ st.markdown("### πŸ’¬ AI Analysis")
499
+
500
+ if st.session_state.chatbot and st.session_state.extracted_data:
501
+ # Display chat history
502
+ for i, chat in enumerate(st.session_state.chat_history):
503
+ if chat["role"] == "user":
504
+ st.markdown(f'<div class="chat-message user-message"><strong>πŸ‘€ You:</strong> {chat["content"]}</div>',
505
+ unsafe_allow_html=True)
506
+ elif chat["role"] == "assistant":
507
+ st.markdown(f'<div class="chat-message assistant-message"><strong>πŸ€– Assistant:</strong> {chat["content"]}</div>',
508
+ unsafe_allow_html=True)
509
+
510
+ # Chat input
511
+ user_input = st.chat_input("Ask about the Facebook data...")
512
+
513
+ if user_input:
514
+ # Add user message
515
+ st.session_state.chat_history.append({"role": "user", "content": user_input})
516
+
517
+ # Generate AI response
518
+ with st.spinner("πŸ€” Analyzing..."):
519
+ try:
520
+ response = st.session_state.chatbot.invoke({"question": user_input})
521
+ answer = response.get("answer", "I couldn't generate a response based on the available data.")
522
+
523
+ st.session_state.chat_history.append({"role": "assistant", "content": answer})
524
+ st.rerun()
525
+ except Exception as e:
526
+ error_msg = f"❌ Error generating response: {str(e)}"
527
+ st.session_state.chat_history.append({"role": "assistant", "content": error_msg})
528
+ st.rerun()
529
+
530
+ # Suggested questions
531
+ if not st.session_state.chat_history:
532
+ st.markdown("#### πŸ’‘ Suggested Questions")
533
+ suggestions = [
534
+ "Summarize the main content of this page",
535
+ "What is this page primarily about?",
536
+ "Extract key information from the content",
537
+ "What are the main topics discussed?",
538
+ "Provide an overview of this Facebook content"
539
+ ]
540
+
541
+ for suggestion in suggestions:
542
+ if st.button(suggestion, key=f"suggest_{suggestion}", use_container_width=True):
543
+ st.info(f"πŸ’‘ Try asking: '{suggestion}'")
544
+
545
+ elif st.session_state.extracted_data:
546
+ st.info("πŸ’¬ Extract data first to start chatting with AI")
547
+ else:
548
+ st.info("πŸ” Extract Facebook data to enable AI analysis")
549
+
550
+ # Features section
551
+ st.markdown("---")
552
+ st.markdown("### πŸš€ Enhanced Features")
553
+
554
+ feature_cols = st.columns(3)
555
+
556
+ with feature_cols[0]:
557
+ st.markdown("""
558
+ <div class="feature-card">
559
+ <h4>πŸ” Smart Extraction</h4>
560
+ <p>Advanced algorithms for better content recognition and structure analysis</p>
561
+ </div>
562
+ """, unsafe_allow_html=True)
563
+
564
+ with feature_cols[1]:
565
+ st.markdown("""
566
+ <div class="feature-card">
567
+ <h4>πŸ€– AI-Powered Analysis</h4>
568
+ <p>HuggingFace integration for intelligent content understanding and Q&A</p>
569
+ </div>
570
+ """, unsafe_allow_html=True)
571
+
572
+ with feature_cols[2]:
573
+ st.markdown("""
574
+ <div class="feature-card">
575
+ <h4>πŸ’¬ Contextual Memory</h4>
576
+ <p>Maintains conversation context for more meaningful interactions</p>
577
+ </div>
578
+ """, unsafe_allow_html=True)
579
+
580
+ if __name__ == "__main__":
581
+ main()