AIGatewayService.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <?php
  2. namespace app\service;
  3. use think\Db;
  4. use think\Queue;
  5. class AIGatewayService{
  6. /**
  7. * 接口访问配置
  8. *
  9. * 每个模块包含:
  10. * - api_key:API 调用密钥(Bearer Token)
  11. * - api_url:对应功能的服务端地址
  12. */
  13. protected $config = [
  14. //图生文
  15. 'imgtotxt' => [
  16. 'api_key' => 'sk-scyWT2YPrPOIzralcb6WzCeFdAZvl91rh1JcuuaNMrhEJNDZ',
  17. 'api_url' => 'https://niubi.zeabur.app/v1/chat/completions'
  18. ],
  19. //文生文
  20. 'txttotxt' => [
  21. 'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
  22. 'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
  23. ],
  24. //文生图
  25. 'txttoimg' => [
  26. 'api_key' => 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY',
  27. 'api_url' => 'https://niubi.zeabur.app/v1/images/generations'
  28. ],
  29. // //文生文-超结损分析
  30. // 'chaojiesun' => [
  31. // 'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
  32. // 'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
  33. // ]
  34. ];
  35. /**
  36. * 图生文
  37. * @param string $imageUrl 图像 URL,支持公网可访问地址
  38. * @param string $prompt 对图像的提问内容或提示文本
  39. */
  40. public function callGptApi($imageUrl, $prompt)
  41. {
  42. $data = [
  43. "model" => "gemini-2.5-pro-preview-05-06",
  44. "messages" => [[
  45. "role" => "user",
  46. "content" => [
  47. ["type" => "text", "text" => $prompt],
  48. ["type" => "image_url", "image_url" => [
  49. "url" => $imageUrl,
  50. "detail" => "auto"
  51. ]]
  52. ]
  53. ]],
  54. "max_tokens" => 1000
  55. ];
  56. return $this->callApi($this->config['imgtotxt']['api_url'], $this->config['imgtotxt']['api_key'], $data);
  57. }
  58. /**
  59. * 图生文-方法二
  60. * @param string $imageUrl 图像 URL,支持公网可访问地址
  61. * @param string $prompt 对图像的提问内容或提示文本
  62. */
  63. // public function callGptApi($imageUrl, $prompt)
  64. // {
  65. // $data = [
  66. // "model" => "gpt-4-vision-preview",
  67. // "messages" => [[
  68. // "role" => "user",
  69. // "content" => [
  70. // ["type" => "text", "text" => $prompt],
  71. // ["type" => "image_url", "image_url" => [
  72. // "url" => $imageUrl,
  73. // "detail" => "auto"
  74. // ]]
  75. // ]
  76. // ]],
  77. // "max_tokens" => 1000
  78. // ];
  79. // return $this->callApi($this->config['imgtotxt']['api_url'], $this->config['imgtotxt']['api_key'], $data);
  80. // }
  81. /**
  82. * 文生文
  83. * @param string $prompt 用户输入的文本提示内容
  84. */
  85. public function txtGptApi($prompt)
  86. {
  87. $data = [
  88. 'prompt' => $prompt,
  89. 'model' => 'gpt-4',
  90. 'session_id' => null,
  91. 'context_reset' => true
  92. ];
  93. return $this->callApi(
  94. $this->config['txttotxt']['api_url'],
  95. $this->config['txttotxt']['api_key'],
  96. $data
  97. );
  98. }
  99. /**
  100. * 文生文-超结损分析
  101. * @param string $prompt 用户输入的文本提示内容
  102. */
  103. // public function chaojiesunGptApi($prompt)
  104. // {
  105. // $data = [
  106. // 'prompt' => $prompt,
  107. // 'model' => 'gpt-4',
  108. // 'session_id' => null,
  109. // 'context_reset' => true
  110. // ];
  111. // return $this->callApi(
  112. // $this->config['chaojiesun']['api_url'],
  113. // $this->config['chaojiesun']['api_key'],
  114. // $data
  115. // );
  116. // }
  117. /**
  118. * 文生图
  119. * @param string $prompt 提示文本,用于指导图像生成
  120. * @param string $selectedOption 模型名称,例如 'dall-e-3' 或其他兼容模型
  121. */
  122. public function callDalleApi($prompt,$selectedOption)
  123. {
  124. if($selectedOption == 'dall-e-3'){
  125. $data = [
  126. 'prompt' => $prompt,
  127. 'model' => $selectedOption,
  128. 'n' => 1,
  129. 'size' => '1024x1024',
  130. 'quality' => 'standard',
  131. 'style' => 'vivid',
  132. 'response_format' => 'url',
  133. 'session_id' => null,
  134. 'context_reset' => true
  135. ];
  136. }else{
  137. $data = [
  138. 'prompt' => $prompt,
  139. 'model' => $selectedOption,
  140. 'n' => 1,
  141. 'size' => '1024x1024',
  142. 'quality' => 'hd',
  143. 'style' => 'vivid',
  144. 'response_format' => 'url',
  145. 'session_id' => null,
  146. 'context_reset' => true
  147. ];
  148. }
  149. return $this->callApi($this->config['txttoimg']['api_url'], $this->config['txttoimg']['api_key'], $data);
  150. }
  151. public function imgtoimgGptApi($prompt, $new_image_url)
  152. {
  153. $imgPath = ROOT_PATH . 'public/' . $new_image_url;
  154. if (!file_exists($imgPath)) {
  155. return ['code' => 1, 'msg' => '原图不存在:' . $new_image_url];
  156. }
  157. // 原图 base64 编码
  158. $imgData = file_get_contents($imgPath);
  159. $base64Img = base64_encode($imgData);
  160. $initImage = 'data:image/png;base64,' . $base64Img;
  161. // 构建 POST 请求参数
  162. $postData = json_encode([
  163. 'prompt' => $prompt,
  164. 'sampler_name' => 'DPM++ 2M SDE Heun',
  165. 'seed' => -1,
  166. 'steps' => 20,
  167. 'cfg_scale' => 7,
  168. 'denoising_strength' => 0.6,
  169. 'width' => 1024,
  170. 'height' => 2048,
  171. 'resize_mode' => 0,
  172. 'inpaint_full_res' => true,
  173. 'inpainting_fill' => 1,
  174. 'init_images' => [$initImage],
  175. 'override_settings' => [
  176. 'sd_model_checkpoint' => 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]',
  177. 'sd_vae' => 'anything-v4.5.vae.pt'
  178. ]
  179. ]);
  180. $apiUrl = "http://20.0.17.233:45001/sdapi/v1/img2img";
  181. $headers = ['Content-Type: application/json'];
  182. $ch = curl_init();
  183. curl_setopt($ch, CURLOPT_URL, $apiUrl);
  184. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  185. curl_setopt($ch, CURLOPT_POST, true);
  186. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  187. curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
  188. curl_setopt($ch, CURLOPT_TIMEOUT, 90);
  189. $response = curl_exec($ch);
  190. $error = curl_error($ch);
  191. curl_close($ch);
  192. if ($error) {
  193. return ['code' => 1, 'msg' => '请求失败:' . $error];
  194. }
  195. $data = json_decode($response, true);
  196. if (!isset($data['images'][0])) {
  197. return ['code' => 1, 'msg' => 'API未返回图像数据'];
  198. }
  199. return [
  200. 'code' => 0,
  201. 'msg' => '图像生成成功',
  202. 'data' => [
  203. 'url' => $data['images'][0]
  204. ]
  205. ];
  206. }
  207. /**
  208. * 通用 API 调用方法(支持重试机制)
  209. *
  210. * @param string $url 接口地址
  211. * @param string $apiKey 授权密钥(Bearer Token)
  212. * @param array $data 请求数据(JSON 格式)
  213. *
  214. * 功能说明:
  215. * - 使用 cURL 发送 POST 请求到指定 API 接口
  216. * - 设置请求头和超时时间等参数
  217. * - 支持最多重试 2 次,当接口调用失败时自动重试
  218. * - 返回成功时解析 JSON 响应为数组
  219. *
  220. * 异常处理:
  221. * - 若全部重试失败,将抛出异常并包含最后一次错误信息
  222. *
  223. * @return array 接口响应数据(成功时返回解析后的数组)
  224. * @throws \Exception 接口请求失败时抛出异常
  225. */
  226. public function callApi($url, $apiKey, $data)
  227. {
  228. $maxRetries = 2; // 最多重试次数
  229. $attempt = 0; // 当前尝试次数
  230. $lastError = ''; // 最后一次错误信息
  231. while ($attempt <= $maxRetries) {
  232. $ch = curl_init();
  233. curl_setopt_array($ch, [
  234. CURLOPT_URL => $url,
  235. CURLOPT_RETURNTRANSFER => true,
  236. CURLOPT_POST => true,
  237. CURLOPT_POSTFIELDS => json_encode($data),
  238. CURLOPT_HTTPHEADER => [
  239. 'Content-Type: application/json',
  240. 'Authorization: Bearer ' . $apiKey
  241. ],
  242. CURLOPT_TIMEOUT => 120,
  243. CURLOPT_SSL_VERIFYPEER => false,
  244. CURLOPT_SSL_VERIFYHOST => 0,
  245. CURLOPT_TCP_KEEPALIVE => 1,
  246. CURLOPT_FORBID_REUSE => false
  247. ]);
  248. $response = curl_exec($ch);
  249. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  250. $curlError = curl_error($ch);
  251. curl_close($ch);
  252. if ($response !== false && $httpCode === 200) {
  253. $result = json_decode($response, true);
  254. return $result;
  255. }
  256. $lastError = $curlError ?: "HTTP错误:{$httpCode}";
  257. $attempt++;
  258. sleep(1);
  259. }
  260. throw new \Exception("请求失败(重试{$maxRetries}次):{$lastError}");
  261. }
  262. }