ibrahim313 commited on
Commit
21e772e
Β·
verified Β·
1 Parent(s): 8c1f293

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +229 -164
app.py CHANGED
@@ -1,175 +1,224 @@
1
  import streamlit as st
2
  import os
3
  from groq import Groq
4
- from typing import List, Dict
5
  import json
6
  from datetime import datetime
7
  import time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  @st.cache_resource
10
- def get_groq_client():
11
- return Groq(api_key=st.secrets["groq_api_key"])
 
 
 
 
 
 
12
 
13
  class ContentAnalysisAgent:
14
  def __init__(self):
15
- """Initialize the agent with Groq client"""
16
  self.client = get_groq_client()
17
  self.system_prompt = """You are an expert social media content analyzer with deep understanding of engagement,
18
- audience psychology, and content optimization. Analyze content step by step using a systematic approach."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- def _think(self, thought_process: str) -> None:
21
- """Display agent's thinking process"""
22
- with st.expander("πŸ€” Agent's Thought Process", expanded=False):
23
- st.write(thought_process)
24
 
25
- def _get_llm_response(self, messages: List[Dict]) -> str:
26
- """Get response from Groq LLM"""
27
- try:
28
- response = self.client.chat.completions.create(
29
- messages=messages,
30
- model="llama3-8b-8192",
31
- temperature=0.7,
32
- max_tokens=1024,
33
- )
34
- return response.choices[0].message.content
35
- except Exception as e:
36
- st.error(f"Error in LLM processing: {str(e)}")
37
- return None
38
-
39
- def _create_analysis_prompt(self, text: str) -> str:
40
- """Create a detailed analysis prompt with agentic thinking"""
41
- return f"""Let's analyze this social media post step by step:
42
- POST: {text}
43
- Think through the following aspects:
44
- 1. CONTENT STRUCTURE ANALYSIS
45
- - Examine length, formatting, and organization
46
- - Identify key message components
47
- - Note special characters and emoji usage
48
- 2. AUDIENCE PSYCHOLOGY
49
- - Who is the target audience?
50
- - What emotional triggers are present?
51
- - What call-to-actions exist?
52
- 3. ENGAGEMENT POTENTIAL
53
- - Analyze hook effectiveness
54
- - Evaluate storytelling elements
55
- - Assess viral potential
56
- 4. STYLE AND TONE
57
- - Determine primary content style
58
- - Identify emotional undertones
59
- - Evaluate brand voice consistency
60
- 5. OPTIMIZATION OPPORTUNITIES
61
- - Identify areas for improvement
62
- - Suggest engagement boosters
63
- - Note potential risks or concerns
64
- Return a JSON structured response with:
65
  {{
66
- "style": "primary posting style",
67
- "tones": ["list of detected tones"],
68
- "rating": "1-5 rating for content appropriateness",
69
- "engagement_score": "0-100 engagement potential",
70
  "analysis": {{
71
- "strengths": ["list of strong points"],
72
- "improvements": ["areas to enhance"],
73
- "audience_fit": "target audience match score"
74
  }}
75
  }}"""
76
 
77
- def analyze_post(self, post_text: str) -> Dict:
78
- """Perform comprehensive post analysis"""
79
- # First thinking phase - Initial Assessment
80
- self._think("πŸ” Phase 1: Initial Assessment\nAnalyzing post structure and basic elements...")
81
-
82
- # Create conversation with system prompt and analysis request
83
  messages = [
84
  {"role": "system", "content": self.system_prompt},
85
- {"role": "user", "content": self._create_analysis_prompt(post_text)}
86
  ]
87
 
88
- # Get initial analysis
89
- with st.spinner("πŸ€– Analyzing content..."):
90
- analysis_response = self._get_llm_response(messages)
91
-
92
- if not analysis_response:
93
- return None
94
-
95
- # Parse JSON response
96
- try:
97
- analysis_result = json.loads(analysis_response)
98
- except json.JSONDecodeError:
99
- st.error("Error parsing LLM response")
100
- return None
101
-
102
- # Second thinking phase - Refinement
103
- self._think("🎯 Phase 2: Refinement\nRefining analysis and generating specific recommendations...")
104
-
105
- # Get specific recommendations
106
- recommendation_prompt = f"""Based on the initial analysis of this post:
107
- {post_text}
108
-
109
- Provide 3 specific, actionable recommendations to improve engagement."""
110
-
111
- messages.append({"role": "user", "content": recommendation_prompt})
112
- recommendations = self._get_llm_response(messages)
113
-
114
- if recommendations:
115
- analysis_result["recommendations"] = recommendations
116
-
117
- return analysis_result
118
-
119
 
