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 |
|