danicor commited on
Commit
7a60b6b
·
verified ·
1 Parent(s): 549cdf8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -152
app.py CHANGED
@@ -1,4 +1,3 @@
1
- #import streamlit as st
2
  import ffmpeg
3
  import os
4
  import time
@@ -17,28 +16,27 @@ import asyncio
17
  from threading import Thread
18
  import nest_asyncio
19
 
20
- # برای اجرای همزمان FastAPI و Streamlit
21
  nest_asyncio.apply()
22
 
23
  app = FastAPI(title="Video Conversion API")
24
 
25
- # Add CORS middleware to handle cross-origin requests
26
  app.add_middleware(
27
  CORSMiddleware,
28
- allow_origins=["*"], # In production, replace with specific domains
29
  allow_credentials=True,
30
  allow_methods=["*"],
31
  allow_headers=["*"],
32
  )
33
 
34
  # Supported formats
35
- supported_formats = [data.upper() for data in (sorted(['3GP', 'ASF', 'AVI', 'DIVX', 'FLV', 'M2TS', 'M4V', 'MKV', 'MOV', 'MP4', 'MPEG', 'MPG', 'MTS', 'TS', 'VOB', 'WEBM', 'WMV', 'XVID'])) if data not in ['3GP', 'DIVX', 'XVID']]
36
- audio_formats = [data.upper() for data in (sorted(['MP3', 'WAV', 'AAC', 'FLAC', 'OGG', 'M4A', 'ALAC', 'WMA', 'AIFF', 'OPUS', 'APE', 'CAF', 'PCM', 'DTS', 'TTA', 'AMR', 'MID', 'SPX', 'WV', 'RA', 'TAK'])) if data not in ['ALC', 'AMR', 'APE', 'DTS', 'MID', 'PCM', 'RA', 'TAK']]
37
  gif_formats = ['GIF']
38
- image_formats = [data.upper() for data in sorted(Image.SAVE.keys() or ['BLP', 'BMP', 'BUFR', 'DDS', 'DIB', 'EPS', 'GIF', 'GRIB', 'HDF5', 'ICNS', 'ICO', 'IM',
39
- 'JPEG', 'JPEG2000', 'MPO', 'MSP', 'PALM', 'PCX', 'PDF', 'PNG', 'PPM', 'SGI', 'SPIDER',
40
- 'TGA', 'TIFF', 'WEBP', 'WMX', 'XBM'])]
41
 
 
42
  CACHE_DIR = tempfile.mkdtemp()
43
 
44
  # Audio codec mapping
@@ -79,9 +77,19 @@ VIDEO_CODECS = {
79
 
80
  def delete_temp_dir(directory, delay=900):
81
  """Delete temporary directory after delay"""
82
- timer = threading.Timer(delay, shutil.rmtree, [directory])
 
 
 
 
 
 
 
 
 
83
  timer.start()
84
 
 
85
  delete_temp_dir(CACHE_DIR, delay=900)
86
 
87
  def sanitize_filename(filename):
@@ -239,7 +247,8 @@ def convert_video(video_path, target_format, conversion_type, time_in_seconds=No
239
  img.save(output_file, format=target_format.upper())
240
 
241
  # Remove temporary PNG file
242
- os.remove(temp_png_file)
 
243
  return output_file
244
 
245
  except Exception as pil_error:
@@ -382,152 +391,35 @@ async def stcore_host_config():
382
  }
383
  }
384
 
385
- @app.get("/health/_stcore/health")
386
- async def health_stcore_health():
387
- return {"status": "healthy"}
388
-
389
- @app.get("/health/_stcore/host-config")
390
- async def health_stcore_host_config():
391
- return {
392
- "version": "1.0",
393
- "config": {
394
- "enableCors": False,
395
- "enableXsrfProtection": False
396
- }
397
- }
398
-
399
- @app.get("/convert/_stcore/health")
400
- async def convert_stcore_health():
401
- return {"status": "healthy"}
402
-
403
- @app.get("/convert/_stcore/host-config")
404
- async def convert_stcore_host_config():
405
- return {
406
- "version": "1.0",
407
- "config": {
408
- "enableCors": False,
409
- "enableXsrfProtection": False
410
- }
411
- }
412
 
413
  @app.get("/")
414
  async def root():
