Ryanus commited on
Commit
887c004
·
verified ·
1 Parent(s): 6048e02

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +277 -47
app.py CHANGED
@@ -1,54 +1,284 @@
1
- # app.py
 
 
2
  import gradio as gr
3
- from split_video import split_video
4
  import os
5
- import subprocess
6
- import sys
 
 
 
7
 
8
- def process_video(input_video, segment_duration, enable_mix=False):
9
- if not input_video:
10
- return [] # 返回空列表,避免無效輸入
11
- try:
12
- # 步驟 1: 切割長影片
13
- output_dir = "temp_segments"
14
- outputs = split_video(input_video, output_dir, int(segment_duration))
15
- print(f"切割完成:生成 {len(outputs)} 個短片") # 改用 print
16
- except Exception as e:
17
- print(f"切割錯誤:{str(e)}") # 改用 print
18
- return [] # 返回空列表,防止錯誤訊息被誤解析
19
-
20
- # 步驟 2: 可選混剪(使用 pyToVideo2 的 main.py)
21
- if enable_mix:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  try:
23
- cmd = [
24
- sys.executable, "main.py",
25
- "--input_folder", output_dir,
26
- "--output_folder", "mixed_output",
27
- "--num_clips", "20"
28
- ]
29
- result = subprocess.run(cmd, capture_output=True, text=True)
30
- if result.returncode != 0:
31
- print(f"混剪警告:{result.stderr}") # 改用 print
32
- else:
33
- mixed_files = [os.path.join("mixed_output", f) for f in os.listdir("mixed_output") if f.endswith(".mp4")]
34
- outputs.extend(mixed_files)
35
- print("混剪完成") # 改用 print
 
 
 
 
 
 
36
  except Exception as e:
37
- print(f"混剪錯誤:{str(e)}") # 改用 print
38
-
39
- return outputs if outputs else [] # 確保返回檔案路徑列表或空列表
40
-
41
- iface = gr.Interface(
42
- fn=process_video,
43
- inputs=[
44
- gr.File(label="上傳長影片 (MP4)"),
45
- gr.Number(label="每段長度 (秒)", value=60),
46
- gr.Checkbox(label="啟用 pyToVideo2 混剪", value=False)
47
- ],
48
- outputs=gr.Files(label="下載短影片 / 混剪結果"),
49
- title="pyToVideo2 影片切割與混剪",
50
- description="上傳長影片切割成短片(使用 FFmpeg),並可選使用 pyToVideo2 混剪成 20 個新影片。"
51
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  if __name__ == "__main__":
54
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
  import gradio as gr
 
5
  import os
6
+ import tempfile
7
+ import json
8
+ import random
9
+ from datetime import datetime
10
+ from pathlib import Path
11
 
12
+ # AI 和视频处理导入
13
+ try:
14
+ from openai import OpenAI
15
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) if os.getenv("OPENAI_API_KEY") else None
16
+ OPENAI_AVAILABLE = bool(client)
17
+ except ImportError:
18
+ OPENAI_AVAILABLE = False
19
+ client = None
20
+
21
+ # 视频处理导入
22
+ try:
23
+ from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, vfx
24
+ MOVIEPY_AVAILABLE = True
25
+ except ImportError:
26
+ MOVIEPY_AVAILABLE = False
27
+ print("⚠️ MoviePy 不可用,将使用模拟模式")
28
+
29
+ # YouTube 上传导入
30
+ try:
31
+ from googleapiclient.discovery import build
32
+ from googleapiclient.http import MediaFileUpload
33
+ from google_auth_oauthlib.flow import InstalledAppFlow
34
+ from google.auth.transport.requests import Request
35
+ import pickle
36
+ YOUTUBE_AVAILABLE = True
37
+ except ImportError:
38
+ YOUTUBE_AVAILABLE = False
39
+
40
+ # 全局配置
41
+ MAX_VIDEO_SIZE = 100 * 1024 * 1024 # 100MB
42
+ MAX_AUDIO_SIZE = 50 * 1024 * 1024 # 50MB
43
+ MAX_TOTAL_SIZE = 500 * 1024 * 1024 # 500MB
44
+
45
+ class YouTubeUploader:
46
+ """YouTube 上传工具类"""
47
+
48
+ def __init__(self):
49
+ self.SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
50
+ self.youtube = None
51
+ self.authenticated = False
52
+
53
+ def setup_credentials(self, client_secrets_content):
54
+ """设置 Google Cloud 凭据"""
55
  try:
