File size: 9,240 Bytes
84d2f90 e71a2c6 84d2f90 e71a2c6 84d2f90 68dceb7 84d2f90 68dceb7 84d2f90 68dceb7 84d2f90 e71a2c6 84d2f90 b6900a2 84d2f90 e71a2c6 84d2f90 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 68dceb7 e71a2c6 84d2f90 e71a2c6 84d2f90 b6900a2 84d2f90 e71a2c6 84d2f90 e71a2c6 84d2f90 e71a2c6 84d2f90 |
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 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
from flask import Flask, request, Response, stream_with_context
import requests
import os
import json
import urllib3
# 禁用 SSL 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
app = Flask(__name__)
# 从环境变量获取配置
OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY')
OPENAI_API_URL = os.environ.get('OPENAI_API_URL', 'https://api.openai.com/v1/chat/completions')
# PPT 大纲生成接口
@app.route('/tools/aippt_outline', methods=['POST'])
def aippt_outline():
data = request.json
content = data.get('content')
language = data.get('language', 'zh')
model = data.get('model', 'gpt-4o')
# 构建发送给 OpenAI 的提示
messages = [
{
"role": "system",
"content": f"""您是一位专业的PPT大纲生成器。请为主题'{content}'创建一个详细的演示文稿大纲,使用{language}语言。
您的大纲必须严格遵循以下格式,这是非常重要的:
# [主题标题]
## [一级章节标题]
### [二级标题]
- [要点]
- [要点]
...
具体要求:
1. 大纲必须以"# [主题标题]"开始
2. 包含4-6个一级章节,每个章节以"##"开头
3. 每个一级章节下包含2-3个二级标题,每个二级标题以"###"开头
4. 每个二级标题下包含2-4个简短要点,每个要点以"-"开头
5. 要点应简洁明了,每个要点不超过15个字
6. 章节标题和二级标题应该是名词短语,不要使用问句或长句
请确保大纲层次分明,内容全面且有深度。章节安排应当符合逻辑顺序,便于读者理解。"""
}
]
def generate():
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {OPENAI_API_KEY}'
}
payload = {
'model': model,
'messages': messages,
'stream': True
}
response = requests.post(
OPENAI_API_URL,
headers=headers,
json=payload,
stream=True,
verify=False # 禁用 SSL 验证
)
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: ') and line != 'data: [DONE]':
try:
data = json.loads(line[6:])
if data['choices'][0]['delta'].get('content'):
content = data['choices'][0]['delta']['content']
yield content
except Exception as e:
print(f"Error parsing OpenAI response: {e}")
return Response(stream_with_context(generate()), mimetype='text/event-stream')
# PPT 内容生成接口
@app.route('/tools/aippt', methods=['POST'])
def aippt():
data = request.json
content = data.get('content')
language = data.get('language', 'zh')
model = data.get('model', 'gpt-4.1-mini')
# 构建发送给 OpenAI 的提示,包含 PPTist 所需数据结构的详细说明
messages = [
{
"role": "system",
"content": f"""您是一位专业的PPT内容生成器。根据提供的大纲,您需要生成一系列JSON对象,每个对象代表一张幻灯片。请严格按照以下规则和格式进行生成:
1. 您需要生成这些类型的幻灯片:封面页(cover)、目录页(contents)、过渡页(transition)、内容页(content)和结束页(end)
2. 必须严格遵循以下JSON格式,任何格式错误都会导致幻灯片无法显示:
封面页:
{{"type":"cover","data":{{"title":"主标题","text":"副标题或简短描述"}}}}
目录页:
{{"type":"contents","data":{{"items":["一级章节1","一级章节2","一级章节3","一级章节4","一级章节5"]}}}}
过渡页:
{{"type":"transition","data":{{"title":"章节标题","text":"章节简介"}}}}
内容页:
{{"type":"content","data":{{"title":"二级标题","items":[{{"title":"要点1标题","text":"要点1描述"}},{{"title":"要点2标题","text":"要点2描述"}},{{"title":"要点3标题","text":"要点3描述"}},{{"title":"要点4标题","text":"要点4描述"}}]}}}}
结束页:
{{"type":"end"}}
3. 转换规则:
- 大纲中的主标题("#"开头)转换为封面页
- 所有一级章节("##"开头)组成目录页
- 每个一级章节前生成一个过渡页
- 每个二级标题("###"开头)生成一个内容页
- 内容页中的items数组由该二级标题下的要点("-"开头)组成
- 最后添加一个结束页
4. 输出要求:
- 每个JSON对象必须单独成行
- 不要添加任何额外的注释或解释
- 确保每个JSON对象格式正确且完整
- 每个内容页必须包含该节点下所有的要点,通常为2-4个
示例输出:
{{"type":"cover","data":{{"title":"5G技术如何改变我们的生活","text":"探索5G技术对现代生活的全方位影响"}}}}
{{"type":"contents","data":{{"items":["5G技术概述","5G对通信领域的变革","5G与智能家居的融合","5G推动智能交通发展","5G在医疗领域的应用","5G助力工业互联网升级"]}}}}
{{"type":"transition","data":{{"title":"5G技术概述","text":"本章将介绍5G技术的定义、关键特性及发展历程。"}}}}"""
},
{
"role": "user",
"content": f"根据这个大纲生成PPT内容:\n{content}"
}
]
def generate():
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {OPENAI_API_KEY}'
}
payload = {
'model': model,
'messages': messages,
'stream': True
}
response = requests.post(
OPENAI_API_URL,
headers=headers,
json=payload,
stream=True,
verify=False # 禁用 SSL 验证
)
buffer = ""
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: ') and line != 'data: [DONE]':
try:
data = json.loads(line[6:])
if data['choices'][0]['delta'].get('content'):
buffer += data['choices'][0]['delta']['content']
# 尝试从缓冲区中提取完整的 JSON 对象
while True:
# 寻找可能的 JSON 对象开始和结束
json_start = buffer.find('{')
if json_start == -1:
break
# 寻找匹配的结束括号(处理嵌套JSON)
bracket_count = 0
json_end = -1
for i in range(json_start, len(buffer)):
if buffer[i] == '{':
bracket_count += 1
elif buffer[i] == '}':
bracket_count -= 1
if bracket_count == 0:
json_end = i
break
if json_end == -1:
# 没有找到匹配的结束括号,等待更多数据
break
json_str = buffer[json_start:json_end+1]
try:
# 验证是否为有效的 JSON
slide_data = json.loads(json_str)
# 验证是否包含必要的字段
if isinstance(slide_data, dict) and 'type' in slide_data:
# 发送到客户端
yield json.dumps(slide_data) + '\n'
# 从缓冲区中移除已处理的部分
buffer = buffer[json_end+1:]
else:
# 格式不符合要求,从缓冲区移除
buffer = buffer[json_end+1:]
except Exception as e:
# 解析错误,可能不是完整的JSON,等待更多数据
print(f"Error parsing JSON: {e}")
break
except Exception as e:
print(f"Error parsing OpenAI response: {e}")
return Response(stream_with_context(generate()), mimetype='text/event-stream')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=7860) |