基于python实现全自动调用通义千文自动生成文章
AI智能写作工具:基于Z-BlogPHP与通义千问的大学作文自动生成系统
在人工智能技术快速发展的今天,如何将大模型能力融入教育与内容创作场景,成为开发者关注的重点。本文介绍一款由 Python 编写的大学作文智能生成工具,它结合了阿里云 DashScope 的通义千问(Qwen3-Max)API 与本地关键词管理机制,能够高效生成具有哲学深度、文学质感和思辨性的中文作文,并自动保存为符合学术规范的 Word 文档。
核心功能亮点
智能关键词生成:调用 Qwen3-Max 模型生成新颖、有深度的作文主题(如“技术时代的诗意栖居”、“记忆的伦理与遗忘的政治”),避免俗套。
本地关键词复用:优先从本地
1.txt文件中读取已有关键词,避免重复生成,提升效率。去重与相似度过滤:通过字符交集与包含关系判断,防止生成语义相近或重复的主题。
800+字高质量文章:每篇文章以第一人称撰写,结构完整,包含意象引入、辩证分析、案例支撑与哲思总结。
纯文本输出,无Markdown:严格禁用任何 Markdown 语法,确保内容可直接用于 Word 或印刷场景。
自动续写机制:若初稿字数不足600字,系统会自动请求模型补充内容,保障文章完整性。
一键导出 Word:生成文件自动保存至
wenben/目录,标题居中、正文宋体小四、1.5倍行距、首行缩进2字符,符合中文排版标准。图形化界面(Tkinter):用户只需输入数量(1–100),点击按钮即可后台生成多篇文章,进度实时反馈。
技术架构
该工具采用模块化设计,主要依赖以下技术栈:
语言:Python 3.x
AI 接口:OpenAI 兼容模式调用阿里云 DashScope 的
qwen3-max模型文档处理:
python-docx库实现 Word 格式控制GUI 框架:Tkinter 构建简易桌面应用
并发处理:使用
threading避免界面卡死
安全与使用建议
项目中的 API_KEY 仅为示例,请务必替换为你在 阿里云 DashScope 控制台 申请的真实密钥。建议:
不要将 API Key 提交至公开代码仓库
限制 API 调用频率,避免超额计费
定期清理
1.txt和wenben/目录,管理生成内容
适用场景
高校写作课程的教学素材生成
自媒体作者获取灵感与初稿
AI 写作能力测试与对比研究
个人思辨训练与哲学写作练习
结语
这款工具不仅展示了大语言模型在中文写作领域的强大潜力,也体现了“人机协同”创作的新范式——AI 负责内容生成与扩展,人类负责选题把控与价值判断。未来可进一步集成 Z-BlogPHP 后台,实现一键发布博客文章,打造完整的智能内容生产闭环。
项目源码结构清晰、注释完整,适合 Python 开发者学习 AI 集成、文档自动化与桌面应用开发。
代码展示
import os
import re
import time
import random
import threading
from tkinter import *
from tkinter import ttk, messagebox
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.style import WD_STYLE_TYPE
from docx.oxml.ns import qn
from docx.oxml import parse_xml
from openai import OpenAI
# 确保wenben文件夹存在
os.makedirs("wenben", exist_ok=True)
# 阿里云DashScope API配置(请替换为你的实际API Key)
API_KEY = "" # 在阿里云控制台获取
def load_existing_keywords():
"""加载已生成的关键词"""
existing_keywords = set()
if os.path.exists("1.txt"):
with open("1.txt", "r", encoding="utf-8") as f:
for line in f:
keyword = line.strip()
if keyword and "主题_" not in keyword and "深度主题_" not in keyword:
existing_keywords.add(keyword)
return existing_keywords
def save_keywords(keywords):
"""保存新生成的关键词到1.txt"""
valid_keywords = [kw for kw in keywords if "主题_" not in kw and "深度主题_" not in kw and "备用主题_" not in kw]
if valid_keywords:
with open("1.txt", "a", encoding="utf-8") as f:
for keyword in valid_keywords:
f.write(keyword + "\n")
def clean_filename(text):
"""清理文件名中的非法字符(保留《》)"""
# 仅移除其他非法字符
invalid_chars = r'\\/*?:"<>|'
for char in invalid_chars:
text = text.replace(char, "")
return text
def get_local_keywords(count, existing_keywords):
"""从本地关键词中获取指定数量的关键词(优先使用本地)"""
local_keywords = list(existing_keywords)
# 如果有足够的本地关键词,直接返回
if len(local_keywords) >= count:
return random.sample(local_keywords, count)
else:
# 如果本地关键词不足,返回所有本地关键词
return local_keywords
def generate_keywords(count, exclude_keywords):
"""调用AI生成指定数量的关键词(排除已存在的关键词)"""
client = OpenAI(
api_key=API_KEY,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 准备排除关键词列表(最多显示30个,避免prompt太长)
exclude_list = list(exclude_keywords)[:30]
exclude_text = ",".join(exclude_list) if exclude_list else "无"
# 改进提示词:告诉AI不要生成已有的关键词
prompt = f"""
我已经有这些作文主题关键词了,请不要重复生成它们:
{exclude_text}
现在,请帮我生成{count}个全新的、有思想深度和文学性的大学作文主题关键词,要求:
1. 避免俗套的高考作文主题(如"成长"、"梦想"等)
2. 体现当代社会的复杂性、人性的多维度和现代性困境
3. 包含对立统一、辩证思考的元素
4. 有诗意和哲学意味,但不过于晦涩
5. 关键词长度为2-10个字
6. 每个关键词都应该是一个完整、独立、有张力的主题
7. 请不要生成上面已有的关键词,也不要生成类似的关键词
8.生成的关键词不要字数都是一样的!
请只输出关键词,每个关键词单独一行,不要编号,不要额外说明。
"""
try:
response = client.chat.completions.create(
model="qwen3-max",
messages=[
{"role": "system",
"content": "你是一位哲学与文学教授,擅长设计有思辨性的深度主题。你会仔细检查避免重复已有的关键词。"},
{"role": "user", "content": prompt}
],
max_tokens=400,
temperature=0.8
)
# 提取关键词(按行分割)
keywords_text = response.choices[0].message.content.strip()
# 分割关键词并清理
raw_keywords = []
for line in keywords_text.split("\n"):
line = line.strip()
# 移除编号(如"1. "、"2. "等)
line = re.sub(r'^\d+[\.、]?\s*', '', line)
# 移除破折号和星号等
line = re.sub(r'^[-*•]\s*', '', line)
if line and len(line) >= 2 and len(line) <= 15: # 合理的长度限制
raw_keywords.append(line)
# 去除重复并确保不在排除列表中
keywords = []
seen = set()
for kw in raw_keywords:
# 检查是否与已有关键词相似(避免变体)
is_similar = False
for existing in exclude_keywords:
if kw in existing or existing in kw:
is_similar = True
break
# 简单相似度检查
if len(kw) >= 3 and len(existing) >= 3:
common_chars = set(kw) & set(existing)
if len(common_chars) / max(len(kw), len(existing)) > 0.7:
is_similar = True
break
if (kw not in seen and
kw not in exclude_keywords and
"主题_" not in kw and
not is_similar):
keywords.append(kw)
seen.add(kw)
# 如果数量不足,生成补充
if len(keywords) < count:
# 准备高质量备份主题列表
backup_themes = [
"技术时代的诗意栖居",
"记忆的伦理与遗忘的政治",
"虚拟现实中的真实感",
"速度社会中的沉思时刻",
"数字原住民的乡愁",
"后人类时代的身体想象",
"算法推荐下的认知窄化",
"消费社会的符号化生存",
"现代性焦虑与身份认同",
"数字鸿沟与知识平权"
]
needed = count - len(keywords)
for i in range(needed):
if i < len(backup_themes):
theme = backup_themes[i]
else:
theme = f"思辨主题_{i + 1}"
# 检查备份主题是否与已有主题相似
is_similar = False
for existing in exclude_keywords:
if theme in existing or existing in theme:
is_similar = True
break
if (theme not in seen and
theme not in exclude_keywords and
"主题_" not in theme and
not is_similar):
keywords.append(theme)
seen.add(theme)
return keywords[:count]
except Exception as e:
raise Exception(f"关键词生成失败: {str(e)}")
def clean_article_content(content):
"""清理文章内容,移除Markdown格式的标题"""
# 移除各种Markdown格式的标题
lines = content.split('\n')
cleaned_lines = []
for line in lines:
# 检查是否是Markdown标题(以#开头)
if line.strip().startswith('#'):
# 找到第一个非#字符的位置
cleaned = re.sub(r'^#+\s*', '', line)
# 如果清理后不是空行,保留但作为普通文本
if cleaned.strip():
cleaned_lines.append(cleaned.strip())
else:
cleaned_lines.append(line)
# 重新组合成文章
cleaned_content = '\n'.join(cleaned_lines)
# 移除可能存在的其他Markdown格式
cleaned_content = re.sub(r'[*_]{2,3}(.+?)[*_]{2,3}', r'\1', cleaned_content) # 移除粗体和斜体标记
cleaned_content = re.sub(r'\[(.+?)\]\(.+?\)', r'\1', cleaned_content) # 移除链接
return cleaned_content
def generate_essay(keyword):
"""调用通义千问API生成习作文章(确保至少800字,不强行截断,不使用Markdown格式)"""
client = OpenAI(
api_key=API_KEY,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 优化的提示词:强调文采、思辨性,要求至少800字但不设上限,明确要求不使用任何Markdown格式
prompt = f"""
以大学中文系学生的身份,创作一篇作文。
主题:{keyword}
重要要求:
1. 文章字数至少800字,可以更多,但不要刻意凑字数
2. 确保文章结构完整,有自然的开头、发展和结尾
3. 内容要充实,论述要充分,不要草草结束
4. 重要:请使用纯文本格式,不要使用任何Markdown格式,包括:
- 不要使用#、##、###等标题标记
- 不要使用**粗体**、*斜体*等格式标记
- 不要使用任何列表标记(如-、*、1.等)
- 不要使用任何链接格式
- 文章应该像在Word文档中一样,只有自然的分段
创作要求:
一、风格与语言:
1. 语言富有文采但不浮夸,有文学质感
2. 适当使用比喻、隐喻、象征等修辞手法
3. 句式多变,长短结合,有节奏感
4. 避免AI腔和模板化表达
二、结构与内容:
1. 开篇:以意象或场景引入,自然切入主题
2. 主体:包含2-3个有张力的段落,每段聚焦一个子话题
3. 论证:体现辩证思维,呈现对立统一的观点
4. 例证:使用文学、历史、哲学或当代社会的具体例子
5. 反思:包含自我质疑和深度追问
三、思辨性要求:
1. 揭示问题的复杂性,避免非黑即白的判断
2. 探讨表面现象背后的深层逻辑
3. 呈现价值冲突和道德困境
4. 最终要有深度的总结或开放式思考
四、格式要求:
1. 以第一人称"我"展开,体现真实思考过程
2. 文章要自然流畅地结束,不要突兀
3. 确保论述充分,不要因为字数限制而仓促结尾
4. 使用纯文本段落,段落之间用空行分隔
5. 绝对不要使用任何形式的Markdown语法
现在,请开始创作一篇完整、充实、有深度的纯文本文章:
"""
try:
response = client.chat.completions.create(
model="qwen3-max",
messages=[
{"role": "system",
"content": "你是一位文笔优美、思想深刻的中文系学生,擅长创作有文学性和哲学思辨的长篇文章。你会确保文章至少800字,内容完整充实,并且使用纯文本格式,不使用任何Markdown语法。"},
{"role": "user", "content": prompt}
],
max_tokens=3000, # 增加token限制,允许更长的文章
temperature=0.7
)
article = response.choices[0].message.content.strip()
# 清理文章内容,移除可能的Markdown格式
article = clean_article_content(article)
# 检查字数(中文字符数)
chinese_chars = len([c for c in article if '\u4e00' <= c <= '\u9fff'])
# 如果字数明显不足(少于600字),考虑补充
if chinese_chars < 600:
# 尝试让AI继续写
continuation_prompt = f"""
你刚才写的文章主题是"{keyword}",但字数有些不足(目前约{chinese_chars}字)。
请继续写下去,补充一些内容:
1. 可以深入分析一个未充分展开的观点
2. 可以添加一个具体的例子或案例
3. 可以从另一个角度思考这个问题
4. 可以增加一些个人反思或感悟
5. 继续使用纯文本格式,不要使用任何Markdown语法
请继续写200-300字,让文章更加充实完整。
继续写:
"""
try:
continuation_response = client.chat.completions.create(
model="qwen3-max",
messages=[
{"role": "system", "content": "你正在补充和完善一篇文章,使其更加充实完整。请使用纯文本格式。"},
{"role": "user", "content": continuation_prompt}
],
max_tokens=500,
temperature=0.6
)
continuation = continuation_response.choices[0].message.content.strip()
# 清理续写内容的Markdown格式
continuation = clean_article_content(continuation)
article += "\n\n" + continuation
except Exception:
# 如果续写失败,至少记录日志
with open("字数不足记录.txt", "a", encoding="utf-8") as f:
f.write(f"主题: {keyword}, 字数: {chinese_chars}\n")
return article
except Exception as e:
raise Exception(f"文章生成失败: {str(e)}")
def save_to_word(title, content, filename):
"""将文章保存为符合要求的Word文档"""
doc = Document()
# 添加标题(宋体四号,加粗,黑色)
title_para = doc.add_heading(title, level=1)
title_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 设置标题字体(黑色)
for run in title_para.runs:
run.font.name = '宋体'
run.font.size = Pt(14)
run.bold = True
run.font.color.rgb = RGBColor(0, 0, 0)
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
# 添加正文(宋体小四,1.5倍行距,首行缩进2字符)
for para in content.split('\n\n'):
if para.strip():
p = doc.add_paragraph(para)
p.paragraph_format.first_line_indent = Inches(0.5)
p.paragraph_format.line_spacing = 1.5
p.paragraph_format.space_after = Pt(6)
# 设置正文字体
for run in p.runs:
run.font.name = '宋体'
run.font.size = Pt(12)
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
# 保存文件
doc.save(os.path.join("wenben", filename))
def generate_essays_thread(count):
"""在后台线程中生成指定数量的文章"""
try:
# 加载已生成关键词
existing_keywords = load_existing_keywords()
status_label.config(text="正在获取关键词...", fg="blue")
root.update()
# 优先使用本地关键词
local_keywords = get_local_keywords(count, existing_keywords)
local_count = len(local_keywords)
if local_count > 0:
status_label.config(text=f"从本地获取了{local_count}个关键词", fg="blue")
root.update()
time.sleep(1)
# 计算需要AI生成的关键词数量
need_ai_count = count - local_count
new_keywords = []
if local_count > 0:
# 使用本地关键词
new_keywords.extend(local_keywords)
status_label.config(text=f"已使用{local_count}个本地关键词,还需生成{need_ai_count}个新关键词", fg="blue")
root.update()
# 如果需要AI生成新关键词
if need_ai_count > 0:
try:
status_label.config(
text=f"正在生成{need_ai_count}个新关键词(会排除已有的{len(existing_keywords)}个关键词)...",
fg="blue")
root.update()
# 生成新关键词,排除已有关键词
ai_keywords = generate_keywords(need_ai_count, existing_keywords)
# 添加到新关键词列表
for kw in ai_keywords:
if kw not in new_keywords:
new_keywords.append(kw)
existing_keywords.add(kw) # 更新已有关键词集合
# 保存新生成的关键词到本地文件
save_keywords(ai_keywords)
status_label.config(text=f"成功生成{len(ai_keywords)}个新关键词(已排除重复)", fg="green")
root.update()
except Exception as e:
status_label.config(text=f"AI生成关键词失败: {str(e)}", fg="red")
# 如果AI生成失败,使用高质量备份主题
backup_themes = [
"技术时代的诗意栖居",
"记忆的伦理与遗忘的政治",
"虚拟现实中的真实感",
"速度社会中的沉思时刻",
"数字原住民的乡愁"
]
added = 0
for i in range(min(need_ai_count, len(backup_themes))):
theme = backup_themes[i]
if theme not in new_keywords and theme not in existing_keywords:
new_keywords.append(theme)
existing_keywords.add(theme)
added += 1
# 如果还是不够,补充
while len(new_keywords) < count:
theme = f"新主题_{len(new_keywords) + 1}"
new_keywords.append(theme)
status_label.config(text=f"使用{added}个备份主题,补充了{need_ai_count - added}个新主题", fg="orange")
root.update()
# 生成文章
status_label.config(text=f"正在生成{len(new_keywords)}篇习作,请稍候...", fg="blue")
progress_label.config(text=f"进度: 0/{len(new_keywords)}", fg="blue")
root.update()
# 生成每篇文章
for i, keyword in enumerate(new_keywords, 1):
try:
# 生成文章标题(保留《》)
title = f"《{keyword}》"
# 生成文章
status_label.config(text=f"正在生成第{i}篇: {keyword}", fg="blue")
root.update()
article = generate_essay(keyword)
# 检查字数并记录
chinese_chars = len([c for c in article if '\u4e00' <= c <= '\u9fff'])
# 生成文件名
clean_keyword = clean_filename(keyword)
filename = f"刘凯写作《{clean_keyword}》.docx"
# 保存Word文档
save_to_word(title, article, filename)
# 更新进度
progress_label.config(text=f"进度: {i}/{len(new_keywords)} (约{chinese_chars}字)", fg="blue")
status_label.config(text=f"已生成第{i}篇: {keyword} (约{chinese_chars}字)", fg="green")
root.update()
# 添加小延迟避免API请求过快
time.sleep(2.5)
except Exception as e:
error_msg = f"第{i}篇生成失败: {str(e)}"
status_label.config(text=error_msg, fg="red")
# 记录错误但继续执行
with open("生成错误日志.txt", "a", encoding="utf-8") as f:
f.write(f"关键词: {keyword}, 错误: {str(e)}\n")
continue
# 统计生成情况
local_keywords_count = local_count
ai_keywords_count = len(new_keywords) - local_count
status_label.config(text=f"{len(new_keywords)}篇习作已全部生成并保存!", fg="green")
messagebox.showinfo("成功",
f"{len(new_keywords)}篇习作已全部生成并保存到wenben文件夹!\n\n"
f"统计信息:\n"
f"- 使用本地关键词: {local_keywords_count}篇\n"
f"- 新生成关键词: {ai_keywords_count}篇\n"
f"- 关键词总数: {len(existing_keywords)}个(已保存到1.txt)")
except Exception as e:
status_label.config(text=f"程序错误: {str(e)}", fg="red")
messagebox.showerror("程序错误", str(e))
def on_generate():
"""处理生成按钮点击事件(多线程)"""
try:
count = int(entry_count.get().strip())
if count < 1 or count > 100:
messagebox.showerror("输入错误", "请输入1-100之间的整数")
return
# 清空旧的状态
progress_label.config(text="进度: 0/0", fg="blue")
status_label.config(text="开始生成...", fg="blue")
# 启动后台线程
threading.Thread(target=generate_essays_thread, args=(count,), daemon=True).start()
except ValueError:
messagebox.showerror("输入错误", "请输入有效的整数")
# 创建主窗口
root = Tk()
root.title("伟大无需多言")
root.geometry("700x550")
root.configure(bg="#f0f0f0")
# 创建框架
main_frame = Frame(root, bg="#f0f0f0")
main_frame.pack(padx=20, pady=20, fill="both", expand=True)
# 标题
title_label = Label(main_frame, text="伟大无需多言-王铁锹", font=("微软雅黑", 16, "bold"), bg="#f0f0f0")
title_label.pack(pady=10)
# 说明文字
info_label = Label(main_frame,
text="优先使用本地的关键词,不足时AI生成新关键词时会排除已有主题\n文章确保至少800字,使用纯文本格式,无Markdown标记",
font=("宋体", 10), bg="#f0f0f0", fg="darkgray", justify="center", wraplength=600)
info_label.pack(pady=5)
# 输入框:生成数量
frame_input = Frame(main_frame, bg="#f0f0f0")
frame_input.pack(pady=10)
Label(frame_input, text="请输入要生成的文章数量 (1-20):", font=("宋体", 12), bg="#f0f0f0").pack(side=LEFT, padx=(0, 10))
entry_count = Entry(frame_input, width=10, font=("宋体", 12))
entry_count.pack(side=LEFT)
entry_count.insert(0, "10")
# 生成按钮
generate_btn = Button(main_frame, text="生成习作", command=on_generate,
bg="#4CAF50", fg="white", font=("宋体", 12, "bold"),
width=18, height=2, relief="raised")
generate_btn.pack(pady=20)
# 进度标签
progress_label = Label(main_frame, text="进度: 0/0", font=("宋体", 11), bg="#f0f0f0", fg="blue")
progress_label.pack(pady=5)
# 状态标签
status_label = Label(main_frame, text="输入数量后点击'生成习作'开始",
font=("宋体", 10), bg="#f0f0f0", fg="gray", wraplength=600)
status_label.pack(pady=5)
# 特性说明
features_frame = Frame(main_frame, bg="#f0f0f0")
features_frame.pack(pady=15, fill="x")
features = [
]
for i, feature in enumerate(features):
label = Label(features_frame, text=feature, font=("宋体", 9),
bg="#f0f0f0", fg="#555555", justify="left", anchor="w")
label.grid(row=i // 2, column=i % 2, sticky="w", padx=10, pady=2)
# 设置列宽
features_frame.grid_columnconfigure(0, weight=1)
features_frame.grid_columnconfigure(1, weight=1)
# 本地关键词统计
def update_local_keywords_count():
"""更新本地关键词数量显示"""
try:
existing_keywords = load_existing_keywords()
count_label.config(text=f"本地已有关键词: {len(existing_keywords)}个")
except:
count_label.config(text=f"本地已有关键词: 0个")
# 每5秒更新一次
root.after(5000, update_local_keywords_count)
count_label = Label(main_frame, text="", font=("宋体", 9, "bold"), bg="#f0f0f0", fg="#333333")
count_label.pack(pady=10)
update_local_keywords_count() # 初始显示
# 运行主循环
root.mainloop() 



