首页 > 其他分享 >简单实现Ai音乐suno-api

简单实现Ai音乐suno-api

时间:2024-07-01 10:58:48浏览次数:21  
标签:nil return string err Ai token json api suno

本文由 ChatMoney团队出品
前言
在科技与艺术的交汇处,AI音乐创作正以其独特的魅力,引领着音乐产业的一次革命。不久前,AI音乐的浪潮席卷了整个创意领域,激发了无数音乐爱好者和技术开发者的无限想象。在这场音乐与科技的盛宴中,主流的AI音乐平台suno无疑成为了焦点,尽管它尚未对外开放API服务,但这并未阻止我们探索的脚步。
今天,我们将踏上一段奇妙的旅程,用Go语言这把精准而强大的工具,尝试构建一个简易的suno-api。
开发前准备

  1. golang开发环境。
  2. golang版本:1.21.0
  3. 可登录suno的环境
  4. 获取suno平台cookie
    [图片]

开发过程
1.安装gin框架
go get -u github.com/gin-gonic/gin
2.封装suno请求

  1. 相关结构体
    package internal

import "time"

// GenerateReq generate-Req
type GenerateReq struct {
GptDescriptionPrompt string json:"gpt_description_prompt"
Prompt string json:"prompt"
Mv string json:"mv"
Title string json:"title"
Tags string json:"tags"
}

// GenerateResp generate-Resp
type GenerateResp struct {
BatchSize int json:"batch_size"
Clips []Clips json:"clips"
CreatedAt time.Time json:"created_at"
ID string json:"id"
Status string json:"status"
Metadata json:"metadata"
MajorModelVersion string json:"major_model_version"
}

// TokenResp token-Response
type TokenResp struct {
Jwt string
Object string
}

// SidResp session-resp
type SidResp struct {
Response struct {
Object string json:"object"
ID string json:"id"
Sessions []Session json:"sessions"
SignIn interface{} json:"sign_in"
SignUp interface{} json:"sign_up"
LastActiveSessionID string json:"last_active_session_id"
CreatedAt time.Time json:"created_at"
UpdatedAt time.Time json:"updated_at"
} json:"response"
Client interface{} json:"client"
}

// Clips clips
type Clips struct {
Detail string json:"detail"
Id string json:"id"
VideoUrl string json:"video_url"
AudioUrl string json:"audio_url"
ImageUrl string json:"image_url"
ImageLargeUrl string json:"image_large_url"
MajorModelVersion string json:"major_model_version"
ModelName string json:"model_name"
Metadata *Metadata json:"metadata"
IsLiked bool json:"is_liked"
UserId string json:"user_id"
IsTrashed bool json:"is_trashed"
Reaction interface{} json:"reaction"
CreatedAt time.Time json:"created_at"
Status string json:"status"
Title string json:"title"
PlayCount int json:"play_count"
UpvoteCount int json:"upvote_count"
IsPublic bool json:"is_public"
}

// Metadata Metadata
type Metadata struct {
Tags string json:"tags"
Prompt string json:"prompt"
GptDescriptionPrompt string json:"gpt_description_prompt"
AudioPromptId interface{} json:"audio_prompt_id"
History interface{} json:"history"
ConcatHistory interface{} json:"concat_history"
Type string json:"type"
Duration float64 json:"duration"
RefundCredits bool json:"refund_credits"
Stream bool json:"stream"
ErrorType interface{} json:"error_type"
ErrorMessage interface{} json:"error_message"
}

// Session sessionId
type Session struct {
Object string json:"object"
ID string json:"id"
}
2. 获取suno的token

  1. 实现逻辑为通过suno的cookie获取到sessionid,后通过sessionid获取token.
    // GetToken getToken
    func (s service) GetToken(cookieString string) (token string, err error) {
    var cookies []
    http.Cookie
    cookies = s.parseCookieString(cookieString)

    jar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
    sidUrl, _ := url.Parse(GetSidUrl)
    jar.SetCookies(sidUrl, cookies)

    client := &http.Client{
    Jar: jar,
    }

    sidResp, err := client.Get(sidUrl.String())
    if err != nil {
    return "", err
    }
    defer sidResp.Body.Close()

    var sidResponse SidResp
    _ = json.NewDecoder(sidResp.Body).Decode(&sidResponse)

    sid := ""
    if len(sidResponse.Response.Sessions) > 0 {
    sid = sidResponse.Response.Sessions[0].ID
    fmt.Println(sidResponse.Response.Sessions[0].ID)
    } else {
    err = errors.New("获取sessionId失败:Response.Sessions为空")
    return "", err
    }

    getTokenUrl := fmt.Sprintf("%s/%s/tokens?_clerk_js_version=4.72.0-snapshot.vc141245", GetTokenUrl, sid)
    tokenResp, err := client.Post(getTokenUrl, ContentType, nil)
    if err != nil {
    return "", err
    }
    defer tokenResp.Body.Close()

    var tokenResponse TokenResp
    bodyBytes, err := io.ReadAll(tokenResp.Body)
    if err != nil {
    return "", fmt.Errorf("error reading response body: %v", err)
    }

    if tokenResp.StatusCode != http.StatusOK {
    fmt.Printf("Error decoding JSON response: %v\nResponse body: %s\n", err, bodyBytes)
    fmt.Printf("请求失败,状态码: %d, 响应内容: %s\n", tokenResp.StatusCode, bodyBytes)
    return "", errors.New(fmt.Sprintf("请求失败,状态码: %d, 响应内容: %s\n", tokenResp.StatusCode, bodyBytes))
    }

    err = json.Unmarshal(bodyBytes, &tokenResponse)
    if err != nil {
    return "", err
    }

    if tokenResponse.Jwt == "" {
    return "", errors.New("获取token失败:token为空")
    }

    return tokenResponse.Jwt, nil
    }

