This commit is contained in:
owenchen 2026-06-04 16:02:01 +08:00
parent cb3fdca3e1
commit ce37c632d3
6 changed files with 89 additions and 67 deletions

View File

@ -227,18 +227,13 @@ namespace CloudBuilder.AI.Service
if (aiChapters != null && aiChapters.Length > 0)
{
foreach (AiChapterEntity aiChapter in aiChapters)
{
AiSentenceEntity[] aiSentences = repositoryAiSentenceEntity.DetachedEntities.Where(x => x.ChapterId == aiChapter.ChapterId).ToArray();
AiSentenceEntity[] aiSentences = repositoryAiSentenceEntity.DetachedEntities.Where(x => x.BookId == data.AiBook.BookId).ToArray();
if (aiSentences != null && aiSentences.Length > 0)
{
if (aiSentences != null && aiSentences.Length > 0)
{
repositoryAiSentenceEntity.DeleteNow(aiSentences);
}
}
if (aiSentences != null && aiSentences.Length > 0)
{
repositoryAiSentenceEntity.DeleteNow(aiSentences);
}
repositoryAiChapterEntity.DeleteNow(aiChapters);
}

View File

@ -13,12 +13,8 @@ namespace CloudBuilder.AI.Entity
{
}
[Column("content")]
public string Content { get; set; }
[Column("status")]
public string? Status { get; set; }
[Column("paragraph_id")]
public long ParagraphId { get; set; }
[Column("sentence_index")]
public int SentenceIndex { get; set; }
[Column("dialogue_indc")]
@ -29,53 +25,61 @@ namespace CloudBuilder.AI.Entity
public string? Gender { get; set; }
[Column("sentiment")]
public string? Sentiment { get; set; }
[Column("created_datetime")]
public DateTime CreatedDatetime { get; set; }
[Column("created_by")]
public string CreatedBy { get; set; }
[Column("content")]
public string Content { get; set; }
[Column("updated_datetime")]
public DateTime UpdatedDatetime { get; set; }
[Column("updated_by")]
public string UpdatedBy { get; set; }
[Column("book_id")]
public string BookId { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("sentence_id")]
public long SentenceId { get; set; }
[Column("chapter_id")]
public int ChapterId { get; set; }
[Column("paragraph_id")]
public long ParagraphId { get; set; }
[Column("created_datetime")]
public DateTime CreatedDatetime { get; set; }
[Column("created_by")]
public string CreatedBy { get; set; }
public const string CONTENT = "Content";
public const string STATUS = "Status";
public const string PARAGRAPH_ID = "ParagraphId";
public const string SENTENCE_INDEX = "SentenceIndex";
public const string DIALOGUE_INDC = "DialogueIndc";
public const string PERSON_NAME = "PersonName";
public const string GENDER = "Gender";
public const string SENTIMENT = "Sentiment";
public const string CREATED_DATETIME = "CreatedDatetime";
public const string CREATED_BY = "CreatedBy";
public const string CONTENT = "Content";
public const string UPDATED_DATETIME = "UpdatedDatetime";
public const string UPDATED_BY = "UpdatedBy";
public const string BOOK_ID = "BookId";
public const string SENTENCE_ID = "SentenceId";
public const string CHAPTER_ID = "ChapterId";
public const string PARAGRAPH_ID = "ParagraphId";
public const string CREATED_DATETIME = "CreatedDatetime";
public const string CREATED_BY = "CreatedBy";
public const string DB_NAME_AI_SENTENCE = "ai_sentence";
public const string DB_NAME_FIELDS="content,status,paragraph_id,sentence_index,dialogue_indc,person_name,gender,sentiment,created_datetime,created_by,updated_datetime,updated_by,sentence_id,chapter_id";
public const string DB_NAME_FIELDS="status,sentence_index,dialogue_indc,person_name,gender,sentiment,content,updated_datetime,updated_by,book_id,sentence_id,chapter_id,paragraph_id,created_datetime,created_by";
public const string DB_CONTENT = "content";
public const string DB_STATUS = "status";
public const string DB_PARAGRAPH_ID = "paragraph_id";
public const string DB_SENTENCE_INDEX = "sentence_index";
public const string DB_DIALOGUE_INDC = "dialogue_indc";
public const string DB_PERSON_NAME = "person_name";
public const string DB_GENDER = "gender";
public const string DB_SENTIMENT = "sentiment";
public const string DB_CREATED_DATETIME = "created_datetime";
public const string DB_CREATED_BY = "created_by";
public const string DB_CONTENT = "content";
public const string DB_UPDATED_DATETIME = "updated_datetime";
public const string DB_UPDATED_BY = "updated_by";
public const string DB_BOOK_ID = "book_id";
public const string DB_SENTENCE_ID = "sentence_id";
public const string DB_CHAPTER_ID = "chapter_id";
public const string DB_PARAGRAPH_ID = "paragraph_id";
public const string DB_CREATED_DATETIME = "created_datetime";
public const string DB_CREATED_BY = "created_by";
public static AiSentenceEntity GetInstance()
@ -95,27 +99,28 @@ namespace CloudBuilder.AI.Entity
throw new NullReferenceException("Source entity is null.");
}
this.Content = source.Content;
this.Status = source.Status;
this.ParagraphId = source.ParagraphId;
this.SentenceIndex = source.SentenceIndex;
this.DialogueIndc = source.DialogueIndc;
this.PersonName = source.PersonName;
this.Gender = source.Gender;
this.Sentiment = source.Sentiment;
this.CreatedDatetime = source.CreatedDatetime;
this.CreatedBy = source.CreatedBy;
this.Content = source.Content;
this.UpdatedDatetime = source.UpdatedDatetime;
this.UpdatedBy = source.UpdatedBy;
this.BookId = source.BookId;
this.SentenceId = source.SentenceId;
this.ChapterId = source.ChapterId;
this.ParagraphId = source.ParagraphId;
this.CreatedDatetime = source.CreatedDatetime;
this.CreatedBy = source.CreatedBy;
if (includeSystemFields)
{
this.CreatedDatetime = source.CreatedDatetime;
this.CreatedBy = source.CreatedBy;
this.UpdatedDatetime = source.UpdatedDatetime;
this.UpdatedBy = source.UpdatedBy;
this.CreatedDatetime = source.CreatedDatetime;
this.CreatedBy = source.CreatedBy;
}
}

