Alpha108 commited on
Commit
cf081f2
·
verified ·
1 Parent(s): 34d0ca6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -84
app.py CHANGED
@@ -1,106 +1,120 @@
1
  import os
2
  import streamlit as st
3
  from llm_groq import generate_post, transform_post, generate_hooks, DEFAULT_MODEL
4
- from prompts import build_post_prompt, transform_instruction
5
  from data_utils import load_posts, extract_keywords, dedupe_sentences, strip_labels
6
- from ui_components import preset_picker, refinement_bar
7
 
8
- st.set_page_config(page_title="Pro LinkedIn Post Generator — Groq", layout="centered")
9
- st.title("Pro LinkedIn Post Generator (Groq)")
10
 
11
- # Sidebar controls
12
  with st.sidebar:
13
  st.subheader("Groq & Decoding")
14
  model = st.selectbox("Model", [DEFAULT_MODEL, "llama-3.1-8b-instant", "mixtral-8x7b-32768"], index=0)
15
  temperature = st.slider("Temperature", 0.1, 1.2, 0.6, 0.05)
16
  top_p = st.slider("Top‑p", 0.1, 1.0, 0.9, 0.05)
17
- target_len = st.slider("Length (words)", 60, 320, 160, 10)
18
  st.markdown("Set GROQ_API_KEY in Space → Settings → Variables & Secrets.")
19
 
20
- # Presets to speed up intent
21
- preset = preset_picker()
22
 
23
- # Core inputs
24
- st.markdown("### Compose")
25
- topic = st.text_input("Topic", value="AI agent playbooks for startup ops")
26
- purpose = st.selectbox("Purpose", ["awareness","lead-gen","hiring","product launch","opinion","lesson learned"], index=0 if not preset else ["awareness","lead-gen","hiring","product launch","opinion","lesson learned"].index(preset.get("purpose","awareness")))
27
- audience = st.text_input("Audience", value="SaaS founders in early stage")
28
- tone = st.selectbox("Tone", ["Professional","Friendly","Contrarian","Technical","Inspirational"], index=0 if not preset else ["Professional","Friendly","Contrarian","Technical","Inspirational"].index(preset.get("tone","Professional")))
29
- language = st.selectbox("Language", ["English","Urdu","Arabic","French","Spanish"], index=0)
30
 
