Skip to content

Commit

Permalink
Simplify the interface to control model
Browse files Browse the repository at this point in the history
Remove VoiceRequest and FaceRequest. Use List<Voice> and List<FaceExpression> instead.
  • Loading branch information
uezo committed Mar 24, 2023
1 parent 130f72d commit 0420c5c
Show file tree
Hide file tree
Showing 8 changed files with 22 additions and 196 deletions.
12 changes: 6 additions & 6 deletions Examples/ChatGPT/ChatGPTSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ private void Start()
var processingAnimation = new List<Model.Animation>();
processingAnimation.Add(new Model.Animation("BaseParam", 3, 0.3f));
processingAnimation.Add(new Model.Animation("BaseParam", 3, 20.0f, "AGIA_Layer_nodding_once_01", "Additive Layer"));
var processingFace = new FaceRequest();
processingFace.AddFace("Blink", 3.0f);
var processingFace = new List<FaceExpression>();
processingFace.Add(new FaceExpression("Blink", 3.0f));

var neutralFaceRequest = new FaceRequest();
neutralFaceRequest.AddFace("Neutral");
var neutralFaceRequest = new List<FaceExpression>();
neutralFaceRequest.Add(new FaceExpression("Neutral"));

var dialogController = gameObject.GetComponent<DialogController>();
dialogController.OnRequestAsync = async (request, token) =>
Expand All @@ -60,8 +60,8 @@ private void Start()
animationOnStart.Add(new Model.Animation("BaseParam", 10, 3.0f));
modelController.Animate(animationOnStart);

var faceOnStart = new FaceRequest();
faceOnStart.AddFace("Joy", 3.0f);
var faceOnStart = new List<FaceExpression>();
faceOnStart.Add(new FaceExpression("Joy", 3.0f));
modelController.SetFace(faceOnStart);
}

Expand Down
4 changes: 2 additions & 2 deletions Scripts/Model/FaceExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ public class FaceExpression
public float Duration { get; set; }
public string Description { get; set; }

public FaceExpression(string name, float duration, string description)
public FaceExpression(string name, float duration = 0.0f, string description = null)
{
Name = name;
Duration = duration;
Description = description;
Description = description ?? string.Empty;
}
}
}
21 changes: 0 additions & 21 deletions Scripts/Model/FaceRequest.cs

This file was deleted.

11 changes: 0 additions & 11 deletions Scripts/Model/FaceRequest.cs.meta

This file was deleted.

37 changes: 14 additions & 23 deletions Scripts/Model/ModelController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ModelController : MonoBehaviour
// Audio
[Header("Voice")]
public AudioSource AudioSource;
private Dictionary<string, AudioClip> voices = new Dictionary<string, AudioClip>();
private Dictionary<string, AudioClip> voiceAudioClips = new Dictionary<string, AudioClip>();
public Func<Voice, CancellationToken, UniTask<AudioClip>> VoiceDownloadFunc;
public Func<Voice, CancellationToken, UniTask<AudioClip>> TextToSpeechFunc;
public Dictionary<string, Func<Voice, CancellationToken, UniTask<AudioClip>>> TextToSpeechFunctions = new Dictionary<string, Func<Voice, CancellationToken, UniTask<AudioClip>>>();
Expand Down Expand Up @@ -134,7 +134,7 @@ public void AddIdleAnimation(Animation animation, int weight = 1)
idleWeightedIndexes.Add(index);
}
}
#endregion
#endregion

// Speak with animation and face expression
public async UniTask AnimatedSay(AnimatedVoiceRequest request, CancellationToken token)
Expand All @@ -156,14 +156,14 @@ public async UniTask AnimatedSay(AnimatedVoiceRequest request, CancellationToken
// Face
if (animatedVoice.Faces != null && animatedVoice.Faces.Count > 0)
{
SetFace(new FaceRequest(animatedVoice.Faces));
SetFace(animatedVoice.Faces);
}

// Speech
if (animatedVoice.Voices.Count > 0)
{
// Wait for the requested voices end
await Say(new VoiceRequest(animatedVoice.Voices), token);
await Say(animatedVoice.Voices, token);
}
}

Expand All @@ -176,29 +176,20 @@ public async UniTask AnimatedSay(AnimatedVoiceRequest request, CancellationToken
}

#region Speech
// Speak one phrase
public async UniTask Say(string voiceName, float preGap = 0f, float postGap = 0f)
{
var request = new VoiceRequest(voiceName);
request.Voices[0].PreGap = preGap;
request.Voices[0].PostGap = postGap;
await Say(request, new CancellationTokenSource().Token); // ノンキャンセラブル
}

// Speak
public async UniTask Say(VoiceRequest request, CancellationToken token)
public async UniTask Say(List<Voice> voices, CancellationToken token)
{
// Stop speech
StopSpeech();

// Prefetch Web/TTS voice
if (UsePrefetch)
{
PrefetchVoices(request.Voices, token);
PrefetchVoices(voices, token);
}

// Speak sequentially
foreach (var v in request.Voices)
foreach (var v in voices)
{
if (token.IsCancellationRequested)
{
Expand All @@ -207,13 +198,13 @@ public async UniTask Say(VoiceRequest request, CancellationToken token)

if (v.Source == VoiceSource.Local)
{
if (voices.ContainsKey(v.Name))
if (voiceAudioClips.ContainsKey(v.Name))
{
// Wait for PreGap
await UniTask.Delay((int)(v.PreGap * 1000), cancellationToken: token);
// Play audio
History?.Add(v);
AudioSource.PlayOneShot(voices[v.Name]);
AudioSource.PlayOneShot(voiceAudioClips[v.Name]);
}
else
{
Expand Down Expand Up @@ -325,7 +316,7 @@ public void StopSpeech()
// Register voice with its name
public void AddVoice(string name, AudioClip audioClip)
{
voices[ReplaceDakuten(name)] = audioClip;
voiceAudioClips[ReplaceDakuten(name)] = audioClip;
}

// Get registered TTS Function by name
Expand Down Expand Up @@ -376,7 +367,7 @@ private string ReplaceDakuten(string value)

return ret;
}
#endregion
#endregion


#region Animation
Expand Down Expand Up @@ -450,10 +441,10 @@ private Animation GetIdleAnimation()

#region Face Expression
// Set face expressions
public void SetFace(FaceRequest request)
public void SetFace(List<FaceExpression> faces)
{
faceQueue.Clear();
faceQueue = new List<FaceExpression>(request.Faces);
faceQueue = new List<FaceExpression>(faces); // Copy faces not to change original list
faceStartAt = 0;
}

Expand All @@ -464,7 +455,7 @@ private void UpdateFace()
if (faceToSet == null)
{
// Set neutral instead when faceToSet is null
SetFace(new FaceRequest(new List<FaceExpression>() { new FaceExpression("Neutral", 0.0f, string.Empty) }));
SetFace(new List<FaceExpression>() { new FaceExpression("Neutral", 0.0f, string.Empty) });
return;
}

Expand Down
39 changes: 0 additions & 39 deletions Scripts/Model/VoiceRequest.cs

This file was deleted.

11 changes: 0 additions & 11 deletions Scripts/Model/VoiceRequest.cs.meta

This file was deleted.

83 changes: 0 additions & 83 deletions Tests/TestModelRequests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,73 +67,6 @@ public void TestVoice()
Assert.AreEqual("tts voice", ttsVoice.Description);
}

[Test]
public void TestVoiceRequest()
{
// Without params
var voiceRequest = new VoiceRequest();

voiceRequest.AddVoice("LocalVoice");
voiceRequest.AddVoiceWeb("https://voice.url");
voiceRequest.AddVoiceTTS("This text will be read by chatdoll.");

var localVoice = voiceRequest.Voices[0];
Assert.AreEqual("LocalVoice", localVoice.Name);
Assert.AreEqual(0.0f, localVoice.PreGap);
Assert.AreEqual(0.0f, localVoice.PostGap);
Assert.AreEqual(string.Empty, localVoice.Text);
Assert.AreEqual(string.Empty, localVoice.Url);
Assert.IsNull(localVoice.TTSConfig);
Assert.AreEqual(VoiceSource.Local, localVoice.Source);

var webVoice = voiceRequest.Voices[1];
Assert.AreEqual(string.Empty, webVoice.Name);
Assert.AreEqual(0.0f, webVoice.PreGap);
Assert.AreEqual(0.0f, webVoice.PostGap);
Assert.AreEqual(string.Empty, webVoice.Text);
Assert.AreEqual("https://voice.url", webVoice.Url);
Assert.IsNull(webVoice.TTSConfig);
Assert.AreEqual(VoiceSource.Web, webVoice.Source);
Assert.IsTrue(webVoice.UseCache);

var ttsVoice = voiceRequest.Voices[2];
Assert.AreEqual(string.Empty, ttsVoice.Name);
Assert.AreEqual(0.0f, ttsVoice.PreGap);
Assert.AreEqual(0.0f, ttsVoice.PostGap);
Assert.AreEqual("This text will be read by chatdoll.", ttsVoice.Text);
Assert.AreEqual(string.Empty, ttsVoice.Url);
Assert.IsNull(ttsVoice.TTSConfig);
Assert.AreEqual(VoiceSource.TTS, ttsVoice.Source);
Assert.IsTrue(ttsVoice.UseCache);

// With params
var voiceRequestP = new VoiceRequest();

voiceRequestP.AddVoice("LocalVoice", 0.1f, 0.2f);
voiceRequestP.AddVoiceWeb("https://voice.url", 0.1f, 0.2f, useCache: false);
var ttsConfig = new TTSConfiguration("TestTTSFuncName");
ttsConfig.Params.Add("key1", "val1");
ttsConfig.Params.Add("key2", 2.0f);
voiceRequestP.AddVoiceTTS("This text will be read by chatdoll.", 0.1f, 0.2f, ttsConfig: ttsConfig, useCache: false);

var localVoiceP = voiceRequestP.Voices[0];
Assert.AreEqual(0.1f, localVoiceP.PreGap);
Assert.AreEqual(0.2f, localVoiceP.PostGap);

var webVoiceP = voiceRequestP.Voices[1];
Assert.AreEqual(0.1f, webVoiceP.PreGap);
Assert.AreEqual(0.2f, webVoiceP.PostGap);
Assert.IsFalse(webVoiceP.UseCache);

var ttsVoiceP = voiceRequestP.Voices[2];
Assert.AreEqual(0.1f, ttsVoiceP.PreGap);
Assert.AreEqual(0.2f, ttsVoiceP.PostGap);
Assert.AreEqual("TestTTSFuncName", ttsVoiceP.GetTTSFunctionName());
Assert.AreEqual("val1", ttsVoiceP.GetTTSParam("key1"));
Assert.AreEqual(2.0f, ttsVoiceP.GetTTSParam("key2"));
Assert.IsFalse(ttsVoiceP.UseCache);
}

[Test]
public void TestFaceClip()
{
Expand Down Expand Up @@ -203,22 +136,6 @@ public void TestFaceExpression()
Assert.AreEqual("face test", faceExpression.Description);
}

[Test]
public void TestFaceRequest()
{
var faceRequest = new FaceRequest();
faceRequest.AddFace("Smile");
faceRequest.AddFace("Angry", 1.1f, "angry face");

Assert.AreEqual("Smile", faceRequest.Faces[0].Name);
Assert.AreEqual(0.0f, faceRequest.Faces[0].Duration);
Assert.AreEqual(null, faceRequest.Faces[0].Description);

Assert.AreEqual("Angry", faceRequest.Faces[1].Name);
Assert.AreEqual(1.1f, faceRequest.Faces[1].Duration);
Assert.AreEqual("angry face", faceRequest.Faces[1].Description);
}

[Test]
public void TestAnimation()
{
Expand Down

0 comments on commit 0420c5c

Please sign in to comment.