Ryanus commited on
Commit
83552bf
·
verified ·
1 Parent(s): a96293b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -115
app.py CHANGED
@@ -1,47 +1,25 @@
1
  import os
2
  import gradio as gr
3
  import tempfile
4
- import random
5
  from datetime import datetime
6
 
7
- # AI 导入
8
- try:
9
- from openai import OpenAI
10
- client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) if os.getenv("OPENAI_API_KEY") else None
11
- OPENAI_AVAILABLE = bool(client)
12
- except ImportError:
13
- OPENAI_AVAILABLE = False
14
- client = None
15
-
16
- # 视频处理导入(MoviePy)
17
- try:
18
- from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, vfx
19
- MOVIEPY_AVAILABLE = True
20
- except ImportError:
21
- MOVIEPY_AVAILABLE = False
22
-
23
- # YouTube API 导入
24
- try:
25
- from googleapiclient.discovery import build
26
- from googleapiclient.http import MediaFileUpload
27
- from google_auth_oauthlib.flow import InstalledAppFlow
28
- from google.auth.transport.requests import Request
29
- import pickle
30
- YOUTUBE_AVAILABLE = True
31
- except ImportError:
32
- YOUTUBE_AVAILABLE = False
33
 
34
  MAX_VIDEO_SIZE = 100 * 1024 * 1024 # 100MB
35
  MAX_AUDIO_SIZE = 50 * 1024 * 1024 # 50MB
36
  MAX_TOTAL_SIZE = 500 * 1024 * 1024 # 500MB
37
 
38
- # YouTube 上传类
39
  class YouTubeUploader:
40
  def __init__(self):
41
  self.SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
42
- self.youtube = None
43
- self.credentials_file = 'youtube_token.pickle'
44
  self.client_secrets_file = 'client_secrets.json'
 
 
45
 
46
  def authenticate(self):
47
  creds = None
@@ -52,8 +30,11 @@ class YouTubeUploader:
52
  if creds and creds.expired and creds.refresh_token:
53
  creds.refresh(Request())
54
  else:
55
- flow = InstalledAppFlow.from_client_secrets_file(self.client_secrets_file, self.SCOPES)
56
- creds = flow.run_local_server(port=0)
 
 
 
57
  with open(self.credentials_file, 'wb') as token:
58
  pickle.dump(creds, token)
59
  self.youtube = build('youtube', 'v3', credentials=creds)
@@ -61,116 +42,89 @@ class YouTubeUploader:
61
 
62
  def upload_video(self, video_path, title, description="", tags="", privacy="private"):
63
  if not os.path.exists(video_path):
64
- return {"success": False, "error": "视频文件不存在"}
65
-
66
  body = {
67
- 'snippet': {
68
- 'title': title,
69
- 'description': description,
70
- 'tags': tags.split(',') if tags else [],
71
- 'categoryId': '22' # People & Blogs
72
  },
73
- 'status': {
74
- 'privacyStatus': privacy,
75
- 'selfDeclaredMadeForKids': False
76
  }
77
  }
78
- media = MediaFileUpload(video_path, resumable=True, mimetype='video/*')
79
- request = self.youtube.videos().insert(part=','.join(body.keys()), body=body, media_body=media)
 
 
80
  response = request.execute()
81
- video_id = response.get('id')
82
- video_url = f"https://www.youtube.com/watch?v={video_id}"
83
- return {"success": True, "video_id": video_id, "url": video_url}
84
-
85
- # AI 视频分析
86
- def generate_ai_analysis(video_count, file_names):
87
- if not OPENAI_AVAILABLE:
88
- return "⚠️ 未配置 OpenAI,无法生成 AI 分析。"
89
- try:
90
- file_info = ", ".join([f"'{name}'" for name in file_names[:3]])
91
- prompt = f"""作为专业视频分析师,基于用户上传的 {video_count} 个视频文件(文件名包括:{file_info} 等),请提供详细分析:
92
- 1. 内容类型推测和特点
93
- 2. 最佳背景音乐风格和节拍
94
- 3. 推荐剪辑策略和转场效果
95
- 4. 目标受众分析
96
 
97
- 请用中文回答,格式清晰。"""
98
- response = client.chat.completions.create(
99
- model="gpt-4o-mini",
100
- messages=[
101
- {"role": "system", "content": "你是专业的视频内容分析专家。"},
102
- {"role": "user", "content": prompt}
103
- ],
104
- max_tokens=600,
105
- temperature=0.7
106
- )
107
- return response.choices[0].message.content
108
- except Exception as e:
109
- return f"❌ AI 分析失败:{str(e)}"
110
-
111
- # 视频文件大小检查
112
- def check_filesize(video_files, audio_file):
113
- total_size = 0
114
- for v in video_files:
115
- size = os.path.getsize(v.name)
116
  if size > MAX_VIDEO_SIZE:
