Merge branch 'feat/custom_schema_and_layout' of github.com:presenton/presenton into feat/custom_schema_and_layout

This commit is contained in:
shiva raj badu 2025-07-16 21:08:30 +05:45
commit 9a2eafd6dc
5 changed files with 117 additions and 55 deletions

View file

@ -1,4 +1,3 @@
from typing import Annotated
from fastapi import APIRouter, Body
from models.image_prompt import ImagePrompt

View file

@ -2,6 +2,7 @@ from typing import List, Optional
from pydantic import BaseModel, Field, HttpUrl, EmailStr
from models.presentation_layout import PresentationLayoutModel, SlideLayoutModel
from models.presentation_outline_model import PresentationOutlineModel
class ContactInfoModel(BaseModel):
@ -559,4 +560,6 @@ presentation_layout = PresentationLayoutModel(
],
)
print(presentation_layout.model_dump_json())
# print(presentation_layout.model_dump_json())
print(PresentationOutlineModel.model_json_schema())

View file

@ -0,0 +1,16 @@
import asyncio
from typing import AsyncGenerator, Callable, Iterator, TypeVar
T = TypeVar("T")
def iterator_to_async(
func: Callable[..., Iterator[T]],
) -> Callable[..., AsyncGenerator[T, None]]:
async def wrapper(*args, **kwargs) -> AsyncGenerator[T, None]:
iterator = func(*args, **kwargs)
for item in iterator:
yield item
await asyncio.sleep(0)
return wrapper

View file

@ -1,10 +1,14 @@
from typing import Optional
from openai.lib.streaming.chat._events import ContentDeltaEvent
from google.genai.types import GenerateContentConfig
from utils.async_iterator import iterator_to_async
from utils.get_dynamic_models import get_presentation_outline_model_with_n_slides
from utils.llm_provider import (
get_google_llm_client,
get_large_model,
get_llm_client,
is_google_selected,
)
system_prompt = """
@ -64,18 +68,33 @@ async def generate_ppt_outline(
model = get_large_model()
response_model = get_presentation_outline_model_with_n_slides(n_slides)
client = get_llm_client()
async with client.beta.chat.completions.stream(
model=model,
messages=get_prompt_template(prompt, n_slides, language, content),
response_format={
"type": "json_schema",
"json_schema": {
"name": "PresentationOutline",
"schema": response_model.model_json_schema(),
if not is_google_selected():
client = get_llm_client()
async with client.beta.chat.completions.stream(
model=model,
messages=get_prompt_template(prompt, n_slides, language, content),
response_format={
"type": "json_schema",
"json_schema": {
"name": "PresentationOutline",
"schema": response_model.model_json_schema(),
},
},
},
) as stream:
async for event in stream:
if isinstance(event, ContentDeltaEvent):
yield event.delta
) as stream:
async for event in stream:
if isinstance(event, ContentDeltaEvent):
yield event.delta
else:
client = get_google_llm_client()
generate_stream = iterator_to_async(client.models.generate_content_stream)
async for event in generate_stream(
model=model,
contents=[get_user_prompt(prompt, n_slides, language, content)],
config=GenerateContentConfig(
system_instruction=system_prompt,
response_mime_type="application/json",
response_json_schema=response_model.model_json_schema(),
),
):
yield event.text

View file

@ -1,36 +1,48 @@
import asyncio
import json
from pydantic import BaseModel, Field
from google.genai.types import GenerateContentConfig
from models.presentation_layout import SlideLayoutModel
from models.presentation_outline_model import SlideOutlineModel
from utils.llm_provider import get_llm_client, get_small_model
from utils.llm_provider import (
get_google_llm_client,
get_llm_client,
get_small_model,
is_google_selected,
)
system_prompt = """
Generate structured slide based on provided title and outline, follow mentioned steps and notes and provide structured output.
# Steps
1. Analyze the outline and title.
2. Generate structured slide based on the outline and title.
# Notes
- Slide body should not use words like "This slide", "This presentation".
- Rephrase the slide body to make it flow naturally.
- Do not use markdown formatting in slide body.
"""
def get_user_prompt(title: str, outline: str):
return f"""
## Slide Title
{title}
## Slide Outline
{outline}
"""
def get_prompt_to_generate_slide_content(title: str, outline: str):
return [
{
"role": "system",
"content": f"""
Generate structured slide based on provided title and outline, follow mentioned steps and notes and provide structured output.
# Steps
1. Analyze the outline and title.
2. Generate structured slide based on the outline and title.
# Notes
- Slide body should not use words like "This slide", "This presentation".
- Rephrase the slide body to make it flow naturally.
- Do not use markdown formatting in slide body.
""",
"content": system_prompt,
},
{
"role": "user",
"content": f"""
## Slide Title
{title}
## Slide Outline
{outline}
""",
"content": get_user_prompt(title, outline),
},
]
@ -38,24 +50,37 @@ def get_prompt_to_generate_slide_content(title: str, outline: str):
async def get_slide_content_from_type_and_outline(
slide_layout: SlideLayoutModel, outline: SlideOutlineModel
):
response_format = {
"type": "json_schema",
"json_schema": {
"name": slide_layout.name or slide_layout.id,
"schema": slide_layout.json_schema,
},
}
client = get_llm_client()
model = get_small_model()
response = await client.beta.chat.completions.parse(
model=model,
messages=get_prompt_to_generate_slide_content(
outline.title,
outline.body,
),
response_format=response_format,
)
return json.loads(response.choices[0].message.content)
if not is_google_selected():
client = get_llm_client()
response = await client.beta.chat.completions.parse(
model=model,
messages=get_prompt_to_generate_slide_content(
outline.title,
outline.body,
),
response_format={
"type": "json_schema",
"json_schema": {
"name": "SlideContent",
"schema": slide_layout.json_schema,
},
},
)
return json.loads(response.choices[0].message.content)
else:
client = get_google_llm_client()
user_prompt = get_user_prompt(outline.title, outline.body)
response = await asyncio.to_thread(
client.models.generate_content,
model=model,
contents=[user_prompt],
config=GenerateContentConfig(
system_instruction=system_prompt,
response_mime_type="application/json",
response_json_schema=slide_layout.json_schema,
),
)
return response.model_dump(mode="json")