think php处理 异步 url 请求 记录

server/2024/11/29 10:33:18/

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
{//请求生成歌曲网站urlpublic $url = 'https://api.sunoaiapi.com/api/v1';//请求生成歌曲keypublic $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;  // 替换为实际的 Tokencurl_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);}}
}

http://www.ppmy.cn/server/145885.html

相关文章

学习使用jquery实现在指定div前面增加内容

学习使用jquery实现在指定div前面增加内容 设计思路代码示例 设计思路 选择要添加内容的指定元素‌&#xff1a; 使用jQuery选择器来选择你希望在其前添加内容的元素。例如&#xff0c;如果你有一个 元素&#xff0c;其ID为qipa250&#xff0c;你可以使用$(‘#qipa250’)来选择…

如何使用 Jenkins 集成 Docker 以实现自动化 CI/CD 流程

Jenkins 是一个开源的自动化服务器&#xff0c;通常用于构建和测试软件项目&#xff0c;从而实现持续集成和持续部署。而 Docker 是一种容器技术&#xff0c;用于提供轻量级的虚拟化环境。结合 Jenkins 和 Docker&#xff0c;可以让开发团队更有效地管理应用程序的构建和发布。…

JDK的版本演化,JDK要收费吗?

Java版本演化历史 Java的版本历史可以追溯到1995年&#xff0c;以下是Java语言自诞生以来的主要版本及其关键特性&#xff1a; 一、早期版本 Java 1.0&#xff08;1996年1月发布&#xff09; 引入了Java虚拟机&#xff08;JVM&#xff09;和Java应用编程接口&#xff08;API&…

【Docker项目实战】使用Docker部署Enclosed文件分享工具

【Docker项目实战】使用Docker部署Enclosed文件分享工具 一、Enclosed介绍1.1 Enclosed 简介1.2 主要特点二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载Enclosed镜像五、部署…

C++设计模式——Abstract Factory Pattern抽象工厂模式

一、抽象工厂模式的定义 抽象工厂模式是一种创建型设计模式&#xff0c;它提供了一种将相关/依赖对象组合在一起创建的方式&#xff0c;而无需指定它们的具体类。 抽象工厂模式与工厂方法模式的区别&#xff1a; 工厂方法模式将对象的创建过程延迟到子类中&#xff0c;允许用…

python: generator model using mysql9.0 or postgreSQL 17.0

mysql 9.0: # encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎 # 描述&#xff1a; # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # OS …

【Ant Design Vue】表单校验 rules 不起作用

先展示修改后可校验的完整 demo<template><div class"rules-container"><a-form-modelref"formRef":model"formState":rules"rules":label-col"labelCol":wrapper-col"wrapperCol"><a-form-…

实验六 用MATLAB设计IIR数字滤波器

例题 例2-1 采用脉冲响应不变法设计一个巴特沃斯数字低通滤波器 要求&#xff1a;ωp0.25π&#xff0c;Rp1dB&#xff1b;ωs0.4π&#xff0c;As15dB&#xff0c;滤波器采样频率Fs2000Hz。 wp0.25*pi; %滤波器的通带截止频率 ws0.4*pi; %滤波器的阻…