CloudBuilder/CloudBuilder.AI.Service/AiBookService.auto.cs
owenchen 2e990e687f ow
2026-05-28 15:05:46 +08:00

383 lines
15 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.Service.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.Text;
using System.Transactions;
namespace CloudBuilder.AI.Service
{
public class AiBookService : IAiBookService
{
private readonly IApplicationService service;
private IRepository<AiBookEntity> repository;
private ChineseNameExtractor chineseNameExtractor;
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.Guid == 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.Guid = 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.Guid == data.AiBook.Guid).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.Guid == 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<AiChapterEntity> aiChapterEntities = chapterSplitter.SplitNovelIntoChapters(context, pattern);
if (aiChapterEntities == null || aiChapterEntities.Count() == 0) return data;
aiChapterEntities.ToLookup(x => x.BookGuid = data.AiBook.Guid);
aiChapterEntities.ToLookup(x => x.Status = ChapterStatusPolicy.PROCESS);
data.AiChapters = aiChapterEntities.ToArray();
paragraphSplitter.PackParagraphs(data);
IRepository<AiChapterEntity> repositoryAiChapterEntity = repository.GetRepository<IRepository<AiChapterEntity>>();
IRepository<AiParagraphEntity> repositoryAiParagraphEntity = repository.GetRepository<IRepository<AiParagraphEntity>>();
IRepository<AiSentenceEntity> repositoryAiSentenceEntity = repository.GetRepository<IRepository<AiSentenceEntity>>();
AiChapterEntity[] aiChapters = repositoryAiChapterEntity.DetachedEntities.Where(x => x.BookGuid == data.AiBook.Guid).ToArray();
if (aiChapters != null && aiChapters.Length > 0)
{
foreach (AiChapterEntity aiChapter in aiChapters)
{
AiParagraphEntity[] aiParagraphs = repositoryAiParagraphEntity.DetachedEntities.Where(x => x.ChapterGuid == aiChapter.Guid).ToArray();
if (aiParagraphs != null && aiParagraphs.Length > 0)
{
foreach (AiParagraphEntity aiParagraph in aiParagraphs)
{
AiSentenceEntity[] aiSentences = repositoryAiSentenceEntity.DetachedEntities.Where(x => x.ParagraphGuid == aiParagraph.Guid).ToArray();
if (aiSentences != null && aiSentences.Length > 0)
{
repositoryAiSentenceEntity.DeleteNow(aiSentences);
}
}
repositoryAiParagraphEntity.DeleteNow(aiParagraphs);
}
}
repositoryAiChapterEntity.DeleteNow(aiChapters);
}
repositoryAiChapterEntity.InsertNow(data.AiChapters);
if (data.AiParagraphs == null || data.AiParagraphs.Count() == 0) return data;
repositoryAiParagraphEntity.InsertNow(data.AiParagraphs);
if (data.AiSentences == null || data.AiSentences.Count() == 0) return data;
repositoryAiSentenceEntity.InsertNow(data.AiSentences);
return FindByKey(key);
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
[UnitOfWork]
public void ExtractNames(string bookGuid)
{
ExtractNamesByChapterGuid(bookGuid, null);
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Update)]
[UnitOfWork]
public void ExtractNamesByChapterGuid(string bookGuid, string chapterGuid)
{
if (chineseNameExtractor == null) chineseNameExtractor = new ChineseNameExtractor(service);
IRepository<AiChapterPersonEntity> repositoryAiChapterPersonEntity = repository.GetRepository<IRepository<AiChapterPersonEntity>>();
IRepository<AiParagraphViewEntity> repositoryAiParagraphEntity = repository.GetRepository<IRepository<AiParagraphViewEntity>>();
AiParagraphViewEntity[] paragraphs = repositoryAiParagraphEntity.DetachedEntities.Where(x => x.BookGuid == bookGuid && (string.IsNullOrEmpty(chapterGuid) || x.ChapterGuid == chapterGuid)).ToArray();
if (paragraphs == null || paragraphs.Length == 0) return;
List<string> names = new List<string>();
List<AiChapterPersonEntity> aiChapterPersonEntities = new List<AiChapterPersonEntity>();
AiChapterPersonEntity entity;
int orderIndex = 0;
foreach (var paragraph in paragraphs)
{
names = chineseNameExtractor.ExtractNames(paragraph.Content);
if (names == null || names.Count() == 0) continue;
orderIndex = 1;
foreach (var name in names)
{
entity = new AiChapterPersonEntity();
entity.Guid = Guid.NewGuid().ToString();
entity.ChapterGuid = paragraph.ChapterGuid;
entity.ParagraphGuid = paragraph.Guid;
entity.ParagraphIndex = paragraph.ParagraphIndex;
entity.OrderIndex = orderIndex++;
entity.PersonName = name;
aiChapterPersonEntities.Add(entity);
}
}
if (aiChapterPersonEntities != null && aiChapterPersonEntities.Count() > 0)
repositoryAiChapterPersonEntity.InsertNow(aiChapterPersonEntities);
}
[PermissionOperate(name: AIPermissionPolicy.AiBook, operate: Operate.Find)]
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 };
}
private string PackParameters(string voice, string save_path, string text)
{
List<string> para = new List<string>();
para.Add("task:" + "TtsTask");
para.Add("voice:" + voice);
para.Add("save_path:" + save_path);
para.Add("text:" + text.Replace(":", ""));
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);
}
}
}
}