osnarayana commited on
Commit
7006220
Β·
1 Parent(s): 578889f

Modified so that streamlit browser working fine

Browse files
app/api/v1/audio.py CHANGED
@@ -1,25 +1,27 @@
1
- # app/api/v1/audio.py
2
- from fastapi import APIRouter, HTTPException, Query, Depends, Request
3
  from pydantic import BaseModel
4
- from app.services.audio_service import generate_audio_file # βœ… Only this import
5
  from app.auth.auth import verify_token
6
-
 
 
7
 
8
  router = APIRouter()
9
 
10
- class AudioInput(BaseModel):
11
  text: str
12
  voice: str = "default"
13
  language: str = "en"
14
 
15
- @router.post("/generate", dependencies=[Depends(verify_token)])
16
- def generate_audio_endpoint(payload: AudioInput):
17
  try:
18
- file_path = generate_audio_file(payload.text, payload.voice, payload.language)
19
-
 
 
 
20
  return {
21
- "status": "success",
22
- "type": "audio",
23
  "file_path": file_path,
24
  "download_url": f"/api/v1/download?file_path={file_path}"
25
  }
 
1
+ from fastapi import APIRouter, HTTPException, Depends, Body
 
2
  from pydantic import BaseModel
3
+ from app.services.audio_service import generate_audio_file
4
  from app.auth.auth import verify_token
5
+ import uuid # βœ… Add this
6
+ import os # βœ… Also needed
7
+ from gtts import gTTS # βœ… Needed if you're calling it directly here
8
 
9
  router = APIRouter()
10
 
11
+ class AudioRequest(BaseModel):
12
  text: str
13
  voice: str = "default"
14
  language: str = "en"
15
 
16
+ @router.post("/generate")
17
+ def generate_audio_endpoint(payload: AudioRequest):
18
  try:
19
+ filename = f"audio_{uuid.uuid4().hex}.mp3"
20
+ file_path = f"generated_audio/{filename}"
21
+ os.makedirs("generated_audio", exist_ok=True)
22
+ tts = gTTS(text=payload.text, lang=payload.language)
23
+ tts.save(file_path)
24
  return {
 
 
25
  "file_path": file_path,
26
  "download_url": f"/api/v1/download?file_path={file_path}"
27
  }
app/api/v1/download.py CHANGED
@@ -1,24 +1,32 @@
1
- from fastapi import APIRouter, HTTPException, Query, Depends, Request
2
  from fastapi.responses import FileResponse
3
- from app.auth.auth import verify_token
4
  import os
5
 
6
  router = APIRouter()
7
 
8
- @router.get("/", dependencies=[Depends(verify_token)])
9
  def download_file(file_path: str = Query(..., description="Relative path from project root")):
10
- # Sanitize the input path
11
- file_path = os.path.normpath(file_path)
12
-
13
- # Absolute path (from project root)
14
- abs_path = os.path.join(os.getcwd(), file_path)
15
-
16
- print("Looking for file at:", abs_path)
17
- if not os.path.isfile(abs_path):
 
 
 
 
 
 
18
  raise HTTPException(status_code=404, detail="File not found")
19
 
 
 
 
20
  return FileResponse(
21
- path=abs_path,
22
- filename=os.path.basename(abs_path),
23
- media_type='application/octet-stream'
24
  )
 
1
+ from fastapi import APIRouter, HTTPException, Query
2
  from fastapi.responses import FileResponse
 
3
  import os
4
 
5
  router = APIRouter()
6
 
7
+ @router.get("/")
8
  def download_file(file_path: str = Query(..., description="Relative path from project root")):
9
+ print(f"πŸ” Requested file path: {file_path}")
10
+
11
+ # Sanitize and resolve absolute path
12
+ full_path = os.path.abspath(file_path)
13
+
14
+ # Ensure file is inside your allowed folder (to prevent directory traversal)
15
+ allowed_root = os.path.abspath("generated")
16
+ if not full_path.startswith(allowed_root):
17
+ raise HTTPException(status_code=400, detail="Invalid file path")
18
+
19
+ print(f"πŸ“‚ Resolved full path: {full_path}")
20
+
21
+ if not os.path.isfile(full_path):
22
+ print("❌ File not found.")
23
  raise HTTPException(status_code=404, detail="File not found")
24
 
25
+ # Set correct media type dynamically (you can refine this later)
26
+ media_type = "audio/mpeg" if full_path.endswith(".mp3") else "image/png"
27
+
28
  return FileResponse(
29
+ full_path,
30
+ media_type=media_type,
31
+ filename=os.path.basename(full_path)
32
  )
