| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- <?php
- namespace app\api\controller;
- use app\common\controller\Api;
- use app\service\AIGatewayService;
- use think\Db;
- use think\Exception;
- /**
- * 首页接口
- */
- class Index extends Api
- {
- protected $noNeedLogin = ['*'];
- protected $noNeedRight = ['*'];
- /**
- * 首页
- */
- public function index()
- {
- $this->success('请求成功');
- }
- /**
- * 图生文接口
- */
- public function img_to_txt() {
- $params = $this->request->param();
- $prompt = trim($params['prompt']);
- $old_path = trim($params['path']);
- $model = trim($params['model']);
- $status_val = trim($params['status_val']);
- // 参数验证
- if (empty($prompt) || empty($old_path) || empty($model)) {
- return json([
- 'code' => 1,
- 'msg' => '缺少必要参数',
- 'data' => null
- ]);
- }
- $aiGateway = new AIGatewayService();
- // 获取图片的base64数据和MIME类型
- $imageData = AIGatewayService::file_get_contents($old_path);
- $base64Data = $imageData['base64Data'];
- $mimeType = $imageData['mimeType'];
- $formattedPrompt = "1. 输出语言:所有内容必须为纯简体中文,禁止出现任何英文、拼音、数字、注释、解释性文字、引导语、示例、标点外的特殊符号;
- 2. 第一步(提取原图产品):
- - 用1句完整中文描述原图产品,字数控制在50字以内;
- - 必须包含「主体细节、产品名称、商标、类型、颜色、风格」核心;
- 3. 第二步(生成新图提示词):
- - 仅替换【模板提示词】中「产品主体」相关内容为第一步的产品描述;
- - 严格保留模板中「设计风格、光影、背景、比例、排版」等非产品相关信息;
- - 完全排除模板中的标题类信息,仅保留提示词核心内容;
- - 替换后必须完全保留原图产品的核心特征,禁止修改模板非产品核心信息;
- 4. 输出格式:不允许添加任何解释、引导、说明、示例、备注,仅返回「产品描述 + 替换后提示词」,直接输出纯文本;
- 【模板提示词】{$prompt}";
- $result = $aiGateway->callGptApi($model, $formattedPrompt, $mimeType, $base64Data);
- // Gemini模型响应格式处理
- $imgToTxtContent = $result['candidates'][0]['content']['parts'][0]['text'];
- // // 图生文成功后,调用文生文功能(gemini-2.0-flash)
- $txtToTxtPrompt = "转换成中文格式,去掉其他特殊符号,不允许添加任何解释、引导、说明、示例等文字:\n\n{$imgToTxtContent}";
- $txtToTxtResult = $aiGateway->txtGptApi($txtToTxtPrompt, 'gemini-2.0-flash');
- $finalContent = $txtToTxtResult['candidates'][0]['content']['parts'][0]['text'];
- // 处理调试输出内容
- $debugContent = json_encode($finalContent, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
- // 去掉特殊符号(只保留字母、数字、中文、常用标点和换行)
- $debugContent = preg_replace('/[^\p{Han}\w\s\n\r\.,,。!!??\-\::;;]/u', '', $debugContent);
- // 去掉第一个冒号前的文字
- $debugContent = preg_replace('/^[^:]+:/', '', $debugContent);
- return json([
- 'code' => 0,
- 'msg' => '处理成功',
- 'data' => [
- 'content' => $debugContent,
- 'english_content' => $imgToTxtContent
- ]
- ]);
- }
- /**
- * 文生图接口
- */
- public function txt_to_img() {
- $params = $this->request->param();
- $prompt = trim($params['prompt']);
- $model = trim($params['model']);
- $status_val = trim($params['status_val']);
- $size = trim($params['size']);
- // 获取产品信息
- $product = Db::name('product')->where('id', 1)->find();
- if (empty($product)) {
- return json([
- 'code' => 1,
- 'msg' => '产品不存在',
- 'data' => null
- ]);
- }
- $product_code = $product['product_code'];
- $product_code_prefix = substr($product_code, 0, 9); // 前九位
- // 构建URL路径(使用正斜杠)
- $url_path = '/uploads/merchant/' . $product_code_prefix . '/' . $product_code . '/newimg/';
- // 构建物理路径(使用正斜杠确保统一格式)
- $save_path = ROOT_PATH . 'public' . '/' . 'uploads' . '/' . 'merchant' . '/' . $product_code_prefix . '/' . $product_code . '/' . 'newimg' . '/';
- // 移除ROOT_PATH中可能存在的反斜杠,确保统一使用正斜杠
- $save_path = str_replace('\\', '/', $save_path);
- // 自动创建文件夹(如果不存在)
- if (!is_dir($save_path)) {
- mkdir($save_path, 0755, true);
- }
- // 调用AI生成图片
- $aiGateway = new AIGatewayService();
- $res = $aiGateway->callDalleApi($prompt, $model, $size);
- // 提取base64图片数据
- if (isset($res['candidates'][0]['content']['parts'][0]['text'])) {
- $text_content = $res['candidates'][0]['content']['parts'][0]['text'];
- // 匹配base64图片数据
- preg_match('/data:image\/(png|jpg|jpeg);base64,([^"]+)/', $text_content, $matches);
- if (empty($matches)) {
- return json([
- 'code' => 1,
- 'msg' => '未找到图片数据',
- 'data' => null
- ]);
- }
- $image_type = $matches[1];
- $base64_data = $matches[2];
- // 解码base64数据
- $image_data = base64_decode($base64_data);
- if ($image_data === false) {
- return json([
- 'code' => 1,
- 'msg' => '图片解码失败',
- 'data' => null
- ]);
- }
- // 生成唯一文件名(包含扩展名)
- $file_name = uniqid() . '.' . $image_type;
- $full_file_path = $save_path . $file_name;
- // 保存图片到文件系统
- if (!file_put_contents($full_file_path, $image_data)) {
- return json([
- 'code' => 1,
- 'msg' => '图片保存失败',
- 'data' => null
- ]);
- }
- // 生成数据库存储路径(使用正斜杠格式)
- $db_img_path = $url_path . $file_name;
- Db::name('product')->where('id', 1)->update(['product_new_img' => $db_img_path]);
- return json([
- 'code' => 0,
- 'msg' => '文生图请求成功并保存图片',
- 'data' => [
- 'img' => $db_img_path,
- 'product_id' => 1
- ]
- ]);
- } else {
- return json([
- 'code' => 1,
- 'msg' => 'AI返回格式错误',
- 'data' => null
- ]);
- }
- }
- /**
- * 图生图本地测试
- */
- public function imgtowimg()
- {
- $prompt = $this->request->param('prompt', '');
- $imgRelPath = 'uploads/operate/ai/Preview/arr/0835006071623.png';
- $imgPath = ROOT_PATH . 'public/' . $imgRelPath;
- if (!file_exists($imgPath)) {
- return json(['code' => 1, 'msg' => '原图不存在:' . $imgRelPath]);
- }
- $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
- ]]
- ]
- ]
- ];
- $apiUrl = "http://20.0.17.188:45001/sdapi/v1/txt2img";
- $headers = ['Content-Type: application/json'];
- $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 json(['code' => 1, 'msg' => '请求失败:' . $error]);
- }
- $data = json_decode($response, true);
- if (!isset($data['images'][0])) {
- return json(['code' => 1, 'msg' => '接口未返回图像数据']);
- }
- $resultImg = base64_decode($data['images'][0]);
- $saveDir = ROOT_PATH . 'public/uploads/img2img/';
- if (!is_dir($saveDir)) {
- mkdir($saveDir, 0755, true);
- }
- $originalBaseName = pathinfo($imgRelPath, PATHINFO_FILENAME);
- $fileName = $originalBaseName . '-' . time() . '-1024x1248.png';
- $savePath = $saveDir . $fileName;
- file_put_contents($savePath, $resultImg);
- return json([
- 'code' => 0,
- 'msg' => '图像生成成功',
- 'data' => [
- 'origin_url' => '/uploads/img2img/' . $fileName
- ]
- ]);
- }
- /**
- * 后期图像处理-单张图片高清放大处理
- */
- public function extra_image()
- {
- // 配置参数
- $config = [
- 'input_dir' => 'uploads/img2img/',
- 'output_dir' => 'uploads/extra_image/',
- 'api_url' => 'http://20.0.17.188:45001/sdapi/v1/extra-single-image',
- 'timeout' => 120, // 增加超时时间,高清处理可能耗时较长
- 'upscale_params' => [
- '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,
- ]
- ];
- // 输入文件处理
- $imgRelPath = '0835006071623-1757406184-1024x1248.png';
- $imgPath = ROOT_PATH . 'public/' . $config['input_dir'] . $imgRelPath;
- if (!file_exists($imgPath)) {
- return json(['code' => 1, 'msg' => '原图不存在:' . $imgRelPath]);
- }
- // 读取并编码图片
- try {
- $imgData = file_get_contents($imgPath);
- if ($imgData === false) {
- throw new Exception('无法读取图片文件');
- }
- $base64Img = base64_encode($imgData);
- } catch (Exception $e) {
- return json(['code' => 1, 'msg' => '图片处理失败:' . $e->getMessage()]);
- }
- // 准备API请求数据
- $postData = array_merge($config['upscale_params'], ['image' => $base64Img]);
- $jsonData = json_encode($postData);
- if ($jsonData === false) {
- return json(['code' => 1, 'msg' => 'JSON编码失败']);
- }
- // 调用API进行高清放大
- $ch = curl_init();
- curl_setopt_array($ch, [
- CURLOPT_URL => $config['api_url'],
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_POST => true,
- CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
- CURLOPT_POSTFIELDS => $jsonData,
- CURLOPT_TIMEOUT => $config['timeout'],
- CURLOPT_CONNECTTIMEOUT => 30,
- ]);
- $response = curl_exec($ch);
- $error = curl_error($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
- if ($error) {
- return json(['code' => 1, 'msg' => 'API请求失败:' . $error]);
- }
- if ($httpCode !== 200) {
- return json(['code' => 1, 'msg' => 'API返回错误状态码:' . $httpCode]);
- }
- $data = json_decode($response, true);
- if (json_last_error() !== JSON_ERROR_NONE) {
- return json(['code' => 1, 'msg' => 'API返回数据解析失败']);
- }
- if (!isset($data['image']) || empty($data['image'])) {
- return json(['code' => 1, 'msg' => '接口未返回有效的图像数据']);
- }
- // 保存处理后的图片
- try {
- $resultImg = base64_decode($data['image']);
- if ($resultImg === false) {
- throw new Exception('Base64解码失败');
- }
- $saveDir = ROOT_PATH . 'public/' . $config['output_dir'];
- if (!is_dir($saveDir) && !mkdir($saveDir, 0755, true)) {
- throw new Exception('无法创建输出目录');
- }
- $originalBaseName = pathinfo($imgRelPath, PATHINFO_FILENAME);
- $fileName = $originalBaseName . '-hd.png'; // 使用-hd后缀更明确
- $savePath = $saveDir . $fileName;
- if (file_put_contents($savePath, $resultImg) === false) {
- throw new Exception('无法保存处理后的图片');
- }
- // 返回成功响应
- return json([
- 'code' => 0,
- 'msg' => '图像高清放大处理成功',
- 'data' => [
- 'url' => '/' . $config['output_dir'] . $fileName,
- 'original_size' => filesize($imgPath),
- 'processed_size' => filesize($savePath),
- 'resolution' => getimagesize($savePath), // 返回新图片的分辨率
- ]
- ]);
- } catch (Exception $e) {
- return json(['code' => 1, 'msg' => '保存结果失败:' . $e->getMessage()]);
- }
- }
- }
|