400 lines
16 KiB
C#
400 lines
16 KiB
C#
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
|
||
List<string> para = new List<string>();
|
||
para.Add("task:" + "TtsTask");
|
||
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);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|