- 作者帖子
典中典游客懂编程的人都很酷
目前就古籍酷的单次字数数量为50000字,但经常排不上队,很糟心。其他网站都是几百上千字。非常的不好用。
有没有更好免费好用的古籍点校模型推荐?或者请编程高手开发一个古籍标点的网站或软件。
感谢!
赤霄游客智慧平台的句读和自动标点准确率奇高,他们的模型确实有水平,但目测也是用的deepseek自己部署的。
典中典游客古籍智慧平台这个没找到使用的地方,需要的是那种有输入框文本粘贴上去或上传就自动标点好的那种样式。其实各家水平都在线的,就是字数限制比较难受。最终还是需要通读对校的,不需要等到完美再上路,目前需要【能用量大】就行。
岭南散人游客其实,现在的人工智能也能标点,准确率高达90%
zyz游客@赤霄 #202324
智慧平台是我见过断句最垃圾的,准确率奇高是从何而来的呢?
典中典游客
摩诃游客当前的模型和算力,没办法一次处理大量数据,暂时只能分割,不然精确度大减。
模型和算力不是某个绝世高手能解决的。
客游游客@摩诃 #202390
古籍酷目前不用登录可用,支持一次五万字的标点,这个技术上没问题的,标点基本不用怎么改。就经常是需要等待几十万秒的提示。
Ai时代了,这个问题应该会很快解决,不会编程确是有赶不上躺的感觉。
拭目以待。
赤霄游客大模型准确率高,小模型蒸馏得好的专门模型效果和速度应该都能兼顾,普通编程实现,也就是之乎者也这种基本断句,根本谈不上精确度。
摩诃游客如何实现古籍文本智能校勘? https://mp.weixin.qq.com/s/AL6-aJas_XVuQmOuJxxtUQ
软件完整配置:https://github.com/anon-research-tools/classical-text-collation第一批用AI「偷懒」的人,抢救了13亿字古籍
mp.weixin.qq.com/s/kbW...oikOW2JUAA
赤霄游客deepseek给的脚本方案:
完全可以!使用大模型进行古文自动断句已经非常成熟,准确率远超传统方法。以下我将提供一个完整的解决方案:
方案一:直接调用大模型API(推荐)
1. 使用ChatGPT/Claude等商业API
`python
import openai
import reclass ClassicalChineseSegmenter:
def __init__(self, api_key, model="gpt-4"):
self.api_key = api_key
self.model = model
openai.api_key = api_keydef segment_text(self, text, max_length=2000):
"""对古文进行自动断句"""
# 如果文本过长,分段处理
if len(text) > max_length:
return self._segment_long_text(text, max_length)prompt = f"""请对以下古文进行专业准确的断句。要求:
1. 按照古文语法和意义正确断句
2. 使用中文句号"。"、逗号","、分号";"等标点
3. 保持原文内容不变,只添加标点
4. 对专有名词、典故要特别注意文本:
{text}断句结果:"""
response = openai.ChatCompletion.create(
model=self.model,
messages=[
{"role": "system", "content": "你是古代汉语专家,精通古文断句和标点。"},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=len(text) * 2
)return response.choices[0].message.content.strip()
def _segment_long_text(self, text, max_length):
"""处理长文本"""
chunks = self._split_text_by_paragraph(text, max_length)
results = []for chunk in chunks:
segmented = self.segment_text(chunk)
results.append(segmented)return '\n'.join(results)
def _split_text_by_paragraph(self, text, max_length):
"""按段落分割文本"""
paragraphs = re.split(r'[\n\r]+', text)
chunks = []
current_chunk = ""for para in paragraphs:
if len(current_chunk) + len(para) + 1 <= max_length:
current_chunk += para + "\n"
else:
if current_chunk:
chunks.append(current_chunk.strip())
current_chunk = para + "\n"if current_chunk:
chunks.append(current_chunk.strip())return chunks
# 使用示例
if __name__ == "__main__":
# 初始化(需要配置API key)
segmenter = ClassicalChineseSegmenter(api_key="your-api-key")# 测试文本
sample_text = """昔者庄周梦为胡蝶栩栩然胡蝶也自喻适志与不知周也俄然觉则蘧蘧然周也不知周之梦为胡蝶与胡蝶之梦为周与周与胡蝶则必有分矣此之谓物化"""result = segmenter.segment_text(sample_text)
print("断句结果:")
print(result)
`2. 使用开源大模型(免费方案)
`python
from transformers import AutoTokenizer, AutoModelForCausalLM
import torchclass OpenSourceSegmenter:
def __init__(self, model_name="Langboat/bloom-389m-zh-classical"):
"""
可选择的开源模型:
- Langboat/bloom-389m-zh-classical (专门训练的古文模型)
- THUDM/chatglm-6b
- Qwen/Qwen-7B
"""
self.tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True
)def segment_text(self, text):
prompt = f"""为下面的古文添加标点:{text}
带标点的文本:"""
inputs = self.tokenizer(prompt, return_tensors="pt")
inputs = inputs.to(self.model.device)with torch.no_grad():
outputs = self.model.generate(
**inputs,
max_new_tokens=len(text) * 2,
temperature=0.7,
do_sample=True,
top_p=0.9
)result = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
# 提取生成的文本
result = result.split("带标点的文本:")[-1].strip()return result
# 使用示例
if __name__ == "__main__":
segmenter = OpenSourceSegmenter()
text = "道可道非常道名可名非常名无名天地之始有名万物之母"
result = segmenter.segment_text(text)
print(result)
`方案二:专用古文断句模型
`python
# 安装:pip install transformers torchimport torch
from transformers import BertTokenizer, BertForTokenClassificationclass ClassicalChinesePunctuator:
"""基于BERT的古文断句模型"""def __init__(self, model_path="ethanyt/guwen-punctuate"):
self.tokenizer = BertTokenizer.from_pretrained(model_path)
self.model = BertForTokenClassification.from_pretrained(model_path)
self.label2punc = {
0: '', # 无标点
1: ',', # 逗号
2: '。', # 句号
3: '?', # 问号
4: '!', # 感叹号
5: ';', # 分号
6: ':', # 冒号
}def punctuate(self, text):
"""为古文添加标点"""
# 将文本转换为字符序列
chars = list(text)
inputs = self.tokenizer(chars,
is_split_into_words=True,
return_tensors="pt",
padding=True)with torch.no_grad():
outputs = self.model(**inputs)
predictions = torch.argmax(outputs.logits, dim=-1)[0].cpu().numpy()# 构建带标点的文本
result = []
for char, pred in zip(chars, predictions[:len(chars)]):
result.append(char)
if pred in self.label2punc and self.label2punc[pred]:
result.append(self.label2punc[pred])return ''.join(result)
# 使用示例
if __name__ == "__main__":
punctuator = ClassicalChinesePunctuator()
text = "学而时习之不亦说乎有朋自远方来不亦乐乎"
result = punctuator.punctuate(text)
print(f"原文:{text}")
print(f"断句:{result}")
`方案三:基于规则的优化方案(轻量级)
`python
import re
import jieba
import jieba.posseg as psegclass RuleBasedSegmenter:
"""基于规则的断句器,适合简单文本"""def __init__(self):
# 加载古汉语词典(如果有的话)
try:
jieba.load_userdict("classical_chinese_dict.txt")
except:
pass# 常见句首词
self.sentence_starters = {
'夫', '盖', '惟', '唯', '然', '而', '故', '是以', '是故',
'若', '苟', '使', '令', '纵', '虽', '即', '则', '且',
'乃', '遂', '于是', '然后', '至于', '若夫'
}# 常见句末词
self.sentence_enders = {
'也', '矣', '乎', '哉', '焉', '耳', '耶', '欤', '兮',
'而已', '而已矣', '者也'
}def segment(self, text):
"""基础断句"""
# 第一步:按常见句末词初步分割
pattern = '|'.join([re.escape(word) for word in self.sentence_enders])
sentences = re.split(f'({pattern})', text)# 重新组合
result = []
i = 0
while i < len(sentences):
if i + 1 < len(sentences) and sentences[i+1] in self.sentence_enders:
result.append(sentences[i] + sentences[i+1] + '。')
i += 2
else:
if sentences[i].strip():
result.append(sentences[i] + ',')
i += 1return ''.join(result)
def advanced_segment(self, text):
"""使用词性分析的高级断句"""
words = pseg.cut(text)
result = []
current_sentence = []for word, flag in words:
current_sentence.append(word)# 根据词性和规则判断是否断句
if self.should_end_sentence(word, flag, current_sentence):
sentence = ''.join(current_sentence)
if sentence.strip():
result.append(sentence + '。')
current_sentence = []if current_sentence:
result.append(''.join(current_sentence) + '。')return ''.join(result)
def should_end_sentence(self, word, flag, sentence_context):
"""判断是否应该结束句子"""
# 虚词结尾
if word in self.sentence_enders:
return True# 句子过长(超过20字)
if len(''.join(sentence_context)) > 20:
return Truereturn False
# 使用示例
if __name__ == "__main__":
segmenter = RuleBasedSegmenter()
text = "道可道非常道名可名非常名"print("基于规则断句:")
print(segmenter.segment(text))
`完整的生产级方案
`python
import argparse
import json
from pathlib import Path
from typing import List, Dict
import loggingclass ProductionSegmenter:
"""生产环境使用的古文断句器"""def __init__(self, strategy="hybrid", api_key=None):
self.strategy = strategy
self.api_key = api_key
self.logger = self._setup_logger()# 根据策略初始化不同的处理器
if strategy == "api":
from openai import OpenAI
self.client = OpenAI(api_key=api_key)
elif strategy == "local":
self.local_model = OpenSourceSegmenter()
elif strategy == "hybrid":
# 混合策略:先尝试本地模型,失败则用API
try:
self.local_model = OpenSourceSegmenter()
except:
self.local_model = None
self.client = OpenAI(api_key=api_key) if api_key else Nonedef process_file(self, input_path: str, output_path: str = None):
"""处理文件"""
with open(input_path, 'r', encoding='utf-8') as f:
text = f.read()result = self.segment_text(text)
if output_path:
with open(output_path, 'w', encoding='utf-8') as f:
f.write(result)return result
def segment_text(self, text: str) -> str:
"""主断句函数"""
if self.strategy == "api" and self.client:
return self._segment_with_api(text)
elif self.strategy == "local" and hasattr(self, 'local_model'):
return self.local_model.segment_text(text)
else:
# 混合策略
try:
return self.local_model.segment_text(text)
except:
if self.client:
return self._segment_with_api(text)
else:
raise Exception("No available segmenter")def _segment_with_api(self, text: str) -> str:
"""使用API断句"""
prompt = f"""请为以下古文添加正确的标点符号,保持原意不变:{text}
请返回添加标点后的完整文本:"""
response = self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "你是专业的古籍整理专家。"},
{"role": "user", "content": prompt}
],
temperature=0.3
)return response.choices[0].message.content
def _setup_logger(self):
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
return logger# 命令行接口
def main():
parser = argparse.ArgumentParser(description="古文自动断句工具")
parser.add_argument("input", help="输入文件或文本")
parser.add_argument("-o", "--output", help="输出文件")
parser.add_argument("--strategy", choices=["api", "local", "hybrid"],
default="hybrid", help="断句策略")
parser.add_argument("--api-key", help="OpenAI API密钥")args = parser.parse_args()
segmenter = ProductionSegmenter(
strategy=args.strategy,
api_key=args.api_key
)# 判断输入是文件还是文本
input_path = Path(args.input)
if input_path.exists():
result = segmenter.process_file(args.input, args.output)
else:
result = segmenter.segment_text(args.input)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(result)print("断句结果:")
print(result)if __name__ == "__main__":
main()
`效果评估和优化建议
1. 准确率对比
· 商业大模型(GPT-4/Claude): 准确率90-95%
· 专用古文模型: 准确率85-90%
· 规则方法: 准确率60-75%2. 优化建议
`python
# 1. 添加后处理
def post_process(text):
"""后处理:修正常见错误"""
corrections = {
r',。': '。', # 修正多余的标点
r'。。': '。',
r'\s+,': ',', # 去除标点前的空格
}for pattern, replacement in corrections.items():
text = re.sub(pattern, replacement, text)return text
# 2. 添加领域适配
def domain_adaptation(text, domain="历史"):
"""根据不同领域调整"""
if domain == "历史":
# 历史文献特有处理
pass
elif domain == "诗词":
# 诗词特有处理
passreturn text
`3. 部署建议
1. 小规模使用: 直接使用GPT API
2. 大规模使用: 微调专用模型(如BERT)
3. 离线环境: 使用Qwen-7B等本地模型
4. 精度要求高: 人工校对+AI辅助总结
大模型在古文断句方面已经非常成熟,特别是:
· GPT-4对古文理解准确
· 专用古文模型效果也不错
· 混合方案(规则+AI)效果最佳建议从方案一开始尝试,根据实际需求调整。如果需要更高精度,可以考虑:
1. 收集标注数据微调模型
2. 结合多模型投票机制
3. 添加人工校对接口需要我详细解释某个特定部分,或者针对特定类型的古文(如诗词、史书、经典)提供专门的优化方案吗?
赤霄游客import re
import torch
import numpy as np
from collections import defaultdict
from typing import List, Tuple, Dict, Optional
import logging
from dataclasses import dataclass
import json
# 如果使用大模型API
try:
import openai
from openai import OpenAI
OPENAI_AVAILABLE = True
except ImportError:
OPENAI_AVAILABLE = False
# 如果使用本地模型
try:
from transformers import AutoTokenizer, AutoModelForTokenClassification
TRANSFORMERS_AVAILABLE = True
except ImportError:
TRANSFORMERS_AVAILABLE = False
@dataclass
class SegmentationResult:
"""断句结果数据结构"""
text: str
sentences: List[str]
confidence: float
method_used: str
metadata: Dict
class ClassicalChineseSegmenter:
"""混合方案古文断句器"""
def __init__(self, config_path: str = None):
# 配置
self.config = self._load_config(config_path)
# 初始化日志
self.logger = self._setup_logger()
# 初始化各模块
self.rules_engine = RuleBasedSegmenter()
self.statistical_model = StatisticalSegmenter()
self.deep_learning_model = None
self.llm_model = None
# 初始化深度学习模型(如果可用)
if self.config.get("use_dl_model", True) and TRANSFORMERS_AVAILABLE:
self._init_deep_learning_model()
# 初始化大模型(如果配置了API)
if self.config.get("use_llm_fallback", False) and OPENAI_AVAILABLE:
self._init_llm_model()
# 权重设置
self.weights = {
"rules": self.config.get("rule_weight", 0.2),
"statistical": self.config.get("statistical_weight", 0.3),
"deep_learning": self.config.get("dl_weight", 0.5)
}
# 缓存机制
self.cache = {}
self.cache_size = self.config.get("cache_size", 1000)
self.logger.info("古文断句器初始化完成")
def _load_config(self, config_path: str) -> Dict:
"""加载配置文件"""
default_config = {
"use_dl_model": True,
"use_llm_fallback": False,
"llm_model": "gpt-4",
"dl_model_path": "ethanyt/guwen-punctuate",
"rule_weight": 0.2,
"statistical_weight": 0.3,
"dl_weight": 0.5,
"confidence_threshold": 0.8,
"cache_size": 1000,
"log_level": "INFO"
}
if config_path:
try:
with open(config_path, 'r', encoding='utf-8') as f:
user_config = json.load(f)
default_config.update(user_config)
except:
pass
return default_config
def _setup_logger(self):
"""设置日志"""
logger = logging.getLogger("ClassicalChineseSegmenter")
logger.setLevel(getattr(logging, self.config.get("log_level", "INFO")))
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def _init_deep_learning_model(self):
"""初始化深度学习模型"""
try:
self.logger.info("正在加载深度学习模型...")
self.deep_learning_model = DeepLearningSegmenter(
model_path=self.config["dl_model_path"]
)
self.logger.info("深度学习模型加载完成")
except Exception as e:
self.logger.warning(f"深度学习模型加载失败: {e}")
self.deep_learning_model = None
def _init_llm_model(self):
"""初始化大语言模型"""
try:
api_key = self.config.get("openai_api_key")
if api_key:
self.llm_model = LLMSegmenter(
api_key=api_key,
model=self.config.get("llm_model", "gpt-4")
)
self.logger.info("大语言模型初始化完成")
except Exception as e:
self.logger.warning(f"大语言模型初始化失败: {e}")
def segment(self, text: str, use_cache: bool = True) -> SegmentationResult:
"""
主断句函数
Args:
text: 输入文本
use_cache: 是否使用缓存
Returns:
SegmentationResult: 断句结果
"""
# 1. 检查缓存
cache_key = hash(text)
if use_cache and cache_key in self.cache:
self.logger.debug("使用缓存结果")
return self.cache[cache_key]
# 2. 清理文本
cleaned_text = self._preprocess_text(text)
# 3. 多方法并行处理
results = []
confidences = []
# 规则方法
rule_result = self.rules_engine.segment(cleaned_text)
rule_confidence = self.rules_engine.calculate_confidence(cleaned_text)
results.append(rule_result)
confidences.append(rule_confidence)
self.logger.debug(f"规则方法置信度: {rule_confidence:.3f}")
# 统计方法
stat_result = self.statistical_model.segment(cleaned_text)
stat_confidence = self.statistical_model.calculate_confidence(cleaned_text)
results.append(stat_result)
confidences.append(stat_confidence)
self.logger.debug(f"统计方法置信度: {stat_confidence:.3f}")
# 深度学习方法
dl_result = None
dl_confidence = 0.0
if self.deep_learning_model:
try:
dl_result = self.deep_learning_model.segment(cleaned_text)
dl_confidence = self.deep_learning_model.calculate_confidence(cleaned_text)
results.append(dl_result)
confidences.append(dl_confidence)
self.logger.debug(f"深度学习置信度: {dl_confidence:.3f}")
except Exception as e:
self.logger.error(f"深度学习方法出错: {e}")
# 4. 加权投票
final_result, final_confidence, method_used = self._weighted_vote(
results, confidences
)
# 5. 后处理
final_result = self._postprocess(final_result)
# 6. 如果置信度低,使用大模型作为后备
if (final_confidence < self.config["confidence_threshold"] and
self.llm_model and len(text) < 2000): # 限制文本长度
self.logger.info("置信度过低,使用大模型作为后备")
try:
llm_result = self.llm_model.segment(cleaned_text)
final_result = llm_result
final_confidence = 0.95 # 大模型通常有高置信度
method_used = "llm_fallback"
except Exception as e:
self.logger.error(f"大模型后备方案失败: {e}")
# 7. 分割句子
sentences = self._split_into_sentences(final_result)
# 8. 构建结果
result = SegmentationResult(
text=final_result,
sentences=sentences,
confidence=final_confidence,
method_used=method_used,
metadata={
"rule_confidence": rule_confidence,
"stat_confidence": stat_confidence,
"dl_confidence": dl_confidence if self.deep_learning_model else None,
"original_length": len(text),
"processed_length": len(cleaned_text)
}
)
# 9. 更新缓存
if use_cache:
self._update_cache(cache_key, result)
return result
def _weighted_vote(self, results: List[str], confidences: List[float]) -> Tuple[str, float, str]:
"""加权投票决策"""
# 如果只有一个结果
if len(results) == 1:
return results[0], confidences[0], "rules_only"
# 计算每个位置的标点概率
max_len = max(len(r) for r in results)
punctuation_votes = defaultdict(lambda: defaultdict(float))
for result, confidence, method in zip(results, confidences, ["rules", "statistical", "deep_learning"]):
weight = self.weights.get(method, 0.0)
if weight == 0:
continue
for i, char in enumerate(result):
if i >= max_len:
break
if char in "。,;:!?、":
punctuation_votes[i][char] += weight * confidence
# 构建最终结果(以第一个结果为字符基础)
base_result = results[0]
final_chars = list(base_result.ljust(max_len, ' '))
for i in range(max_len):
if i < len(base_result) and base_result[i] in "。,;:!?、":
continue # 已经有标点
if i in punctuation_votes:
votes = punctuation_votes[i]
if votes:
best_punct = max(votes.items(), key=lambda x: x[1])[0]
final_chars[i] = best_punct
final_result = ''.join(final_chars).strip()
# 计算平均置信度
valid_confidences = [c for c in confidences if c > 0]
avg_confidence = sum(valid_confidences) / len(valid_confidences) if valid_confidences else 0.0
# 确定使用的方法
if len(results) == 3 and confidences[2] > 0.7: # 深度学习置信度高
method_used = "deep_learning_primary"
elif confidences[1] > 0.8: # 统计方法置信度高
method_used = "statistical_primary"
else:
method_used = "weighted_vote"
return final_result, avg_confidence, method_used
def _preprocess_text(self, text: str) -> str:
"""文本预处理"""
# 移除多余空格和换行
text = re.sub(r'\s+', '', text)
# 移除现代标点(如果有)
text = re.sub(r'[.,;:!?]', '', text)
return text
def _postprocess(self, text: str) -> str:
"""后处理"""
# 修正常见错误
corrections = [
(r',。', '。'),
(r'。。+', '。'),
(r',,+', ','),
(r'^,', ''), # 开头不能是逗号
(r'。$', ''), # 结尾的句号可能不需要
(r'([。!?]),', r'\1'), # 句末标点后不能跟逗号
]
for pattern, replacement in corrections:
text = re.sub(pattern, replacement, text)
# 确保标点平衡
opening = len(re.findall(r'[「『《(〔【]', text))
closing = len(re.findall(r'[」』》)〕】]', text))
if opening > closing:
text += '」' * (opening - closing)
return text
def _split_into_sentences(self, text: str) -> List[str]:
"""将文本分割成句子"""
# 按句末标点分割
sentences = re.split(r'([。!?])', text)
# 重新组合
result = []
i = 0
while i < len(sentences):
if i + 1 < len(sentences) and sentences[i+1] in '。!?':
sentence = sentences[i] + sentences[i+1]
if sentence.strip():
result.append(sentence.strip())
i += 2
else:
if sentences[i].strip():
result.append(sentences[i].strip())
i += 1
return result
def _update_cache(self, key: int, result: SegmentationResult):
"""更新缓存"""
if len(self.cache) >= self.cache_size:
# 移除最旧的缓存项
oldest_key = next(iter(self.cache))
del self.cache[oldest_key]
self.cache[key] = result
def batch_segment(self, texts: List[str], batch_size: int = 10) -> List[SegmentationResult]:
"""批量处理"""
results = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
batch_results = [self.segment(text, use_cache=True) for text in batch]
results.extend(batch_results)
self.logger.info(f"已处理 {min(i+batch_size, len(texts))}/{len(texts)} 个文本")
return results
# ============ 子模块实现 ============
class RuleBasedSegmenter:
"""基于规则的断句器"""
def __init__(self):
# 加载规则
self.rules = self._load_rules()
# 常见虚词
self.sentence_end_particles = {
'也', '矣', '乎', '哉', '焉', '耳', '耶', '欤', '兮',
'而已', '而已矣', '者也', '者矣', '者也矣'
}
self.sentence_start_particles = {
'夫', '盖', '惟', '唯', '然', '而', '故', '是以', '是故',
'若', '苟', '使', '令', '纵', '虽', '即', '则', '且',
'乃', '遂', '于是', '然后', '至于', '若夫'
}
# 四字成语/常见搭配(通常不断开)
self.fixed_expressions = {
'天衣无缝', '画蛇添足', '守株待兔', '刻舟求剑',
'卧薪尝胆', '破釜沉舟', '高山流水', '知足常乐'
}
def _load_rules(self) -> List[Dict]:
"""加载断句规则"""
return [
# 规则1:常见句末虚词后加句号
{
'pattern': r'([^。,;:!?])({})(?![。,;:!?])'.format(
'|'.join(self.sentence_end_particles)
),
'replacement': r'\1\2。',
'weight': 0.8
},
# 规则2:常见句首虚词前加分句
{
'pattern': r'([。!?])({})'.format(
'|'.join(self.sentence_start_particles)
),
'replacement': r'\1\n\2',
'weight': 0.7
},
# 规则3:引用标记
{
'pattern': r'([「『《])([^」』》]+)([」』》])',
'replacement': r'\1\2\3,',
'weight': 0.6
}
]
def segment(self, text: str) -> str:
"""应用规则进行断句"""
result = text
for rule in self.rules:
pattern = rule['pattern']
replacement = rule['replacement']
# 应用规则
result = re.sub(pattern, replacement, result)
# 添加基础逗号(按固定长度)
result = self._add_basic_punctuation(result)
return result
def _add_basic_punctuation(self, text: str) -> str:
"""添加基础标点(按长度)"""
chars = list(text)
result = []
for i, char in enumerate(chars):
result.append(char)
# 每8-15个字符加逗号,除非在固定表达式中
if i > 0 and (i + 1) % 12 == 0:
# 检查前后字符是否组成固定表达式
context = ''.join(chars[max(0, i-3):min(len(chars), i+4)])
should_break = True
for expr in self.fixed_expressions:
if expr in context:
should_break = False
break
if should_break and char not in '。,;:!?、':
result.append(',')
return ''.join(result)
def calculate_confidence(self, text: str) -> float:
"""计算规则方法的置信度"""
# 基于规则匹配程度计算置信度
matches = 0
total_patterns = len(self.rules) * 2 # 考虑正向和反向规则
for rule in self.rules:
pattern = rule['pattern']
if re.search(pattern, text):
matches += 1
confidence = matches / total_patterns if total_patterns > 0 else 0.5
# 考虑文本长度:短文本置信度较低
length_factor = min(len(text) / 50, 1.0) # 50字以上置信度不再增加
return confidence * 0.5 + length_factor * 0.5
class StatisticalSegmenter:
"""基于统计的断句器(N-gram模型)"""
def __init__(self, ngram_path: str = None):
self.n = 3 # 使用trigram
self.ngram_probs = defaultdict(float)
self.punctuation_probs = defaultdict(float)
# 加载预训练的统计模型
if ngram_path and os.path.exists(ngram_path):
self.load_model(ngram_path)
else:
# 使用内置的简单统计
self._init_default_stats()
def _init_default_stats(self):
"""初始化默认统计信息"""
# 基于常见古文的统计
self.punctuation_probs = {
'。': 0.15, # 句号概率
',': 0.25, # 逗号概率
';': 0.05, # 分号概率
':': 0.03, # 冒号概率
'!': 0.02, # 感叹号概率
'?': 0.02, # 问号概率
}
def segment(self, text: str) -> str:
"""使用统计方法断句"""
if len(text) < 10:
return text # 太短的文本不处理
chars = list(text)
result = []
for i in range(len(chars)):
result.append(chars[i])
# 计算当前位置加标点的概率
if i > 0 and i < len(chars) - 1:
context = ''.join(chars[max(0, i-2):i+1])
punct_prob = self._get_punctuation_probability(context, i, chars)
# 根据概率决定是否加标点
if punct_prob > 0.7: # 高概率加句号
result.append('。')
elif punct_prob > 0.5: # 中等概率加逗号
result.append(',')
return ''.join(result)
def _get_punctuation_probability(self, context: str, position: int, chars: List[str]) -> float:
"""获取当前位置加标点的概率"""
# 基于上下文的简单概率计算
base_prob = 0.0
# 检查上下文特征
if position > 0:
prev_char = chars[position-1]
# 句末虚词
if prev_char in '也矣乎哉焉耳':
base_prob += 0.3
# 四字结构后
if position % 4 == 0 and position >= 4:
base_prob += 0.2
# 常见结尾模式
endings = ['而已', '者也', '之谓']
for ending in endings:
if position >= len(ending) and ''.join(chars[position-len(ending):position]) == ending:
base_prob += 0.4
return min(base_prob, 1.0)
def calculate_confidence(self, text: str) -> float:
"""计算统计方法的置信度"""
# 基于文本长度和特征丰富度
length = len(text)
if length < 20:
return 0.4 # 短文本置信度低
elif length < 100:
return 0.6
else:
return 0.7
class DeepLearningSegmenter:
"""基于深度学习的断句器"""
def __init__(self, model_path: str = "ethanyt/guwen-punctuate"):
self.model_path = model_path
self.tokenizer = None
self.model = None
self.device = None
self._load_model()
def _load_model(self):
"""加载模型"""
if not TRANSFORMERS_AVAILABLE:
raise ImportError("transformers库未安装")
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.tokenizer = AutoTokenizer.from_pretrained(self.model_path)
self.model = AutoModelForTokenClassification.from_pretrained(self.model_path)
self.model.to(self.device)
self.model.eval()
def segment(self, text: str) -> str:
"""使用深度学习模型断句"""
# 将文本转换为字符序列
chars = list(text.replace(' ', ''))
# 编码
inputs = self.tokenizer(
chars,
is_split_into_words=True,
return_tensors="pt",
padding=True,
truncation=True
)
inputs = {k: v.to(self.device) for k, v in inputs.items()}
# 预测
with torch.no_grad():
outputs = self.model(**inputs)
predictions = torch.argmax(outputs.logits, dim=-1)[0].cpu().numpy()
# 映射标签到标点
label_map = {
0: '', # 无标点
1: ',', # 逗号
2: '。', # 句号
3: '?', # 问号
4: '!', # 感叹号
}
# 构建结果
result = []
for char, pred in zip(chars, predictions[:len(chars)]):
result.append(char)
if pred in label_map and label_map[pred]:
result.append(label_map[pred])
return ''.join(result)
def calculate_confidence(self, text: str) -> float:
"""计算深度学习模型的置信度"""
# 使用模型输出的概率分布计算置信度
chars = list(text.replace(' ', ''))
inputs = self.tokenizer(
chars,
is_split_into_words=True,
return_tensors="pt",
padding=True
)
inputs = {k: v.to(self.device) for k, v in inputs.items()}
with torch.no_grad():
outputs = self.model(**inputs)
probabilities = torch.softmax(outputs.logits, dim=-1)[0]
# 计算平均最大概率
max_probs, _ = torch.max(probabilities, dim=-1)
avg_max_prob = torch.mean(max_probs[:len(chars)]).item()
return float(avg_max_prob)
class LLMSegmenter:
"""基于大语言模型的断句器"""
def __init__(self, api_key: str, model: str = "gpt-4"):
if not OPENAI_AVAILABLE:
raise ImportError("openai库未安装")
self.client = OpenAI(api_key=api_key)
self.model = model
# 系统提示词
self.system_prompt = """你是一位精通古代汉语的专家,请为古文添加正确的标点符号。
要求:
1. 严格按照古文语法和意义断句
2. 使用正确的古汉语标点:句号(。)、逗号(,)、分号(;)、冒号(:)、感叹号(!)、问号(?)
3. 保持原文内容不变,只添加标点
4. 对专有名词、典故要特别注意
5. 注意对仗、排比等修辞结构
请直接返回添加标点后的完整文本,不要添加任何解释。"""
def segment(self, text: str) -> str:
"""使用大模型断句"""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": f"请为以下古文添加标点:\n\n{text}"}
],
temperature=0.1, # 低温度确保稳定性
max_tokens=len(text) * 2,
)
return response.choices[0].message.content.strip()
# ============ 使用示例 ============
def main():
"""使用示例"""
import os
# 1. 创建配置
config = {
"use_dl_model": True,
"use_llm_fallback": False, # 设置为True并添加API key以启用
"openai_api_key": os.getenv("OPENAI_API_KEY", ""),
"rule_weight": 0.2,
"statistical_weight": 0.3,
"dl_weight": 0.5,
"confidence_threshold": 0.75,
"log_level": "INFO"
}
# 保存配置
with open("segmenter_config.json", "w", encoding="utf-8") as f:
json.dump(config, f, ensure_ascii=False, indent=2)
# 2. 初始化断句器
segmenter = ClassicalChineseSegmenter("segmenter_config.json")
# 3. 测试文本
test_texts = [
# 《道德经》节选
"道可道非常道名可名非常名无名天地之始有名万物之母",
# 《庄子》节选
"北冥有鱼其名为鲲鲲之大不知其几千里也化而为鸟其名为鹏鹏之背不知其几千里也",
# 《论语》节选
"学而时习之不亦说乎有朋自远方来不亦乐乎人不知而不愠不亦君子乎",
# 复杂文本
"夫天地者万物之逆旅也光阴者百代之过客也而浮生若梦为欢几何古人秉烛夜游良有以也",
]
# 4. 批量处理
print("=" * 60)
print("古文自动断句系统")
print("=" * 60)
for i, text in enumerate(test_texts, 1):
print(f"\n测试文本 {i}:")
print(f"原文: {text}")
result = segmenter.segment(text)
print(f"断句: {result.text}")
print(f"置信度: {result.confidence:.2%}")
print(f"使用的方法: {result.method_used}")
print("\n分割后的句子:")
for j, sentence in enumerate(result.sentences, 1):
print(f" {j:2d}. {sentence}")
# 5. 批量处理示例
print("\n" + "=" * 60)
print("批量处理示例")
print("=" * 60)
batch_results = segmenter.batch_segment(test_texts)
for i, result in enumerate(batch_results, 1):
print(f"\n文本{i}: {result.text[:50]}...")
print(f" 句子数: {len(result.sentences)}, 置信度: {result.confidence:.2%}")
if __name__ == "__main__":
# 安装依赖: pip install torch transformers openai
main()
赤霄游客看了古籍酷、北师大、北大、古联的对比,大概都是五万字的额度,只能说免费开放了但又不完全开放。
赤霄游客核心架构:
混合策略系统:规则方法 + 统计模型 + 深度学习 + 大模型后备
工作流程
1. 并行处理:三种方法同时运行
2. 加权投票:各方法按权重和置信度投票
3. 智能降级:置信度低时调用大模型
4. 后处理优化:修正常见标点错误
四大模块
· 规则引擎:基于古文虚词和语法规则
· 统计模型:N-gram概率判断断句位置
· 深度学习:BERT预训练模型(ethanyt/guwen-punctuate)
· 大模型:GPT-4等作为高成本后备
关键特性
✅ 可配置:支持JSON配置,权重可调
✅ 缓存机制:提升重复文本处理速度
✅ 批量处理:支持大批量古文处理
✅ 置信度评估:量化断句可靠性
✅ 自动降级:低置信度时启用后备方案
适用场景
· 古籍数字化批量处理
· 古文学习工具开发
· 文献研究预处理
· 出版校对辅助工具
本质:一个生产级的混合智能系统,在准确率、速度和成本间取得平衡。
赤霄游客
典中典游客哇 ,感谢大佬出手, 晚上研究一下怎么部署运行 ,有问题再反馈。感谢感谢。
architc游客这事儿有个“小”问题:如果做出这么个基于ai驱动的古文句读软件,如果自己掏腰包、不限数量、但只有自己使用,那当然什么话也没有;如果公开使用,这时候会每日使用“不限字数”且“完全免费”吗?没有别的意思,我看到楼上好几位留言都提到不满现有这个那个网站的“限制”。那既然对一件事“有反感”,那想来逻辑的结论是,轮到自己做,一定做得“更漂亮”。
也许日后就是“完全不设限且免费”,这当然非常非常好的事情,提前赞美都没有问题。但还是有点疑问。当然,也不指望谁当真回答,毕竟没发生的事情,说太早,日后万一做不到,也挺打脸的。
再说一次,不需要任何人当真答复,看过算过。
典中典游客感谢各位对这个话题的关注和耐心回复,使这个帖子不至于沉没过快。
对各个网站的不满主要是我发的。能用是能用,但用起来就是不爽快。我的诉求是能用量大。不一定非常“漂亮”,这也不敢奢望。商业网站有商业网站的逻辑。
相信论坛是有热心人的。从单纯书籍(很多人),下载工具(bookget),光学识别网站(看典),字体制作软件(赤霄),排版软件等,免费且已经很完善了。就觉得古籍数字化还缺失一个好用的标点工具或更贪心一下多文本对校工具。识别➕标点是实现古籍数字化的最重要环节。
相信ai时代,这些都会很快实现。
- 作者帖子
正在查看 18 个帖子:1-18 (共 18 个帖子)
正在查看 18 个帖子:1-18 (共 18 个帖子)
正在查看 18 个帖子:1-18 (共 18 个帖子)