415
- return {"message": "Video Conversion API is running", "docs": "/docs"}
416
-
417
- # # Streamlit UI
418
- # def streamlit_app():
419
- # st.set_page_config(layout="wide", page_title="Video Conversion Tool")
420
-
421
- # st.title("🎬 Video Conversion Tool")
422
- # st.write("Convert videos to audio, GIFs, images, or other formats with optimized codecs for best quality.")
423
-
424
- # # Create two columns
425
- # col1, col2 = st.columns([1, 1])
426
-
427
- # with col1:
428
- # video_file = st.file_uploader("Upload a Video", type=[ext.lower() for ext in supported_formats])
429
- # if video_file:
430
- # st.video(video_file)
431
-
432
- # with col2:
433
- # if video_file:
434
- # # Save uploaded video to cache
435
- # temp_video_path = os.path.join(CACHE_DIR, video_file.name)
436
- # with open(temp_video_path, "wb") as f:
437
- # f.write(video_file.getbuffer())
438
-
439
- # # Get video duration
440
- # video_duration = get_video_duration(temp_video_path)
441
-
442
- # # Select conversion type
443
- # conversion_type = st.selectbox(
444
- # "Select Conversion Type",
445
- # ['Video to Video', 'Video to Audio', 'Video to GIF', 'Video to Image']
446
- # )
447
-
448
- # # Update format choices
449
- # def update_format_choices(conversion_type):
450
- # if conversion_type == 'Video to Video':
451
- # return supported_formats
452
- # elif conversion_type == 'Video to Audio':
453
- # return audio_formats
454
- # elif conversion_type == 'Video to GIF':
455
- # return gif_formats
456
- # elif conversion_type == 'Video to Image':
457
- # return image_formats
458
- # return []
459
-
460
- # target_format_choices = update_format_choices(conversion_type)
461
- # target_format = st.selectbox("Select Target Format", target_format_choices)
462
-
463
- # # Show codec info for supported formats
464
- # if conversion_type == 'Video to Audio' and target_format.upper() in AUDIO_CODECS:
465
- # codec_info = AUDIO_CODECS[target_format.upper()]
466
- # st.info(f"🎵 Audio Codec: {codec_info.get('acodec', 'default')}")
467
- # elif conversion_type == 'Video to Video' and target_format.upper() in VIDEO_CODECS:
468
- # codec_info = VIDEO_CODECS[target_format.upper()]
469
- # st.info(f"🎬 Video Codec: {codec_info.get('vcodec', 'default')} | Audio Codec: {codec_info.get('acodec', 'default')}")
470
-
471
- # if conversion_type == 'Video to Image':
472
- # time_in_seconds = st.slider(
473
- # "Time (in seconds) for image extraction",
474
- # 0, int(video_duration), 0, 1
475
- # )
476
- # else:
477
- # time_in_seconds = None
478
-
479
- # if st.button("🚀 Convert", type="primary"):
480
- # with st.spinner("Converting with optimized codecs..."):
481
- # try:
482
- # output_file = convert_video(temp_video_path, target_format, conversion_type, time_in_seconds)
483
-
484
- # st.success("✅ Conversion Successful!")
485
-
486
- # # Show file size
487
- # file_size = os.path.getsize(output_file) / (1024 * 1024) # MB
488
- # st.info(f"📁 File size: {file_size:.2f} MB")
489
-
490
- # with open(output_file, "rb") as f:
491
- # st.download_button(
492
- # "⬇️ Download Converted File",
493
- # f,
494
- # file_name=os.path.basename(output_file),
495
- # type="primary"
496
- # )
497
- # except Exception as e:
498
- # st.error(f"❌ Error: {str(e)}")
499
-
500
- # API Info & Supported Codecs
501
- st.sidebar.header("🔧 API Information")
502
- st.sidebar.info("""
503
- **API Endpoints:**
504
- - `POST /api/convert` - Convert video files
505
- - `GET /api/formats` - Get supported formats
506
-
507
- **WordPress Integration:**
508
- Configure the Hugging Face Space URL in WordPress settings.
509
 
510
- **Test API:**
511
- Visit `/docs` for interactive API documentation.
512
- """)
513
 
514
- # Show supported codecs
515
- with st.sidebar.expander("🎵 Supported Audio Codecs"):
516
- for format_name, codec_info in AUDIO_CODECS.items():
517
- st.write(f"**{format_name}:** {codec_info.get('acodec', 'default')}")
518
 
