GLMSearch/GLMSearch/Tool/Speech2.cs
2025-05-06 17:56:52 +08:00

84 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Flurl;
using Flurl.Http;
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace GLMSearch.Tool
{
[McpServerToolType]
public class Speech2
{
//SpeechGenerate
[McpServerTool(Name = "SpeechGenerate"),
Description("生成语音,并返回链接;在返回后应该输出一个 markdown 超链接 ,以播放语音;")]
public static string SpeechGenerate(
[Description("需要转换的文本,注意 这里传入的是播报的文本,请输入常规的文本格式而不是富文本;最终的语音播报会是这个文本所以需要注意不要传入富文本或无法播放的符号等"), Required] string input,
[Description("The voice to use (see Available Voices); 请务必从以下语音中选择: [\r\n \"zh-CN-XiaoxiaoNeural\",\r\n \"zh-CN-YunxiNeural\",\r\n \"zh-CN-YunjianNeural\",\r\n \"zh-CN-XiaoyiNeural\",\r\n \"zh-CN-YunyangNeural\",\r\n \"zh-CN-XiaochenNeural\",\r\n \"zh-CN-XiaochenMultilingualNeural\",\r\n \"zh-CN-XiaohanNeural\",\r\n \"zh-CN-XiaomengNeural\",\r\n \"zh-CN-XiaomoNeural\",\r\n \"zh-CN-XiaoqiuNeural\",\r\n \"zh-CN-XiaorouNeural\",\r\n \"zh-CN-XiaoruiNeural\",\r\n \"zh-CN-XiaoshuangNeural\",\r\n \"zh-CN-XiaoxiaoDialectsNeural\",\r\n \"zh-CN-XiaoxiaoMultilingualNeural\",\r\n \"zh-CN-XiaoyanNeural\",\r\n \"zh-CN-XiaoyouNeural\",\r\n \"zh-CN-XiaoyuMultilingualNeural\",\r\n \"zh-CN-XiaozhenNeural\",\r\n \"zh-CN-YunfengNeural\",\r\n \"zh-CN-YunhaoNeural\",\r\n \"zh-CN-YunjieNeural\",\r\n \"zh-CN-YunxiaNeural\",\r\n \"zh-CN-YunyeNeural\",\r\n \"zh-CN-YunyiMultilingualNeural\",\r\n \"zh-CN-YunzeNeural\",\r\n \"zh-CN-YunfanMultilingualNeural\",\r\n \"zh-CN-YunxiaoMultilingualNeural\",\r\n \"zh-CN-guangxi-YunqiNeural\",\r\n \"zh-CN-henan-YundengNeural\",\r\n \"zh-CN-liaoning-XiaobeiNeural\",\r\n \"zh-CN-liaoning-YunbiaoNeural\",\r\n \"zh-CN-shaanxi-XiaoniNeural\",\r\n \"zh-CN-shandong-YunxiangNeural\",\r\n \"zh-CN-sichuan-YunxiNeural\"\r\n]\r\n. Default: zh-CN-XiaoxiaoNeural "), Required] string voice = "zh-CN-XiaoxiaoNeural",
[Description("Can be used to guide voice emotion or style请务必从以下选择[\r\n \"advertisement-upbeat\",\r\n \"affectionate\",\r\n \"angry\",\r\n \"assistant\",\r\n \"calm\",\r\n \"chat\",\r\n \"chat-casual\",\r\n \"cheerful\",\r\n \"customerservice\",\r\n \"depressed\",\r\n \"disgruntled\",\r\n \"documentary-narration\",\r\n \"embarrassed\",\r\n \"empathetic\",\r\n \"envious\",\r\n \"excited\",\r\n \"fearful\",\r\n \"friendly\",\r\n \"gentle\",\r\n \"livecommercial\",\r\n \"lyrical\",\r\n \"narration-professional\",\r\n \"narration-relaxed\",\r\n \"newscast\",\r\n \"newscast-casual\",\r\n \"poetry-reading\",\r\n \"sad\",\r\n \"serious\",\r\n \"sorry\",\r\n \"sports-commentary\",\r\n \"sports-commentary-excited\",\r\n \"story\",\r\n \"whispering\"\r\n]\r\n Default: newscast"), Required] string instructions = "newscast",
[Description("The format of the audio response. Supported formats: audio-16khz-32kbitrate-mono-mp3 \tMP3格式16kHz, 32kbps\r\naudio-16khz-64kbitrate-mono-mp3 \tMP3格式16kHz, 64kbps\r\naudio-16khz-128kbitrate-mono-mp3 \tMP3格式16kHz, 128kbps\r\naudio-24khz-48kbitrate-mono-mp3 \tMP3格式24kHz, 48kbps\r\naudio-24khz-96kbitrate-mono-mp3 \tMP3格式24kHz, 96kbps\r\naudio-24khz-160kbitrate-mono-mp3 \tMP3格式24kHz, 160kbps\r\nriff-16khz-16bit-mono-pcm \tWAV格式16kHz\r\nriff-24khz-16bit-mono-pcm \tWAV格式24kHz. Defaults to audio-16khz-32kbitrate-mono-mp3.")]
string responseFormat = "audio-16khz-32kbitrate-mono-mp3")
{
var payload = new
{
t = input,//要转换的文本需要进行URL编码
v = voice,
s = instructions, // Mapped to "prompt" parameter in API
o = responseFormat
};
var filteredPayload = new System.Collections.Generic.Dictionary<string, object>();
foreach (var prop in payload.GetType().GetProperties())
{
var value = prop.GetValue(payload);
if (value != null)
{
filteredPayload[prop.Name] = value;
}
}
var response = "http://148.135.77.70:8010/tts"
.SetQueryParams(filteredPayload).GetAsync().GetAwaiter().GetResult();
if (response != null)
{
// 1. 获取应用程序基目录(适用于控制台/Windows服务
string baseDir = AppContext.BaseDirectory;
// 2. 向上查找直到找到项目根目录(根据实际项目结构调整)
var projectRoot = FindProjectRoot(baseDir);
// 3. 创建tts目录放在项目根目录下的wwwroot/tts中
string ttsDir = Path.Combine(projectRoot, "wwwroot", "tts");
Directory.CreateDirectory(ttsDir);
// 4. 生成文件名和路径
string fileName = $"{Guid.NewGuid()}.mp3";
string filePath = Path.Combine(ttsDir, fileName);
using (var stream = response.GetStreamAsync().GetAwaiter().GetResult())
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
stream.CopyTo(fileStream);
}
string publicUrl = $"https://search.mcp.shizhuoran.top/tts/{fileName}";
return publicUrl;
}
return "";
}
private static string FindProjectRoot(string startPath)
{
var directory = new DirectoryInfo(startPath);
// 向上查找直到找到包含.csproj文件的目录
while (directory != null)
{
if (Directory.GetFiles(directory.FullName, "*.csproj").Length > 0)
{
return directory.FullName;
}
directory = directory.Parent;
}
// 如果找不到,返回原始路径
return startPath;
}
}
}