You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »


텍스트를 입력하면 음성으로 변환해 



응답속도를 높이기 위한

_ = Task.Run(() => GetChatCompletion(command.Text));
var recVoice = _openAIService.ConvertTextToVoiceAsync(command.Text, command.Voice).Result;
_blazorCallback?.Invoke("AddMessage", new object[] { command.From, command.Text });
_blazorCallback?.Invoke("PlayAudioBytes", new object[] { recVoice, 0.5f, playType });
  • Text가 입력되면 TTS 음성파일을 준비하는 동안, LLM요청을 분리된 스레드에서 요청합니다.



private float[] ConvertMp3ToFloatArray(byte[] mp3Data)
{
    using var mp3Stream = new MemoryStream(mp3Data);
    using var mp3Reader = new Mp3FileReader(mp3Stream);

    // PCM 데이터를 float 배열로 변환
    var sampleProvider = mp3Reader.ToSampleProvider();
    var totalSamples = (int)(mp3Reader.TotalTime.TotalSeconds * mp3Reader.WaveFormat.SampleRate * mp3Reader.WaveFormat.Channels);
    var floatBuffer = new float[totalSamples];
    int samplesRead = sampleProvider.Read(floatBuffer, 0, floatBuffer.Length);

    return floatBuffer.Take(samplesRead).ToArray();
}
async function playAudioBytes(audioBytes, playbackRate, type, dotNetRef) {
    try {
        if (!audioContext || audioContext.state === 'closed') {
            audioContext = new AudioContext();
        }

        // Float32Array로 변환된 PCM 데이터 사용
        const float32Array = new Float32Array(audioBytes);

        // AudioBuffer 생성
        const audioBuffer = audioContext.createBuffer(1, float32Array.length, audioContext.sampleRate);
        audioBuffer.copyToChannel(float32Array, 0);

        // 재생
        const bufferSource = audioContext.createBufferSource();
        bufferSource.buffer = audioBuffer;
        bufferSource.playbackRate.value = playbackRate; // 재생 속도 설정
        bufferSource.connect(audioContext.destination);                

        // 재생 완료 이벤트 핸들러 추가
        bufferSource.onended = () => {            
            // 타입에 따라 추가 작업 수행
            console.log(`오디오 재생 완료 재생 타입: ${type}`);
            if (type === 1) {
                console.log("Type 1: 휴먼 재생완료~ LLM응답요청");
                if (dotNetRef && typeof dotNetRef.invokeMethodAsync === "function") {
                    dotNetRef.invokeMethodAsync("OnAudioPlaybackCompleted", 1)
                        .catch(err => console.error("Blazor 메서드 호출 OnAudioPlaybackCompleted 중 오류 발생:", err));
                }                
            } else if (type === 2) {
                console.log("Type 2: AI재생완료");
            } else if (type === 3) {
                console.log("Type 3: 사용자 정의 작업");
            }
        };

        bufferSource.start();
    } catch (err) {
        console.error("오디오 재생 중 오류 발생:", err);
    }
}



<PageTitle>WebRTC</PageTitle>
<h1>WebRTC</h1>
    <!-- 채팅창 -->
    <MudItem xs="12">
        <MudPaper Class="pa-3">
            <MudButton OnClick="StartWebRTC" Class="mt-4">
                Start WebRTC
            </MudButton>
        </MudPaper>
        <MudPaper Class="pa-3">
            <MudText Typo="Typo.subtitle1">채팅</MudText>
            <MudStack>
                <!-- 채팅 리스트 -->
                <MudList T="string">
                    @foreach (var chat in ChatMessages)
                    {
                        <MudListItem Text="@chat" Icon="@Icons.Material.Filled.Chat" />
                    }
                </MudList>
                <!-- 채팅 입력 -->
                <MudTextField @bind-Value="ChatInput" Placeholder="메시지를 입력하세요..." />
                <MudButton OnClick="SendChatMessage" Class="mt-2">전송</MudButton>
            </MudStack>
        </MudPaper>
    </MudItem>




@code {
    [JSInvokable]
    public async Task OnAudioPlaybackCompleted(int option)
    {
      MyVoiceActor.Tell(new TTSCommand()
      {
      From = "AI",
      Text = "LLM자동재생",
      Voice = "alloy"
      });
    }

    private void PlayAudioBytes(float[] voice, float speed, int playtype)
    {
      InvokeAsync(() =>
      {
      var dotNetRef = DotNetObjectReference.Create(this);
      JSRuntime.InvokeVoidAsync("playAudioBytes", voice, speed, playtype, dotNetRef);
      });
    }
}







  • No labels