| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- <?php
- namespace app\service;
- use app\service\AIGatewayService;
- use think\Db;
- use think\Queue;
- /**
- * ImageService 类用于处理图像任务和存放日志队列。
- * 该类将前端传过来的多个图像信息推送到处理队列中。
- */
- class ImageService{
- /**
- * 直接调用文生文API并返回结果
- * @param array $params 请求参数,包含文生文提示词、模型类型等
- * @return array GPT生成的结果
- */
- public function handleTextToText($params) {
- // 直接调用文生文API
- $ai = new AIGatewayService();
- $prompt = $params['prompt'];
- $model = $params['model'];
- $gptRes = $ai->txtGptApi($prompt, $model);
- $gptText = trim($gptRes['choices'][0]['message']['content'] ?? '');
- // 返回结果
- return [
- 'success' => true,
- 'message' => '文生文生成成功',
- 'data' => $gptText
- ];
- }
- /**
- * 直接调用文生图API并返回结果
- * @param array $params 请求参数,包含文生文提示词、模型类型等
- * @return array GPT生成的结果
- */
- public function handleTextToImg($params) {
- $prompt = $params['prompt'];
- $model = $params['model'];
- $size = $params['size'];
- // $ai = new AIGatewayService();
- // $response = $ai->callDalleApi($prompt, $model, $size);
- // 使用模拟数据进行测试
- $response = array(
- 'created' => 1766732917,
- 'data' => array(
- 0 => array(
- 'revised_prompt' => "A high-end real estate poster for New Year's Day featuring an indigo texture background. On the left, there is an ancient style folding fan with a red plum blossom branch painting and white cloud decorations. On the right, there are vertical golden characters wishing 'Happy New Year', accompanied by smaller text saying 'Future goals should be set, goals need to be firm'. At the bottom, the text reads 'High-end real estate' and 'Artistic East, Everlasting Mansion' with a phone number. The design includes Chinese elements like plum blossoms and folding fans, luxurious gold color scheme, minimal typography, and has a high-end business poster style, in 8K resolution.",
- 'url' => 'https://oaidalleapiprodscus.blob.core.windows.net/private/org-cVDLOO48jmNEm0j82aW7iWKC/user-Qr4ZM43TMl5KP37UnSn0RhzQ/img-krzDOBoXrcsk9cTSVeGSVLpd.png?st=2025-12-26T06%3A08%3A37Z&se=2025-12-26T08%3A08%3A37Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=0e2a3d55-e963-40c9-9c89-2a1aa28cb3ac&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-12-26T05%3A15%3A04Z&ske=2025-12-27T05%3A15%3A04Z&sks=b&skv=2024-08-04&sig=XIXQbk/abDibZL%2BNeQiNzKv4qo5fgpxSckJcyn6BbOM%3D'
- )
- )
- );
- $revised_prompt = $response['data'][0]['revised_prompt'];
- $Url = $response['data'][0]['url'];
- return [
- 'success' => true,
- 'revised_prompt' => $revised_prompt,
- 'url' => $Url
- ];
- }
- /**
- * 保存图片URL到本地
- * @param string $imageUrl 图片URL
- * @return string|null 本地图片路径或null(如果保存失败)
- */
- private function saveImageFromUrl($imageUrl) {
- // 创建保存目录结构
- $dateDir = date('Ymd');
- $savePath = ROOT_PATH . 'public/uploads/operate/ai/dall-e/' . $dateDir . '/';
- // 确保目录存在
- if (!is_dir($savePath)) {
- mkdir($savePath, 0755, true);
- }
- // 生成唯一的图片文件名
- $fileName = uniqid() . '.png';
- $fullFilePath = $savePath . $fileName;
- $relativePath = '/uploads/operate/ai/dall-e/' . $dateDir . '/' . $fileName;
- // 使用curl下载图片
- $ch = curl_init($imageUrl);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_TIMEOUT, 30);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- $imageData = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
- if ($httpCode == 200 && $imageData !== false) {
- // 保存图片到本地
- if (file_put_contents($fullFilePath, $imageData) !== false) {
- // 返回相对URL路径
- return $relativePath;
- }
- }
- return null;
- }
- /**
- * 推送图像任务到队列(支持链式和单独模式)
- * @param array $params 请求参数,包含图像批次、模型类型、尺寸等
- */
- public function handleImage($params) {
- if (!isset($params["batch"])) {return false;}
- $arr = [];
- // 获取图像批量信息
- $batch = $params["batch"];
- // 获取执行次数数量
- $num = $params["num"];
- /*获取ids为1模板
- * english_content 文生文提示词
- * content 图生文提示词
- * */
- $template = Db::name('template')
- ->field('id,english_content,content,ids')
- ->where('path',$params['old_image_file'])
- ->where('ids',1)
- ->find();
- // 构建任务基础结构(每图生成 N 份任务)
- foreach ($batch as $k => $v) {
- $baseItem = [
- "sourceDir" => $this->sourceDir($v, 1),
- "outputDir" => $this->sourceDir($v, 2),
- "file_name" => $this->sourceDir($v, 3),
- "type" => $params['type'] ?? '',
- "selectedOption" => $params['selectedOption'],//文生图模型
- "txttotxt_selectedOption" => $params['txttotxt_selectedOption'],//文生文模型
- "imgtotxt_selectedOption" => $params['imgtotxt_selectedOption'],//图生文模型
- "prompt" => '',
- "width" => $params['width'],
- "height" => $params['height'],
- "executeKeywords" => $params['executeKeywords'],//是否执行几何图
- "sys_id" => $params['sys_id']//用户
- ];
- // 创建$num个相同的项目并合并到$arr
- $arr = array_merge($arr, array_fill(0, $num, $baseItem));
- }
- // 插入队列日志
- $insertData = [
- 'create_time' => date('Y-m-d H:i:s'),
- 'old_image_file' => $params['old_image_file'],
- 'status' => '等待中',
- 'image_count' => count($arr),
- 'params' => json_encode($params, JSON_UNESCAPED_UNICODE)
- ];
- //模型任务类型处理
- if (empty($params['type'])) {
- /*
- * 执行全部任务时一键链式任务队列
- * 用于存放队列日志
- * 链式任务:图生文 → 文生文 → 文生图
- * */
- $insertData['model'] = "gpt-4-vision-preview,"."gpt-4,".$params['selectedOption'];
- $insertData['model_name'] = '文生图';
- $task_id = Db::name('queue_logs')->insertGetId($insertData);
- $arr = array_map(function ($item) use ($task_id) {
- $item['type'] = '图生文';
- $item['chain_next'] = ['文生文', '文生图','图生图','高清放大'];
- $item['task_id'] = $task_id;
- return $item;
- }, $arr);
- $payload = [
- 'task_id' => $task_id,
- 'data' => $arr
- ];
- Queue::push('app\job\ImageArrJob', $payload, "arrimage");
- } else {
- // 指定单个独立任务类型
- switch ($params['type']) {
- case '图生文':
- $insertData['model'] = 'gpt-4-vision-preview';
- $insertData['model_name'] = '图生文';
- break;
- case '文生文':
- $insertData['model'] = $params['txttotxt_selectedOption'];
- $insertData['model_name'] = '文生文';
- break;
- case '文生图':
- $insertData['model'] = $params['selectedOption'];
- $insertData['model_name'] = '文生图';
- break;
- case '图生图':
- $insertData['model'] = "realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]";
- $insertData['model_name'] = '图生图';
- break;
- case '高清放大':
- $insertData['model'] = "高清放大";
- $insertData['model_name'] = '高清放大';
- break;
- default:
- return false;
- }
- //将一组队列存放queue_logs任务表中,将新增id最为任务id记录
- $task_id = Db::name('queue_logs')->insertGetId($insertData);
- $arr = array_map(function ($item) use ($params, $task_id) {
- $item['type'] = $params['type'];
- $item['task_id'] = $task_id;
- return $item;
- }, $arr);
- // 投递任务到队列
- $payload = [
- 'task_id' => $task_id,
- 'data' => $arr
- ];
- Queue::push('app\job\ImageArrJob', $payload, "arrimage");
- }
- return true;
- }
- /**
- * 解析图像路径,返回不同组成部分
- *
- * @param string $filePath 图像路径(如 uploads/operate/ai/Preview/20240610/xxx.png)
- * @param int $type 返回内容类型:
- * 1 = 基础路径(去掉日期+文件名)
- * sourceDir 源目录uploads/operate/ai/Preview/
- * 2 = 输出路径(Preview 替换为 dall-e,并加日期代表当天数据存到当天文件夹中)
- * outputDir 输出目录/uploads/operate/ai/dall-e/hua/并加日期
- * 3 = 文件名
- * file_name 文件名0194b6fdd6203fda369d5e3b74b6b454.png
- * @return string|null
- */
- public function sourceDir($filePath, $type) {
- $arr = [];
- $pathParts = explode('/', $filePath);
- $filename = array_pop($pathParts); // 最后是文件名
- $baseParts = $pathParts;
- // 查找是否有 8 位数字(即日期)文件夹
- $date = '';
- foreach ($pathParts as $index => $part) {
- if (preg_match('/^\d{8}$/', $part)) {
- $date = $part;
- unset($baseParts[$index]); // 日期不算在 basePath 里
- break;
- }
- }
- $arr = [
- 'basePath' => implode('/', $baseParts),
- 'date' => $date,
- 'filename' => $filename
- ];
- // 根据类型返回不同路径
- if ($type == 1) {
- return $arr["basePath"];
- }
- if ($type == 2) {
- return '/' . str_replace('/Preview/', '/dall-e/', $arr["basePath"]) . $arr["date"];
- }
- if ($type == 3) {
- return $arr["filename"];
- }
- }
- }
|