View File

@ -21,16 +21,19 @@ namespace CloudBuilder.AI.Entity
public DateTime UpdatedDatetime { get; set; }
[Column("updated_by")]
public string UpdatedBy { get; set; }
[Column("book_id")]
public string BookId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("sentence_id")]
public long SentenceId { get; set; }
[Column("chapter_id")]
public int ChapterId { get; set; }
[Column("sentiment")]
public string? Sentiment { get; set; }
[Column("content")]
public string Content { get; set; }
[Column("status")]
public string? Status { get; set; }
[Column("book_id")]
public string BookId { get; set; }
[Column("chapter_id")]
public int ChapterId { get; set; }
[Column("paragraph_id")]
public long ParagraphId { get; set; }
[Column("sentence_index")]
@ -41,43 +44,41 @@ namespace CloudBuilder.AI.Entity
public string? PersonName { get; set; }
[Column("gender")]
public string? Gender { get; set; }
[Column("sentiment")]
public string? Sentiment { get; set; }
public const string CREATED_DATETIME = "CreatedDatetime";
public const string CREATED_BY = "CreatedBy";
public const string UPDATED_DATETIME = "UpdatedDatetime";
public const string UPDATED_BY = "UpdatedBy";
public const string BOOK_ID = "BookId";
public const string SENTENCE_ID = "SentenceId";
public const string CHAPTER_ID = "ChapterId";
public const string SENTIMENT = "Sentiment";
public const string CONTENT = "Content";
public const string STATUS = "Status";
public const string BOOK_ID = "BookId";
public const string CHAPTER_ID = "ChapterId";
public const string PARAGRAPH_ID = "ParagraphId";
public const string SENTENCE_INDEX = "SentenceIndex";
public const string DIALOGUE_INDC = "DialogueIndc";
public const string PERSON_NAME = "PersonName";
public const string GENDER = "Gender";
public const string SENTIMENT = "Sentiment";
public const string DB_NAME_AI_SENTENCE_VIEW = "ai_sentence_view";
public const string DB_NAME_FIELDS="created_datetime,created_by,updated_datetime,updated_by,sentence_id,chapter_id,content,status,book_id,paragraph_id,sentence_index,dialogue_indc,person_name,gender,sentiment";
public const string DB_NAME_FIELDS="created_datetime,created_by,updated_datetime,updated_by,book_id,sentence_id,sentiment,content,status,chapter_id,paragraph_id,sentence_index,dialogue_indc,person_name,gender";
public const string DB_CREATED_DATETIME = "created_datetime";
public const string DB_CREATED_BY = "created_by";
public const string DB_UPDATED_DATETIME = "updated_datetime";
public const string DB_UPDATED_BY = "updated_by";
public const string DB_BOOK_ID = "book_id";
public const string DB_SENTENCE_ID = "sentence_id";
public const string DB_CHAPTER_ID = "chapter_id";
public const string DB_SENTIMENT = "sentiment";
public const string DB_CONTENT = "content";
public const string DB_STATUS = "status";
public const string DB_BOOK_ID = "book_id";
public const string DB_CHAPTER_ID = "chapter_id";
public const string DB_PARAGRAPH_ID = "paragraph_id";
public const string DB_SENTENCE_INDEX = "sentence_index";
public const string DB_DIALOGUE_INDC = "dialogue_indc";
public const string DB_PERSON_NAME = "person_name";
public const string DB_GENDER = "gender";
public const string DB_SENTIMENT = "sentiment";
public static AiSentenceViewEntity GetInstance()
@ -101,17 +102,17 @@ namespace CloudBuilder.AI.Entity
this.CreatedBy = source.CreatedBy;
this.UpdatedDatetime = source.UpdatedDatetime;
this.UpdatedBy = source.UpdatedBy;
this.BookId = source.BookId;
this.SentenceId = source.SentenceId;
this.ChapterId = source.ChapterId;
this.Sentiment = source.Sentiment;
this.Content = source.Content;
this.Status = source.Status;
this.BookId = source.BookId;
this.ChapterId = source.ChapterId;
this.ParagraphId = source.ParagraphId;
this.SentenceIndex = source.SentenceIndex;
this.DialogueIndc = source.DialogueIndc;
this.PersonName = source.PersonName;
this.Gender = source.Gender;
this.Sentiment = source.Sentiment;
if (includeSystemFields)
{

View File

@ -45,6 +45,7 @@ namespace CloudBuilder.AI.Entity
builder.Entity<AiChapterEntity>().HasKey(c => new {c.BookId,c.ChapterId});
builder.Entity<AiSentenceDialogueViewEntity>(eb => { eb.HasNoKey(); });
builder.Entity<AiSentenceViewEntity>(eb => { eb.HasNoKey(); });
builder.Entity<AiSentenceViewEntity>(eb => { eb.HasNoKey(); });
//***END***
}
}

