-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfinal-converter (1).py
204 lines (169 loc) · 7.18 KB
/
final-converter (1).py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import sys
import re
from bs4 import BeautifulSoup
import html
def process_inline_code(element):
"""
处理内联代码块,将code标签转换为markdown的内联代码格式
"""
result = []
for content in element.contents:
if content.name == 'code':
# 使用markdown的内联代码格式 `code`
result.append(f'`{content.get_text()}`')
else:
result.append(str(content.string) if content.string else '')
return ''.join(result)
def extract_code_block(element):
"""
从pre标签中提取代码块内容并转换为markdown格式
"""
# 查找代码语言标识
lang_div = element.find('div', class_='text-text-300')
language = lang_div.get_text().strip() if lang_div else ''
# 查找代码内容
code_div = element.find('div', class_='code-block__code')
if not code_div:
return ''
# 提取纯代码文本(移除所有HTML标签和样式)
code_content = ''
code_element = code_div.find('code')
if code_element:
# 获取所有文本节点
for item in code_element.strings:
code_content += item
# 确保代码内容两端没有多余的空行
code_content = code_content.strip()
# 按markdown代码块格式返回
return f"```{language}\n{code_content}\n```\n"
def convert_ai_message_to_md(content):
"""
将AI消息的HTML内容转换为Markdown格式,保持格式化
"""
soup = BeautifulSoup(content, 'html.parser')
md_lines = []
for element in soup.children:
if not element.name: # 跳过空文本节点
continue
if element.name == 'pre':
# 处理代码块
md_lines.append(extract_code_block(element))
elif element.name == 'p':
# 普通段落文本
text = element.get_text().strip()
md_lines.append(f"{text}\n")
elif element.name == 'ol':
# 有序列表,先加一个空行
md_lines.append("")
# 获取所有列表项
items = element.find_all('li', recursive=False)
for i, item in enumerate(items, 1):
# 使用process_inline_code处理可能包含的code标签
text = process_inline_code(item)
# 使用实际的序号
md_lines.append(f"{i}. {text}")
md_lines.append("") # 列表后加空行
elif element.name == 'ul':
# 无序列表,先加一个空行
md_lines.append("")
items = element.find_all('li', recursive=False)
for item in items:
text = process_inline_code(item)
md_lines.append(f"* {text}")
md_lines.append("") # 列表后加空行
return "\n".join(md_lines)
def convert_html_to_md(html_content):
"""
将HTML格式的聊天记录转换为Markdown格式
"""
# 对话标识模式 - 更新匹配模式使其更宽松
user_start = r'</div></div><div data-testid="user-message"'
user_end = r'<div class="absolute -bottom-0 -right-1.5"'
ai_start = r'<div class="grid-cols-1 grid gap-2\.5 \[&_>_\*\]:min-w-0">'
# 分割对话内容
conversations = []
current_pos = 0
while current_pos < len(html_content):
# 查找下一个用户或AI的发言开始位置
user_match = re.search(user_start, html_content[current_pos:])
ai_match = re.search(ai_start, html_content[current_pos:])
# 如果找不到更多的对话了,就结束
if not user_match and not ai_match:
break
if not ai_match or (user_match and user_match.start() < ai_match.start()):
# 处理用户发言
if user_match:
start_pos = current_pos + user_match.start()
content_start = start_pos + len(user_start)
# 找到用户发言的结束位置(下一个AI发言开始或用户发言结束标记)
next_ai = re.search(ai_start, html_content[content_start:])
end_mark = re.search(user_end, html_content[content_start:])
if end_mark and (not next_ai or end_mark.start() < next_ai.start()):
content_end = content_start + end_mark.start()
elif next_ai:
content_end = content_start + next_ai.start()
else:
content_end = len(html_content)
# 提取用户消息内容
content = html_content[content_start:content_end]
# 使用BeautifulSoup提取文本
soup = BeautifulSoup(content, 'html.parser')
user_text = ' '.join(p.get_text().strip() for p in soup.find_all('p'))
if user_text:
conversations.append(("user", user_text))
current_pos = content_end
else:
# 处理AI发言
start_pos = current_pos + ai_match.start()
content_start = start_pos + len(ai_start)
# 查找下一个用户发言作为当前AI发言的结束点
next_user = re.search(user_start, html_content[content_start:])
if next_user:
content_end = content_start + next_user.start()
else:
content_end = len(html_content)
# 提取内容
content = html_content[content_start:content_end]
conversations.append(("ai", content))
current_pos = content_end
# 转换为Markdown格式
md_content = []
for speaker, content in conversations:
if speaker == "user":
# 用户消息已经是纯文本了
md_content.append(f"\n## User\n")
md_content.append(content.strip())
else:
# AI消息需要保持格式
md_content.append(f"\n## AI\n")
md_content.append(convert_ai_message_to_md(content))
return "\n".join(md_content)
def main():
# 检查命令行参数
if len(sys.argv) != 2:
print("Usage: python script.py input.html")
print("Example: python script.py chat.html")
sys.exit(1)
# 获取输入文件路径
input_file = sys.argv[1]
# 检查文件是否以.html结尾
if not input_file.lower().endswith('.html'):
print("Error: Input file must be an HTML file (.html)")
sys.exit(1)
# 生成输出文件名(替换.html为.md)
output_file = input_file[:-5] + '.md' # 去掉.html后加上.md
try:
# 读取HTML文件
with open(input_file, 'r', encoding='utf-8') as f:
html_content = f.read()
# 转换内容
md_content = convert_html_to_md(html_content)
# 写入Markdown文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write(md_content)
print(f"Successfully converted {input_file} to {output_file}")
except Exception as e:
print(f"Error: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()