| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- <?php
- namespace app\service;
- use think\Db;
- use think\Queue;
- class AIGatewayService{
- /**
- * 接口访问配置
- *
- * 配置说明:
- * - gpt:用于文本生成或图文识别模型接口(如 chat/completions)
- * OpenAI GPT 接口配置:支持 chat、图文结合模型(如 gpt-4-vision-preview)
- *
- * - dalle:用于文生图(图像生成)模型接口
- * OpenAI DALL·E 接口配置:用于文生图像(图像生成)
- *
- * 每个模块包含:
- * - api_key:API 调用密钥(Bearer Token)
- * - api_url:对应功能的服务端地址
- */
- protected $config = [
- 'gpt' => [
- 'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
- 'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
- ],
- 'dalle' => [
- 'api_key' => 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY',
- 'api_url' => 'https://niubi.zeabur.app/v1/images/generations'
- ]
- ];
- /**
- * 调用 GPT-4 图文识别模型接口(图生文)
- *
- * @param string $imageUrl 图像 URL,支持公网可访问地址
- * @param string $prompt 对图像的提问内容或提示文本
- *
- * 功能说明:
- * - 使用 OpenAI 的 gpt-4-vision-preview 模型对图片进行图文理解
- * - 支持图像与文本混合输入,返回图像内容相关的文本输出
- * - 限制最大 token 数为 1000
- *
- * 返回值:
- * - 返回调用 GPT API 后的响应结果(通常为模型生成的文本)
- */
- public function callGptApi($imageUrl, $prompt)
- {
- $data = [
- "model" => "gpt-4-vision-preview",
- "messages" => [[
- "role" => "user",
- "content" => [
- ["type" => "text", "text" => $prompt],
- ["type" => "image_url", "image_url" => [
- "url" => $imageUrl,
- "detail" => "auto"
- ]]
- ]
- ]],
- "max_tokens" => 1000
- ];
- return $this->callApi($this->config['gpt']['api_url'], $this->config['gpt']['api_key'], $data);
- }
- /**
- * 调用 GPT 文生文模型接口(文本生成)
- *
- * @param string $prompt 用户输入的文本提示内容
- *
- * 功能说明:
- * - 使用 OpenAI 的 GPT-4 模型,根据用户提供的 prompt 文本生成响应内容
- * - 支持上下文重置,确保每次调用为独立会话(无历史记忆)
- * - session_id 设为 null 表示不使用会话追踪
- *
- * 返回值:
- * - 返回调用 GPT 接口后的响应结果(通常为模型生成的文本)
- */
- public function txtGptApi($prompt)
- {
- $data = [
- 'prompt' => $prompt,
- 'model' => 'gpt-4',
- 'session_id' => null,
- 'context_reset' => true
- ];
- return $this->callApi(
- $this->config['gpt']['api_url'],
- $this->config['gpt']['api_key'],
- $data
- );
- }
- /**
- * 调用 DALL·E 图像生成接口(文生图)
- *
- * @param string $prompt 提示文本,用于指导图像生成
- * @param string $selectedOption 模型名称,例如 'dall-e-3' 或其他兼容模型
- *
- * 功能说明:
- * - 根据用户提供的文本提示,通过指定的模型生成图像
- * - 若选择模型为 'dall-e-3',使用标准质量(standard);其他模型使用高清质量(hd)
- * - 默认生成 1 张图像,尺寸为 1024x1024,风格为 vivid(生动)
- * - 返回的图像链接格式为 URL
- * - 每次调用为独立会话(session_id 为 null,context_reset 为 true)
- *
- * 返回值:
- * - 返回调用 DALL·E 接口后的响应结果(图像 URL)
- */
- public function callDalleApi($prompt,$selectedOption)
- {
- if($selectedOption == 'dall-e-3'){
- $data = [
- 'prompt' => $prompt,
- 'model' => $selectedOption,
- 'n' => 1,
- 'size' => '1024x1024',
- 'quality' => 'standard',
- 'style' => 'vivid',
- 'response_format' => 'url',
- 'session_id' => null,
- 'context_reset' => true
- ];
- }else{
- $data = [
- 'prompt' => $prompt,
- 'model' => $selectedOption,
- 'n' => 1,
- 'size' => '1024x1024',
- 'quality' => 'hd',
- 'style' => 'vivid',
- 'response_format' => 'url',
- 'session_id' => null,
- 'context_reset' => true
- ];
- }
- return $this->callApi($this->config['dalle']['api_url'], $this->config['dalle']['api_key'], $data);
- }
- /**
- * 通用 API 调用方法(支持重试机制)
- *
- * @param string $url 接口地址
- * @param string $apiKey 授权密钥(Bearer Token)
- * @param array $data 请求数据(JSON 格式)
- *
- * 功能说明:
- * - 使用 cURL 发送 POST 请求到指定 API 接口
- * - 设置请求头和超时时间等参数
- * - 支持最多重试 2 次,当接口调用失败时自动重试
- * - 返回成功时解析 JSON 响应为数组
- *
- * 异常处理:
- * - 若全部重试失败,将抛出异常并包含最后一次错误信息
- *
- * @return array 接口响应数据(成功时返回解析后的数组)
- * @throws \Exception 接口请求失败时抛出异常
- */
- public function callApi($url, $apiKey, $data)
- {
- $maxRetries = 2; // 最多重试次数
- $attempt = 0; // 当前尝试次数
- $lastError = ''; // 最后一次错误信息
- while ($attempt <= $maxRetries) {
- $ch = curl_init();
- curl_setopt_array($ch, [
- CURLOPT_URL => $url,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_POST => true,
- CURLOPT_POSTFIELDS => json_encode($data),
- CURLOPT_HTTPHEADER => [
- 'Content-Type: application/json',
- 'Authorization: Bearer ' . $apiKey
- ],
- CURLOPT_TIMEOUT => 120,
- CURLOPT_SSL_VERIFYPEER => false,
- CURLOPT_SSL_VERIFYHOST => 0,
- CURLOPT_TCP_KEEPALIVE => 1,
- CURLOPT_FORBID_REUSE => false
- ]);
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $curlError = curl_error($ch);
- curl_close($ch);
- if ($response !== false && $httpCode === 200) {
- $result = json_decode($response, true);
- return $result;
- }
- $lastError = $curlError ?: "HTTP错误:{$httpCode}";
- $attempt++;
- sleep(1);
- }
- throw new \Exception("请求失败(重试{$maxRetries}次):{$lastError}");
- }
- }
|