gemini_api.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. """
  2. Gemini API 工具
  3. 提供内容分析和比较功能。
  4. """
  5. import json
  6. import os
  7. from typing import List, Dict, Any, Optional
  8. import httpx
  9. from agent.tools import tool, ToolResult
  10. # API 基础配置
  11. GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "")
  12. GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent"
  13. DEFAULT_TIMEOUT = 60.0
  14. @tool(
  15. display={
  16. "zh": {
  17. "name": "Gemini内容分析",
  18. "params": {
  19. "content": "要分析的内容",
  20. "analysis_type": "分析类型",
  21. "context": "上下文信息"
  22. }
  23. }
  24. }
  25. )
  26. async def gemini_analyze_content(
  27. content: str,
  28. analysis_type: str = "general",
  29. context: Optional[str] = None,
  30. ) -> ToolResult:
  31. """
  32. 使用Gemini分析内容
  33. Args:
  34. content: 要分析的内容(视频标题、描述等)
  35. analysis_type: 分析类型,可选:
  36. - general: 通用分析
  37. - emotion: 情感分析
  38. - audience: 受众分析
  39. - quality: 质量评估
  40. context: 额外的上下文信息
  41. Returns:
  42. ToolResult 包含分析结果:
  43. {
  44. "analysis": "分析结果文本",
  45. "structured_data": {
  46. "emotion": "感动",
  47. "target_audience": "50+老年人",
  48. "key_themes": ["抗日", "英雄", "历史"],
  49. "quality_score": 8.5,
  50. "recommendations": ["适合老年人观看", "具有教育意义"]
  51. }
  52. }
  53. """
  54. try:
  55. if not GEMINI_API_KEY:
  56. return ToolResult(
  57. title="配置错误",
  58. output="",
  59. error="未配置 GEMINI_API_KEY 环境变量"
  60. )
  61. # 构建提示词
  62. prompts = {
  63. "general": f"请分析以下内容,提供详细的分析报告:\n\n{content}",
  64. "emotion": f"请分析以下内容的情感倾向,识别主要情感和情感强度:\n\n{content}",
  65. "audience": f"请分析以下内容适合的目标受众,包括年龄、兴趣等特征:\n\n{content}",
  66. "quality": f"请评估以下内容的质量,包括吸引力、完整性、可信度等:\n\n{content}",
  67. }
  68. prompt = prompts.get(analysis_type, prompts["general"])
  69. if context:
  70. prompt += f"\n\n上下文信息:{context}"
  71. # 调用Gemini API
  72. payload = {
  73. "contents": [{
  74. "parts": [{
  75. "text": prompt
  76. }]
  77. }]
  78. }
  79. headers = {
  80. "Content-Type": "application/json",
  81. }
  82. url = f"{GEMINI_API_URL}?key={GEMINI_API_KEY}"
  83. async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
  84. response = await client.post(
  85. url,
  86. json=payload,
  87. headers=headers,
  88. )
  89. response.raise_for_status()
  90. data = response.json()
  91. # 提取分析结果
  92. candidates = data.get("candidates", [])
  93. if not candidates:
  94. return ToolResult(
  95. title="分析失败",
  96. output="",
  97. error="Gemini API 未返回结果"
  98. )
  99. analysis_text = candidates[0].get("content", {}).get("parts", [{}])[0].get("text", "")
  100. result = {
  101. "analysis": analysis_text,
  102. "analysis_type": analysis_type,
  103. "content_preview": content[:100] + "..." if len(content) > 100 else content
  104. }
  105. return ToolResult(
  106. title=f"Gemini分析: {analysis_type}",
  107. output=json.dumps(result, ensure_ascii=False, indent=2),
  108. long_term_memory=f"Analyzed content with Gemini ({analysis_type})"
  109. )
  110. except httpx.HTTPStatusError as e:
  111. return ToolResult(
  112. title="API调用失败",
  113. output="",
  114. error=f"HTTP error {e.response.status_code}: {e.response.text}"
  115. )
  116. except Exception as e:
  117. return ToolResult(
  118. title="分析失败",
  119. output="",
  120. error=str(e)
  121. )
  122. @tool(
  123. display={
  124. "zh": {
  125. "name": "Gemini比较视频",
  126. "params": {
  127. "videos": "视频列表",
  128. "comparison_criteria": "比较标准"
  129. }
  130. }
  131. }
  132. )
  133. async def gemini_compare_videos(
  134. videos: List[Dict[str, Any]],
  135. comparison_criteria: Optional[List[str]] = None,
  136. ) -> ToolResult:
  137. """
  138. 使用Gemini比较多个视频
  139. Args:
  140. videos: 视频列表,每个视频包含:
  141. - title: 标题
  142. - description: 描述
  143. - tags: 标签列表
  144. - stats: 数据统计
  145. comparison_criteria: 比较标准,可选:
  146. - similarity: 相似度
  147. - quality: 质量
  148. - audience_fit: 受众匹配度
  149. - engagement: 互动表现
  150. Returns:
  151. ToolResult 包含比较结果:
  152. {
  153. "comparison": "比较分析文本",
  154. "rankings": [
  155. {
  156. "video_index": 0,
  157. "title": "...",
  158. "score": 8.5,
  159. "strengths": ["..."],
  160. "weaknesses": ["..."]
  161. }
  162. ],
  163. "recommendations": ["..."]
  164. }
  165. """
  166. try:
  167. if not GEMINI_API_KEY:
  168. return ToolResult(
  169. title="配置错误",
  170. output="",
  171. error="未配置 GEMINI_API_KEY 环境变量"
  172. )
  173. if len(videos) < 2:
  174. return ToolResult(
  175. title="参数错误",
  176. output="",
  177. error="至少需要2个视频进行比较"
  178. )
  179. # 构建比较提示词
  180. criteria_text = "、".join(comparison_criteria) if comparison_criteria else "相似度、质量、受众匹配度"
  181. prompt = f"请比较以下{len(videos)}个视频,从{criteria_text}等方面进行分析:\n\n"
  182. for i, video in enumerate(videos, 1):
  183. prompt += f"视频{i}:\n"
  184. prompt += f"标题:{video.get('title', 'N/A')}\n"
  185. prompt += f"描述:{video.get('description', 'N/A')}\n"
  186. prompt += f"标签:{', '.join(video.get('tags', []))}\n"
  187. if 'stats' in video:
  188. prompt += f"数据:{json.dumps(video['stats'], ensure_ascii=False)}\n"
  189. prompt += "\n"
  190. prompt += "请提供详细的比较分析,并给出推荐建议。"
  191. # 调用Gemini API
  192. payload = {
  193. "contents": [{
  194. "parts": [{
  195. "text": prompt
  196. }]
  197. }]
  198. }
  199. headers = {
  200. "Content-Type": "application/json",
  201. }
  202. url = f"{GEMINI_API_URL}?key={GEMINI_API_KEY}"
  203. async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
  204. response = await client.post(
  205. url,
  206. json=payload,
  207. headers=headers,
  208. )
  209. response.raise_for_status()
  210. data = response.json()
  211. # 提取比较结果
  212. candidates = data.get("candidates", [])
  213. if not candidates:
  214. return ToolResult(
  215. title="比较失败",
  216. output="",
  217. error="Gemini API 未返回结果"
  218. )
  219. comparison_text = candidates[0].get("content", {}).get("parts", [{}])[0].get("text", "")
  220. result = {
  221. "comparison": comparison_text,
  222. "video_count": len(videos),
  223. "criteria": comparison_criteria or ["similarity", "quality", "audience_fit"]
  224. }
  225. return ToolResult(
  226. title=f"Gemini比较: {len(videos)}个视频",
  227. output=json.dumps(result, ensure_ascii=False, indent=2),
  228. long_term_memory=f"Compared {len(videos)} videos with Gemini"
  229. )
  230. except httpx.HTTPStatusError as e:
  231. return ToolResult(
  232. title="API调用失败",
  233. output="",
  234. error=f"HTTP error {e.response.status_code}: {e.response.text}"
  235. )
  236. except Exception as e:
  237. return ToolResult(
  238. title="比较失败",
  239. output="",
  240. error=str(e)
  241. )