diff --git a/CloudBuilder.AI.Service/AiBookService.auto.cs b/CloudBuilder.AI.Service/AiBookService.auto.cs index 76db8ec..cd6228e 100644 --- a/CloudBuilder.AI.Service/AiBookService.auto.cs +++ b/CloudBuilder.AI.Service/AiBookService.auto.cs @@ -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); } diff --git a/CloudBuilder.AI/Entity/AiSentenceEntity.auto.cs b/CloudBuilder.AI/Entity/AiSentenceEntity.auto.cs index 2466864..c68884a 100644 --- a/CloudBuilder.AI/Entity/AiSentenceEntity.auto.cs +++ b/CloudBuilder.AI/Entity/AiSentenceEntity.auto.cs @@ -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; } } diff --git a/CloudBuilder.AI/Entity/AiSentenceViewEntity.auto.cs b/CloudBuilder.AI/Entity/AiSentenceViewEntity.auto.cs index fed399b..7ad5fc3 100644 --- a/CloudBuilder.AI/Entity/AiSentenceViewEntity.auto.cs +++ b/CloudBuilder.AI/Entity/AiSentenceViewEntity.auto.cs @@ -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) { diff --git a/CloudBuilder.AI/Entity/CloudBuilderAIRegistEntity.auto.cs b/CloudBuilder.AI/Entity/CloudBuilderAIRegistEntity.auto.cs index 90f2321..5bde315 100644 --- a/CloudBuilder.AI/Entity/CloudBuilderAIRegistEntity.auto.cs +++ b/CloudBuilder.AI/Entity/CloudBuilderAIRegistEntity.auto.cs @@ -45,6 +45,7 @@ namespace CloudBuilder.AI.Entity builder.Entity().HasKey(c => new {c.BookId,c.ChapterId}); builder.Entity(eb => { eb.HasNoKey(); }); builder.Entity(eb => { eb.HasNoKey(); }); + builder.Entity(eb => { eb.HasNoKey(); }); //***END*** } } diff --git a/CloudBuilder.AI/Utility/ParagraphSplitter.cs b/CloudBuilder.AI/Utility/ParagraphSplitter.cs index dfd59e4..070cf11 100644 --- a/CloudBuilder.AI/Utility/ParagraphSplitter.cs +++ b/CloudBuilder.AI/Utility/ParagraphSplitter.cs @@ -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; diff --git a/CloudBuilder.AI/Utility/SentenceSplitter.cs b/CloudBuilder.AI/Utility/SentenceSplitter.cs index 9ac7bd9..c6694eb 100644 --- a/CloudBuilder.AI/Utility/SentenceSplitter.cs +++ b/CloudBuilder.AI/Utility/SentenceSplitter.cs @@ -48,27 +48,44 @@ namespace CloudBuilder.AI.Utility /// /// 初始化动态正则:根据配置的成对引号生成匹配规则 /// + //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:构建动态正则表达式 + // // 分组说明: + // // ?:匹配配置的任意左引号 + // // ?:匹配引号内的内容(必须以指定标点结尾) + // // ?:匹配配置的任意右引号 + // string regexPattern = $@"(?{escapedLeftQuotes})(?.+?[{escapedPunctuations}])(?{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:构建动态正则表达式 - // 分组说明: - // ?:匹配配置的任意左引号 - // ?:匹配引号内的内容(必须以指定标点结尾) - // ?:匹配配置的任意右引号 - string regexPattern = $@"(?{escapedLeftQuotes})(?.+?[{escapedPunctuations}])(?{escapedRightQuotes})"; + // ✅ 修复:移除必须以标点结尾的限制,匹配任意引号内容 + string regexPattern = $@"(?{escapedLeftQuotes})(?.+?)(?{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; } }