519
- with st.sidebar.expander("🎬 Supported Video Codecs"):
520
- for format_name, codec_info in VIDEO_CODECS.items():
521
- st.write(f"**{format_name}:** {codec_info.get('vcodec', 'default')}")
 
 
 
 
 
522
 
523
- def run_fastapi():
524
- uvicorn.run(app, host="0.0.0.0", port=7860)
525
-
526
- # Run both applications
527
  if __name__ == "__main__":
528
- # Run FastAPI in background
529
- fastapi_thread = Thread(target=run_fastapi, daemon=True)
530
- fastapi_thread.start()
531
-
532
- # # Run Streamlit
533
- # streamlit_app()
 
 
1
  import ffmpeg
2
  import os
3
  import time
 
16
  from threading import Thread
17
  import nest_asyncio
18
 
19
+ # Apply nest_asyncio for concurrent execution
20
  nest_asyncio.apply()
21
 
22
  app = FastAPI(title="Video Conversion API")
23
 
24
+ # Add CORS middleware
25
  app.add_middleware(
26
  CORSMiddleware,
27
+ allow_origins=["*"],
28
  allow_credentials=True,
29
  allow_methods=["*"],
30
  allow_headers=["*"],
31
  )
32
 
33
  # Supported formats
34
+ supported_formats = ['ASF', 'AVI', 'FLV', 'M2TS', 'M4V', 'MKV', 'MOV', 'MP4', 'MPEG', 'MPG', 'MTS', 'TS', 'VOB', 'WEBM', 'WMV']
35
+ audio_formats = ['AAC', 'AIFF', 'ALAC', 'CAF', 'FLAC', 'M4A', 'MP3', 'OGG', 'OPUS', 'SPX', 'TTA', 'WAV', 'WMA', 'WV']
36
  gif_formats = ['GIF']
37
+ image_formats = ['BMP', 'DIB', 'EPS', 'GIF', 'ICNS', 'ICO', 'IM', 'JPEG', 'JPEG2000', 'MPO', 'MSP', 'PALM', 'PCX', 'PDF', 'PNG', 'PPM', 'SGI', 'SPIDER', 'TGA', 'TIFF', 'WEBP', 'WMX', 'XBM']
 
 
38
 
39
+ # Create cache directory
40
  CACHE_DIR = tempfile.mkdtemp()
41
 
42
  # Audio codec mapping
 
77
 
78
  def delete_temp_dir(directory, delay=900):
79
  """Delete temporary directory after delay"""
80
+ def cleanup():
81
+ try:
82
+ if os.path.exists(directory):
83
+ shutil.rmtree(directory)
84
+ print(f"Cleaned up temporary directory: {directory}")
85
+ except Exception as e:
86
+ print(f"Error cleaning up directory {directory}: {e}")
87
+
88
+ timer = threading.Timer(delay, cleanup)
89
+ timer.daemon = True
90
  timer.start()
91
 
92
+ # Schedule cleanup
93
  delete_temp_dir(CACHE_DIR, delay=900)
94
 
95
  def sanitize_filename(filename):
 
247
  img.save(output_file, format=target_format.upper())
248
 
249
  # Remove temporary PNG file
250
+ if os.path.exists(temp_png_file):
251
+ os.remove(temp_png_file)
252
  return output_file
253
 
254
  except Exception as pil_error:
 
391
  }
392
  }
393
 
394
+ @app.get("/health")
395
+ async def health():
396
+ return {"status": "healthy", "message": "Video Conversion API is running"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
  @app.get("/")
399
  async def root():
400
+ return {"message": "Video Conversion API is running", "docs": "/docs", "status": "healthy"}
401
+
402
+ # Main function to run the app
403
+ def main():
404
+ print("Starting Video Conversion API...")
405
+ print(f"Cache directory: {CACHE_DIR}")
406
+ print(f"Supported video formats: {supported_formats}")
407
+ print(f"Supported audio formats: {audio_formats}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
 
409
+ # Get port from environment variable (Hugging Face Spaces uses specific port)
410
+ port = int(os.environ.get("PORT", 7860))
411
+ host = "0.0.0.0"
412
 
413
+ print(f"Starting server on {host}:{port}")
 
 
 
414
 
415
+ # Configure uvicorn with proper settings for Hugging Face Spaces
416
+ uvicorn.run(
417
+ app,
418
+ host=host,
419
+ port=port,
420
+ log_level="info",
421
+ access_log=True
422
+ )
423
 
 
 
 
 
424
  if __name__ == "__main__":
425
+ main()