| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- <?php
- namespace app\service;
- use think\Db;
- use think\Queue;
- class AIGatewayService{
- /**
- * 接口访问配置
- *
- * 每个模块包含:
- * - api_key:API 调用密钥(Token)
- * - api_url:对应功能的服务端地址
- */
- protected $config = [
- //图生文-gemini-2.5-flash-preview
- 'imgtotxt' => [
- 'api_key' => 'sk-LVcDfTx5SYK6pWiGpfcAN2KA0LunymnMiYSVfzUKQXrjlkZv',
- 'api_url' => 'https://chatapi.onechats.top/v1/chat/completions'
- ],
- //文生文-gtp-4
- 'txttotxtgtp' => [
- 'api_key' => 'sk-fxlawqVtbbQbNW0wInR3E4wsLo5JHozDC2XOHzMa711su6ss',
- 'api_url' => 'https://chatapi.onechats.top/v1/chat/completions'
- ],
- //文生文-gemini-2.0-flash
- 'txttotxtgemini' => [
- 'api_key' => 'sk-cqfCZFiiSIdpDjIHLMBbH6uWfeg7iVsASvlubjrNEmfUXbpX',
- 'api_url' => 'https://chatapi.onechats.top/v1/chat/completions'
- ],
- //文生图-dall-e-3
- 'txttoimg' => [
- // 'api_key' => 'sk-MB6SR8qNaTjO80U7HJl4ztivX3zQKPgKVka9oyfVSXIkHSYZ',
- 'api_key' => 'sk-iURfrAgzAjhZ4PpPLwzmWIAhM7zKfrkwDvyxk4RVBQ4ouJNK',
- 'api_url' => 'https://chatapi.onechats.ai/v1/images/generations'
- ],
- 'submitimage' => [
- 'api_key' => 'sk-iURfrAgzAjhZ4PpPLwzmWIAhM7zKfrkwDvyxk4RVBQ4ouJNK',
- 'api_url' => 'https://chatapi.onechats.ai/mj/submit/imagine'
- ]
- ];
- /**
- * 图生文
- * @param string $imageUrl 图像 URL,支持公网可访问地址
- * @param string $prompt 对图像的提问内容或提示文本
- */
- public function callGptApi($imageUrl, $prompt,$imgtotxt_selectedOption)
- {
- //方式一
- $data = [
- "model" => $imgtotxt_selectedOption,
- "messages" => [[
- "role" => "user",
- "content" => [
- ["type" => "text", "text" => $prompt],
- ["type" => "image_url", "image_url" => [
- "url" => $imageUrl,
- "detail" => "auto"
- ]]
- ]
- ]],
- "max_tokens" => 1000
- ];
- //方式二
- // $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['imgtotxt']['api_url'], $this->config['imgtotxt']['api_key'], $data);
- }
- /**
- * 文生文
- * @param string $prompt 用户输入的文本提示内容
- */
- public function txtGptApi($prompt,$txttotxt_selectedOption)
- {
- if (empty($prompt)) {
- throw new \Exception("Prompt 不允许为空");
- }
- //判断使用模型
- if ($txttotxt_selectedOption === 'gemini-2.0-flash') {
- $data = [
- 'model' => 'gemini-2.0-flash',
- 'messages' => [
- ['role' => 'user', 'content' => $prompt]
- ],
- 'temperature' => 0.7,
- 'max_tokens' => 1024
- ];
- return $this->callApi(
- $this->config['txttotxtgemini']['api_url'],
- $this->config['txttotxtgemini']['api_key'],
- $data
- );
- }else if ($txttotxt_selectedOption === 'gpt-4') {
- $data = [
- 'model' => 'gpt-4',
- 'messages' => [
- ['role' => 'user', 'content' => $prompt]
- ],
- 'temperature' => 0.7,
- 'max_tokens' => 1024
- ];
- return $this->callApi(
- $this->config['txttotxtgtp']['api_url'],
- $this->config['txttotxtgtp']['api_key'],
- $data
- );
- }
- }
- /**
- * 文生图
- *
- * @param string $prompt 提示文本,用于指导图像生成(最长建议 1000 字符)
- * @param string $selectedOption 模型名称,例如 'dall-e-3' 或其他兼容模型
- *
- * 默认参数说明(适用于所有模型):
- * - n: 1(生成 1 张图)
- * - size: '1024x1024'(标准正方形图像)
- * - quality: 'hd'(高清质量)
- * - style: 'vivid'(鲜明风格)
- *
- * response_format 参数差异:
- * - 若模型为 'dall-e-3':返回 base64 图像,字段为 `b64_json`
- * - 其他模型默认返回图像 URL,字段为 `url`
- *
- * ⚠️ 注意:使用此方法后,需在 Job/TextToImageJob.php 中按 response_format 判断提取方式:
- * 提取 url 图像
- * $base64Image = $dalle1024['data'][0]['url'] ?? null;
- * 提取 base64 图像
- * $base64Image = $dalle1024['data'][0]['b64_json'] ?? null;
- *
- * @return array 返回接口响应,成功时包含 'data' 字段,失败时包含 'error' 信息
- */
- public function callDalleApi($prompt, $selectedOption)
- {
- if ($selectedOption === 'dall-e-3') {
- $data = [
- 'prompt' => $prompt,
- 'model' => $selectedOption,
- 'n' => 1,
- 'size' => '1024x1024',
- 'quality' => 'hd',
- 'style' => 'vivid',
- 'response_format' => 'url',
- ];
- return $this->callApi($this->config['txttoimg']['api_url'],$this->config['txttoimg']['api_key'],$data);
- } else if ($selectedOption === 'black-forest-labs/FLUX.1-kontext-pro') {
- $data = [
- 'prompt' => $prompt,
- 'model' => $selectedOption,
- 'n' => 1,
- 'size' => '1024x1024',
- 'quality' => 'hd',
- 'style' => 'vivid',
- 'response_format' => 'url',
- ];
- return $this->callApi($this->config['txttoimg']['api_url'],$this->config['txttoimg']['api_key'],$data);
- } else if ($selectedOption === 'gpt-image-1') {
- $data = [
- 'prompt' => $prompt,
- 'model' => $selectedOption,
- 'n' => 1,
- 'size' => '1024x1024',
- 'quality' => 'hd',
- 'style' => 'vivid',
- 'response_format' => 'url',
- ];
- return $this->callApi($this->config['txttoimg']['api_url'],$this->config['txttoimg']['api_key'],$data);
- } else if ($selectedOption === 'MID_JOURNEY') {
- $data = [
- 'botType' => $selectedOption,
- 'prompt' => $prompt,
- 'base64Array' => [],
- 'accountFilter' => [
- 'channelId' => "",
- 'instanceId' => "",
- 'modes' => [],
- 'remark' => "",
- 'remix' => true,
- 'remixAutoConsidered' => true
- ],
- 'notifyHook' => "",
- 'state' => ""
- ];
- return $this->callApi($this->config['submitimage']['api_url'],$this->config['submitimage']['api_key'],$data);
- }else{
- echo '其他文生图模型参数配置';
- }
- }
- /**
- * 图生图
- * @param string $prompt 用户输入的文本提示内容
- * @param string $new_image_url 原图路径
- * @param array $options 可选参数,可覆盖默认配置
- * @return array
- */
- public function txt2imgWithControlNet($prompt, $controlImgUrl, $options = []) {
- $apiUrl = "http://20.0.17.188:45001/sdapi/v1/txt2img";
- $headers = ['Content-Type: application/json'];
- $imgPath = ROOT_PATH . 'public/' . ltrim($controlImgUrl, '/');
- if (!file_exists($imgPath)) {
- return ['code' => 1, 'msg' => '图片不存在:' . $controlImgUrl];
- }
- $imgData = file_get_contents($imgPath);
- $base64Img = 'data:image/png;base64,' . base64_encode($imgData);
- $params = [
- 'prompt' => $prompt,
- 'negative_prompt' => '(deformed, distorted, disfigured:1.3), poorly drawn, bad anatomy',
- 'steps' => 20,
- 'sampler_name' => 'DPM++ 2M SDE',
- 'cfg_scale' => 7,
- 'seed' => -1,
- 'width' => 1024,
- 'height' => 1303,
- 'override_settings' => [
- 'sd_model_checkpoint' => 'realisticVisionV51_v51VAE-inpainting',
- 'sd_vae' => 'vae-ft-mse-840000-ema-pruned',
- 'CLIP_stop_at_last_layers' => 2
- ],
- 'clip_skip' => 2,
- 'alwayson_scripts' => [
- 'controlnet' => [
- 'args' => [[
- 'enabled' => true,
- 'input_image' => $base64Img,
- 'module' => 'inpaint_only+lama',
- 'model' => 'control_v11p_sd15_inpaint_fp16 [be8bc0ed]',
- 'weight' => 1,
- 'resize_mode' => 'Resize and Fill',
- 'pixel_perfect' => false,
- 'control_mode' => 'ControlNet is more important',
- 'starting_control_step' => 0,
- 'ending_control_step' => 1
- ]]
- ]
- ]
- ];
- if (!empty($options)) {
- $params = array_merge($params, $options);
- }
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $apiUrl);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params, JSON_UNESCAPED_UNICODE));
- curl_setopt($ch, CURLOPT_TIMEOUT, 180);
- $response = curl_exec($ch);
- $error = curl_error($ch);
- curl_close($ch);
- if ($error) {
- return ['code' => 1, 'msg' => '请求失败:' . $error];
- }
- $data = json_decode($response, true);
- if (!isset($data['images'][0])) {
- return ['code' => 1, 'msg' => '接口未返回图像数据'];
- }
- return [
- 'code' => 0,
- 'msg' => '成功',
- 'data' => [
- 'base64' => $data['images'][0],
- 'info' => $data['info'] ?? ''
- ]
- ];
- }
- // 第一阶段:图生图
- public function upscaleWithImg2Img($prompt, $imgPath)
- {
- if (!file_exists($imgPath)) {
- return ['code' => 1, 'msg' => '原图不存在:' . $imgPath];
- }
- // 获取原始图像尺寸
- [$origWidth, $origHeight] = getimagesize($imgPath);
- if (!$origWidth || !$origHeight) {
- return ['code' => 1, 'msg' => '无法识别图片尺寸'];
- }
- // 按2倍尺寸计算目标大小
- $targetWidth = $origWidth * 2;
- $targetHeight = $origHeight * 2;
- // 编码图像为 base64
- $imgData = file_get_contents($imgPath);
- $base64Img = 'data:image/png;base64,' . base64_encode($imgData);
- // 构造参数
- $params = [
- 'init_images' => [$base64Img],
- 'prompt' => $prompt,
- 'steps' => 20,
- 'sampler_name' => 'DPM++ 2M SDE Heun',
- 'cfg_scale' => 7,
- 'seed' => 1669863506,
- 'width' => $targetWidth,
- 'height' => $targetHeight,
- 'denoising_strength' => 0.2,
- 'clip_skip' => 2,
- 'override_settings' => [
- 'sd_model_checkpoint' => 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]',
- 'sd_vae' => 'vae-ft-mse-840000-ema-pruned.safetensors',
- 'CLIP_stop_at_last_layers' => 2
- ],
- 'override_settings_restore_afterwards' => true
- ];
- $apiUrl = "http://20.0.17.188:45001/sdapi/v1/img2img";
- $headers = ['Content-Type: application/json'];
- // 发起请求
- $ch = curl_init();
- curl_setopt_array($ch, [
- CURLOPT_URL => $apiUrl,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_POST => true,
- CURLOPT_HTTPHEADER => $headers,
- CURLOPT_POSTFIELDS => json_encode($params),
- CURLOPT_TIMEOUT => 180
- ]);
- $response = curl_exec($ch);
- $error = curl_error($ch);
- curl_close($ch);
- if ($error) return ['code' => 1, 'msg' => '图生图请求失败:' . $error];
- $data = json_decode($response, true);
- if (!isset($data['images'][0])) return ['code' => 1, 'msg' => '图生图接口未返回图像'];
- return ['code' => 0, 'data' => ['base64' => $data['images'][0]]];
- }
- // 第二阶段:高清超分
- public function imgtogqGptApi($imageRelPath, $options = [])
- {
- $imgPath = ROOT_PATH . 'public/' . $imageRelPath;
- if (!file_exists($imgPath)) {
- return ['code' => 1, 'msg' => '原图不存在:' . $imageRelPath];
- }
- $defaultParams = [
- 'resize_mode' => 0,
- 'show_extras_results' => true,
- 'gfpgan_visibility' => 0,
- 'codeformer_visibility' => 0,
- 'codeformer_weight' => 0,
- 'upscaling_resize' => 1.62,
- 'upscaling_crop' => true,
- 'upscaler_1' => 'R-ESRGAN 4x+ Anime6B',
- 'upscaler_2' => 'None',
- 'extras_upscaler_2_visibility' => 0,
- 'upscale_first' => false
- ];
- $params = array_merge($defaultParams, $options);
- try {
- $imgData = file_get_contents($imgPath);
- if ($imgData === false) {
- throw new Exception('无法读取图片文件');
- }
- $params['image'] = base64_encode($imgData);
- } catch (Exception $e) {
- return ['code' => 1, 'msg' => '图片读取失败:' . $e->getMessage()];
- }
- $apiUrl = "http://20.0.17.188:45001/sdapi/v1/extra-single-image";
- $headers = ['Content-Type: application/json'];
- $ch = curl_init();
- curl_setopt_array($ch, [
- CURLOPT_URL => $apiUrl,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_POST => true,
- CURLOPT_HTTPHEADER => $headers,
- CURLOPT_POSTFIELDS => json_encode($params),
- CURLOPT_TIMEOUT => 120
- ]);
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $curlErr = curl_error($ch);
- curl_close($ch);
- if ($curlErr) {
- return ['code' => 1, 'msg' => '请求失败:' . $curlErr];
- }
- if ($httpCode !== 200) {
- return ['code' => 1, 'msg' => 'API请求失败,HTTP状态码:' . $httpCode];
- }
- $data = json_decode($response, true);
- if (json_last_error() !== JSON_ERROR_NONE) {
- return ['code' => 1, 'msg' => 'API返回数据解析失败:' . json_last_error_msg()];
- }
- if (empty($data['image'])) {
- return ['code' => 1, 'msg' => '接口未返回有效的图像数据'];
- }
- return [
- 'code' => 0,
- 'msg' => '高清图生成成功',
- 'data' => [
- 'base64_image' => $data['image'],
- 'original_size' => strlen($imgData),
- 'processed_size' => strlen(base64_decode($data['image']))
- ]
- ];
- }
- // public function imgtogqGptApi($imageRelPath, $options = [])
- // {
- // // 构造图片路径
- // $imgPath = ROOT_PATH . 'public/' . $imageRelPath;
- //
- // if (!file_exists($imgPath)) {
- // return ['code' => 1, 'msg' => '原图不存在:' . $imageRelPath];
- // }
- //
- // // 默认放大配置
- // $defaultParams = [
- // 'resize_mode' => 0,
- // 'show_extras_results' => true,
- // 'gfpgan_visibility' => 0,
- // 'codeformer_visibility' => 0,
- // 'codeformer_weight' => 0,
- // 'upscaling_resize' => 2.45,
- // 'upscaling_crop' => true,
- // 'upscaler_1' => 'R-ESRGAN 4x+ Anime6B',
- // 'upscaler_2' => 'None',
- // 'extras_upscaler_2_visibility' => 0,
- // 'upscale_first' => false
- // ];
- //
- // // 合并配置参数
- // $params = array_merge($defaultParams, $options);
- //
- // // 编码原始图片
- // try {
- // $imgData = file_get_contents($imgPath);
- // if ($imgData === false) {
- // throw new Exception('无法读取图片文件');
- // }
- // $params['image'] = base64_encode($imgData);
- // } catch (Exception $e) {
- // return ['code' => 1, 'msg' => '图片读取失败:' . $e->getMessage()];
- // }
- //
- // $apiUrl = "http://20.0.17.188:45001/sdapi/v1/extra-single-image";
- // $headers = ['Content-Type: application/json'];
- //
- // // 调用接口
- // $ch = curl_init();
- // curl_setopt_array($ch, [
- // CURLOPT_URL => $apiUrl,
- // CURLOPT_RETURNTRANSFER => true,
- // CURLOPT_POST => true,
- // CURLOPT_HTTPHEADER => $headers,
- // CURLOPT_POSTFIELDS => json_encode($params),
- // CURLOPT_TIMEOUT => 120
- // ]);
- //
- // $response = curl_exec($ch);
- // $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- // $curlErr = curl_error($ch);
- // curl_close($ch);
- //
- // // 网络请求失败
- // if ($curlErr) {
- // return ['code' => 1, 'msg' => '请求失败:' . $curlErr];
- // }
- //
- // // 状态码错误
- // if ($httpCode !== 200) {
- // return ['code' => 1, 'msg' => 'API请求失败,HTTP状态码:' . $httpCode];
- // }
- //
- // // 解析响应
- // $data = json_decode($response, true);
- // if (json_last_error() !== JSON_ERROR_NONE) {
- // return ['code' => 1, 'msg' => 'API返回数据解析失败:' . json_last_error_msg()];
- // }
- //
- // if (empty($data['image'])) {
- // return ['code' => 1, 'msg' => '接口未返回有效的图像数据'];
- // }
- //
- // // 保存新图片
- // try {
- // $baseName = pathinfo($imageRelPath, PATHINFO_FILENAME);
- // $ext = pathinfo($imageRelPath, PATHINFO_EXTENSION);
- // $outputDir = 'uploads/extra_image/';
- // $outputPath = ROOT_PATH . 'public/' . $outputDir;
- //
- // if (!is_dir($outputPath)) {
- // mkdir($outputPath, 0755, true);
- // }
- //
- // $saveFileName = $baseName . '-hd.' . $ext;
- // $saveFullPath = $outputPath . $saveFileName;
- // $resultImg = base64_decode($data['image']);
- //
- // if ($resultImg === false || file_put_contents($saveFullPath, $resultImg) === false) {
- // throw new Exception('保存图片失败');
- // }
- //
- // return [
- // 'code' => 0,
- // 'msg' => '高清图生成成功',
- // 'data' => [
- // 'url' => '/' . $outputDir . $saveFileName,
- // 'original_size' => filesize($imgPath),
- // 'processed_size' => filesize($saveFullPath),
- // 'resolution' => getimagesize($saveFullPath)
- // ]
- // ];
- // } catch (Exception $e) {
- // return ['code' => 1, 'msg' => '保存失败:' . $e->getMessage()];
- // }
- // }
- /**
- * 通用 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 = '';
- $httpCode = 0;
- $apiErrorDetail = '';
- while ($attempt <= $maxRetries) {
- try {
- $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 => true,
- CURLOPT_SSL_VERIFYHOST => 2,
- CURLOPT_CONNECTTIMEOUT => 30,
- CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
- CURLOPT_FAILONERROR => true
- ]);
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $curlError = curl_error($ch);
- if ($response === false) {
- throw new \Exception("请求发送失败: " . $curlError);
- }
- $result = json_decode($response, true);
- // 检查API返回的错误
- if (isset($result['error'])) {
- $apiErrorDetail = $result['error']['message'] ?? '';
- $errorType = $result['error']['type'] ?? '';
- // 常见错误类型映射
- $errorMessages = [
- 'invalid_request_error' => '请求参数错误',
- 'authentication_error' => '认证失败',
- 'rate_limit_error' => '请求频率过高',
- 'insufficient_quota' => '额度不足',
- 'billing_not_active' => '账户未开通付费',
- 'content_policy_violation' => '内容违反政策'
- ];
- $friendlyMessage = $errorMessages[$errorType] ?? 'API服务错误';
- throw new \Exception("{$friendlyMessage}: {$apiErrorDetail}");
- }
- if ($httpCode !== 200) {
- // HTTP状态码映射
- $statusMessages = [
- 400 => '请求参数不合法',
- 401 => 'API密钥无效或权限不足',
- 403 => '访问被拒绝',
- 404 => 'API端点不存在',
- 429 => '请求过于频繁,请稍后再试',
- 500 => '服务器内部错误',
- 503 => '服务暂时不可用'
- ];
- $statusMessage = $statusMessages[$httpCode] ?? "HTTP错误({$httpCode})";
- throw new \Exception($statusMessage);
- }
- curl_close($ch);
- return $result;
- } catch (\Exception $e) {
- $lastError = $e->getMessage();
- $attempt++;
- if ($attempt <= $maxRetries) {
- sleep(pow(2, $attempt));
- } else {
- // 最终失败时的详细错误信息
- $errorDetails = [
- '错误原因' => $this->getErrorCause($httpCode, $apiErrorDetail),
- '解决方案' => $this->getErrorSolution($httpCode),
- '请求参数' => json_encode($data, JSON_UNESCAPED_UNICODE),
- 'HTTP状态码' => $httpCode,
- '重试次数' => $attempt
- ];
- throw new \Exception("API请求失败\n" .
- "失败说明: " . $errorDetails['错误原因'] . "\n" .
- "建议解决方案: " . $errorDetails['解决方案'] . "\n" .
- "技术详情: HTTP {$httpCode} - " . $lastError);
- }
- }
- }
- }
- /**
- * 根据错误类型获取友好的错误原因
- */
- private function getErrorCause($httpCode, $apiError)
- {
- $causes = [
- 401 => 'API密钥无效、过期或没有访问权限',
- 400 => $apiError ?: '请求参数不符合API要求',
- 429 => '已达到API调用频率限制',
- 403 => '您的账户可能没有开通相关服务权限',
- 500 => 'OpenAI服务器处理请求时出错'
- ];
- return $causes[$httpCode] ?? '未知错误,请检查网络连接和API配置';
- }
- /**
- * 根据错误类型获取解决方案建议
- */
- private function getErrorSolution($httpCode)
- {
- $solutions = [
- 401 => '1. 检查API密钥是否正确 2. 确认密钥是否有访问权限 3. 尝试创建新密钥',
- 400 => '1. 检查请求参数 2. 验证提示词内容 3. 参考API文档修正参数',
- 429 => '1. 等待1分钟后重试 2. 升级账户提高限额 3. 优化调用频率',
- 403 => '1. 检查账户状态 2. 确认是否已开通付费 3. 联系OpenAI支持',
- 500 => '1. 等待几分钟后重试 2. 检查OpenAI服务状态页'
- ];
- return $solutions[$httpCode] ?? '1. 检查网络连接 2. 查看服务日志 3. 联系技术支持';
- }
- }
|