From 241a04496bc9ba265e0957045079cf2430b8d105 Mon Sep 17 00:00:00 2001 From: gouki Date: Tue, 18 Aug 2026 00:09:12 +0000 Subject: [PATCH] =?UTF-8?q?fix(term):=20=E6=B8=85=E7=90=86=E7=99=BE?= =?UTF-8?q?=E5=BA=A6=E7=99=BE=E7=A7=91=E6=91=98=E8=A6=81=E7=9A=84=E6=88=AA?= =?UTF-8?q?=E6=96=AD=E7=BB=93=E5=B0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 百度百科 BaikeLemmaCardApi 摘要以 ... 硬截断,出现半截话。 新增 trimTruncatedTail:去掉结尾省略号后,若末句不完整则 回退到最后一个完整句标点(。!?),避免「唐宋时期,冬至...」 这类戛然而止的结尾。仅依赖百度百科,不引入维基,线上可用。 --- server/internal/service/baike_term_sync.go | 33 ++++++++++++++++++- .../internal/service/baike_term_sync_test.go | 21 ++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/server/internal/service/baike_term_sync.go b/server/internal/service/baike_term_sync.go index ca4070b..2837181 100644 --- a/server/internal/service/baike_term_sync.go +++ b/server/internal/service/baike_term_sync.go @@ -247,7 +247,7 @@ func (s *BaikeTermSyncService) syncOneTerm(name string) error { } extraJSON, _ := json.Marshal(extra) - content := cleanTermHTML(lemma.Abstract) + content := trimTruncatedTail(cleanTermHTML(lemma.Abstract)) brief := extra["meaning"] if brief == "" { brief = firstSentence(content) @@ -365,3 +365,34 @@ func cleanTermHTML(s string) string { s = reTermSpace.ReplaceAllString(s, " ") return strings.TrimSpace(s) } + +// trimTruncatedTail 清理百度百科摘要的截断结尾: +// 摘要以「...」「…」等结尾说明被接口截断,先去掉省略号; +// 若去掉后末句不是完整句(不以 。!? 结尾),回退到最后一个完整句标点,避免半截话 +func trimTruncatedTail(s string) string { + // 去掉结尾的省略号(英文 ... / 中文 … / 多个点) + s = strings.TrimRight(s, ".… ") + if s == "" { + return s + } + // 末字符已是完整句标点则无需回退 + last := []rune(s) + if len(last) == 0 { + return s + } + if strings.ContainsRune("。!?", last[len(last)-1]) { + return s + } + // 回退到最后一个完整句标点(LastIndex 未找到返回 -1,需先判断 j >= 0) + idx := -1 + for _, sep := range []string{"。", "!", "?"} { + if j := strings.LastIndex(s, sep); j >= 0 && j+len(sep) > idx { + idx = j + len(sep) + } + } + if idx > 0 { + return s[:idx] + } + // 没有完整句标点则保留原文(避免清空) + return s +} diff --git a/server/internal/service/baike_term_sync_test.go b/server/internal/service/baike_term_sync_test.go index 4115e9e..6fea34c 100644 --- a/server/internal/service/baike_term_sync_test.go +++ b/server/internal/service/baike_term_sync_test.go @@ -128,3 +128,24 @@ func TestTermSort(t *testing.T) { t.Errorf("termSort(不存在) = %d, want 0", termSort("不存在")) } } + +func TestTrimTruncatedTail(t *testing.T) { + cases := []struct { + name string + in string + want string + }{ + {"完整句号结尾不动", "夏至后人们普遍食用清补凉汤来避暑。", "夏至后人们普遍食用清补凉汤来避暑。"}, + {"英文省略号回退", "表达感谢的心情。唐宋时期,冬至...", "表达感谢的心情。"}, + {"中文省略号回退", "表达感谢的心情。唐宋时期,冬至…", "表达感谢的心情。"}, + {"无句号半截话保留", "可明显感觉到早春的气...", "可明显感觉到早春的气"}, + {"多点省略号", "农事谚语....", "农事谚语"}, + {"结尾空白加省略号", "冬至大如年。 ...", "冬至大如年。"}, + {"空字符串", "", ""}, + } + for _, c := range cases { + if got := trimTruncatedTail(c.in); got != c.want { + t.Errorf("%s: trimTruncatedTail(%q) = %q, want %q", c.name, c.in, got, c.want) + } + } +}