CloudBuilder/CloudBuilder.AI.Service/AiBookService.auto.cs
owenchen 996bb243df ow
2026-06-22 17:02:13 +08:00

404 lines
16 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 CliWrap;
using CloudBuilder.AI.Data;
using CloudBuilder.AI.Entity;
using CloudBuilder.AI.Policy;
using CloudBuilder.AI.SearchCriteria;
using CloudBuilder.AI.Utility;
using CloudBuilder.Core.DatabaseAccessor;
using CloudBuilder.Core.DatabaseAccessor.Entity;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Data;
using CloudBuilder.Security.Entity;
using CloudBuilder.Security.Policy;
using CloudBuilder.Security.Service;
using CloudBuilder.Security.Utility;
using DocumentFormat.OpenXml.ExtendedProperties;
using DocumentFormat.OpenXml.Presentation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics.Contracts;
using System.IO;
using System.Net;
using System.Text;
using System.Transactions;
namespace CloudBuilder.AI.Service
{
public class AiBookService : IAiBookService
{
private readonly IApplicationService service;
private IRepository<AiBookEntity> repository;
public AiBookService(IApplicationService service)
{
this.service = service;
repository = service.GetRepository<IRepository<AiBookEntity>>();
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public AiBookData FindByKey(string key)
{
AiBookData data = new AiBookData();
data.AiBook = repository.DetachedEntities.Where(x => x.BookId == key).FirstOrDefault()!;
if (data.AiBook.FileId > 0)
{
IRepository<BookDmsFileViewEntity> repositoryUploadDmsFile = service.GetRepository<IRepository<BookDmsFileViewEntity>>();
BookDmsFileViewEntity dms;
dms = repositoryUploadDmsFile.DetachedEntities.Where(x => x.FileId == data.AiBook.FileId).FirstOrDefault()!;
data.FileName = dms.OrgFileName;
}
return data;
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public AiBookEntity FindByTitle(string title)
{
return repository.DetachedEntities.Where(x => x.Title == title).FirstOrDefault()!;
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public AiBookResultData FindBySearchCriteria(AiBookSearchCriteria criteria)
{
AiBookResultData data = new AiBookResultData();
AiBookEntity[] list = null;
int count = 0;
string sqlWhere = null;
if (criteria.Filter != null && criteria.Filter.Length > 0)
{
sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter);
}
AiBookEntity entity = AiBookEntity.GetInstance();
string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere);
string err = null;
try
{
list = repository.FromSql(sql).ToArray();
}
catch (System.Exception ex)
{
err = ex.Message;
}
if (list != null && list.Length > 0)
{
sql = entity.GetSelectCountFrom(sqlWhere);
count = (int)repository.ExecuteScalar(sql);
}
data.Limit = criteria.limit;
data.Page = criteria.page;
data.Datas = list;
data.Total = count;
//data.Sql = sql;
data.ErrorMessage = err;
return data;
}
//[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Print)]
public dynamic PrintBySearchCriteria(AiBookSearchCriteria criteria)
{
throw new NotImplementedException();
}
//[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Insert)]
//[UnitOfWork]
//public AiBookEntity Insert(AiBookEntity data)
//{
// throw new NotImplementedException();
//}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Insert)]
[UnitOfWork]
public AiBookData Insert(AiBookData data)
{
AiBookEntity entity = repository.DetachedEntities.Where(x => x.Title == data.AiBook.Title).FirstOrDefault();
if (entity != null)
{
throw new ValidatedException("记录已存在.");
}
ISecurityGeneratorNumberService securityGeneratorNumberService = service.ServiceProvider.GetService<ISecurityGeneratorNumberService>()!;
data.AiBook.BookId = securityGeneratorNumberService.GetNo(AIPrefixPolicy.AI_BOOK, AIPrefixPolicy.GUID, AIPrefixPolicy.AI_BOOK_PREFIX, YesNoPolicy.NO, AIPrefixPolicy.AI_BOOK_GUID_FORMAT);
repository.InsertNow(data.AiBook);
IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
if (data.AiChapters != null && data.AiChapters.Length > 0)
repositoryAiChapterEntity.InsertNow(data.AiChapters);
return data;
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
[UnitOfWork]
public AiBookData Update(AiBookData data)
{
AiBookEntity aiBook = repository.DetachedEntities.Where(x => x.BookId == data.AiBook.BookId).FirstOrDefault();
if (aiBook == null)
{
throw new ValidatedException("记录不存在.");
}
ValidateHelper.Validate(service, data.AiBook, AiBookEntity.DB_NAME_AI_BOOK);
ObjectCopyHelper.Copy(data.AiBook, aiBook);
repository.UpdateNow(aiBook);
return data;
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Delete)]
[UnitOfWork]
public void Delete(string key)
{
var ent = repository.DetachedEntities.Where(x => x.BookId == key).FirstOrDefault()!;
if (ent != null) { repository.DeleteNow(ent); }
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Delete)]
[UnitOfWork]
public void Deletes(string[] keys)
{
foreach (string key in keys)
{
Delete(key);
}
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
[UnitOfWork]
public AiBookData ProcessBook(string key, string encoding, string pattern)
{
AiBookData data = FindByKey(key);
ChapterSplitter chapterSplitter = new ChapterSplitter();
ParagraphSplitter paragraphSplitter = new ParagraphSplitter();
IRepository<DmsFileEntity> repositoryDmsFile = repository.GetRepository<IRepository<DmsFileEntity>>();
DmsFileEntity entity = repositoryDmsFile.DetachedEntities.Where(x => x.FileId == data.AiBook.FileId && x.CreatedBy == service.UserId).FirstOrDefault()!;
if (entity == null) throw new ValidatedException("文件不存在.");
var fileExtension = Path.GetExtension(entity.OrderKey);//获取文件格式,拓展名
string file = FileTypePolicy.PackFilePath(service, entity.CreatedBy, entity.OrderKey);
if (!File.Exists(file)) throw new ValidatedException("文件不存在.");
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
string context = File.ReadAllText(file, Encoding.GetEncoding(encoding));
List<AiChapterDisplayData> aiChapterEntities = chapterSplitter.SplitNovelIntoChapters(context, pattern);
if (aiChapterEntities == null || aiChapterEntities.Count() == 0) return data;
int chapterIndex = 1;
foreach (var chapter in aiChapterEntities)
{
chapter.ChapterId = chapterIndex++;
chapter.BookId = data.AiBook.BookId;
chapter.Status = ChapterStatusPolicy.PROCESS;
}
data.AiChapters = aiChapterEntities.ToArray();
paragraphSplitter.PackParagraphs(data);
IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
IRepository<AiSentenceEntity> repositoryAiSentenceEntity = repository.GetRepository<IRepository<AiSentenceEntity>>();
AiChapterEntity[] aiChapters = repositoryAiChapterEntity.DetachedEntities.Where(x => x.BookId == data.AiBook.BookId).ToArray();
if (aiChapters != null && aiChapters.Length > 0)
{
AiSentenceEntity[] aiSentences = repositoryAiSentenceEntity.DetachedEntities.Where(x => x.BookId == data.AiBook.BookId).ToArray();
if (aiSentences != null && aiSentences.Length > 0)
{
repositoryAiSentenceEntity.DeleteNow(aiSentences);
}
repositoryAiChapterEntity.DeleteNow(aiChapters);
}
repositoryAiChapterEntity.InsertNow(data.AiChapters);
if (data.AiSentences == null || data.AiSentences.Count() == 0) return data;
repositoryAiSentenceEntity.InsertNow(data.AiSentences);
return FindByKey(key);
}
//public IActionResult GetTtsStream(string text)
//{
// string fileDownloadName = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice", DateTime.Now.ToString("yyyyMMddHHmmss") + ".mp3");
// string param = PackParameters(ChineseTtsVoice.Sherpa2.ToString(), fileDownloadName, text);
// RunMyProcess(service.Configuration["CloudBuilder.Topshelf:Path"], param);
// var stream = System.IO.File.OpenRead(fileDownloadName);
// string contentType = "application/octet-stream";
// return new FileStreamResult(stream, contentType) { FileDownloadName = fileDownloadName };
//}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public IActionResult GetMp3Stream(AiSentenceViewEntity aiSentence)
{
string fileDownloadName = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice", string.Format("{0}_{1}.mp3", aiSentence.BookId, aiSentence.ChapterId));
var stream = System.IO.File.OpenRead(fileDownloadName);
string contentType = "application/octet-stream";
return new FileStreamResult(stream, contentType) { FileDownloadName = fileDownloadName };
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public void GenerateMp3(AiChapterEntity[] chapters)
{
string save_path = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice");
foreach (AiChapterEntity sentence in chapters)
{
string param = PackTtsParameters(ChineseTtsVoice.Sherpa2.ToString(), save_path, sentence.BookId, sentence.ChapterId.ToString());
RunMyProcess(service.Configuration["CloudBuilder.Topshelf:Path"], param);
}
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public void GenerateMp3ByBookId(string bookId)
{
IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
AiChapterEntity[] chapters
= repositoryAiChapterEntity.DetachedEntities.Where(x => x.BookId == bookId).OrderBy(x => x.ChapterId).ToArray();
string save_path = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice");
foreach (AiChapterEntity sentence in chapters)
{
string param = PackTtsParameters(ChineseTtsVoice.Sherpa2.ToString(), save_path, sentence.BookId, sentence.ChapterId.ToString());
RunMyProcess(service.Configuration["CloudBuilder.Topshelf:Path"], param);
}
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public void PackPersonNameByBookId(string bookId)
{
IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
AiChapterEntity[] chapters
= repositoryAiChapterEntity.DetachedEntities.Where(x => x.BookId == bookId).OrderBy(x => x.ChapterId).ToArray();
string save_path = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice");
foreach (AiChapterEntity aiChapter in chapters)
{
string param = PackPersonNameParameters(ChineseTtsVoice.Sherpa2.ToString(), save_path, aiChapter.BookId, aiChapter.ChapterId.ToString());
RunMyProcess(service.Configuration["CloudBuilder.Topshelf:Path"], param);
}
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
public void PackPersonName(AiChapterEntity[] chapters)
{
string save_path = Path.Combine(service.Configuration["FileServiceSettings:BackupDmsFileDirectory"], @"voice");
foreach (AiChapterEntity aiChapter in chapters)
{
string param = PackPersonNameParameters(ChineseTtsVoice.Sherpa2.ToString(), save_path, aiChapter.BookId, aiChapter.ChapterId.ToString());
RunMyProcess(service.Configuration["CloudBuilder.Topshelf:Path"], param);
}
}
private string PackPersonNameParameters(string voice, string save_path, string bookId, string chapterId)
{
//task:ChineseNameExtractorTask book_id:B000008 chapter_id:3
List<string> para = new List<string>();
para.Add("task:" + "ChineseNameExtractorTask");
para.Add("book_id:" + bookId);
para.Add("chapter_id:" + chapterId);
return para.ToArray().ToDelimiteredList(' ');
}
private string PackTtsParameters(string voice, string save_path, string bookId, string chapterId)
{
//速度快,音质差
//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:SoVITSTtsTask book_id:B000011 chapter_id:3 save_path:D:\\Net8\\FileServer\\Backup\\DmsFile\\voice
//非必要参数 voice:MIDDLE_AGED_FEMALE5 actor:韩立 actor_voice:YOUNG_MALE2
List<string> para = new List<string>();
para.Add("task:" + "SoVITSTtsTask");
para.Add("book_id:" + bookId);
para.Add("chapter_id:" + chapterId);
para.Add("voice:" + voice);
para.Add("save_path:" + save_path);
para.Add("speed:1");
para.Add("actor:NA");
return para.ToArray().ToDelimiteredList(' ');
}
/// <summary>
/// 执行cmd指令(同步等待await要求等待返回转码太耗时)
/// </summary>
/// <param name="Parameters"></param>
public void RunMyProcess(string exePath, string Parameters)
{
try
{
if (string.IsNullOrEmpty(exePath)) return;
var result = Cli.Wrap(exePath)
.WithWorkingDirectory(Path.GetDirectoryName(exePath))
.WithArguments(Parameters)
.ExecuteAsync().GetAwaiter().GetResult();
Thread.Sleep(300);
}
catch (Exception ex)
{
throw new ValidatedException(ex.Message);
}
}
/// <summary>
/// 执行cmd指令(异步不等待await要求等待返回转码太耗时)
/// </summary>
/// <param name="Parameters"></param>
public void RunMyProcessAsync(string exePath, string Parameters)
{
try
{
if (string.IsNullOrEmpty(exePath)) return;
Cli.Wrap(exePath)
.WithWorkingDirectory(Path.GetDirectoryName(exePath))
.WithArguments(Parameters)
.ExecuteAsync();
Thread.Sleep(300);
}
catch (Exception ex)
{
throw new ValidatedException(ex.Message);
}
}
}
}