- Added MAX_NUMBER_OF_SLIDES constant to limit slide generation. - Updated GeneratePresentationRequest model to allow optional slide count and language detection. - Implemented language resolution in edit_slide and generate_presentation_outlines utilities. - Enhanced user prompts to include optional parameters for slide count and table of contents. - Introduced outline utilities for managing table of contents and slide outlines. - Improved image and icon processing in slides to utilize outline image URLs. - Updated frontend components to resolve backend asset URLs for icons and images. - Refactored upload components to handle optional slide count and language selection. - Enhanced API utility functions to resolve backend asset URLs correctly.
194 lines
5.4 KiB
Python
194 lines
5.4 KiB
Python
from datetime import datetime
|
|
import json
|
|
from typing import Optional
|
|
from models.llm_message import LLMSystemMessage, LLMUserMessage
|
|
from models.presentation_layout import SlideLayoutModel
|
|
from models.presentation_outline_model import SlideOutlineModel
|
|
from services.llm_client import LLMClient
|
|
from utils.llm_client_error_handler import handle_llm_client_exceptions
|
|
from utils.llm_provider import get_model
|
|
from utils.schema_utils import add_field_in_schema, remove_fields_from_schema
|
|
|
|
|
|
SLIDE_CONTENT_SYSTEM_PROMPT = """
|
|
You will be given slide content and response schema.
|
|
You need to generate structured content json based on the schema.
|
|
|
|
# Steps
|
|
1. Analyze the content.
|
|
2. Analyze the response schema.
|
|
3. Generate structured content json based on the schema.
|
|
4. Generate speaker note if required.
|
|
5. Provide structured content json as output.
|
|
|
|
# General Rules
|
|
- Make sure to follow language guidelines.
|
|
- Speaker note should be normal text, not markdown.
|
|
- Never ever go over the max character limit.
|
|
- Do not add emoji in the content.
|
|
- Don't provide $schema field in content json.
|
|
{markdown_emphasis_rules}
|
|
|
|
{user_instructions}
|
|
|
|
{tone_instructions}
|
|
|
|
{verbosity_instructions}
|
|
|
|
{output_fields_instructions}
|
|
"""
|
|
|
|
|
|
SLIDE_CONTENT_USER_PROMPT = """
|
|
# Current Date and Time:
|
|
{current_date_time}
|
|
|
|
# Icon Query And Image Prompt Language:
|
|
English
|
|
|
|
# Slide Language:
|
|
{language}
|
|
|
|
# SLIDE CONTENT: START
|
|
{content}
|
|
# SLIDE CONTENT: END
|
|
"""
|
|
|
|
|
|
def _resolve_prompt_language(language: Optional[str]) -> str:
|
|
if language is None:
|
|
return "auto-detect"
|
|
s = str(language).strip()
|
|
if not s:
|
|
return "auto-detect"
|
|
if s.lower() in {"auto", "auto-detect"}:
|
|
return "auto-detect"
|
|
return s
|
|
|
|
|
|
def _get_schema_markdown(response_schema: Optional[dict]) -> str:
|
|
if not response_schema:
|
|
return "- Follow the provided response schema strictly."
|
|
try:
|
|
schema_text = json.dumps(response_schema, ensure_ascii=False)
|
|
except Exception:
|
|
return "- Follow the provided response schema strictly."
|
|
return f"- Follow this response schema exactly: {schema_text}"
|
|
|
|
|
|
def get_system_prompt(
|
|
tone: Optional[str] = None,
|
|
verbosity: Optional[str] = None,
|
|
instructions: Optional[str] = None,
|
|
response_schema: Optional[dict] = None,
|
|
):
|
|
markdown_emphasis_rules = (
|
|
"- Strictly use markdown to emphasize important points, by bolding or "
|
|
"italicizing the part of text."
|
|
)
|
|
|
|
user_instructions = f"# User Instructions:\n{instructions}" if instructions else ""
|
|
tone_instructions = (
|
|
f"# Tone Instructions:\nMake slide as {tone} as possible." if tone else ""
|
|
)
|
|
|
|
verbosity_instructions = ""
|
|
if verbosity:
|
|
verbosity_instructions = "# Verbosity Instructions:\n"
|
|
if verbosity == "concise":
|
|
verbosity_instructions += "Make slide as concise as possible."
|
|
elif verbosity == "standard":
|
|
verbosity_instructions += "Make slide as standard as possible."
|
|
elif verbosity == "text-heavy":
|
|
verbosity_instructions += "Make slide as text-heavy as possible."
|
|
|
|
output_fields_instructions = "# Output Fields:\n" + _get_schema_markdown(
|
|
response_schema
|
|
)
|
|
|
|
return SLIDE_CONTENT_SYSTEM_PROMPT.format(
|
|
markdown_emphasis_rules=markdown_emphasis_rules,
|
|
user_instructions=user_instructions,
|
|
tone_instructions=tone_instructions,
|
|
verbosity_instructions=verbosity_instructions,
|
|
output_fields_instructions=output_fields_instructions,
|
|
)
|
|
|
|
|
|
def get_user_prompt(outline: str, language: Optional[str]):
|
|
return SLIDE_CONTENT_USER_PROMPT.format(
|
|
current_date_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
language=_resolve_prompt_language(language),
|
|
content=outline,
|
|
)
|
|
|
|
|
|
def get_messages(
|
|
outline: str,
|
|
language: Optional[str],
|
|
tone: Optional[str] = None,
|
|
verbosity: Optional[str] = None,
|
|
instructions: Optional[str] = None,
|
|
response_schema: Optional[dict] = None,
|
|
):
|
|
|
|
return [
|
|
LLMSystemMessage(
|
|
content=get_system_prompt(
|
|
tone,
|
|
verbosity,
|
|
instructions,
|
|
response_schema,
|
|
),
|
|
),
|
|
LLMUserMessage(
|
|
content=get_user_prompt(outline, language),
|
|
),
|
|
]
|
|
|
|
|
|
async def get_slide_content_from_type_and_outline(
|
|
slide_layout: SlideLayoutModel,
|
|
outline: SlideOutlineModel,
|
|
language: Optional[str],
|
|
tone: Optional[str] = None,
|
|
verbosity: Optional[str] = None,
|
|
instructions: Optional[str] = None,
|
|
):
|
|
client = LLMClient()
|
|
model = get_model()
|
|
|
|
response_schema = remove_fields_from_schema(
|
|
slide_layout.json_schema, ["__image_url__", "__icon_url__"]
|
|
)
|
|
response_schema = add_field_in_schema(
|
|
response_schema,
|
|
{
|
|
"__speaker_note__": {
|
|
"type": "string",
|
|
"minLength": 100,
|
|
"maxLength": 250,
|
|
"description": "Speaker note for the slide",
|
|
}
|
|
},
|
|
True,
|
|
)
|
|
|
|
try:
|
|
response = await client.generate_structured(
|
|
model=model,
|
|
messages=get_messages(
|
|
outline.content,
|
|
language,
|
|
tone,
|
|
verbosity,
|
|
instructions,
|
|
response_schema,
|
|
),
|
|
response_format=response_schema,
|
|
strict=False,
|
|
)
|
|
return response
|
|
|
|
except Exception as e:
|
|
raise handle_llm_client_exceptions(e)
|