python(25) : 含有大模型生成的公式的文本渲染成图片并生成word文档
公式样例
渲染前
\[
\sqrt{1904.615384} \approx 43.64
\]
渲染后
安装依赖
pip install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ requests
pip install sympy -i https://mirrors.aliyun.com/pypi/simple/ requests
pip install python-docx -i https://mirrors.aliyun.com/pypi/simple/ requests
代码
# -*- coding: utf-8 -*-
import os
import random
import string
import time
import matplotlib.pyplot as plt
from docx import Document
start_marker = "\["
end_marker = "\]"
output_tmp_folder = f'{os.getcwd()}math_2_img{os.sep}'
if not os.path.exists(output_tmp_folder):
os.mkdir(output_tmp_folder)
def is_have_math(text):
s_count = text.count('\[')
e_count = text.count('\]')
if s_count >= e_count or e_count >= s_count:
return True
return False
def find_and_replace(text, start_marker="\[", end_marker="\]"):
"""
查找并替换由_start和_end包围的文本。
:param text: 需要处理的原始文本
:param start_marker: 标记开始的字符串,默认为"_start"
:param end_marker: 标记结束的字符串,默认为"_end"
:return: 替换后的文本
"""
result_parts = [] # 存储结果片段
current_position = 0 # 当前处理到的位置
while True:
start_pos = text.find(start_marker, current_position)
if start_pos == -1:
# 没有找到更多的_start标记,将剩余部分添加到结果中并退出循环
result_parts.append(text[current_position:])
break
# 添加_start之前的部分到结果中
result_parts.append(text[current_position:start_pos])
# 查找对应的_end标记
end_pos = text.find(end_marker, start_pos + len(start_marker))
if end_pos == -1:
# 如果没有找到_end标记,则将剩余部分全部添加到结果中并退出
result_parts.append(text[start_pos:])
break
# 提取并处理_start和_end之间的文本
content = text[start_pos + len(start_marker):end_pos]
processed_content = '111' # 定义你自己的处理逻辑
print(content)
# 将处理后的内容添加到结果中
result_parts.append(processed_content)
# 更新当前处理位置为_end之后
current_position = end_pos + len(end_marker)
# 返回拼接后的最终结果
return ''.join(result_parts)
def replace_first_closing_brace(text, split_marker=r'\(\boxed{', start_tag='[', end_tag=']'):
"""
根据split_marker切割文本,并将每个元素的第一个"}"替换为replacement字符。
:param text: 需要处理的原始文本
:param split_marker: 用于切割文本的标记,默认为'\(\boxed{'
:param replacement: 用来替换第一个'}'的字符,默认为'_'
:return: 处理后的文本
"""
# 如果没有split_marker,则直接返回原text
if split_marker not in text:
return text
# 根据split_marker切割文本
parts = text.split(split_marker)
# 第一个元素是split_marker之前的内容,不需要处理
processed_parts = [parts[0]]
for part in parts[1:]:
# 找到第一个"}"的位置并替换为replacement
closing_brace_index = part.find('}')
if closing_brace_index != -1:
new_part = part[:closing_brace_index] + end_tag + part[closing_brace_index + 3:]
else:
new_part = part # 如果没有找到"}",则保持原样
processed_parts.append(new_part)
# 将处理后的部分重新组合成新的字符串
result = split_marker.join(processed_parts)
if split_marker in result:
result = result.replace(split_marker, start_tag)
return result
def math_generate_docx(text, path):
# 创建新的Document对象
document = Document()
# 添加标题
# document.add_heading('Document Title', 0)
current_position = 0 # 当前处理到的位置
imgs = []
while True:
start_pos = text.find(start_marker, current_position)
if start_pos == -1:
# 没有找到更多的_start标记,将剩余部分添加到结果中并退出循环
other_text = replace_first_closing_brace(text[current_position:])
document.add_paragraph(other_text)
break
# 添加_start之前的部分到结果中
document.add_paragraph(text[current_position:start_pos])
# 查找对应的_end标记
end_pos = text.find(end_marker, start_pos + len(start_marker))
if end_pos == -1:
# 如果没有找到_end标记,则将剩余部分全部添加到结果中并退出
document.add_paragraph(text[start_pos:])
break
# 提取并处理_start和_end之间的文本
content = text[start_pos + len(start_marker):end_pos]
math_img_path = math_2_img(content)
imgs.append(math_img_path)
document.add_picture(math_img_path)
# 更新当前处理位置为_end之后
current_position = end_pos + len(end_marker)
# 保存文档到本地
document.save(path)
for img in imgs:
if os.path.exists(img):
os.remove(img)
print(f"文档已创建并保存为 {path}")
def math_2_img(text):
text = text.replace('\n', '')
formula = r"$" + text + "$"
# 创建一个只包含公式的图像
plt.figure(figsize=(6, 1)) # 调整大小以适应公式
plt.text(0.5, 0.5, formula, fontsize=20, ha='center', va='center')
plt.axis('off') # 关闭坐标轴
# 保存图像到本地
output_tmp_path = f'{output_tmp_folder}{generate_time_random_code(5)}.png'
plt.savefig(output_tmp_path, bbox_inches='tight', pad_inches=0.1, dpi=300)
plt.close()
return output_tmp_path
def generate_random_code(length):
characters = string.ascii_lowercase + string.digits # 使用ascii_lowercase获取小写字母,digits获取数字
code = ''.join(random.choice(characters) for _ in range(length)) # 从字符集中随机选择生成指定长度的随机编码
return code
def get_time_int():
current_time_float = time.time() # 获取当前时间的浮点数时间戳
current_time_int = int(current_time_float)
return str(current_time_int)
def generate_time_random_code(length):
return get_time_int() + generate_random_code(length)
if __name__ == '__main__':
s = r"""
为了解决这个问题,我们将按照以下步骤进行:
1. 计算58和64的乘积。
2. 将结果除以3.12。
3. 将结果乘以1.6。
4. 对结果取平方根。
让我们从第一步开始:
1. 计算58和64的乘积:
\[
58 \times 64 = 3712
\]
2. 将3712除以3.12:
\[
\frac{3712}{3.12} \approx 1190.384615
\]
3. 将1190.384615乘以1.6:
\[
1190.384615 \times 1.6 \approx 1904.615384
\]
4. 对1904.615384取平方根:
\[
\sqrt{1904.615384} \approx 43.64
\]
因此,最后的得数是 \(\boxed{43.64}\)。
"""
math_generate_docx(s, 'example.docx')