ow
This commit is contained in:
1 parent
39494fb5c3
commit
871de41ba5
9 files changed
+259
-49
No files matched your search
@@ -3,15 +3,16 @@ using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||||
using CloudBuilder.Core.DependencyInjection.Task;
|
||||
using CloudBuilder.Topshelf.Python;
|
||||
using CloudBuilder.Topshelf.Utility;
|
||||
using System.Text.RegularExpressions;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace CloudBuilder.Topshelf.Task
|
||||
{
|
||||
//task:ChineseNameExtractorTask book_id:B000008
|
||||
//task:ChineseNameExtractorTask book_id:B000008 chapter_id:3
|
||||
public class ChineseNameExtractorTask : IScheduleTask
|
||||
{
|
||||
private readonly IApplicationService service;
|
||||
|
||||
private List<string> commonSurnames;
|
||||
public ChineseNameExtractorTask(IApplicationService service)
|
||||
{
|
||||
this.service = service;
|
||||
@@ -19,14 +20,20 @@ namespace CloudBuilder.Topshelf.Task
|
||||
|
||||
public void Run(Dictionary<string, string> bodyDict)
|
||||
{
|
||||
File.AppendAllText("log.txt", "ChineseNameExtractorTask:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
if (!bodyDict.ContainsKey("book_id")) return;
|
||||
|
||||
string guid = bodyDict["book_id"];
|
||||
string bookId = bodyDict["book_id"];
|
||||
string chapterId = string.Empty;
|
||||
if (bodyDict.ContainsKey("chapter_id"))
|
||||
chapterId = bodyDict["chapter_id"];
|
||||
|
||||
PythonCommand python = new PythonCommand(service);
|
||||
try
|
||||
{
|
||||
Hanlp2 hanlp = new Hanlp2(python);
|
||||
commonSurnames = hanlp.GetSurnames();
|
||||
|
||||
IRepository<AiSentenceViewEntity> repository = service.GetRepository<IRepository<AiSentenceViewEntity>>();
|
||||
|
||||
@@ -34,6 +41,9 @@ namespace CloudBuilder.Topshelf.Task
|
||||
|
||||
IRepository<AiChapterPersonEntity> repositoryAiChapterPersonEntity = service.GetRepository<IRepository<AiChapterPersonEntity>>();
|
||||
|
||||
AiChapterPersonEntity[] dels = repositoryAiChapterPersonEntity.DetachedEntities.Where(x => x.BookId == bookId).ToArray();
|
||||
if (dels != null && dels.Length > 0) repositoryAiChapterPersonEntity.DeleteNow(dels);
|
||||
|
||||
string depRoot;
|
||||
|
||||
List<NamedEntity> ners;
|
||||
@@ -44,7 +54,7 @@ namespace CloudBuilder.Topshelf.Task
|
||||
|
||||
SpeakerAnalysisHelper speakerAnalysisHelper = new SpeakerAnalysisHelper();
|
||||
|
||||
AiSentenceViewEntity[] ents = repository.DetachedEntities.Where(x => x.BookId == guid).OrderBy(x => x.ChapterId).ThenBy(x => x.ParagraphId).ThenBy(x => x.SentenceIndex).ToArray();
|
||||
AiSentenceViewEntity[] ents = repository.DetachedEntities.Where(x => x.BookId == bookId && (string.IsNullOrEmpty(chapterId) || x.ChapterId == Convert.ToInt32(chapterId))).OrderBy(x => x.ChapterId).ThenBy(x => x.ParagraphId).ThenBy(x => x.SentenceIndex).ToArray();
|
||||
if (ents == null || ents.Length == 0) return;
|
||||
|
||||
AiSentenceEntity aiSentenceEntity;
|
||||
@@ -70,22 +80,23 @@ namespace CloudBuilder.Topshelf.Task
|
||||
{
|
||||
if (p.Length == 1) continue;
|
||||
aiChapterPerson = new AiChapterPersonEntity();
|
||||
aiChapterPerson.PersonName = p;
|
||||
aiChapterPerson.PersonName = KeepChineseCharactersOnly(p);
|
||||
aiChapterPerson.BookId = ent.BookId;
|
||||
aiChapterPerson.ChapterId = ent.ChapterId;
|
||||
aiChapterPerson.ParagraphIndex = ent.ParagraphId;
|
||||
aiChapterPerson.SentenceIndex= ent.SentenceIndex;
|
||||
aiChapterPerson.SentenceIndex = ent.SentenceIndex;
|
||||
aiChapterPerson.DialogueIndc = ent.DialogueIndc;
|
||||
aiChapterPerson.OrderIndex = orderIndex++;
|
||||
cps.Add(aiChapterPerson);
|
||||
repositoryAiChapterPersonEntity.InsertNow(aiChapterPerson);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateProgress(processedLines, totalLines);
|
||||
ConsoleOutput.UpdateProgress(processedLines, totalLines);
|
||||
}
|
||||
|
||||
speakerAnalysisHelper.AiChapterPersons = cps.ToArray();
|
||||
|
||||
speakerAnalysisHelper.CommonSurnames = commonSurnames;
|
||||
speakerAnalysisHelper.MatchPerson(ents, repositoryAiSentenceEntity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -99,18 +110,25 @@ namespace CloudBuilder.Topshelf.Task
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateProgress(int processed, int total)
|
||||
|
||||
private string KeepChineseCharactersOnly(string input)
|
||||
{
|
||||
double progressPercent = (double)processed / total * 100;
|
||||
int progressBarLength = 50; // 进度条总长度
|
||||
int filledLength = (int)(progressPercent / 100 * progressBarLength);
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return input;
|
||||
|
||||
// 构建进度条(如:[██████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░])
|
||||
string progressBar = "[" + new string('█', filledLength) + new string('░', progressBarLength - filledLength) + "]";
|
||||
|
||||
string progressInfo = $"{progressBar} {progressPercent:F2}% | 已处理:{processed}/{total} ";
|
||||
Console.Write($"\r{progressInfo}");
|
||||
Console.Out.Flush();
|
||||
// 方法1:使用正则表达式
|
||||
//return Regex.Replace(input, @"[^\u4e00-\u9fff]", "");
|
||||
return Regex.Replace(input, @"[^\u4e00-\u9fff\【\】]", "");
|
||||
// 方法2:手动遍历(性能更好)
|
||||
// var sb = new StringBuilder();
|
||||
// foreach (char c in input)
|
||||
// {
|
||||
// if (c >= 0x4e00 && c <= 0x9fff)
|
||||
// sb.Append(c);
|
||||
// }
|
||||
// return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+35
-8
@@ -17,7 +17,7 @@ using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace CloudBuilder.Topshelf.Task.TTS
|
||||
{
|
||||
//task:TtsTask book_id:B000008 voice:Sherpa2 actor:韩立 actor_voice:Sherpa1 save_path:D:\\Net8\\FileServer\\Backup\\DmsFile\\voice
|
||||
//task:TtsTask book_id:B000008 chapter_id:3 speed:1 voice:Sherpa2 actor:韩立 actor_voice:Sherpa1 save_path:D:\\Net8\\FileServer\\Backup\\DmsFile\\voice
|
||||
//task:TtsTask voice:Sherpa2 save_path:D:\\Net8\\FileServer\\Backup\\DmsFile\\voice\\20260528112739.mp3 text:二愣子睁大着双眼,直直望着茅草和烂泥糊成的黑屋顶,身上盖着的旧棉被,已呈深黄色,看不出原来的本来面目,还若有若无的散发着淡淡的霉味。
|
||||
public class TtsTask : IScheduleTask
|
||||
{
|
||||
@@ -38,7 +38,11 @@ namespace CloudBuilder.Topshelf.Task.TTS
|
||||
if (bodyDict.ContainsKey("book_id"))
|
||||
bookId = bodyDict["book_id"];
|
||||
|
||||
AiSentenceViewEntity[] ents = repository.DetachedEntities.Where(x => x.BookId == bookId).OrderBy(x => x.ChapterId).ThenBy(x => x.ParagraphId).ThenBy(x => x.SentenceIndex).ToArray();
|
||||
string chapterId = string.Empty;
|
||||
if (bodyDict.ContainsKey("chapter_id"))
|
||||
chapterId = bodyDict["chapter_id"];
|
||||
|
||||
AiSentenceViewEntity[] ents = repository.DetachedEntities.Where(x => x.BookId == bookId && (string.IsNullOrEmpty(chapterId) || x.ChapterId == Convert.ToInt32(chapterId))).OrderBy(x => x.ChapterId).ThenBy(x => x.ParagraphId).ThenBy(x => x.SentenceIndex).ToArray();
|
||||
|
||||
if (ents == null || ents.Length == 0) return;
|
||||
|
||||
@@ -55,10 +59,15 @@ namespace CloudBuilder.Topshelf.Task.TTS
|
||||
if (bodyDict.ContainsKey("save_path"))
|
||||
save_path = bodyDict["save_path"];
|
||||
|
||||
GenerateAndMergeChapterAudio(ents, actor, actor_voice, voice, save_path);
|
||||
float speed = 1.0f;
|
||||
|
||||
if (bodyDict.ContainsKey("speed"))
|
||||
speed = Convert.ToSingle(bodyDict["speed"]);
|
||||
|
||||
GenerateAndMergeChapterAudio(ents, speed, actor, actor_voice, voice, save_path);
|
||||
}
|
||||
|
||||
public void GenerateAndMergeChapterAudio(AiSentenceViewEntity[] ents, string actor, string actor_voice, string mainVoice, string save_path)
|
||||
public void GenerateAndMergeChapterAudio(AiSentenceViewEntity[] ents, float speed, string actor, string actor_voice, string mainVoice, string save_path)
|
||||
{
|
||||
// 1. 按 BookId + ChapterId 分组(关键!)
|
||||
var chapterGroups = ents
|
||||
@@ -69,7 +78,7 @@ namespace CloudBuilder.Topshelf.Task.TTS
|
||||
int totalLines = ents.Count();
|
||||
int processedLines = 0; // 已处理行数计数器
|
||||
UpdateProgress(processedLines, totalLines);
|
||||
|
||||
Dictionary<string, string> personMapping = new Dictionary<string, string>();
|
||||
foreach (var chapter in chapterGroups)
|
||||
{
|
||||
string bookId = chapter.Key.BookId;
|
||||
@@ -85,9 +94,27 @@ namespace CloudBuilder.Topshelf.Task.TTS
|
||||
if (ent.DialogueIndc == YesNoPolicy.YES)
|
||||
{
|
||||
if (ent.PersonName == actor)
|
||||
voice = actor_voice;
|
||||
{
|
||||
if (personMapping.ContainsKey(ent.PersonName))
|
||||
voice = personMapping[ent.PersonName];
|
||||
else
|
||||
{
|
||||
voice = actor_voice;
|
||||
personMapping.Add(ent.PersonName, voice);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
voice = AI.Policy.ChineseTtsVoiceRandom.GetRandom().ToString();
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ent.PersonName) && personMapping.ContainsKey(ent.PersonName))
|
||||
voice = personMapping[ent.PersonName];
|
||||
else
|
||||
{
|
||||
voice = AI.Policy.ChineseTtsVoiceRandom.GetRandom(80).ToString();
|
||||
personMapping.Add(ent.PersonName, voice);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -102,7 +129,7 @@ namespace CloudBuilder.Topshelf.Task.TTS
|
||||
string filePath = Path.Combine(save_path, fileName);
|
||||
|
||||
// 生成音频
|
||||
SaveAudioToFileHelper.AudioToFile(EnumHelper.ToEnum<ChineseTtsVoice>(voice), ent.Content, filePath);
|
||||
SaveAudioToFileHelper.AudioToFile(EnumHelper.ToEnum<ChineseTtsVoice>(voice), speed, ent.Content, filePath);
|
||||
|
||||
tempMp3List.Add(filePath); // 加入合并列表
|
||||
|
||||
|
||||
Reference in new issue
Block a user