import gradio as gr
import os
from gradio.data_classes import FileData
from config import Config
from chatbot import ChatBot
from content_formatter import ContentFormatter
from content_assistant import ContentAssistant
from image_advisor import ImageAdvisor
from input_parser import parse_input_text
from ppt_generator import generate_presentation
from template_manager import load_template, get_layout_mapping
from layout_manager import LayoutManager
from logger import LOG
from openai_whisper import asr, transcribe
# from minicpm_v_model import chat_with_image
from docx_parser import generate_markdown_from_docx
# os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "ChatPPT"
# 实例化 Config,加载配置文件
config = Config()
chatbot = ChatBot(config.chatbot_prompt)
content_formatter = ContentFormatter(config.content_formatter_prompt)
content_assistant = ContentAssistant(config.content_assistant_prompt)
image_advisor = ImageAdvisor(config.image_advisor_prompt)
# 加载 PowerPoint 模板,并获取可用布局
ppt_template = load_template(config.ppt_template)
# 初始化 LayoutManager,管理幻灯片布局
layout_manager = LayoutManager(get_layout_mapping(ppt_template))
# 定义生成幻灯片内容的函数
def generate_contents(message, history):
try:
# 初始化一个列表,用于收集用户输入的文本和音频转录
texts = []
# 获取文本输入,如果存在则添加到列表
text_input = message.get("text")
if text_input:
texts.append(text_input)
# 获取上传的文件列表,如果存在则处理每个文件
for uploaded_file in message.get("files", []):
LOG.debug(f"[上传文件]: {uploaded_file}")
# 获取文件的扩展名,并转换为小写
file_ext = os.path.splitext(uploaded_file)[1].lower()
if file_ext in ('.wav', '.flac', '.mp3'):
# 使用 OpenAI Whisper 模型进行语音识别
audio_text = asr(uploaded_file)
texts.append(audio_text)
# 解释说明图像文件
# elif file_ext in ('.jpg', '.png', '.jpeg'):
# if text_input:
# image_desc = chat_with_image(uploaded_file, text_input)
# else:
# image_desc = chat_with_image(uploaded_file)
# return image_desc
# 使用 Docx 文件作为素材创建 PowerPoint
elif file_ext in ('.docx', '.doc'):
# 调用 generate_markdown_from_docx 函数,获取 markdown 内容
raw_content = generate_markdown_from_docx(uploaded_file)
markdown_content = content_formatter.format(raw_content)
return content_assistant.adjust_single_picture(markdown_content)
else:
LOG.debug(f"[格式不支持]: {uploaded_file}")
# 将所有文本和转录结果合并为一个字符串,作为用户需求
user_requirement = "需求如下:\n" + "\n".join(texts)
LOG.info(user_requirement)
# 与聊天机器人进行对话,生成幻灯片内容
slides_content = chatbot.chat_with_history(user_requirement)
return slides_content
except Exception as e:
LOG.error(f"[内容生成错误]: {e}")
# 抛出 Gradio 错误,以便在界面上显示友好的错误信息
raise gr.Error(f"网络问题,请重试:)")
def handle_image_generate(history):
try:
# 获取聊天记录中的最新内容
slides_content = history[-1]["content"]
content_with_images, image_pair = image_advisor.generate_images(slides_content)
# for k, v in image_pair.items():
# history.append(
# # {"text": k, "files": FileData(path=v)}
# {"role": "user", "files": FileData(path=v)}
# )
new_message = {"role": "assistant", "content": content_with_images}
history.append(new_message)
return history
except Exception as e:
LOG.error(f"[配图生成错误]: {e}")
# 提示用户先输入主题内容或上传文件
raise gr.Error(f"【提示】未找到合适配图,请重试!")
# 定义处理生成按钮点击事件的函数
def handle_generate(history):
try:
# 获取聊天记录中的最新内容
slides_content = history[-1]["content"]
# 解析输入文本,生成幻灯片数据和演示文稿标题
powerpoint_data, presentation_title = parse_input_text(slides_content, layout_manager)
# 定义输出的 PowerPoint 文件路径
output_pptx = f"outputs/{presentation_title}.pptx"
# 生成 PowerPoint 演示文稿
generate_presentation(powerpoint_data, config.ppt_template, output_pptx)
return output_pptx
except Exception as e:
LOG.error(f"[PPT 生成错误]: {e}")
# 提示用户先输入主题内容或上传文件
raise gr.Error(f"【提示】请先输入你的主题内容或上传文件")
# 创建 Gradio 界面
with gr.Blocks(
title="ChatPPT",
css="""
body { animation: fadeIn 2s; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
"""
) as demo:
# 添加标题
gr.Markdown("## ChatPPT")
# 定义语音(mic)转文本的接口
# gr.Interface(
# fn=transcribe, # 执行转录的函数
# inputs=[
# gr.Audio(sources="microphone", type="filepath"), # 使用麦克风录制的音频输入
# ],
# outputs="text", # 输出为文本
# flagging_mode="never", # 禁用标记功能
# )
# 创建聊天机器人界面,提示用户输入
contents_chatbot = gr.Chatbot(
placeholder="AI 一键生成 PPT
输入你的主题内容或上传音频文件",
height=800,
type="messages",
)
# 定义 ChatBot 和生成内容的接口
gr.ChatInterface(
fn=generate_contents, # 处理用户输入的函数
chatbot=contents_chatbot, # 绑定的聊天机器人
type="messages",
multimodal=True # 支持多模态输入(文本和文件)
)
image_generate_btn = gr.Button("一键为 PowerPoint 配图")
image_generate_btn.click(
fn=handle_image_generate,
inputs=contents_chatbot,
outputs=contents_chatbot,
)
# 创建生成 PowerPoint 的按钮
generate_btn = gr.Button("一键生成 PowerPoint")
# 监听生成按钮的点击事件
generate_btn.click(
fn=handle_generate, # 点击时执行的函数
inputs=contents_chatbot, # 输入为聊天记录
outputs=gr.File() # 输出为文件下载链接
)
# 主程序入口
if __name__ == "__main__":
# 启动Gradio应用,允许队列功能,并通过 HTTPS 访问
demo.queue().launch(
share=False,
server_name="0.0.0.0",
# auth=("django", "qaz!@#$") # ⚠️注意:记住修改密码
)