前言
本文将带你深入理解 banana-slides(蕉幻)这个基于 nano banana pro 的 AI PPT 生成应用,从技术架构到实际使用,用大白话讲透它的设计哲学与实现细节。
1. 为什么我们需要'蕉幻'?—— 从痛点出发
想象一下,你刚结束一个重要的会议,老板要求你"明天上午前出个 PPT"。你打开 PPT 软件,开始翻找模板,调整配色,插入图表… 3 小时后,你疲惫地发现 PPT 还是"老套"、"缺乏设计感"。这就是传统 AI PPT 工具的困境:
深度解析了原生 AI PPT 生成应用“蕉幻”。文章介绍了其设计哲学,即通过自然语言实现个性化 PPT 创作。技术架构采用前后端分离,后端基于 Flask 和 Google Gemini API,前端为 React。核心功能包括从想法、大纲或页面描述生成 PPT,支持自然语言修改及多模态素材处理。项目提供 Docker 部署方案,具备插件化 AI 集成和智能重试机制。旨在解决传统 AI PPT 工具模板固定、自由度低的问题,代表 AI 与设计融合的未来方向。
本文将带你深入理解 banana-slides(蕉幻)这个基于 nano banana pro 的 AI PPT 生成应用,从技术架构到实际使用,用大白话讲透它的设计哲学与实现细节。
想象一下,你刚结束一个重要的会议,老板要求你"明天上午前出个 PPT"。你打开 PPT 软件,开始翻找模板,调整配色,插入图表… 3 小时后,你疲惫地发现 PPT 还是"老套"、"缺乏设计感"。这就是传统 AI PPT 工具的困境:
1️⃣ 只能选预设模板:像点外卖只能选菜单上的菜,无法根据需求定制
2️⃣ 自由度低:修改一次要重新生成,像去超市买菜要重新排队
3️⃣ 成品同质化:所有 PPT 都像"预制菜",没有特色
4️⃣ 素材质量低:图片像"路边摊",缺乏专业感
5️⃣ 图文割裂:文字和图片不搭,像"汉堡配牛奶"
传统 AI PPT 工具就像"自动点餐机",你只能选菜单上的菜,不能说"我要加辣"或"换种摆盘"。
而 banana-slides 的诞生,正是为了解决这个问题——真正的'Vibe PPT',让你像和朋友聊天一样,自然地说出需求,AI 就能生成符合你口味的 PPT。
'Vibe'在这里不是指音乐氛围,而是指设计感、流畅度、个性化。banana-slides 的设计哲学可以概括为:
'用自然语言,生成有灵魂的 PPT'
这意味着:
想象你去一家高级餐厅点菜:
banana-slides:你告诉厨师"我想要一道健康、低卡、适合商务场合的菜,有蔬菜和鱼,摆盘要精致",厨师会根据你的描述,现场创作出一道符合你口味的菜banana-slides 采用典型的前后端分离架构,就像餐厅的前厅和后厨分工明确:
【插入架构图位置:banana-slides 系统架构图】前端 (React) ←→ 后端 (Flask) ←→ AI 服务 (Gemini API)
│ │ │
用户界面层 业务逻辑层 AI 能力层
大白话解释:就像你点外卖时,告诉客服"我要一份辣度中等、有牛肉、不加香菜的牛肉面",客服会理解你的需求,然后下单。
大白话解释:就像你告诉设计师"我要一个简洁的商务 PPT,主题是 AI,第一页要有标题和背景图,第二页是数据图表",设计师会根据你的描述,画出草图。
大白话解释:就像你点完外卖后,发现"辣度中等"不够辣,你直接说"加点辣",外卖小哥会立刻调整。
让我们深入分析项目的代码组织结构:
banana-slides/
├── frontend/ # React 前端应用
│ ├── src/
│ │ ├── pages/ # 页面组件
│ │ │ ├── Home.tsx # 首页(创建项目)
│ │ │ ├── OutlineEditor.tsx # 大纲编辑页
│ │ │ ├── DetailEditor.tsx # 详细描述编辑页
│ │ │ ├── SlidePreview.tsx # 幻灯片预览页
│ │ │ └── History.tsx # 历史版本管理页
│ │ ├── components/ # UI 组件
│ │ │ ├── outline/ # 大纲相关组件
│ │ │ │ └── OutlineCard.tsx
│ │ │ ├── preview/ # 预览相关组件
│ │ │ │ ├── SlideCard.tsx
│ │ │ │ └── DescriptionCard.tsx
│ │ │ ├── shared/ # 共享组件
│ │ │ │ ├── Button.tsx
│ │ │ │ ├── Card.tsx
│ │ │ │ ├── Input.tsx
│ │ │ │ ├── Textarea.tsx
│ │ │ │ ├── Modal.tsx
│ │ │ │ ├── Loading.tsx
│ │ │ │ ├── Toast.tsx
│ │ │ │ ├── Markdown.tsx
│ │ │ │ ├── MaterialSelector.tsx
│ │ │ │ ├── MaterialGeneratorModal.tsx
│ │ │ │ ├── TemplateSelector.tsx
│ │ │ │ ├── ReferenceFileSelector.tsx
│ │ │ │ └── ...
│ │ │ ├── layout/ # 布局组件
│ │ │ └── history/ # 历史版本组件
│ │ ├── store/ # Zustand 状态管理
│ │ │ └── useProjectStore.ts
│ │ ├── api/ # API 接口
│ │ │ ├── client.ts # Axios 客户端配置
│ │ │ └── endpoints.ts # API 端点定义
│ │ ├── types/ # TypeScript 类型定义
│ │ ├── utils/ # 工具函数
│ │ ├── constants/ # 常量定义
│ │ └── styles/ # 样式文件
│ ├── public/ # 静态资源
│ ├── package.json
│ ├── vite.config.ts
│ ├── tailwind.config.js # Tailwind CSS 配置
│ ├── Dockerfile
│ └── nginx.conf # Nginx 配置
│ ├── backend/ # Flask 后端应用
│ ├── app.py # Flask 应用入口
│ ├── config.py # 配置文件
│ ├── models/ # 数据库模型
│ │ ├── project.py # Project 模型
│ │ ├── page.py # Page 模型(幻灯片页)
│ │ ├── task.py # Task 模型(异步任务)
│ │ ├── material.py # Material 模型(参考素材)
│ │ ├── user_template.py # UserTemplate 模型(用户模板)
│ │ ├── reference_file.py # ReferenceFile 模型(参考文件)
│ │ ├── page_image_version.py # PageImageVersion 模型(页面版本)
│ ├── services/ # 服务层
│ │ ├── ai_service.py # AI 生成服务(Gemini 集成)
│ │ ├── file_service.py # 文件管理服务
│ │ ├── file_parser_service.py # 文件解析服务
│ │ ├── export_service.py # PPTX/PDF 导出服务
│ │ ├── task_manager.py # 异步任务管理
│ │ ├── prompts.py # AI 提示词模板
│ ├── controllers/ # API 控制器
│ │ ├── project_controller.py # 项目管理
│ │ ├── page_controller.py # 页面管理
│ │ ├── material_controller.py # 素材管理
│ │ ├── template_controller.py # 模板管理
│ │ ├── reference_file_controller.py # 参考文件管理
│ │ ├── export_controller.py # 导出功能
│ │ └── file_controller.py # 文件上传
│ ├── utils/ # 工具函数
│ │ ├── response.py # 统一响应格式
│ │ ├── validators.py # 数据验证
│ │ └── path_utils.py # 路径处理
│ ├── instance/ # SQLite 数据库(自动生成)
│ ├── exports/ # 导出文件目录
│ ├── Dockerfile
│ └── README.md
├── tests/ # 测试文件目录
├── v0_demo/ # 早期演示版本
├── output/ # 输出文件目录
│ ├── pyproject.toml # Python 项目配置(uv 管理)
├── uv.lock # uv 依赖锁定文件
├── docker-compose.yml # Docker Compose 配置
├── .env.example # 环境变量示例
├── LICENSE # 许可证
└── README.md # 本文件
banana-slides 的核心技术是巧妙地集成外部 AI API,而不是自己训练模型。这就像餐厅不是自己种菜,而是精选优质供应商:
class AIService:
"""Service for AI model interactions using pluggable providers"""
def __init__(self, text_provider: TextProvider = None, image_provider: ImageProvider = None):
# 使用插件化设计,支持不同的 AI 提供商
self.text_provider = text_provider or get_text_provider(model=self.text_model)
self.image_provider = image_provider or get_image_provider(model=self.image_model)
核心思想:AIService 不直接调用具体的 AI 模型,而是通过抽象的 TextProvider 和 ImageProvider 接口。这种设计就像电视机的遥控器——不管内部是 LCD 还是 OLED 屏幕,用户都用同样的按钮操作。
@retry(stop=stop_after_attempt(3), retry=retry_if_exception_type((json.JSONDecodeError, ValueError)))
def generate_json(self, prompt: str, thinking_budget: int = 1000) -> Union[Dict, List]:
""" 生成并解析 JSON,如果解析失败则重新生成
这就像让 AI 写作文,如果格式不对就重写,直到符合要求
"""
response_text = self.text_provider.generate_text(prompt, thinking_budget=thinking_budget)
# 清理响应文本:移除 markdown 代码块标记
cleaned_text = response_text.strip().strip("```json").strip("```").strip()
try:
return json.loads(cleaned_text)
except json.JSONDecodeError as e:
logger.warning(f"JSON 解析失败,将重新生成。原始文本:{cleaned_text[:200]}...")
raise
关键技术点:
@retry 装饰器,JSON 解析失败自动重试 3 次thinking_budget 参数控制 AI 的"思考深度"def generate_outline(self, project_context: ProjectContext, language: str = None) -> List[Dict]:
""" 从想法生成 PPT 大纲 - 这是整个流程的起点
过程:用户想法 → AI 理解 → 结构化大纲
"""
outline_prompt = get_outline_generation_prompt(project_context, language)
outline = self.generate_json(outline_prompt, thinking_budget=1000)
return outline
实际工作流程:
get_outline_generation_prompt 生成适合 AI 理解的指令def flatten_outline(self, outline: List[Dict]) -> List[Dict]:
""" 将层次化大纲扁平化为页面列表
例如:将"第一部分{页面 1, 页面 2}"转换为 [页面 1, 页面 2]
"""
pages = []
for item in outline:
if "part" in item and "pages" in item:
# 处理章节结构:展开章节内的页面
for page in item["pages"]:
page_with_part = page.copy()
page_with_part["part"] = item["part"]
# 保留章节信息
pages.append(page_with_part)
else:
# 直接页面
pages.append(item)
return pages
设计思想:保持原始大纲的层次结构,但在需要时能够扁平化处理,兼顾灵活性和实用性。
def generate_image(self, prompt: str, ref_image_path: Optional[str] = None, additional_ref_images: Optional[List[Union[str, Image.Image]]] = None) -> Optional[Image.Image]:
""" 生成图片,支持多种参考图片来源:
- 本地文件路径
- HTTP URL
- MinerU 特殊路径
- 直接传入的 PIL Image 对象
"""
ref_images = []
# 处理主参考图片
if ref_image_path and os.path.exists(ref_image_path):
ref_images.append(Image.open(ref_image_path))
# 处理额外参考图片
if additional_ref_images:
for ref_img in additional_ref_images:
if isinstance(ref_img, Image.Image):
ref_images.append(ref_img)
elif isinstance(ref_img, str):
if ref_img.startswith('http'):
# 下载网络图片
downloaded_img = self.download_image_from_url(ref_img)
if downloaded_img:
ref_images.append(downloaded_img)
elif ref_img.startswith('/files/mineru/'):
# 处理 MinerU 路径
local_path = self._convert_mineru_path_to_local(ref_img)
if local_path:
ref_images.append(Image.open(local_path))
return self.image_provider.generate_image(prompt=prompt, ref_images=ref_images)
技术亮点:
def extract_image_urls_from_markdown(self, text: str) -> List[str]:
""" 从 markdown 文本中提取图片 URL
自动识别格式的图片引用
"""
pattern = r'!\[.*?\]\((.*?)\)'
matches = re.findall(pattern, text)
urls = []
for url in matches:
url = url.strip()
if url and (url.startswith('http') or url.startswith('/files/mineru/')):
urls.append(url)
return urls
def remove_markdown_images(self, text: str) -> str:
""" 移除 Markdown 图片链接,只保留描述文字
例如:将"请看下图"转换为"请看下图"
"""
def replace_image(match):
alt_text = match.group(1).strip()
return alt_text if alt_text else ''
pattern = r'!\[(.*?)\]\([^)]+\)'
return re.sub(pattern, replace_image, text)
应用场景:当用户上传包含图片引用的 Markdown 文档时,系统能自动提取图片作为素材,同时保留文字描述用于生成提示词。
def refine_outline(self, current_outline: List[Dict], user_requirement: str, project_context: ProjectContext, previous_requirements: Optional[List[str]] = None) -> List[Dict]:
""" 根据自然语言指令修改大纲
支持多轮对话,能记住之前的修改要求
"""
refinement_prompt = get_outline_refinement_prompt(
current_outline=current_outline,
user_requirement=user_requirement,
project_context=project_context,
previous_requirements=previous_requirements # 支持历史上下文
)
return self.generate_json(refinement_prompt, thinking_budget=1000)
def edit_image(self, prompt: str, current_image_path: str, original_description: str = None) -> Optional[Image.Image]:
""" 基于自然语言指令编辑现有图片
例如:"把这张图的背景换成蓝色"
"""
edit_instruction = get_image_edit_prompt(
edit_instruction=prompt,
original_description=original_description # 提供原始描述作为上下文
)
return self.generate_image(edit_instruction, current_image_path)
创新点:不是简单的替换,而是在理解原始内容和用户意图的基础上进行智能修改。
class ProjectContext:
"""统一管理 AI 需要的所有项目信息"""
def __init__(self, project_or_dict, reference_files_content: Optional[List[Dict[str, str]]] = None):
# 支持 Project 对象或字典,提高灵活性
if hasattr(project_or_dict, 'idea_prompt'):
self.idea_prompt = project_or_dict.idea_prompt
self.outline_text = project_or_dict.outline_text
# ... 其他属性
else:
self.idea_prompt = project_or_dict.get('idea_prompt')
# ... 其他属性
self.reference_files_content = reference_files_content or []
设计优势:通过统一的上下文对象,确保 AI 在各个处理阶段都能获得完整的信息,避免信息孤岛。
基于代码分析,banana-slides 的完整工作流程如下:
用户输入
↓
AIService.generate_outline() # 生成大纲
↓
AIService.flatten_outline() # 扁平化处理
↓
循环每个页面:
↓
AIService.generate_page_description() # 生成页面描述
↓
AIService.generate_image_prompt() # 生成图片提示词
↓
AIService.generate_image() # 生成图片
↓
组合成完整 PPT
这个 AIService 类体现了 banana-slides 项目的核心价值:不是简单调用 AI API,而是通过精巧的工程设计和提示词工程,将 AI 能力转化为真正易用的 PPT 创作体验。
# 1. 克隆项目
git clone https://github.com/Anionex/banana-slides
cd banana-slides
# 2. 配置环境变量(需 Gemini API Key)
cp .env.example .env
# 编辑 .env 文件,填入你的 Google API Key
# GOOGLE_API_KEY=your-api-key-here
# 3. 启动服务
docker compose up -d
# 4. 访问应用
http://localhost:3000
用户输入:"我需要一个关于 AI PPT 工具的演示,重点讲蕉幻的创新点,有数据图表和案例。"
用户输入:
1. 项目介绍
2. 核心功能
- 三种生成路径
- 素材解析
- 自然语言修改
3. 技术架构
4. 未来规划
用户输入:
第一页:标题"蕉幻 - 重新定义 AI PPT",副标题"基于 nano banana pro 的原生 AI PPT 生成应用",背景图是科技感的抽象线条
第二页:核心功能,3 个要点,每个要点配图标
banana-slides 的核心是使用 Google 的 nano banana pro 模型,相比传统 AI PPT 工具,它有以下优势:
就像一位经验丰富的设计师,不仅能理解你的需求,还能精准执行。
| 生成方式 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| 从想法生成 | 初期构思,思路模糊 | 快速启动,无需详细规划 | 可能需要多次调整 |
| 从大纲生成 | 有基本结构,需要填充内容 | 结构清晰,内容丰富 | 需要提前规划大纲 |
| 从页面描述生成 | 有明确每页内容,只需生成设计 | 最快,适合细节把控 | 需要详细描述每页 |
banana-slides 支持像聊天一样修改 PPT:
'第三页的图表改成柱状图,颜色换成蓝色。'
而不是像传统工具那样:
'删除第三页,重新生成第三页,要求是柱状图,蓝色。'
支持上传参考图片、旧 PPT 作为风格线索,AI 会分析并模仿。
| 状态 | 功能 | 说明 |
|---|---|---|
| ✅ 已完成 | 三种生成路径 | 从想法/大纲/页面描述生成 PPT |
| ✅ 已完成 | 文本与链接自动提取 | 从文本中抽取要点和图片链接 |
| ✅ 已完成 | 素材上传与解析 | 上传参考图片、旧 PPT |
| 🔄 进行中 | 元素分割与编辑 | 支持对已生成图片的元素进行分割和编辑 |
| 🔄 进行中 | 文件上传与网络搜索 | 支持上传文件和网络搜索素材 |
| 🧭 规划中 | Agent 模式 | AI 自动优化 PPT 内容和设计 |
banana-slides 不仅仅是一个工具,它代表了 AI 与设计的融合。未来的 PPT 工具将不再是"模板选择器",而是"设计伙伴",能真正理解你的需求,生成符合你品味的 PPT。
正如《设计心理学》作者唐纳德·诺曼所说:
'好的设计不是让用户去适应产品,而是让产品适应用户。'
banana-slides 正在实践这一理念,让 PPT 制作从"苦差事"变成"享受"。
《Designing for the Digital Age》 - Kim Goodwin
这本书是数字产品设计的圣经,深入探讨了设计思维、用户体验和设计流程。虽然不是专门讲 PPT 设计,但其中的"设计思维"和"用户中心"理念,正是
banana-slides的设计哲学基础。
书中提到:'设计不是关于美学,而是关于解决问题。'这正是
banana-slides试图解决的 PPT 制作痛点。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online