Spaces:
Sleeping
Sleeping
Nagesh Muralidhar
commited on
Commit
·
d7391ba
1
Parent(s):
62fea8b
midterm-submission
Browse files- podcraft/src/pages/Home.tsx +1 -1
- podcraft/src/pages/Podcasts.tsx +6 -4
- server/main.py +59 -54
podcraft/src/pages/Home.tsx
CHANGED
@@ -58,7 +58,7 @@ const Home: React.FC = () => {
|
|
58 |
agent: "system"
|
59 |
}]);
|
60 |
|
61 |
-
const response = await fetch(`${API_URL}/chat`, {
|
62 |
method: 'POST',
|
63 |
headers: {
|
64 |
'Content-Type': 'application/json',
|
|
|
58 |
agent: "system"
|
59 |
}]);
|
60 |
|
61 |
+
const response = await fetch(`${API_URL}/api/chat`, {
|
62 |
method: 'POST',
|
63 |
headers: {
|
64 |
'Content-Type': 'application/json',
|
podcraft/src/pages/Podcasts.tsx
CHANGED
@@ -2,7 +2,9 @@ import React, { useState, useEffect } from 'react';
|
|
2 |
import { useNavigate } from 'react-router-dom';
|
3 |
import '../App.css';
|
4 |
|
5 |
-
|
|
|
|
|
6 |
|
7 |
interface Podcast {
|
8 |
id: number;
|
@@ -25,7 +27,7 @@ const Podcasts: React.FC = () => {
|
|
25 |
|
26 |
const handleDelete = async (podcast: Podcast) => {
|
27 |
try {
|
28 |
-
const response = await fetch(`${API_URL}/audio/${podcast.filename}`, {
|
29 |
method: 'DELETE',
|
30 |
headers: {
|
31 |
'Content-Type': 'application/json',
|
@@ -51,7 +53,7 @@ const Podcasts: React.FC = () => {
|
|
51 |
|
52 |
const fetchPodcasts = async () => {
|
53 |
try {
|
54 |
-
const response = await fetch(`${API_URL}/audio-list`);
|
55 |
if (!response.ok) {
|
56 |
throw new Error('Failed to fetch podcasts');
|
57 |
}
|
@@ -67,7 +69,7 @@ const Podcasts: React.FC = () => {
|
|
67 |
id: index + 1,
|
68 |
title: `${descriptionPart.replace(/_/g, ' ').replace(/^\w/, c => c.toUpperCase())}`,
|
69 |
description: `A debate exploring ${queryPart.replace(/_/g, ' ')}`,
|
70 |
-
audio_file:
|
71 |
filename: filename,
|
72 |
category: category.replace(/_/g, ' ')
|
73 |
};
|
|
|
2 |
import { useNavigate } from 'react-router-dom';
|
3 |
import '../App.css';
|
4 |
|
5 |
+
// Use relative URLs in production, full URLs in development
|
6 |
+
const isDevelopment = window.location.hostname === 'localhost';
|
7 |
+
const API_URL = isDevelopment ? 'http://localhost:8000' : '';
|
8 |
|
9 |
interface Podcast {
|
10 |
id: number;
|
|
|
27 |
|
28 |
const handleDelete = async (podcast: Podcast) => {
|
29 |
try {
|
30 |
+
const response = await fetch(`${API_URL}/api/audio/${podcast.filename}`, {
|
31 |
method: 'DELETE',
|
32 |
headers: {
|
33 |
'Content-Type': 'application/json',
|
|
|
53 |
|
54 |
const fetchPodcasts = async () => {
|
55 |
try {
|
56 |
+
const response = await fetch(`${API_URL}/api/audio-list`);
|
57 |
if (!response.ok) {
|
58 |
throw new Error('Failed to fetch podcasts');
|
59 |
}
|
|
|
69 |
id: index + 1,
|
70 |
title: `${descriptionPart.replace(/_/g, ' ').replace(/^\w/, c => c.toUpperCase())}`,
|
71 |
description: `A debate exploring ${queryPart.replace(/_/g, ' ')}`,
|
72 |
+
audio_file: file.path, // Use relative path returned from server
|
73 |
filename: filename,
|
74 |
category: category.replace(/_/g, ' ')
|
75 |
};
|
server/main.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from fastapi import FastAPI, HTTPException
|
2 |
from fastapi.middleware.cors import CORSMiddleware
|
3 |
from fastapi.responses import FileResponse
|
4 |
from fastapi.staticfiles import StaticFiles
|
@@ -61,6 +61,9 @@ class PodcastChatResponse(BaseModel):
|
|
61 |
# Initialize FastAPI app
|
62 |
app = FastAPI()
|
63 |
|
|
|
|
|
|
|
64 |
# Configure CORS
|
65 |
app.add_middleware(
|
66 |
CORSMiddleware,
|
@@ -80,7 +83,7 @@ context_dir = os.path.join(os.path.dirname(__file__), "context_storage")
|
|
80 |
os.makedirs(context_dir, exist_ok=True)
|
81 |
|
82 |
# API Routes
|
83 |
-
@
|
84 |
async def chat(message: ChatMessage):
|
85 |
"""Process a chat message."""
|
86 |
try:
|
@@ -116,7 +119,7 @@ async def chat(message: ChatMessage):
|
|
116 |
logger.error(f"Error in chat endpoint: {str(e)}", exc_info=True)
|
117 |
raise HTTPException(status_code=500, detail=str(e))
|
118 |
|
119 |
-
@
|
120 |
async def list_audio_files():
|
121 |
"""List all available audio files."""
|
122 |
try:
|
@@ -134,8 +137,7 @@ async def list_audio_files():
|
|
134 |
except Exception as e:
|
135 |
raise HTTPException(status_code=500, detail=str(e))
|
136 |
|
137 |
-
|
138 |
-
@app.get("/audio/{filename}")
|
139 |
async def get_audio_file(filename: str):
|
140 |
"""Get an audio file by filename."""
|
141 |
try:
|
@@ -146,6 +148,55 @@ async def get_audio_file(filename: str):
|
|
146 |
except Exception as e:
|
147 |
raise HTTPException(status_code=500, detail=str(e))
|
148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
@app.get("/podcast/{podcast_id}/context")
|
150 |
async def get_podcast_context(podcast_id: str):
|
151 |
"""Get or generate context for a podcast."""
|
@@ -376,56 +427,10 @@ async def podcast_chat(podcast_id: str, request: PodcastChatRequest):
|
|
376 |
logger.error(f"Error in podcast chat: {str(e)}", exc_info=True)
|
377 |
raise HTTPException(status_code=500, detail=str(e))
|
378 |
|
379 |
-
|
380 |
-
|
381 |
-
"""Delete an audio file and its corresponding transcript."""
|
382 |
-
try:
|
383 |
-
# Delete audio file
|
384 |
-
file_path = os.path.join(audio_dir, filename)
|
385 |
-
if not os.path.exists(file_path):
|
386 |
-
raise HTTPException(status_code=404, detail="File not found")
|
387 |
-
|
388 |
-
# Get all audio files to determine the podcast ID
|
389 |
-
audio_files = [f for f in os.listdir(audio_dir) if f.endswith(('.mp3', '.wav'))]
|
390 |
-
try:
|
391 |
-
# Find the index (0-based) of the file being deleted
|
392 |
-
podcast_id = audio_files.index(filename) + 1 # Convert to 1-based ID
|
393 |
-
logger.info(f"Deleting podcast with ID: {podcast_id}")
|
394 |
-
|
395 |
-
# Path to transcripts file
|
396 |
-
transcripts_file = os.path.join(os.path.dirname(__file__), "transcripts", "podcasts.json")
|
397 |
-
|
398 |
-
# Update transcripts if file exists
|
399 |
-
if os.path.exists(transcripts_file):
|
400 |
-
with open(transcripts_file, 'r') as f:
|
401 |
-
transcripts = json.load(f)
|
402 |
-
|
403 |
-
# Remove the transcript at the corresponding index
|
404 |
-
if len(transcripts) >= podcast_id:
|
405 |
-
transcripts.pop(podcast_id - 1) # Convert back to 0-based index
|
406 |
-
|
407 |
-
# Save updated transcripts
|
408 |
-
with open(transcripts_file, 'w') as f:
|
409 |
-
json.dump(transcripts, f, indent=2)
|
410 |
-
logger.info(f"Removed transcript for podcast ID {podcast_id}")
|
411 |
-
|
412 |
-
# Delete the audio file
|
413 |
-
os.remove(file_path)
|
414 |
-
logger.info(f"Deleted audio file: {filename}")
|
415 |
-
|
416 |
-
return {"message": "File and transcript deleted successfully"}
|
417 |
-
|
418 |
-
except ValueError:
|
419 |
-
logger.error(f"Could not determine podcast ID for file: {filename}")
|
420 |
-
# Still delete the audio file even if transcript removal fails
|
421 |
-
os.remove(file_path)
|
422 |
-
return {"message": "Audio file deleted, but transcript could not be removed"}
|
423 |
-
|
424 |
-
except Exception as e:
|
425 |
-
logger.error(f"Error in delete_audio_file: {str(e)}")
|
426 |
-
raise HTTPException(status_code=500, detail=str(e))
|
427 |
|
428 |
-
#
|
429 |
app.mount("/audio-files", StaticFiles(directory=audio_dir), name="audio")
|
430 |
app.mount("/", StaticFiles(directory="static", html=True), name="frontend")
|
431 |
|
|
|
1 |
+
from fastapi import FastAPI, HTTPException, APIRouter
|
2 |
from fastapi.middleware.cors import CORSMiddleware
|
3 |
from fastapi.responses import FileResponse
|
4 |
from fastapi.staticfiles import StaticFiles
|
|
|
61 |
# Initialize FastAPI app
|
62 |
app = FastAPI()
|
63 |
|
64 |
+
# Create API router
|
65 |
+
api_router = APIRouter(prefix="/api")
|
66 |
+
|
67 |
# Configure CORS
|
68 |
app.add_middleware(
|
69 |
CORSMiddleware,
|
|
|
83 |
os.makedirs(context_dir, exist_ok=True)
|
84 |
|
85 |
# API Routes
|
86 |
+
@api_router.post("/chat")
|
87 |
async def chat(message: ChatMessage):
|
88 |
"""Process a chat message."""
|
89 |
try:
|
|
|
119 |
logger.error(f"Error in chat endpoint: {str(e)}", exc_info=True)
|
120 |
raise HTTPException(status_code=500, detail=str(e))
|
121 |
|
122 |
+
@api_router.get("/audio-list")
|
123 |
async def list_audio_files():
|
124 |
"""List all available audio files."""
|
125 |
try:
|
|
|
137 |
except Exception as e:
|
138 |
raise HTTPException(status_code=500, detail=str(e))
|
139 |
|
140 |
+
@api_router.get("/audio/{filename}")
|
|
|
141 |
async def get_audio_file(filename: str):
|
142 |
"""Get an audio file by filename."""
|
143 |
try:
|
|
|
148 |
except Exception as e:
|
149 |
raise HTTPException(status_code=500, detail=str(e))
|
150 |
|
151 |
+
@api_router.delete("/audio/{filename}")
|
152 |
+
async def delete_audio_file(filename: str):
|
153 |
+
"""Delete an audio file and its corresponding transcript."""
|
154 |
+
try:
|
155 |
+
# Delete audio file
|
156 |
+
file_path = os.path.join(audio_dir, filename)
|
157 |
+
if not os.path.exists(file_path):
|
158 |
+
raise HTTPException(status_code=404, detail="File not found")
|
159 |
+
|
160 |
+
# Get all audio files to determine the podcast ID
|
161 |
+
audio_files = [f for f in os.listdir(audio_dir) if f.endswith(('.mp3', '.wav'))]
|
162 |
+
try:
|
163 |
+
# Find the index (0-based) of the file being deleted
|
164 |
+
podcast_id = audio_files.index(filename) + 1 # Convert to 1-based ID
|
165 |
+
logger.info(f"Deleting podcast with ID: {podcast_id}")
|
166 |
+
|
167 |
+
# Path to transcripts file
|
168 |
+
transcripts_file = os.path.join(os.path.dirname(__file__), "transcripts", "podcasts.json")
|
169 |
+
|
170 |
+
# Update transcripts if file exists
|
171 |
+
if os.path.exists(transcripts_file):
|
172 |
+
with open(transcripts_file, 'r') as f:
|
173 |
+
transcripts = json.load(f)
|
174 |
+
|
175 |
+
# Remove the transcript at the corresponding index
|
176 |
+
if len(transcripts) >= podcast_id:
|
177 |
+
transcripts.pop(podcast_id - 1) # Convert back to 0-based index
|
178 |
+
|
179 |
+
# Save updated transcripts
|
180 |
+
with open(transcripts_file, 'w') as f:
|
181 |
+
json.dump(transcripts, f, indent=2)
|
182 |
+
logger.info(f"Removed transcript for podcast ID {podcast_id}")
|
183 |
+
|
184 |
+
# Delete the audio file
|
185 |
+
os.remove(file_path)
|
186 |
+
logger.info(f"Deleted audio file: {filename}")
|
187 |
+
|
188 |
+
return {"message": "File and transcript deleted successfully"}
|
189 |
+
|
190 |
+
except ValueError:
|
191 |
+
logger.error(f"Could not determine podcast ID for file: {filename}")
|
192 |
+
# Still delete the audio file even if transcript removal fails
|
193 |
+
os.remove(file_path)
|
194 |
+
return {"message": "Audio file deleted, but transcript could not be removed"}
|
195 |
+
|
196 |
+
except Exception as e:
|
197 |
+
logger.error(f"Error in delete_audio_file: {str(e)}")
|
198 |
+
raise HTTPException(status_code=500, detail=str(e))
|
199 |
+
|
200 |
@app.get("/podcast/{podcast_id}/context")
|
201 |
async def get_podcast_context(podcast_id: str):
|
202 |
"""Get or generate context for a podcast."""
|
|
|
427 |
logger.error(f"Error in podcast chat: {str(e)}", exc_info=True)
|
428 |
raise HTTPException(status_code=500, detail=str(e))
|
429 |
|
430 |
+
# Include the API router
|
431 |
+
app.include_router(api_router)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
432 |
|
433 |
+
# Mount static directories
|
434 |
app.mount("/audio-files", StaticFiles(directory=audio_dir), name="audio")
|
435 |
app.mount("/", StaticFiles(directory="static", html=True), name="frontend")
|
436 |
|