ImageService.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <?php
  2. namespace app\service;
  3. use app\service\AIGatewayService;
  4. use think\Db;
  5. use think\Exception;
  6. use think\Queue;
  7. /**
  8. * ImageService 类用于处理图像任务和存放日志队列。
  9. * 该类将前端传过来的多个图像信息推送到处理队列中。
  10. */
  11. class ImageService{
  12. /**
  13. * 直接调用图生文API并返回结果
  14. * @param array $params 请求参数,包含文生文提示词、模型类型等
  15. * @return array GPT生成的结果
  16. */
  17. public function handleImgToText($params) {
  18. Queue::push('app\job\ImageArrJob', $params, "arrimage");
  19. return true;
  20. }
  21. /**
  22. * 文生文
  23. * @param array $params 请求参数,包含文生文提示词、模型类型等
  24. * @return array GPT生成的结果
  25. */
  26. public function handleTextToText($prompt,$model) {
  27. $ai = new AIGatewayService();
  28. $gptRes = $ai->txtGptApi($prompt, $model);
  29. // 根据不同模型解析返回结果
  30. $gptText = '';
  31. if (strpos($model, 'gemini') !== false && isset($gptRes['candidates'][0]['content']['parts'][0]['text'])) {
  32. $gptText = trim($gptRes['candidates'][0]['content']['parts'][0]['text']);
  33. } elseif (isset($gptRes['choices'][0]['message']['content'])) {
  34. $gptText = trim($gptRes['choices'][0]['message']['content']);
  35. } else {
  36. throw new Exception('AI API返回格式错误');
  37. }
  38. return [
  39. 'success' => true,
  40. 'message' => '生成成功',
  41. 'data' => $gptText
  42. ];
  43. }
  44. /**
  45. * 文生图API并返回结果
  46. * @param array $params 请求参数,包含文生文提示词、模型类型等
  47. * @return array GPT生成的结果
  48. */
  49. public function handleTextToImg($params) {
  50. // 生成唯一任务ID,格式:$params['id']-年月日时间-随机四位数字
  51. $id = $params['id'];
  52. $time = date('YmdHis');
  53. $random = mt_rand(1000, 9999);
  54. $taskId = "{$id}-{$time}-{$random}";
  55. $params['task_id'] = $taskId;
  56. // 将任务状态存储到Redis
  57. $redis = new \Redis();
  58. $redis->connect('127.0.0.1', 6379);
  59. $redis->auth('123456');
  60. $redis->select(15);
  61. $redis->set("text_to_image_task:{$taskId}", json_encode([
  62. 'status' => 'pending',
  63. 'created_at' => date('Y-m-d H:i:s')
  64. ]), ['EX' => 300]); // 5分钟过期
  65. // 将任务推送到队列
  66. Queue::push('app\job\ImageArrJob', $params, "arrimage");
  67. // 返回任务ID
  68. return ['success' => true, 'message' => '正在生成图片中,请稍等.....', 'task_id' => $taskId];
  69. }
  70. /**
  71. * 图生图(Gemini:产品图+模板图)
  72. * @param array $params 包含 product_img、template_img、prompt、model、id(可选)
  73. * @return array
  74. */
  75. public function handleImgToImg($params) {
  76. $id = $params['id'];
  77. $time = date('YmdHis');
  78. $random = mt_rand(1000, 9999);
  79. $taskId = "{$id}-{$time}-{$random}";
  80. $params['task_id'] = $taskId;
  81. $redis = new \Redis();
  82. $redis->connect('127.0.0.1', 6379);
  83. $redis->auth('123456');
  84. $redis->select(15);
  85. $redis->set("img_to_img_task:{$taskId}", json_encode([
  86. 'status' => 'pending',
  87. 'created_at' => date('Y-m-d H:i:s')
  88. ]), ['EX' => 300]);
  89. Queue::push('app\job\ImageArrJob', $params, "arrimage");
  90. return ['success' => true, 'message' => '正在生成图片中,请稍等.....', 'task_id' => $taskId];
  91. }
  92. /**
  93. * 推送图像任务到队列(支持链式和单独模式)
  94. * @param array $params 请求参数,包含图像批次、模型类型、尺寸等
  95. */
  96. public function handleImage($params) {
  97. if (!isset($params["batch"])) {return false;}
  98. $arr = [];
  99. // 获取图像批量信息
  100. $batch = $params["batch"];
  101. // 获取执行次数数量
  102. $num = $params["num"];
  103. /*获取ids为1模板
  104. * english_content 文生文提示词
  105. * content 图生文提示词
  106. * */
  107. $template = Db::name('template')
  108. ->field('id,english_content,content,ids')
  109. ->where('path',$params['old_image_file'])
  110. ->where('ids',1)
  111. ->find();
  112. // 构建任务基础结构(每图生成 N 份任务)
  113. foreach ($batch as $k => $v) {
  114. $baseItem = [
  115. "sourceDir" => $this->sourceDir($v, 1),
  116. "outputDir" => $this->sourceDir($v, 2),
  117. "file_name" => $this->sourceDir($v, 3),
  118. "type" => $params['type'] ?? '',
  119. "selectedOption" => $params['selectedOption'],//文生图模型
  120. "txttotxt_selectedOption" => $params['txttotxt_selectedOption'],//文生文模型
  121. "imgtotxt_selectedOption" => $params['imgtotxt_selectedOption'],//图生文模型
  122. "prompt" => '',
  123. "width" => $params['width'],
  124. "height" => $params['height'],
  125. "executeKeywords" => $params['executeKeywords'],//是否执行几何图
  126. "sys_id" => $params['sys_id']//用户
  127. ];
  128. // 创建$num个相同的项目并合并到$arr
  129. $arr = array_merge($arr, array_fill(0, $num, $baseItem));
  130. }
  131. // 插入队列日志
  132. $insertData = [
  133. 'create_time' => date('Y-m-d H:i:s'),
  134. 'old_image_file' => $params['old_image_file'],
  135. 'status' => '等待中',
  136. 'image_count' => count($arr),
  137. 'params' => json_encode($params, JSON_UNESCAPED_UNICODE)
  138. ];
  139. //模型任务类型处理
  140. if (empty($params['type'])) {
  141. /*
  142. * 执行全部任务时一键链式任务队列
  143. * 用于存放队列日志
  144. * 链式任务:图生文 → 文生文 → 文生图
  145. * */
  146. $insertData['model'] = "gpt-4-vision-preview,"."gpt-4,".$params['selectedOption'];
  147. $insertData['model_name'] = '文生图';
  148. $task_id = Db::name('queue_logs')->insertGetId($insertData);
  149. $arr = array_map(function ($item) use ($task_id) {
  150. $item['type'] = '图生文';
  151. $item['chain_next'] = ['文生文', '文生图','图生图','高清放大'];
  152. $item['task_id'] = $task_id;
  153. return $item;
  154. }, $arr);
  155. $payload = [
  156. 'task_id' => $task_id,
  157. 'data' => $arr
  158. ];
  159. Queue::push('app\job\ImageArrJob', $payload, "arrimage");
  160. } else {
  161. // 指定单个独立任务类型
  162. switch ($params['type']) {
  163. case '图生文':
  164. $insertData['model'] = 'gpt-4-vision-preview';
  165. $insertData['model_name'] = '图生文';
  166. break;
  167. case '文生文':
  168. $insertData['model'] = $params['txttotxt_selectedOption'];
  169. $insertData['model_name'] = '文生文';
  170. break;
  171. case '文生图':
  172. $insertData['model'] = $params['selectedOption'];
  173. $insertData['model_name'] = '文生图';
  174. break;
  175. case '图生图':
  176. $insertData['model'] = "realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]";
  177. $insertData['model_name'] = '图生图';
  178. break;
  179. case '高清放大':
  180. $insertData['model'] = "高清放大";
  181. $insertData['model_name'] = '高清放大';
  182. break;
  183. default:
  184. return false;
  185. }
  186. //将一组队列存放queue_logs任务表中,将新增id最为任务id记录
  187. $task_id = Db::name('queue_logs')->insertGetId($insertData);
  188. $arr = array_map(function ($item) use ($params, $task_id) {
  189. $item['type'] = $params['type'];
  190. $item['task_id'] = $task_id;
  191. return $item;
  192. }, $arr);
  193. // 投递任务到队列
  194. $payload = [
  195. 'task_id' => $task_id,
  196. 'data' => $arr
  197. ];
  198. Queue::push('app\job\ImageArrJob', $payload, "arrimage");
  199. }
  200. return true;
  201. }
  202. /**
  203. * 解析图像路径,返回不同组成部分
  204. *
  205. * @param string $filePath 图像路径(如 uploads/operate/ai/Preview/20240610/xxx.png)
  206. * @param int $type 返回内容类型:
  207. * 1 = 基础路径(去掉日期+文件名)
  208. * sourceDir 源目录uploads/operate/ai/Preview/
  209. * 2 = 输出路径(Preview 替换为 dall-e,并加日期代表当天数据存到当天文件夹中)
  210. * outputDir 输出目录/uploads/operate/ai/dall-e/hua/并加日期
  211. * 3 = 文件名
  212. * file_name 文件名0194b6fdd6203fda369d5e3b74b6b454.png
  213. * @return string|null
  214. */
  215. public function sourceDir($filePath, $type) {
  216. $arr = [];
  217. $pathParts = explode('/', $filePath);
  218. $filename = array_pop($pathParts); // 最后是文件名
  219. $baseParts = $pathParts;
  220. // 查找是否有 8 位数字(即日期)文件夹
  221. $date = '';
  222. foreach ($pathParts as $index => $part) {
  223. if (preg_match('/^\d{8}$/', $part)) {
  224. $date = $part;
  225. unset($baseParts[$index]); // 日期不算在 basePath 里
  226. break;
  227. }
  228. }
  229. $arr = [
  230. 'basePath' => implode('/', $baseParts),
  231. 'date' => $date,
  232. 'filename' => $filename
  233. ];
  234. // 根据类型返回不同路径
  235. if ($type == 1) {
  236. return $arr["basePath"];
  237. }
  238. if ($type == 2) {
  239. return '/' . str_replace('/Preview/', '/dall-e/', $arr["basePath"]) . $arr["date"];
  240. }
  241. if ($type == 3) {
  242. return $arr["filename"];
  243. }
  244. }
  245. }