389 lines
14 KiB
Python
Executable File
389 lines
14 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
中文去AI化工具
|
||
基于 oh-my-writing-skill 的 humanizer-cn 技能
|
||
消除AI写作痕迹,让文章更自然
|
||
"""
|
||
|
||
import re
|
||
import json
|
||
from typing import Dict, List, Optional
|
||
|
||
class HumanizerCN:
|
||
"""中文去AI化处理器"""
|
||
|
||
def __init__(self):
|
||
# AI写作特征模式
|
||
self.ai_patterns = {
|
||
# 过度强调意义和历史地位
|
||
'overemphasis': [
|
||
r'彰显[了着]', r'见证[了着]', r'标志着', r'具有里程碑意义',
|
||
r'揭示了', r'体现了', r'承载着', r'奠定了基础',
|
||
r'树立了标杆', r'开创了先河', r'具有划时代意义', r'承前启后'
|
||
],
|
||
|
||
# 过度强调知名度和媒体报道
|
||
'overhype': [
|
||
r'广受关注', r'引发热议', r'备受瞩目', r'获得广泛报道',
|
||
r'在业界引起强烈反响', r'各大媒体纷纷报道'
|
||
],
|
||
|
||
# "-ing 式"假深度分析
|
||
'fake_depth': [
|
||
r'致力于', r'旨在', r'聚焦于', r'着眼于',
|
||
r'立足于', r'依托于', r'围绕着', r'基于', r'借助于'
|
||
],
|
||
|
||
# 广告式推销语言
|
||
'advertising': [
|
||
r'匠心独运', r'精心打造', r'倾力呈现', r'独具匠心',
|
||
r'别具一格', r'独树一帜', r'引领潮流', r'开启新篇章',
|
||
r'重新定义'
|
||
],
|
||
|
||
# 模糊归因和万金油说法
|
||
'vague_attribution': [
|
||
r'业内人士指出', r'专家表示', r'有观点认为',
|
||
r'据了解', r'据悉', r'相关人士透露', r'多方消息显示'
|
||
],
|
||
|
||
# 套路化的"挑战与展望"段落
|
||
'cliche_ending': [
|
||
r'尽管如此', r'虽然面临挑战', r'但我们有理由相信',
|
||
r'未来可期', r'前景广阔', r'任重道远', r'砥砺前行'
|
||
],
|
||
|
||
# 高频AI词汇
|
||
'ai_vocabulary': [
|
||
r'此外', r'值得一提的是', r'值得注意的是',
|
||
r'不言而喻', r'毋庸置疑', r'显而易见',
|
||
r'与此同时', r'综上所述', r'总而言之',
|
||
r'一言以蔽之', r'鉴于此', r'基于此',
|
||
r'有鉴于此', r'就此而言', r'从某种意义上说'
|
||
],
|
||
|
||
# 回避简单动词
|
||
'avoid_simple_verbs': [
|
||
r'作为[^,。]*而存在', r'扮演着[^,。]*的角色',
|
||
r'承担着[^,。]*的使命', r'发挥着[^,。]*的作用',
|
||
r'被视为', r'被认为是'
|
||
],
|
||
|
||
# 否定式并列句
|
||
'negative_parallel': [
|
||
r'不仅[^,。]*更是[^,。]*',
|
||
r'不只是[^,。]*而是[^,。]*'
|
||
],
|
||
|
||
# 三段式堆砌
|
||
'triple_structure': [
|
||
r'创新、品质与服务的完美结合',
|
||
r'高效、稳定、易用三大特点'
|
||
]
|
||
}
|
||
|
||
# 替换映射
|
||
self.replacement_map = {
|
||
# 语气转换
|
||
'本文将介绍': '今天来聊聊',
|
||
'建议用户': '建议大家',
|
||
'该产品性能优秀': '这个真的很好用',
|
||
'综上所述': '总之就是',
|
||
'值得注意的是': '划重点',
|
||
'需要指出的是': '这里要注意',
|
||
'根据研究显示': '我发现',
|
||
'一般来说': '通常来说',
|
||
'具体来说': '具体来说',
|
||
'换句话说': '简单说就是',
|
||
'例如': '比如',
|
||
'此外': '另外',
|
||
'然而': '不过',
|
||
'因此': '所以',
|
||
'最终': '最后',
|
||
|
||
# 简化表达
|
||
'为了能够实现这一目标': '为了',
|
||
'由于这一事实的存在': '因为',
|
||
'在当前这个时间点上': '现在',
|
||
'在如果需要帮助的情况下': '如果需要帮助',
|
||
'具有能够处理的能力': '能处理',
|
||
'需要特别指出的是': '',
|
||
|
||
# 具体化
|
||
'该项目一经发布便引发业界广泛关注': '发布后反响不错',
|
||
'业内专家普遍认为': '有专家认为',
|
||
'具有广阔的应用前景': '应用前景不错',
|
||
'对行业产生深远影响': '对行业影响挺大'
|
||
}
|
||
|
||
def detect_ai_patterns(self, text: str) -> Dict:
|
||
"""检测AI写作模式"""
|
||
detection = {
|
||
'total_patterns': 0,
|
||
'patterns_by_type': {},
|
||
'suggestions': []
|
||
}
|
||
|
||
for pattern_type, patterns in self.ai_patterns.items():
|
||
count = 0
|
||
found_patterns = []
|
||
|
||
for pattern in patterns:
|
||
matches = re.findall(pattern, text)
|
||
if matches:
|
||
count += len(matches)
|
||
found_patterns.extend(matches)
|
||
|
||
if count > 0:
|
||
detection['patterns_by_type'][pattern_type] = {
|
||
'count': count,
|
||
'examples': list(set(found_patterns))[:3] # 最多显示3个例子
|
||
}
|
||
detection['total_patterns'] += count
|
||
|
||
# 生成建议
|
||
if detection['total_patterns'] > 10:
|
||
detection['suggestions'].append('AI痕迹较重,建议全面重写')
|
||
elif detection['total_patterns'] > 5:
|
||
detection['suggestions'].append('有较多AI痕迹,建议重点修改')
|
||
elif detection['total_patterns'] > 0:
|
||
detection['suggestions'].append('有少量AI痕迹,建议微调')
|
||
else:
|
||
detection['suggestions'].append('AI痕迹较少,质量不错')
|
||
|
||
return detection
|
||
|
||
def humanize_text(self, text: str, aggressive: bool = False) -> str:
|
||
"""去AI化处理"""
|
||
if not text:
|
||
return text
|
||
|
||
# 第一步:替换模式化表达
|
||
humanized = text
|
||
for pattern, replacement in self.replacement_map.items():
|
||
humanized = humanized.replace(pattern, replacement)
|
||
|
||
# 第二步:处理段落结构
|
||
paragraphs = humanized.split('\n\n')
|
||
processed_paragraphs = []
|
||
|
||
for para in paragraphs:
|
||
if not para.strip():
|
||
processed_paragraphs.append(para)
|
||
continue
|
||
|
||
# 缩短长段落
|
||
if len(para) > 200:
|
||
sentences = re.split(r'[。!?]', para)
|
||
if len(sentences) > 3:
|
||
para = '。'.join(sentences[:3]) + '。'
|
||
|
||
# 添加一点"人味"
|
||
if aggressive and len(para) > 50:
|
||
# 随机添加一些口语化表达
|
||
import random
|
||
human_touches = [
|
||
'说实话',
|
||
'我个人觉得',
|
||
'其实吧',
|
||
'怎么说呢',
|
||
'你猜怎么着'
|
||
]
|
||
|
||
if random.random() < 0.3: # 30%概率添加
|
||
touch = random.choice(human_touches)
|
||
para = f"{touch},{para}"
|
||
|
||
processed_paragraphs.append(para)
|
||
|
||
humanized = '\n\n'.join(processed_paragraphs)
|
||
|
||
# 第三步:修复过度修饰
|
||
# 移除过多的修饰词
|
||
modifiers = ['非常', '极其', '十分', '特别', '相当', '颇为']
|
||
for modifier in modifiers:
|
||
pattern = rf'{modifier}[的得地]?[^,。]*?的'
|
||
humanized = re.sub(pattern, '', humanized)
|
||
|
||
# 第四步:简化列表结构
|
||
lines = humanized.split('\n')
|
||
simplified_lines = []
|
||
|
||
for line in lines:
|
||
# 简化加粗列表项
|
||
if re.search(r'\*\*.*?\*\*:', line):
|
||
line = re.sub(r'\*\*(.*?)\*\*:', r'\1:', line)
|
||
|
||
simplified_lines.append(line)
|
||
|
||
humanized = '\n'.join(simplified_lines)
|
||
|
||
return humanized
|
||
|
||
def add_human_touch(self, text: str) -> str:
|
||
"""添加人味"""
|
||
if not text:
|
||
return text
|
||
|
||
# 添加一些个人化的表达
|
||
touches = [
|
||
'我试过',
|
||
'我的经验是',
|
||
'说实话',
|
||
'个人觉得',
|
||
'其实吧',
|
||
'你猜怎么着',
|
||
'没想到的是'
|
||
]
|
||
|
||
import random
|
||
|
||
# 在开头添加
|
||
if random.random() < 0.4:
|
||
touch = random.choice(touches)
|
||
text = f"{touch},{text}"
|
||
|
||
# 在中间随机添加
|
||
sentences = re.split(r'[。!?]', text)
|
||
if len(sentences) > 2:
|
||
insert_pos = random.randint(1, len(sentences)-1)
|
||
touch = random.choice(touches)
|
||
sentences.insert(insert_pos, f"{touch},")
|
||
text = '。'.join(sentences)
|
||
|
||
return text
|
||
|
||
def analyze_and_humanize(self, text: str) -> Dict:
|
||
"""分析并去AI化"""
|
||
print("🔍 分析文本中的AI痕迹...")
|
||
|
||
# 检测AI模式
|
||
detection = self.detect_ai_patterns(text)
|
||
|
||
print(f"📊 检测结果:")
|
||
print(f" 总AI模式数: {detection['total_patterns']}")
|
||
|
||
for pattern_type, info in detection['patterns_by_type'].items():
|
||
print(f" {pattern_type}: {info['count']} 处")
|
||
if info['examples']:
|
||
print(f" 示例: {', '.join(info['examples'][:2])}")
|
||
|
||
# 去AI化处理
|
||
print("\n🛠️ 进行去AI化处理...")
|
||
humanized = self.humanize_text(text, aggressive=detection['total_patterns'] > 5)
|
||
|
||
# 添加人味(如果需要)
|
||
if detection['total_patterns'] > 3:
|
||
print("💬 添加人味...")
|
||
humanized = self.add_human_touch(humanized)
|
||
|
||
# 计算改进程度
|
||
original_length = len(text)
|
||
humanized_length = len(humanized)
|
||
length_change = ((humanized_length - original_length) / original_length) * 100
|
||
|
||
result = {
|
||
'original_text': text,
|
||
'humanized_text': humanized,
|
||
'detection': detection,
|
||
'stats': {
|
||
'original_length': original_length,
|
||
'humanized_length': humanized_length,
|
||
'length_change_percent': round(length_change, 2),
|
||
'ai_patterns_removed': detection['total_patterns']
|
||
},
|
||
'suggestions': detection['suggestions']
|
||
}
|
||
|
||
print(f"✅ 处理完成")
|
||
print(f" 原文长度: {original_length} 字符")
|
||
print(f" 处理后长度: {humanized_length} 字符")
|
||
print(f" 长度变化: {length_change:.1f}%")
|
||
print(f" 建议: {', '.join(detection['suggestions'])}")
|
||
|
||
return result
|
||
|
||
def main():
|
||
"""主函数"""
|
||
import argparse
|
||
|
||
parser = argparse.ArgumentParser(description='中文去AI化工具')
|
||
subparsers = parser.add_subparsers(dest='command', help='命令')
|
||
|
||
# analyze命令
|
||
analyze_parser = subparsers.add_parser('analyze', help='分析文本')
|
||
analyze_parser.add_argument('--text', help='要分析的文本')
|
||
analyze_parser.add_argument('--file', help='文本文件路径')
|
||
|
||
# humanize命令
|
||
humanize_parser = subparsers.add_parser('humanize', help='去AI化处理')
|
||
humanize_parser.add_argument('--text', help='要处理的文本')
|
||
humanize_parser.add_argument('--file', help='文本文件路径')
|
||
humanize_parser.add_argument('--output', help='输出文件路径')
|
||
humanize_parser.add_argument('--aggressive', action='store_true', help='激进模式')
|
||
|
||
# test命令
|
||
subparsers.add_parser('test', help='测试功能')
|
||
|
||
args = parser.parse_args()
|
||
|
||
humanizer = HumanizerCN()
|
||
|
||
if args.command == 'analyze':
|
||
text = args.text
|
||
if args.file:
|
||
with open(args.file, 'r', encoding='utf-8') as f:
|
||
text = f.read()
|
||
|
||
if not text:
|
||
print("❌ 请提供文本")
|
||
return
|
||
|
||
result = humanizer.analyze_and_humanize(text)
|
||
print("\n📊 分析结果:")
|
||
print(json.dumps(result['detection'], indent=2, ensure_ascii=False))
|
||
|
||
elif args.command == 'humanize':
|
||
text = args.text
|
||
if args.file:
|
||
with open(args.file, 'r', encoding='utf-8') as f:
|
||
text = f.read()
|
||
|
||
if not text:
|
||
print("❌ 请提供文本")
|
||
return
|
||
|
||
result = humanizer.analyze_and_humanize(text)
|
||
|
||
if args.output:
|
||
with open(args.output, 'w', encoding='utf-8') as f:
|
||
f.write(result['humanized_text'])
|
||
print(f"✅ 已保存到: {args.output}")
|
||
else:
|
||
print("\n📝 处理后的文本:")
|
||
print("=" * 60)
|
||
print(result['humanized_text'])
|
||
print("=" * 60)
|
||
|
||
elif args.command == 'test':
|
||
test_text = """该软件的发布标志着人工智能领域的一个重要里程碑,彰显了公司在技术创新方面的不懈追求。此外,值得一提的是,该产品具有高性能、低功耗、易扩展三大优势。业内专家普遍认为,这将对整个行业产生深远影响。尽管面临诸多挑战,但我们有理由相信,未来可期。"""
|
||
|
||
print("🧪 测试去AI化功能")
|
||
print("=" * 60)
|
||
print("测试文本:")
|
||
print(test_text)
|
||
print("=" * 60)
|
||
|
||
result = humanizer.analyze_and_humanize(test_text)
|
||
|
||
print("\n📝 处理后的文本:")
|
||
print("=" * 60)
|
||
print(result['humanized_text'])
|
||
print("=" * 60)
|
||
|
||
else:
|
||
parser.print_help()
|
||
|
||
if __name__ == "__main__":
|
||
main()
|