mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-30 02:58:37 +08:00
feat(WebSpeechSynthesizer): add WebSpeechSynthesizer service (#4135)
* refactor: 使用主构造函数 * feat: 增加 WebSpeech 服务 * feat: 增加 WebSpeechService 服务 * doc: 增加示例 * feat: 增加回调方法 * doc: 更新示例 * doc: 更新示例 * chore: bump version 8.8.4-beta07
This commit is contained in:
parent
511a88ee72
commit
ad6ac66d62
@ -0,0 +1,19 @@
|
||||
@page "/speech/web-synthesizer"
|
||||
@inherits BootstrapComponentBase
|
||||
|
||||
<h3>@Localizer["WebSpeechTitle"]</h3>
|
||||
<h4>@Localizer["WebSpeechSubTitle"]</h4>
|
||||
|
||||
<DemoBlock Title="@Localizer["WebSpeechNormalTitle"]"
|
||||
Introduction="@Localizer["WebSpeechNormalIntro"]"
|
||||
Name="Normal">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<textarea @bind="_text" rows="6"></textarea>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 text-center">
|
||||
<SpeechWave Show="_star" ShowUsedTime="false" class="my-3"></SpeechWave>
|
||||
<Button Text="@_buttonText" OnClickWithoutRender="OnStart" IsAsync="true" Icon="fa-fw fa-solid fa-microphone"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</DemoBlock>
|
@ -0,0 +1,52 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace BootstrapBlazor.Server.Components.Samples.Speeches;
|
||||
|
||||
/// <summary>
|
||||
/// WebSpeech 组件示例代码
|
||||
/// </summary>
|
||||
public partial class WebSpeeches
|
||||
{
|
||||
[Inject, NotNull]
|
||||
private WebSpeechService? WebSpeechService { get; set; }
|
||||
|
||||
[Inject, NotNull]
|
||||
private IStringLocalizer<WebSpeeches>? Localizer { get; set; }
|
||||
|
||||
private bool _star;
|
||||
private string? _text;
|
||||
private string? _buttonText = "开始合成";
|
||||
private WebSpeechSynthesizer _entry = default!;
|
||||
private TaskCompletionSource? _tcs;
|
||||
|
||||
private async Task OnStart()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_text))
|
||||
{
|
||||
if (_entry == null)
|
||||
{
|
||||
_entry = await WebSpeechService.CreateSynthesizerAsync();
|
||||
_entry.OnEndAsync = SpeakAsync;
|
||||
}
|
||||
_tcs ??= new();
|
||||
_star = true;
|
||||
StateHasChanged();
|
||||
|
||||
await _entry.SpeakAsync(_text, "zh-CN");
|
||||
await _tcs.Task;
|
||||
_star = false;
|
||||
_tcs = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private Task SpeakAsync()
|
||||
{
|
||||
_tcs?.TrySetResult();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>8.8.4-beta06</Version>
|
||||
<Version>8.8.4-beta07</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
|
||||
|
@ -7,23 +7,12 @@ namespace BootstrapBlazor.Components;
|
||||
/// <summary>
|
||||
/// 语音识别服务
|
||||
/// </summary>
|
||||
public class RecognizerService
|
||||
public class RecognizerService(IRecognizerProvider provider)
|
||||
{
|
||||
private IRecognizerProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
public RecognizerService(IRecognizerProvider provider)
|
||||
{
|
||||
Provider = provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 语音识别回调方法
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
/// <returns></returns>
|
||||
public Task InvokeAsync(RecognizerOption option) => Provider.InvokeAsync(option);
|
||||
public Task InvokeAsync(RecognizerOption option) => provider.InvokeAsync(option);
|
||||
}
|
||||
|
@ -7,23 +7,13 @@ namespace BootstrapBlazor.Components;
|
||||
/// <summary>
|
||||
/// 语音合成服务
|
||||
/// </summary>
|
||||
public class SynthesizerService
|
||||
/// <param name="provider"></param>
|
||||
public class SynthesizerService(ISynthesizerProvider provider)
|
||||
{
|
||||
private ISynthesizerProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
public SynthesizerService(ISynthesizerProvider provider)
|
||||
{
|
||||
Provider = provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 语音合成回调方法
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
/// <returns></returns>
|
||||
public Task InvokeAsync(SynthesizerOption option) => Provider.InvokeAsync(option);
|
||||
public Task InvokeAsync(SynthesizerOption option) => provider.InvokeAsync(option);
|
||||
}
|
||||
|
30
src/BootstrapBlazor/Components/Speech/WebSpeechService.cs
Normal file
30
src/BootstrapBlazor/Components/Speech/WebSpeechService.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Web Speech 服务
|
||||
/// </summary>
|
||||
public class WebSpeechService(IJSRuntime runtime, IComponentIdGenerator ComponentIdGenerator, ILogger<WebSpeechService> logger)
|
||||
{
|
||||
private JSModule? Module { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 语音合成方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<WebSpeechSynthesizer> CreateSynthesizerAsync()
|
||||
{
|
||||
if (Module == null)
|
||||
{
|
||||
var moduleName = "./_content/BootstrapBlazor/modules/speech.js";
|
||||
logger.LogInformation("load module {moduleName}", moduleName);
|
||||
Module = await runtime.LoadModule(moduleName);
|
||||
}
|
||||
return new WebSpeechSynthesizer(Module, ComponentIdGenerator);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// WebSpeechSynthesizer 类
|
||||
/// </summary>
|
||||
public class WebSpeechSynthesizer(JSModule module, IComponentIdGenerator componentIdGenerator)
|
||||
{
|
||||
private DotNetObjectReference<WebSpeechSynthesizer>? _interop;
|
||||
|
||||
private string? _id;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 朗读结束回调方法 默认 null
|
||||
/// </summary>
|
||||
public Func<Task>? OnEndAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始朗读方法
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="lang"></param>
|
||||
public async Task SpeakAsync(string? text, string? lang = null)
|
||||
{
|
||||
_id = componentIdGenerator.Generate(this);
|
||||
_interop = DotNetObjectReference.Create(this);
|
||||
await module.InvokeVoidAsync("speak", _id, _interop, new { text, lang });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停朗读方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task Pause()
|
||||
{
|
||||
await module.InvokeVoidAsync("pause", _id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复朗读方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task Resume()
|
||||
{
|
||||
await module.InvokeVoidAsync("resume", _id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[JSInvokable]
|
||||
public async Task OnError()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[JSInvokable]
|
||||
public async Task OnEnd()
|
||||
{
|
||||
if (OnEndAsync != null)
|
||||
{
|
||||
await OnEndAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[JSInvokable]
|
||||
public async Task OnSpeaking()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
}
|
||||
}
|
@ -88,6 +88,7 @@ public static class BootstrapBlazorServiceCollectionExtensions
|
||||
services.AddScoped<ResizeNotificationService>();
|
||||
services.AddScoped<NotificationService>();
|
||||
services.AddScoped<EyeDropperService>();
|
||||
services.AddScoped<WebSpeechService>();
|
||||
|
||||
services.ConfigureBootstrapBlazorOption(configureOptions);
|
||||
|
||||
|
35
src/BootstrapBlazor/wwwroot/modules/speech.js
Normal file
35
src/BootstrapBlazor/wwwroot/modules/speech.js
Normal file
@ -0,0 +1,35 @@
|
||||
import Data from "./data.js"
|
||||
|
||||
export function speak(id, invoke, option) {
|
||||
const synth = window.speechSynthesis;
|
||||
if (synth.speaking) {
|
||||
console.error("speechSynthesis.speaking");
|
||||
invoke.invokeMethodAsync("OnSpeaking");
|
||||
return;
|
||||
}
|
||||
const { text, lang } = option;
|
||||
if (text !== "") {
|
||||
const utter = new SpeechSynthesisUtterance(text);
|
||||
if (lang) {
|
||||
utter.lang = lang;
|
||||
}
|
||||
|
||||
utter.onend = () => {
|
||||
invoke.invokeMethodAsync("OnEnd");
|
||||
};
|
||||
|
||||
utter.onerror = e => {
|
||||
console.error("SpeechSynthesisUtterance.onerror", e);
|
||||
invoke.invokeMethodAsync("OnError");
|
||||
};
|
||||
synth.speak(utter);
|
||||
}
|
||||
}
|
||||
|
||||
export function pause(id) {
|
||||
|
||||
}
|
||||
|
||||
export function resume(id) {
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user