117
- return False, f"单个视频文件 {os.path.basename(v.name)} 过大 {size/(1024*1024):.1f}MB,最大限制为 100MB"
118
- total_size += size
119
- if audio_file:
120
- audio_size = os.path.getsize(audio_file.name)
121
- if audio_size > MAX_AUDIO_SIZE:
122
- return False, f"音频文件 {os.path.basename(audio_file.name)} 过大 {audio_size/(1024*1024):.1f}MB,最大限制为 50MB"
123
- total_size += audio_size
124
- if total_size > MAX_TOTAL_SIZE:
125
- return False, f"上传文件总大小过大 {total_size/(1024*1024):.1f}MB,最大限制为 500MB"
126
  return True, ""
127
 
128
- # 视频处理示范(简化,未完整实现)
129
- def process_videos(video_files, audio_file, clip_duration=2, num_output=3):
130
- ok, msg = check_filesize(video_files, audio_file)
131
  if not ok:
132
  return msg, [], ""
133
- # 这里可以使用 MoviePy 处理视频,当前仅模拟
134
- out_files = [] # 真实项目中应为生成的视频路径列表
135
- return " 视频上传成功,处理已完成(演示模式,不生成文件)", out_files, ""
136
 
137
- # Gradio 主界面
138
  def main_app(video_files, audio_file, clip_duration, num_output, upload_yt, yt_privacy):
139
  status, outfiles, _ = process_videos(video_files, audio_file, clip_duration, num_output)
140
- file_names = [os.path.basename(f.name) for f in (video_files or [])]
141
- ai_analysis = generate_ai_analysis(len(video_files or []), file_names) if OPENAI_AVAILABLE else "未启用 AI 分析功能"
142
 
143
- yt_upload_res = ""
144
  if upload_yt:
145
  if not YOUTUBE_AVAILABLE:
146
- yt_upload_res = "⚠️ 未安装 YouTube API 库,上传功能不可用"
147
  elif not os.path.exists("client_secrets.json"):
148
- yt_upload_res = "⚠️ client_secrets.json 文件缺失,无法上传"
149
  else:
150
  uploader = YouTubeUploader()
151
- auth_ok = uploader.authenticate()
152
- if not auth_ok:
153
- yt_upload_res = "❌ YouTube 认证失败"
154
  else:
155
- # 这里示范上传已生成文件,示例为空,需替换为真实文件路径
156
- yt_upload_res = "上传功能暂未实现,请在本地运行上传脚本"
 
157
 
158
- return status, ai_analysis, yt_upload_res
 
 
 
 
 
159
 
160
  with gr.Blocks() as demo:
161
- gr.Markdown("## pyTovideo2 视频处理 + YouTube 上传示范")
162
- video_files = gr.File(file_types=[".mp4", ".mov", ".avi"], label="上传视频文件(s)", file_count="multiple")
163
- audio_file = gr.File(file_types=[".mp3", ".wav", ".m4a"], label="上传音频文件", file_count="single")
 
164
  clip_duration = gr.Number(value=2, label="切片时长 (秒)", minimum=1, maximum=10)
165
  num_output = gr.Number(value=3, label="输出视频数量", minimum=1, maximum=10)
166
- upload_yt = gr.Checkbox(label="处理后自动上传至 YouTube")
167
- yt_privacy = gr.Dropdown(choices=["public", "private", "unlisted"], value="private", label="YouTube 视频隐私状态")
168
- btn = gr.Button("开始处理")
169
- status_out = gr.Textbox(label="处理状态", lines=4)
170
- ai_out = gr.Textbox(label="AI 内容分析", lines=12)
171
- yt_out = gr.Textbox(label="YouTube 上传结果", lines=8)
172
 
173
  btn.click(main_app, inputs=[video_files, audio_file, clip_duration, num_output, upload_yt, yt_privacy],
174
- outputs=[status_out, ai_out, yt_out])
175
 
176
  demo.launch()
 
1
  import os
2
  import gradio as gr
3
  import tempfile
4
+ import pickle
5
  from datetime import datetime
6
 
7
+ # 导入 Google 认证和 API 客户端
8
+ from googleapiclient.discovery import build
9
+ from googleapiclient.http import MediaFileUpload
10
+ from google_auth_oauthlib.flow import InstalledAppFlow
11
+ from google.auth.transport.requests import Request
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  MAX_VIDEO_SIZE = 100 * 1024 * 1024 # 100MB
14
  MAX_AUDIO_SIZE = 50 * 1024 * 1024 # 50MB
15
  MAX_TOTAL_SIZE = 500 * 1024 * 1024 # 500MB
16
 
 
17
  class YouTubeUploader:
18
  def __init__(self):
19
  self.SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
 
 
20
  self.client_secrets_file = 'client_secrets.json'
21
+ self.credentials_file = 'youtube_token.pickle'
22
+ self.youtube = None
23
 
24
  def authenticate(self):
25
  creds = None
 
30
  if creds and creds.expired and creds.refresh_token:
