【代码优化】AI:music 的路径修改

This commit is contained in:
YunaiV
2024-07-30 09:23:21 +08:00
parent 2ff21aa65e
commit 900d275055
9 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
<template>
<div class="flex h-full items-stretch">
<!-- 模式 -->
<Mode class="flex-none" @generate-music="generateMusic"/>
<!-- 音频列表 -->
<List ref="listRef" class="flex-auto"/>
</div>
</template>
<script lang="ts" setup>
import Mode from './mode/index.vue'
import List from './list/index.vue'
defineOptions({ name: 'Index' })
const listRef = ref<Nullable<{generateMusic: (...args) => void}>>(null)
/*
*@Description: 拿到左侧配置信息调用右侧音乐生成的方法
*@MethodAuthor: xiaohong
*@Date: 2024-07-19 11:13:38
*/
function generateMusic (args: {formData: Recordable}) {
unref(listRef)?.generateMusic(args.formData)
}
</script>

View File

@@ -0,0 +1,70 @@
<template>
<div class="flex items-center justify-between px-2 h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none">
<!-- 歌曲信息 -->
<div class="flex gap-[10px]">
<el-image src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" class="w-[45px]"/>
<div>
<div>{{currentSong.name}}</div>
<div class="text-[12px] text-gray-400">{{currentSong.singer}}</div>
</div>
</div>
<!-- 音频controls -->
<div class="flex gap-[12px] items-center">
<Icon icon="majesticons:back-circle" :size="20" class="text-gray-300 cursor-pointer"/>
<Icon :icon="audioProps.paused ? 'mdi:arrow-right-drop-circle' : 'solar:pause-circle-bold'" :size="30" class=" cursor-pointer" @click="toggleStatus('paused')"/>
<Icon icon="majesticons:next-circle" :size="20" class="text-gray-300 cursor-pointer"/>
<div class="flex gap-[16px] items-center">
<span>{{audioProps.currentTime}}</span>
<el-slider v-model="audioProps.duration" color="#409eff" class="w-[160px!important] "/>
<span>{{ audioProps.duration }}</span>
</div>
<!-- 音频 -->
<audio v-bind="audioProps" ref="audioRef" controls v-show="!audioProps" @timeupdate="audioTimeUpdate">
<source :src="audioUrl"/>
</audio>
</div>
<!-- 音量控制器 -->
<div class="flex gap-[16px] items-center">
<Icon :icon="audioProps.muted ? 'tabler:volume-off' : 'tabler:volume'" :size="20" class="cursor-pointer" @click="toggleStatus('muted')"/>
<el-slider v-model="audioProps.volume" color="#409eff" class="w-[160px!important] "/>
</div>
</div>
</template>
<script lang="ts" setup>
import { formatPast } from '@/utils/formatTime'
import audioUrl from '@/assets/audio/response.mp3'
defineOptions({ name: 'Index' })
const currentSong = inject('currentSong', {})
const audioRef = ref<Nullable<HTMLElement>>(null)
// 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
const audioProps = reactive({
autoplay: true,
paused: false,
currentTime: '00:00',
duration: '00:00',
muted: false,
volume: 50,
})
function toggleStatus (type: string) {
audioProps[type] = !audioProps[type]
if (type === 'paused' && audioRef.value) {
if (audioProps[type]) {
audioRef.value.pause()
} else {
audioRef.value.play()
}
}
}
// 更新播放位置
function audioTimeUpdate (args) {
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss')
}
</script>

View File

