dwarkesh commited on
Commit
f870c02
·
1 Parent(s): f80f903

actually did it in app

Browse files
Files changed (2) hide show
  1. app.py +40 -51
  2. producer.py +0 -231
app.py CHANGED
@@ -4,14 +4,11 @@ import pandas as pd
4
  from typing import Tuple, Dict
5
  from youtube_transcript_api import YouTubeTranscriptApi
6
  import re
7
- import json
8
- from pathlib import Path
9
 
10
- # Initialize Anthropic client and settings
11
  client = anthropic.Anthropic()
12
- PROMPTS_FILE = Path("prompts.json")
13
 
14
- # Default prompts
15
  DEFAULT_PROMPTS = {
16
  "clips": """You are a social media expert for the Dwarkesh Podcast. Generate 10 viral-worthy clips from the transcript.
17
  Format as:
@@ -48,23 +45,8 @@ Previous examples:
48
  {titles_and_thumbnails_examples}""",
49
  }
50
 
51
-
52
- def load_prompts() -> Dict[str, str]:
53
- """Load prompts from file or return defaults."""
54
- if PROMPTS_FILE.exists():
55
- with open(PROMPTS_FILE, "r") as f:
56
- return json.load(f)
57
- return DEFAULT_PROMPTS
58
-
59
-
60
- def save_prompts(prompts: Dict[str, str]) -> str:
61
- """Save prompts to file."""
62
- try:
63
- with open(PROMPTS_FILE, "w") as f:
64
- json.dump(prompts, f, indent=2)
65
- return f"Prompts saved to: {PROMPTS_FILE.absolute()}"
66
- except Exception as e:
67
- return f"Error saving prompts: {str(e)}"
68
 
69
 
70
  def load_examples(filename: str, columns: list) -> str:
@@ -101,12 +83,11 @@ def generate_content(
101
  ),
102
  }
103
 
104
- prompts = load_prompts()
105
  message = client.messages.create(
106
  model="claude-3-5-sonnet-20241022",
107
  max_tokens=max_tokens,
108
  temperature=temp,
109
- system=prompts[prompt_key].format(
110
  **{f"{prompt_key}_examples": examples[prompt_key]}
111
  ),
112
  messages=[
@@ -161,6 +142,20 @@ def process_transcript(input_text: str) -> Tuple[str, str, str, str]:
161
  return (error_msg,) * 4
162
 
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  def create_interface():
165
  """Create the Gradio interface."""
166
  with gr.Blocks(title="Podcast Transcript Analyzer") as app:
@@ -182,56 +177,50 @@ def create_interface():
182
  fn=process_transcript, inputs=[input_text], outputs=outputs
183
  )
184
 
185
- with gr.Tab("Configure Prompts"):
186
- gr.Markdown("# Edit Prompts")
187
- gr.Markdown(f"Prompts are saved to: `{PROMPTS_FILE.absolute()}`")
 
 
 
 
 
 
 
188
 
189
- prompts = load_prompts()
190
  prompt_inputs = [
191
  gr.Textbox(
192
- label="Clips Prompt",
193
- lines=10,
194
- value=prompts["clips"],
195
- interactive=True,
196
  ),
197
  gr.Textbox(
198
  label="Description Prompt",
199
  lines=10,
200
- value=prompts["description"],
201
- interactive=True,
202
  ),
203
  gr.Textbox(
204
  label="Timestamps Prompt",
205
  lines=10,
206
- value=prompts["timestamps"],
207
- interactive=True,
208
  ),
209
  gr.Textbox(
210
  label="Titles & Thumbnails Prompt",
211
  lines=10,
212
- value=prompts["titles_and_thumbnails"],
213
- interactive=True,
214
  ),
215
  ]
216
  status = gr.Textbox(label="Status", interactive=False)
217
 
218
- def save_prompts_callback(*values):
219
- new_prompts = {
220
- "clips": values[0],
221
- "description": values[1],
222
- "timestamps": values[2],
223
- "titles_and_thumbnails": values[3],
224
- }
225
- return save_prompts(new_prompts)
226
-
227
  for prompt in prompt_inputs:
228
- prompt.change(
229
- fn=save_prompts_callback, inputs=prompt_inputs, outputs=[status]
230
- )
231
 
 
232
  reset_btn = gr.Button("Reset to Default Prompts")
233
  reset_btn.click(
234
- fn=lambda: (save_prompts(DEFAULT_PROMPTS), *DEFAULT_PROMPTS.values()),
 
 
 
235
  outputs=[status] + prompt_inputs,
236
  )
237
 
 
4
  from typing import Tuple, Dict
5
  from youtube_transcript_api import YouTubeTranscriptApi
6
  import re
 
 
7
 
8
+ # Initialize Anthropic client
9
  client = anthropic.Anthropic()
 
10
 
11
+ # Default prompts that we can experiment with
12
  DEFAULT_PROMPTS = {
13
  "clips": """You are a social media expert for the Dwarkesh Podcast. Generate 10 viral-worthy clips from the transcript.
14
  Format as:
 
45
  {titles_and_thumbnails_examples}""",
46
  }
47
 
48
+ # Current prompts used in the session
49
+ current_prompts = DEFAULT_PROMPTS.copy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
 
52
  def load_examples(filename: str, columns: list) -> str:
 
83
  ),
