decodingdatascience commited on
Commit
b655b7d
Β·
verified Β·
1 Parent(s): b170190

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -41
app.py CHANGED
@@ -1,9 +1,14 @@
1
- # app.py
 
 
 
2
  from crewai import Agent, Task, Crew
3
  import gradio as gr
4
  import re
5
  from datetime import datetime
6
  from pathlib import Path
 
 
7
  import os
8
  from openai import OpenAI # make sure `openai` is in requirements.txt
9
 
@@ -15,18 +20,17 @@ if not OPENAI_API_KEY:
15
  "Settings β†’ Secrets and add OPENAI_API_KEY."
16
  )
17
 
18
- # Optional: allow swapping models via secret/env
19
- OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4.1-mini")
20
- openai_client = OpenAI(api_key=OPENAI_API_KEY) # CrewAI also reads env automatically
21
-
22
- # ---- Logo helper --------------------------------------------------------------
23
  def to_raw_github(url: str) -> str:
24
  # Accepts both blob and raw URLs; converts blob β†’ raw
25
  return url.replace("https://github.com/", "https://raw.githubusercontent.com/").replace("/blob/", "/")
26
 
27
  LOGO_URL = to_raw_github("https://github.com/Decoding-Data-Science/airesidency/blob/main/dds_logo.jpg")
28
 