@@ -0,0 +1,108 @@
<template>
<div class="flex flex-col">
<div class="flex-auto flex overflow-hidden">
<el-tabs v-model="currentType" class="flex-auto px-[var(--app-content-padding)]">
<!-- 我的创作 -->
<el-tab-pane v-loading="loading" label="我的创作" name="mine">
<el-row v-if="mySongList.length" :gutter="12">
<el-col v-for="song in mySongList" :key="song.id" :span="24">
<songCard :songInfo="song" @play="setCurrentSong(song)"/>
</el-col>
</el-row>
<el-empty v-else description="暂无音乐"/>
</el-tab-pane>
<!-- 试听广场 -->
<el-tab-pane v-loading="loading" label="试听广场" name="square">
<el-row v-if="squareSongList.length" v-loading="loading" :gutter="12">
<el-col v-for="song in squareSongList" :key="song.id" :span="24">
<songCard :songInfo="song" @play="setCurrentSong(song)"/>
</el-col>
</el-row>
<el-empty v-else description="暂无音乐"/>
</el-tab-pane>
</el-tabs>
<!-- songInfo -->
<songInfo class="flex-none"/>
</div>
<audioBar class="flex-none"/>
</div>
</template>
<script lang="ts" setup>
import songCard from './songCard/index.vue'
import songInfo from './songInfo/index.vue'
import audioBar from './audioBar/index.vue'
defineOptions({ name: 'Index' })
const currentType = ref('mine')
// loading 状态
const loading = ref(false)
// 当前音乐
const currentSong = ref({})
const mySongList = ref<Recordable[]>([])
const squareSongList = ref<Recordable[]>([])
provide('currentSong', currentSong)
/*
*@Description: 调接口生成音乐列表
*@MethodAuthor: xiaohong
*@Date: 2024-06-27 17:06:44
*/
function generateMusic (formData: Recordable) {
console.log(formData);
loading.value = true
setTimeout(() => {
mySongList.value = Array.from({ length: 20 }, (_, index) => {
return {
id: index,
audioUrl: '',
videoUrl: '',
title: '我走后' + index,
imageUrl: 'https://www.carsmp3.com/data/attachment/forum/201909/19/091020q5kgre20fidreqyt.jpg',
desc: 'Metal, symphony, film soundtrack, grand, majesticMetal, dtrack, grand, majestic',
date: '2024年04月30日 14:02:57',
lyric: `<div class="_words_17xen_66"><div>大江东去,浪淘尽,千古风流人物。
</div><div>故垒西边,人道是,三国周郎赤壁。
</div><div>乱石穿空,惊涛拍岸,卷起千堆雪。
</div><div>江山如画,一时多少豪杰。
</div><div>
</div><div>遥想公瑾当年,小乔初嫁了,雄姿英发。
</div><div>羽扇纶巾,谈笑间,樯橹灰飞烟灭。
</div><div>故国神游,多情应笑我,早生华发。
</div><div>人生如梦,一尊还酹江月。</div></div>`
}
})
loading.value = false
}, 3000)
}
/*
*@Description: 设置当前播放的音乐
*@MethodAuthor: xiaohong
*@Date: 2024-07-19 11:22:33
*/
function setCurrentSong (music: Recordable) {
currentSong.value = music
}
defineExpose({
generateMusic
})
</script>
<style lang="scss" scoped>
:deep(.el-tabs) {
display: flex;
flex-direction: column;
.el-tabs__content {
padding: 0 7px;
overflow: auto;
}
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<div class="flex bg-[var(--el-bg-color-overlay)] p-12px mb-12px rounded-1">
<div class="relative" @click="playSong">
<el-image :src="songInfo.imageUrl" class="flex-none w-80px"/>
<div class="bg-black bg-op-40 absolute top-0 left-0 w-full h-full flex items-center justify-center cursor-pointer">
<Icon :icon="currentSong.id === songInfo.id ? 'solar:pause-circle-bold':'mdi:arrow-right-drop-circle'" :size="30" />
</div>
</div>
<div class="ml-8px">
<div>{{ songInfo.title }}</div>
<div class="mt-8px text-12px text-[var(--el-text-color-secondary)] line-clamp-2">
{{ songInfo.desc }}
</div>
</div>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'Index' })
defineProps({
songInfo: {
type: Object,
default: () => ({})
}
})
const emits = defineEmits(['play'])
const currentSong = inject('currentSong', {})
function playSong () {
emits('play')
}
</script>

View File

@@ -0,0 +1,22 @@
<template>
<ContentWrap class="w-300px mb-[0!important] line-height-24px">
<el-image :src="currentSong.imageUrl"/>
<div class="">{{ currentSong.title }}</div>
<div class="text-[var(--el-text-color-secondary)] text-12px line-clamp-1">
{{ currentSong.desc }}
</div>
<div class="text-[var(--el-text-color-secondary)] text-12px">
{{ currentSong.date }}
</div>
<el-button size="small" round class="my-6px">信息复用</el-button>
<div class="text-[var(--el-text-color-secondary)] text-12px" v-html="currentSong.lyric"></div>
</ContentWrap>
</template>
<script lang="ts" setup>
defineOptions({ name: 'Index' })
const currentSong = inject('currentSong', {})
</script>

View File

