写在前面
很早就在b站上看到有虚拟主播的计划,之前看到的计划主要分为3种:
- ①用的unity+live2d
- ②有的用的steam的Vtube Studio这款软件
- ③也有根据galgame的。
根据纯前端和python的我好像没找到,在看到一篇文章:/post/720474… ,运用的pixi-live2d-display这个纯前端es6就能够完成前端的表情操控。不过这个没写口型的操控。关于pixi-live2d-display的口型操控,我在这个 github.com/itorr/itorr… 找到了计划。
下面介绍我完成的live2d虚拟直播姬Demo的过程,代码放在了:github.com/nladuo/live…
视频作用见B站:www.bilibili.com/video/BV1iX…
前端Live2D虚拟形象
前端的虚拟形象便是用的pixi-live2d-display,我用vite的vue模版建了一个工程(后来发现用不到vue,自己前端小白哈),首先调通了嘴型的操控,也便是经过按钮来操控嘴型闭合。
HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/dylanNew/live2d/webgl/Live2D/lib/live2d.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pixi.js@6.5.2/dist/browser/pixi.min.js"></script>
<title>Live2d display control</title>
</head>
<body>
<canvas id="canvas2" style="margin-top: 50px;"></canvas>
<button id="mbtn">张嘴</button>
<button id="mbtn2">闭嘴</button>
<script type="module" src="/src/main.js"></script>
</body>
</html>
JS代码:
import * as PIXI from 'pixi.js';
import { Live2DModel } from 'pixi-live2d-display/cubism4';
window.PIXI = PIXI;
const app = new PIXI.Application({
view: document.getElementById("canvas2"),
autoStart: true,
// resizeTo: window
});
const cubism4Model = "assets/haru/haru_greeter_t03.model3.json";
const model = await Live2DModel.from(cubism4Model);
app.stage.addChild(model);
// transforms
model.x = 900;
model.y = 0;
model.rotation = Math.PI;
model.skew.x = Math.PI;
model.scale.set(0.45);
// 设置嘴型
const setMouthOpenY = v=>{
v = Math.max(0,Math.min(1,v));
model.internalModel.coreModel.setParameterValueById('ParamMouthOpenY',v);
}
document.getElementById("mbtn").onclick = () =>{
setMouthOpenY(1)
}
document.getElementById("mbtn2").onclick = () =>{
setMouthOpenY(0)
}
这儿经过setMouthOpenY
来设置嘴型开闭,1为张嘴,0为闭嘴。
live2d模型修正
由于要操控口型,需求删掉live2d自身自带的一堆动作,模型文件删的差不多了,就剩余基本的: github.com/nladuo/live…
{
"Version": 3,
"FileReferences": {
"Moc": "haru_greeter_t03.moc3",
"Textures": [
"haru_greeter_t03.2048/texture_00.png",
"haru_greeter_t03.2048/texture_01.png"
],
"Expressions": [
],
"Motions": {
}
},
"Groups": [
{
"Target": "Parameter",
"Name": "EyeBlink",
"Ids": [
"ParamEyeLOpen",
"ParamEyeROpen"
]
}
],
"HitAreas": [
{
"Id": "HitArea",
"Name": "Head"
},
{
"Id": "HitArea2",
"Name": "Body"
}
]
}
作用
张嘴
闭嘴
音频和虚拟形象嘴型对应
我在网上搜了一些音频和口型的操控许多都是深度学习办法的,不过关于直播姬的要求我觉得没必要那么精确。
这儿我拍脑袋想了一种办法,经过声响的响度来操控口型。
这儿运用librosa得到音频的时域信息,能够看到声响的起伏随着时刻改变的情况,然起伏越大也意味着响度越大,代表张嘴越大。
这儿我挑选采样间隔为0.1秒,算法如下:
def my_tts(text, save_path):
tts = gTTS(text, lang="zh-CN")
tts.save(save_path)
def tts_and_play_audio(text):
tmp_audio_path = 'tmp.mp3'
my_tts(text, tmp_audio_path)
pygame.mixer.init()
pygame.mixer.music.load(tmp_audio_path)
pygame.mixer.music.set_volume(0.8)
x , sr = librosa.load(tmp_audio_path, sr=8000)
x = x - min(x)
x = x / max(x)
x= np.log(x) + 1
x = x / max(x) * 1.2
pygame.mixer.music.play()
s_time = time.time()
try:
for _ in range(int(len(x) / 800)):
it = x[int((time.time() - s_time) * 8000)+1]
if it < 0:
it = 0
with open("tmp.txt", "w") as f:
f.write(str(float(it)))
time.sleep(0.1)
except:
pass
time.sleep(0.1)
with open("tmp.txt", "w") as f:
f.write("0")
这儿我运用了gTTS
来做文字转声响,把tts的输出的音频经过pygame进行后台播放,同时根据时刻来操控嘴的巨细,把嘴型的巨细写到tmp.txt文件中。
前后端操控
然后写个后端不断的读取tmp.txt的嘴型巨细,前端再去恳求嘴型巨细进行操控即可。流程如下:
接入ChatGPT
最终的话便是接入ChatGPT了,这儿我用了:pypi.org/project/rev…,运用的prompt如下:
请运用女性化的语言风格,扮演一个正在直播的 vtuber,之后我的输入均为用户谈论,请用简略的一句话回答它们吧,每句话不要超越20字,而且不要运用表情,运用纯文字进行回答,不要运用emoji表情。
这儿我在ChatGPT首先先创建了一个会话窗口然后在指定的conversation_id进行直播内容互动。
from revChatGPT.V1 import Chatbot
access_token = "浏览器访问https://chat.openai.com/api/auth/session获取"
conversation_id = ""
chatbot = Chatbot(config={"access_token": access_token}, conversation_id=conversation_id)
def ask(prompt):
for data in chatbot.ask(prompt):
response = data["message"]
return response
最终作用如下:
(真实跑起来口型会动起来,而且我觉得对的还能够。)
弥补说明
gTTS的发声感觉其实不像一个直播姬(心爱的女孩子)该有的声响,能够加入VITS练习得到自己喜爱的声响【B站有许多教程这儿就不说了】,当然也能够用用别的哈。