marquesafonso commited on
Commit
c564fad
·
1 Parent(s): 25a7124

make api stateless with tempfile.

Browse files
Dockerfile CHANGED
@@ -1,11 +1,15 @@
1
  # Use an official Python runtime as a parent image
2
  FROM python:3.11.7-slim-bullseye
3
 
 
 
 
 
4
  # Set the working directory in the container to /app
5
  WORKDIR /app
6
 
7
  # Copy the current directory contents into the container at /app
8
- COPY . /app
9
 
10
  #Install ImageMagick
11
  RUN apt-get update && apt-get install -y imagemagick && sed -i '91d' /etc/ImageMagick-6/policy.xml
 
1
  # Use an official Python runtime as a parent image
2
  FROM python:3.11.7-slim-bullseye
3
 
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+
8
  # Set the working directory in the container to /app
9
  WORKDIR /app
10
 
11
  # Copy the current directory contents into the container at /app
12
+ COPY --chown=user . /app
13
 
14
  #Install ImageMagick
15
  RUN apt-get update && apt-get install -y imagemagick && sed -i '91d' /etc/ImageMagick-6/policy.xml
main.py CHANGED
@@ -1,31 +1,21 @@
1
- from fastapi import FastAPI, UploadFile, HTTPException, Form, Depends
2
- from fastapi.responses import FileResponse, HTMLResponse
3
- from fastapi.security import HTTPBasic, HTTPBasicCredentials
4
  from typing import Optional
5
- from pydantic import BaseModel, field_validator
6
  from utils.process_video import process_video
7
  from utils.zip_response import zip_response
8
  from utils.api_configs import api_configs
9
  from utils.read_html import read_html
10
- from utils.archiver import archiver
11
  from utils.logger import setup_logger
12
- import shutil, os, logging, uvicorn, secrets
 
 
 
 
13
 
14
  app = FastAPI()
15
  security = HTTPBasic()
16
  api_configs_file = os.path.abspath("api_config.yml")
17
 
18
- async def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
19
- correct_username = secrets.compare_digest(credentials.username, api_configs(api_configs_file)["secrets"]["username"])
20
- correct_password = secrets.compare_digest(credentials.password, api_configs(api_configs_file)["secrets"]["password"])
21
- if not (correct_username and correct_password):
22
- raise HTTPException(
23
- status_code=401,
24
- detail="Incorrect email or password",
25
- headers={"WWW-Authenticate": "Basic"},
26
- )
27
- return credentials.username
28
-
29
  class MP4Video(BaseModel):
30
  video_file: UploadFile
31
 
@@ -61,7 +51,6 @@ class SRTFile(BaseModel):
61
  raise HTTPException(status_code=422, detail='Invalid subtitle file type. Please upload an SRT file.')
62
  return v
63
 
64
-
65
  @app.get("/")
66
  async def root():
67
  html_content = f"""
@@ -77,6 +66,13 @@ async def get_form():
77
  """
78
  return HTMLResponse(content=html_content)
79
 
 
 
 
 
 
 
 
80
  @app.post("/process_video/")
