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

allows experimentation with prompts

Browse files
Files changed (1) hide show
  1. producer.py +231 -0
producer.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()