think php处理 异步 url 请求 记录

1、需求 某网站 需要 AI生成音乐,生成mp3文件的时候需要等待,需要程序中实时监听mp3文件是否生成
2、用的开发框架 为php
3、文件结构
在这里插入图片描述在这里插入图片描述配置路由设置

在这里插入图片描述

Route::group('/music', function () {
    Route::post('/musicLyrics', 'AiMusic/musicLyrics');//Ai生成歌词流式
    Route::post('/selectSleepMusicList', 'AiMusic/selectSleepMusicList');//查找睡眠音乐列表
    Route::post('/createMusic', 'AiMusic/createMusic');//查找睡眠音乐列表
    Route::post('/selectMusicHistory', 'AiMusic/selectMusicHistory');//查找用户AI生成音乐历史记录
    Route::post('/deleteMusic', 'AiMusic/deleteMusic');//删除用户选中音乐
    Route::get('/musicLyricsNoStream', 'AiMusic/musicLyricsNoStream');//Ai生成歌词非流式
    Route::post('/publishMusic', 'AiMusic/publishMusic');//发布音乐到广场
    Route::get('/updateMp3FileStatus', 'AiMusic/updateMp3FileStatus');//Ai生成歌词非流式
})->middleware([app\api\middleware\AuthMiddleware::class]);

在这里插入图片描述控制器实现代码

<?php
declare (strict_types=1);

namespace app\api\controller;

use app\constants\Message;
use app\exception\BusinessException;
use app\service\ChatBaseService;
use app\service\ModelService;
use think\exception\ValidateException;
use think\facade\Db;

class AiMusic extends Base
{
    //请求生成歌曲网站url
    public $url = 'https://api.sunoaiapi.com/api/v1';
    //请求生成歌曲key
    public $apiKey = 'your key';
    public $mv = 'chirp-v3-5';
    public $mapList = [
        'limit' => '/gateway/limit',
        'create' => '/gateway/generate/music',
        'query' => '/gateway/query',
    ];

    /**
     * ai 生成音乐歌词
     * @return
     */
    public function musicLyrics()
    {
        $question = $this->request->all('q');
        if (empty($question)) {
            throw new BusinessException('q' . Message::NOT_NUL);
        }
        $modelId = 1;
        $rand = rand(00000, 99999);
        $conversationId = substr(md5((string)time()), 8, 16) . '-' . substr(md5((string)$rand), 8, 16) . '-' . substr(md5($question . $modelId), 8, 16);
        $answer = (new ChatBaseService($this->getModeName(), $conversationId))->chat((string)trim($question), (int)$this->uid, (int)$modelId);
        if ($answer) {
            return json(['code' => 200, 'msg' => $answer['message']['content']]);
        } else {
            return json(['code' => 400, 'msg' => 'AI生成歌词失败']);
        }
    }

    /**
     * ai 获取模型名字
     * @return
     */
    private function getModeName()
    {
        $modelId = 1;
        $res = (new ModelService)->getOneById($modelId);
        if (empty($res)) {
            throw new BusinessException('model_id' . Message::NOT_NUL);
        }
        return $res['name'];
    }

    /**
     * ai 生成音乐歌词非流式
     * @return
     */
    public function musicLyricsNoStream()
    {
        header("Access-Control-Allow-Origin: *");
        $command = "curl http://your ip:11434/api/chat -d '{\"model\": \"openchat:latest\",\"messages\": [{\"role\": \"user\",\"content\": \"" . $_GET['question'] . "\"}],\"stream\": false}'";
        $output = shell_exec($command); // 执行shell命令并将结果赋值给$output变量
        $data = json_decode($output, true);
        if ($data) {
            return json(['msg' => $data['message']['content']]);
        } else {
            return json(['code' => 400, 'msg' => 'AI生成歌词失败']);
        }
    }

    /**
     * 睡眠时听音乐列表
     * @return
     */
    public function selectSleepMusicList()
    {
        $res = Db::name('music')->field('music_file_path,music_name,music_publicity_picture')->select();
        if ($res) {
            return json(['code' => 200, 'msg' => '获取成功', 'data' => $res]);
        } else {
            return json(['code' => 400, 'msg' => '获取失败']);
        }
    }