31
- # Evidence & style
32
- st.markdown("### Evidence & Style")
33
- evidence = st.text_area("Evidence (metric/anecdote/quote)", value="")
34
- style_text = st.text_area("Style cues (max 4, one per line)", value="Short punchy hooks\nActionable bullets\nOne metric per paragraph\nQuestion-led CTA")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
- # Dataset upload (optional)
37
- st.markdown("### Optional Dataset")
38
- uploaded = st.file_uploader("Upload CSV/JSON of past posts (must include 'text')", type=["csv","json"])
39
- keywords = []
40
- if uploaded is not None:
41
- try:
42
- df = load_posts(uploaded)
43
- keywords = extract_keywords(topic, df)
44
- st.success(f"Loaded {len(df)} posts. Extracted keywords: {', '.join(keywords[:8]) or '—'}")
45
- except Exception as e:
46
- st.error(f"Dataset error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # Hook lab (lightweight)
49
- st.markdown("### Hook Lab")
50
- hook_btn = st.button("Suggest 5 hooks")
51
- chosen_hook = st.text_input("Chosen opening line (optional)")
52
- if hook_btn:
53
- try:
54
- raw_hooks = generate_hooks(topic, audience, tone, 5, model, temperature, top_p, 200)
55
- st.code(raw_hooks)
56
- except Exception as e:
57
- st.error(f"Hook generation failed: {e}")
58
 
59
- # Clarifier (simple)
60
- st.markdown("### Clarifier")
61
- outcome = st.text_input("Desired outcome (e.g., 10 demo requests this week)", value="")
62
- extra_note = st.text_input("One concrete detail to include (e.g., 'onboarding 14→3 days')", value="")
63
- clarifier_notes = "\n".join([f"Outcome: {outcome}" if outcome else "", f"Detail: {extra_note}" if extra_note else ""]).strip()
64
-
65
- if st.button("Generate Post"):
66
- try:
67
- style_cues = [s.strip() for s in style_text.splitlines() if s.strip()][:4]
68
- prompt = build_post_prompt(
69
- topic=topic,
70
- language=language,
71
- tone=tone,
72
- target_len=target_len,
73
- purpose=purpose,
74
- audience=audience,
75
- evidence=evidence,
76
- keywords=keywords,
77
- style_cues=style_cues,
78
- clarifier_notes=clarifier_notes,
79
- chosen_hook=chosen_hook
80
- )
81
- max_tokens = max(200, min(1200, int(target_len*1.6)+120))
82
- raw = generate_post(prompt, model, temperature, top_p, max_tokens)
83
- post = dedupe_sentences(strip_labels(raw))
84
- st.session_state["post"] = post
85
- st.success("Post generated.")
86
- st.write(post)
87
- st.download_button("Download (.txt)", post, file_name="linkedin_post.txt")
88
- st.code(prompt, language="markdown")
89
- except Exception as e:
90
- st.error(f"Generation failed: {e}")
91
 
92
- # Refinement bar
93
- if "post" in st.session_state and st.session_state["post"]:
94
- st.markdown("---")
95
- st.subheader("Refine")
96
- actions = refinement_bar()
97
- for kind, pressed in actions.items():
98
- if pressed:
99
  try:
100
- instr = transform_instruction(kind)
101
- raw = transform_post(instr, st.session_state["post"], model, temperature, top_p, 500)
102
- st.session_state["post"] = dedupe_sentences(strip_labels(raw))
 
103
  except Exception as e:
104
  st.error(f"Refinement failed: {e}")
105
- if st.session_state["post"]:
106
- st.write(st.session_state["post"])
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import streamlit as st
3
  from llm_groq import generate_post, transform_post, generate_hooks, DEFAULT_MODEL
4
+ from prompts import build_quick_prompt, build_post_prompt, transform_instruction
5
  from data_utils import load_posts, extract_keywords, dedupe_sentences, strip_labels
6
+ from ui_components import quick_controls, pro_controls
7
 
8
+ st.set_page_config(page_title="LinkedIn Post Generator — Groq", layout="centered")
9
+ st.title("LinkedIn Post Generator — Quick & Pro")
10
 
11
+ # Sidebar
12
  with st.sidebar:
13
  st.subheader("Groq & Decoding")
14
  model = st.selectbox("Model", [DEFAULT_MODEL, "llama-3.1-8b-instant", "mixtral-8x7b-32768"], index=0)
15
  temperature = st.slider("Temperature", 0.1, 1.2, 0.6, 0.05)
16
  top_p = st.slider("Top‑p", 0.1, 1.0, 0.9, 0.05)
 
17
  st.markdown("Set GROQ_API_KEY in Space → Settings → Variables & Secrets.")
18
 
19
+ tabs = st.tabs(["Quick Draft", "Pro Mode", "History"])
 
20
 
21
+ # Session memory
22
+ if "history" not in st.session_state:
23
+ st.session_state.history = []
 
 
 
 
24
 
25
+ # Quick Draft
26
+ with tabs[0]:
27
+ idea, tone, words, variations, include_emoji, add_hashtags, language = quick_controls()
28
+ if st.button("Generate"):
29
+ if not os.getenv("GROQ_API_KEY"):
30
+ st.error("GROQ_API_KEY missing.")
31
+ elif not idea.strip():
32
+ st.warning("Enter your idea.")
33
+ else:
34
+ prompt = build_quick_prompt(idea, tone, words, include_emoji, add_hashtags, language)
35
+ posts = []
36
+ with st.spinner("Generating…"):
37
+ try:
38
+ max_tokens = max(200, min(1200, int(words*1.6)+120))
39
+ for _ in range(variations):
40
+ raw = generate_post(prompt, model, temperature, top_p, max_tokens)
41
+ clean = dedupe_sentences(strip_labels(raw))
42
+ posts.append(clean)
43
+ except Exception as e:
44
+ st.error(f"Generation failed: {e}")
45
+ posts = []
46
+ for i, p in enumerate(posts, start=1):
47
+ st.markdown(f"#### Post {i}")
48
+ st.write(p)
49
+ st.download_button(f"Download Post {i}", p, file_name=f"post_{i}.txt")
50
+ if posts:
51
+ st.session_state.history.append({"mode":"quick","idea":idea,"tone":tone,"words":words,"posts":posts})
52
 
53
+ # Pro Mode
54
+ with tabs[1]:
55
+ st.markdown("Upload CSV/JSON of past posts (must include 'text') to auto-extract keywords (optional).")
56
+ uploaded = st.file_uploader("Upload dataset", type=["csv","json"])
57
+ defaults = {"topic":"AI agent playbooks for startup ops","audience":"SaaS founders in early stage"}
58
+ topic, purpose, audience, tone2, language2, evidence, style_text = pro_controls(defaults)
59
+ keywords = []
60
+ if uploaded is not None:
61
+ try:
62
+ df = load_posts(uploaded)
63
+ keywords = extract_keywords(topic, df)
64
+ st.success(f"Loaded {len(df)} posts. Extracted keywords: {', '.join(keywords[:8]) or '—'}")
65
+ except Exception as e:
66
+ st.error(f"Dataset error: {e}")
67
+ chosen_hook = ""
68
+ if st.button("Suggest 5 hooks"):
69
+ try:
70
+ hooks = generate_hooks(topic, audience, tone2, 5, model, temperature, top_p, 200)
71
+ st.code(hooks)
72
+ chosen_hook = st.text_input("Chosen opening line (optional)", value=chosen_hook)
73
+ except Exception as e:
74
+ st.error(f"Hook generation failed: {e}")
75
+ chosen_hook = st.text_input("Chosen opening line (optional)") # visible even if not generated
76
 
77
+ outcome = st.text_input("Desired outcome (e.g., 10 demo requests this week)", value="")
78
+ extra_detail = st.text_input("One concrete detail (e.g., 'onboarding 14→3 days')", value="")
79
+ clarifier_notes = "\n".join([f"Outcome: {outcome}" if outcome else "", f"Detail: {extra_detail}" if extra_detail else ""]).strip()
80
+ style_cues = [s.strip() for s in style_text.splitlines() if s.strip()][:4]
 
 
 
 
 
 
81
 
82
+ if st.button("Generate Post (Pro)"):
83
+ if not os.getenv("GROQ_API_KEY"):
84
+ st.error("GROQ_API_KEY missing.")
85
+ else:
86
+ try:
87
+ prompt = build_post_prompt(topic, language2, tone2, 160, purpose, audience, evidence, keywords, style_cues, clarifier_notes, chosen_hook)
88
+ raw = generate_post(prompt, model, temperature, top_p, 800)
89
+ post = dedupe_sentences(strip_labels(raw))
90
+ st.success("Post")
91
+ st.write(post)
92
+ st.download_button("Download (.txt)", post, file_name="linkedin_post.txt")
93
+ st.session_state.history.append({"mode":"pro","topic":topic,"audience":audience,"post":post})
94
+ except Exception as e:
95
+ st.error(f"Generation failed: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ # Refinements (transformations)
98
+ if st.button("Shorter"):
99
+ if st.session_state.get("history") and st.session_state.history[-1].get("post"):
 
 
 
 
100
  try:
101
+ instr = transform_instruction("shorter")
102
+ raw = transform_post(instr, st.session_state.history[-1]["post"], model, temperature, top_p, 500)
103
+ st.session_state.history[-1]["post"] = dedupe_sentences(strip_labels(raw))
104
+ st.write(st.session_state.history[-1]["post"])
105
  except Exception as e:
106
  st.error(f"Refinement failed: {e}")
107
+
108
+ # History
109
+ with tabs[2]:
110
+ if not st.session_state.history:
111
+ st.info("No saved drafts yet.")
112
+ else:
113
+ for i, item in enumerate(reversed(st.session_state.history), start=1):
114
+ st.markdown(f"#### Draft {i} ({item.get('mode')})")
115
+ if "posts" in item:
116
+ for j, p in enumerate(item["posts"], start=1):
117
+ st.markdown(f"Post {j}")
118
+ st.write(p)
119
+ else:
120
+ st.write(item.get("post",""))