TongyiQianwen.php 6.1 KB

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