TongyiQianwen.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. namespace App\Servers\Aliyun;
  3. use \Exception;
  4. /**
  5. * 通义千问大模型API
  6. * 提供简单易用的接口调用阿里云百炼大模型平台
  7. * @author 唐远望
  8. * @version 1.0
  9. * @date 2025-12-22
  10. */
  11. class TongyiQianwen
  12. {
  13. private $apiKey;
  14. private $baseUrl = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions';
  15. private $model = 'qwen-flash';
  16. private $timeout = 30;
  17. /**
  18. * 构造函数
  19. *
  20. * @param string $apiKey API密钥,如果不传则尝试从环境变量获取
  21. * @throws Exception 当API密钥未设置时抛出异常
  22. */
  23. public function __construct($apiKey = null)
  24. {
  25. if ($apiKey) {
  26. $this->apiKey = $apiKey;
  27. } else {
  28. $this->apiKey = config('aliyun.bailian_access_key', '');
  29. }
  30. if (empty($this->apiKey)) {
  31. throw new Exception('API密钥未设置,请通过构造函数传入或设置DASHSCOPE_API_KEY环境变量');
  32. }
  33. }
  34. /**
  35. * 设置模型
  36. *
  37. * @param string $model 模型名称
  38. * @return $this
  39. */
  40. public function setModel($model)
  41. {
  42. $this->model = $model;
  43. return $this;
  44. }
  45. /**
  46. * 设置请求超时时间
  47. *
  48. * @param int $timeout 超时时间(秒)
  49. * @return $this
  50. */
  51. public function setTimeout($timeout)
  52. {
  53. $this->timeout = $timeout;
  54. return $this;
  55. }
  56. /**
  57. * 发送消息并获取回复
  58. *
  59. * @param string|array $messages 消息内容,可以是字符串或消息数组
  60. * @param string $systemPrompt 系统提示词
  61. * @return array 包含响应数据和错误信息的数组
  62. */
  63. public function sendMessage($messages, $systemPrompt = "")
  64. {
  65. // 格式化消息
  66. $formattedMessages = $this->formatMessages($messages, $systemPrompt);
  67. // 准备请求数据
  68. $data = [
  69. "model" => $this->model,
  70. "messages" => $formattedMessages
  71. ];
  72. // 设置请求头
  73. $headers = [
  74. 'Authorization: Bearer ' . $this->apiKey,
  75. 'Content-Type: application/json'
  76. ];
  77. // 初始化cURL
  78. $ch = curl_init();
  79. curl_setopt_array($ch, [
  80. CURLOPT_URL => $this->baseUrl,
  81. CURLOPT_POST => true,
  82. CURLOPT_POSTFIELDS => json_encode($data),
  83. CURLOPT_RETURNTRANSFER => true,
  84. CURLOPT_HTTPHEADER => $headers,
  85. CURLOPT_TIMEOUT => $this->timeout,
  86. CURLOPT_SSL_VERIFYPEER => true,
  87. ]);
  88. // 执行请求
  89. $response = curl_exec($ch);
  90. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  91. $error = curl_error($ch);
  92. curl_close($ch);
  93. // 处理响应
  94. if ($error) {
  95. return [
  96. 'success' => false,
  97. 'error' => 'CURL错误: ' . $error,
  98. 'data' => null
  99. ];
  100. }
  101. $decodedResponse = json_decode($response, true);
  102. if ($httpCode !== 200) {
  103. return [
  104. 'success' => false,
  105. 'error' => 'API请求失败,HTTP状态码: ' . $httpCode,
  106. 'data' => $decodedResponse
  107. ];
  108. }
  109. return [
  110. 'success' => true,
  111. 'error' => null,
  112. 'data' => $decodedResponse
  113. ];
  114. }
  115. /**
  116. * 格式化消息为API所需的格式
  117. *
  118. * @param string|array $messages 消息内容
  119. * @param string $systemPrompt 系统提示词
  120. * @return array 格式化后的消息数组
  121. */
  122. private function formatMessages($messages, $systemPrompt)
  123. {
  124. $formattedMessages = [];
  125. // 添加系统提示
  126. if (!empty($systemPrompt)) {
  127. $formattedMessages[] = [
  128. "role" => "system",
  129. "content" => $systemPrompt
  130. ];
  131. }
  132. // 处理不同类型的消息输入
  133. if (is_string($messages)) {
  134. // 单条用户消息
  135. $formattedMessages[] = [
  136. "role" => "user",
  137. "content" => $messages
  138. ];
  139. } elseif (is_array($messages)) {
  140. // 多条消息
  141. foreach ($messages as $message) {
  142. if (is_string($message)) {
  143. $formattedMessages[] = [
  144. "role" => "user",
  145. "content" => $message
  146. ];
  147. } elseif (is_array($message) && isset($message['role']) && isset($message['content'])) {
  148. $formattedMessages[] = $message;
  149. }
  150. }
  151. }
  152. return $formattedMessages;
  153. }
  154. /**
  155. * 从响应中提取助手的回复内容
  156. *
  157. * @param array $responseData sendMessage返回的数据
  158. * @return string|null 助手的回复内容,如果不存在则返回null
  159. */
  160. public function getAssistantReply($responseData)
  161. {
  162. if (!$responseData['success'] || !isset($responseData['data']['choices'][0]['message']['content'])) {
  163. return null;
  164. }
  165. return $responseData['data']['choices'][0]['message']['content'];
  166. }
  167. /**
  168. * 从响应中提取助手的回复消息ID
  169. *
  170. * @param array $responseData sendMessage返回的数据
  171. * @return string|null 助手的回复内容,如果不存在则返回null
  172. */
  173. public function getAssistantReplyId($responseData)
  174. {;
  175. if (!$responseData['success'] || !isset($responseData['data']['id'])) {
  176. return null;
  177. }
  178. return $responseData['data']['id'];
  179. }
  180. /**
  181. * 简化调用 - 发送消息并直接获取回复文本
  182. *
  183. * @param string $message 用户消息
  184. * @param string $systemPrompt 系统提示词
  185. * @return string 助手的回复内容,如果出错则返回错误信息
  186. */
  187. public function ask($message, $systemPrompt = "You are a helpful assistant.")
  188. {
  189. $response = $this->sendMessage($message, $systemPrompt);
  190. if (!$response['success']) {
  191. return "错误: " . $response['error'];
  192. }
  193. $reply = $this->getAssistantReply($response);
  194. return $reply ?: "未能获取到有效回复";
  195. }
  196. }