160 lines
4.9 KiB
Python
160 lines
4.9 KiB
Python
import re
|
||
import traceback
|
||
import json
|
||
|
||
def call_ai_api(system_prompt, user_prompt, model="glm-4.5", base_url="https://open.bigmodel.cn/api/paas/v4/", api_key="ce39bdd4fcf34ec0aec75072bc9ff988.hAp7HZTVUwy7vImn"):
|
||
"""
|
||
调用AI API生成Markdown
|
||
"""
|
||
try:
|
||
# 尝试导入OpenAI客户端
|
||
try:
|
||
from openai import OpenAI
|
||
except ImportError:
|
||
print("OpenAI库未安装,返回模拟数据")
|
||
return f"""# {user_prompt}
|
||
|
||
## 概述
|
||
{user_prompt}是一个重要的概念和领域。
|
||
|
||
## 核心要素
|
||
- 要素1
|
||
- 要素2
|
||
- 要素3
|
||
|
||
## 应用场景
|
||
- 场景1
|
||
- 场景2
|
||
- 场景3
|
||
|
||
## 发展趋势
|
||
- 趋势1
|
||
- 趋势2
|
||
- 趋势3"""
|
||
|
||
# 构建消息
|
||
messages = [
|
||
{"role": "system", "content": system_prompt},
|
||
{"role": "user", "content": user_prompt}
|
||
]
|
||
|
||
print(f"发送AI API请求到: {base_url}")
|
||
print(f"模型: {model}")
|
||
|
||
# 创建OpenAI客户端
|
||
client = OpenAI(api_key=api_key, base_url=base_url)
|
||
|
||
# 使用非流式调用,更简单可靠
|
||
try:
|
||
response = client.chat.completions.create(
|
||
model=model,
|
||
messages=messages,
|
||
temperature=0.7,
|
||
max_tokens=8000, # 增加token限制,避免内容截断
|
||
stream=False
|
||
)
|
||
except Exception as e:
|
||
print(f"API调用失败: {e}")
|
||
# 如果API调用失败,抛出异常而不是返回模拟数据
|
||
raise Exception(f"AI API调用失败: {e}")
|
||
|
||
# 获取响应内容
|
||
content = response.choices[0].message.content
|
||
print(f"AI原始响应: {content}")
|
||
|
||
# 处理可能的JSON格式响应
|
||
try:
|
||
# 尝试解析为JSON
|
||
json_data = json.loads(content)
|
||
if 'answer' in json_data:
|
||
content = json_data['answer']
|
||
print(f"从JSON中提取answer: {content[:100]}...")
|
||
elif 'content' in json_data:
|
||
content = json_data['content']
|
||
print(f"从JSON中提取content: {content[:100]}...")
|
||
elif 'markdown' in json_data:
|
||
content = json_data['markdown']
|
||
print(f"从JSON中提取markdown: {content[:100]}...")
|
||
except json.JSONDecodeError:
|
||
# 不是JSON格式,直接使用内容
|
||
print("响应不是JSON格式,直接使用内容")
|
||
|
||
# 清理内容
|
||
content = content.strip()
|
||
|
||
# 如果返回的内容包含代码块标记,提取其中的内容
|
||
markdown_match = re.search(r"```(?:markdown)?\n(.*?)```", content, re.DOTALL)
|
||
if markdown_match:
|
||
content = markdown_match.group(1).strip()
|
||
|
||
# 如果内容为空,返回模拟数据
|
||
if not content:
|
||
print("AI返回内容为空,使用模拟数据")
|
||
return f"""# {user_prompt}
|
||
|
||
## 概述
|
||
{user_prompt}是一个重要的概念和领域。
|
||
|
||
## 核心要素
|
||
- 要素1
|
||
- 要素2
|
||
- 要素3
|
||
|
||
## 应用场景
|
||
- 场景1
|
||
- 场景2
|
||
- 场景3
|
||
|
||
## 发展趋势
|
||
- 趋势1
|
||
- 趋势2
|
||
- 趋势3"""
|
||
|
||
return content
|
||
|
||
except Exception as e:
|
||
print(f"AI API调用异常: {e}")
|
||
traceback.print_exc()
|
||
return None
|
||
|
||
|
||
def generate_markdown_from_text(text):
|
||
"""
|
||
从文本生成Markdown的便捷函数
|
||
"""
|
||
system_prompt = """你是一位Markdown格式转换专家。你的任务是将用户提供的文章内容精确转换为结构化的Markdown格式。请遵循以下步骤:
|
||
|
||
提取主标题: 识别文章最顶层的主标题(通常为文章题目或书名),并使用Markdown的 # 级别表示。
|
||
|
||
识别层级标题: 从文章内容中提取所有层级的内容标题(从主标题后的第一个标题开始,Level 1 至 Level 4)。判断层级依据:
|
||
|
||
视觉与结构特征: 如独立成行/段、位置(行首)、格式(加粗、编号如 1., 1.1, (1), - 等)。
|
||
|
||
语义逻辑: 标题之间的包含和并列关系。
|
||
|
||
在Markdown中,使用相应标题级别:
|
||
|
||
Level 1 标题用 ##
|
||
|
||
Level 2 标题用 ###
|
||
|
||
Level 3 标题用 ####
|
||
|
||
Level 4 标题用 #####
|
||
|
||
精确保留原文标题文字,不得修改、概括或润色。
|
||
|
||
处理正文内容: 对于每个标题下的正文内容区块(从该标题后开始,直到下一个同级或更高级别标题前):
|
||
|
||
直接保留原文文本,但根据内容结构适当格式化为Markdown。
|
||
|
||
如果内容是列表(如项目符号或编号列表),使用Markdown列表语法(例如 - 用于无序列表,1. 用于有序列表)。
|
||
|
||
保持段落和换行不变。
|
||
|
||
输出格式: 输出必须是纯Markdown格式的文本,不得包含任何额外说明、JSON或非Markdown元素。确保输出与示例风格一致。"""
|
||
|
||
user_prompt = f"请将以下内容转换为结构化的Markdown格式:\n\n{text}"
|
||
|
||
return call_ai_api(system_prompt, user_prompt)
|