You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
5.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import asyncio
import socket
import time
import uvicorn
from fastapi import FastAPI, Body
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse, PlainTextResponse
from openai import OpenAI
from AiService.MarkdownToJsonConverter import MarkdownToJsonConverter
# 阿里云中用来调用 deepseek v3 的密钥
MODEL_API_KEY = "sk-01d13a39e09844038322108ecdbd1bbc"
MODEL_NAME = "qwen-plus"
# 初始化 OpenAI 客户端
client = OpenAI(
api_key=MODEL_API_KEY,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
def convertMarkdownToJson(markdown_content: str, language: str):
# 创建转换器实例
converter = MarkdownToJsonConverter(client, language)
# 转换 Markdown 为 JSON
for item in converter.convert_markdown_to_json(markdown_content, language): # 使用普通 for 循环
yield f"{item}\n" # 每行数据后添加换行符
# 添加结束标记
yield '{"type": "end" }\n' # 结束标记后也添加换行符
# 获取本机所有 IPv4 地址
def get_local_ips():
ips = []
hostname = socket.gethostname()
try:
# 获取所有 IP 地址
addrs = socket.getaddrinfo(hostname, None, family=socket.AF_INET) # 只获取 IPv4 地址
for addr in addrs:
ip = addr[4][0]
if ip not in ips:
ips.append(ip)
except Exception as e:
print(f"获取 IP 地址失败: {e}")
return ips
# 流式生成数据的函数
async def generate_stream_markdown(course_name: str, language: str):
"""
流式生成 Markdown 数据,并在控制台输出完整的 Markdown 内容
"""
prompt = ''
if language == 'cn':
prompt = '请使用中文回答'
elif language == 'en':
prompt = 'Please answer in English。'
# 调用阿里云 API启用流式响应
stream = client.chat.completions.create(
model=MODEL_NAME,
messages=[
{'role': 'system', 'content': '你是一个教学经验丰富的基础教育教师'},
{'role': 'user',
'content': prompt + ',帮我设计一下' + course_name + '的课件提纲用markdown格式返回。强调1、标签只能返回 #,##,###,-,其它标签一率不可以返回这个非常重要2、不要返回 ```markdown 或者 ``` 这样的内容! 3、每部分都有生成完整的一、二、三级内容不能省略。'}
],
stream=True, # 启用流式响应
timeout=6000,
)
# 初始化完整的 Markdown 内容
full_markdown = ""
# 逐字返回数据
for chunk in stream:
if chunk.choices[0].delta.content:
chunk_content = chunk.choices[0].delta.content
full_markdown += chunk_content # 拼接 Markdown 内容
for char in chunk_content:
yield char.encode("utf-8")
await asyncio.sleep(0.05) # 控制逐字输出的速度
# 在控制台输出完整的 Markdown 内容
print("\n完整的 Markdown 内容:")
print(full_markdown)
app = FastAPI()
# 添加 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 根路由,返回提示信息
@app.get("/")
def root():
return PlainTextResponse("Hello ApiStream")
@app.post("/api/tools/aippt_outline") # 仅支持 POST 方法
async def aippt_outline(
course_name: str = Body(..., embed=True, description="课程名称"), # 从请求体中获取 course_name
language: str = Body(..., embed=True, description="语言"),
):
# 返回流式响应
return StreamingResponse(
generate_stream_markdown(course_name, language),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"X-Accel-Buffering": "no"
}
)
@app.post("/api/tools/aippt") # 修改为 POST 方法
def aippt(content: str = Body(..., embed=True, description="Markdown 内容"),
language: str = Body(..., embed=True, description="语言")): # 使用 Body 接收请求体参数
return StreamingResponse(
convertMarkdownToJson(content, language), # 传入 content
media_type="text/plain", # 使用 text/plain 格式
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
"X-Accel-Buffering": "no",
"Content-Type": "text/plain; charset=utf-8" # 明确设置 Content-Type
}
)
# 运行应用
if __name__ == "__main__":
# 获取本机所有 IPv4 地址
ips = get_local_ips()
if not ips:
print("无法获取本机 IP 地址,使用默认地址 127.0.0.1")
ips = ["127.0.0.1"]
# 打印所有 IP 地址
print("服务将在以下 IP 地址上运行:")
for ip in ips:
print(f"http://{ip}:5176")
# 启动 FastAPI 应用,绑定到所有 IP 地址
uvicorn.run(app, host="0.0.0.0", port=5176)