diff --git a/README.md b/README.md index b183a7ce..42727476 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ * ✅ **API Presentation Generation** — Host as API to generate presentations over requests * ✅ **Ollama Support** — Run open-source models locally with Ollama integration * ✅ **OpenAI API Compatibility** — Use any OpenAI-compatible API endpoint with your own models +* ✅ **Versatile Image Generation** — Choose from DALL-E 3, Gemini Flash, Pexels, or Pixabay for your visuals * ✅ **Runs Locally** — All code runs on your device * ✅ **Privacy-First** — No tracking, no data stored by us * ✅ **Flexible** — Generate presentations from prompts or outlines @@ -74,7 +75,7 @@ You may want to directly provide your API KEYS as environment variables and keep You can also set the following environment variables to customize the image generation provider and API keys: - **IMAGE_PROVIDER=[pexels/pixabay/gemini_flash/dall-e-3]**: Select the image provider of your choice. - - Defaults to **dall-e-3** for OpenAI models and **gemini_flash** for Google models if not set. + - Defaults to **dall-e-3** for OpenAI models, **gemini_flash** for Google models if not set. - **PEXELS_API_KEY=[Your Pexels API Key]**: Required if using **pexels** as the image provider. - **PIXABAY_API_KEY=[Your Pixabay API Key]**: Required if using **pixabay** as the image provider. - **GOOGLE_API_KEY=[Your Google API Key]**: Required if using **gemini_flash** as the image provider. diff --git a/servers/fastapi/api/v1/ppt/endpoints/slide.py b/servers/fastapi/api/v1/ppt/endpoints/slide.py index a6f9ee9a..c473fc03 100644 --- a/servers/fastapi/api/v1/ppt/endpoints/slide.py +++ b/servers/fastapi/api/v1/ppt/endpoints/slide.py @@ -1,10 +1,11 @@ -from typing import Annotated +from typing import Annotated, Optional from fastapi import APIRouter, Body, HTTPException from models.sql.presentation import PresentationModel from models.sql.slide import SlideModel from services.database import get_sql_session from utils.llm_calls.edit_slide import get_edited_slide_content +from utils.llm_calls.edit_slide_html import get_edited_slide_html from utils.llm_calls.select_slide_type_on_edit import get_slide_layout_from_prompt from utils.process_slides import process_old_and_new_slides_and_fetch_assets from utils.randomizers import get_random_uuid @@ -14,10 +15,7 @@ SLIDE_ROUTER = APIRouter(prefix="/slide", tags=["Slide"]) @SLIDE_ROUTER.post("/edit") -async def edit_slide( - id: Annotated[str, Body()], - prompt: Annotated[str, Body()] -): +async def edit_slide(id: Annotated[str, Body()], prompt: Annotated[str, Body()]): with get_sql_session() as sql_session: slide = sql_session.get(SlideModel, id) @@ -53,3 +51,33 @@ async def edit_slide( sql_session.refresh(slide) return slide + + +@SLIDE_ROUTER.post("/edit-html", response_model=SlideModel) +async def edit_slide_html( + id: Annotated[str, Body()], + prompt: Annotated[str, Body()], + html: Annotated[Optional[str], Body()] = None, +): + with get_sql_session() as sql_session: + slide = sql_session.get(SlideModel, id) + if not slide: + raise HTTPException(status_code=404, detail="Slide not found") + + html_to_edit = html or slide.html_content + if not html_to_edit: + raise HTTPException(status_code=400, detail="No HTML to edit") + + edited_slide_html = await get_edited_slide_html(prompt, html_to_edit) + + # Always assign a new unique id to the slide + # This is to ensure that the nextjs can track slide updates + slide.id = get_random_uuid() + + with get_sql_session() as sql_session: + sql_session.add(slide) + slide.html_content = edited_slide_html + sql_session.commit() + sql_session.refresh(slide) + + return slide diff --git a/servers/fastapi/models/sql/slide.py b/servers/fastapi/models/sql/slide.py index 2195350f..76ad01c5 100644 --- a/servers/fastapi/models/sql/slide.py +++ b/servers/fastapi/models/sql/slide.py @@ -1,3 +1,4 @@ +from typing import Optional from sqlmodel import SQLModel, Field, Column, JSON from utils.randomizers import get_random_uuid @@ -10,3 +11,4 @@ class SlideModel(SQLModel, table=True): layout: str index: int content: dict = Field(sa_column=Column(JSON)) + html_content: Optional[str] diff --git a/servers/fastapi/utils/llm_calls/edit_slide.py b/servers/fastapi/utils/llm_calls/edit_slide.py index 17d7e4a6..20c87c53 100644 --- a/servers/fastapi/utils/llm_calls/edit_slide.py +++ b/servers/fastapi/utils/llm_calls/edit_slide.py @@ -7,8 +7,8 @@ from models.sql.slide import SlideModel from google.genai.types import GenerateContentConfig from utils.llm_provider import ( get_google_llm_client, + get_large_model, get_llm_client, - get_small_model, is_google_selected, ) from utils.schema_utils import remove_fields_from_schema @@ -58,7 +58,7 @@ async def get_edited_slide_content( slide: SlideModel, language: Optional[str] = None, ): - model = get_small_model() + model = get_large_model() response_schema = remove_fields_from_schema( slide_layout.json_schema, ["__image_url__", "__icon_url__"] ) diff --git a/servers/fastapi/utils/llm_calls/edit_slide_html.py b/servers/fastapi/utils/llm_calls/edit_slide_html.py new file mode 100644 index 00000000..b20f3cf7 --- /dev/null +++ b/servers/fastapi/utils/llm_calls/edit_slide_html.py @@ -0,0 +1,93 @@ +import asyncio +from typing import Optional +from google.genai.types import GenerateContentConfig +from utils.llm_provider import ( + get_google_llm_client, + get_large_model, + is_google_selected, + get_llm_client, +) + +system_prompt = """ + You are an expert HTML slide editor. Your task is to modify slide HTML content based on user prompts while maintaining proper structure, styling, and functionality. + + Guidelines: + 1. **Preserve Structure**: Maintain the overall HTML structure, including essential containers, classes, and IDs + 2. **Content Updates**: Modify text, images, lists, and other content elements as requested + 3. **Style Consistency**: Keep existing CSS classes and styling unless specifically asked to change them + 4. **Responsive Design**: Ensure modifications work across different screen sizes + 5. **Accessibility**: Maintain proper semantic HTML and accessibility attributes + 6. **Clean Output**: Return only the modified HTML without explanations unless errors occur + + Common Edit Types: + - Text content changes (headings, paragraphs, lists) + - Image updates (src, alt text, captions) + - Layout modifications (adding/removing sections) + - Style adjustments (colors, fonts, spacing via classes) + - Interactive elements (buttons, links, forms) + + Error Handling: + - If the HTML structure is invalid, fix it while making requested changes + - If a request would break functionality, suggest an alternative approach + - For unclear prompts, make reasonable assumptions and note any ambiguities + + Output Format: + Return the complete modified HTML. If the original HTML contains