MeUtils 2025.5.9.17.18.7__py3-none-any.whl → 2025.5.12.15.21.44__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/METADATA +258 -258
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/RECORD +12 -12
- meutils/apis/google/chat.py +17 -25
- meutils/apis/hailuoai/images.py +2 -29
- meutils/apis/hailuoai/videos.py +3 -4
- meutils/apis/jimeng/images.py +270 -8
- meutils/data/VERSION +1 -1
- meutils/llm/completions/todo.py +15 -0
- meutils/apis/google//350/247/206/351/242/221/350/247/243/346/236/220V1.2.4-/346/211/223/346/211/271/345/217/2212/346/254/241+/346/257/224/350/276/2034.11.py +0 -332
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/LICENSE +0 -0
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/WHEEL +0 -0
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/entry_points.txt +0 -0
- {MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/top_level.txt +0 -0
@@ -1,332 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
import requests
|
3
|
-
import json
|
4
|
-
import os
|
5
|
-
import shutil # 移到顶部导入
|
6
|
-
from urllib.parse import urlparse
|
7
|
-
from docx import Document
|
8
|
-
import glob
|
9
|
-
import datetime
|
10
|
-
|
11
|
-
# 配置信息
|
12
|
-
config = {
|
13
|
-
"api_url": "https://api.chatfire.cn/v1/chat/completions",
|
14
|
-
"api_key": "sk-",
|
15
|
-
"input_txt": "input/video_urls.txt", # 包含视频 URL 的输入文件
|
16
|
-
}
|
17
|
-
|
18
|
-
def get_timestamped_output_dir():
|
19
|
-
# 生成带时间戳的输出目录
|
20
|
-
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
21
|
-
output_dir = os.path.join('output', timestamp)
|
22
|
-
|
23
|
-
# 确保主目录存在
|
24
|
-
os.makedirs(output_dir, exist_ok=True)
|
25
|
-
|
26
|
-
# 创建子目录 A, B, C
|
27
|
-
for subdir in ['A', 'B', 'C']:
|
28
|
-
subdir_path = os.path.join(output_dir, subdir)
|
29
|
-
os.makedirs(subdir_path, exist_ok=True)
|
30
|
-
|
31
|
-
return output_dir
|
32
|
-
|
33
|
-
def analyze_video(video_url, prompt):
|
34
|
-
"""使用API分析视频"""
|
35
|
-
headers = {
|
36
|
-
'Content-Type': 'application/json',
|
37
|
-
'Authorization': f'Bearer {config["api_key"]}'
|
38
|
-
}
|
39
|
-
payload = {
|
40
|
-
"model": "gemini-all",
|
41
|
-
"messages": [
|
42
|
-
{
|
43
|
-
"role": "system",
|
44
|
-
"content": """你是一位专业的短剧编剧。请将视频内容转换为剧本格式,重点关注:
|
45
|
-
1. 角色对白(包括语气、情感提示)
|
46
|
-
2. 具体的表演动作指示
|
47
|
-
3. 场景和道具说明
|
48
|
-
4. 表情和肢体语言
|
49
|
-
5. 非台词的字幕
|
50
|
-
6.人物台词不要出现张冠李戴的情况,无法判别人物身份时,这一集中出现最多的年轻成年女性为女主,出现最多的年轻成年男性为男主
|
51
|
-
7. 对重复的台词、动作进行识别和删除
|
52
|
-
8.每一集的场次都需要从1开始,用1.2.3连续符号标注,不要被上一集影响
|
53
|
-
9. 剧本全文不要出现"*"
|
54
|
-
10. 注意分辨不同人物,学习我所给出的主要人物关系"""
|
55
|
-
},
|
56
|
-
{
|
57
|
-
"role": "user",
|
58
|
-
"content": [
|
59
|
-
{
|
60
|
-
"type": "text",
|
61
|
-
"text": prompt
|
62
|
-
},
|
63
|
-
{
|
64
|
-
"type": "video_url",
|
65
|
-
"video_url": {
|
66
|
-
"url": video_url
|
67
|
-
}
|
68
|
-
}
|
69
|
-
]
|
70
|
-
}
|
71
|
-
]
|
72
|
-
}
|
73
|
-
try:
|
74
|
-
print(f"正在分析视频: {video_url}")
|
75
|
-
response = requests.post(
|
76
|
-
config["api_url"],
|
77
|
-
headers=headers,
|
78
|
-
json=payload,
|
79
|
-
timeout=180
|
80
|
-
)
|
81
|
-
if response.status_code == 200:
|
82
|
-
result = response.json()
|
83
|
-
return result.get('choices', [{}])[0].get('message', {}).get('content')
|
84
|
-
else:
|
85
|
-
print(f"错误信息:{response.text}")
|
86
|
-
return None
|
87
|
-
except Exception as e:
|
88
|
-
print(f"分析失败: {e}")
|
89
|
-
return None
|
90
|
-
|
91
|
-
|
92
|
-
def format_episode_title(filename):
|
93
|
-
# 从文件名中去掉.txt后缀,前面加上"第",后面加上"集"
|
94
|
-
name = os.path.splitext(filename)[0]
|
95
|
-
return f"第{name}集"
|
96
|
-
|
97
|
-
def process_scene(text):
|
98
|
-
# 提取场次信息和其余内容
|
99
|
-
scene_match = re.match(r'(场次\s*[\[【]?\s*\d+\s*[\]】]?.*?)(?=\n)', text, re.DOTALL)
|
100
|
-
if scene_match:
|
101
|
-
scene_header = scene_match.group(1).strip()
|
102
|
-
remaining_content = text[scene_match.end():].strip()
|
103
|
-
return scene_header, remaining_content
|
104
|
-
return None, text
|
105
|
-
|
106
|
-
def filter_content(text):
|
107
|
-
# 定义需要过滤的废话
|
108
|
-
filters = [
|
109
|
-
"剧本结束。",
|
110
|
-
"好的,请看剧本:",
|
111
|
-
"请看剧本:",
|
112
|
-
"以下是剧本:",
|
113
|
-
"剧本如下:",
|
114
|
-
]# 过滤掉这些废话
|
115
|
-
filtered_text = text
|
116
|
-
for filter_text in filters:
|
117
|
-
filtered_text = filtered_text.replace(filter_text, "")
|
118
|
-
return filtered_text.strip()
|
119
|
-
|
120
|
-
def merge_to_word(txt_files, output_file): # 修改参数
|
121
|
-
document = Document()
|
122
|
-
for txt_file in txt_files: # 直接使用文件列表
|
123
|
-
episode_title = format_episode_title(os.path.basename(txt_file)) # 使用basename
|
124
|
-
document.add_heading(episode_title, level=2)
|
125
|
-
with open(txt_file, 'r', encoding='utf-8') as f: # 直接使用文件路径
|
126
|
-
content = f.read()
|
127
|
-
content = filter_content(content)
|
128
|
-
scenes = [s for s in content.split('\n\n') if s.strip()]
|
129
|
-
|
130
|
-
for scene in scenes:
|
131
|
-
scene_header, scene_content = process_scene(scene)
|
132
|
-
if scene_header:
|
133
|
-
document.add_heading(scene_header, level=3)
|
134
|
-
if scene_content:
|
135
|
-
document.add_paragraph(scene_content)
|
136
|
-
else:
|
137
|
-
document.add_paragraph(scene)
|
138
|
-
|
139
|
-
document.save(output_file)
|
140
|
-
print(f"文档已保存至: {output_file}")
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
def main():
|
145
|
-
try:
|
146
|
-
# 创建带时间戳的输出目录
|
147
|
-
output_dir = get_timestamped_output_dir()
|
148
|
-
|
149
|
-
# 确保所有子目录都已创建
|
150
|
-
for subdir in ['A', 'B', 'C']:
|
151
|
-
subdir_path = os.path.join(output_dir, subdir)
|
152
|
-
if not os.path.exists(subdir_path):
|
153
|
-
os.makedirs(subdir_path, exist_ok=True)
|
154
|
-
|
155
|
-
# 读取视频URL列表
|
156
|
-
with open(config['input_txt'], 'r') as f:
|
157
|
-
urls = [line.strip() for line in f if line.strip()]
|
158
|
-
# 通用的剧本生成prompt(保持不变)
|
159
|
-
base_prompt = """出场人物
|
160
|
-
|
161
|
-
场次编号+地点+时间(日/夜)+内/外景
|
162
|
-
(场景描述包含布景要求、核心道具、环境氛围)
|
163
|
-
字幕:角色身份说明(角色首次出场时标注)
|
164
|
-
旁白:画外音内容(如有)
|
165
|
-
△ 动作描述(使用△符号起始,包含肢体语言、关键走位)
|
166
|
-
角色名(情感提示):对白内容(保留方言特色如"啷个""铲铲"等)
|
167
|
-
|
168
|
-
【剧本示例参考】
|
169
|
-
出场人物:
|
170
|
-
陈海清:冷冻机厂副主任
|
171
|
-
刘厂长:冷冻机三分厂厂长
|
172
|
-
蔡晓艳:冷冻机一分厂车间组长
|
173
|
-
王日新:冷冻机二分厂财务主任
|
174
|
-
李医生:医生
|
175
|
-
赵春红:蔡晓艳嫂子
|
176
|
-
蔡晓艳母亲
|
177
|
-
蔡晓艳儿子:邵一帆
|
178
|
-
|
179
|
-
1. 川南冷冻厂 夜 外
|
180
|
-
字幕:1981年
|
181
|
-
长江中上游洪水灾后
|
182
|
-
旁白:长江中上游洪水灾后,群众正在积极投入恢复建设中……
|
183
|
-
△ 灾难现场,一双男人的手把掉在地上的招牌捡起来,招牌上写着“川南冷冻机械二分厂”。
|
184
|
-
工人甲:快来帮忙!
|
185
|
-
工人乙:来了来了!
|
186
|
-
△ 一名工人拉木头时不小心脚滑了一下,拖车失控,一只戴了手表的男的人手突然握住把手,把车控制住。
|
187
|
-
字幕:冷冻机总厂副主任陈海清陈海清:我来帮你。
|
188
|
-
△ 一群厂里的管理员赶忙追过来。
|
189
|
-
管理员(劝阻):领导领导,陈主任……
|
190
|
-
陈海清(忙着干活):拿个石头——
|
191
|
-
管理员:我们分厂的这个灾后工作做得很好,领导,你不用亲自来的嘛?
|
192
|
-
陈海清:莫浪费时间,救灾要紧!
|
193
|
-
△ 突然从厂区二楼医务室传来一个女人的吵闹声。女人(画外音):领导算个屁,李医生你再不跟老子走,老子把你医务室给你砸烂,你个背时(倒霉)领导,脸皮比城墙加拐棍还厚!
|
194
|
-
△ 陈海清跟现场工人都抬头看向医务室。
|
195
|
-
|
196
|
-
2. 医务室夜 内
|
197
|
-
字幕:蔡晓艳冷东机二分厂车间组长
|
198
|
-
蔡晓艳:李医生,我嫂子怀起娃儿(怀着孕),困到车间头好几天了,现在大出血!工人里头好多女工,骨头都砸断了,再不去真的来不及了!走嘛!
|
199
|
-
△ 陈海清走到医务室门口。李医生:但是我这儿,还没检查完的嘛。
|
200
|
-
......
|
201
|
-
|
202
|
-
依照场景类推
|
203
|
-
|
204
|
-
【处理要求】
|
205
|
-
1. 严格区分日/夜、内/外景,每场戏用编号分隔
|
206
|
-
2. 人物首次出场必须用字幕说明姓名+身份
|
207
|
-
3. 动作描述用△符号,包含表情细节(如"揩了揩泪")
|
208
|
-
4. 保留方言词汇和口语化表达(如"歪婆娘""背时")
|
209
|
-
5. 注意角色关系标注(如"蔡晓艳儿子邵一帆")
|
210
|
-
6. 关键道具需特别说明(如"二八大杠""蜂窝煤")
|
211
|
-
7. 情感提示用括号标注(如"憋着气""得意一笑")
|
212
|
-
8. 人物台词前面不要加△ ,只有人物动作才加△
|
213
|
-
9. 场景描述不需要加上“场景描述:”和括号
|
214
|
-
10. 对生成内容进行检查,对重复内容进行删除(重复的对话、场景描述)
|
215
|
-
11. 禁止人物台词张冠李戴
|
216
|
-
|
217
|
-
请确保生成格式与示例完全一致,包含所有叙事元素:场景、字幕、旁白、动作、对白、情感提示,剧本全文不要出现“*”。并对重复内容进行检查和删除。
|
218
|
-
|
219
|
-
并注意:
|
220
|
-
1.不需要任何额外的解释、问候或结束语(如,
|
221
|
-
好的,请看剧本:
|
222
|
-
好的我给你生成剧本
|
223
|
-
剧本结束了希望你满意
|
224
|
-
)诸如此类都不要给!
|
225
|
-
2. 直接输出剧本内容
|
226
|
-
3. 保持格式规范和一致性
|
227
|
-
|
228
|
-
"""
|
229
|
-
|
230
|
-
# 存储所有生成的txt文件路径,按子目录分类
|
231
|
-
txt_files = {'A': [], 'B': [], 'C': []}
|
232
|
-
|
233
|
-
# 处理每个视频URL
|
234
|
-
for index, url in enumerate(urls, start=1):
|
235
|
-
# 提取文件名作为输出文件名
|
236
|
-
parsed_url = urlparse(url)
|
237
|
-
filename = os.path.basename(parsed_url.path)
|
238
|
-
|
239
|
-
# 为子目录A和B分别生成剧本文件路径
|
240
|
-
output_filename_A = os.path.join(output_dir, 'A', f"{index}.txt")
|
241
|
-
output_filename_B = os.path.join(output_dir, 'B', f"{index}.txt")
|
242
|
-
output_filename_C = os.path.join(output_dir, 'C', f"{index}.txt")
|
243
|
-
|
244
|
-
# 为每个URL生成两次剧本
|
245
|
-
print(f"为第{index}集生成两份剧本...")
|
246
|
-
|
247
|
-
# 生成第一个剧本 (A)
|
248
|
-
analysis_result_A = analyze_video(url, base_prompt)
|
249
|
-
success_A = False
|
250
|
-
if analysis_result_A:
|
251
|
-
# 保存剧本到txt文件
|
252
|
-
with open(output_filename_A, 'w', encoding='utf-8') as output_file:
|
253
|
-
output_file.write(analysis_result_A)
|
254
|
-
print(f"第{index}集剧本A已保存到 {output_filename_A}")
|
255
|
-
txt_files['A'].append(output_filename_A)
|
256
|
-
success_A = True
|
257
|
-
else:
|
258
|
-
print(f"第{index}集视频分析A失败")
|
259
|
-
|
260
|
-
# 生成第二个剧本 (B)
|
261
|
-
analysis_result_B = analyze_video(url, base_prompt)
|
262
|
-
success_B = False
|
263
|
-
if analysis_result_B:
|
264
|
-
# 保存剧本到txt文件
|
265
|
-
with open(output_filename_B, 'w', encoding='utf-8') as output_file:
|
266
|
-
output_file.write(analysis_result_B)
|
267
|
-
print(f"第{index}集剧本B已保存到 {output_filename_B}")
|
268
|
-
txt_files['B'].append(output_filename_B)
|
269
|
-
success_B = True
|
270
|
-
else:
|
271
|
-
print(f"第{index}集视频分析B失败")
|
272
|
-
|
273
|
-
# 处理生成结果 - 这部分应该在每个视频的循环内部
|
274
|
-
# 1. 一个成功一个失败的情况
|
275
|
-
if success_A and not success_B:
|
276
|
-
# 确保目录存在
|
277
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
278
|
-
# 复制文件
|
279
|
-
shutil.copy(output_filename_A, output_filename_C)
|
280
|
-
txt_files['C'].append(output_filename_C)
|
281
|
-
print(f"第{index}集剧本A成功而B失败,已将A复制到C目录")
|
282
|
-
elif not success_A and success_B:
|
283
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
284
|
-
shutil.copy(output_filename_B, output_filename_C)
|
285
|
-
txt_files['C'].append(output_filename_C)
|
286
|
-
print(f"第{index}集剧本B成功而A失败,已将B复制到C目录")
|
287
|
-
# 2. 检查文件大小异常
|
288
|
-
elif success_A and success_B:
|
289
|
-
# 获取文件大小
|
290
|
-
size_A = os.path.getsize(output_filename_A)
|
291
|
-
size_B = os.path.getsize(output_filename_B)
|
292
|
-
|
293
|
-
# 检查是否有异常大的文件(超过6KB)
|
294
|
-
max_normal_size = 6 * 1024 # 6KB
|
295
|
-
|
296
|
-
if size_A > max_normal_size and size_B <= max_normal_size:
|
297
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
298
|
-
shutil.copy(output_filename_B, output_filename_C)
|
299
|
-
txt_files['C'].append(output_filename_C)
|
300
|
-
print(f"第{index}集剧本A文件异常大({size_A}字节),已将B复制到C目录")
|
301
|
-
elif size_B > max_normal_size and size_A <= max_normal_size:
|
302
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
303
|
-
shutil.copy(output_filename_A, output_filename_C)
|
304
|
-
txt_files['C'].append(output_filename_C)
|
305
|
-
print(f"第{index}集剧本B文件异常大({size_B}字节),已将A复制到C目录")
|
306
|
-
# 3. 两个都正常,比较哪个更好
|
307
|
-
else:
|
308
|
-
# 这里简单比较文本长度,更复杂的比较方法可以根据需要添加
|
309
|
-
if len(analysis_result_A) > len(analysis_result_B):
|
310
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
311
|
-
shutil.copy(output_filename_A, output_filename_C)
|
312
|
-
txt_files['C'].append(output_filename_C)
|
313
|
-
print(f"第{index}集剧本A和B都成功,A内容更丰富,已将A复制到C目录")
|
314
|
-
else:
|
315
|
-
os.makedirs(os.path.dirname(output_filename_C), exist_ok=True)
|
316
|
-
shutil.copy(output_filename_B, output_filename_C)
|
317
|
-
txt_files['C'].append(output_filename_C)
|
318
|
-
print(f"第{index}集剧本A和B都成功,B内容更丰富,已将B复制到C目录")
|
319
|
-
|
320
|
-
# 根据子目录C的结果生成Word文档
|
321
|
-
if txt_files['C']:
|
322
|
-
output_docx = os.path.join(output_dir, 'merged_scripts.docx')
|
323
|
-
merge_to_word(txt_files['C'], output_docx)
|
324
|
-
print(f"剧本已合并到 {output_docx}")
|
325
|
-
else:
|
326
|
-
print("没有成功生成任何剧本文件")
|
327
|
-
except Exception as e:
|
328
|
-
print(f"发生错误:{str(e)}")
|
329
|
-
|
330
|
-
# 运行主函数
|
331
|
-
if __name__ == "__main__":
|
332
|
-
main()
|
File without changes
|
File without changes
|
{MeUtils-2025.5.9.17.18.7.dist-info → MeUtils-2025.5.12.15.21.44.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|