|
|
@@ -27,34 +27,21 @@ class WorkOrder extends Api
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * 图生图功能 - /sdapi/v1/img2img
|
|
|
+ * 图生图功能-单张图片本地测试使用
|
|
|
+ * 接口地址: /sdapi/v1/img2img
|
|
|
*/
|
|
|
public function imgtowimg()
|
|
|
{
|
|
|
- $prompt = $this->request->param('prompt', ''); // 用户传入的提示词
|
|
|
-// $imgRelPath = 'uploads/operate/ai/Preview/arr/0828004096727.png';
|
|
|
-// $imgRelPath = 'uploads/operate/ai/Preview/arr/1751019283787.jpg';
|
|
|
- $imgRelPath = 'uploads/operate/ai/Preview/arr/圣诞主题复古油画圣诞老人和孩子们乘坐红色雪橇在雪地中滑行充满.png';
|
|
|
+ $prompt = $this->request->param('prompt', '将图片不完整部分补充完整');
|
|
|
+ $imgRelPath = 'uploads/operate/ai/Preview/arr/一朵盛开的白色牡丹花为主体采用厚涂技法花心和背景点缀金箔灰银.png';
|
|
|
$imgPath = ROOT_PATH . 'public/' . $imgRelPath;
|
|
|
-
|
|
|
- // 校验原图是否存在
|
|
|
+ //原图是否存在
|
|
|
if (!file_exists($imgPath)) {
|
|
|
return json(['code' => 1, 'msg' => '原图不存在:' . $imgRelPath]);
|
|
|
}
|
|
|
|
|
|
- // -------- 参数调整 -------- //
|
|
|
- $denoising = 0.2; // 降低重绘幅度
|
|
|
- $steps = 10; // 减少迭代步数
|
|
|
- $cfgScale = 7;
|
|
|
- $clipSkip = 7;
|
|
|
- $sampler = 'DPM++ 2M SDE Heun';
|
|
|
- $modelName = 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]';
|
|
|
- $vaeName = 'anything-v4.5.vae.pt';
|
|
|
- $seed = 611075477;
|
|
|
- $targetW = 679; // 目标宽度
|
|
|
- $targetH = 862; // 目标高度
|
|
|
-
|
|
|
// -------- 图像编码 -------- //
|
|
|
$imgData = file_get_contents($imgPath);
|
|
|
$base64Img = base64_encode($imgData);
|
|
|
@@ -63,21 +50,24 @@ class WorkOrder extends Api
|
|
|
// -------- 请求体构建 -------- //
|
|
|
$postData = json_encode([
|
|
|
'prompt' => $prompt,
|
|
|
- 'steps' => $steps,
|
|
|
- 'cfg_scale' => $cfgScale,
|
|
|
- 'denoising_strength' => $denoising,
|
|
|
- 'width' => $targetW,
|
|
|
- 'height' => $targetH,
|
|
|
- 'resize_mode' => 0,
|
|
|
- 'sampler_name' => $sampler,
|
|
|
- 'seed' => $seed,
|
|
|
- 'inpaint_full_res' => true, // 关闭高分辨率重绘
|
|
|
- 'inpainting_fill' => 1,
|
|
|
- 'init_images' => [$initImage],
|
|
|
+ 'steps' => 30, // 步数
|
|
|
+ 'cfg_scale' => 7, // CFG 强度
|
|
|
+ 'denoising_strength' => 0.2, // 重绘强度
|
|
|
+ 'width' => 679, // 图像宽度
|
|
|
+ 'height' => 862, // 图像高度
|
|
|
+ 'resize_mode' => 1, // 保留原图比例并裁剪
|
|
|
+ 'inpaint_full_res' => true, // 使用原图分辨率
|
|
|
+ 'inpaint_full_res_padding' => 64, // 边缘补全像素
|
|
|
+ 'mask_blur' => 4, // 蒙版柔化
|
|
|
+ 'inpainting_fill' => 3, // 自动填充内容(不是黑色)
|
|
|
+ 'sampler_name' => 'DPM++ 2M SDE', // 采样器
|
|
|
+ 'scheduler' => 'Exponential', // ✅ 调度类型(补充字段)
|
|
|
+ 'seed' => 3689437019, // 固定种子(确保结果可复现)
|
|
|
+ 'init_images' => [$initImage], // 原图 base64
|
|
|
'override_settings' => [
|
|
|
- 'sd_model_checkpoint' => $modelName,
|
|
|
- 'sd_vae' => $vaeName,
|
|
|
- 'CLIP_stop_at_last_layers' => $clipSkip
|
|
|
+ 'sd_model_checkpoint' => 'AbyssOrangeMix2_sfw', // 模型名
|
|
|
+ 'sd_vae' => "Automatic",
|
|
|
+ 'CLIP_stop_at_last_layers' => 2
|
|
|
],
|
|
|
'override_settings_restore_afterwards' => true
|
|
|
]);
|
|
|
@@ -97,10 +87,7 @@ class WorkOrder extends Api
|
|
|
$error = curl_error($ch);
|
|
|
curl_close($ch);
|
|
|
|
|
|
- if ($error) {
|
|
|
- return json(['code' => 1, 'msg' => '请求失败:' . $error]);
|
|
|
- }
|
|
|
-
|
|
|
+ if ($error) {return json(['code' => 1, 'msg' => '请求失败:' . $error]);}
|
|
|
$data = json_decode($response, true);
|
|
|
if (!isset($data['images'][0])) {
|
|
|
return json(['code' => 1, 'msg' => '接口未返回图像数据']);
|
|
|
@@ -127,84 +114,193 @@ class WorkOrder extends Api
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * 后期图像处理
|
|
|
- * /sdapi/v1/extra-single-image
|
|
|
+ * 后期图像处理-单张图片高清放大处理
|
|
|
+ * 接口地址: /sdapi/v1/extra-single-image
|
|
|
*/
|
|
|
public function extra_image()
|
|
|
{
|
|
|
- $imgRelPath = 'uploads/img2img/0828004096727-1.png'; // 图生图结果
|
|
|
- $imgPath = ROOT_PATH . 'public/' . $imgRelPath;
|
|
|
+ // 配置参数
|
|
|
+ $config = [
|
|
|
+ 'input_dir' => 'uploads/operate/ai/Preview/arr/',
|
|
|
+ 'output_dir' => 'uploads/extra_image/',
|
|
|
+ 'api_url' => 'http://20.0.17.233: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 = '图案的整体色调是柔和的蓝色和灰色形成温馨而宁静的视觉效果花卉.png';
|
|
|
+ $imgPath = ROOT_PATH . 'public/' . $config['input_dir'] . $imgRelPath;
|
|
|
|
|
|
if (!file_exists($imgPath)) {
|
|
|
return json(['code' => 1, 'msg' => '原图不存在:' . $imgRelPath]);
|
|
|
}
|
|
|
|
|
|
- $imgData = file_get_contents($imgPath);
|
|
|
- $base64Img = base64_encode($imgData);
|
|
|
-
|
|
|
- $postData = json_encode([
|
|
|
- '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,
|
|
|
- 'image' => $base64Img
|
|
|
- ]);
|
|
|
+ // 读取并编码图片
|
|
|
+ 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()]);
|
|
|
+ }
|
|
|
|
|
|
- $apiUrl = "http://20.0.17.233:45001/sdapi/v1/extra-single-image";
|
|
|
- $headers = ['Content-Type: application/json'];
|
|
|
+ // 准备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($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, $postData);
|
|
|
- curl_setopt($ch, CURLOPT_TIMEOUT, 90);
|
|
|
+ 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' => '请求失败:' . $error]);
|
|
|
+ return json(['code' => 1, 'msg' => 'API请求失败:' . $error]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($httpCode !== 200) {
|
|
|
+ return json(['code' => 1, 'msg' => 'API返回错误状态码:' . $httpCode]);
|
|
|
}
|
|
|
|
|
|
$data = json_decode($response, true);
|
|
|
- if (!isset($data['image'])) {
|
|
|
- return json(['code' => 1, 'msg' => '接口未返回图像数据']);
|
|
|
+ if (json_last_error() !== JSON_ERROR_NONE) {
|
|
|
+ return json(['code' => 1, 'msg' => 'API返回数据解析失败']);
|
|
|
}
|
|
|
|
|
|
- // 保存:原图基础名 + -2
|
|
|
- $resultImg = base64_decode($data['image']);
|
|
|
- $saveDir = ROOT_PATH . 'public/uploads/extra_image/';
|
|
|
- if (!is_dir($saveDir)) {
|
|
|
- mkdir($saveDir, 0755, true);
|
|
|
+ if (!isset($data['image']) || empty($data['image'])) {
|
|
|
+ return json(['code' => 1, 'msg' => '接口未返回有效的图像数据']);
|
|
|
}
|
|
|
|
|
|
- $originalBaseName = pathinfo($imgRelPath, PATHINFO_FILENAME);
|
|
|
- $fileName = $originalBaseName . '-2.png';
|
|
|
- $savePath = $saveDir . $fileName;
|
|
|
- file_put_contents($savePath, $resultImg);
|
|
|
+ // 保存处理后的图片
|
|
|
+ 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()]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取 SD 模型列表
|
|
|
+ * 接口地址: /sdapi/v1/sd-models
|
|
|
+ */
|
|
|
+ public function sd_models() {
|
|
|
+ $url = "http://20.0.17.233:45001/sdapi/v1/sd-models";
|
|
|
+
|
|
|
+ // 初始化 cURL
|
|
|
+ $ch = curl_init();
|
|
|
+
|
|
|
+ // 设置请求参数
|
|
|
+ curl_setopt($ch, CURLOPT_URL, $url);
|
|
|
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
|
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
|
+ 'Content-Type: application/json',
|
|
|
+ 'Accept: application/json',
|
|
|
+ ]);
|
|
|
|
|
|
+ // 发送请求
|
|
|
+ $response = curl_exec($ch);
|
|
|
+
|
|
|
+ // 错误处理
|
|
|
+ if (curl_errno($ch)) {
|
|
|
+ curl_close($ch);
|
|
|
+ return json([
|
|
|
+ 'code' => 1,
|
|
|
+ 'msg' => '请求失败: ' . curl_error($ch),
|
|
|
+ 'data' => [],
|
|
|
+ 'count' => 0
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ curl_close($ch);
|
|
|
+
|
|
|
+ // 解析 JSON 响应
|
|
|
+ $result = json_decode($response, true);
|
|
|
+
|
|
|
+ // 判断返回数据是否有效
|
|
|
+ if (!is_array($result)) {
|
|
|
+ return json([
|
|
|
+ 'code' => 1,
|
|
|
+ 'msg' => '数据解析失败',
|
|
|
+ 'data' => [],
|
|
|
+ 'count' => 0
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 正常返回
|
|
|
return json([
|
|
|
'code' => 0,
|
|
|
- 'msg' => '图像后处理成功',
|
|
|
- 'data' => [
|
|
|
- 'url' => '/uploads/extra_image/' . $fileName
|
|
|
- ]
|
|
|
+ 'msg' => '查询成功',
|
|
|
+ 'data' => $result,
|
|
|
+ 'count' => count($result)
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* 查询队列列表
|
|
|
* 统计文件对应的队列情况
|