    /**
     * 创建歌曲
     * @param $this ->request 请求参数 llm 模型ID lyric 歌词 song 歌曲名称
     * @return  mixed JSON格式的响应数据
     */
    public function createMusic()
    {
        $lyric = $this->request->param('lyric', '');//歌词
        $song = $this->request->param('song', '');//歌曲名称
        $tags = $this->request->param('tags', '流行');//歌曲风格
        $token = trim(ltrim($this->request->header('Authorization'), 'Bearer'));

        if (empty($song)) {
            throw new ValidateException('歌曲名称必填');
        }
        $url = $this->url.$this->mapList['create'];

        $headers = [
            'api-key: '.$this->apiKey,
        ];

        $body = [
            'title' => $song,
            'tags' => $tags,
            'prompt' => $lyric,
            'mv' => $this->mv,
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if (!empty($body)) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
        }
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if (!empty($headers)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        $result = curl_exec($ch);
        curl_close($ch);

        if (empty($result)) {
            return '创建失败';
        }
        // 解码 JSON 数据
        $data = json_decode($result, true);

        if (empty($data['data'][0]['song_id'])) {
            return json(['code' => 400, 'msg' => '没有得到歌曲id']);
        } else {
            Db::name('ai_generated_music')->insert([
                'user_id' => $this->uid,
                'song_id' => 'https://cdn1.suno.ai/' . $data['data'][0]['song_id'] . '.mp3',
                'title' => $data['data'][0]['title'],
                'music_type' => '1',//默认为我的音乐值为1
                'meta_tags' => $data['data'][0]['meta_tags'],
                'meta_prompt' => $data['data'][0]['meta_prompt'],
                'music_generation_state' => '生成中',
                'music_img' => 'https://cdn1.suno.ai/image_' . $data['data'][0]['song_id'] . '.jpeg',
            ]);
            $this->runAsyncGetMp3FileStatus('https://cdn1.suno.ai/' . $data['data'][0]['song_id'] . '.mp3',$token);
            return json(['code' => 200,
                'msg' => '生成歌曲成功',
                'song_url' => 'https://cdn1.suno.ai/' . $data['data'][0]['song_id'] . '.mp3',
                'music_img' => 'https://cdn1.suno.ai/image_' . $data['data'][0]['song_id'] . '.jpeg',
                'music_generation_state' => '生成中',
            ]);
        }
    }

    /**
     * 查找用户生成的音乐列表
     * @param 用户id
     * @return  当前用户的音乐列表数据
     */
    public function selectMusicHistory()
    {
        $musicType = $this->request->param('type', '');//从页面传入的音乐类型

        $res = Db::name('ai_generated_music')->where([['user_id', '=', $this->uid], ['music_type', '=', $musicType]])->select();
        if ($res) {
            return json(['code' => 200, 'msg' => '获取成功', 'data' => $res]);
        } else {
            return json(['code' => 400, 'msg' => '获取失败']);
        }
    }

    /**
     * 删除用户选中音乐
     * @param 音乐ID
     * @return  删除成功或失败
     */
    public function deleteMusic()
    {
        $musicId = $this->request->param('musicId', '');//从页面传入的音乐ID
        $result = Db::name('ai_generated_music')->where(['id' => (int)$musicId])->delete();
        if ($result) {
            return json(['code' => 200, 'msg' => '删除成功']);
        } else {
            return json(['code' => 400, 'msg' => '删除失败']);
        }
    }

    /**
     * 发布音乐到广场
     * @param 音乐ID
     * @return   发布音乐到广场
     */
    public function publishMusic()
    {
        $musicId = $this->request->param('musicId', '');//从页面传入的音乐ID
        $res = Db::name('ai_generated_music')->where(['id' => (int)$musicId])->update(['music_type' => '0']);//更新音乐表中的音乐类型为广场音乐

        if ($res) {
            return json(['code' => 200, 'msg' => '发布音乐到广场成功']);
        } else {
            return json(['code' => 400, 'msg' => '发布音乐到广场失败或该音乐已发布']);
        }
    }

    /**
     * curl 异步调用  api/music/updateMp3FileStatus 接口 更新 mp3 音乐 文件状态
     * @param 音乐ID,令牌
     * @return
     */
    public function runAsyncGetMp3FileStatus($songId,$token)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "https://headsetmusic.yuzhouxiong.net/api/music/updateMp3FileStatus?songId=".$songId);  // 这个 URL 会调用异步的 PHP 脚本
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");  // 或 "POST"
        $authorizationToken = "Bearer ".$token;  // 替换为实际的 Token
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: $authorizationToken",
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);  // 设置超时为 1 秒
        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);  // 禁用信号
        curl_exec($ch);
        curl_close($ch);
    }

    /**
     * curl 异步更新mp3 文件状态 方法
     * @param 音乐ID
     * @return 数据库表h_ai_generated_music  字段 music_generation_state 为 已完成
     */
    function updateMp3FileStatus($songId)
    {
        while (true) {
            $headers = @get_headers($songId);
            // 如果获取不到响应头或者响应码不是 200,表示文件不存在
            if ($headers && strpos($headers[0], '200')) {
                $res=Db::name('ai_generated_music')->where(['song_id' => $songId])->update(['music_generation_state' => '已完成']);//更新音乐表中的音乐类型为广场音乐
                if ($res) {
                    $logMessage = 'music id: '.$songId.' MP3  update success';
                } else {
                    $logMessage = 'music id: '.$songId.' MP3  update failure';
                }
                // 日志文件路径
                $logFile = '/www/wwwroot/headset/runtime/updateMp3FileStatus.log';
                // 打开文件,如果文件不存在会创建,'a'模式表示追加内容
                $file = fopen($logFile, 'a');
                // 检查文件是否成功打开
                if ($file) {
                    // 日志内容
                    $logMessageTemp = "[".date('Y-m-d H:i:s')."] " . $logMessage. PHP_EOL;;
                    // 写入日志内容
                    fwrite($file, $logMessageTemp);
                    // 关闭文件
                    fclose($file);
                } else {
                    echo "无法打开日志文件";
                }
                echo "处理完成";
                break;
            }
            // 每隔 1 秒继续检查
            sleep(1);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/925871.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

27 基于51单片机的方向盘模拟系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用两个MPX4115压力传感器作为两路压力到位开关电路&#xff0c; 采用滑动变阻器连接数模转换器模拟重力加速度传感器电路&#xff1b; 一个按键控制LED灯的点亮与…

【亚马逊云科技】使用Amazon Lightsail搭建nginx服务

文章目录 前言一、为什么选择Amazon Lightsail二、创建账号与登录注册亚马逊账号登录控制台 三、创建Amazon Lightsail进入控制台创建实例登录服务器部署nginx服务关闭防火墙 总结 前言 不论是个人名片还是官方网站都离不开网站建设工作。计算机技术经历漫长的发展&#xff0c…

YOLOv8实战无人机视角目标检测

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对无人机目标数据集进行训练和优化&#xff0c;该数据集包含丰富的无人机目标图像…

Java设计模式——职责链模式:解锁高效灵活的请求处理之道

嘿&#xff0c;各位 Java 编程大神和爱好者们&#xff01;今天咱们要一同深入探索一种超厉害的设计模式——职责链模式。它就像一条神奇的“处理链”&#xff0c;能让请求在多个对象之间有条不紊地传递&#xff0c;直到找到最合适的“处理者”。准备好跟我一起揭开它神秘的面纱…

【四轴】利用PWM捕获解析接收机信号

在学习这部分之间&#xff0c;建议大家先看之前这篇博客&#xff0c;里面包含对PWM一些重要概念的基本介绍。 【四轴】利用PWM输出驱动无刷电机-CSDN博客 1. 基本原理 1.1 PWM是什么 这一部分可以看我之前的博客&#xff0c;已经对PWM有了基本的介绍。 1.2 什么叫捕获PWM波&…

HTTP 1

文章目录 1.2个简单的预备知识域名统一资源定位符 URL完整的URL 2. http请求和响应 格式画出来&#xff0c;两个工具见一见http请求/响应的样子3. 写一个最简单的httpserver&#xff0c;用浏览器直接测试recvsend处理请求stringstream 字符串分割工具wget 4. 读http报文的细节 …

【mac】mac自动定时开关机和其他常用命令,管理电源设置的工具pmset

一、操作步骤 1、打开终端 2、pmset 是用于管理电源设置的强大工具&#xff0c;我们将使用这个命令 &#xff08;1&#xff09;查询当前任务 pmset -g sched查看到我当前的设置是 唤醒电源开启在 工作日的每天早上8点半 上班时不用手动开机了 &#xff08;2&#xff09;删…

瀚高创库建表pgsql

1.瀚高下载地址&#xff1a; 下载 (highgo.com)https://www.highgo.com/down_main.html 2.瀚高linux安装 上传deb文件到ubuntu系统中 执行 dpkg -i hgdb-see-4.5.8-fe4791c.x86_64.deb 命令安装数据库 安装完成后&#xff0c;会在/opt 目录下生成安装目录 数据库安装完毕后…

力扣--LCR 150.彩灯装饰记录II

题目 代码 if(root null){ return new ArrayList<>(); } Queue<TreeNode> queue new LinkedList<>();List<List<Integer>> res new ArrayList<>();queue.add(root);while(!queue.isEmpty()){int k queue.size();List<Integer> …

ubuntu24.04安装Kubernetes1.31.0(k8s1.30.0)高可用集群

ubuntu24.04安装Kubernetes1.30.0(kubernetes1.30.0)高可用集群 一、总体概览 目前最新版的K8S版本应该是1.31.0,我们安装的是第二新的版本1.30.0,因为有大神XiaoHH Superme指路,所以基本上没踩坑,很顺利就搭建完成了。所有的机器都采用的最新版Ubuntu-Server-24.04长期支…

由于导包而引发的错误

今天在调试时发现删除功能无论如何都无法实现&#xff0c;于是调试找到了mapper层的错误但不知道为什么报错。以下是报错信息。 Caused by: org.apache.ibatis.binding.BindingException: Parameter userIds not found. Available parameters are [arg0, collection, list]at o…

结构体,枚举,联合知识点笔记总结

结构体&#xff1a; 1.之前我们知道&#xff0c;数组&#xff1a;一些值的结合&#xff0c;类型是相同的 结构&#xff1a;是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 struct s {int a; --|-->结构体成员int b; --}; 注意…

HTML飞舞的爱心(完整代码)

写在前面 HTML语言实现飞舞的爱心完整代码。 完整代码 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><title>飞舞爱心</title><style>* {margin: 0;padding: 0;}html,body {overflow: hidd…

数据结构--数组

目录 1 定义 1.1 数组内存结构 1.2二维数组 2 练习 2.1 将数组内两个区间内有序元素合并 2.2 leetcode88. 合并两个有序数组 3 缓存与局部性原理 1 定义 1.1 数组内存结构 1 2 3 5 6 给数组添加元素时&#xff0c;应将原来添加位置的元素和之后的元素进行复制 System…

【接口自动化测试】一文从3000字从0到1详解接口测试用例设计

接口自动化测试是软件测试中的一种重要手段&#xff0c;它能有效提高测试效率和测试覆盖率。在进行接口自动化测试之前&#xff0c;首先需要进行接口测试用例的设计。本文将从0到1详细且规范的介绍接口测试用例设计的过程&#xff0c;帮助读者快速掌握这一技能。 一、了解接口…

麒麟系统x86安装达梦数据库

一、安装准备前工作 操作系统&#xff1a;银河麒麟V10&#xff0c;CPU&#xff1a; x86_64 架构 下载地址&#xff0c;麒麟官网&#xff1a;https://www.kylinos.cn/ 数据库&#xff1a;dm8_20220915_x86_kylin10_64 下载地址&#xff0c;达梦数据库官网&#xff1a;https://…

个人博客接入github issue风格的评论,utteranc,gitment

在做个人博客的时候&#xff0c;如果你需要评论功能&#xff0c;但是又不想构建用户体系和评论模块&#xff0c;那么可以直接使用github的issue提供的接口&#xff0c;对应的开源项目有utteranc和gitment&#xff0c;尤其是前者。 它们的原理是一样的&#xff1a;在博客文章下…

6.算法移植第六篇 YOLOV5/rknn生成可执行文件部署在RK3568上

接上一篇文章best-sim.rknn模型生成好后&#xff0c;我们要将其转换成可执行文件运行在RK3568上&#xff0c;这一步需要在rknpu上进行&#xff0c;在强调一遍&#xff01;&#xff01;rknpu的作用是可以直接生成在开发板上运行的程序 退出上一步的docker环境 exit1.复制best-…

PyMOL操作手册

PyMOL 操作手册 The man will be silent, the woman will be tears. – itwangyang ​ 翻译整理&#xff1a;itwangyanng 2024 年 11月 29 日 目录 初识 PyMOL… 5 0.1 安装 PyMOL… 5 0.1.1 Windows 系统开源版 PyMOL 的安装… 5 0.1.2 教育版 PyMOL 的下载安装……

HarmonyOS Next 模拟器安装与探索

HarmonyOS 5 也发布了有一段时间了&#xff0c;不知道大家实际使用的时候有没有发现一些惊喜。当然随着HarmonyOS 5的更新也带来了很多新特性&#xff0c;尤其是 HarmonyOS Next 模拟器。今天&#xff0c;我们就来探索一下这个模拟器&#xff0c;看看它能给我们的开发过程带来什…