View File

@ -56,6 +56,7 @@ namespace CloudBuilder.AI.Utility
aiParagraph = new AiSentenceEntity();
aiParagraph.Content = text;
aiParagraph.BookId = aiChapter.BookId;
aiParagraph.ChapterId = aiChapter.ChapterId;
aiParagraph.ParagraphId = index++;
aiParagraph.DialogueIndc = sentenceSplitter.IsDialogue(text) ? YesNoPolicy.YES : YesNoPolicy.NO;

View File

@ -48,27 +48,44 @@ namespace CloudBuilder.AI.Utility
/// <summary>
/// 初始化动态正则:根据配置的成对引号生成匹配规则
/// </summary>
//private void InitDynamicRegex()
//{
// if (_quotePairs.Count == 0)
// {
// // 空配置时生成空正则,避免匹配任何内容
// _dynamicQuotePattern = new Regex(@"^$", RegexOptions.Compiled);
// return;
// }
// // 步骤1转义所有引号避免正则特殊字符冲突拼接左/右引号匹配组
// string escapedLeftQuotes = string.Join("|", _quotePairs.Select(p => Regex.Escape(p.LeftQuote)));
// string escapedRightQuotes = string.Join("|", _quotePairs.Select(p => Regex.Escape(p.RightQuote)));
// // 步骤2转义标点集合避免正则解析错误
// string escapedPunctuations = Regex.Escape(_endPunctuations);
// // 步骤3构建动态正则表达式
// // 分组说明:
// // ?<left>:匹配配置的任意左引号
// // ?<content>:匹配引号内的内容(必须以指定标点结尾)
// // ?<right>:匹配配置的任意右引号
// string regexPattern = $@"(?<left>{escapedLeftQuotes})(?<content>.+?[{escapedPunctuations}])(?<right>{escapedRightQuotes})";
// _dynamicQuotePattern = new Regex(regexPattern, RegexOptions.Compiled | RegexOptions.Singleline);
//}
private void InitDynamicRegex()
{
if (_quotePairs.Count == 0)
{
// 空配置时生成空正则,避免匹配任何内容
_dynamicQuotePattern = new Regex(@"^$", RegexOptions.Compiled);
return;
}
// 步骤1转义所有引号避免正则特殊字符冲突拼接左/右引号匹配组
string escapedLeftQuotes = string.Join("|", _quotePairs.Select(p => Regex.Escape(p.LeftQuote)));
string escapedRightQuotes = string.Join("|", _quotePairs.Select(p => Regex.Escape(p.RightQuote)));
// 步骤2转义标点集合避免正则解析错误
string escapedPunctuations = Regex.Escape(_endPunctuations);
// 步骤3构建动态正则表达式
// 分组说明:
// ?<left>:匹配配置的任意左引号
// ?<content>:匹配引号内的内容(必须以指定标点结尾)
// ?<right>:匹配配置的任意右引号
string regexPattern = $@"(?<left>{escapedLeftQuotes})(?<content>.+?[{escapedPunctuations}])(?<right>{escapedRightQuotes})";
// ✅ 修复:移除必须以标点结尾的限制,匹配任意引号内容
string regexPattern = $@"(?<left>{escapedLeftQuotes})(?<content>.+?)(?<right>{escapedRightQuotes})";
_dynamicQuotePattern = new Regex(regexPattern, RegexOptions.Compiled | RegexOptions.Singleline);
}
@ -108,6 +125,7 @@ namespace CloudBuilder.AI.Utility
if (!string.IsNullOrEmpty(prefixText))
{
aiSentence = new AiSentenceEntity();
aiSentence.BookId = aiParagraphEntity.BookId;
aiSentence.ChapterId = aiParagraphEntity.ChapterId;
aiSentence.Content = prefixText;
aiSentence.DialogueIndc = YesNoPolicy.NO;
@ -123,6 +141,7 @@ namespace CloudBuilder.AI.Utility
if (!string.IsNullOrEmpty(quotedContent))
{
aiSentence = new AiSentenceEntity();
aiSentence.BookId = aiParagraphEntity.BookId;
aiSentence.ChapterId = aiParagraphEntity.ChapterId;
aiSentence.Content = quotedContent;
aiSentence.DialogueIndc = YesNoPolicy.YES;
@ -142,6 +161,7 @@ namespace CloudBuilder.AI.Utility
if (!string.IsNullOrEmpty(suffixText))
{
aiSentence = new AiSentenceEntity();
aiSentence.BookId = aiParagraphEntity.BookId;
aiSentence.ChapterId = aiParagraphEntity.ChapterId;
aiSentence.Content = suffixText;
aiSentence.DialogueIndc = YesNoPolicy.NO;
@ -181,16 +201,15 @@ namespace CloudBuilder.AI.Utility
.Replace("", "'");
// 3. 核心判断规则:
// - 包含成对/单个双引号(排除仅含引号无内容的情况)
// - 包含冒号+引号(如:"XXX说"XXX"" 场景)
var hasQuote = Regex.IsMatch(cleanedText, @""".+?""") || // 成对双引号(含内容)
Regex.IsMatch(cleanedText, @":\s*"""); // 冒号后接引号(说话人+对话)
var hasSingleQuote = Regex.IsMatch(cleanedText, @"'[^']+'"); // 成对单引号(英文对话)
var hasQuote = Regex.IsMatch(cleanedText, @""".+?""") ||
Regex.IsMatch(cleanedText, @"[:,]\s*"""); // 冒号/逗号+引号(说话标记)
// 4. 排除仅含引号符号的无效情况(如 ""、''、“”)
var onlyQuote = Regex.IsMatch(cleanedText, @"^\s*[""''“”]{1,2}\s*$");
var hasSingleQuote = Regex.IsMatch(cleanedText, @"'[^']+'");
// 最终判断:包含有效引号且不是仅含引号 → 判定为对话
// 4. 排除仅含引号符号的无效情况(修复:只匹配替换后的符号)
var onlyQuote = Regex.IsMatch(cleanedText, @"^\s*[""']{1,2}\s*$");
// 最终判断
return (hasQuote || hasSingleQuote) && !onlyQuote;
}
}