app/api/v1/image.py CHANGED
@@ -1,19 +1,54 @@
1
- from fastapi import APIRouter, HTTPException, Query, Depends, Request
2
  from pydantic import BaseModel
3
- from app.services.image_service import generate_image_file
4
  from app.auth.auth import verify_token
 
 
 
5
 
6
  router = APIRouter()
7
 
8
- class ImageInput(BaseModel):
9
  prompt: str
10
  style: str = "default"
11
 
12
- @router.post("/generate", dependencies=[Depends(verify_token)]) # βœ… FIX: POST, not GET
13
- def generate_image(payload: ImageInput):
14
- filename = generate_image_file(payload.prompt, payload.style)
15
- return {
16
- "message": "Image generated successfully",
17
- "filename": filename,
18
- "download_url": f"/api/v1/download?file_path=generated/image/{filename}"
19
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException, Depends, Body
2
  from pydantic import BaseModel
 
3
  from app.auth.auth import verify_token
4
+ from PIL import Image, ImageDraw, ImageFont
5
+ from datetime import datetime
6
+ import os
7
 
8
  router = APIRouter()
9
 
10
+ class ImageRequest(BaseModel):
11
  prompt: str
12
  style: str = "default"
13
 
14
+ class ImageResponse(BaseModel):
15
+ message: str
16
+ filename: str
17
+ download_url: str
18
+
19
+ @router.post("/generate", response_model=ImageResponse)
20
+ def generate_image_file_endpoint(
21
+ data: ImageRequest = Body(...),
22
+ token: str = Depends(verify_token)
23
+ ):
24
+ prompt = data.prompt
25
+ style = data.style
26
+ filename = f"image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
27
+ folder = "generated/image"
28
+ os.makedirs(folder, exist_ok=True)
29
+ output_path = os.path.join(folder, filename)
30
+
31
+ try:
32
+ img = Image.new("RGB", (768, 512), color="white")
33
+ draw = ImageDraw.Draw(img)
34
+
35
+ try:
36
+ font = ImageFont.truetype("arial.ttf", 20)
37
+ except:
38
+ font = ImageFont.load_default()
39
+
40
+ draw.text((20, 20), f"Prompt: {prompt}", fill="black", font=font)
41
+ draw.text((20, 60), f"Style: {style}", fill="gray", font=font)
42
+
43
+ img.save(output_path, format="PNG")
44
+
45
+ print(f"βœ… Image created: {output_path}, size = {os.path.getsize(output_path)} bytes")
46
+ return {
47
+ "message": "Image generated successfully",
48
+ "filename": filename,
49
+ "download_url": f"/api/v1/download?file_path=generated/image/{filename}"
50
+ }
51
+
52
+ except Exception as e:
53
+ print(f"❌ Image generation failed: {str(e)}")
54
+ raise HTTPException(status_code=500, detail=str(e))
app/api/v1/ppt.py CHANGED
@@ -14,7 +14,7 @@ class Slide(BaseModel):
14
  class PPTInput(BaseModel):
15
  slides: List[Slide]
16
 
17
- @router.post("/generate", dependencies=[Depends(verify_token)])
18
  def generate_ppt(payload: PPTInput):
19
  filename = generate_ppt_file([slide.dict() for slide in payload.slides])
20
  return {
 
14
  class PPTInput(BaseModel):
15
  slides: List[Slide]
16
 
17
+ @router.post("/generate")
18
  def generate_ppt(payload: PPTInput):
19
  filename = generate_ppt_file([slide.dict() for slide in payload.slides])
20
  return {
app/api/v1/video.py CHANGED
@@ -1,20 +1,37 @@
1
- from fastapi import APIRouter, HTTPException, Query, Depends, Request
 
2
  from pydantic import BaseModel
3
  from app.services.video_service import generate_video_file
4
  from app.auth.auth import verify_token
5
-
 
 
 
6
 
7
  router = APIRouter()
8
 
9
  class VideoInput(BaseModel):
10
- script: str
11
- duration: int = 10
 
 
 
12
 
13
- @router.post("/generate", dependencies=[Depends(verify_token)]) # βœ… FIX: POST, not GET
14
- def generate_video(payload: VideoInput):
15
- filename = generate_video_file(payload.script, payload.duration)
16
- return {
17
- "message": "Video generated successfully",
18
- "filename": filename,
19
- "download_url": f"/api/v1/download?file_path=generated/video/{filename}"
20
- }
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/v1/video.py
2
+ from fastapi import APIRouter, HTTPException, Depends, Body
3
  from pydantic import BaseModel
4
  from app.services.video_service import generate_video_file
5
  from app.auth.auth import verify_token
6
+ import uuid # βœ… Add this
7
+ import os # βœ… Also needed
8
+ from gtts import gTTS # βœ… Needed if you're calling it directly here
9
+ from typing import Optional
10
 
11
  router = APIRouter()
12
 
13
  class VideoInput(BaseModel):
14
+ prompt: str
15
+ tone: str
16
+ domain: str
17
+ environment: str
18
+ transcript: Optional[str] = None # βœ… make optional
19
 
20
+ @router.post("/generate")
21
+ def generate_video_endpoint(
22
+ payload: VideoInput = Body(...),
23
+ token: str = Depends(verify_token)):
24
+ try:
25
+ # Use `payload.prompt` as the script
26
+ filename = generate_video_file(
27
+ script=payload.prompt, # πŸ‘ˆ mapping prompt to script
28
+ duration=10 # Or dynamically set based on text length
29
+ )
30
+ return {
31
+ "message": "Video generated successfully",
32
+ "filename": filename,
33
+ "download_url": f"/api/v1/download?file_path=generated/video/{filename}"
34
+ }
35
+ except Exception as e:
36
+ print("❌ Video generation error:", str(e))
37
+ raise HTTPException(status_code=500, detail=str(e))
app/auth/auth.py CHANGED
@@ -1,32 +1,25 @@
1
- from fastapi import Request, HTTPException, status
2
- from fastapi import Depends, HTTPException, status
3
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
 
4
 
 
 
5
 
6
- # Replace with a more secure method later (e.g., from .env)
7
- API_TOKEN = "my_secure_token_123" # we can generate a random one using uuid or secrets
8
 
9
- def verify_token(request: Request):
10
- token = request.headers.get("Authorization")
11
- if not token or token.replace("Bearer ", "") != API_TOKEN:
12
- raise HTTPException(
13
- status_code=status.HTTP_401_UNAUTHORIZED,
14
- detail="Invalid or missing token",
15
- )
16
- return request
17
 
18
- security = HTTPBearer()
19
 
20
- VALID_TOKENS = {"token123", "mysecuretoken"} # Your valid tokens
21
 
22
- def auth_required(
23
- credentials: HTTPAuthorizationCredentials = Depends(security),
24
- ):
25
  token = credentials.credentials
26
- if token not in VALID_TOKENS:
 
27
  raise HTTPException(
28
- status_code=status.HTTP_401_UNAUTHORIZED,
29
- detail="Invalid or missing token"
30
  )
31
- return token
32
 
 
1
+ #from fastapi import Depends, HTTPException, status
2
+ from fastapi import HTTPException, Security
3
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
4
+ from starlette.status import HTTP_403_FORBIDDEN
5
 
6
+ from fastapi import Security
7
+ from fastapi.security import HTTPBearer
8
 
9
+ bearer_scheme = HTTPBearer()
 
10
 
11
+ #security = HTTPBearer()
 
 
 
 
 
 
 
12
 
13
+ from fastapi import Header, HTTPException, Depends
14
 
15
+ VALID_TOKENS = ["my_secure_token_123"] # or load from file/db/env
16
 
17
+ def verify_token(credentials: HTTPAuthorizationCredentials = Security(bearer_scheme)):
 
 
18
  token = credentials.credentials
19
+ # Replace with your actual logic (static check shown here)
20
+ if token != "my_secure_token_123":
21
  raise HTTPException(
22
+ status_code=HTTP_403_FORBIDDEN,
23
+ detail="Invalid or expired token"
24
  )
 
25
 
app/main.py CHANGED
@@ -1,8 +1,39 @@
1
  # app/main.py
 
 
 
 
2
  from fastapi import FastAPI
3
 
4
- app = FastAPI()
 
 
 
 
 
 
 
 
 
 
 
5
 
 
 
 
 
 
 
 
6
  @app.get("/")
7
  def root():
8
- return {"message": "FastAPI on Fly.io!"}
 
 
 
 
 
 
 
 
 
 
1
  # app/main.py
2
+ from fastapi import FastAPI, Depends
3
+ from fastapi.security import HTTPBearer
4
+ from fastapi import Security
5
+
6
  from fastapi import FastAPI
7
 
8
+ from app.api.v1.audio import router as audio_router
9
+ from app.api.v1.video import router as video_router
10
+ from app.api.v1.image import router as image_router
11
+ from app.api.v1.ppt import router as ppt_router
12
+ from app.api.v1.metrics import router as metrics_router
13
+ from app.api.v1.download import router as download_router
14
+ from fastapi import Security
15
+
16
+ from app.auth.auth import verify_token
17
+
18
+ bearer_scheme = HTTPBearer()
19
+
20
 
21
+ app = FastAPI(
22
+ title="Media Generation API",
23
+ description="Generate audio, video, image, and PPT content via secure endpoints.",
24
+ version="1.0.0"
25
+ )
26
+
27
+ # Root for health check
28
  @app.get("/")
29
  def root():
30
+ return {"message": "FastAPI running successfully!"}
31
+
32
+ # Registering route modules
33
+ app.include_router(audio_router, prefix="/api/v1/audio", tags=["Audio"], dependencies=[Depends(verify_token)])
34
+ app.include_router(video_router, prefix="/api/v1/video", tags=["Video"], dependencies=[Depends(verify_token)])
35
+ app.include_router(image_router, prefix="/api/v1/image", tags=["Image"], dependencies=[Depends(verify_token)])
36
+ app.include_router(ppt_router, prefix="/api/v1/ppt", tags=["PPT"], dependencies=[Depends(verify_token)])
37
+ app.include_router(metrics_router, prefix="/api/v1/metrics", tags=["Metrics"], dependencies=[Depends(verify_token)])
38
+ app.include_router(download_router, prefix="/api/v1/download", tags=["Download"])
39
+
app/services/audio_service.py CHANGED
@@ -6,6 +6,7 @@ from app.db import SessionLocal
6
  from app.models import MediaGeneration
7
  import logging
8
  logger = logging.getLogger(__name__)
 
9
 
10
  def generate_audio_file(text: str, voice: str = "default", language: str = "en") -> str:
11
  try:
 
6
  from app.models import MediaGeneration
7
  import logging
8
  logger = logging.getLogger(__name__)
9
+ import uuid
10
 
11
  def generate_audio_file(text: str, voice: str = "default", language: str = "en") -> str:
12
  try:
app/services/image_service.py CHANGED
@@ -18,6 +18,10 @@ def generate_image_file(prompt: str, style: str = "default") -> str:
18
  with open(os.path.join(folder, filename), "w") as f:
19
  f.write(f"Prompt: {prompt}\nStyle: {style}")
20
  logger.info(f"Generated Image: {filename}")
 
 
 
 
21
  return filename
22
  except:
23
  logger.error(f"Image Geneartion failed: {str(e)}")
 
18
  with open(os.path.join(folder, filename), "w") as f:
19
  f.write(f"Prompt: {prompt}\nStyle: {style}")
20
  logger.info(f"Generated Image: {filename}")
21
+ if os.path.isfile(output_path):
22
+ print(f"βœ… Image created: {output_path}, size = {os.path.getsize(output_path)} bytes")
23
+ else:
24
+ print(f"❌ Image file not found at: {output_path}")
25
  return filename
26
  except:
27
  logger.error(f"Image Geneartion failed: {str(e)}")
app/services/video_service - Copy.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/services/video_service.py
2
+ import os
3
+ from datetime import datetime
4
+ from app.db import SessionLocal
5
+ from app.models import MediaGeneration
6
+ import logging
7
+ logger = logging.getLogger(__name__)
8
+
9
+ def generate_video_file(script: str, duration: int = 10) -> str:
10
+ try:
11
+ # Simulate saving a generated video file
12
+ filename = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
13
+ folder = "generated/video"
14
+ os.makedirs(folder, exist_ok=True)
15
+
16
+ # Placeholder: Simulate video generation by writing script info to a file
17
+ with open(os.path.join(folder, filename), "w") as f:
18
+ f.write(f"Script: {script}\nDuration: {duration} seconds")
19
+ logger.info(f"Generated Video: {filename}")
20
+ return filename
21
+ except:
22
+ logger.error(f"Video generation failed: {str(e)}")
23
+ raise
24
+
25
+
26
+ def save_metadata(media_type, prompt, file_path):
27
+ db = SessionLocal()
28
+ record = MediaGeneration(
29
+ media_type=media_type,
30
+ prompt=prompt,
31
+ file_path=file_path,
32
+ )
33
+ db.add(record)
34
+ db.commit()
35
+ db.close()
app/services/video_service.py CHANGED
@@ -1,35 +1,67 @@
1
  # app/services/video_service.py
 
 
 
2
  import os
3
- from datetime import datetime
4
- from app.db import SessionLocal
5
- from app.models import MediaGeneration
6
- import logging
7
- logger = logging.getLogger(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- def generate_video_file(script: str, duration: int = 10) -> str:
10
  try:
11
- # Simulate saving a generated video file
12
- filename = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
13
- folder = "generated/video"
14
- os.makedirs(folder, exist_ok=True)
15
-
16
- # Placeholder: Simulate video generation by writing script info to a file
17
- with open(os.path.join(folder, filename), "w") as f:
18
- f.write(f"Script: {script}\nDuration: {duration} seconds")
19
- logger.info(f"Generated Video: {filename}")
20
- return filename
21
- except:
22
- logger.error(f"Video generation failed: {str(e)}")
23
- raise
24
-
25
-
26
- def save_metadata(media_type, prompt, file_path):
27
- db = SessionLocal()
28
- record = MediaGeneration(
29
- media_type=media_type,
30
- prompt=prompt,
31
- file_path=file_path,
32
- )
33
- db.add(record)
34
- db.commit()
35
- db.close()
 
1
  # app/services/video_service.py
2
+
3
+ import cv2
4
+ import numpy as np
5
  import os
6
+ import uuid
7
+ import math
8
+ from gtts import gTTS
9
+ from mutagen.mp3 import MP3
10
+ import subprocess
11
+
12
+ def generate_video_file(script: str, duration: int = None) -> str:
13
+ # Paths
14
+ audio_filename = f"generated/audio/audio_{uuid.uuid4().hex}.mp3"
15
+ raw_video_path = f"generated/video/video_{uuid.uuid4().hex}.mp4"
16
+ final_video_path = raw_video_path.replace(".mp4", "_final.mp4")
17
+
18
+ # Ensure directories exist
19
+ os.makedirs(os.path.dirname(audio_filename), exist_ok=True)
20
+ os.makedirs(os.path.dirname(raw_video_path), exist_ok=True)
21
+
22
+ # Generate audio
23
+ tts = gTTS(text=script, lang='en')
24
+ tts.save(audio_filename)
25
+
26
+ # Get accurate audio duration
27
+ audio = MP3(audio_filename)
28
+ audio_duration = audio.info.length # e.g., 5.98 seconds
29
+
30
+ # Video specs
31
+ fps = 25 # Higher FPS = smoother video
32
+ total_frames = int(audio_duration * fps)
33
+ width, height = 640, 480
34
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
35
+ out = cv2.VideoWriter(raw_video_path, fourcc, fps, (width, height))
36
+
37
+ # Create each frame
38
+ for _ in range(total_frames):
39
+ frame = np.ones((height, width, 3), dtype=np.uint8) * 255
40
+ cv2.putText(frame, script, (30, height // 2), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 2)
41
+ out.write(frame)
42
+
43
+ out.release()
44
+
45
+ # Merge audio and video
46
+ ffmpeg_cmd = [
47
+ "ffmpeg",
48
+ "-y",
49
+ "-i", raw_video_path,
50
+ "-i", audio_filename,
51
+ "-c:v", "libx264",
52
+ "-c:a", "aac",
53
+ "-crf", "23",
54
+ "-c:a", "aac",
55
+ "-b:a", "128k",
56
+ "-shortest",
57
+ "-movflags", "+faststart", # πŸ‘ˆ crucial for browser playback
58
+ final_video_path
59
+ ]
60
 
 
61
  try:
62
+ subprocess.run(ffmpeg_cmd, check=True)
63
+ except subprocess.CalledProcessError as e:
64
+ print(f"FFmpeg failed: {e}")
65
+ return None
66
+
67
+ return os.path.basename(final_video_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
generated_audio/audio_12aa4a7f8c6b4e459e88fd7bfa8559fe.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:343053419eba6ee94bd9d7fd54631336e97b693dea9775f2d57c6f342953cefb
3
+ size 9024
generated_audio/audio_2084def7399c47fc81f1ea75a2bb38df.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:343053419eba6ee94bd9d7fd54631336e97b693dea9775f2d57c6f342953cefb
3
+ size 9024
generated_audio/audio_4d6439239f3b4099b1e6fde8a9331613.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6924a2184a3a139ef4d6d9bc5e1e08d3b1b69d7e6904f8acb458d40cbc90fc73
3
+ size 9024
generated_audio/audio_785571d23e8c401886fbe9b176071973.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f1b9c225a86625e285d88be0b465bdb82177e21876fb7bedce63c313e018f343
3
+ size 47808
generated_audio/audio_8a8be69edd134341afc83be9d200f5c2.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:343053419eba6ee94bd9d7fd54631336e97b693dea9775f2d57c6f342953cefb
3
+ size 9024
generated_audio/audio_b3d3a162a45941579686e8bee223032e.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6924a2184a3a139ef4d6d9bc5e1e08d3b1b69d7e6904f8acb458d40cbc90fc73
3
+ size 9024
generated_audio/audio_ddccc5c34f7840bdb838254e343c7b14.mp3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:343053419eba6ee94bd9d7fd54631336e97b693dea9775f2d57c6f342953cefb
3
+ size 9024
streamlit_ui.py CHANGED
@@ -1,9 +1,12 @@
1
  # streamlit_ui.py
 
2
  import streamlit as st
3
  import requests
4
  import base64
 
 
 
5
  import tempfile
6
- from backend.subtitle_utils import generate_srt_from_text, enhance_video_with_subtitles_and_bgm
7
 
8
  st.set_page_config(
9
  page_title="Prompta - Text to Media Generator",
@@ -13,40 +16,95 @@ st.set_page_config(
13
  )
14
  st.title("πŸŽ™οΈπŸ–ΌοΈπŸŽžοΈ Prompta - Text to Media Generator")
15
 
16
- #API_BASE = "http://localhost:8000"
17
- API_BASE = "https://2255d6a4793d.ngrok-free.app"
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- def render_media(file_bytes, media_type, label):
 
 
 
 
20
  b64 = base64.b64encode(file_bytes).decode()
21
  if media_type == "audio":
22
  st.audio(f"data:audio/wav;base64,{b64}", format="audio/wav")
23
  elif media_type == "video":
24
  st.video(f"data:video/mp4;base64,{b64}")
25
  elif media_type == "image":
26
- st.image(file_bytes, caption=label, use_column_width=True)
 
 
 
 
 
 
27
 
28
  st.sidebar.header("πŸ› οΈ Settings")
29
- TOKEN = st.sidebar.text_input("πŸ”‘ API Token", type="password")
30
- HEADERS = {"Authorization": f"Bearer {TOKEN}"} if TOKEN else {}
 
 
 
 
 
 
 
 
31
 
32
  tab = st.sidebar.radio("Select Task", ["Text to Audio", "Text to Image", "Text to Video"])
33
 
34
  if tab == "Text to Audio":
35
  st.subheader("🎀 Text to Audio")
36
  text = st.text_area("Enter text")
37
- voice = st.selectbox("Choose voice/language", ["en-US", "hi-IN", "te-IN", "ta-IN"])
 
 
 
 
 
 
 
38
 
39
  if st.button("πŸ”Š Generate Audio"):
40
  with st.spinner("Generating audio..."):
41
- r = requests.post(f"{API_BASE}/audio/generate", json={"text": text, "voice": voice}, headers=HEADERS)
 
 
 
 
 
 
 
 
42
  if r.status_code == 200:
43
- data = r.json()
44
- download_url = f"{API_BASE}{data['download_url']}"
45
- audio_resp = requests.get(download_url, headers=HEADERS)
46
- if audio_resp.status_code == 200:
47
- render_media(audio_resp.content, "audio", "Generated Audio")
48
- else:
49
- st.error("❌ Failed to download audio file.")
 
 
 
 
 
 
 
 
 
 
 
50
  else:
51
  st.error(f"❌ Failed: {r.json().get('detail')}")
52
 
@@ -54,15 +112,41 @@ if tab == "Text to Audio":
54
  elif tab == "Text to Image":
55
  st.subheader("πŸ–ΌοΈ Text to Image")
56
  prompt = st.text_area("Enter image prompt")
57
- model = st.selectbox("Choose model", ["sdxl", "deepfloyd", "kandinsky"])
58
 
59
  if st.button("🧠 Generate Image"):
60
  with st.spinner("Generating image..."):
61
- r = requests.post(f"{API_BASE}/image/generate", json={"prompt": prompt, "model": model}, headers=HEADERS)
 
 
 
 
62
  if r.status_code == 200:
63
- render_media(r.content, "image", "Generated Image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  else:
65
- st.error(f"❌ Failed: {r.json().get('detail')}")
 
 
 
 
 
66
 
67
  elif tab == "Text to Video":
68
  st.subheader("🎞️ Text to Video")
@@ -77,32 +161,55 @@ elif tab == "Text to Video":
77
  if st.button("🎬 Generate Video"):
78
  with st.spinner("Generating video..."):
79
  r = requests.post(
80
- f"{API_BASE}/video/generate",
81
  json={"prompt": prompt, "tone": tone, "domain": domain, "environment": environment},
82
  headers=HEADERS
83
  )
84
  if r.status_code == 200:
85
- video_bytes = r.content
86
- if enhance and transcript:
87
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_vid:
88
- tmp_vid.write(video_bytes)
89
- tmp_vid_path = tmp_vid.name
90
-
91
- srt_path = generate_srt_from_text(transcript, output_path="streamlit_subs.srt")
92
- enhanced_path = "streamlit_final_video.mp4"
93
- enhance_video_with_subtitles_and_bgm(
94
- video_path=tmp_vid_path,
95
- srt_path=srt_path,
96
- bgm_path="default_bgm.mp3",
97
- output_path=enhanced_path
98
- )
99
-
100
- with open(enhanced_path, "rb") as f:
101
- render_media(f.read(), "video", "Enhanced Video")
102
- else:
103
- render_media(video_bytes, "video", "Generated Video")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  else:
105
- st.error(f"❌ Failed: {r.json().get('detail')}")
 
 
 
 
106
 
107
  st.sidebar.markdown("---")
108
  st.sidebar.info("Built with ❀️ for AI GovTech Challenge 2025")
 
1
  # streamlit_ui.py
2
+
3
  import streamlit as st
4
  import requests
5
  import base64
6
+ from PIL import Image
7
+ import io
8
+ import os
9
  import tempfile
 
10
 
11
  st.set_page_config(
12
  page_title="Prompta - Text to Media Generator",
 
16
  )
17
  st.title("πŸŽ™οΈπŸ–ΌοΈπŸŽžοΈ Prompta - Text to Media Generator")
18
 
19
+ # πŸ› οΈ Get Token FIRST
20
+ TOKEN = st.sidebar.text_input("πŸ”‘ API Token", type="password")
21
+ HEADERS = {"Authorization": f"Bearer {TOKEN}"} if TOKEN else {}
22
+
23
+ # βœ… Display AFTER token is typed
24
+ if TOKEN:
25
+ st.sidebar.write("Using token:", TOKEN)
26
+ st.sidebar.write("Sending headers:", HEADERS)
27
+ else:
28
+ st.sidebar.warning("⚠️ Please enter a valid API token to use the app.")
29
+
30
+ API_BASE = "http://localhost:8000"
31
+
32
 
33
+
34
+ API_BASE = "http://localhost:8000"
35
+ #API_BASE = "https://2255d6a4793d.ngrok-free.app"
36
+
37
+ def render_media(file_bytes, media_type, caption):
38
  b64 = base64.b64encode(file_bytes).decode()
39
  if media_type == "audio":
40
  st.audio(f"data:audio/wav;base64,{b64}", format="audio/wav")
41
  elif media_type == "video":
42
  st.video(f"data:video/mp4;base64,{b64}")
43
  elif media_type == "image":
44
+ try:
45
+ # Validate if it's a valid image
46
+ img = Image.open(io.BytesIO(file_bytes))
47
+ st.image(img, caption=caption)
48
+ except Exception as e:
49
+ st.warning("⚠️ Cannot render image. It may be corrupt or empty.")
50
+ st.code(str(e))
51
 
52
  st.sidebar.header("πŸ› οΈ Settings")
53
+ #TOKEN = st.sidebar.text_input("πŸ”‘ API Token", type="password")
54
+ #HEADERS = {"Authorization": f"Bearer {TOKEN}"} if TOKEN else {}
55
+
56
+ voice = st.selectbox("Choose voice", ["en", "hi", "te", "ta"])
57
+ voice_map = {
58
+ "en": "en-US",
59
+ "hi": "hi-IN",
60
+ "te": "te-IN",
61
+ "ta": "ta-IN"
62
+ }
63
 
64
  tab = st.sidebar.radio("Select Task", ["Text to Audio", "Text to Image", "Text to Video"])
65
 
66
  if tab == "Text to Audio":
67
  st.subheader("🎀 Text to Audio")
68
  text = st.text_area("Enter text")
69
+ voice = st.selectbox("Choose language", ["English", "Hindi", "Telugu", "Tamil"])
70
+ voice_map = {
71
+ "English": ("en-US", "en"),
72
+ "Hindi": ("hi-IN", "hi"),
73
+ "Telugu": ("te-IN", "te"),
74
+ "Tamil": ("ta-IN", "ta")
75
+ }
76
+ voice_code, lang_code = voice_map[voice]
77
 
78
  if st.button("πŸ”Š Generate Audio"):
79
  with st.spinner("Generating audio..."):
80
+ r = requests.post(
81
+ f"{API_BASE}/api/v1/audio/generate",
82
+ json={
83
+ "text": text,
84
+ "voice": voice_code,
85
+ "language": lang_code
86
+ },
87
+ headers=HEADERS
88
+ )
89
  if r.status_code == 200:
90
+ try:
91
+ data = r.json()
92
+ st.code(data, language="json") # Debug: show full JSON response in UI
93
+
94
+ if "download_url" in data:
95
+ download_url = f"{API_BASE}{data['download_url']}"
96
+ audio_resp = requests.get(download_url, headers=HEADERS)
97
+ if audio_resp.status_code == 200:
98
+ render_media(audio_resp.content, "audio", "Generated Audio")
99
+ else:
100
+ st.error("❌ Failed to download audio file.")
101
+ else:
102
+ st.error("❌ `download_url` not found in API response.")
103
+ st.code(data)
104
+ except Exception as e:
105
+ st.error("❌ Failed to parse API response.")
106
+ st.code(r.text)
107
+ st.exception(e)
108
  else:
109
  st.error(f"❌ Failed: {r.json().get('detail')}")
110
 
 
112
  elif tab == "Text to Image":
113
  st.subheader("πŸ–ΌοΈ Text to Image")
114
  prompt = st.text_area("Enter image prompt")
115
+ style = st.selectbox("Choose Style", ["sdxl", "deepfloyd", "kandinsky"])
116
 
117
  if st.button("🧠 Generate Image"):
118
  with st.spinner("Generating image..."):
119
+ r = requests.post(
120
+ f"{API_BASE}/api/v1/image/generate",
121
+ json={"prompt": prompt, "style": style}, # βœ… correct key
122
+ headers=HEADERS
123
+ )
124
  if r.status_code == 200:
125
+ try:
126
+ res_json = r.json()
127
+ download_url = res_json.get("download_url")
128
+ if not download_url:
129
+ st.error("No download URL returned.")
130
+ else:
131
+ download_full_url = f"{API_BASE}{download_url}"
132
+ image_response = requests.get(download_full_url, headers={"accept": "image/png"}, allow_redirects=True)
133
+ if image_response.status_code != 200:
134
+ st.error("❌ Failed to download image.")
135
+ st.code(image_response.text)
136
+ st.write("Status:", image_response.status_code)
137
+ st.write("Headers:", image_response.headers)
138
+ st.write(image_response.status_code, image_response.headers)
139
+ render_media(image_response.content, "image", "Generated Image")
140
+ except Exception as e:
141
+ st.error(f"⚠️ Failed to fetch/display image: {str(e)}")
142
+ st.code(r.text)
143
  else:
144
+ try:
145
+ detail = r.json().get("detail")
146
+ except Exception:
147
+ detail = r.text # fallback to raw response text (may be empty or HTML)
148
+
149
+ st.error(f"❌ Failed: {detail}")
150
 
151
  elif tab == "Text to Video":
152
  st.subheader("🎞️ Text to Video")
 
161
  if st.button("🎬 Generate Video"):
162
  with st.spinner("Generating video..."):
163
  r = requests.post(
164
+ f"{API_BASE}/api/v1/video/generate",
165
  json={"prompt": prompt, "tone": tone, "domain": domain, "environment": environment},
166
  headers=HEADERS
167
  )
168
  if r.status_code == 200:
169
+ try:
170
+ data = r.json()
171
+ st.code(data, language="json")
172
+
173
+ download_url = data.get("download_url")
174
+ if not download_url:
175
+ st.error("⚠️ No download URL received.")
176
+ else:
177
+ full_video_url = f"{API_BASE}{download_url}"
178
+ video_response = requests.get(full_video_url, headers=HEADERS)
179
+ if video_response.status_code == 200:
180
+ video_bytes = video_response.content
181
+ st.write("πŸ“¦ Video size (bytes):", len(video_bytes))
182
+
183
+ if enhance and transcript:
184
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_vid:
185
+ tmp_vid.write(video_bytes)
186
+ tmp_vid_path = tmp_vid.name
187
+
188
+ srt_path = generate_srt_from_text(transcript, output_path="streamlit_subs.srt")
189
+ enhanced_path = "streamlit_final_video.mp4"
190
+ enhance_video_with_subtitles_and_bgm(
191
+ video_path=tmp_vid_path,
192
+ srt_path=srt_path,
193
+ bgm_path="default_bgm.mp3",
194
+ output_path=enhanced_path
195
+ )
196
+
197
+ with open(enhanced_path, "rb") as f:
198
+ render_media(f.read(), "video", "Enhanced Video")
199
+ else:
200
+ st.video(video_bytes)
201
+ else:
202
+ st.error("❌ Failed to download video.")
203
+ except Exception as e:
204
+ st.error("❌ Error parsing response or rendering video.")
205
+ st.code(r.text)
206
+ st.exception(e)
207
  else:
208
+ try:
209
+ st.error(f"❌ Failed: {r.json().get('detail')}")
210
+ except:
211
+ st.error(f"❌ Failed: {r.text}")
212
+
213
 
214
  st.sidebar.markdown("---")
215
  st.sidebar.info("Built with ❀️ for AI GovTech Challenge 2025")