81
  async def process_video_api(video_file: MP4Video = Depends(),
82
  srt_file: SRTFile = Depends(),
@@ -87,40 +83,36 @@ async def process_video_api(video_file: MP4Video = Depends(),
87
  bg_color: Optional[str] = Form("#070a13b3"),
88
  text_color: Optional[str] = Form("white"),
89
  caption_mode: Optional[str] = Form("desktop"),
90
- username: str = Depends(get_current_user)
91
  ):
92
  try:
93
  logging.info("Creating temporary directories")
94
- temp_dir = os.path.join(os.getcwd(),"temp")
95
- os.makedirs(temp_dir, exist_ok=True)
96
- temp_vid_dir = os.path.join(temp_dir,video_file.filename.split('.')[0])
97
- os.makedirs(temp_vid_dir, exist_ok=True)
98
- temp_input_path = os.path.join(temp_vid_dir, video_file.filename)
99
- logging.info("Copying video UploadFile to the temp_input_path")
100
- with open(temp_input_path, 'wb') as buffer:
101
  try:
102
- shutil.copyfileobj(video_file.file, buffer)
103
  finally:
104
  video_file.file.close()
105
- logging.info("Copying SRT UploadFile to the temp_input_path")
106
- if srt_file.size > 0:
107
- SRT_PATH = os.path.abspath(f"{temp_input_path.split('.')[0]}.srt")
108
- with open(SRT_PATH, 'wb') as buffer:
109
- try:
110
- shutil.copyfileobj(srt_file.file, buffer)
111
- finally:
112
- srt_file.file.close()
113
- logging.info("Processing the video...")
114
- output_path, _ = process_video(temp_input_path, SRT_PATH, task, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode)
115
- logging.info("Zipping response...")
116
- zip_path = zip_response(os.path.join(temp_vid_dir,"archive.zip"), [output_path, SRT_PATH])
117
- return FileResponse(zip_path, media_type='application/zip', filename=f"result_{video_file.filename.split('.')[0]}.zip")
118
- logging.info("Processing the video...")
119
- output_path, srt_path = process_video(temp_input_path, None, task, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode, api_configs_file)
120
- logging.info("Zipping response...")
121
- zip_path = zip_response(os.path.join(temp_vid_dir,"archive.zip"), [output_path, srt_path])
122
- return FileResponse(zip_path, media_type='application/zip', filename=f"result_{video_file.filename.split('.')[0]}.zip")
123
-
 
124
  except Exception as e:
125
  raise HTTPException(status_code=500, detail=str(e))
126
 
 
1
+ import shutil, os, logging, uvicorn, tempfile
 
 
2
  from typing import Optional
3
+
4
  from utils.process_video import process_video
5
  from utils.zip_response import zip_response
6
  from utils.api_configs import api_configs
7
  from utils.read_html import read_html
 
8
  from utils.logger import setup_logger
9
+
10
+ from fastapi import FastAPI, UploadFile, HTTPException, Form, Depends
11
+ from fastapi.responses import HTMLResponse, Response
12
+ from fastapi.security import HTTPBasic
13
+ from pydantic import BaseModel, field_validator
14
 
15
  app = FastAPI()
16
  security = HTTPBasic()
17
  api_configs_file = os.path.abspath("api_config.yml")
18
 
 
 
 
 
 
 
 
 
 
 
 
19
  class MP4Video(BaseModel):
20
  video_file: UploadFile
21
 
 
51
  raise HTTPException(status_code=422, detail='Invalid subtitle file type. Please upload an SRT file.')
52
  return v
53
 
 
54
  @app.get("/")
55
  async def root():
56
  html_content = f"""
 
66
  """
67
  return HTMLResponse(content=html_content)
68
 
69
+ async def get_temp_dir():
70
+ dir = tempfile.TemporaryDirectory()
71
+ try:
72
+ yield dir.name
73
+ finally:
74
+ del dir
75
+
76
  @app.post("/process_video/")
77
  async def process_video_api(video_file: MP4Video = Depends(),
78
  srt_file: SRTFile = Depends(),
 
83
  bg_color: Optional[str] = Form("#070a13b3"),
84
  text_color: Optional[str] = Form("white"),
85
  caption_mode: Optional[str] = Form("desktop"),
86
+ temp_dir: str = Depends(get_temp_dir)
87
  ):
88
  try:
89
  logging.info("Creating temporary directories")
90
+ with open(os.path.join(temp_dir, video_file.filename), 'w+b') as temp_file:
91
+ logging.info("Copying video UploadFile to the temporary directory")
 
 
 
 
 
92
  try:
93
+ shutil.copyfileobj(video_file.file, temp_file)
94
  finally:
95
  video_file.file.close()
96
+ logging.info("Copying SRT UploadFile to the temp_input_path")
97
+ if srt_file.size > 0:
98
+ with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.srt"), 'w+b') as temp_srt_file:
99
+ try:
100
+ shutil.copyfileobj(srt_file.file, temp_srt_file)
101
+ finally:
102
+ srt_file.file.close()
103
+ logging.info("Processing the video...")
104
+ output_path, _ = process_video(temp_file.name, temp_srt_file.name, task, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode)
105
+ logging.info("Zipping response...")
106
+ with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.zip"), 'w+b') as temp_zip_file:
107
+ zip_file = zip_response(temp_zip_file.name, [output_path, srt_path])
108
+ return Response(content = zip_file)
109
+ with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.srt"), 'w+b') as temp_srt_file:
110
+ logging.info("Processing the video...")
111
+ output_path, srt_path = process_video(temp_file.name, None, task, max_words_per_line, fontsize, font, bg_color, text_color, caption_mode, api_configs_file)
112
+ logging.info("Zipping response...")
113
+ with open(os.path.join(temp_dir, f"{video_file.filename.split('.')[0]}.zip"), 'w+b') as temp_zip_file:
114
+ zip_file = zip_response(temp_zip_file.name, [output_path, srt_path])
115
+ return Response(content = zip_file)
116
  except Exception as e:
117
  raise HTTPException(status_code=500, detail=str(e))
118
 
utils/archiver.py DELETED
@@ -1,17 +0,0 @@
1
- import shutil, os
2
- from datetime import datetime
3
-
4
- def archiver(timestamp:datetime=datetime.now()):
5
- TIME = f"{timestamp.year:4d}-{timestamp.month:02d}-{timestamp.day:02d}_{timestamp.hour:02d}-{timestamp.minute:02d}"
6
- ARCHIVE = os.path.abspath(f"archive/{TIME}")
7
- TEMP_DIR = os.path.abspath("temp/")
8
- LOG_FILE = os.path.abspath("main.log")
9
- if os.path.exists(TEMP_DIR):
10
- shutil.make_archive(os.path.join(ARCHIVE, "files"), 'zip', TEMP_DIR)
11
- shutil.rmtree(TEMP_DIR)
12
- if os.path.exists(LOG_FILE):
13
- shutil.copy(LOG_FILE, os.path.join(ARCHIVE, f"{TIME}.log"))
14
- os.remove(LOG_FILE)
15
-
16
- if __name__ == '__main__':
17
- archiver(timestamp=datetime.now())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utils/process_video.py CHANGED
@@ -1,17 +1,9 @@
 
1
  from utils.transcriber import transcriber
2
  from utils.subtitler import subtitler
3
- import logging, os
4
-
5
- # Set up logging
6
- logging.basicConfig(filename='main.log',
7
- encoding='utf-8',
8
- level=logging.DEBUG,
9
- format='%(asctime)s %(levelname)s %(message)s',
10
- datefmt='%m/%d/%Y %I:%M:%S %p')
11
 
12
- # API Function
13
- def process_video(invideo_filename:str,
14
- srt_path: str,
15
  task: str,
16
  max_words_per_line:int,
17
  fontsize:str,
@@ -21,17 +13,15 @@ def process_video(invideo_filename:str,
21
  caption_mode:str,
22
  config_file:str
23
  ):
24
- invideo_filename = os.path.normpath(invideo_filename)
25
- invideo_path_parts = invideo_filename.split(os.path.sep)
26
- VIDEO_NAME = invideo_path_parts[-1]
27
- OUTVIDEO_PATH = os.path.join(invideo_path_parts[-3], invideo_path_parts[-2], f"result_{VIDEO_NAME}")
28
- if srt_path:
29
- subtitler(invideo_filename, srt_path, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
30
- return OUTVIDEO_PATH, srt_path
31
- SRT_PATH = os.path.abspath(f"{invideo_filename.split('.')[0]}.srt")
32
- logging.info("Transcribing...")
33
- if not os.path.exists(SRT_PATH):
34
- transcriber(invideo_filename, SRT_PATH, max_words_per_line, task, config_file)
35
- logging.info("Subtitling...")
36
- subtitler(invideo_filename, SRT_PATH, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
37
- return OUTVIDEO_PATH, SRT_PATH
 
1
+ import logging, os
2
  from utils.transcriber import transcriber
3
  from utils.subtitler import subtitler
 
 
 
 
 
 
 
 
4
 
5
+ def process_video(invideo_file: str,
6
+ srt_file: str | None,
 
7
  task: str,
8
  max_words_per_line:int,
9
  fontsize:str,
 
13
  caption_mode:str,
14
  config_file:str
15
  ):
16
+ invideo_path_parts = os.path.normpath(invideo_file).split(os.path.sep)
17
+ VIDEO_NAME = os.path.basename(invideo_file)
18
+ OUTVIDEO_PATH = os.path.join(os.path.normpath('/'.join(invideo_path_parts[:-1])), f"result_{VIDEO_NAME}")
19
+ if srt_file:
20
+ logging.info("Subtitling...")
21
+ subtitler(invideo_file, srt_file, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
22
+ else:
23
+ srt_file = os.path.normpath(f"{invideo_file.split('.')[0]}.srt")
24
+ transcriber(invideo_file, srt_file, max_words_per_line, task, config_file)
25
+ logging.info("Subtitling...")
26
+ subtitler(invideo_file, srt_file, OUTVIDEO_PATH, fontsize, font, bg_color, text_color, caption_mode)
27
+ return OUTVIDEO_PATH, srt_file
 
 
utils/transcriber.py CHANGED
@@ -1,19 +1,19 @@
1
  from gradio_client import Client, handle_file
2
  from utils.api_configs import api_configs
 
3
 
4
- def transcriber(invideo_path:str, srt_path:str,
5
  max_words_per_line:int, task:str,
6
  config_file:str):
7
-
8
  HF_TOKEN = api_configs(config_file)["secrets"]["hf-token"]
9
  HF_SPACE = api_configs(config_file)["secrets"]["hf-space"]
10
  client = Client(HF_SPACE, hf_token=HF_TOKEN)
11
  result = client.predict(
12
- video_input=handle_file(invideo_path),
13
  max_words_per_line=max_words_per_line,
14
  task=task,
15
  api_name="/predict"
16
  )
17
- with open(srt_path, "w", encoding='utf-8') as file:
18
  file.write(result[0])
19
- return srt_path
 
1
  from gradio_client import Client, handle_file
2
  from utils.api_configs import api_configs
3
+ import tempfile
4
 
5
+ def transcriber(invideo_file:str, srt_file:str,
6
  max_words_per_line:int, task:str,
7
  config_file:str):
 
8
  HF_TOKEN = api_configs(config_file)["secrets"]["hf-token"]
9
  HF_SPACE = api_configs(config_file)["secrets"]["hf-space"]
10
  client = Client(HF_SPACE, hf_token=HF_TOKEN)
11
  result = client.predict(
12
+ video_input=handle_file(invideo_file),
13
  max_words_per_line=max_words_per_line,
14
  task=task,
15
  api_name="/predict"
16
  )
17
+ with open(srt_file, "w", encoding='utf-8') as file:
18
  file.write(result[0])
19
+ return srt_file
utils/zip_response.py CHANGED
@@ -1,9 +1,9 @@
1
  import zipfile, os
2
 
3
- def zip_response(archive_name: str, files: list):
4
- # Create a new zip file
5
- with zipfile.ZipFile(archive_name, 'w') as zipf:
6
- # Add specific files to the zip file
7
  for file in files:
8
  zipf.write(file, arcname=os.path.basename(file))
9
- return archive_name
 
 
 
1
  import zipfile, os
2
 
3
+ def zip_response(temp_zip_file: str, files: list):
4
+ with zipfile.ZipFile(temp_zip_file, 'w') as zipf:
 
 
5
  for file in files:
6
  zipf.write(file, arcname=os.path.basename(file))
7
+ with open(temp_zip_file, 'rb') as zip_file:
8
+ zip_bytes = zip_file.read()
9
+ return zip_bytes