120
  class GraicieApp:
121
  def __init__(self):
 
122
  self.agent = ContentAnalysisAgent()
 
 
 
 
 
 
 
 
 
 
123
 
124
- def display_header(self):
 
125
  st.title("πŸ€– Project Graicie - Advanced Content Analyzer")
126
  st.markdown("""
127
  ### Powered by LLaMA 3 & Agentic AI
128
  Get deep, AI-powered insights into your social media content using advanced language models.
129
  """)
130
 
131
- def display_example_posts(self):
132
- examples = {
133
- "Viral Post": "πŸš€ HUGE ANNOUNCEMENT! After months of work, my online course is finally LIVE! πŸŽ‰\n"
134
- "Learn how I grew from 0 to 100K followers in 6 months! Early bird pricing ends tomorrow! πŸ’«\n"
135
- "#socialmedia #digitalmarketing #success",
136
- "Personal Story": "Sometimes life throws you curveballs... Today I faced my biggest fear and went "
137
- "skydiving! πŸͺ‚ Swipe to see my reaction! Remember: growth happens outside your comfort zone πŸ’•\n"
138
- "#personalgrowth #motivation",
139
- "Educational": "🧠 5 Python Tips You Didn't Know:\n1. List comprehensions\n2. f-strings\n3. Walrus operator\n"
140
- "4. Context managers\n5. Lambda functions\nSave this for later! πŸ’‘\n#coding #programming"
141
- }
142
-
143
- st.subheader("πŸ“± Try an Example Post")
144
- selected_example = st.selectbox("Select an example post:", list(examples.keys()))
145
-
146
- if selected_example:
147
- st.text_area("Example Post", examples[selected_example], height=100, disabled=True)
148
- if st.button("Analyze Example", use_container_width=True):
149
- self.analyze_and_display(examples[selected_example])
150
-
151
- def display_results(self, results: Dict):
152
  if not results:
153
  return
154
 
155
- # Display main metrics
156
- col1, col2, col3, col4 = st.columns(4)
157
- with col1:
158
  st.metric("Style", results["style"])
159
- with col2:
160
- st.metric("Engagement Score", f"{results['engagement_score']}/100")
161
- with col3:
162
- st.metric("Content Rating", f"{results['rating']}/5")
163
- with col4:
164
  st.metric("Audience Fit", results["analysis"]["audience_fit"])
165
 
166
- # Display tones
167
  st.subheader("πŸ“Š Content Tones")
168
- for tone in results["tones"]:
169
- st.markdown(f"<span style='background-color: #e6f3ff; padding: 5px 10px; "
170
- f"margin: 5px; border-radius: 15px;'>{tone}</span>", unsafe_allow_html=True)
171
-
172
- # Display strengths and improvements
 
 
 
173
  col1, col2 = st.columns(2)
174
  with col1:
175
  st.subheader("πŸ’ͺ Strengths")
@@ -181,24 +230,55 @@ class GraicieApp:
181
  for improvement in results["analysis"]["improvements"]:
182
  st.markdown(f"πŸ“Œ {improvement}")
183
 
184
- # Display recommendations
185
  if "recommendations" in results:
186
  st.subheader("πŸš€ Specific Recommendations")
187
- st.markdown(results["recommendations"])
 
188
 