84
  }
85
 
 
86
  message = client.messages.create(
87
  model="claude-3-5-sonnet-20241022",
88
  max_tokens=max_tokens,
89
  temperature=temp,
90
+ system=current_prompts[prompt_key].format(
91
  **{f"{prompt_key}_examples": examples[prompt_key]}
92
  ),
93
  messages=[
 
142
  return (error_msg,) * 4
143
 
144
 
145
+ def update_prompts(*values) -> str:
146
+ """Update the current session's prompts."""
147
+ global current_prompts
148
+ current_prompts = {
149
+ "clips": values[0],
150
+ "description": values[1],
151
+ "timestamps": values[2],
152
+ "titles_and_thumbnails": values[3],
153
+ }
154
+ return (
155
+ "Prompts updated for this session! Changes will reset when you reload the page."
156
+ )
157
+
158
+
159
  def create_interface():
160
  """Create the Gradio interface."""
161
  with gr.Blocks(title="Podcast Transcript Analyzer") as app:
 
177
  fn=process_transcript, inputs=[input_text], outputs=outputs
178
  )
179
 
180
+ with gr.Tab("Experiment with Prompts"):
181
+ gr.Markdown("# Experiment with Prompts")
182
+ gr.Markdown(
183
+ """
184
+ Here you can experiment with different prompts during your session.
185
+ Changes will remain active until you reload the page.
186
+
187
+ Tip: Copy your preferred prompts somewhere safe if you want to reuse them later!
188
+ """
189
+ )
190
 
 
191
  prompt_inputs = [
192
  gr.Textbox(
193
+ label="Clips Prompt", lines=10, value=DEFAULT_PROMPTS["clips"]
 
 
 
194
  ),
195
  gr.Textbox(
196
  label="Description Prompt",
197
  lines=10,
198
+ value=DEFAULT_PROMPTS["description"],
 
199
  ),
200
  gr.Textbox(
201
  label="Timestamps Prompt",
202
  lines=10,
203
+ value=DEFAULT_PROMPTS["timestamps"],
 
204
  ),
205
  gr.Textbox(
206
  label="Titles & Thumbnails Prompt",
207
  lines=10,
208
+ value=DEFAULT_PROMPTS["titles_and_thumbnails"],
 
209
  ),
210
  ]
211
  status = gr.Textbox(label="Status", interactive=False)
212
 
213
+ # Update prompts when they change
 
 
 
 
 
 
 
 
214
  for prompt in prompt_inputs:
215
+ prompt.change(fn=update_prompts, inputs=prompt_inputs, outputs=[status])
 
 
216
 
217
+ # Reset button
218
  reset_btn = gr.Button("Reset to Default Prompts")
219
  reset_btn.click(
220
+ fn=lambda: (
221
+ update_prompts(*DEFAULT_PROMPTS.values()),
222
+ *DEFAULT_PROMPTS.values(),
223
+ ),
224
  outputs=[status] + prompt_inputs,
225
  )
226
 
producer.py DELETED
@@ -1,231 +0,0 @@
1
- import gradio as gr
2
- import anthropic
3
- import pandas as pd
4
- from typing import Tuple, Dict
5
- from youtube_transcript_api import YouTubeTranscriptApi
6
- import re
7
-
8
- # Initialize Anthropic client
9
- client = anthropic.Anthropic()
10
-
11
- # Default prompts that we can experiment with
12
- DEFAULT_PROMPTS = {
13
- "clips": """You are a social media expert for the Dwarkesh Podcast. Generate 10 viral-worthy clips from the transcript.
14
- Format as:
15
- Tweet 1
16
- Tweet Text: [text]
17
- Clip Transcript: [45-120 seconds of transcript]
18
-
19
- Previous examples:
20
- {clips_examples}""",
21
- "description": """Create an engaging episode description tweet (280 chars max) that:
22
- 1. Highlights compelling aspects
23
- 2. Includes topic areas and handles
24
- 3. Ends with "Links below" or "Enjoy!"
25
-
26
- Previous examples:
27
- {description_examples}""",
28
- "timestamps": """Generate timestamps (HH:MM:SS) every 3-8 minutes covering key transitions and moments.
29
- Use 2-6 word descriptions.
30
- Start at 00:00:00.
31
-
32
- Previous examples:
33
- {timestamps_examples}""",
34
- "titles_and_thumbnails": """Create 3-5 compelling title-thumbnail combinations that tell a story.
35
-
36
- Title Format: "Guest Name – Key Story or Core Insight"
37
- Thumbnail: 2-4 ALL CAPS words that create intrigue with the title
38
-
39
- Example: "David Reich – How One Small Tribe Conquered the World 70,000 Years Ago"
40
- Thumbnail: "LAST HUMANS STANDING"
41
-
42
- The combination should create intellectual curiosity without clickbait.
43
-
44
- Previous examples:
45
- {titles_and_thumbnails_examples}""",
46
- }
47
-
48
- # Current prompts used in the session
49
- current_prompts = DEFAULT_PROMPTS.copy()
50
-
51
-
52
- def load_examples(filename: str, columns: list) -> str:
53
- """Load examples from CSV file."""
54
- try:
55
- df = pd.read_csv(filename)
56
- if len(columns) == 1:
57
- examples = df[columns[0]].dropna().tolist()
58
- return "\n\n".join(examples)
59
-
60
- examples = []
61
- for _, row in df.iterrows():
62
- if all(pd.notna(row[col]) for col in columns):
63
- example = "\n".join(f"{col}: {row[col]}" for col in columns)
64
- examples.append(example)
65
- return "\n\n".join(examples)
66
- except Exception as e:
67
- print(f"Error loading {filename}: {str(e)}")
68
- return ""
69
-
70
-
71
- def generate_content(
72
- prompt_key: str, transcript: str, max_tokens: int = 1000, temp: float = 0.6
73
- ) -> str:
74
- """Generate content using Claude."""
75
- examples = {
76
- "clips": load_examples(
77
- "Viral Twitter Clips.csv", ["Tweet Text", "Clip Transcript"]
78
- ),
79
- "description": load_examples("Viral Episode Descriptions.csv", ["Tweet Text"]),
80
- "timestamps": load_examples("Timestamps.csv", ["Timestamps"]),
81
- "titles_and_thumbnails": load_examples(
82
- "Titles & Thumbnails.csv", ["Titles", "Thumbnail"]
83
- ),
84
- }
85
-
86
- message = client.messages.create(
87
- model="claude-3-5-sonnet-20241022",
88
- max_tokens=max_tokens,
89
- temperature=temp,
90
- system=current_prompts[prompt_key].format(
91
- **{f"{prompt_key}_examples": examples[prompt_key]}
92
- ),
93
- messages=[
94
- {
95
- "role": "user",
96
- "content": [
97
- {
98
- "type": "text",
99
- "text": f"Process this transcript:\n\n{transcript}",
100
- }
101
- ],
102
- }
103
- ],
104
- )
105
- return message.content[0].text
106
-
107
-
108
- def get_youtube_transcript(url: str) -> str:
109
- """Get transcript from YouTube URL."""
110
- try:
111
- video_id = re.search(
112
- r"(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/)([A-Za-z0-9_-]+)",
113
- url,
114
- ).group(1)
115
- transcript = YouTubeTranscriptApi.list_transcripts(video_id).find_transcript(
116
- ["en"]
117
- )
118
- return " ".join(entry["text"] for entry in transcript.fetch())
119
- except Exception as e:
120
- raise Exception(f"Error fetching YouTube transcript: {str(e)}")
121
-
122
-
123
- def process_transcript(input_text: str) -> Tuple[str, str, str, str]:
124
- """Process input and generate all content."""
125
- try:
126
- # Get transcript from URL or use direct input
127
- transcript = (
128
- get_youtube_transcript(input_text)
129
- if any(x in input_text for x in ["youtube.com", "youtu.be"])
130
- else input_text
131
- )
132
-
133
- # Generate all content types
134
- return (
135
- generate_content("clips", transcript, max_tokens=8192),
136
- generate_content("description", transcript),
137
- generate_content("timestamps", transcript, temp=0.4),
138
- generate_content("titles_and_thumbnails", transcript, temp=0.7),
139
- )
140
- except Exception as e:
141
- error_msg = f"Error processing input: {str(e)}"
142
- return (error_msg,) * 4
143
-
144
-
145
- def update_prompts(*values) -> str:
146
- """Update the current session's prompts."""
147
- global current_prompts
148
- current_prompts = {
149
- "clips": values[0],
150
- "description": values[1],
151
- "timestamps": values[2],
152
- "titles_and_thumbnails": values[3],
153
- }
154
- return (
155
- "Prompts updated for this session! Changes will reset when you reload the page."
156
- )
157
-
158
-
159
- def create_interface():
160
- """Create the Gradio interface."""
161
- with gr.Blocks(title="Podcast Transcript Analyzer") as app:
162
- with gr.Tab("Generate Content"):
163
- gr.Markdown("# Podcast Content Generator")
164
- input_text = gr.Textbox(
165
- label="Input", placeholder="YouTube URL or transcript...", lines=10
166
- )
167
- submit_btn = gr.Button("Generate Content")
168
- outputs = [
169
- gr.Textbox(label="Twitter Clips", lines=10, interactive=False),
170
- gr.Textbox(label="Twitter Description", lines=3, interactive=False),
171
- gr.Textbox(label="Timestamps", lines=10, interactive=False),
172
- gr.Textbox(
173
- label="Title & Thumbnail Suggestions", lines=10, interactive=False
174
- ),
175
- ]
176
- submit_btn.click(
177
- fn=process_transcript, inputs=[input_text], outputs=outputs
178
- )
179
-
180
- with gr.Tab("Experiment with Prompts"):
181
- gr.Markdown("# Experiment with Prompts")
182
- gr.Markdown(
183
- """
184
- Here you can experiment with different prompts during your session.
185
- Changes will remain active until you reload the page.
186
-
187
- Tip: Copy your preferred prompts somewhere safe if you want to reuse them later!
188
- """
189
- )
190
-
191
- prompt_inputs = [
192
- gr.Textbox(
193
- label="Clips Prompt", lines=10, value=DEFAULT_PROMPTS["clips"]
194
- ),
195
- gr.Textbox(
196
- label="Description Prompt",
197
- lines=10,
198
- value=DEFAULT_PROMPTS["description"],
199
- ),
200
- gr.Textbox(
201
- label="Timestamps Prompt",
202
- lines=10,
203
- value=DEFAULT_PROMPTS["timestamps"],
204
- ),
205
- gr.Textbox(
206
- label="Titles & Thumbnails Prompt",
207
- lines=10,
208
- value=DEFAULT_PROMPTS["titles_and_thumbnails"],
209
- ),
210
- ]
211
- status = gr.Textbox(label="Status", interactive=False)
212
-
213
- # Update prompts when they change
214
- for prompt in prompt_inputs:
215
- prompt.change(fn=update_prompts, inputs=prompt_inputs, outputs=[status])
216
-
217
- # Reset button
218
- reset_btn = gr.Button("Reset to Default Prompts")
219
- reset_btn.click(
220
- fn=lambda: (
221
- update_prompts(*DEFAULT_PROMPTS.values()),
222
- *DEFAULT_PROMPTS.values(),
223
- ),
224
- outputs=[status] + prompt_inputs,
225
- )
226
-
227
- return app
228
-
229
-
230
- if __name__ == "__main__":
231
- create_interface().launch()