fix: ТТС снова выдает правильные голоса
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
using Content.Server._White.TTS;
|
||||
using Content.Shared.Humanoid;
|
||||
|
||||
namespace Content.Server.Humanoid;
|
||||
|
||||
public sealed partial class HumanoidAppearanceSystem
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public void SetTTSVoice(EntityUid uid, string voiceId, HumanoidAppearanceComponent humanoid)
|
||||
{
|
||||
if (!TryComp<TTSComponent>(uid, out var comp))
|
||||
return;
|
||||
|
||||
humanoid.Voice = voiceId;
|
||||
comp.VoicePrototypeId = voiceId;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
namespace Content.Server._White.TTS;
|
||||
|
||||
public sealed class TTSAnnouncementEvent : EntityEventArgs
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class TTSAnnouncementEvent(string message, string voiceId, EntityUid source, bool global)
|
||||
: EntityEventArgs
|
||||
{
|
||||
public readonly string Message;
|
||||
public readonly bool Global;
|
||||
public readonly string VoiceId;
|
||||
public readonly EntityUid Source;
|
||||
|
||||
public TTSAnnouncementEvent(string message, string voiceId, EntityUid source , bool global)
|
||||
{
|
||||
Message = message;
|
||||
Global = global;
|
||||
VoiceId = voiceId;
|
||||
Source = source;
|
||||
}
|
||||
}
|
||||
public readonly string Message = message;
|
||||
public readonly bool Global = global;
|
||||
public readonly string VoiceId = voiceId;
|
||||
public readonly EntityUid Source = source;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Shared._White.TTS;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server._White.TTS;
|
||||
|
||||
/// <summary>
|
||||
/// Apply TTS for entity chat say messages
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed partial class TTSComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Prototype of used voice for TTS.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("voice", customTypeSerializer:typeof(PrototypeIdSerializer<TTSVoicePrototype>))]
|
||||
public string VoicePrototypeId { get; set; } = "Eugene";
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared._White;
|
||||
using Prometheus;
|
||||
using Robust.Shared.Configuration;
|
||||
@@ -18,9 +17,9 @@ public sealed class TTSManager
|
||||
private static readonly Histogram RequestTimings = Metrics.CreateHistogram(
|
||||
"tts_req_timings",
|
||||
"Timings of TTS API requests",
|
||||
new HistogramConfiguration()
|
||||
new HistogramConfiguration
|
||||
{
|
||||
LabelNames = new[] {"type"},
|
||||
LabelNames = new[] { "type" },
|
||||
Buckets = Histogram.ExponentialBuckets(.1, 1.5, 10),
|
||||
});
|
||||
|
||||
@@ -55,7 +54,12 @@ public sealed class TTSManager
|
||||
/// <param name="text">SSML formatted text</param>
|
||||
/// <returns>OGG audio bytes</returns>
|
||||
/// <exception cref="Exception">Throws if url or token CCVar not set or http request failed</exception>
|
||||
public async Task<byte[]?> ConvertTextToSpeech(string speaker, string text, string pitch, string rate, string? effect = null)
|
||||
public async Task<byte[]?> ConvertTextToSpeech(
|
||||
string speaker,
|
||||
string text,
|
||||
string pitch,
|
||||
string rate,
|
||||
string? effect = null)
|
||||
{
|
||||
var url = _cfg.GetCVar(WhiteCVars.TtsApiUrl);
|
||||
var maxCacheSize = _cfg.GetCVar(WhiteCVars.TtsMaxCacheSize);
|
||||
@@ -96,7 +100,7 @@ public sealed class TTSManager
|
||||
|
||||
var soundData = await response.Content.ReadAsByteArrayAsync(cts.Token);
|
||||
|
||||
if(_cache.Count > maxCacheSize)
|
||||
if (_cache.Count > maxCacheSize)
|
||||
{
|
||||
_cache.Remove(_cache.Last().Key);
|
||||
}
|
||||
@@ -104,7 +108,9 @@ public sealed class TTSManager
|
||||
_cache.Add(cacheKey, soundData);
|
||||
CachedCount.Inc();
|
||||
|
||||
_sawmill.Debug($"Generated new sound for '{text}' speech by '{speaker}' speaker ({soundData.Length} bytes)");
|
||||
_sawmill.Debug(
|
||||
$"Generated new sound for '{text}' speech by '{speaker}' speaker ({soundData.Length} bytes)");
|
||||
|
||||
RequestTimings.WithLabels("Success").Observe((DateTime.UtcNow - reqTime).TotalSeconds);
|
||||
|
||||
return soundData;
|
||||
@@ -149,7 +155,7 @@ public sealed class TTSManager
|
||||
private string GenerateCacheKey(string speaker, string text)
|
||||
{
|
||||
var key = $"{speaker}/{text}";
|
||||
byte[] keyData = Encoding.UTF8.GetBytes(key);
|
||||
var keyData = Encoding.UTF8.GetBytes(key);
|
||||
var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
var bytes = sha256.ComputeHash(keyData);
|
||||
return Convert.ToHexString(bytes);
|
||||
@@ -187,4 +193,4 @@ public sealed class TTSManager
|
||||
[JsonPropertyName("audio")]
|
||||
public string Audio { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using Content.Server.Station.Systems;
|
||||
using Content.Shared._White.TTS;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared._White;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
@@ -31,7 +30,6 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly TTSPitchRateSystem _ttsPitchRateSystem = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
|
||||
private const int MaxMessageChars = 100 * 2; // same as SingleBubbleCharLimit * 2
|
||||
@@ -44,7 +42,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
_cfg.OnValueChanged(WhiteCVars.TtsApiUrl, url => _apiUrl = url, true);
|
||||
|
||||
SubscribeLocalEvent<TransformSpeechEvent>(OnTransformSpeech);
|
||||
SubscribeLocalEvent<TTSComponent, EntitySpokeEvent>(OnEntitySpoke);
|
||||
SubscribeLocalEvent<SharedTTSComponent, EntitySpokeEvent>(OnEntitySpoke);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);
|
||||
|
||||
SubscribeLocalEvent<TTSAnnouncementEvent>(OnAnnounceRequest);
|
||||
@@ -80,37 +78,37 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
|
||||
foreach (var player in filter.Recipients)
|
||||
{
|
||||
if (player.AttachedEntity != null)
|
||||
if (player.AttachedEntity == null)
|
||||
continue;
|
||||
|
||||
// Get emergency lights in range to broadcast from
|
||||
var entities = _lookup.GetEntitiesInRange(player.AttachedEntity.Value, 30f)
|
||||
.Where(HasComp<EmergencyLightComponent>)
|
||||
.ToList();
|
||||
|
||||
if (entities.Count == 0)
|
||||
return;
|
||||
|
||||
// Get closest emergency light
|
||||
var entity = entities.First();
|
||||
var range = new Vector2(100f);
|
||||
|
||||
foreach (var item in entities)
|
||||
{
|
||||
// Get emergency lights in range to broadcast from
|
||||
var entities = _lookup.GetEntitiesInRange(player.AttachedEntity.Value, 30f)
|
||||
.Where(HasComp<EmergencyLightComponent>)
|
||||
.ToList();
|
||||
var itemSource = _xforms.GetWorldPosition(Transform(item));
|
||||
var playerSource = _xforms.GetWorldPosition(Transform(player.AttachedEntity.Value));
|
||||
|
||||
if (entities.Count == 0)
|
||||
return;
|
||||
var distance = playerSource - itemSource;
|
||||
|
||||
// Get closest emergency light
|
||||
var entity = entities.First();
|
||||
var range = new Vector2(100f);
|
||||
|
||||
foreach (var item in entities)
|
||||
if (range.Length() > distance.Length())
|
||||
{
|
||||
var itemSource = _xforms.GetWorldPosition(Transform(item));
|
||||
var playerSource = _xforms.GetWorldPosition(Transform(player.AttachedEntity.Value));
|
||||
|
||||
var distance = playerSource - itemSource;
|
||||
|
||||
if (range.Length() > distance.Length())
|
||||
{
|
||||
range = distance;
|
||||
entity = item;
|
||||
}
|
||||
range = distance;
|
||||
entity = item;
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(entity), soundData, true), Filter.SinglePlayer(player),
|
||||
false);
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(entity), soundData, true), Filter.SinglePlayer(player),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +119,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
return;
|
||||
|
||||
if (!_playerManager.TryGetSessionByChannel(ev.MsgChannel, out var session) ||
|
||||
!_prototypeManager.TryIndex<TTSVoicePrototype>(ev.VoiceId, out var protoVoice))
|
||||
!_prototypeManager.TryIndex(ev.VoiceId, out var protoVoice))
|
||||
return;
|
||||
|
||||
var soundData = await GenerateTTS(ev.Uid, ev.Text, protoVoice.Speaker);
|
||||
@@ -129,7 +127,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
RaiseNetworkEvent(new PlayTTSEvent(GetNetEntity(ev.Uid), soundData, false), Filter.SinglePlayer(session), false);
|
||||
}
|
||||
|
||||
private async void OnEntitySpoke(EntityUid uid, TTSComponent component, EntitySpokeEvent args)
|
||||
private async void OnEntitySpoke(EntityUid uid, SharedTTSComponent component, EntitySpokeEvent args)
|
||||
{
|
||||
if (!_isEnabled ||
|
||||
args.Message.Length > MaxMessageChars)
|
||||
@@ -145,7 +143,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, voiceEv);
|
||||
voiceId = voiceEv.VoiceId;
|
||||
|
||||
if (!_prototypeManager.TryIndex<TTSVoicePrototype>(voiceId, out var protoVoice))
|
||||
if (!_prototypeManager.TryIndex(voiceId, out var protoVoice))
|
||||
return;
|
||||
|
||||
var message = FormattedMessage.RemoveMarkup(args.Message);
|
||||
|
||||
Reference in New Issue
Block a user