post-write-check-plugin.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import type { PostWriteCheck, PostWriteCheckItem } from "../context-trace"
  2. import type { PrePlugin, PrePluginInput, PrePluginOutput } from "../pipeline"
  3. export interface PostWriteCheckDeps {
  4. chapterContent?: string
  5. }
  6. const DEFAULT_CHECK_ITEMS: {
  7. name: string
  8. check: (content: string) => boolean
  9. detail: (content: string) => string
  10. }[] = [
  11. {
  12. name: "剧情承接",
  13. check: (c) => c.length > 100,
  14. detail: () => "章节正文超过 100 字,剧情承接检查通过。",
  15. },
  16. {
  17. name: "主线推进",
  18. check: (c) => !c.includes("【待补充】") && !c.includes("待完善"),
  19. detail: () => "正文中未包含占位标记,主线推进检查通过。",
  20. },
  21. {
  22. name: "人物动机",
  23. check: (c) => c.length > 200,
  24. detail: () => "正文长度超过 200 字,人物动机有基本体现。",
  25. },
  26. {
  27. name: "冲突强度",
  28. check: (c) => c.includes("但是") || c.includes("然而") || c.includes("突然") || c.includes("却"),
  29. detail: () => "正文中包含转折词,冲突强度检查通过。",
  30. },
  31. {
  32. name: "伏笔处理",
  33. check: () => true,
  34. detail: () => "检查通过。",
  35. },
  36. {
  37. name: "节奏",
  38. check: (c) => {
  39. const separators = /[。!?\n]/
  40. const sentences = c.split(separators).filter(Boolean)
  41. return sentences.length >= 3
  42. },
  43. detail: (c) => {
  44. const separators = /[。!?\n]/
  45. const sentences = c.split(separators).filter(Boolean)
  46. return `正文包含 ${sentences.length} 个句子,节奏检查通过。`
  47. },
  48. },
  49. {
  50. name: "风格一致性",
  51. check: () => true,
  52. detail: () => "风格一致性检查通过。",
  53. },
  54. ]
  55. export function createPostWriteCheckPlugin(deps: PostWriteCheckDeps = {}): PrePlugin {
  56. return {
  57. name: "post_write_check",
  58. priority: 5,
  59. run: async (input: PrePluginInput): Promise<PrePluginOutput> => {
  60. const content = deps.chapterContent || (input as any).contextInfo?.latestChapterContent || ""
  61. if (!content) return {}
  62. const items: PostWriteCheckItem[] = DEFAULT_CHECK_ITEMS.map((item) => ({
  63. name: item.name,
  64. passed: item.check(content),
  65. detail: item.detail(content),
  66. }))
  67. const passedCount = items.filter((i) => i.passed).length
  68. const totalCount = items.length
  69. const postWriteCheck: PostWriteCheck = {
  70. items,
  71. passedCount,
  72. totalCount,
  73. allPassed: passedCount === totalCount,
  74. }
  75. return { postWriteCheck }
  76. },
  77. }
  78. }
  79. export function runPostWriteCheck(content: string): PostWriteCheck {
  80. const items: PostWriteCheckItem[] = DEFAULT_CHECK_ITEMS.map((item) => ({
  81. name: item.name,
  82. passed: item.check(content),
  83. detail: item.detail(content),
  84. }))
  85. const passedCount = items.filter((i) => i.passed).length
  86. const totalCount = items.length
  87. return {
  88. items,
  89. passedCount,
  90. totalCount,
  91. allPassed: passedCount === totalCount,
  92. }
  93. }