56
+ # 使用你已有的凭据
57
+ credentials_data = {
58
+ "installed": {
59
+ "client_id": "288005932157-k7dhq8c7rgmt8km0nm50ntuif9lse7j1.apps.googleusercontent.com",
60
+ "project_id": "corded-palisade-458105-p7",
61
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
62
+ "token_uri": "https://oauth2.googleapis.com/token",
63
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
64
+ "client_secret": "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",
65
+ "redirect_uris": ["http://localhost"]
66
+ }
67
+ }
68
+
69
+ # 保存到临时文件
70
+ temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False)
71
+ json.dump(credentials_data, temp_file)
72
+ temp_file.close()
73
+
74
+ return temp_file.name
75
  except Exception as e:
76
+ return None
77
+
78
+ def generate_upload_script(self, video_titles):
79
+ """生成 YouTube 上传脚本"""
80
+
81
+ script_template = f'''#!/usr/bin/env python3
82
+ """
83
+ pyTovideo2 YouTube 自动上传脚本
84
+ 使用说明:
85
+ 1. pip install google-api-python-client google-auth-oauthlib
86
+ 2. 将此脚本与你的视频文件放在同一目录
87
+ 3. 运行:python youtube_upload_script.py
88
+ """
89
+
90
+ import os
91
+ import pickle
92
+ import json
93
+ from googleapiclient.discovery import build
94
+ from googleapiclient.http import MediaFileUpload
95
+ from google_auth_oauthlib.flow import InstalledAppFlow
96
+ from google.auth.transport.requests import Request
97
+
98
+ # Google Cloud 凭据(已配置好)
99
+ CLIENT_SECRETS = {{
100
+ "installed": {{
101
+ "client_id": "288005932157-k7dhq8c7rgmt8km0nm50ntuif9lse7j1.apps.googleusercontent.com",
102
+ "project_id": "corded-palisade-458105-p7",
103
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
104
+ "token_uri": "https://oauth2.googleapis.com/token",
105
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
106
+ "client_secret": "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",
107
+ "redirect_uris": ["http://localhost"]
108
+ }}
109
+ }}
110
+
111
+ class YouTubeUploader:
112
+ def __init__(self):
113
+ self.SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
114
+ self.youtube = None
115
+
116
+ # 保存凭据文件
117
+ with open('client_secrets.json', 'w') as f:
118
+ json.dump(CLIENT_SECRETS, f)
119
+
120
+ def authenticate(self):
121
+ """认证 YouTube API"""
122
+ credentials = None
123
+
124
+ if os.path.exists('youtube_token.pickle'):
125
+ with open('youtube_token.pickle', 'rb') as token:
126
+ credentials = pickle.load(token)
127
+
128
+ if not credentials or not credentials.valid:
129
+ if credentials and credentials.expired and credentials.refresh_token:
130
+ credentials.refresh(Request())
131
+ else:
132
+ flow = InstalledAppFlow.from_client_secrets_file(
133
+ 'client_secrets.json', self.SCOPES)
134
+ credentials = flow.run_local_server(port=0)
135
+
136
+ with open('youtube_token.pickle', 'wb') as token:
137
+ pickle.dump(credentials, token)
138
+
139
+ self.youtube = build('youtube', 'v3', credentials=credentials)
140
+ return True
141
+
142
+ def upload_video(self, video_path, title, description="", tags="", privacy="private"):
143
+ """上传视频到 YouTube"""
144
+ body = {{
145
+ 'snippet': {{
146
+ 'title': title,
147
+ 'description': description,
148
+ 'tags': tags.split(',') if tags else [],
149
+ 'categoryId': '22'
150
+ }},
151
+ 'status': {{
152
+ 'privacyStatus': privacy
153
+ }}
154
+ }}
155
+
156
+ media = MediaFileUpload(video_path, resumable=True)
157
+ request = self.youtube.videos().insert(
158
+ part=','.join(body.keys()),
159
+ body=body,
160
+ media_body=media
161
+ )
162
+
163
+ response = request.execute()
164
+ return f"https://www.youtube.com/watch?v={{response['id']}}"
165
+
166
+ def main():
167
+ """主程序"""
168
+ print("🎬 pyTovideo2 YouTube 上传工具")
169
+ print("=" * 40)
170
+
171
+ uploader = YouTubeUploader()
172
+
173
+ if not uploader.authenticate():
174
+ print("❌ 认证失败")
175
+ return
176
+
177
+ print("✅ YouTube 认证成功!")
178
+
179
+ # 要上传的视频列表
180
+ videos_info = ['''
181
+
182
+ for i, title in enumerate(video_titles, 1):
183
+ script_template += f'''
184
+ {{
185
+ "file": "混剪视频_{i:02d}.mp4",
186
+ "title": "{title}",
187
+ "description": """🎬 使用 pyTovideo2 制作的精彩混剪视频
188
+
189
+ ✨ 制作特色:
190
+ • 智能视频切片处理
191
+ • 音乐节拍完美同步
192
+ • 创意片段随机组合
193
+ • 镜像翻转防重复检测
194
+
195
+ 💡 工具优势:
196
+ • 批量处理高效率
197
+ • 支持多种视频格式
198
+ • 一键生成多个版本
199
+ • 完美适配各大平台
200
+
201
+ 👍 如果喜欢请:
202
+ • 点赞支持这个项目
203
+ • 订阅获取更多内容
204
+ • 分享给感兴趣的朋友
205
+ • 评论交流制作心得
206
+
207
+ 🔗 项目开源地址: https://github.com/BassZou/pyToVideo2
208
+
209
+ #短视频 #混剪 #Python #自动化 #pyTovideo2 #视频制作""",
210
+ "tags": "短视频,混剪,Python,自动化,pyTovideo2,视频制作,内容创作",
211
+ "privacy": "private" # private, unlisted, public
212
+ }},'''
213
+
214
+ script_template += f'''
215
+ ]
216
+
217
+ # 批量上传
218
+ print(f"🚀 开始批量上传 {{len(videos_info)}} 个视频...")
219
+
220
+ for i, video_info in enumerate(videos_info, 1):
221
+ if os.path.exists(video_info['file']):
222
+ print(f"\\n--- 上传第 {{i}}/{{len(videos_info)}} 个视频 ---")
223
+ print(f"📹 文件: {{video_info['file']}}")
224
+
225
+ try:
226
+ url = uploader.upload_video(
227
+ video_path=video_info['file'],
228
+ title=video_info['title'],
229
+ description=video_info['description'],
230
+ tags=video_info['tags'],
231
+ privacy=video_info['privacy']
232
+ )
233
+ print(f"✅ 上传成功: {{url}}")
234
+ except Exception as e:
235
+ print(f"❌ 上传失败: {{e}}")
236
+ else:
237
+ print(f"❌ 文件不存在: {{video_info['file']}}")
238
+
239
+ print("\\n🎉 批量上���完成!")
240
 
241
  if __name__ == "__main__":
242
+ main()
243
+ '''
244
+
245
+ return script_template
246
+
247
+ def generate_ai_analysis(video_count, file_names):
248
+ """使用 AI 生成视频分析"""
249
+ if not OPENAI_AVAILABLE:
250
+ return f"""
251
+ 📊 **视频分析报告**(基于文件信息)
252
+
253
+ 📹 **内容预测**:
254
+ 根据上传的 {video_count} 个视频文件,预测内容类型:
255
+ • 生活记录类:适合温馨背景音乐
256
+ • 技能展示类:适合节奏感强的音乐
257
+ • 风景旅行类:适合轻松舒缓音乐
258
+ • 娱乐搞笑类:适合活泼欢快音乐
259
+
260
+ 🎵 **音乐建议**:
261
+ • 节拍:120-140 BPM 最适合短视频
262
+ • 风格:流行、电子、轻音乐
263
+ • 时长:与最终视频长度匹配
264
+
265
+ ✂️ **剪辑策略**:
266
+ • 快切:适合动感内容,2-3秒一切
267
+ • 慢节奏:适合情感内容,4-5秒一切
268
+ • 混合节奏:根据音乐变化调整
269
+
270
+ 🎯 **平台优化**:
271
+ • 抖音:竖屏 9:16,15-60秒
272
+ • 小红书:方形 1:1,15-90秒
273
+ • YouTube:横屏 16:9,3-10分钟
274
+ """
275
+
276
+ try:
277
+ file_info = ", ".join([f"'{name}'" for name in file_names[:3]]) # 只取前3个文件名
278
+
279
+ prompt = f"""作为专业视频分析师,基于用户上传的 {video_count} 个视频文件(文件名包括:{file_info}等),请提供详细分析:
280
+
281
+ 1. 📹 内容类型推测和特点分析
282
+ 2. 🎵 最佳背景音乐风格和节拍建议
283
+ 3. ✂️ 推荐的剪辑策略和转场效果
284
+ 4. 🎯 目标受