312
This commit is contained in:
parent
b00924a691
commit
7cf247a873
24
ShengShengBuXi.ConsoleApp/ShengShengBuXi.ConsoleApp.sln
Normal file
24
ShengShengBuXi.ConsoleApp/ShengShengBuXi.ConsoleApp.sln
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.2.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShengShengBuXi.ConsoleApp", "ShengShengBuXi.ConsoleApp.csproj", "{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FE0A1BEA-BEF1-CDEB-D076-0AD5E44F7491}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9BAF9C30-5594-4165-981C-6FACBF081E8D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -91,7 +92,99 @@ namespace ShengShengBuXi.Hubs
|
|||
/// </summary>
|
||||
private static readonly int _sentenceHistoryLimit = 20;
|
||||
|
||||
// 客户端注册信息
|
||||
private static Dictionary<string, ClientInfo> _clientsDict = new Dictionary<string, ClientInfo>();
|
||||
// 用于线程安全访问
|
||||
private static object _clientsLock = new object();
|
||||
|
||||
// 文本显示队列
|
||||
private static List<DisplayText> _displayTextList = new List<DisplayText>();
|
||||
private static object _displayTextListLock = new object();
|
||||
|
||||
// 监控文本列表
|
||||
private static List<MonitorText> _monitorTextList = new List<MonitorText>();
|
||||
private static object _monitorTextListLock = new object();
|
||||
|
||||
// 配置信息
|
||||
private static string _displayConfig = "{}";
|
||||
private static object _displayConfigLock = new object();
|
||||
|
||||
// 管理员配置保存路径
|
||||
private static readonly string ConfigDirectory = Path.Combine(Directory.GetCurrentDirectory(), "config");
|
||||
private static readonly string DisplayConfigPath = Path.Combine(ConfigDirectory, "display.json");
|
||||
|
||||
// 用于初始化配置
|
||||
static AudioHub()
|
||||
{
|
||||
// 确保配置目录存在
|
||||
if (!Directory.Exists(ConfigDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(ConfigDirectory);
|
||||
}
|
||||
|
||||
// 加载显示配置
|
||||
LoadDisplayConfig();
|
||||
}
|
||||
|
||||
// 加载显示配置
|
||||
private static void LoadDisplayConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(DisplayConfigPath))
|
||||
{
|
||||
string configJson = File.ReadAllText(DisplayConfigPath);
|
||||
lock (_displayConfigLock)
|
||||
{
|
||||
_displayConfig = configJson;
|
||||
}
|
||||
Console.WriteLine("加载显示配置成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 创建默认配置
|
||||
string defaultConfig = @"{
|
||||
""leftContainer"": {
|
||||
""turnPageHeight"": 0.8,
|
||||
""fontSize"": ""16px"",
|
||||
""typewriterSpeed"": 50
|
||||
},
|
||||
""rightContainer"": {
|
||||
""fontSize"": ""24px"",
|
||||
""fontWeight"": ""normal"",
|
||||
""fontStyle"": ""normal"",
|
||||
""typewriterSpeed"": 50
|
||||
},
|
||||
""waterEffect"": {
|
||||
""enabled"": true,
|
||||
""minInterval"": 800,
|
||||
""maxInterval"": 2000,
|
||||
""simultaneousDrops"": 3,
|
||||
""fadeOutSpeed"": 0.1,
|
||||
""centerBias"": 0.5,
|
||||
""largeDrop"": {
|
||||
""probability"": 0.2,
|
||||
""size"": 9
|
||||
}
|
||||
}
|
||||
}";
|
||||
|
||||
lock (_displayConfigLock)
|
||||
{
|
||||
_displayConfig = defaultConfig;
|
||||
}
|
||||
|
||||
// 保存默认配置
|
||||
File.WriteAllText(DisplayConfigPath, defaultConfig);
|
||||
Console.WriteLine("创建默认显示配置成功");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"加载显示配置出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化音频Hub
|
||||
/// </summary>
|
||||
|
|
@ -1328,5 +1421,76 @@ namespace ShengShengBuXi.Hubs
|
|||
_logger.LogInformation($"客户端获取当前显示模式: {Context.ConnectionId}, 类型: {clientInfo.ClientType}");
|
||||
return _configurationService.CurrentConfig.DisplayType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示配置
|
||||
/// </summary>
|
||||
/// <returns>显示配置的JSON字符串</returns>
|
||||
public string GetDisplayConfig()
|
||||
{
|
||||
lock (_displayConfigLock)
|
||||
{
|
||||
return _displayConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存显示配置
|
||||
/// </summary>
|
||||
/// <param name="configJson">配置的JSON字符串</param>
|
||||
/// <returns>是否保存成功</returns>
|
||||
public async Task<bool> SaveDisplayConfig(string configJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 尝试解析JSON以验证格式
|
||||
JsonDocument.Parse(configJson);
|
||||
|
||||
// 保存到文件
|
||||
await File.WriteAllTextAsync(DisplayConfigPath, configJson);
|
||||
|
||||
// 更新内存中的配置
|
||||
lock (_displayConfigLock)
|
||||
{
|
||||
_displayConfig = configJson;
|
||||
}
|
||||
|
||||
// 通知所有显示客户端
|
||||
await NotifyDisplayConfig();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"保存显示配置出错: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通知所有显示客户端更新配置
|
||||
/// </summary>
|
||||
private async Task NotifyDisplayConfig()
|
||||
{
|
||||
string configJson;
|
||||
lock (_displayConfigLock)
|
||||
{
|
||||
configJson = _displayConfig;
|
||||
}
|
||||
|
||||
List<string> displayClientIds = new List<string>();
|
||||
lock (_clients)
|
||||
{
|
||||
displayClientIds = _clients
|
||||
.Where(c => c.Value.ClientType.ToString() == "Display")
|
||||
.Select(c => c.Key)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
foreach (var clientId in displayClientIds)
|
||||
{
|
||||
await Clients.Client(clientId).SendAsync("ReceiveDisplayConfig", configJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
ShengShengBuXi/Models/MonitorText.cs
Normal file
60
ShengShengBuXi/Models/MonitorText.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
|
||||
namespace ShengShengBuXi.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 监控文本模型
|
||||
/// </summary>
|
||||
public class MonitorText
|
||||
{
|
||||
/// <summary>
|
||||
/// 唯一标识符
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示文本内容
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否来自真实用户(否则为系统预设文本)
|
||||
/// </summary>
|
||||
public bool IsRealUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始语音识别结果ID(如果有)
|
||||
/// </summary>
|
||||
public string RecognitionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文本优先级(真实用户优先显示)
|
||||
/// </summary>
|
||||
public int Priority => IsRealUser ? 10 : 1;
|
||||
|
||||
/// <summary>
|
||||
/// 是否处理过
|
||||
/// </summary>
|
||||
public bool IsProcessed { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 处理后的文字
|
||||
/// </summary>
|
||||
public string CompletedText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 录音文件路径
|
||||
/// </summary>
|
||||
public string RecordingPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 识别文字的文件的路径
|
||||
/// </summary>
|
||||
public string TextFilePath { get; set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -155,10 +155,7 @@
|
|||
size: 80 // 大涟漪的大小
|
||||
}
|
||||
},
|
||||
// 预设的中文句子数组
|
||||
sentences: [
|
||||
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
let currentSentenceIndex = 0; // 当前句子索引
|
||||
|
|
@ -354,6 +351,19 @@
|
|||
displayText(text);
|
||||
});
|
||||
|
||||
// 接收显示配置的处理函数
|
||||
hubConnection.on("ReceiveDisplayConfig", function (configJson) {
|
||||
console.log("收到显示配置");
|
||||
try {
|
||||
const newConfig = JSON.parse(configJson);
|
||||
// 更新全局配置
|
||||
updateConfig(newConfig);
|
||||
console.log("已更新显示配置");
|
||||
} catch (error) {
|
||||
console.error("解析显示配置失败:", error);
|
||||
}
|
||||
});
|
||||
|
||||
// 启动连接
|
||||
hubConnection.start()
|
||||
.then(function () {
|
||||
|
|
@ -362,6 +372,19 @@
|
|||
hubConnection.invoke("RegisterClient", 3, "Display")
|
||||
.then(function() {
|
||||
console.log("注册为显示客户端成功");
|
||||
// 获取显示配置
|
||||
return hubConnection.invoke("GetDisplayConfig");
|
||||
})
|
||||
.then(function(configJson) {
|
||||
if(configJson) {
|
||||
console.log("已获取显示配置");
|
||||
try {
|
||||
const config = JSON.parse(configJson);
|
||||
updateConfig(config);
|
||||
} catch (error) {
|
||||
console.error("解析显示配置失败:", error);
|
||||
}
|
||||
}
|
||||
// 开始接收显示文本
|
||||
return hubConnection.invoke("StartReceivingDisplayText");
|
||||
})
|
||||
|
|
@ -369,7 +392,7 @@
|
|||
console.log("开始接收显示文本");
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error("注册客户端失败:", err);
|
||||
console.error("客户端操作失败:", err);
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
|
|
@ -385,6 +408,67 @@
|
|||
});
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
function updateConfig(newConfig) {
|
||||
// 更新左侧容器配置
|
||||
if (newConfig.leftContainer) {
|
||||
CONFIG.leftContainer.turnPageHeight = newConfig.leftContainer.turnPageHeight || CONFIG.leftContainer.turnPageHeight;
|
||||
CONFIG.leftContainer.fontSize = newConfig.leftContainer.fontSize || CONFIG.leftContainer.fontSize;
|
||||
CONFIG.leftContainer.typewriterSpeed = newConfig.leftContainer.typewriterSpeed || CONFIG.leftContainer.typewriterSpeed;
|
||||
|
||||
// 应用字体大小到CSS
|
||||
document.documentElement.style.setProperty('--left-font-size', CONFIG.leftContainer.fontSize);
|
||||
}
|
||||
|
||||
// 更新右侧容器配置
|
||||
if (newConfig.rightContainer) {
|
||||
CONFIG.rightContainer.fontSize = newConfig.rightContainer.fontSize || CONFIG.rightContainer.fontSize;
|
||||
CONFIG.rightContainer.fontWeight = newConfig.rightContainer.fontWeight || CONFIG.rightContainer.fontWeight;
|
||||
CONFIG.rightContainer.fontStyle = newConfig.rightContainer.fontStyle || CONFIG.rightContainer.fontStyle;
|
||||
CONFIG.rightContainer.typewriterSpeed = newConfig.rightContainer.typewriterSpeed || CONFIG.rightContainer.typewriterSpeed;
|
||||
|
||||
// 应用到CSS
|
||||
document.documentElement.style.setProperty('--right-font-size', CONFIG.rightContainer.fontSize);
|
||||
document.documentElement.style.setProperty('--right-font-weight', CONFIG.rightContainer.fontWeight);
|
||||
document.documentElement.style.setProperty('--right-font-style', CONFIG.rightContainer.fontStyle);
|
||||
}
|
||||
|
||||
// 更新水波纹效果配置
|
||||
if (newConfig.waterEffect) {
|
||||
CONFIG.waterEffect.enabled = newConfig.waterEffect.enabled !== undefined ? newConfig.waterEffect.enabled : CONFIG.waterEffect.enabled;
|
||||
CONFIG.waterEffect.minInterval = newConfig.waterEffect.minInterval || CONFIG.waterEffect.minInterval;
|
||||
CONFIG.waterEffect.maxInterval = newConfig.waterEffect.maxInterval || CONFIG.waterEffect.maxInterval;
|
||||
CONFIG.waterEffect.simultaneousDrops = newConfig.waterEffect.simultaneousDrops || CONFIG.waterEffect.simultaneousDrops;
|
||||
CONFIG.waterEffect.fadeOutSpeed = newConfig.waterEffect.fadeOutSpeed || CONFIG.waterEffect.fadeOutSpeed;
|
||||
CONFIG.waterEffect.centerBias = newConfig.waterEffect.centerBias !== undefined ? newConfig.waterEffect.centerBias : CONFIG.waterEffect.centerBias;
|
||||
|
||||
if (newConfig.waterEffect.largeDrop) {
|
||||
CONFIG.waterEffect.largeDrop.probability = newConfig.waterEffect.largeDrop.probability !== undefined ?
|
||||
newConfig.waterEffect.largeDrop.probability : CONFIG.waterEffect.largeDrop.probability;
|
||||
CONFIG.waterEffect.largeDrop.size = newConfig.waterEffect.largeDrop.size || CONFIG.waterEffect.largeDrop.size;
|
||||
}
|
||||
|
||||
// 应用水波纹效果配置
|
||||
if ($('.water-effect').data('ripples')) {
|
||||
// 如果ripples已初始化,先销毁
|
||||
$('.water-effect').ripples('destroy');
|
||||
}
|
||||
|
||||
if (CONFIG.waterEffect.enabled) {
|
||||
$('.water-effect').show();
|
||||
$('.water-effect').ripples({
|
||||
resolution: 1024,
|
||||
dropRadius: 1.5,
|
||||
perturbance: 0
|
||||
});
|
||||
} else {
|
||||
$('.water-effect').hide();
|
||||
}
|
||||
}
|
||||
|
||||
console.log("配置已更新:", CONFIG);
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
$(window).ready(function () {
|
||||
$('#magazine').turn({
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="config.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\js\jquery.ripples.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
|||
25
ShengShengBuXi/config/display.json
Normal file
25
ShengShengBuXi/config/display.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"leftContainer": {
|
||||
"turnPageHeight": 0.55,
|
||||
"fontSize": "16px",
|
||||
"typewriterSpeed": 50
|
||||
},
|
||||
"rightContainer": {
|
||||
"fontSize": "40px",
|
||||
"fontWeight": "700",
|
||||
"fontStyle": "italic",
|
||||
"typewriterSpeed": 330
|
||||
},
|
||||
"waterEffect": {
|
||||
"enabled": true,
|
||||
"minInterval": 1600,
|
||||
"maxInterval": 8000,
|
||||
"simultaneousDrops": 2,
|
||||
"fadeOutSpeed": 2000,
|
||||
"centerBias": 0.6,
|
||||
"largeDrop": {
|
||||
"probability": 0.2,
|
||||
"size": 80
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user