// parseCookieString 格式化cookie
func (s service) parseCookieString(cookieString string) []http.Cookie {
var cookies []*http.Cookie
for _, cookiePair := range strings.Split(cookieString, "; ") {
parts := strings.Split(cookiePair, "=")
if len(parts) == 2 {
cookies = append(cookies, &http.Cookie{Name: parts[0], Value: parts[1]})
}
}
return cookies
}
3. 生成歌曲提交
// Generate 发起生成请求
func (s *service) Generate(prompt string) (response GenerateResp, err error) {
// token校验
if err = s.checkToken(); err != nil {
return
}

// 携带token发起请求
genReq := GenerateReq{
GptDescriptionPrompt: prompt,
Mv: "chirp-v3-0",
}
reqData, _ := json.Marshal(genReq)
genMusicUrl := BaseUrl + "/api/generate/v2/"
req, _ := http.NewRequest("POST", genMusicUrl, bytes.NewBuffer(reqData))
req.Header.Set("Authorization", "Bearer "+Token)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}

defer resp.Body.Close()

var genResponse GenerateResp
err = json.NewDecoder(resp.Body).Decode(&genResponse)
if err != nil {
return
}

return genResponse, nil
}
4. 查询歌曲详情
// GetFeed 查询详情
func (s *service) GetFeed(ids []string) (result []Clips, err error) {
// token校验
if err = s.checkToken(); err != nil {
return
}

idsFormat := url.PathEscape(strings.Join(ids, ","))
feedUrl := fmt.Sprintf("%s/api/feed/?ids=%s", BaseUrl, idsFormat)
req, _ := http.NewRequest("GET", feedUrl, nil)
req.Header.Set("Authorization", "Bearer "+Token)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{
Timeout: 10 * time.Second,
}

resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %v", err)
}

err = json.Unmarshal(bodyBytes, &result)
if err != nil {
fmt.Printf("Error decoding JSON response: %v\nResponse body: %s\n", err, bodyBytes)
return nil, err
}
return result, nil
}
3.控制器
// GenMusic 提交音乐请求
func (h *Handler) GenMusic(c *gin.Context) {
var genReq genReq
if err := c.ShouldBindJSON(&genReq); err != nil {
errResponse(c, err.Error(), "Params Fail")
return
}

token, err := SunoService.GetToken(cookieString)
if err != nil {
errResponse(c, err.Error(), "Request Failed")
return
}

SunoService.SetToken(token)

res, err := SunoService.Generate(genReq.Prompt)
if err != nil {
errResponse(c, err.Error(), "Request Failed")
return
}

okResponse(c, res)
return
}

// GetFeed 查询详情
func (h *Handler) GetFeed(c *gin.Context) {
var feedReq feedReq
if err := c.ShouldBindJSON(&feedReq); err != nil {
errResponse(c, err.Error(), "Params Fail")
return
}

token, err := SunoService.GetToken(cookieString)
if err != nil {
errResponse(c, err.Error(), "Request Failed")
return
}
SunoService.SetToken(token)

data, err := SunoService.GetFeed(feedReq.ClipsIds)
if err != nil {
errResponse(c, err.Error(), "Request Failed")
return
}
okResponse(c, data)
return
}
postman测试
项目启动
cd cmd
go run main.go
生成音乐
[图片]
查询音乐详情
[图片]
结语
虽然目前这个suno-api仅揭开了其神秘的面纱,实现了基础的生成及详情查询功能,但它所蕴含的潜力与未来的发展空间却是无限的。如果我们能够为这个API增添更多的功能和优化,它将变得更加强大和完善。比如,通过配置文件来管理cookie,让它们更加安全和持久;增加cookie的保活机制,让用户体验更加流畅;记录每一次的请求日志,让问题追踪和系统监控变得更加简单;实施接口限流策略,保障系统在高并发情况下的稳定性等等。希望后续能够激发更多的创意火花,创造出更多动人心弦的旋律。
感谢这段旅程有你的陪伴,让我们一起期待下一次更加精彩的启程。
完整代码
https://gitee.com/mofung1/go-suno
关于我们
本文由ChatMoney团队出品,ChatMoney专注于AI应用落地与变现,我们提供全套、持续更新的AI源码系统与可执行的变现方案,致力于帮助更多人利用AI来变现,欢迎进入ChatMoney获取更多AI变现方案!