@@ -0,0 +1,55 @@
<template>
<div>
<Title title="音乐/歌词说明" desc="描述您想要的音乐风格和主题,使用流派和氛围而不是特定的艺术家和歌曲">
<el-input
v-model="formData.desc"
:autosize="{ minRows: 6, maxRows: 6}"
resize="none"
type="textarea"
maxlength="1200"
show-word-limit
placeholder="一首关于糟糕分手的欢快歌曲"
/>
</Title>
<Title title="纯音乐" desc="创建一首没有歌词的歌曲">
<template #extra>
<el-switch v-model="formData.pure" size="small"/>
</template>
</Title>
<Title title="版本" desc="描述您想要的音乐风格和主题,使用流派和氛围而不是特定的艺术家和歌曲">
<el-select v-model="formData.version" placeholder="请选择">
<el-option
v-for="item in [{
value: '3',
label: 'V3'
}, {
value: '2',
label: 'V2'
}]"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</Title>
</div>
</template>
<script lang="ts" setup>
import Title from '../title/index.vue'
defineOptions({ name: 'Desc' })
const formData = reactive({
desc: '',
pure: false,
version: '3'
})
defineExpose({
formData
})
</script>

View File

@@ -0,0 +1,41 @@
<template>
<ContentWrap class="w-300px h-full mb-[0!important]">
<el-radio-group v-model="generateMode" class="mb-15px">
<el-radio-button label="desc">
描述模式
</el-radio-button>
<el-radio-button label="lyric">
歌词模式
</el-radio-button>
</el-radio-group>
<!-- 描述模式/歌词模式 切换 -->
<component :is="generateMode === 'desc' ? desc : lyric" ref="modeRef"/>
<el-button type="primary" round class="w-full" @click="generateMusic">
创作音乐
</el-button>
</ContentWrap>
</template>
<script lang="ts" setup>
import desc from './desc.vue'
import lyric from './lyric.vue'
defineOptions({ name: 'Index' })
const emits = defineEmits(['generate-music'])
const generateMode = ref('lyric')
const modeRef = ref<Nullable<{ formData: Recordable }>>(null)
/*
*@Description: 根据信息生成音乐
*@MethodAuthor: xiaohong
*@Date: 2024-06-27 16:40:16
*/
function generateMusic () {
emits('generate-music', {formData: unref(modeRef)?.formData})
}
</script>

View File

@@ -0,0 +1,83 @@
<template>
<div class="">
<Title title="歌词" desc="自己编写歌词或使用Ai生成歌词两节/8行效果最佳">
<el-input
v-model="formData.lyric"
:autosize="{ minRows: 6, maxRows: 6}"
resize="none"
type="textarea"
maxlength="1200"
show-word-limit
placeholder="请输入您自己的歌词"
/>
</Title>
<Title title="音乐风格">
<el-space class="flex-wrap">
<el-tag v-for="tag in tags" :key="tag" round class="mb-8px">{{tag}}</el-tag>
</el-space>
<el-button
:type="showCustom ? 'primary': 'default'"
round
size="small"
class="mb-6px"
@click="showCustom = !showCustom"
>自定义风格
</el-button>
</Title>
<Title v-show="showCustom" desc="描述您想要的音乐风格Suno无法识别艺术家的名字但可以理解流派和氛围" class="-mt-12px">
<el-input
v-model="formData.style"
:autosize="{ minRows: 4, maxRows: 4}"
resize="none"
type="textarea"
maxlength="256"
show-word-limit
placeholder="输入音乐风格(英文)"
/>
</Title>
<Title title="音乐/歌曲名称">
<el-input v-model="formData.name" placeholder="请输入音乐/歌曲名称"/>
</Title>
<Title title="版本">
<el-select v-model="formData.version" placeholder="请选择">
<el-option
v-for="item in [{
value: '3',
label: 'V3'
}, {
value: '2',
label: 'V2'
}]"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</Title>
</div>
</template>
<script lang="ts" setup>
import Title from '../title/index.vue'
defineOptions({ name: 'Lyric' })
const tags = ['rock', 'punk', 'jazz', 'soul', 'country', 'kidsmusic', 'pop']
const showCustom = ref(false)
const formData = reactive({
lyric: '',
style: '',
name: '',
version: ''
})
defineExpose({
formData
})
</script>

View File

@@ -0,0 +1,25 @@
<template>
<div class="mb-12px">
<div class="flex text-[var(--el-text-color-primary)] justify-between items-center">
<span>{{title}}</span>
<slot name="extra"></slot>
</div>
<div class="text-[var(--el-text-color-secondary)] text-12px my-8px">
{{desc}}
</div>
<slot></slot>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'Index' })
defineProps({
title: {
type: String
},
desc: {
type: String
}
})
</script>