189
- def analyze_and_display(self, text: str):
190
- results = self.agent.analyze_post(text)
191
- if results:
192
- self.display_results(results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  def run(self):
195
- self.display_header()
 
 
196
 
197
  # Main content area
198
  col1, col2 = st.columns([2, 1])
199
 
200
  with col1:
201
- self.display_example_posts()
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
  st.subheader("πŸ“ Analyze Your Post")
204
  user_post = st.text_area(
@@ -209,35 +289,17 @@ class GraicieApp:
209
 
210
  if st.button("πŸ” Analyze My Post", use_container_width=True):
211
  if user_post:
212
- self.analyze_and_display(user_post)
 
 
213
  else:
214
  st.warning("Please enter some content to analyze!")
215
 
216
- with col2:
217
- st.subheader("πŸ’‘ Pro Tips")
218
- st.info("""
219
- **Content That Works:**
220
- 1. Tell authentic stories
221
- 2. Use relevant hashtags
222
- 3. Include call-to-actions
223
- 4. Add visual elements
224
- 5. Engage with questions
225
- """)
226
-
227
- st.markdown("### πŸ“Š Optimal Post Elements")
228
- st.markdown("""
229
- - Length: 80-150 characters
230
- - Hashtags: 3-5 relevant tags
231
- - Emojis: 2-3 key emojis
232
- - CTA: One clear action
233
- """)
234
-
235
  # Footer
236
  st.markdown(
237
  """
238
- <div style='position: fixed; bottom: 0; width: 100%; background-color: #f0f2f6;
239
- padding: 10px; text-align: center;'>
240
- <p style='margin: 0; color: #666;'>
241
  Powered by LLaMA 3 & Groq | Made with ❀️ by Project Graicie Team |
242
  Β© 2024 Project Graicie
243
  </p>
@@ -246,7 +308,10 @@ class GraicieApp:
246
  unsafe_allow_html=True,
247
  )
248
 
249
-
250
  if __name__ == "__main__":
251
- app = GraicieApp()
252
- app.run()
 
 
 
 
 
1
  import streamlit as st
2
  import os
3
  from groq import Groq
4
+ from typing import List, Dict, Optional, Union
5
  import json
6
  from datetime import datetime
7
  import time
8
+ from functools import lru_cache
9
+ import logging
10
+ from contextlib import contextmanager
11
+
12
+ # Configure logging
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Constants
17
+ MAX_RETRIES = 3
18
+ RETRY_DELAY = 1
19
+ DEFAULT_TEMPERATURE = 0.5
20
+ MAX_TOKENS = 1024
21
+ MODEL_NAME = "llama3-8b-8192"
22
+
23
+ class APIError(Exception):
24
+ """Custom exception for API-related errors"""
25
+ pass
26
+
27
+ class JSONParsingError(Exception):
28
+ """Custom exception for JSON parsing errors"""
29
+ pass
30
+
31
+ @contextmanager
32
+ def error_handler(context: str):
33
+ """Context manager for handling errors with specific context"""
34
+ try:
35
+ yield
36
+ except Exception as e:
37
+ logger.error(f"Error in {context}: {str(e)}")
38
+ st.error(f"An error occurred in {context}. Please try again.")
39
+ raise
40
 
41
  @st.cache_resource
42
+ def get_groq_client() -> Groq:
43
+ """Initialize and cache Groq client"""
44
+ try:
45
+ return Groq(api_key=st.secrets["groq_api_key"])
46
+ except Exception as e:
47
+ logger.error(f"Failed to initialize Groq client: {str(e)}")
48
+ st.error("Failed to initialize AI service. Please check your API key.")
49
+ raise APIError("Failed to initialize Groq client")
50
 
51
  class ContentAnalysisAgent:
52
  def __init__(self):
53
+ """Initialize the agent with Groq client and default settings"""
54
  self.client = get_groq_client()
55
  self.system_prompt = """You are an expert social media content analyzer with deep understanding of engagement,
56
+ audience psychology, and content optimization. You must ALWAYS return responses in valid JSON format when requested.
57
+ Analyze content step by step using a systematic approach."""
58
+
59
+ @staticmethod
60
+ def _display_thinking(thought: str):
61
+ """Display agent's thinking process in a collapsible container"""
62
+ with st.expander("πŸ€” Analysis Process", expanded=False):
63
+ st.markdown(f"```\n{thought}\n```")
64
+
65
+ def _call_api(self, messages: List[Dict], retries: int = MAX_RETRIES) -> Optional[str]:
66
+ """Make API call with retry logic"""
67
+ for attempt in range(retries):
68
+ try:
69
+ response = self.client.chat.completions.create(
70
+ messages=messages,
71
+ model=MODEL_NAME,
72
+ temperature=DEFAULT_TEMPERATURE,
73
+ max_tokens=MAX_TOKENS
74
+ )
75
+ return response.choices[0].message.content
76
+ except Exception as e:
77
+ if attempt == retries - 1:
78
+ logger.error(f"API call failed after {retries} attempts: {str(e)}")
79
+ raise APIError(f"Failed to get response from AI service: {str(e)}")
80
+ time.sleep(RETRY_DELAY)
81
+ return None
82
+
83
+ @staticmethod
84
+ def _parse_json(response: str) -> Dict:
85
+ """Parse JSON from response with enhanced error handling"""
86
+ try:
87
+ # First attempt: direct JSON parsing
88
+ return json.loads(response)
89
+ except json.JSONDecodeError:
90
+ try:
91
+ # Second attempt: extract JSON structure
92
+ start_idx = response.find('{')
93
+ end_idx = response.rfind('}') + 1
94
+ if start_idx != -1 and end_idx > start_idx:
95
+ json_str = response[start_idx:end_idx]
96
+ # Clean up common formatting issues
97
+ json_str = (json_str.replace('\n', ' ')
98
+ .replace('```json', '')
99
+ .replace('```', '')
100
+ .strip())
101
+ return json.loads(json_str)
102
+ except (json.JSONDecodeError, ValueError) as e:
103
+ logger.warning(f"JSON parsing failed: {str(e)}")
104
+ # Return fallback structure
105
+ return {
106
+ "style": "unknown",
107
+ "tones": ["neutral"],
108
+ "rating": "3",
109
+ "engagement_score": "50",
110
+ "analysis": {
111
+ "strengths": ["Content provided"],
112
+ "improvements": ["Format needs review"],
113
+ "audience_fit": "medium"
114
+ },
115
+ "error": "Response parsing failed"
116
+ }
117
 
118
+ def analyze_post(self, post_text: str) -> Dict:
119
+ """Analyze post content with comprehensive error handling"""
120
+ analysis_prompt = f"""Analyze this social media post and return ONLY a valid JSON object:
121
+ POST: {post_text}
122
 
123
+ Required structure:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  {{
125
+ "style": "posting style",
126
+ "tones": ["tone1", "tone2"],
127
+ "rating": "1-5",
128
+ "engagement_score": "0-100",
129
  "analysis": {{
130
+ "strengths": ["strength1", "strength2"],
131
+ "improvements": ["improvement1", "improvement2"],
132
+ "audience_fit": "low/medium/high"
133
  }}
134
  }}"""
135
 
 
 
 
 
 
 
136
  messages = [
137
  {"role": "system", "content": self.system_prompt},
138
+ {"role": "user", "content": analysis_prompt}
139
  ]
140
 
141
+ with st.spinner("πŸ” Analyzing content..."):
142
+ try:
143
+ analysis_response = self._call_api(messages)
144
+ if not analysis_response:
145
+ raise APIError("No response received from API")
146
+
147
+ analysis_result = self._parse_json(analysis_response)
148
+
149
+ # Get recommendations
150
+ recommendation_prompt = """Provide exactly 3 specific, actionable recommendations
151
+ to improve engagement. Return as a JSON array of strings."""
152
+
153
+ messages.append({"role": "user", "content": recommendation_prompt})
154
+ recommendations = self._call_api(messages)
155
+
156
+ if recommendations:
157
+ try:
158
+ parsed_recommendations = json.loads(recommendations)
159
+ if isinstance(parsed_recommendations, list):
160
+ analysis_result["recommendations"] = parsed_recommendations
161
+ else:
162
+ analysis_result["recommendations"] = [recommendations.strip()]
163
+ except json.JSONDecodeError:
164
+ analysis_result["recommendations"] = [recommendations.strip()]
165
+
166
+ return analysis_result
167
+
168
+ except Exception as e:
169
+ logger.error(f"Analysis failed: {str(e)}")
170
+ st.error("Analysis failed. Please try again.")
171
+ return None
172
 
173
  class GraicieApp:
174
  def __init__(self):
175
+ """Initialize the Graicie application"""
176
  self.agent = ContentAnalysisAgent()
177
+ self.example_posts = {
178
+ "Viral Marketing": "πŸš€ HUGE ANNOUNCEMENT! After months of work, my online course is finally LIVE! πŸŽ‰\n"
179
+ "Learn how I grew from 0 to 100K followers in 6 months! Early bird pricing ends tomorrow! πŸ’«\n"
180
+ "#socialmedia #digitalmarketing #success",
181
+ "Personal Story": "Sometimes life throws you curveballs... Today I faced my biggest fear and went "
182
+ "skydiving! πŸͺ‚ Swipe to see my reaction! Remember: growth happens outside your comfort zone πŸ’•\n"
183
+ "#personalgrowth #motivation",
184
+ "Educational": "🧠 5 Python Tips You Didn't Know:\n1. List comprehensions\n2. f-strings\n3. Walrus operator\n"
185
+ "4. Context managers\n5. Lambda functions\nSave this for later! πŸ’‘\n#coding #programming"
186
+ }
187
 
188
+ def _display_header(self):
189
+ """Display application header"""
190
  st.title("πŸ€– Project Graicie - Advanced Content Analyzer")
191
  st.markdown("""
192
  ### Powered by LLaMA 3 & Agentic AI
193
  Get deep, AI-powered insights into your social media content using advanced language models.
194
  """)
195
 
196
+ def _display_metrics(self, results: Dict):
197
+ """Display analysis metrics in a structured format"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  if not results:
199
  return
200
 
201
+ # Main metrics
202
+ cols = st.columns(4)
203
+ with cols[0]:
204
  st.metric("Style", results["style"])
205
+ with cols[1]:
206
+ st.metric("Engagement", f"{results['engagement_score']}/100")
207
+ with cols[2]:
208
+ st.metric("Rating", f"{results['rating']}/5")
209
+ with cols[3]:
210
  st.metric("Audience Fit", results["analysis"]["audience_fit"])
211
 
212
+ # Content tones
213
  st.subheader("πŸ“Š Content Tones")
214
+ tone_html = " ".join([
215
+ f"<span style='background-color: #e6f3ff; padding: 5px 10px; "
216
+ f"margin: 5px; border-radius: 15px;'>{tone}</span>"
217
+ for tone in results["tones"]
218
+ ])
219
+ st.markdown(tone_html, unsafe_allow_html=True)
220
+
221
+ # Analysis details
222
  col1, col2 = st.columns(2)
223
  with col1:
224
  st.subheader("πŸ’ͺ Strengths")
 
230
  for improvement in results["analysis"]["improvements"]:
231
  st.markdown(f"πŸ“Œ {improvement}")
232
 
233
+ # Recommendations
234
  if "recommendations" in results:
235
  st.subheader("πŸš€ Specific Recommendations")
236
+ for idx, rec in enumerate(results["recommendations"], 1):
237
+ st.markdown(f"{idx}. {rec}")
238
 
239
+ def _display_sidebar(self):
240
+ """Display sidebar with tips and information"""
241
+ with st.sidebar:
242
+ st.subheader("πŸ’‘ Pro Tips")
243
+ st.info("""
244
+ **Content Best Practices:**
245
+ 1. Tell authentic stories
246
+ 2. Use relevant hashtags
247
+ 3. Include call-to-actions
248
+ 4. Add visual elements
249
+ 5. Engage with questions
250
+ """)
251
+
252
+ st.markdown("### πŸ“Š Optimal Post Elements")
253
+ st.markdown("""
254
+ - Length: 80-150 characters
255
+ - Hashtags: 3-5 relevant tags
256
+ - Emojis: 2-3 key emojis
257
+ - CTA: One clear action
258
+ """)
259
 
260
  def run(self):
261
+ """Run the Graicie application"""
262
+ self._display_header()
263
+ self._display_sidebar()
264
 
265
  # Main content area
266
  col1, col2 = st.columns([2, 1])
267
 
268
  with col1:
269
+ st.subheader("πŸ“± Try an Example Post")
270
+ selected_example = st.selectbox(
271
+ "Select an example:",
272
+ list(self.example_posts.keys())
273
+ )
274
+
275
+ if selected_example:
276
+ example_text = self.example_posts[selected_example]
277
+ st.text_area("Example Post", example_text, height=100, disabled=True)
278
+ if st.button("Analyze Example", use_container_width=True):
279
+ with error_handler("example analysis"):
280
+ results = self.agent.analyze_post(example_text)
281
+ self._display_metrics(results)
282
 
283
  st.subheader("πŸ“ Analyze Your Post")
284
  user_post = st.text_area(
 
289
 
290
  if st.button("πŸ” Analyze My Post", use_container_width=True):
291
  if user_post:
292
+ with error_handler("user post analysis"):
293
+ results = self.agent.analyze_post(user_post)
294
+ self._display_metrics(results)
295
  else:
296
  st.warning("Please enter some content to analyze!")
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  # Footer
299
  st.markdown(
300
  """
301
+ <div style='text-align: center; padding: 20px;'>
302
+ <p style='color: #666;'>
 
303
  Powered by LLaMA 3 & Groq | Made with ❀️ by Project Graicie Team |
304
  Β© 2024 Project Graicie
305
  </p>
 
308
  unsafe_allow_html=True,
309
  )
310
 
 
311
  if __name__ == "__main__":
312
+ try:
313
+ app = GraicieApp()
314
+ app.run()
315
+ except Exception as e:
316
+ logger.error(f"Application failed to start: {str(e)}")
317
+ st.error("Application failed to start. Please check the logs.")