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
{//请求生成歌曲网站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.mzph.cn/pingmian/62341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【VRChat 改模】开发环境搭建:VCC、VRChat SDK、Unity 等环境配置

一、配置 Unity 相关 1.下载 UnityHub 下载地址&#xff1a;https://unity.com/download 安装打开后如图所示&#xff1a; 2.下载 VRChat 官方推荐版本的 Unity 跳转界面&#xff08;VRChat 官方推荐页面&#xff09;&#xff1a;https://creators.vrchat.com/sdk/upgrade/…

ollama部署bge-m3,并实现与dify平台对接

概述 这几天为了写技术博客,各种组件可谓是装了卸,卸了装,只想复现一些东西,确保你们看到的东西都是可以复现的。 (看在我这么认真的份上,求个关注啊,拜托各位观众老爷了。) 这不,为了实验在windows上docker里运行pytorch,把docker重装了。 dify也得重装: Dify基…

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?

目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一&#xff1a;是先有HTTP还是先有RPC&…

Lesson 10 GNN

听课&#xff08;李宏毅老师的&#xff09;笔记&#xff0c;方便梳理框架&#xff0c;以作复习之用。本节课主要讲了生成式对抗网络&#xff08;GNN&#xff09;。 目录 Generation Network as Generator 到目前为止&#xff0c;我们学习到的是类似于函数的network&#xf…

Scala入门基础(20)数据集复习拓展

一.Stack栈二.Queue 队列 一.Stack栈 Stack:栈&#xff0c;特殊的结构。它对元素的操作是在头部&#xff1a;栈顶 先进后出的队列。pop表示取出&#xff0c;push表示在栈中添加元素 二.Queue 队列 Queue 队列;先进先出.enqueue入队&#xff0c;dequeue出队。

Ubuntu20.04运行DM-VIO

目录 环境配置非ROS环境运行编译运行结果图 ROS环境参考 环境配置 Ubuntu20.04 将项目中Cmakelists.txt中C 和 opencv版本修改下 C 使用 14 opencv使用4 非ROS环境运行 编译 按照官网即可 cd dm-vio mkdir build cd build cmake .. make -j运行 DM-VIO给的命令是 bin/d…

TDengine 签约深圳综合粒子,赋能粒子研究新突破

在高能物理和粒子研究领域&#xff0c;实验装置的不断升级伴随着海量数据的产生与处理。尤其是随着大湾区综合性国家科学中心的建设步伐加快&#xff0c;深圳综合粒子设施研究院&#xff08;以下简称“研究院”&#xff09;作为承载“双区驱动”战略的重要科研机构&#xff0c;…

IDEA连接Apifox客户端

IDEA连接Apifox客户端 一、下载Apifox安装包二、IDEA配置三、配置Apifox和IDEA项目同步 一、下载Apifox安装包 Apifox官网&#xff0c;根据自己的操作系统下载对应的Apifox安装包&#xff0c;我是windows系统所以下载的是windows版。 下载 默认仅为我安装&#xff0c;点击下一…

(C语言) 8大翻译阶段

(C语言) 8大翻译阶段 文章目录 (C语言) 8大翻译阶段⭐前言&#x1f5c3;️8大阶段&#x1f5c2;️1. 字符映射&#x1f5c2;️2. 行分割&#x1f5c2;️3. 标记化&#x1f5c2;️4. 预处理&#x1f5c2;️5. 字符集映射&#x1f5c2;️6. 字符串拼接&#x1f5c2;️7. 翻译&…

php反序列化1_常见php序列化的CTF考题

声明&#xff1a; 以下多内容来自暗月师傅我是通过他的教程来学习记录的&#xff0c;如有侵权联系删除。 一道反序列化的CTF题分享_ctf反序列化题目_Mr.95的博客-CSDN博客 一些其他大佬的wp参考&#xff1a;php_反序列化_1 | dayu’s blog (killdayu.com) 序列化一个对象将…

Spring Boot拦截器(Interceptor)详解

拦截器Interceptor 拦截器我们主要分为三个方面进行讲解&#xff1a; 介绍下什么是拦截器&#xff0c;并通过快速入门程序上手拦截器拦截器的使用细节通过拦截器Interceptor完成登录校验功能 1. 快速入门 什么是拦截器&#xff1f; 是一种动态拦截方法调用的机制&#xff…

使用zabbix监控k8s

一、 参考文献 小阿轩yx-案例&#xff1a;Zabbix监控kubernetes云原生环境 手把手教你实现zabbix对Kubernetes的监控 二、部署经验 关于zabbix监控k8s&#xff0c;总体来说是分为两块内容&#xff0c;一是在k8s集群部署zabbix-agent和zabbix- proxy。二是在zabbix进行配置。…

GitCode 平台设置访问令牌 从而git仓库(附pycharm创建版本控制项目)

GitCode 背靠CSDN搞了国产的git平台&#xff0c;但在实际使用过程中&#xff0c;我直接感受就是坑爹&#xff01;在查找用户令牌&#xff08;账号密码&#xff09;这一基本功能上&#xff0c;因为是csdn直接登录跳转过去的用户令牌&#xff0c;没有设置过密码&#xff0c;默认就…

神经网络入门实战:(五)本地数据集的读取,以及从pytorch官网下载数据集的操作

本地带标签图片数据集的读取 代码里面的注释写的都比较清楚&#xff0c;也有拓展的部分&#xff0c;这里就不详细列出。 from torch.utils.data import Dataset # 从torch.utils.data导入Dataset类&#xff0c;用于创建自定义的数据集类 from PIL import Image #引入PIL库中的I…

【Maven】继承和聚合

5. Maven的继承和聚合 5.1 什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置&#xff0c;但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本&#xff0c;且这些模块之间不存在依赖关系&#xff0c;这就导致同一个依赖…

【C++打怪之路Lv16】-- map set

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…

Python爬虫爬取数据报错

报错&#xff1a; Error fetching the URL: (Connection aborted., ConnectionResetError(10054, 远程主机强迫关闭了一个现有的连接。, None, 10054, None)) 报错原因&#xff1a; 目标服务器限制&#xff1a; 目标网站可能已经检测到你的请求来自自动化工具&#xff08;如爬虫…

【Linux】线程的互斥和同步

【Linux】线程的互斥和同步 线程间的互斥 临界资源&#xff1a;多线程执行共享的资源就叫做临界资源临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临界区&#…

抓包之查看http basic auth认证方式

写在前面 在这篇文章中我们看了http basic auth的认证方式&#xff0c;本文通过wireshark抓包的方式来验证http协议的交互过程。 1&#xff1a;正文 首先wireshark抓取本机回环地址&#xff08;具体看你服务情况&#xff0c;决定哪个网卡&#xff0c;我本地是运行在127的&am…

网络安全(1)_对称加密和非对称加密

1 网络安全概述 1.1 计算机网络面临的安全威协 &#xff08;1&#xff09;截获&#xff1a;攻击者从网络上窃听他人的通信内容&#xff0c;通常把这类攻击称为“截获”。在被动攻击中&#xff0c;攻击者只是观察和分析某一个协议数据单元&#xff08;PDU&#xff09;而不干扰信…