31
  creds.refresh(Request())
32
  else:
33
+ flow = InstalledAppFlow.from_client_secrets_file(
34
+ self.client_secrets_file, self.SCOPES
35
+ )
36
+ # 命令行授权,手动复制粘贴链接和验证码,无需浏览器自动打开
37
+ creds = flow.run_console()
38
  with open(self.credentials_file, 'wb') as token:
39
  pickle.dump(creds, token)
40
  self.youtube = build('youtube', 'v3', credentials=creds)
 
42
 
43
  def upload_video(self, video_path, title, description="", tags="", privacy="private"):
44
  if not os.path.exists(video_path):
45
+ return {"success": False, "error": f"视频文件 {video_path} 不存在"}
46
+
47
  body = {
48
+ "snippet": {
49
+ "title": title,
50
+ "description": description,
51
+ "tags": tags.split(",") if tags else [],
52
+ "categoryId": "22"
53
  },
54
+ "status": {
55
+ "privacyStatus": privacy,
56
+ "selfDeclaredMadeForKids": False
57
  }
58
  }
59
+
60
+ media = MediaFileUpload(video_path, chunksize=-1, resumable=True, mimetype="video/*")
61
+ request = self.youtube.videos().insert(part=",".join(body.keys()), body=body, media_body=media)
62
+
63
  response = request.execute()
64
+ video_id = response.get("id")
65
+ url = f"https://www.youtube.com/watch?v={video_id}"
66
+ return {"success": True, "video_id": video_id, "url": url, "title": title}
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
+ def check_filesize(files):
69
+ total = 0
70
+ for f in files:
71
+ size = os.path.getsize(f.name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  if size > MAX_VIDEO_SIZE:
73
+ return False, f"单个视频文件 {f.name} 过大,超过100MB限制"
74
+ total += size
75
+ if total > MAX_TOTAL_SIZE:
76
+ return False, f"视频文件总大小 {total/(1024*1024):.1f}MB 超过500MB限制"
 
 
 
 
 
77
  return True, ""
78
 
79
+ def process_videos(video_files, audio_file, clip_duration, num_output):
80
+ ok, msg = check_filesize(video_files)
 
81
  if not ok:
82
  return msg, [], ""
83
+
84
+ # 此处可集成视频切片和混剪处理,这里只模拟处理成功
85
+ return f"成功处理 {len(video_files)} 个视频,生成 {num_output} 个混剪视频(演示版本)", [], ""
86
 
 
87
  def main_app(video_files, audio_file, clip_duration, num_output, upload_yt, yt_privacy):
88
  status, outfiles, _ = process_videos(video_files, audio_file, clip_duration, num_output)
 
 
89
 
90
+ yt_result = ""
91
  if upload_yt:
92
  if not YOUTUBE_AVAILABLE:
93
+ yt_result = "⚠️ 未安装 YouTube API 相关库,上传不可用"
94
  elif not os.path.exists("client_secrets.json"):
95
+ yt_result = "⚠️ 未找到 client_secrets.json 文件,无法上传"
96
  else:
97
  uploader = YouTubeUploader()
98
+ authed = uploader.authenticate()
99
+ if not authed:
100
+ yt_result = "❌ YouTube 认证失败"
101
  else:
102
+ yt_result = "上传功能需配合实际处理视频文件使用,当前演示未包含上传调用。"
103
+
104
+ return status, yt_result
105
 
106
+ # 判断是否安装 YouTube API 库
107
+ try:
108
+ import googleapiclient
109
+ YOUTUBE_AVAILABLE = True
110
+ except ImportError:
111
+ YOUTUBE_AVAILABLE = False
112
 
113
  with gr.Blocks() as demo:
114
+ gr.Markdown("## pyTovideo2 视频处理+YouTube上传演示(命令行OAuth)")
115
+
116
+ video_files = gr.File(file_types=[".mp4", ".mov", ".avi"], label="上传视频文件", file_count="multiple")
117
+ audio_file = gr.File(file_types=[".mp3", ".wav", ".m4a"], label="上传音频文件")
118
  clip_duration = gr.Number(value=2, label="切片时长 (秒)", minimum=1, maximum=10)
119
  num_output = gr.Number(value=3, label="输出视频数量", minimum=1, maximum=10)
120
+ upload_yt = gr.Checkbox(label="处理后上传到YouTube")
121
+ yt_privacy = gr.Dropdown(choices=["public", "private", "unlisted"], value="private", label="YouTube隐私状态")
122
+ btn = gr.Button("开始")
123
+
124
+ status_out = gr.Textbox(label="处理状态", lines=4, interactive=False)
125
+ yt_out = gr.Textbox(label="YouTube上传状态", lines=4, interactive=False)
126
 
127
  btn.click(main_app, inputs=[video_files, audio_file, clip_duration, num_output, upload_yt, yt_privacy],
128
+ outputs=[status_out, yt_out])
129
 
130
  demo.launch()