Merge branch 'feat/custom_schema_and_layout' of github.com:presenton/presenton into feat/custom_schema_and_layout
This commit is contained in:
commit
9a2eafd6dc
5 changed files with 117 additions and 55 deletions
|
|
@ -1,4 +1,3 @@
|
|||
from typing import Annotated
|
||||
from fastapi import APIRouter, Body
|
||||
|
||||
from models.image_prompt import ImagePrompt
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
16
servers/fastapi/utils/async_iterator.py
Normal file
16
servers/fastapi/utils/async_iterator.py
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue