语音转文字脚本
本文介绍了一个基于Unity的语音交互系统实现方案。系统整合了Whisper语音识别和NobodyWho对话AI插件,主要功能包括:通过麦克风录制用户语音(最长30秒),实时显示录音进度条;将语音转为文字后显示在玩家输入框,并带有打字机效果;调用AI评委生成回复,在独立文本框中逐步显示响应内容。代码结构清晰,包含录音控制、语音识别、AI交互和UI更新等模块,实现了完整的语音输入到AI响应的交互流程
我们需要插件nobodywho,whisper,ui配置如下:两个text专门负责人说话文字,ai文字回答,一个滑动条slider代表说话倒计时,一个button负责录音,两个空物体挂载这两个对应的插件
代码如下
using UnityEngine;
using UnityEngine.UI;
using Whisper;
using Whisper.Utils;
using System.Collections;
using System.Diagnostics;
using System.Threading.Tasks;
using NobodyWho;
public class VoiceToText : MonoBehaviour
{
[Header("核心组件")]
public WhisperManager whisperManager;
// 1. 将原来的 resultText 拆分为输入和输出两个 Text 组件
public Text playerInputText; // 专门显示玩家说的话(语音识别结果)
public Text aiResponseText; // 专门显示 AI 评委的回复
[SerializeField] private Chat nobodyWhoChat;
[Header("录音设置")]
public float maxRecordTime = 30f;
public Slider recordProgressSlider;
public Button recordButton;
[Header("打字机效果设置")]
[Range(1f, 50f)]
public float charsPerSecond = 20f;
// 私有变量
private MicrophoneRecord microphoneRecord;
private bool isRecording;
private float recordTimer;
private Coroutine progressCoroutine;
private Coroutine typewriterCoroutine;
void Start()
{
microphoneRecord = GetComponent<MicrophoneRecord>();
if (microphoneRecord == null)
microphoneRecord = gameObject.AddComponent<MicrophoneRecord>();
microphoneRecord.OnRecordStop += OnRecordStop;
if (recordProgressSlider != null)
{
recordProgressSlider.minValue = 0f;
recordProgressSlider.maxValue = maxRecordTime;
recordProgressSlider.value = 0f;
}
if (recordButton != null)
recordButton.onClick.AddListener(OnButtonPressed);
if (nobodyWhoChat != null)
{
nobodyWhoChat.StartWorker();
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
StartRecording();
if (Input.GetKeyUp(KeyCode.P) && isRecording)
StopRecording();
}
public void OnButtonPressed()
{
if (!isRecording) StartRecording();
else StopRecording();
}
void StartRecording()
{
if (isRecording) return;
microphoneRecord.StartRecord();
isRecording = true;
recordTimer = 0f;
if (progressCoroutine != null) StopCoroutine(progressCoroutine);
progressCoroutine = StartCoroutine(UpdateProgressBar());
if (typewriterCoroutine != null)
{
StopCoroutine(typewriterCoroutine);
typewriterCoroutine = null;
}
playerInputText.text = "🎤 录音中,请说话...";
UnityEngine.Debug.Log("开始录音");
}
void StopRecording()
{
if (!isRecording) return;
microphoneRecord.StopRecord();
isRecording = false;
if (progressCoroutine != null)
{
StopCoroutine(progressCoroutine);
progressCoroutine = null;
}
if (recordProgressSlider != null)
recordProgressSlider.value = 0f;
playerInputText.text = "⏳ 识别中,请稍后...";
}
IEnumerator UpdateProgressBar()
{
while (isRecording && recordTimer < maxRecordTime)
{
recordTimer += Time.deltaTime;
if (recordProgressSlider != null)
recordProgressSlider.value = recordTimer;
if (recordTimer >= maxRecordTime)
{
StopRecording();
yield break;
}
yield return null;
}
}
private async void OnRecordStop(AudioChunk recordedAudio)
{
var sw = new Stopwatch();
sw.Start();
var res = await whisperManager.GetTextAsync(
recordedAudio.Data,
recordedAudio.Frequency,
recordedAudio.Channels
);
if (res == null || string.IsNullOrEmpty(res.Result))
{
playerInputText.text = "❌ 识别失败,请重试。";
return;
}
string playerSpeech = res.Result;
var time = sw.ElapsedMilliseconds;
var rate = recordedAudio.Length / (time * 0.001f);
UnityEngine.Debug.Log($"识别耗时: {time} ms, 实时率: {rate:F1}x");
UnityEngine.Debug.Log($"玩家说: {playerSpeech}");
// 2. 在玩家的输入框中显示打字机效果
if (typewriterCoroutine != null) StopCoroutine(typewriterCoroutine);
typewriterCoroutine = StartCoroutine(TypewriterEffect($"你说:{playerSpeech}", playerInputText));
// 清空 AI 的回复框,准备接收新回复
aiResponseText.text = "";
await CallAIAsync(playerSpeech);
}
private async Task CallAIAsync(string playerMessage)
{
await Task.Delay(500);
// 3. 将 "评委思考中..." 提示显示在 AI 回复框中
aiResponseText.text = "评委思考中...";
bool isFirstChunk = true;
nobodyWhoChat.responseUpdated.RemoveAllListeners();
nobodyWhoChat.responseFinished.RemoveAllListeners();
nobodyWhoChat.responseUpdated.AddListener((token) =>
{
if (isFirstChunk)
{
// 第一次收到数据时,清除“思考中”提示,并加上“评委:”
aiResponseText.text = "评委:";
isFirstChunk = false;
}
// 4. 将 AI 的回复追加到 AI 回复框中
aiResponseText.text += token;
});
nobodyWhoChat.responseFinished.AddListener((fullResponse) =>
{
UnityEngine.Debug.Log("AI评委已完成回复");
});
nobodyWhoChat.Say(playerMessage);
}
// 5. 修改打字机协程,让它支持指定要更新的 Text 组件
IEnumerator TypewriterEffect(string fullText, Text targetText)
{
targetText.text = "";
float delay = 1f / charsPerSecond;
foreach (char c in fullText)
{
targetText.text += c;
yield return new WaitForSeconds(delay);
}
typewriterCoroutine = null;
}
void OnDestroy()
{
if (nobodyWhoChat != null)
{
nobodyWhoChat.responseUpdated.RemoveAllListeners();
nobodyWhoChat.responseFinished.RemoveAllListeners();
}
}
}
更多推荐
所有评论(0)