google_ai_analyze.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import os
  2. import time
  3. import uuid
  4. from typing import Optional
  5. import google.generativeai as genai
  6. import orjson
  7. import requests
  8. from google.generativeai.types import (HarmBlockThreshold, HarmCategory)
  9. from loguru import logger
  10. from utils.coze_hook import CozeHook
  11. from utils.google_ai_prompt import VIDEO_TOPIC_ANALYSIS_PROMPT, VIDEO_SEGMENT_ANALYSIS_PROMPT
  12. # from utils.feishu_data import Material
  13. CACHE_DIR = os.path.join(os.getcwd(), 'video_cache')
  14. # CACHE_DIR = '/Users/z/Downloads/'
  15. # PROXY_ADDR = 'http://localhost:1081'
  16. # os.environ['http_proxy'] = PROXY_ADDR
  17. # os.environ['https_proxy'] = PROXY_ADDR
  18. def load_prompts():
  19. """从prompt.py加载Prompt"""
  20. try:
  21. print("\n[初始化] 从prompt.py加载Prompt")
  22. prompts = [
  23. {
  24. "name": "视频选题与要点理解",
  25. "content": VIDEO_TOPIC_ANALYSIS_PROMPT
  26. },
  27. {
  28. "name": "视频分段与时间点分析",
  29. "content": VIDEO_SEGMENT_ANALYSIS_PROMPT
  30. }
  31. ]
  32. print(f"[成功] 加载 {len(prompts)} 个Prompt")
  33. return prompts
  34. except Exception as e:
  35. raise Exception(f"加载Prompt失败: {str(e)}")
  36. class GoogleAI(object):
  37. @classmethod
  38. def download_video(cls, video_link: str) -> Optional[str]:
  39. file_path = os.path.join(CACHE_DIR, f'{str(uuid.uuid4())}.mp4')
  40. try:
  41. # 确保缓存目录存在
  42. try:
  43. os.makedirs(CACHE_DIR, exist_ok=True)
  44. except Exception as e:
  45. error_info = {
  46. "error_type": type(e).__name__,
  47. "error_message": str(e),
  48. "cache_dir": CACHE_DIR,
  49. "current_dir": os.getcwd(),
  50. "dir_exists": os.path.exists(CACHE_DIR),
  51. "dir_permissions": oct(os.stat(os.path.dirname(CACHE_DIR)).st_mode)[-3:] if os.path.exists(os.path.dirname(CACHE_DIR)) else "N/A"
  52. }
  53. error_json = orjson.dumps(error_info, option=orjson.OPT_INDENT_2).decode('utf-8')
  54. logger.error(f'[内容分析] 创建缓存目录失败: {error_json}')
  55. return None
  56. for _ in range(3):
  57. try:
  58. response = requests.get(url=video_link, timeout=60)
  59. print(f"response content: {file_path}")
  60. if response.status_code == 200:
  61. try:
  62. with open(file_path, 'wb') as f:
  63. f.write(response.content)
  64. logger.info(f'[内容分析] 视频链接: {video_link}, 存储地址: {file_path}')
  65. except Exception as e:
  66. error_info = {
  67. "error_type": type(e).__name__,
  68. "error_message": str(e),
  69. "file_path": file_path,
  70. "content_length": len(response.content) if response.content else 0
  71. }
  72. error_json = orjson.dumps(error_info, option=orjson.OPT_INDENT_2).decode('utf-8')
  73. logger.error(f'[内容分析] 视频保存失败: {error_json}')
  74. return None
  75. return file_path
  76. except Exception:
  77. time.sleep(1)
  78. continue
  79. except Exception:
  80. logger.error(f'[内容分析] 创建缓存目录失败')
  81. return None
  82. @classmethod
  83. def _analyze_content(cls, video, prompt):
  84. """增强版内容分析"""
  85. model = genai.GenerativeModel(
  86. model_name='gemini-2.0-flash',
  87. generation_config=genai.GenerationConfig(
  88. response_mime_type='application/json',
  89. temperature=0.3,
  90. max_output_tokens=20480
  91. ),
  92. safety_settings={
  93. HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
  94. HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
  95. }
  96. )
  97. try:
  98. response = model.generate_content(
  99. contents=[video, prompt],
  100. request_options={'timeout': 300}
  101. )
  102. if hasattr(response, '_error') and response._error:
  103. raise Exception(f"生成错误: {response._error}")
  104. result = orjson.loads(response.text.strip())
  105. print(f"[视频分析] 响应: {result}")
  106. if not isinstance(result, dict):
  107. raise ValueError("响应格式错误:非字典结构")
  108. return result
  109. except orjson.JSONDecodeError:
  110. raise Exception("响应解析失败,非JSON格式")
  111. except Exception as e:
  112. raise Exception(f"分析失败: {str(e)}")
  113. @classmethod
  114. def run(cls, api_key, video_url):
  115. print(f"api_key:{api_key},video_url:{video_url}")
  116. video_path = None
  117. try:
  118. genai.configure(api_key=api_key)
  119. video_path = cls.download_video(video_link=video_url)
  120. if not video_path:
  121. logger.error(f'[内容分析] 视频下载失败, 跳过任务')
  122. os.remove(video_path)
  123. logger.info(f"[内容分析] 文件已删除: {video_path}")
  124. return "[异常] 视频下载失败",""
  125. video = genai.upload_file(path=video_path, mime_type='video/mp4')
  126. while video.state.name == 'PROCESSING':
  127. time.sleep(1)
  128. video = genai.get_file(name=video.name)
  129. if video.state.name != 'ACTIVE':
  130. genai.delete_file(name=video.name)
  131. os.remove(video_path)
  132. return "[异常] 上传视频失败", ""
  133. prompts = load_prompts()
  134. analysis_data = {}
  135. for prompt in prompts[:3]:
  136. print(f"[分析] 正在执行: {prompt['name']}")
  137. try:
  138. result = cls._analyze_content(video, prompt['content'])
  139. analysis_data[prompt['name']] = result
  140. except Exception as e:
  141. analysis_data[prompt['name']] = {
  142. "error": str(e),
  143. "error_type": type(e).__name__
  144. }
  145. print(f"[分析] 所有分析完成, 结果: {analysis_data}")
  146. coze_hook = CozeHook()
  147. demand_list = coze_hook.run(analysis_data["视频选题与要点理解"], analysis_data["视频分段与时间点分析"])
  148. print(f"[分析] 所有分析完成, 结果: {demand_list}")
  149. genai.delete_file(name=video.name)
  150. os.remove(video_path)
  151. return analysis_data, demand_list
  152. except Exception as e:
  153. logger.error(f"[内容分析] 处理异常,异常信息{e}")
  154. os.remove(video_path)
  155. return f"[异常] {e}",""
  156. if __name__ == '__main__':
  157. ai = GoogleAI()
  158. ai.run("AIzaSyBFLCKMLX-Pf1iXoC2e_rMDLbNhNG23vTk",
  159. "http://rescdn.yishihui.com/jq_oss/video/2025012215472528213")