标签:nil,return,string,err,Ai,token,json,api,suno
From: https://www.cnblogs.com/chatlin/p/18277618

相关文章

  • 【AI大模型】跌倒监控与健康:技术实践及如何改变未来
    文章目录1.**背景与意义**2.**关键技术与方法**2.1传感器数据融合2.2深度学习模型2.3行为模式识别2.4预测与预防3.**应用场景**3.1老年人跌倒预警3.2康复患者监测3.3高风险职业防护4.**实践案例**案例1:某老年社区的跌倒预警系统案例2:康复中心的患者监测系......
  • Java Chassis 3技术解密,流式响应如何简化AI应用开发
    本文分享自华为云社区《JavaChassis3技术解密:流式响应和人工智能应用开发》,作者:liubao68。随着生成式人工智能技术的发展,应用程序开发者对于流式响应(StreamingResponses)的诉求越来越多。服务器事件推送(ServerPushEvents)技术能够在使用HTTP协议的前提下,提供流式响应能力......
  • [淘宝/天猫/1688/京东]API接口数据采集分享
    在当今时代,从数据中挖掘价值的重要性愈发凸显,远超以往任何时期。随着新冠疫情的席卷,所有B2B公司都迎来了前所未有的挑战,它们不得不迅速将业务转移到线上的电子商务平台,以加速数字化转型的步伐。而随着疫情的逐渐缓解,这种线上线下的融合趋势非但没有减弱,反而得到了进一步的强化。......
  • AI大模型:解锁未来职业竞争力的金钥匙
    AI元年:大模型的革新力量随着ChatGPT的震撼登场,2023年被标记为AI元年,大模型以其前所未有的影响力,重塑我们的日常生活和工作方式。从日常的问答对话到复杂的编程辅助,乃至创意图像生成,AI大模型展现出超乎想象的能力,预示着“未来已来”,并成为互联网行业的新宠。大模型人才:高......
  • 存档main
    import'package:flutter/material.dart';import'package:gowater/widget/buy-water.dart';import'package:gowater/widget/history.dart';////voidmain(){runApp(constGoWaterMyApp());}classGoWaterMyAppextendsStatele......
  • AI绘画升温、AI写作降温,AIGC玩“变脸”
    前言AI作为先进科技技术的代表领域之一,一直都颇受人们的关注。经过这些年的发展,AI越来越聪明,甚至在某些领域已经能达成甚至超越人类的能力水平。本文作者围绕AI进行了分析,希望对你有帮助。自柯洁在“围棋人机大战”中惜败AlphaGo后,AI再次上演打败艺术家的戏码,AIGC(人工......
  • webAPI连接SQLserver,并快速建立数据模型
    首先,你需要有一个webAPI来作为Android应用和SQLserver数据库之间的中间件,创建该api在项目中导入三个NuGet包通过服务器资源管理器连接数据库,获取数据库连接的字符串 快速建立数据模型思路:通过数据库创建数据类:导入包=>打开程序包管理器控制台=>选择项目=>Scaffold-DbCont......
  • 详述Python环境下配置AI大模型Qwen-72B的步骤
    随着人工智能技术的发展,大规模预训练模型如Qwen-72B等逐渐成为研究和应用的重点。本篇博客旨在提供一份详细的指南,帮助Python开发者们在自己的环境中顺利配置并使用Qwen-72B大模型。请注意:由于Qwen-72B这一模型目前并未公开存在,所以以下内容仅为假设性描述,实际上你需要替换为......
  • AI引到学习前端开发
    假设你是一位前端技术开发专家,我有几个JavaScript的问题想向你咨询我想用JavaScript来做微信小程序开发,请以表格的方式输出知识要点请叙述JavaScript操作浏览器对象的常用接口和方法把上述表格按照访问对象归类将上述文字制作一个表格来呈现,要求逻辑清晰描述信息简明扼要且......
  • 乌班图Ubuntu 24.04初始化MySQL报错error while loading shared libraries: libaio.so
    由于乌班图24.04LTS已经发布了,因此准备新业务逐步往这上面迁移,毕竟支持有效期比22.04更长准备在24.04上进行MySQL的初始化,因为习惯自定义安装存储目录,所以使用mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz这个最新的二进制版本。按照22.04版本整理的安装笔记进行操作,第一步安装......