jameszokah commited on
Commit
23beeea
·
1 Parent(s): 6f1d384

UNDO the update for the path to the that was casing permission issues in entire app

Browse files
Dockerfile CHANGED
@@ -38,32 +38,31 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
38
  ffmpeg \
39
  git \
40
  build-essential \
 
41
  && apt-get clean \
42
  && rm -rf /var/lib/apt/lists/*
43
 
44
- # Create user and set up environment
45
- RUN useradd -m -u 1000 user
46
-
47
- USER user
48
-
49
- ENV HOME=/home/user \
50
- PATH=/home/user/.local/bin:$PATH
51
 
52
  # Set working directory
53
- WORKDIR $HOME/app
 
 
 
 
 
 
 
 
54
 
55
  # Copy requirements first for better caching
56
  COPY --chown=user:user requirements.txt .
57
 
58
- # Create and set up persistent directories with proper permissions
59
- RUN mkdir -p $HOME/app/static $HOME/app/models $HOME/app/voice_memories $HOME/app/voice_references \
60
- $HOME/app/voice_profiles $HOME/app/cloned_voices $HOME/app/audio_cache $HOME/app/tokenizers $HOME/app/logs && \
61
- chmod -R 755 $HOME/app && \
62
- chmod -R 777 $HOME/app/voice_references $HOME/app/voice_profiles $HOME/app/voice_memories \
63
- $HOME/app/cloned_voices $HOME/app/audio_cache $HOME/app/static $HOME/app/logs $HOME/app/tokenizers $HOME/app/models
64
-
65
- # Copy static files
66
- COPY --chown=user:user ./static $HOME/app/static
67
 
68
  # Install Python dependencies
69
  RUN pip3 install --no-cache-dir --upgrade pip && \
@@ -85,11 +84,12 @@ RUN pip3 install -r requirements.txt
85
  # Install additional dependencies for streaming and voice cloning
86
  RUN pip3 install yt-dlp openai-whisper
87
 
88
- # Copy application code
89
- COPY --chown=user:user ./app $HOME/app/app
 
90
 
91
  # Copy downloaded model from the model-downloader stage
92
- COPY --chown=user:user --from=model-downloader /model-downloader/models $HOME/app/models
93
 
94
  # Show available models in torchtune
95
  RUN python3 -c "import torchtune.models; print('Available models in torchtune:', dir(torchtune.models))"
 
38
  ffmpeg \
39
  git \
40
  build-essential \
41
+ sudo \
42
  && apt-get clean \
43
  && rm -rf /var/lib/apt/lists/*
44
 
45
+ # Create user and give sudo access
46
+ RUN useradd -m -s /bin/bash user && \
47
+ usermod -aG sudo user && \
48
+ echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
 
 
 
49
 
50
  # Set working directory
51
+ WORKDIR /app
52
+
53
+ # Create and set up persistent directories with proper permissions
54
+ RUN mkdir -p /app/static /app/models /app/voice_memories /app/voice_references \
55
+ /app/voice_profiles /app/cloned_voices /app/audio_cache /app/tokenizers /app/logs && \
56
+ chown -R user:user /app && \
57
+ chmod -R 755 /app && \
58
+ chmod -R 777 /app/voice_references /app/voice_profiles /app/voice_memories \
59
+ /app/cloned_voices /app/audio_cache /app/static /app/logs /app/tokenizers /app/models
60
 
61
  # Copy requirements first for better caching
62
  COPY --chown=user:user requirements.txt .
63
 
64
+ # Switch to user
65
+ USER user
 
 
 
 
 
 
 
66
 
67
  # Install Python dependencies
68
  RUN pip3 install --no-cache-dir --upgrade pip && \
 
84
  # Install additional dependencies for streaming and voice cloning
85
  RUN pip3 install yt-dlp openai-whisper
86
 
87
+ # Copy static files and application code
88
+ COPY --chown=user:user ./static /app/static
89
+ COPY --chown=user:user ./app /app/app
90
 
91
  # Copy downloaded model from the model-downloader stage
92
+ COPY --chown=user:user --from=model-downloader /model-downloader/models /app/models
93
 
94
  # Show available models in torchtune
95
  RUN python3 -c "import torchtune.models; print('Available models in torchtune:', dir(torchtune.models))"
app/api/routes.py CHANGED
@@ -16,7 +16,7 @@ import numpy as np
16
  from fastapi import APIRouter, Request, HTTPException, BackgroundTasks, Body, Response, Query
17
  from fastapi.responses import StreamingResponse
18
  from app.api.schemas import SpeechRequest, ResponseFormat, Voice
19
- from app.models import Segment, TTSRequest, TTSResponse, StreamRequest
20
  from app.api.streaming import AudioChunker
21
  from app.prompt_engineering import split_into_segments
22
 
@@ -24,11 +24,6 @@ from app.prompt_engineering import split_into_segments
24
  logger = logging.getLogger(__name__)
25
  router = APIRouter()
26
 
27
- # Constants
28
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
29
- AUDIO_CACHE_DIR = os.path.join(APP_DIR, "audio_cache")
30
- os.makedirs(AUDIO_CACHE_DIR, exist_ok=True)
31
-
32
  # Mapping of response_format to MIME types
33
  MIME_TYPES = {
34
  "mp3": "audio/mpeg",
@@ -438,7 +433,7 @@ async def format_audio(audio, response_format, sample_rate, app_state):
438
  # Generate a hash of the audio tensor for caching
439
  audio_hash = hashlib.md5(audio.cpu().numpy().tobytes()).hexdigest()
440
  cache_key = f"{audio_hash}_{response_format}"
441
- cache_dir = getattr(app_state, "audio_cache_dir", AUDIO_CACHE_DIR)
442
  os.makedirs(cache_dir, exist_ok=True)
443
  cache_path = os.path.join(cache_dir, f"{cache_key}")
444
 
@@ -539,7 +534,7 @@ async def format_audio(audio, response_format, sample_rate, app_state):
539
  # Store in cache if enabled
540
  if cache_enabled and cache_key:
541
  try:
542
- cache_path = os.path.join(getattr(app_state, "audio_cache_dir", AUDIO_CACHE_DIR), f"{cache_key}")
543
  with open(cache_path, "wb") as f:
544
  f.write(response_data)
545
  logger.debug(f"Cached {response_format} audio with key: {cache_key}")
 
16
  from fastapi import APIRouter, Request, HTTPException, BackgroundTasks, Body, Response, Query
17
  from fastapi.responses import StreamingResponse
18
  from app.api.schemas import SpeechRequest, ResponseFormat, Voice
19
+ from app.models import Segment
20
  from app.api.streaming import AudioChunker
21
  from app.prompt_engineering import split_into_segments
22
 
 
24
  logger = logging.getLogger(__name__)
25
  router = APIRouter()
26
 
 
 
 
 
 
27
  # Mapping of response_format to MIME types
28
  MIME_TYPES = {
29
  "mp3": "audio/mpeg",
 
433
  # Generate a hash of the audio tensor for caching
434
  audio_hash = hashlib.md5(audio.cpu().numpy().tobytes()).hexdigest()
435
  cache_key = f"{audio_hash}_{response_format}"
436
+ cache_dir = getattr(app_state, "audio_cache_dir", "/app/audio_cache")
437
  os.makedirs(cache_dir, exist_ok=True)
438
  cache_path = os.path.join(cache_dir, f"{cache_key}")
439
 
 
534
  # Store in cache if enabled
535
  if cache_enabled and cache_key:
536
  try:
537
+ cache_path = os.path.join(getattr(app_state, "audio_cache_dir", "/app/audio_cache"), f"{cache_key}")
538
  with open(cache_path, "wb") as f:
539
  f.write(response_data)
540
  logger.debug(f"Cached {response_format} audio with key: {cache_key}")
app/main.py CHANGED
@@ -54,7 +54,7 @@ async def lifespan(app: FastAPI):
54
  app.state.logger = logger # Make logger available to routes
55
 
56
  # Create necessary directories - use persistent locations
57
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
58
  os.makedirs(os.path.join(APP_DIR, "models"), exist_ok=True)
59
  os.makedirs(os.path.join(APP_DIR, "tokenizers"), exist_ok=True)
60
  os.makedirs(os.path.join(APP_DIR, "voice_memories"), exist_ok=True)
@@ -498,12 +498,11 @@ app.add_middleware(
498
  )
499
 
500
  # Create static and other required directories
501
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
502
- os.makedirs(os.path.join(APP_DIR, "static"), exist_ok=True)
503
- os.makedirs(os.path.join(APP_DIR, "cloned_voices"), exist_ok=True)
504
 
505
  # Mount the static files directory
506
- app.mount("/static", StaticFiles(directory=os.path.join(APP_DIR, "static")), name="static")
507
 
508
  # Include routers
509
  app.include_router(api_router, prefix="/api/v1")
@@ -590,13 +589,13 @@ async def version():
590
  @app.get("/voice-cloning", include_in_schema=False)
591
  async def voice_cloning_ui():
592
  """Voice cloning UI endpoint."""
593
- return FileResponse(os.path.join(APP_DIR, "static/voice-cloning.html"))
594
 
595
  # Streaming demo endpoint
596
  @app.get("/streaming-demo", include_in_schema=False)
597
  async def streaming_demo():
598
  """Streaming TTS demo endpoint."""
599
- return FileResponse(os.path.join(APP_DIR, "static/streaming-demo.html"))
600
 
601
  @app.get("/", include_in_schema=False)
602
  async def root():
 
54
  app.state.logger = logger # Make logger available to routes
55
 
56
  # Create necessary directories - use persistent locations
57
+ APP_DIR = "/app"
58
  os.makedirs(os.path.join(APP_DIR, "models"), exist_ok=True)
59
  os.makedirs(os.path.join(APP_DIR, "tokenizers"), exist_ok=True)
60
  os.makedirs(os.path.join(APP_DIR, "voice_memories"), exist_ok=True)
 
498
  )
499
 
500
  # Create static and other required directories
501
+ os.makedirs("/app/static", exist_ok=True)
502
+ os.makedirs("/app/cloned_voices", exist_ok=True)
 
503
 
504
  # Mount the static files directory
505
+ app.mount("/static", StaticFiles(directory="/app/static"), name="static")
506
 
507
  # Include routers
508
  app.include_router(api_router, prefix="/api/v1")
 
589
  @app.get("/voice-cloning", include_in_schema=False)
590
  async def voice_cloning_ui():
591
  """Voice cloning UI endpoint."""
592
+ return FileResponse("/app/static/voice-cloning.html")
593
 
594
  # Streaming demo endpoint
595
  @app.get("/streaming-demo", include_in_schema=False)
596
  async def streaming_demo():
597
  """Streaming TTS demo endpoint."""
598
+ return FileResponse("/app/static/streaming-demo.html")
599
 
600
  @app.get("/", include_in_schema=False)
601
  async def root():
app/utils/voice_manager.py CHANGED
@@ -8,23 +8,18 @@ from typing import Dict, List, Optional, Any
8
 
9
  logger = logging.getLogger(__name__)
10
 
11
- # Constants
12
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
13
- VOICE_REFERENCES_DIR = os.path.join(APP_DIR, "voice_references")
14
- VOICE_PROFILES_DIR = os.path.join(APP_DIR, "voice_profiles")
15
- VOICE_MEMORIES_DIR = os.path.join(APP_DIR, "voice_memories")
16
- VOICE_BACKUPS_DIR = os.path.join(APP_DIR, "voice_backups")
17
 
18
  # Ensure directories exist
19
  os.makedirs(VOICE_REFERENCES_DIR, exist_ok=True)
20
  os.makedirs(VOICE_PROFILES_DIR, exist_ok=True)
21
  os.makedirs(VOICE_MEMORIES_DIR, exist_ok=True)
22
- os.makedirs(VOICE_BACKUPS_DIR, exist_ok=True)
23
 
24
- def backup_voice_data(backup_dir: str = None):
25
  """Create a backup of all voice data."""
26
- if backup_dir is None:
27
- backup_dir = VOICE_BACKUPS_DIR
28
  os.makedirs(backup_dir, exist_ok=True)
29
  timestamp = torch.datetime.now().strftime("%Y%m%d_%H%M%S")
30
  backup_path = os.path.join(backup_dir, f"voice_backup_{timestamp}")
 
8
 
9
  logger = logging.getLogger(__name__)
10
 
11
+ # Define persistent paths
12
+ VOICE_REFERENCES_DIR = "/app/voice_references"
13
+ VOICE_PROFILES_DIR = "/app/voice_profiles"
14
+ VOICE_MEMORIES_DIR = "/app/voice_memories"
 
 
15
 
16
  # Ensure directories exist
17
  os.makedirs(VOICE_REFERENCES_DIR, exist_ok=True)
18
  os.makedirs(VOICE_PROFILES_DIR, exist_ok=True)
19
  os.makedirs(VOICE_MEMORIES_DIR, exist_ok=True)
 
20
 
21
+ def backup_voice_data(backup_dir: str = "/app/voice_backups"):
22
  """Create a backup of all voice data."""
 
 
23
  os.makedirs(backup_dir, exist_ok=True)
24
  timestamp = torch.datetime.now().strftime("%Y%m%d_%H%M%S")
25
  backup_path = os.path.join(backup_dir, f"voice_backup_{timestamp}")
app/voice_cloning.py CHANGED
@@ -27,8 +27,7 @@ from app.models import Segment
27
  logger = logging.getLogger(__name__)
28
 
29
  # Directory for storing cloned voice data
30
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
31
- CLONED_VOICES_DIR = os.path.join(APP_DIR, "cloned_voices")
32
  os.makedirs(CLONED_VOICES_DIR, exist_ok=True)
33
 
34
  class ClonedVoice(BaseModel):
 
27
  logger = logging.getLogger(__name__)
28
 
29
  # Directory for storing cloned voice data
30
+ CLONED_VOICES_DIR = "/app/cloned_voices"
 
31
  os.makedirs(CLONED_VOICES_DIR, exist_ok=True)
32
 
33
  class ClonedVoice(BaseModel):
app/voice_enhancement.py CHANGED
@@ -8,15 +8,13 @@ from typing import Dict, List, Optional, Tuple
8
  import logging
9
  from dataclasses import dataclass
10
  from scipy import signal
11
- from app.models import Segment
12
 
13
  # Setup logging
14
  logger = logging.getLogger(__name__)
15
 
16
- # Constants
17
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
18
- VOICE_REFERENCES_DIR = os.path.join(APP_DIR, "voice_references")
19
- VOICE_PROFILES_DIR = os.path.join(APP_DIR, "voice_profiles")
20
 
21
  # Ensure directories exist
22
  os.makedirs(VOICE_REFERENCES_DIR, exist_ok=True)
@@ -478,6 +476,8 @@ def get_voice_segments(voice_name: str, device: torch.device) -> List:
478
  Returns:
479
  List of context segments
480
  """
 
 
481
  if voice_name not in VOICE_PROFILES:
482
  logger.warning(f"Voice {voice_name} not found, defaulting to alloy")
483
  voice_name = "alloy"
 
8
  import logging
9
  from dataclasses import dataclass
10
  from scipy import signal
 
11
 
12
  # Setup logging
13
  logger = logging.getLogger(__name__)
14
 
15
+ # Define persistent paths
16
+ VOICE_REFERENCES_DIR = "/app/voice_references"
17
+ VOICE_PROFILES_DIR = "/app/voice_profiles"
 
18
 
19
  # Ensure directories exist
20
  os.makedirs(VOICE_REFERENCES_DIR, exist_ok=True)
 
476
  Returns:
477
  List of context segments
478
  """
479
+ from app.models import Segment
480
+
481
  if voice_name not in VOICE_PROFILES:
482
  logger.warning(f"Voice {voice_name} not found, defaulting to alloy")
483
  voice_name = "alloy"
app/voice_memory.py CHANGED
@@ -12,9 +12,8 @@ from app.models import Segment
12
  # Setup logging
13
  logger = logging.getLogger(__name__)
14
 
15
- # Constants
16
- APP_DIR = os.path.join(os.environ['HOME'], 'app')
17
- VOICE_MEMORIES_DIR = os.path.join(APP_DIR, "voice_memories")
18
  os.makedirs(VOICE_MEMORIES_DIR, exist_ok=True)
19
 
20
  @dataclass
 
12
  # Setup logging
13
  logger = logging.getLogger(__name__)
14
 
15
+ # Path to store voice memories - use persistent location
16
+ VOICE_MEMORIES_DIR = "/app/voice_memories"
 
17
  os.makedirs(VOICE_MEMORIES_DIR, exist_ok=True)
18
 
19
  @dataclass