29
- # ---- Agents ------------------------------------------------------------------
 
 
30
  lead_market_analyst = Agent(
31
  role="Lead Market Analyst",
32
  goal="Deliver sharp, data-driven market insights for the brand/product.",
@@ -54,7 +58,7 @@ creative_content_creator = Agent(
54
  verbose=True,
55
  )
56
 
57
- # Optional social copywriter (only used if toggled)
58
  social_copywriter = Agent(
59
  role="Social Copywriter",
60
  goal="Turn strategy into platform-appropriate copy with strong hooks and clear CTAs.",
@@ -63,7 +67,9 @@ social_copywriter = Agent(
63
  verbose=False,
64
  )
65
 
66
- # ---- Tasks & Crew -------------------------------------------------------------
 
 
67
  def run_marketing_crew(product_brand: str, target_audience: str, objective: str) -> str:
68
  topic = f"{product_brand} | Audience: {target_audience} | Objective: {objective}"
69
 
@@ -115,15 +121,16 @@ def run_marketing_crew(product_brand: str, target_audience: str, objective: str)
115
  )
116
  return crew.kickoff()
117
 
118
- # ---- Helpers -----------------------------------------------------------------
 
 
119
  def _first_n_points(text: str, n: int = 5):
120
  lines = [l.strip() for l in text.splitlines() if l.strip()]
121
  bullets = []
122
  for l in lines:
123
  if l.startswith(("-", "*", "β€’")) or re.match(r"^\d+[\.\)]", l) or len(l) > 50:
124
  bullets.append(l.lstrip("-*β€’ ").strip())
125
- if len(bullets) >= n:
126
- break
127
  if not bullets:
128
  parts = [p.strip() for p in text.split("\n\n") if p.strip()]
129
  bullets = parts[:n]
@@ -136,11 +143,9 @@ def _hashtags(csv_tags: str) -> str:
136
  def _truncate_chars(s: str, max_chars: int) -> str:
137
  return s if len(s) <= max_chars else s[:max_chars - 1] + "…"
138
 
139
- def _slugify(name: str) -> str:
140
- # Replace non-word chars with underscores and trim
141
- return re.sub(r"\W+", "_", (name or "").lower()).strip("_")
142
-
143
- # ---- Lightweight templates (no extra LLM call) --------------------------------
144
  def tpl_linkedin(strategy, brand, audience, objective, hashtags, max_words=180):
145
  hook = f"{brand}: a sharper path to {objective} for {audience}."
146
  pts = "\n".join([f"- {p}" for p in _first_n_points(strategy, 5)])
@@ -191,7 +196,9 @@ def tpl_article(strategy, brand, audience, objective, hashtags, max_words=800):
191
  words = text.split()
192
  return (" ".join(words[:max_words]) + "…") if len(words) > max_words else text
193
 
194
- # ---- Optional LLM copywriter (uses the Social Copywriter agent) ---------------
 
 
195
  def llm_copywriter(strategy_text, brand, audience, objective, tone, platform,
196
  hashtags, li_words, tweet_chars, article_words):
197
  limits = {
@@ -221,7 +228,9 @@ Requirements:
221
  crew = Crew(agents=[social_copywriter], tasks=[task], verbose=False)
222
  return crew.kickoff()
223
 
224
- # ---- Generation wrapper -------------------------------------------------------
 
 
225
  PLATFORMS = ["LinkedIn", "X (Twitter)", "Article"] # Reduced for better UX
226
 
227
  def generate(product_brand, target_audience, objective,
@@ -239,31 +248,31 @@ def generate(product_brand, target_audience, objective,
239
  social = llm_copywriter(strategy, product_brand, target_audience, objective,
240
  tone, platform, hashtags,
241
  li_max_words, tweet_max_chars, article_max_words)
242
-
243
- name_map = {"LinkedIn": "linkedin", "X (Twitter)": "tweet", "Article": "article"}
244
- safe = _slugify(product_brand)
245
- fname = f"{name_map.get(platform, 'post')}_{safe}.md"
246
- out_path = Path(fname).resolve()
247
- out_path.write_text(social, encoding="utf-8")
248
- return strategy, social, str(out_path)
249
-
250
  else:
251
- safe = _slugify(product_brand)
252
  if platform == "LinkedIn":
253
  social = tpl_linkedin(strategy, product_brand, target_audience, objective, hashtags, li_max_words)
254
- fname = f"linkedin_{safe}.md"
255
  elif platform == "X (Twitter)":
256
  social = tpl_tweet(strategy, product_brand, target_audience, objective, hashtags, tweet_max_chars)
257
- fname = f"tweet_{safe}.txt"
258
  else: # Article
259
  social = tpl_article(strategy, product_brand, target_audience, objective, hashtags, article_max_words)
260
- fname = f"article_{safe}.md"
261
 
262
  out_path = Path(fname).resolve()
263
  out_path.write_text(social, encoding="utf-8")
264
  return strategy, social, str(out_path)
265
 
266
- # ---- Theming & Layout (2 columns with header) --------------------------------
 
 
 
 
 
 
 
 
 
267
  theme = gr.themes.Soft(primary_hue="indigo", neutral_hue="slate")
268
 
269
  CUSTOM_CSS = """
@@ -297,10 +306,8 @@ with gr.Blocks(title="DDS Marketing Crew β†’ Social Content", theme=theme, css=C
297
 
298
  with gr.Group(elem_classes="card"):
299
  platform = gr.Dropdown(choices=PLATFORMS, value="LinkedIn", label="Platform")
300
- tone = gr.Dropdown(
301
- choices=["Professional", "Friendly", "Bold", "Educational", "Conversational"],
302
- value="Professional", label="Tone"
303
- )
304
  hashtags = gr.Textbox(label="Hashtags (comma separated)", placeholder="ai, generativeai, datascience")
305
  use_llm = gr.Checkbox(value=False, label="Use LLM Copywriter (higher fidelity)")
306
 
@@ -329,8 +336,6 @@ with gr.Blocks(title="DDS Marketing Crew β†’ Social Content", theme=theme, css=C
329
  outputs=[strategy_md, social_tb, download_file]
330
  )
331
 
332
- # ---- Space-friendly launch ----------------------------------------------------
333
- if __name__ == "__main__":
334
- host = os.getenv("HOST", "0.0.0.0")
335
- port = int(os.getenv("PORT", "7860"))
336
- demo.launch(server_name=host, server_port=port)
 
1
+
2
+
3
+
4
+
5
  from crewai import Agent, Task, Crew
6
  import gradio as gr
7
  import re
8
  from datetime import datetime
9
  from pathlib import Path
10
+
11
+
12
  import os
13
  from openai import OpenAI # make sure `openai` is in requirements.txt
14
 
 
20
  "Settings β†’ Secrets and add OPENAI_API_KEY."
21
  )
22
 
23
+
24
+ # --- Logo: convert GitHub page URL to raw if needed ---
 
 
 
25
  def to_raw_github(url: str) -> str:
26
  # Accepts both blob and raw URLs; converts blob β†’ raw
27
  return url.replace("https://github.com/", "https://raw.githubusercontent.com/").replace("/blob/", "/")
28
 
29
  LOGO_URL = to_raw_github("https://github.com/Decoding-Data-Science/airesidency/blob/main/dds_logo.jpg")
30
 
31
+ # ----------------------------
32
+ # Your existing agents (unchanged)
33
+ # ----------------------------
34
  lead_market_analyst = Agent(
35
  role="Lead Market Analyst",
36
  goal="Deliver sharp, data-driven market insights for the brand/product.",
 
58
  verbose=True,
59
  )
60
 
61
+ # Optional: focused social copywriter (only if toggled)
62
  social_copywriter = Agent(
63
  role="Social Copywriter",
64
  goal="Turn strategy into platform-appropriate copy with strong hooks and clear CTAs.",
 
67
  verbose=False,
68
  )
69
 
70
+ # ----------------------------
71
+ # Core crew (unchanged)
72
+ # ----------------------------
73
  def run_marketing_crew(product_brand: str, target_audience: str, objective: str) -> str:
74
  topic = f"{product_brand} | Audience: {target_audience} | Objective: {objective}"
75
 
 
121
  )
122
  return crew.kickoff()
123
 
124
+ # ----------------------------
125
+ # Helpers
126
+ # ----------------------------
127
  def _first_n_points(text: str, n: int = 5):
128
  lines = [l.strip() for l in text.splitlines() if l.strip()]
129
  bullets = []
130
  for l in lines:
131
  if l.startswith(("-", "*", "β€’")) or re.match(r"^\d+[\.\)]", l) or len(l) > 50:
132
  bullets.append(l.lstrip("-*β€’ ").strip())
133
+ if len(bullets) >= n: break
 
134
  if not bullets:
135
  parts = [p.strip() for p in text.split("\n\n") if p.strip()]
136
  bullets = parts[:n]
 
143
  def _truncate_chars(s: str, max_chars: int) -> str:
144
  return s if len(s) <= max_chars else s[:max_chars - 1] + "…"
145
 
146
+ # ----------------------------
147
+ # Lightweight templates (no extra LLM call)
148
+ # ----------------------------
 
 
149
  def tpl_linkedin(strategy, brand, audience, objective, hashtags, max_words=180):
150
  hook = f"{brand}: a sharper path to {objective} for {audience}."
151
  pts = "\n".join([f"- {p}" for p in _first_n_points(strategy, 5)])
 
196
  words = text.split()
197
  return (" ".join(words[:max_words]) + "…") if len(words) > max_words else text
198
 
199
+ # ----------------------------
200
+ # Optional LLM copywriter (reuses Social Copywriter agent)
201
+ # ----------------------------
202
  def llm_copywriter(strategy_text, brand, audience, objective, tone, platform,
203
  hashtags, li_words, tweet_chars, article_words):
204
  limits = {
 
228
  crew = Crew(agents=[social_copywriter], tasks=[task], verbose=False)
229
  return crew.kickoff()
230
 
231
+ # ----------------------------
232
+ # Generation wrapper
233
+ # ----------------------------
234
  PLATFORMS = ["LinkedIn", "X (Twitter)", "Article"] # Reduced for better UX
235
 
236
  def generate(product_brand, target_audience, objective,
 
248
  social = llm_copywriter(strategy, product_brand, target_audience, objective,
249
  tone, platform, hashtags,
250
  li_max_words, tweet_max_chars, article_max_words)
 
 
 
 
 
 
 
 
251
  else:
 
252
  if platform == "LinkedIn":
253
  social = tpl_linkedin(strategy, product_brand, target_audience, objective, hashtags, li_max_words)
254
+ fname = f"linkedin_{re.sub(r'\\W+','_',product_brand.lower())}.md"
255
  elif platform == "X (Twitter)":
256
  social = tpl_tweet(strategy, product_brand, target_audience, objective, hashtags, tweet_max_chars)
257
+ fname = f"tweet_{re.sub(r'\\W+','_',product_brand.lower())}.txt"
258
  else: # Article
259
  social = tpl_article(strategy, product_brand, target_audience, objective, hashtags, article_max_words)
260
+ fname = f"article_{re.sub(r'\\W+','_',product_brand.lower())}.md"
261
 
262
  out_path = Path(fname).resolve()
263
  out_path.write_text(social, encoding="utf-8")
264
  return strategy, social, str(out_path)
265
 
266
+ # Save LLM result with reasonable extension
267
+ name_map = {"LinkedIn": "linkedin", "X (Twitter)": "tweet", "Article": "article"}
268
+ fname = f"{name_map.get(platform,'post')}_{re.sub(r'\\W+','_',product_brand.lower())}.md"
269
+ out_path = Path(fname).resolve()
270
+ out_path.write_text(social, encoding="utf-8")
271
+ return strategy, social, str(out_path)
272
+
273
+ # ----------------------------
274
+ # Theming & Layout (2 columns with header)
275
+ # ----------------------------
276
  theme = gr.themes.Soft(primary_hue="indigo", neutral_hue="slate")
277
 
278
  CUSTOM_CSS = """
 
306
 
307
  with gr.Group(elem_classes="card"):
308
  platform = gr.Dropdown(choices=PLATFORMS, value="LinkedIn", label="Platform")
309
+ tone = gr.Dropdown(choices=["Professional", "Friendly", "Bold", "Educational", "Conversational"],
310
+ value="Professional", label="Tone")
 
 
311
  hashtags = gr.Textbox(label="Hashtags (comma separated)", placeholder="ai, generativeai, datascience")
312
  use_llm = gr.Checkbox(value=False, label="Use LLM Copywriter (higher fidelity)")
313
 
 
336
  outputs=[strategy_md, social_tb, download_file]
337
  )
338
 
339
+ # In Colab, share=True is handy
340
+ demo.launch(share=True)
341
+