apiUrl = Env::get('doubaoAi.api_url'); $this->apiKey = Env::get('doubaoAi.api_key'); // 设置请求头 $this->headers = [ 'Content-Type: application/json', 'Authorization: Bearer ' . $this->apiKey ]; if (empty($this->apiKey) || empty($this->apiUrl)) { return json_encode(['code' => 500, 'msg' => '参数缺失']); } } public function text($params = []) { if (empty($params)){ $content = $this->request->param('content', ''); $model = $this->request->param('model', 'doubao-seed-1-8-251215'); if(empty($content)){ return json_encode(['code' => 500, 'msg' => '提示词缺失']); } $params = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => '你现在是存客宝的AI助理,你精通中国大陆的法律'], ['role' => 'user', 'content' => $content], ], ]; } $result = requestCurl($this->apiUrl.'/api/v3/chat/completions', $params, 'POST', $this->headers, 'json'); $result = json_decode($result, true); if(isset($result['error'])){ $error = $result['error']; return json_encode(['code' => 500, 'msg' => $error['message']]); }else{ $content = $result['choices'][0]['message']['content']; $token = intval($result['usage']['total_tokens']) * 20; exit_data($content); return json_encode(['code' => 200, 'msg' => '成功','data' => ['token' => $token,'content' => $content]]); } } /** * 图片生成功能(基于火山方舟 Seedream 4.0-4.5 API) * 参考文档:https://www.volcengine.com/docs/82379/1541523?lang=zh * * @param array $params 请求参数,如果为空则从请求中获取 * @return string JSON格式的响应 */ public function image($params = []) { try { // 如果参数为空,从请求中获取 if (empty($params)){ $content = $this->request->param('content', ''); $model = $this->request->param('model', 'doubao-seedream-4-5-251128'); $size = $this->request->param('size', '16:9'); // 支持档位(1K/2K/4K)、比例(16:9/9:16等)、像素(1280x720等) $responseFormat = $this->request->param('response_format', 'url'); // url 或 b64_json $sequentialImageGeneration = $this->request->param('sequential_image_generation', 'disabled'); // enabled 或 disabled $watermark = $this->request->param('watermark', true); // true 或 false // 参数验证 if(empty($content)){ return json_encode(['code' => 500, 'msg' => '提示词(prompt)不能为空']); } // 验证和规范化尺寸参数 $size = $this->validateAndNormalizeSize($size); if(!in_array($responseFormat, ['url', 'b64_json'])){ $responseFormat = 'url'; } if(!in_array($sequentialImageGeneration, ['enabled', 'disabled'])){ $sequentialImageGeneration = 'disabled'; } // 构建请求参数(根据火山方舟文档) $params = [ 'model' => $model, 'prompt' => $content, 'sequential_image_generation' => $sequentialImageGeneration, 'response_format' => $responseFormat, 'size' => $size, 'stream' => false, 'watermark' => true ]; } // 确保API URL正确(图片生成API的endpoint) $imageApiUrl = $this->apiUrl. '/api/v3/images/generations'; // 发送请求 $result = requestCurl($imageApiUrl, $params, 'POST', $this->headers, 'json'); $result = json_decode($result, true); // 错误处理 if(isset($result['error'])){ $error = $result['error']; $errorMsg = isset($error['message']) ? $error['message'] : '图片生成失败'; $errorCode = isset($error['code']) ? $error['code'] : 'unknown'; \think\facade\Log::error('火山方舟图片生成失败', [ 'error' => $error, 'params' => $params ]); return json_encode([ 'code' => 500, 'msg' => $errorMsg, 'error_code' => $errorCode ]); } // 成功响应处理(根据火山方舟文档的响应格式) if(isset($result['data']) && is_array($result['data']) && !empty($result['data'])){ $imageData = $result['data'][0]; // 根据 response_format 获取图片数据 $imageUrl = null; $imageB64 = null; if(isset($imageData['url'])){ $imageUrl = $imageData['url']; } if(isset($imageData['b64_json'])){ $imageB64 = $imageData['b64_json']; } // 计算token(如果有usage信息) $token = 0; if(isset($result['usage']['total_tokens'])){ $token = intval($result['usage']['total_tokens']) * 20; } // 构建返回数据 $responseData = [ 'token' => $token, 'image_url' => $imageUrl, 'image_b64' => $imageB64, 'model' => $params['model'] ?? '', 'size' => $params['size'] ?? '2K', 'created' => isset($result['created']) ? $result['created'] : time() ]; // 根据请求的response_format返回对应的数据 if($params['response_format'] == 'url' && $imageUrl){ $responseData['content'] = $imageUrl; } elseif($params['response_format'] == 'b64_json' && $imageB64){ $responseData['content'] = $imageB64; } return json_encode([ 'code' => 200, 'msg' => '图片生成成功', 'data' => $responseData ]); } else { // 响应格式不符合预期 \think\facade\Log::warning('火山方舟图片生成响应格式异常', [ 'result' => $result, 'params' => $params ]); return json_encode([ 'code' => 500, 'msg' => '图片生成响应格式异常', 'raw_response' => $result ]); } } catch (\Exception $e) { \think\facade\Log::error('火山方舟图片生成异常', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return json_encode([ 'code' => 500, 'msg' => '图片生成异常:' . $e->getMessage() ]); } } /** * 验证和规范化尺寸参数 * 支持三种格式: * 1. 档位形式:1K, 2K, 4K(不区分大小写) * 2. 比例形式:16:9, 9:16, 1:1, 4:3, 3:4 等 * 3. 像素形式:1280x720, 2048x2048 等(宽度1280-4096,高度720-4096,宽高比0.0625-16) * * @param string $size 尺寸参数 * @return string 规范化后的尺寸值 */ private function validateAndNormalizeSize($size) { if (empty($size)) { return '2K'; } $size = trim($size); // 1. 检查是否为档位形式(1K, 2K, 4K) $sizeUpper = strtoupper($size); if (in_array($sizeUpper, ['1K', '2K', '4K'])) { return $sizeUpper; } // 2. 检查是否为比例形式(如 16:9, 9:16, 1:1) if (preg_match('/^(\d+):(\d+)$/', $size, $matches)) { $width = intval($matches[1]); $height = intval($matches[2]); if ($width > 0 && $height > 0) { $ratio = $width / $height; // 验证宽高比范围:0.0625 ~ 16 if ($ratio >= 0.0625 && $ratio <= 16) { return $size; // 返回比例形式,如 "16:9" } } } // 3. 检查是否为像素形式(如 1280x720, 2048x2048) if (preg_match('/^(\d+)x(\d+)$/i', $size, $matches)) { $width = intval($matches[1]); $height = intval($matches[2]); // 验证宽度范围:1280 ~ 4096 if ($width < 1280 || $width > 4096) { return '2K'; // 默认返回 2K } // 验证高度范围:720 ~ 4096 if ($height < 720 || $height > 4096) { return '2K'; // 默认返回 2K } // 验证宽高比范围:0.0625 ~ 16 $ratio = $width / $height; if ($ratio < 0.0625 || $ratio > 16) { return '2K'; // 默认返回 2K } return $size; // 返回像素形式,如 "1280x720" } // 如果都不匹配,返回默认值 return '2K'; } }