Skip to content

Commit

Permalink
fix issues
Browse files Browse the repository at this point in the history
  • Loading branch information
giulioco committed Nov 16, 2024
1 parent 692062c commit cadc009
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 14 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
curl \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*

# Install Node.js and npm
Expand Down
8 changes: 4 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { CustomPodcast } from "@/components/CustomPodcast";
import { APIKeys } from "@/components/APIKeys";
import { NewsPodcast } from "@/components/NewsPodcast";
import { TopicPodcast } from "@/components/TopicPodcast";
import { Toaster } from "@/components/ui/toaster";

export default function App() {
Expand Down Expand Up @@ -57,13 +57,13 @@ export default function App() {
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="grid w-full grid-cols-2 mb-8">
<TabsTrigger value="custom">Custom Podcast</TabsTrigger>
<TabsTrigger value="news">News Podcast</TabsTrigger>
<TabsTrigger value="topic">Topic Research</TabsTrigger>
</TabsList>
<TabsContent value="custom">
<CustomPodcast />
</TabsContent>
<TabsContent value="news">
<NewsPodcast />
<TabsContent value="topic">
<TopicPodcast />
</TabsContent>
</Tabs>
</div>
Expand Down
39 changes: 29 additions & 10 deletions src/components/CustomPodcast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,8 @@ export function CustomPodcast() {
localStorage.setItem("podcast_urls", JSON.stringify(parsedUrls));
}, [parsedUrls]);

const onPaste = (e: React.ClipboardEvent) => {
e.preventDefault();
const pastedText = e.clipboardData.getData("text");
const urls = extractUrls(pastedText);

const handleUrlInput = (text: string) => {
const urls = extractUrls(text);
if (urls.length > 0) {
setParsedUrls((prev) => [...new Set([...prev, ...urls])]);
form.setValue("urls", "", { shouldValidate: true });
Expand All @@ -165,6 +162,20 @@ export function CustomPodcast() {
}
};

const onPaste = (e: React.ClipboardEvent) => {
e.preventDefault();
const pastedText = e.clipboardData.getData("text");
handleUrlInput(pastedText);
};

const onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
const inputText = form.getValues("urls");
handleUrlInput(inputText);
}
};

const removeUrl = (index: number) => {
// Prevent event propagation
event?.preventDefault();
Expand Down Expand Up @@ -362,9 +373,10 @@ export function CustomPodcast() {
<Label htmlFor="urls">Enter URLs</Label>
<Textarea
id="urls"
placeholder="Paste content containing URLs - they will be automatically extracted"
placeholder="Paste content containing URLs or type and press Enter to extract"
{...form.register("urls")}
onPaste={onPaste}
onKeyDown={onKeyDown}
className="min-h-[100px] font-mono text-sm"
/>
</div>
Expand Down Expand Up @@ -615,15 +627,22 @@ export function CustomPodcast() {
</div>

<div className="space-y-2">
<div className="flex items-center gap-2">
<div className="flex items-center justify-between mb-2">
<Label>Text-to-Speech Model</Label>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<InfoCircledIcon className="h-4 w-4 text-muted-foreground" />
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
type="button"
className="h-6 w-6 p-0"
>
<InfoCircledIcon className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent className="max-w-sm">
<div className="space-y-2">
<div className="space-y-2 text-sm">
<p className="font-semibold">
API Key Setup Instructions:
</p>
Expand Down
146 changes: 146 additions & 0 deletions src/components/TopicPodcast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";
import { useToast } from "@/hooks/use-toast";
import { Loader2, Play } from "lucide-react";
import { io } from "socket.io-client";
import { Card } from "@/components/ui/card";

export function TopicPodcast() {
const [isGenerating, setIsGenerating] = useState(false);
const [progress, setProgress] = useState(0);
const [statusMessage, setStatusMessage] = useState("");
const [audioUrl, setAudioUrl] = useState("");
const [, setTranscript] = useState("");
const [topic, setTopic] = useState("");
const { toast } = useToast();

const generateTopicPodcast = async () => {
if (!topic.trim()) {
toast({
title: "Missing Topic",
description: "Please enter a topic you'd like to learn about",
variant: "destructive",
});
return;
}

// Get the Gemini API key
const apiKey = sessionStorage.getItem("google_key");
if (!apiKey) {
toast({
title: "Missing API Key",
description: "Please set your Google API key first",
variant: "destructive",
});
return;
}

setIsGenerating(true);
setProgress(0);
setStatusMessage("Connecting to server...");
setAudioUrl("");
setTranscript("");

try {
const socket = io({
path: "/socket.io",
reconnection: true,
timeout: 10000,
});

socket.on("connect", () => {
console.log("Socket connected successfully");
setStatusMessage("Connected to server");

const payload = {
topics: topic,
google_key: apiKey,
};

socket.emit("generate_news_podcast", payload);
});

socket.on("progress", (data: { progress: number; message: string }) => {
setProgress(data.progress);
setStatusMessage(data.message);
});
} catch (error: any) {
toast({
title: "Error",
description: error.message || "Failed to generate podcast",
variant: "destructive",
});
setIsGenerating(false);
}
};

return (
<Card className="p-6 space-y-6">
<div className="space-y-4">
<div>
<h2 className="text-lg font-semibold mb-2">Topic Research Podcast</h2>
<p className="text-sm text-muted-foreground mb-4">
Enter any topic and we'll research it, synthesize the information,
and create an engaging podcast discussion about it. Perfect for
learning about new subjects or getting a comprehensive overview of
any topic.
</p>
</div>

<div className="space-y-2">
<Label htmlFor="topic">Topic</Label>
<Input
id="topic"
placeholder="e.g., Quantum Computing, Climate Change, History of Jazz"
value={topic}
onChange={(e) => setTopic(e.target.value)}
/>
<p className="text-sm text-muted-foreground">
Be as specific or broad as you'd like. We'll research and create an
informative discussion about it.
</p>
</div>
</div>

{isGenerating && (
<div className="space-y-2">
<Progress value={progress} className="w-full" />
<p className="text-sm text-center text-muted-foreground">
{statusMessage || `Generating podcast... ${progress}%`}
</p>
</div>
)}

{audioUrl && (
<div className="space-y-2">
<Label>Generated Topic Podcast</Label>
<audio controls className="w-full">
<source src={audioUrl} type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
</div>
)}

<Button
onClick={generateTopicPodcast}
className="w-full"
disabled={isGenerating}
>
{isGenerating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Researching and Generating Podcast
</>
) : (
<>
<Play className="mr-2 h-4 w-4" />
Generate Topic Podcast
</>
)}
</Button>
</Card>
);
}

0 comments on commit cadc009

Please sign in to comment.