返回 VideoClaw
llm_dashscope.py
根目录 / video-claw / video-claw / backend / models / llm_dashscope.py
1 # -*- coding: utf-8 -*-
2 """
3 Qwen LLM API 客户端(DashScope Generation API)
4 支持 qwen3.7-max、qwen3.6-max-preview、qwen3-max 等文本生成模型
5 """
6
7 import os
8 import sys
9
10 models_dir = os.path.dirname(os.path.abspath(__file__))
11 backend_dir = os.path.dirname(models_dir)
12 if backend_dir not in sys.path:
13 sys.path.insert(0, backend_dir)
14
15 import time
16 import logging
17 from typing import Optional
18 from config import Config
19
20 logger = logging.getLogger(__name__)
21
22 try:
23 import dashscope
24 from dashscope import Generation
25 except ImportError:
26 dashscope = None
27 Generation = None
28
29
30 class QwenLLM:
31 """
32 Qwen LLM 客户端,使用 DashScope Generation API
33 支持纯文本生成(可作为 LLM 使用)
34 """
35 def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None):
36 """
37 :param api_key: DashScope API Key
38 :param base_url: DashScope API Base URL (可选)
39 """
40 self.api_key = api_key or Config.DASHSCOPE_API_KEY
41 self.base_url = base_url or Config.DASHSCOPE_BASE_URL
42
43 if not self.api_key:
44 logger.warning("DASHSCOPE_API_KEY is not set")
45
46 if dashscope:
47 dashscope.api_key = self.api_key
48 # Do not override base_url to avoid "url error" if config contains wrong path
49 # if self.base_url:
50 # dashscope.base_http_api_url = self.base_url
51
52 self.max_attempts = 3
53
54 def query(self, prompt: str, image_urls: list = None, model: str = "qwen-max", web_search: bool = False):
55 """
56 Query Qwen model for text generation.
57 Note: This is for text-only LLM use. For image+text, use VLM client.
58
59 :param prompt: Text prompt
60 :param image_urls: Ignored in this LLM implementation (use VLM for multimodal)
61 :param model: Model name (e.g., qwen3.7-max, qwen3.6-max-preview, qwen3-max)
62 :param web_search: If True, adds enable_search: True to API call
63 """
64 if dashscope is None:
65 raise RuntimeError("dashscope package not installed. Run: pip install dashscope")
66
67 if not model or "qwen3.5" in model:
68 # 兼容处理遗留的 qwen3.5 传参,避免 url error
69 if "max" in model:
70 model = "qwen-max"
71 elif "turbo" in model:
72 model = "qwen-turbo"
73 else:
74 model = "qwen-plus"
75
76
77 messages = [{"role": "system", "content": "You are a helpful assistant."}]
78 messages.append({"role": "user", "content": prompt})
79
80 attempts = 0
81 while attempts < self.max_attempts:
82 try:
83 # Build request parameters
84 request_params = {
85 "model": model,
86 "messages": messages,
87 "result_format": "message",
88 "stream": False,
89 }
90 # Add web search if enabled
91 if web_search:
92 request_params["enable_search"] = True
93
94 response = Generation.call(api_key=self.api_key, **request_params)
95
96 if response.status_code == 200:
97 choice = response.output.choices[0]
98 if choice.message.content:
99 return choice.message.content
100 elif hasattr(choice.message, 'reasoning_content') and choice.message.reasoning_content:
101 return choice.message.reasoning_content
102 else:
103 logger.warning("Qwen returned an empty response; retrying")
104 time.sleep(2)
105 else:
106 error_msg = f"Qwen API error: {response.code} - {response.message}"
107 logger.error(error_msg)
108 raise RuntimeError(error_msg)
109
110 except Exception as e:
111 logger.error(f"Error occurred with Qwen: {e}. Retrying.")
112 time.sleep(5)
113
114 attempts += 1
115
116 raise Exception("Max attempts reached, failed to get a response from Qwen.")
117
118
119 if __name__ == "__main__":
120 import sys
121 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
122 from config import Config
123
124 # 支持的模型列表
125
126 MODELS = ["qwen3.7-max", "qwen3.6-max-preview", "qwen3-max", "deepseek-v3.2"]
127
128 print("=== DashScope LLM 可用性测试 ===")
129 api_key = Config.DASHSCOPE_API_KEY
130 if not api_key:
131 print("✗ DASHSCOPE_API_KEY 未设置,跳过")
132 sys.exit(1)
133 print(f" API Key: {api_key[:6]}***{api_key[-4:]}")
134
135 client = QwenLLM(api_key=api_key)
136 prompt = "用一句话介绍你自己。"
137 print(f" Prompt: {prompt}")
138
139 for model in MODELS:
140 print(f"\n--- 测试模型: {model} ---")
141 t0 = time.time()
142 try:
143 resp = client.query(prompt, model=model)
144 elapsed = time.time() - t0
145 print(f"✓ 响应 ({elapsed:.1f}s): {resp.strip()[:200]}")
146 except Exception as e:
147 print(f"✗ 失败: {e}")
148
148 lines PYTHON