From f2d219897f6489a15425683baab494febd7b2126 Mon Sep 17 00:00:00 2001 From: zpc Date: Wed, 18 Sep 2024 17:55:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HuanMeng.MiaoYu.Code/Music/MusicBLL.cs | 108 ++++++++++++++++- .../Music/MusicService.cs | 114 ++++++++++++++++++ .../HuanMeng.MiaoYu.Code/Users/UserBLL.cs | 4 +- .../DbSqlServer/Db_MiaoYu/M_SongInfo.cs | 48 ++++++++ .../DbSqlServer/Db_MiaoYu/M_Songs.cs | 22 +++- .../DbSqlServer/Db_MiaoYu/MiaoYuContext.cs | 43 ++++++- .../Dto/Music/MusicCreateRequest.cs | 30 +++++ .../EnumModel/User/UserCurrencyType.cs | 4 + .../Controllers/MusicController.cs | 13 +- src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs | 6 +- 10 files changed, 380 insertions(+), 12 deletions(-) create mode 100644 src/0-core/HuanMeng.MiaoYu.Code/Music/MusicService.cs create mode 100644 src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_SongInfo.cs create mode 100644 src/0-core/HuanMeng.MiaoYu.Model/Dto/Music/MusicCreateRequest.cs diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicBLL.cs b/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicBLL.cs index 9c0a76d..d8a21e4 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicBLL.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicBLL.cs @@ -7,13 +7,19 @@ using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http.Headers; +using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using HuanMeng.MiaoYu.Code.Chat.Contract; +using Org.BouncyCastle.Utilities; namespace HuanMeng.MiaoYu.Code.Music { /// - /// ai音乐逻辑类 + /// ai音乐逻辑类 /// public class MusicBLL : MiaoYuBase { @@ -78,5 +84,105 @@ namespace HuanMeng.MiaoYu.Code.Music musicUserGenresDtos = musicUserGenresDtos.OrderBy(it => it.GenreType).ThenBy(it => it.OrderId).ToList(); return new BaseResponse>(ResonseCode.Success, "", musicUserGenresDtos); } + + /// + /// + /// + /// + /// + /// + public async Task> CreateMusic(MusicCreateRequest musicCreateRequest) + { + if (_UserId == 0) + { + throw new Exception("请先登录"); + } + UserInfoBLL userInfoBLL = new UserInfoBLL(Dao, _UserId); + if (!userInfoBLL.IsCheckingSufficient(UserCurrencyType.生成音乐点数, 10)) + { + throw new Exception("音乐点数不足"); + } + Dictionary keyValuePairs = new Dictionary(); + keyValuePairs.Add("gpt_description_prompt", $"歌曲风格:{musicCreateRequest.GenreName}"); + keyValuePairs.Add("make_instrumental", false); + keyValuePairs.Add("mv", "chirp-v3-5"); + keyValuePairs.Add("prompt", musicCreateRequest.Prompt); + var requestBody = JsonConvert.SerializeObject(keyValuePairs); + var httpClient = HttpClientFactory.CreateClient(); + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + httpClient.DefaultRequestHeaders.Add("authorization", "Bearer hk-ylg6c31000042000fef54b80aec96b39e83b36f6e551440b"); + var content = new StringContent(requestBody, Encoding.UTF8, "application/json"); + var url = "https://api.openai-hk.com/sunoapi/generate/description-mode"; + var response = await httpClient.PostAsync(url, content); + if (response == null || !response.IsSuccessStatusCode) + { + throw new Exception("创建音乐失败"); + } + var responseContent = await response.Content.ReadAsStringAsync(); + if (string.IsNullOrEmpty(responseContent)) + { + throw new Exception("创建音乐失败!"); + } + var obj = JsonConvert.DeserializeObject(responseContent); + var id = obj?["id"]?.ToString() ?? ""; + + var musicId1 = obj?.SelectToken("clips[0].id")?.ToString(); + var musicId2 = obj?.SelectToken("clips[1].id")?.ToString(); + M_SongInfo m_SongInfo = new M_SongInfo() + { + CompleteAt = DateTime.Now, + CreateAt = DateTime.Now, + GetUrl = url, + RequestInfo = requestBody, + ResonseInfo = responseContent, + Status = "已完成", + UpdateAt = DateTime.Now, + }; + Dao.daoDbMiaoYu.context.Add(m_SongInfo); + Dao.daoDbMiaoYu.context.SaveChanges(); + if (string.IsNullOrEmpty(musicId1) && string.IsNullOrEmpty(musicId2)) + { + throw new Exception("创建音乐失败!!!"); + } + if (!string.IsNullOrEmpty(musicId1)) + { + var song1 = GetSong(musicCreateRequest.GenreName, musicCreateRequest.Name, musicId1, m_SongInfo.Id); + Dao.daoDbMiaoYu.context.Add(song1); + } + if (!string.IsNullOrEmpty(musicId2)) + { + var song2 = GetSong(musicCreateRequest.GenreName, musicCreateRequest.Name, musicId2, m_SongInfo.Id); + Dao.daoDbMiaoYu.context.Add(song2); + } + //扣除货币 + userInfoBLL[UserCurrencyType.生成音乐点数].ConsumeMoneyNoWork(-10, Dao); + return new BaseResponse(ResonseCode.Success, "音乐正在生成", true) { }; + } + + private M_Songs GetSong(string genreName, string name, string? musicId1, int songInfoId) + { + M_Songs m_Songs = new M_Songs() + { + AuthorId = _UserId, + CoverImage = "https://cos.shhuanmeng.com/yinyue/fengmian.png", + CreationTimestamp = DateTime.Now, + DownloadCount = 0, + LikeCount = 0, + PlayCount = 0, + Duration = TimeOnly.MinValue, + Genre = genreName, + GenreId = 0, + ImageLargeUrl = "https://cos.shhuanmeng.com/yinyue/fengmian.png", + IsPublic = false, + Lyrics = "", + MusicAddress = "", + SongInfoId = songInfoId, + SpecialId = musicId1, + State = 1, + Title = name + + }; + return m_Songs; + } } } diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicService.cs b/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicService.cs new file mode 100644 index 0000000..dde8c8a --- /dev/null +++ b/src/0-core/HuanMeng.MiaoYu.Code/Music/MusicService.cs @@ -0,0 +1,114 @@ +using HuanMeng.DotNetCore.MultiTenant.Contract; +using HuanMeng.DotNetCore.Processors; +using HuanMeng.MiaoYu.Code.AppExtend; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +using StackExchange.Redis; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http.Headers; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace HuanMeng.MiaoYu.Code.Music +{ + /// + /// + /// + public class MusicService(IServiceProvider serviceProvider) : IHostedService, IDisposable + { + MusicProcessor? musicProcessor = null; + public Task StartAsync(CancellationToken cancellationToken) + { + musicProcessor = new MusicProcessor(serviceProvider); + musicProcessor.Run(); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + if (musicProcessor != null) + { + musicProcessor.Stop(); + musicProcessor.Dispose(); + } + return Task.CompletedTask; + } + + public void Dispose() + { + musicProcessor?.Dispose(); + } + } + + public class MusicProcessor(IServiceProvider serviceProvider) : ThreadProcessor + { + protected override async void Proc_Do() + { + while (true) + { + + foreach (var item in AppConfigurationExtend.AppConfigs.Values) + { + + var service = serviceProvider.CreateScope(); + var temantInfo = serviceProvider.GetRequiredService(); + item.ToITenantInfo(temantInfo); + DAO dao = new DAO(serviceProvider); + var list = dao.daoDbMiaoYu.context.M_Songs.Where(it => it.State == 1).ToList(); + if (list.Count > 0) + { + var httpFactory = serviceProvider.GetRequiredService(); + foreach (var songs in list) + { + var httpClient = httpFactory.CreateClient(); + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + httpClient.DefaultRequestHeaders.Add("authorization", "Bearer hk-ylg6c31000042000fef54b80aec96b39e83b36f6e551440b"); + var url = $"https://api.openai-hk.com/suno/feed/{songs.SpecialId}"; + var response = await httpClient.GetAsync(url); + if (response == null || !response.IsSuccessStatusCode) + { + //throw new Exception("创建音乐失败"); + continue; + } + var responseContent = await response.Content.ReadAsStringAsync(); + if (string.IsNullOrEmpty(responseContent)) + { + continue; + } + var obj = JsonConvert.DeserializeObject(responseContent); + //status + var status = obj?.SelectToken("[0].status")?.ToString(); + if (status == "complete") + { + //obj.SelectToken("[0].video_url")?.ToString(); + + songs.MusicAddress = obj?.SelectToken("[0].audio_url")?.ToString() ?? ""; + songs.CoverImage = obj?.SelectToken("[0].image_url")?.ToString() ?? ""; + songs.ImageLargeUrl = obj?.SelectToken("[0].image_large_url")?.ToString() ?? ""; + songs.Lyrics = obj?.SelectToken("[0].metadata.prompt")?.ToString() ?? ""; + var duration = obj?.SelectToken("[0].metadata.duration")?.ToString() ?? ""; + if (!string.IsNullOrEmpty(duration)) + { + if (int.TryParse(duration, out var d)) + { + songs.Duration = new TimeOnly(0, 0, d); + } + } + dao.daoDbMiaoYu.context.SaveChanges(); + } + } + } + } + Thread.Sleep(1000 * 5); + + } + } + } +} diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Users/UserBLL.cs b/src/0-core/HuanMeng.MiaoYu.Code/Users/UserBLL.cs index 99259bd..fbe0e70 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Users/UserBLL.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Users/UserBLL.cs @@ -116,7 +116,7 @@ namespace HuanMeng.MiaoYu.Code.Users public async Task> GetUserInfo() { var user = await Dao.daoDbMiaoYu.context.T_User.FirstOrDefaultAsync(it => it.Id == _UserId); - var userData = await Dao.daoDbMiaoYu.context.T_User_Data.FirstOrDefaultAsync(it => it.Id == _UserId); + var userData = await Dao.daoDbMiaoYu.context.T_User_Data.FirstOrDefaultAsync(it => it.UserId == _UserId); //获取用户余额 UserInfoBLL userInfoBLL = new UserInfoBLL(Dao, _UserId); var Currency = userInfoBLL[UserCurrencyType.语珠]?.CurrencyMoney; @@ -134,7 +134,7 @@ namespace HuanMeng.MiaoYu.Code.Users NickName = user.NickName, UserId = user.Id, Currency = (int)Currency, - UserIconUrl = string.IsNullOrEmpty(userData.UserIconUrl) ? "https://cos.shhuanmeng.com/default.png" : userData.UserIconUrl, + UserIconUrl = string.IsNullOrEmpty(userData?.UserIconUrl) ? "https://cos.shhuanmeng.com/default.png" : userData?.UserIconUrl, RemainingChatCount = (int)RemainingChatCount,//这里先写1,我不会decimal转int HasTalked = hasTalked, Photographs = 0, diff --git a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_SongInfo.cs b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_SongInfo.cs new file mode 100644 index 0000000..61f3618 --- /dev/null +++ b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_SongInfo.cs @@ -0,0 +1,48 @@ +using System; + +namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu; + +/// +/// 音乐任务表 +/// +public partial class M_SongInfo: MultiTenantEntity +{ + public virtual int Id { get; set; } + + public override Guid TenantId { get; set; } + + /// + /// 请求数据 + /// + public virtual string? RequestInfo { get; set; } + + /// + /// 返回数据 + /// + public virtual string? ResonseInfo { get; set; } + + /// + /// 请求地址 + /// + public virtual string? GetUrl { get; set; } + + /// + /// 创建时间 + /// + public virtual DateTime CreateAt { get; set; } + + /// + /// 任务完成时间 + /// + public virtual DateTime? CompleteAt { get; set; } + + /// + /// 任务状态 + /// + public virtual string Status { get; set; } = null!; + + /// + /// 修改时间 + /// + public virtual DateTime UpdateAt { get; set; } +} diff --git a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_Songs.cs b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_Songs.cs index a5ea316..2a1d5eb 100644 --- a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_Songs.cs +++ b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/M_Songs.cs @@ -3,7 +3,7 @@ namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu; /// -/// 存储所有生成的歌曲的信息。 +/// 存储所有生成的歌曲的信息 /// public partial class M_Songs: MultiTenantEntity { @@ -78,4 +78,24 @@ public partial class M_Songs: MultiTenantEntity /// 音乐风格Id /// public virtual int? GenreId { get; set; } + + /// + /// 封面缩略图 + /// + public virtual string? ImageLargeUrl { get; set; } + + /// + /// 所属任务Id + /// + public virtual int SongInfoId { get; set; } + + /// + /// 音乐状态,0生成功,1生成中 + /// + public virtual int State { get; set; } + + /// + /// 特殊Id + /// + public virtual string SpecialId { get; set; } = null!; } diff --git a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs index 3184476..1584bfd 100644 --- a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs +++ b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs @@ -74,7 +74,12 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext public virtual DbSet M_SongComments { get; set; } /// - /// 存储所有生成的歌曲的信息。 + /// 音乐任务表 + /// + public virtual DbSet M_SongInfo { get; set; } + + /// + /// 存储所有生成的歌曲的信息 /// public virtual DbSet M_Songs { get; set; } @@ -379,11 +384,39 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext } }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__M_SongIn__3214EC070CFDD5C9"); + + entity.ToTable(tb => tb.HasComment("音乐任务表")); + + entity.Property(e => e.CompleteAt) + .HasComment("任务完成时间") + .HasColumnType("datetime"); + entity.Property(e => e.CreateAt) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.GetUrl).HasComment("请求地址"); + entity.Property(e => e.RequestInfo).HasComment("请求数据"); + entity.Property(e => e.ResonseInfo).HasComment("返回数据"); + entity.Property(e => e.Status) + .HasMaxLength(100) + .HasComment("任务状态"); + entity.Property(e => e.UpdateAt) + .HasComment("修改时间") + .HasColumnType("datetime"); + //添加全局筛选器 + if (this.TenantInfo != null) + { + entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId); + } + }); + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id).HasName("PK__Songs__3214EC0728D42B46"); - entity.ToTable(tb => tb.HasComment("存储所有生成的歌曲的信息。")); + entity.ToTable(tb => tb.HasComment("存储所有生成的歌曲的信息")); entity.Property(e => e.Id).HasComment("歌曲唯一标识"); entity.Property(e => e.AuthorId).HasComment("歌曲作者ID"); @@ -395,14 +428,18 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext entity.Property(e => e.DownloadCount).HasComment("下载次数"); entity.Property(e => e.Duration).HasComment("歌曲时长"); entity.Property(e => e.Genre) - .HasMaxLength(50) + .HasMaxLength(200) .HasComment("音乐风格"); entity.Property(e => e.GenreId).HasComment("音乐风格Id"); + entity.Property(e => e.ImageLargeUrl).HasComment("封面缩略图"); entity.Property(e => e.IsPublic).HasComment("歌曲是否公开展示"); entity.Property(e => e.LikeCount).HasComment("点赞次数"); entity.Property(e => e.Lyrics).HasComment("歌词内容"); entity.Property(e => e.MusicAddress).HasComment("音乐下载地址"); entity.Property(e => e.PlayCount).HasComment("播放次数"); + entity.Property(e => e.SongInfoId).HasComment("所属任务Id"); + entity.Property(e => e.SpecialId).HasComment("特殊Id"); + entity.Property(e => e.State).HasComment("音乐状态,0生成功,1生成中"); entity.Property(e => e.Title) .HasMaxLength(200) .HasComment("歌曲名称"); diff --git a/src/0-core/HuanMeng.MiaoYu.Model/Dto/Music/MusicCreateRequest.cs b/src/0-core/HuanMeng.MiaoYu.Model/Dto/Music/MusicCreateRequest.cs new file mode 100644 index 0000000..61a64d9 --- /dev/null +++ b/src/0-core/HuanMeng.MiaoYu.Model/Dto/Music/MusicCreateRequest.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.MiaoYu.Model.Dto.Music +{ + /// + /// 创建音乐 + /// + public class MusicCreateRequest + { + + /// + /// 音乐风格 + /// + public string GenreName { get; set; } + + /// + /// 音乐描述 + /// + public string Prompt { get; set; } + + /// + /// 歌曲名称 + /// + public string Name { get; set; } + } +} diff --git a/src/0-core/HuanMeng.MiaoYu.Model/EnumModel/User/UserCurrencyType.cs b/src/0-core/HuanMeng.MiaoYu.Model/EnumModel/User/UserCurrencyType.cs index ade3b93..2070f9c 100644 --- a/src/0-core/HuanMeng.MiaoYu.Model/EnumModel/User/UserCurrencyType.cs +++ b/src/0-core/HuanMeng.MiaoYu.Model/EnumModel/User/UserCurrencyType.cs @@ -29,6 +29,10 @@ namespace HuanMeng.MiaoYu.Model.EnumModel.User /// 记忆卡 = 3, + /// + /// 生成音乐次数 + /// + 生成音乐点数 = 4, /// /// 初级记忆卡 /// diff --git a/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/MusicController.cs b/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/MusicController.cs index 80ab856..228408d 100644 --- a/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/MusicController.cs +++ b/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/MusicController.cs @@ -24,7 +24,7 @@ namespace HuanMeng.MiaoYu.WebApi.Controllers /// /// [HttpGet] - public async Task>> GetMusicGenresList() + public async Task>> GetMusicGenresList() { MusicBLL musicBLL = new MusicBLL(ServiceProvider); return await musicBLL.GetMusicGenresList(); @@ -51,5 +51,16 @@ namespace HuanMeng.MiaoYu.WebApi.Controllers MusicBLL musicBLL = new MusicBLL(ServiceProvider); return await musicBLL.GetUserMusicGenresList(); } + + /// + /// 创作音乐 + /// + /// + [HttpPost] + public async Task> CreateMusic([FromBody] MusicCreateRequest musicCreateRequest) + { + MusicBLL musicBLL = new MusicBLL(ServiceProvider); + return await musicBLL.CreateMusic(musicCreateRequest); ; + } } } diff --git a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs index bc513b9..5bb55c5 100644 --- a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs +++ b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs @@ -1,8 +1,7 @@ -using AgileConfig.Client; - using HuanMeng.DotNetCore.CustomExtension; using HuanMeng.DotNetCore.MiddlewareExtend; using HuanMeng.DotNetCore.Utility.AssemblyHelper; +using HuanMeng.MiaoYu.Code.AppExtend; using HuanMeng.MiaoYu.Code.Base; using HuanMeng.MiaoYu.Code.JwtUtil; using HuanMeng.MiaoYu.Code.MultiTenantUtil; @@ -13,9 +12,8 @@ using HuanMeng.MiaoYu.Code.TencentUtile; using HuanMeng.MiaoYu.Code.Users.UserAccount.VerificationCodeManager; using HuanMeng.MiaoYu.Model.Dto; using HuanMeng.MiaoYu.WebApi.Base; -using HuanMeng.MiaoYu.Code.AppExtend; + using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Configuration; using Microsoft.OpenApi.Models; using Newtonsoft.Json.Serialization;