jacky3102 commited on
Commit
6f33ef7
·
verified ·
1 Parent(s): 9790bbf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +138 -0
app.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Form
2
+ from fastapi.responses import JSONResponse, PlainTextResponse
3
+ import whisper
4
+ import tempfile
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Optional
8
+ import subprocess
9
+ import json
10
+
11
+ app = FastAPI(title="Subtitle Generator API")
12
+
13
+ # 加载Whisper模型(首次启动时会下载模型)
14
+ model_size = os.getenv("WHISPER_MODEL", "base") # tiny, base, small, medium, large
15
+ model = whisper.load_model(model_size)
16
+
17
+ def format_timestamp(seconds: float) -> str:
18
+ """将秒数转换为SRT时间戳格式"""
19
+ hours = int(seconds // 3600)
20
+ minutes = int((seconds % 3600) // 60)
21
+ secs = int(seconds % 60)
22
+ millisecs = int((seconds - int(seconds)) * 1000)
23
+ return f"{hours:02d}:{minutes:02d}:{secs:02d},{millisecs:03d}"
24
+
25
+ def generate_srt(segments) -> str:
26
+ """生成SRT格式字幕"""
27
+ srt_content = []
28
+ for i, segment in enumerate(segments, 1):
29
+ start_time = format_timestamp(segment['start'])
30
+ end_time = format_timestamp(segment['end'])
31
+ text = segment['text'].strip()
32
+ srt_content.append(f"{i}\n{start_time} --> {end_time}\n{text}\n")
33
+ return "\n".join(srt_content)
34
+
35
+ def generate_vtt(segments) -> str:
36
+ """生成WebVTT格式字幕"""
37
+ vtt_content = ["WEBVTT\n"]
38
+ for i, segment in enumerate(segments):
39
+ start_time = format_timestamp(segment['start']).replace(',', '.')
40
+ end_time = format_timestamp(segment['end']).replace(',', '.')
41
+ text = segment['text'].strip()
42
+ vtt_content.append(f"{start_time} --> {end_time}\n{text}\n")
43
+ return "\n".join(vtt_content)
44
+
45
+ @app.get("/")
46
+ async def root():
47
+ return {
48
+ "message": "Subtitle Generator API",
49
+ "endpoints": {
50
+ "/generate_subtitle": "POST - Upload audio/video and get subtitles",
51
+ "/health": "GET - Health check"
52
+ },
53
+ "supported_formats": ["srt", "vtt", "txt", "json"],
54
+ "model": model_size
55
+ }
56
+
57
+ @app.get("/health")
58
+ async def health_check():
59
+ return {"status": "healthy", "model": model_size}
60
+
61
+ @app.post("/generate_subtitle")
62
+ async def generate_subtitle(
63
+ file: UploadFile = File(...),
64
+ output_format: str = Form("srt"),
65
+ language: Optional[str] = Form(None)
66
+ ):
67
+ """
68
+ 生成字幕文件
69
+
70
+ - file: 音频或视频文件
71
+ - output_format: 输出格式 (srt, vtt, txt, json)
72
+ - language: 语言代码 (如 en, zh, ja),不指定则自动检测
73
+ """
74
+
75
+ # 验证格式
76
+ valid_formats = ["srt", "vtt", "txt", "json"]
77
+ if output_format not in valid_formats:
78
+ raise HTTPException(
79
+ status_code=400,
80
+ detail=f"Invalid format. Choose from: {valid_formats}"
81
+ )
82
+
83
+ # 保存上传文件到临时目录
84
+ with tempfile.NamedTemporaryFile(delete=False, suffix=Path(file.filename).suffix) as tmp_file:
85
+ content = await file.read()
86
+ tmp_file.write(content)
87
+ tmp_path = tmp_file.name
88
+
89
+ try:
90
+ # 转码选项
91
+ transcribe_options = {}
92
+ if language:
93
+ transcribe_options["language"] = language
94
+
95
+ # 使用Whisper转录音频
96
+ result = model.transcribe(tmp_path, **transcribe_options)
97
+
98
+ # 根据请求格式生成字幕
99
+ if output_format == "srt":
100
+ subtitle_text = generate_srt(result["segments"])
101
+ media_type = "text/plain"
102
+ filename = "subtitle.srt"
103
+ elif output_format == "vtt":
104
+ subtitle_text = generate_vtt(result["segments"])
105
+ media_type = "text/plain"
106
+ filename = "subtitle.vtt"
107
+ elif output_format == "txt":
108
+ subtitle_text = result["text"]
109
+ media_type = "text/plain"
110
+ filename = "subtitle.txt"
111
+ elif output_format == "json":
112
+ subtitle_text = json.dumps({
113
+ "text": result["text"],
114
+ "segments": result["segments"],
115
+ "language": result["language"]
116
+ }, ensure_ascii=False, indent=2)
117
+ media_type = "application/json"
118
+ filename = "subtitle.json"
119
+
120
+ return PlainTextResponse(
121
+ content=subtitle_text,
122
+ media_type=media_type,
123
+ headers={
124
+ "Content-Disposition": f"attachment; filename={filename}"
125
+ }
126
+ )
127
+
128
+ except Exception as e:
129
+ raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
130
+
131
+ finally:
132
+ # 清理临时文件
133
+ if os.path.exists(tmp_path):
134
+ os.unlink(tmp_path)
135
+
136
+ if __name__ == "__main__":
137
+ import uvicorn
138
+ uvicorn.run(app, host="0.0.0.0", port=7860)