添加了计算tokens费用
This commit is contained in:
parent
0e0ec3ae5c
commit
cdcc55f4b4
@ -3,7 +3,7 @@ import os
|
|||||||
import base64
|
import base64
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from token_counter import *
|
||||||
|
|
||||||
# Base64 编码格式
|
# Base64 编码格式
|
||||||
def encode_video(video_path):
|
def encode_video(video_path):
|
||||||
@ -231,16 +231,16 @@ def save_result_to_txt(response_text, video_path, save_dir="/root/autodl-tmp/fin
|
|||||||
STREAM_MODE = True
|
STREAM_MODE = True
|
||||||
|
|
||||||
# 文件路径配置
|
# 文件路径配置
|
||||||
video_path = "/root/autodl-tmp/new/西藏2.mp4"
|
video_path = "/root/autodl-tmp/new/哈尔滨.mp4"
|
||||||
#audio_path = "/root/autodl-tmp/video2audio/sample_demo_6.wav"
|
#audio_path = "/root/autodl-tmp/video2audio/sample_demo_6.wav"
|
||||||
#txt_path = "/root/autodl-tmp/hot_video_analyse/source/example_reference.txt" # 使用示例参考文档
|
#txt_path = "/root/autodl-tmp/hot_video_analyse/source/example_reference.txt" # 使用示例参考文档
|
||||||
|
|
||||||
# JSON文件路径配置
|
# JSON文件路径配置
|
||||||
speech_json_path = "/root/autodl-tmp/new_sensevoice/西藏2_sensevoice.json" # 口播转文字JSON文件
|
speech_json_path = "/root/autodl-tmp/new_sensevoice/哈尔滨_sensevoice.json" # 口播转文字JSON文件
|
||||||
ocr_json_path = "/root/autodl-tmp/new_cnocr/西藏2_subtitles.json" # OCR字幕转文字JSON文件
|
ocr_json_path = "/root/autodl-tmp/new_cnocr/哈尔滨_subtitles.json" # OCR字幕转文字JSON文件
|
||||||
#clip_json_path = "/root/autodl-tmp/02_VideoSplitter/VideoSplitter_output/shou_gonglve_3_scenes.json"
|
#clip_json_path = "/root/autodl-tmp/02_VideoSplitter/VideoSplitter_output/shou_gonglve_3_scenes.json"
|
||||||
whisper_json_path = "/root/autodl-tmp/new_whisper/西藏2_transcript.json" # Whisper转文字JSON文件
|
whisper_json_path = "/root/autodl-tmp/new_whisper/哈尔滨_transcript.json" # Whisper转文字JSON文件
|
||||||
ocr_txt_path = "/root/autodl-tmp/new_cnocr/西藏2_subtitles_processed.txt"
|
ocr_txt_path = "/root/autodl-tmp/new_cnocr/哈尔滨_subtitles_processed.txt"
|
||||||
# 编码文件
|
# 编码文件
|
||||||
print("开始编码文件...")
|
print("开始编码文件...")
|
||||||
encode_start_time = time.time()
|
encode_start_time = time.time()
|
||||||
@ -283,6 +283,122 @@ encode_duration = encode_end_time - encode_start_time
|
|||||||
print(f"文件编码完成,耗时: {encode_duration:.2f} 秒")
|
print(f"文件编码完成,耗时: {encode_duration:.2f} 秒")
|
||||||
|
|
||||||
|
|
||||||
|
# 统计提示词token
|
||||||
|
prompt_text = """🎥 **抖音短视频内容分析专家**
|
||||||
|
## 任务背景
|
||||||
|
您是一位经验丰富的视频导演和编辑,需要基于以上两个时间轴数据,和视频内容。为视频写一个完整、流畅的脚本。
|
||||||
|
请对这个抖音短视频进行详细的内容分析,重点关注以下三个方面:
|
||||||
|
## 🎤 一、口播内容提取
|
||||||
|
请仔细听取视频中的语音内容,完整转录:
|
||||||
|
- **完整口播转录**:逐字逐句转录所有口语表达
|
||||||
|
- **语音时长**:估算总的讲话时长
|
||||||
|
## 📝 二、字幕文字识别
|
||||||
|
请识别视频画面中出现的所有文字内容:
|
||||||
|
- **屏幕字幕**:视频中显示的字幕文字(包括自动字幕和手动添加的字幕)
|
||||||
|
- **标题文字**:视频开头、中间、结尾出现的大标题
|
||||||
|
|
||||||
|
## 🎬 三、转场效果分析
|
||||||
|
请仔细观察视频中的转场效果,并且结合参考资料中的转场内容,请你整体分析一下视频。比如几个画面出现第一个转场等.
|
||||||
|
转场的time_start","time_end","textIdx"请严格按照参考资料中的口播内容的时间戳start,end,id填写,不要自己生成。
|
||||||
|
|
||||||
|
|
||||||
|
## 📊 输出格式要求
|
||||||
|
|
||||||
|
## 视频内容分析
|
||||||
|
请按照以下JSON格式输出视频描述:
|
||||||
|
|
||||||
|
{
|
||||||
|
"total_Oral broadcasting":"请你生成一个完整的口播内容。",
|
||||||
|
"summary": "请用一句话总结视频的核心内容,突出视频的主要卖点和价值主张",
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "cut",
|
||||||
|
"scenes": 1,
|
||||||
|
"time_start": 0.0,
|
||||||
|
"time_end": 2.0,
|
||||||
|
"talk": "请将对应时间的口播或字幕信息,填入此",
|
||||||
|
"description": "跳转到视频对应时间,将视频对应时间的图片,描述这个镜头的画面内容、人物动作、场景特点等。不要重复描述。"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "cut",
|
||||||
|
"scenes": 2,
|
||||||
|
"time_start": 2.0,
|
||||||
|
"time_end": 4.5,
|
||||||
|
"talk": "请将对应时间的口播或字幕信息,填入此",
|
||||||
|
"description": "跳转到视频对应时间,将视频对应时间的图片,详细描述这个镜头的画面内容、人物动作、场景特点等。不要描述视频内容,只描述这个镜头的画面内容,不要重复描述。"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "cut",
|
||||||
|
"scenes": 3,
|
||||||
|
"time_start": 4.5,
|
||||||
|
"time_end": 6.0,
|
||||||
|
"talk": "请将对应时间的口播或字幕信息,填入此",
|
||||||
|
"description": "跳转到视频对应时间,将视频对应时间的图片,详细描述这个镜头的画面内容、人物动作、场景特点等。不要描述视频内容,只描述这个镜头的画面内容,不要重复描述。"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
## 输出要求
|
||||||
|
1. summary:用一句话概括视频核心内容,突出主要卖点
|
||||||
|
2. content:按时间顺序交替描述镜头和转场
|
||||||
|
- 镜头(lens)描述:
|
||||||
|
* textIdx:镜头序号,从1开始递增
|
||||||
|
* time_start:开始时间(秒),精确到小数点后一位
|
||||||
|
* time_end:结束时间(秒),精确到小数点后一位
|
||||||
|
* talk:该镜头中的对话或文字内容
|
||||||
|
* description:详细描述镜头内容,包括:
|
||||||
|
- 画面构图和场景
|
||||||
|
- 人物动作和表情
|
||||||
|
- 重要道具和元素
|
||||||
|
- 特殊效果和转场
|
||||||
|
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
1. 保持描述简洁明了,但要有足够的细节
|
||||||
|
2. 突出视频的亮点和特色
|
||||||
|
3. 确保时间戳的准确性
|
||||||
|
4. 对话内容要符合视频画面
|
||||||
|
5. 整体风格要统一连贯
|
||||||
|
6. 每个镜头的描述要包含关键信息
|
||||||
|
|
||||||
|
## 示例内容描述
|
||||||
|
1. 镜头1:
|
||||||
|
- 开场特写镜头,展示产品外观
|
||||||
|
- 画面从模糊到清晰,突出产品细节
|
||||||
|
- 背景音乐渐入,营造氛围
|
||||||
|
- 文字提示:"全新升级,品质保证"
|
||||||
|
|
||||||
|
2. 转场1-2:
|
||||||
|
- 类型:平滑滑动
|
||||||
|
- 目的:自然过渡到使用场景
|
||||||
|
- 效果:画面从产品特写平滑滑向使用场景
|
||||||
|
|
||||||
|
3. 镜头2:
|
||||||
|
- 中景展示使用场景
|
||||||
|
- 人物自然流畅的动作展示
|
||||||
|
- 光线明亮,突出产品效果
|
||||||
|
- 文字说明:"简单操作,轻松上手"
|
||||||
|
|
||||||
|
4. 转场2-3:
|
||||||
|
- 类型:快速缩放
|
||||||
|
- 目的:突出产品核心功能
|
||||||
|
- 效果:画面快速聚焦到产品关键部位
|
||||||
|
|
||||||
|
5. 镜头3:
|
||||||
|
- 特写展示产品核心功能
|
||||||
|
- 慢动作展示关键细节
|
||||||
|
- 画面色彩鲜明,对比强烈
|
||||||
|
- 文字强调:"专业性能,值得信赖"
|
||||||
|
|
||||||
|
请根据以上要求,分析视频并输出JSON格式的描述。
|
||||||
|
|
||||||
|
请开始详细分析这个抖音短视频:"""
|
||||||
|
|
||||||
|
# 调用token统计功能
|
||||||
|
token_stats = analyze_input_tokens(video_path, txt_content, prompt_text)
|
||||||
|
|
||||||
client = OpenAI(
|
client = OpenAI(
|
||||||
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx"
|
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx"
|
||||||
api_key="EMPTY",
|
api_key="EMPTY",
|
||||||
@ -348,7 +464,7 @@ content_list.append({
|
|||||||
"time_start": 0.0,
|
"time_start": 0.0,
|
||||||
"time_end": 2.0,
|
"time_end": 2.0,
|
||||||
"talk": "请将对应时间的口播或字幕信息,填入此",
|
"talk": "请将对应时间的口播或字幕信息,填入此",
|
||||||
"description": "跳转到视频对应时间,将视频对应时间的图片,详细描述这个镜头的画面内容、人物动作、场景特点等。不要描述视频内容,只描述这个镜头的画面内容,不要重复描述。"
|
"description": "跳转到视频对应时间,将视频对应时间的图片,描述这个镜头的画面内容、人物动作、场景特点等。不要重复描述。"
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -449,7 +565,7 @@ completion = client.chat.completions.create(
|
|||||||
],
|
],
|
||||||
stream=STREAM_MODE,
|
stream=STREAM_MODE,
|
||||||
stream_options={"include_usage": True} if STREAM_MODE else None,
|
stream_options={"include_usage": True} if STREAM_MODE else None,
|
||||||
temperature=0.4
|
temperature=0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
if STREAM_MODE:
|
if STREAM_MODE:
|
||||||
@ -510,7 +626,9 @@ if STREAM_MODE:
|
|||||||
tokens_per_second = token_count / generation_time
|
tokens_per_second = token_count / generation_time
|
||||||
print(f"🔥 生成速度: {tokens_per_second:.2f} tokens/秒")
|
print(f"🔥 生成速度: {tokens_per_second:.2f} tokens/秒")
|
||||||
print(f"⏰ 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
print(f"⏰ 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
|
print(f"输出总费用:{token_count*0.0045/1000:.4f}元")
|
||||||
|
final_cost = token_stats['total_cost']+token_count*0.0045/1000
|
||||||
|
print(f"总费用:{final_cost:.4f}元")
|
||||||
# 输出使用情况信息
|
# 输出使用情况信息
|
||||||
if usage_info:
|
if usage_info:
|
||||||
print("\n" + "="*50)
|
print("\n" + "="*50)
|
||||||
|
|||||||
@ -72,6 +72,7 @@ class VideoSubtitleExtractor:
|
|||||||
self.paddle_ocr = PaddleOCR(
|
self.paddle_ocr = PaddleOCR(
|
||||||
use_textline_orientation=True,
|
use_textline_orientation=True,
|
||||||
lang=paddle_lang,
|
lang=paddle_lang,
|
||||||
|
use_gpu=True, # 启用GPU加速
|
||||||
show_log=False # 减少日志输出
|
show_log=False # 减少日志输出
|
||||||
)
|
)
|
||||||
logger.info("PaddleOCR加载完成")
|
logger.info("PaddleOCR加载完成")
|
||||||
@ -101,7 +102,8 @@ class VideoSubtitleExtractor:
|
|||||||
logger.info(f"EasyOCR模型路径: {model_storage_directory}")
|
logger.info(f"EasyOCR模型路径: {model_storage_directory}")
|
||||||
self.easy_ocr = easyocr.Reader(
|
self.easy_ocr = easyocr.Reader(
|
||||||
lang_list,
|
lang_list,
|
||||||
model_storage_directory=model_storage_directory
|
model_storage_directory=model_storage_directory,
|
||||||
|
gpu=True # 启用GPU加速
|
||||||
)
|
)
|
||||||
logger.info("EasyOCR加载完成")
|
logger.info("EasyOCR加载完成")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -125,7 +127,7 @@ class VideoSubtitleExtractor:
|
|||||||
logger.info("使用CnOCR默认模型配置")
|
logger.info("使用CnOCR默认模型配置")
|
||||||
|
|
||||||
# 使用默认配置,CnOCR会自动选择合适的模型
|
# 使用默认配置,CnOCR会自动选择合适的模型
|
||||||
self.cn_ocr = CnOcr()
|
self.cn_ocr = CnOcr(device='gpu') # 启用GPU加速
|
||||||
logger.info("CnOCR加载完成")
|
logger.info("CnOCR加载完成")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.error("请安装CnOCR: pip install cnocr")
|
logger.error("请安装CnOCR: pip install cnocr")
|
||||||
|
|||||||
112
token_counter.py
Normal file
112
token_counter.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import tiktoken
|
||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
def count_tokens(text, model="gpt-4"):
|
||||||
|
"""统计文本的token数量"""
|
||||||
|
try:
|
||||||
|
encoding = tiktoken.encoding_for_model(model)
|
||||||
|
tokens = encoding.encode(text)
|
||||||
|
return len(tokens)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Token统计出错: {e}")
|
||||||
|
# 简单估算:中文字符约1.5个token,英文单词约1.3个token
|
||||||
|
chinese_chars = sum(1 for char in text if '\u4e00' <= char <= '\u9fff')
|
||||||
|
english_words = len([word for word in text.split() if word.isascii()])
|
||||||
|
estimated_tokens = int(chinese_chars * 1.5 + english_words * 1.3)
|
||||||
|
return estimated_tokens
|
||||||
|
|
||||||
|
def get_video_token_estimate(video_path):
|
||||||
|
"""估算视频的token数量(基于文件大小和时长)"""
|
||||||
|
try:
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
if not cap.isOpened():
|
||||||
|
return {'estimated_tokens': 0, 'duration': 0, 'frame_count': 0, 'fps': 0, 'file_size_mb': 0, 'frames_used': 0}
|
||||||
|
|
||||||
|
# 获取视频信息
|
||||||
|
fps = cap.get(cv2.CAP_PROP_FPS)
|
||||||
|
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
duration = frame_count / fps if fps > 0 else 0
|
||||||
|
|
||||||
|
# 获取文件大小
|
||||||
|
file_size = os.path.getsize(video_path)
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
|
||||||
|
# 基于GPT-4V的token估算规则
|
||||||
|
# 视频token = 基础token + 帧数 * 每帧token
|
||||||
|
base_tokens = 85 # 基础token
|
||||||
|
frames_per_second = min(fps, 1) # 每秒最多1帧
|
||||||
|
total_frames = min(frame_count, int(duration * frames_per_second))
|
||||||
|
tokens_per_frame = 170 # 每帧约170个token
|
||||||
|
|
||||||
|
estimated_tokens = base_tokens + total_frames * tokens_per_frame
|
||||||
|
|
||||||
|
return {
|
||||||
|
'estimated_tokens': int(estimated_tokens),
|
||||||
|
'duration': duration,
|
||||||
|
'frame_count': frame_count,
|
||||||
|
'fps': fps,
|
||||||
|
'file_size_mb': file_size / (1024 * 1024),
|
||||||
|
'frames_used': total_frames
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"视频token估算出错: {e}")
|
||||||
|
return {'estimated_tokens': 0, 'duration': 0, 'frame_count': 0, 'fps': 0, 'file_size_mb': 0, 'frames_used': 0}
|
||||||
|
|
||||||
|
def analyze_input_tokens(video_path, text_content="", prompt_text=""):
|
||||||
|
"""分析输入token统计"""
|
||||||
|
print("\n" + "="*50)
|
||||||
|
print("📊 Token统计信息:")
|
||||||
|
print("="*50)
|
||||||
|
|
||||||
|
# 统计视频token
|
||||||
|
video_token_info = get_video_token_estimate(video_path)
|
||||||
|
print(f"🎬 视频Token统计:")
|
||||||
|
print(f" 估算Token数量: {video_token_info['estimated_tokens']:,}")
|
||||||
|
print(f" 视频时长: {video_token_info['duration']:.2f}秒")
|
||||||
|
print(f" 总帧数: {video_token_info['frame_count']:,}")
|
||||||
|
print(f" 帧率: {video_token_info['fps']:.2f} fps")
|
||||||
|
print(f" 文件大小: {video_token_info['file_size_mb']:.2f} MB")
|
||||||
|
print(f" 使用帧数: {video_token_info['frames_used']:,}")
|
||||||
|
|
||||||
|
# 统计文本token
|
||||||
|
text_tokens = 0
|
||||||
|
if text_content.strip():
|
||||||
|
text_tokens = count_tokens(text_content)
|
||||||
|
print(f"\n📝 文本Token统计:")
|
||||||
|
print(f" 文本内容Token: {text_tokens:,}")
|
||||||
|
print(f" 文本字符数: {len(text_content):,}")
|
||||||
|
|
||||||
|
# 统计提示词token
|
||||||
|
prompt_tokens = 0
|
||||||
|
if prompt_text.strip():
|
||||||
|
prompt_tokens = count_tokens(prompt_text)
|
||||||
|
print(f" 提示词Token: {prompt_tokens:,}")
|
||||||
|
|
||||||
|
# 计算总输入token
|
||||||
|
total_input_tokens = video_token_info['estimated_tokens'] + text_tokens + prompt_tokens
|
||||||
|
print(f"\n📈 总输入Token统计:")
|
||||||
|
print(f" 视频Token: {video_token_info['estimated_tokens']:,}")
|
||||||
|
print(f" 文本Token: {text_tokens:,}")
|
||||||
|
print(f" 提示词Token: {prompt_tokens:,}")
|
||||||
|
print(f" 🔥 总输入Token: {total_input_tokens:,}")
|
||||||
|
|
||||||
|
print("="*50)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'video_tokens': video_token_info['estimated_tokens'],
|
||||||
|
'text_tokens': text_tokens,
|
||||||
|
'prompt_tokens': prompt_tokens,
|
||||||
|
'total_input_tokens': total_input_tokens,
|
||||||
|
'video_info': video_token_info
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 测试token统计功能
|
||||||
|
test_video = "/root/autodl-tmp/new/哈尔滨.mp4"
|
||||||
|
test_text = "这是一个测试文本,包含中英文内容。This is a test text with Chinese and English content."
|
||||||
|
test_prompt = "请分析这个视频的内容。"
|
||||||
|
|
||||||
|
result = analyze_input_tokens(test_video, test_text, test_prompt)
|
||||||
|
print(f"\n测试结果: {result}")
|
||||||
Loading…
x
Reference in New Issue
Block a user