feat(fastapi): converts schema to pydantic model for structured response, fix: changes icon and image schema for pydantic model support

This commit is contained in:
sauravniraula 2025-07-31 15:50:41 +05:45
parent c63944b7cf
commit bb6abf1890
No known key found for this signature in database
GPG key ID: 60FCC1B5A5E83326
56 changed files with 440 additions and 377 deletions

View file

@ -8,4 +8,5 @@ build
.gitignore
tmp
debug
.fastembed_cache
.fastembed_cache
generated_models

3
.gitignore vendored
View file

@ -11,4 +11,5 @@ app_data
tmp
debug
.fastembed_cache
my-doc.txt
my-doc.txt
generated_models

View file

@ -2,10 +2,11 @@ import asyncio
import json
import os
import random
import importlib
from typing import Annotated, List, Literal, Optional
from fastapi import APIRouter, Body, Depends, File, HTTPException, UploadFile
from fastapi.responses import StreamingResponse
from sqlalchemy import String, cast, delete
from sqlalchemy import delete
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from constants.documents import UPLOAD_ACCEPTED_FILE_TYPES
@ -27,7 +28,7 @@ from utils.export_utils import export_presentation
from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
from models.sql.slide import SlideModel
from models.sse_response import SSECompleteResponse, SSEResponse
from services import TEMP_FILE_SERVICE
from services import SCHEMA_TO_MODEL_SERVICE, TEMP_FILE_SERVICE
from services.database import get_async_session
from services.documents_loader import DocumentsLoader
from models.sql.presentation import PresentationModel
@ -42,6 +43,7 @@ from utils.llm_calls.generate_slide_content import (
)
from utils.process_slides import process_slide_and_fetch_assets
from utils.randomizers import get_random_uuid
from utils.schema_utils import remove_fields_from_schema
from utils.validators import validate_files
PRESENTATION_ROUTER = APIRouter(prefix="/presentation", tags=["Presentation"])
@ -217,9 +219,23 @@ async def stream_presentation(
).to_string()
for i, slide_layout_index in enumerate(structure.slides):
slide_layout = layout.slides[slide_layout_index]
slide_content = await get_slide_content_from_type_and_outline(
slide_layout, outline.slides[i], presentation.language
# Generate Pydantic model from slide layout schema
schema_model_id = f"{layout.name}/{slide_layout.id}"
response_schema = remove_fields_from_schema(
slide_layout.json_schema, ["image_url_", "icon_url_"]
)
schema_model_path = (
await SCHEMA_TO_MODEL_SERVICE.get_pydantic_model_path_from_schema(
schema_model_id, response_schema
)
)
module = importlib.import_module(schema_model_path)
response_model = module.GeneratedModel
slide_content = await get_slide_content_from_type_and_outline(
response_model, outline.slides[i], presentation.language
)
slide = SlideModel(
presentation=presentation_id,
layout_group=layout.name,

View file

@ -1,9 +1,11 @@
import importlib
from typing import Annotated, Optional
from fastapi import APIRouter, Body, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from models.sql.presentation import PresentationModel
from models.sql.slide import SlideModel
from services import SCHEMA_TO_MODEL_SERVICE
from services.database import get_async_session
from services.icon_finder_service import IconFinderService
from services.image_generation_service import ImageGenerationService
@ -13,6 +15,7 @@ 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
from utils.schema_utils import remove_fields_from_schema
SLIDE_ROUTER = APIRouter(prefix="/slide", tags=["Slide"])
@ -36,8 +39,21 @@ async def edit_slide(
slide_layout = await get_slide_layout_from_prompt(
prompt, presentation_layout, slide
)
# Generate Pydantic model from slide layout schema
schema_model_id = f"{presentation_layout.name}/{slide_layout.id}"
response_schema = remove_fields_from_schema(
slide_layout.json_schema, ["image_url_", "icon_url_"]
)
schema_model_path = (
await SCHEMA_TO_MODEL_SERVICE.get_pydantic_model_path_from_schema(
schema_model_id, response_schema
)
)
module = importlib.import_module(schema_model_path)
response_model = module.GeneratedModel
edited_slide_content = await get_edited_slide_content(
prompt, slide_layout, slide, presentation.language
prompt, slide, presentation.language, response_model
)
image_generation_service = ImageGenerationService(get_images_directory())

View file

@ -17,8 +17,8 @@ class ContactInfoModel(BaseModel):
class ImageModel(BaseModel):
__image_url__: str = Field(description="Image URL")
__image_prompt__: str = Field(description="Image prompt")
image_url_: str = Field(description="Image URL")
image_prompt_: str = Field(description="Image prompt")
# First Slide Layout

View file

@ -12,7 +12,7 @@ class SlideLayoutModel(BaseModel):
class PresentationLayoutModel(BaseModel):
name: Optional[str] = None
name: str
ordered: bool = Field(default=False)
slides: List[SlideLayoutModel]

View file

@ -6,11 +6,13 @@ aiosqlite==0.21.0
annotated-types==0.7.0
anthropic==0.60.0
anyio==4.9.0
argcomplete==3.6.2
async-timeout==5.0.1
asyncpg==0.30.0
attrs==25.3.0
backoff==2.2.1
bcrypt==4.3.0
black==25.1.0
build==1.2.2.post1
cachetools==5.5.2
certifi==2025.7.14
@ -20,6 +22,7 @@ chromadb==1.0.15
click==8.2.1
coloredlogs==15.0.1
cryptography==45.0.5
datamodel-code-generator==0.32.0
distro==1.9.0
dnspython==2.7.0
durationpy==0.10
@ -32,6 +35,7 @@ filelock==3.18.0
flatbuffers==25.2.10
frozenlist==1.7.0
fsspec==2025.7.0
genson==1.3.0
google-auth==2.40.3
google-genai==1.25.0
googleapis-common-protos==1.70.0
@ -50,7 +54,9 @@ hyperframe==6.1.0
idna==3.10
importlib_metadata==8.7.0
importlib_resources==6.5.2
inflect==7.5.0
iniconfig==2.1.0
isort==6.0.1
Jinja2==3.1.6
jiter==0.10.0
jsonschema==4.25.0
@ -62,8 +68,10 @@ markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
mmh3==5.1.0
more-itertools==10.7.0
mpmath==1.3.0
multidict==6.6.3
mypy_extensions==1.1.0
numpy==2.3.2
oauthlib==3.3.1
onnxruntime==1.22.1
@ -77,10 +85,12 @@ opentelemetry-semantic-conventions==0.56b0
orjson==3.11.1
overrides==7.7.0
packaging==25.0
pathspec==0.12.1
pathvalidate==3.3.1
pdfminer.six==20250506
pdfplumber==0.11.7
pillow==11.3.0
platformdirs==4.3.8
pluggy==1.6.0
portalocker==3.2.0
posthog==5.4.0
@ -123,7 +133,9 @@ starlette==0.47.1
sympy==1.14.0
tenacity==8.5.0
tokenizers==0.21.2
tomli==2.2.1
tqdm==4.67.1
typeguard==4.4.4
typer==0.16.0
typing-inspection==0.4.1
typing_extensions==4.14.1

View file

@ -1,6 +1,8 @@
from services.redis_service import RedisService
from services.schema_to_model_service import SchemaToModelService
from services.temp_file_service import TempFileService
TEMP_FILE_SERVICE = TempFileService()
REDIS_SERVICE = RedisService()
SCHEMA_TO_MODEL_SERVICE = SchemaToModelService(TEMP_FILE_SERVICE)

View file

@ -205,14 +205,13 @@ class LLMClient:
)
content = response.choices[0].message.parsed
if content:
return content
return content.model_dump(mode="json")
return None
async def _generate_google_structured(
self, model: str, messages: List[LLMMessage], response_format: BaseModel | dict
):
client: genai.Client = self._client
is_response_format_dict = isinstance(response_format, dict)
response = await asyncio.to_thread(
client.models.generate_content,
model=model,
@ -228,9 +227,6 @@ class LLMClient:
if response.text:
content = json.loads(response.text)
# If response format is Pydantic model, return the model instance
if content and not is_response_format_dict:
return response_format(**content)
return content
async def _generate_anthropic_structured(
@ -263,9 +259,6 @@ class LLMClient:
if content_block.type == "tool_use":
content = content_block.input
# If response format is Pydantic model, return the model instance
if content and not is_response_format_dict:
return response_format(**content)
return content
async def _generate_ollama_structured(
@ -280,7 +273,7 @@ class LLMClient:
async def generate_structured(
self, model: str, messages: List[LLMMessage], response_format: BaseModel | dict
):
) -> dict:
content = None
match self.llm_provider:
case LLMProvider.OPENAI:

View file

@ -1,39 +1,78 @@
import asyncio
import json
import tempfile
from pydantic import BaseModel
import os
from pathlib import Path
from typing import Dict
from fastapi import HTTPException
from datamodel_code_generator import generate, InputFileType, DataModelType
from services import TEMP_FILE_SERVICE
from services.temp_file_service import TempFileService
from utils.randomizers import get_random_uuid
class SchemaToModelService:
def __init__(self):
self.temp_dir = TEMP_FILE_SERVICE.create_temp_dir()
self._records = {}
def __init__(self, temp_file_service: TempFileService):
self.temp_file_service = temp_file_service
self.temp_dir = self.temp_file_service.create_temp_dir()
def convert(self, schema: dict, identifier: str) -> BaseModel:
return BaseModel.model_validate(schema)
self.generated_models_dir = "generated_models"
if os.path.exists(self.generated_models_dir):
for file in os.listdir(self.generated_models_dir):
if file.endswith(".py"):
os.remove(os.path.join(self.generated_models_dir, file))
os.makedirs(self.generated_models_dir, exist_ok=True)
def schema_to_pydantic_model(self, schema: dict, class_name: str):
schema_path = TEMP_FILE_SERVICE.create_temp_file_path(
get_random_uuid() + ".json", self.temp_dir
self._records: Dict[str, str] = {}
self._fetch_locks: Dict[str, asyncio.Lock] = {}
def convert_path_to_module_path(self, path: str):
return path.replace("/", ".").replace("\\", ".").replace(".py", "")
async def get_pydantic_model_path_from_schema(
self, identifier: str, schema: dict
) -> str:
if identifier in self._fetch_locks:
async with self._fetch_locks[identifier]:
return self._records[identifier]
else:
async_lock = asyncio.Lock()
await async_lock.acquire()
self._fetch_locks[identifier] = async_lock
model_path = await self.generate_pydantic_model_from_schema_async(schema)
model_path = self.convert_path_to_module_path(model_path)
self._records[identifier] = model_path
async_lock.release()
return model_path
async def generate_pydantic_model_from_schema_async(self, schema: dict):
return await asyncio.to_thread(self.generate_pydantic_model_from_schema, schema)
def generate_pydantic_model_from_schema(self, schema: dict):
generated_model_path = os.path.join(
self.generated_models_dir, get_random_uuid() + ".py"
)
with open(schema_path, "w") as f:
json.dump(schema, f)
try:
schema_path = self.temp_file_service.create_temp_file_path(
get_random_uuid() + ".json", self.temp_dir
)
with open(schema_path, "w") as f:
json.dump(schema, f)
generated_model_path = TEMP_FILE_SERVICE.create_temp_file_path(
get_random_uuid() + ".py", self.temp_dir
)
# generate(
# input_=Path(schema_path),
# input_file_type=InputFileType.JsonSchema,
# output=Path(output_file),
# output_model_type=DataModelType.PydanticV2BaseModel,
# class_name=class_name,
# use_annotated=False,
# field_constraints=True,
# )
# Path(schema_file).unlink(missing_ok=True)
generate(
input_=Path(schema_path),
input_file_type=InputFileType.JsonSchema,
output=Path(generated_model_path),
output_model_type=DataModelType.PydanticV2BaseModel,
class_name="GeneratedModel",
use_annotated=False,
field_constraints=True,
extra_fields="ignore",
)
except Exception as e:
raise HTTPException(
status_code=500, detail="Failed to generate Pydantic model from schema"
)
finally:
self.temp_file_service.cleanup_temp_file(schema_path)
return generated_model_path

View file

@ -1,3 +1,4 @@
from pydantic import BaseModel
from models.llm_message import LLMMessage
from models.presentation_layout import SlideLayoutModel
from models.sql.slide import SlideModel
@ -54,19 +55,16 @@ def get_messages(
async def get_edited_slide_content(
prompt: str,
slide_layout: SlideLayoutModel,
slide: SlideModel,
language: str,
response_model: BaseModel,
):
model = get_large_model()
response_schema = remove_fields_from_schema(
slide_layout.json_schema, ["__image_url__", "__icon_url__"]
)
client = LLMClient()
response = await client.generate_structured(
model=model,
messages=get_messages(prompt, slide.content, language),
response_format=response_schema,
response_format=response_model,
)
return response

View file

@ -76,4 +76,4 @@ async def generate_presentation_structure(
),
response_format=response_model,
)
return response
return PresentationStructureModel(**response)

View file

@ -1,19 +1,8 @@
import asyncio
import json
from google.genai.types import GenerateContentConfig
from pydantic import BaseModel
from models.llm_message import LLMMessage
from models.presentation_layout import SlideLayoutModel
from models.presentation_outline_model import SlideOutlineModel
from services.llm_client import LLMClient
from utils.llm_provider import (
get_anthropic_llm_client,
get_google_llm_client,
get_large_model,
get_llm_client,
is_anthropic_selected,
is_google_selected,
)
from utils.schema_utils import remove_fields_from_schema
from utils.llm_provider import get_large_model
system_prompt = """
Generate structured slide based on provided title and outline, follow mentioned steps and notes and provide structured output.
@ -25,8 +14,8 @@ system_prompt = """
# Notes
- Slide body should not use words like "This slide", "This presentation".
- Rephrase the slide body to make it flow naturally.
- Provide prompt to generate image on "__image_prompt__" property.
- Provide query to search icon on "__icon_query__" property.
- Provide prompt to generate image on "image_prompt_" property.
- Provide query to search icon on "icon_query_" property.
- Do not use markdown formatting in slide body.
- Make sure to follow language guidelines.
**Strictly follow the max and min character limit for every property in the slide.**
@ -64,15 +53,11 @@ def get_messages(title: str, outline: str, language: str):
async def get_slide_content_from_type_and_outline(
slide_layout: SlideLayoutModel, outline: SlideOutlineModel, language: str
response_model: BaseModel, outline: SlideOutlineModel, language: str
):
client = LLMClient()
model = get_large_model()
response_schema = remove_fields_from_schema(
slide_layout.json_schema, ["__image_url__", "__icon_url__"]
)
response = await client.generate_structured(
model=model,
messages=get_messages(
@ -80,6 +65,6 @@ async def get_slide_content_from_type_and_outline(
outline.body,
language,
),
response_format=response_schema,
response_format=response_model,
)
return response

View file

@ -48,7 +48,7 @@ async def get_slide_layout_from_prompt(
slide_layout_ids = list(map(lambda x: x.id, layout.slides))
response: SlideLayoutIndex = await client.generate_structured(
response = await client.generate_structured(
model=model,
messages=get_messages(
prompt,
@ -58,5 +58,5 @@ async def get_slide_layout_from_prompt(
),
response_format=SlideLayoutIndex,
)
index = response.index
index = SlideLayoutIndex(**response).index
return layout.slides[index]

View file

@ -107,7 +107,7 @@ def get_anthropic_llm_client():
def get_large_model():
selected_llm = get_llm_provider()
if selected_llm == LLMProvider.OPENAI:
return "gpt-4.1-nano"
return "gpt-4.1"
elif selected_llm == LLMProvider.GOOGLE:
return "gemini-2.0-flash"
elif selected_llm == LLMProvider.ANTHROPIC:

View file

@ -17,15 +17,15 @@ async def process_slide_and_fetch_assets(
async_tasks = []
image_paths = get_dict_paths_with_key(slide.content, "__image_prompt__")
icon_paths = get_dict_paths_with_key(slide.content, "__icon_query__")
image_paths = get_dict_paths_with_key(slide.content, "image_prompt_")
icon_paths = get_dict_paths_with_key(slide.content, "icon_query_")
for image_path in image_paths:
image_prompt_parent = get_dict_at_path(slide.content, image_path)
async_tasks.append(
image_generation_service.generate_image(
ImagePrompt(
prompt=image_prompt_parent["__image_prompt__"],
prompt=image_prompt_parent["image_prompt_"],
)
)
)
@ -33,7 +33,7 @@ async def process_slide_and_fetch_assets(
for icon_path in icon_paths:
icon_query_parent = get_dict_at_path(slide.content, icon_path)
async_tasks.append(
icon_finder_service.search_icons(icon_query_parent["__icon_query__"])
icon_finder_service.search_icons(icon_query_parent["icon_query_"])
)
results = await asyncio.gather(*async_tasks)
@ -45,14 +45,14 @@ async def process_slide_and_fetch_assets(
result = results.pop()
if isinstance(result, ImageAsset):
return_assets.append(result)
image_dict["__image_url__"] = result.path
image_dict["image_url_"] = result.path
else:
image_dict["__image_url__"] = result
image_dict["image_url_"] = result
set_dict_at_path(slide.content, image_path, image_dict)
for icon_path in icon_paths:
icon_dict = get_dict_at_path(slide.content, icon_path)
icon_dict["__icon_url__"] = results.pop()[0]
icon_dict["icon_url_"] = results.pop()[0]
set_dict_at_path(slide.content, icon_path, icon_dict)
return return_assets
@ -66,34 +66,34 @@ async def process_old_and_new_slides_and_fetch_assets(
) -> List[ImageAsset]:
# Finds all old images
old_image_dict_paths = get_dict_paths_with_key(
old_slide_content, "__image_prompt__"
old_slide_content, "image_prompt_"
)
old_image_dicts = [
get_dict_at_path(old_slide_content, path) for path in old_image_dict_paths
]
old_image_prompts = [
old_image_dict["__image_prompt__"] for old_image_dict in old_image_dicts
old_image_dict["image_prompt_"] for old_image_dict in old_image_dicts
]
# Finds all old icons
old_icon_dict_paths = get_dict_paths_with_key(old_slide_content, "__icon_query__")
old_icon_dict_paths = get_dict_paths_with_key(old_slide_content, "icon_query_")
old_icon_dicts = [
get_dict_at_path(old_slide_content, path) for path in old_icon_dict_paths
]
old_icon_queries = [
old_icon_dict["__icon_query__"] for old_icon_dict in old_icon_dicts
old_icon_dict["icon_query_"] for old_icon_dict in old_icon_dicts
]
# Finds all new images
new_image_dict_paths = get_dict_paths_with_key(
new_slide_content, "__image_prompt__"
new_slide_content, "image_prompt_"
)
new_image_dicts = [
get_dict_at_path(new_slide_content, path) for path in new_image_dict_paths
]
# Finds all new icons
new_icon_dict_paths = get_dict_paths_with_key(new_slide_content, "__icon_query__")
new_icon_dict_paths = get_dict_paths_with_key(new_slide_content, "icon_query_")
new_icon_dicts = [
get_dict_at_path(new_slide_content, path) for path in new_icon_dict_paths
]
@ -109,18 +109,18 @@ async def process_old_and_new_slides_and_fetch_assets(
# Creates async tasks for fetching new images
# Use old image url if prompt is same
for new_image in new_image_dicts:
if new_image["__image_prompt__"] in old_image_prompts:
if new_image["image_prompt_"] in old_image_prompts:
old_image_url = old_image_dicts[
old_image_prompts.index(new_image["__image_prompt__"])
]["__image_url__"]
new_image["__image_url__"] = old_image_url
old_image_prompts.index(new_image["image_prompt_"])
]["image_url_"]
new_image["image_url_"] = old_image_url
new_images_fetch_status.append(False)
continue
async_image_fetch_tasks.append(
image_generation_service.generate_image(
ImagePrompt(
prompt=new_image["__image_prompt__"],
prompt=new_image["image_prompt_"],
)
)
)
@ -129,16 +129,16 @@ async def process_old_and_new_slides_and_fetch_assets(
# Creates async tasks for fetching new icons
# Use old icon url if query is same
for new_icon in new_icon_dicts:
if new_icon["__icon_query__"] in old_icon_queries:
if new_icon["icon_query_"] in old_icon_queries:
old_icon_url = old_icon_dicts[
old_icon_queries.index(new_icon["__icon_query__"])
]["__icon_url__"]
new_icon["__icon_url__"] = old_icon_url
old_icon_queries.index(new_icon["icon_query_"])
]["icon_url_"]
new_icon["icon_url_"] = old_icon_url
new_icons_fetch_status.append(False)
continue
async_icon_fetch_tasks.append(
icon_finder_service.search_icons(new_icon["__icon_query__"])
icon_finder_service.search_icons(new_icon["icon_query_"])
)
new_icons_fetch_status.append(True)
@ -157,11 +157,11 @@ async def process_old_and_new_slides_and_fetch_assets(
image_url = fetched_image.path
else:
image_url = fetched_image
new_image_dicts[i]["__image_url__"] = image_url
new_image_dicts[i]["image_url_"] = image_url
for i, new_icon in enumerate(new_icons):
if new_icons_fetch_status[i]:
new_icon_dicts[i]["__icon_url__"] = new_icons[i][0]
new_icon_dicts[i]["icon_url_"] = new_icons[i][0]
for i, new_image_dict in enumerate(new_image_dicts):
set_dict_at_path(new_slide_content, new_image_dict_paths[i], new_image_dict)

View file

@ -42,12 +42,12 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
const matches: { path: string; type: 'image' | 'icon'; data: any }[] = [];
// Check current level for __image_url__ or __icon_url__
if (data.__image_url__ && targetUrl.includes(data.__image_url__)) {
// Check current level for image_url_ or icon_url_
if (data.image_url_ && targetUrl.includes(data.image_url_)) {
matches.push({ path, type: 'image', data });
}
if (data.__icon_url__ && targetUrl.includes(data.__icon_url__)) {
if (data.icon_url_ && targetUrl.includes(data.icon_url_)) {
matches.push({ path, type: 'icon', data });
}
@ -308,7 +308,7 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
slideIndex,
dataPath: activeEditor.dataPath,
imageUrl: newImageUrl,
prompt: prompt || activeEditor.data?.__image_prompt__ || ''
prompt: prompt || activeEditor.data?.image_prompt_ || ''
}));
setActiveEditor(null);
}
@ -326,7 +326,7 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
slideIndex,
dataPath: activeEditor.dataPath,
iconUrl: newIconUrl,
query: query || activeEditor.data?.__icon_query__ || ''
query: query || activeEditor.data?.icon_query_ || ''
}));
@ -361,7 +361,7 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
<ImageEditor
initialImage={activeEditor.src}
slideIndex={slideIndex}
promptContent={activeEditor.data?.__image_prompt__ || ''}
promptContent={activeEditor.data?.image_prompt_ || ''}
imageIdx={0}
properties={null}
onClose={handleEditorClose}
@ -374,7 +374,7 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
{/* Render IconsEditor when an icon is being edited */}
{activeEditor && activeEditor.type === 'icon' && (
<IconsEditor
icon_prompt={activeEditor.data?.__icon_query__ ? [activeEditor.data.__icon_query__] : []}
icon_prompt={activeEditor.data?.icon_query_ ? [activeEditor.data.icon_query_] : []}
onClose={handleEditorClose}
onIconChange={handleIconChange}
>

View file

@ -31,15 +31,15 @@ export const Schema = z.object({
}),
chartImage: ImageSchema.default({
__image_url__: "https://example.com/quarterly-chart.png",
__image_prompt__: "Quarterly performance chart showing upward trend"
image_url_: "https://example.com/quarterly-chart.png",
image_prompt_: "Quarterly performance chart showing upward trend"
}).meta({
description: "Main performance chart",
}),
trendIcon: IconSchema.default({
__icon_url__: "/static/icons/placeholder.png",
__icon_query__: "upward trend arrow icon"
icon_url_: "/static/icons/placeholder.png",
icon_query_: "upward trend arrow icon"
}).meta({
description: "Trend indicator icon",
}),
@ -57,11 +57,11 @@ export default function ExampleSlideLayout({ data }: { data: SchemaType }) {
</header>
<main className="slide-content flex-1 flex">
{chartImage?.__image_url__ && (
{chartImage?.image_url_ && (
<div className="chart-section flex-1">
<img
src={chartImage.__image_url__}
alt={chartImage.__image_prompt__}
src={chartImage.image_url_}
alt={chartImage.image_prompt_}
className="w-full h-auto max-h-96 object-contain"
/>
</div>
@ -74,9 +74,9 @@ export default function ExampleSlideLayout({ data }: { data: SchemaType }) {
<div key={index} className="metric-item mb-4 p-3 bg-gray-50 rounded">
<div className="flex items-center justify-between">
<span className="font-medium">{metric.label}</span>
{trendIcon?.__icon_url__ && (
{trendIcon?.icon_url_ && (
<img
src={trendIcon.__icon_url__}
src={trendIcon.icon_url_}
alt={metric.trend}
className="w-6 h-6"
/>

View file

@ -37,16 +37,16 @@ const type10SlideSchema = z.object({
})).min(2).max(3).default(() => [
{
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'A beautiful road in the mountains'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'A beautiful road in the mountains'
},
heading: 'First Key Point',
description: 'Detailed explanation of the first important point that supports the main topic'
},
{
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'A beautiful road in the mountains'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'A beautiful road in the mountains'
},
heading: 'Second Key Point',
description: 'Detailed explanation of the second important point with relevant information'
@ -240,9 +240,9 @@ const Type10SlideLayout: React.FC<Type10SlideLayoutProps> = ({ data: slideData }
<div className="flex gap-6">
<div className="w-[48px] h-[48px]">
<div className="w-full h-full bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
{item.icon?.icon_url_ && <img
src={item.icon?.icon_url_ || ''}
alt={item.icon?.icon_query_ || item.heading}
className="w-full h-full object-cover"
/>}
</div>

View file

@ -14,8 +14,8 @@ const type1SlideSchema = z.object({
description: "Main description text",
}),
image: ImageSchema.default({
__image_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__image_prompt__: 'A beautiful road in the mountains'
image_url_: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
image_prompt_: 'A beautiful road in the mountains'
}).meta({
description: "Main slide image",
})
@ -52,8 +52,8 @@ const Type1SlideLayout: React.FC<Type1SlideLayoutProps> = ({ data: slideData })
{/* Image */}
<div className="w-full max-h-[600px]">
{image && <img
src={image?.__image_url__ || ''}
alt={image?.__image_prompt__ || title || ''}
src={image?.image_url_ || ''}
alt={image?.image_prompt_ || title || ''}
className="w-full max-h-full object-cover rounded-lg shadow-md"
/>}
</div>

View file

@ -25,24 +25,24 @@ const type3SlideSchema = z.object({
heading: 'First Feature',
description: 'Description for the first featured item with detailed information',
image: {
__image_url__: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
__image_prompt__: 'A beautiful road in the mountains'
image_url_: 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
image_prompt_: 'A beautiful road in the mountains'
}
},
{
heading: 'Second Feature',
description: 'Description for the second featured item with relevant details',
image: {
__image_url__: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
__image_prompt__: 'Modern office workspace'
image_url_: 'https://cdn.pixabay.com/photo/2016/02/19/11/19/office-1209640_1280.jpg',
image_prompt_: 'Modern office workspace'
}
},
{
heading: 'Third Feature',
description: 'Description for the third featured item with important points',
image: {
__image_url__: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
__image_prompt__: 'Laptop with code on screen'
image_url_: 'https://cdn.pixabay.com/photo/2017/08/10/08/47/laptop-2619235_1280.jpg',
image_prompt_: 'Laptop with code on screen'
}
}
]).meta({
@ -94,8 +94,8 @@ const Type3SlideLayout: React.FC<Type3SlideLayoutProps> = ({ data: slideData })
{/* Image */}
<div className="max-md:h-[140px] max-lg:h-[180px] h-48 w-full">
<img
src={item.image?.__image_url__ || ''}
alt={item.image?.__image_prompt__ || item.heading}
src={item.image?.image_url_ || ''}
alt={item.image?.image_prompt_ || item.heading}
className="w-full h-full object-cover"
/>
</div>

View file

@ -23,32 +23,32 @@ const type6SlideSchema = z.object({
heading: 'Professional Service',
description: 'High-quality professional services tailored to your specific needs and requirements',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Professional Service'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Professional Service'
}
},
{
heading: 'Expert Consultation',
description: 'Expert advice and consultation from experienced professionals in the field',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Expert Consultation'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Expert Consultation'
}
},
{
heading: 'Quality Assurance',
description: 'Comprehensive quality assurance processes to ensure excellent results',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Quality Assurance'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Quality Assurance'
}
},
{
heading: 'Customer Support',
description: 'Dedicated customer support available to assist you throughout the process',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Customer Support'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Customer Support'
}
}
]).meta({
@ -94,7 +94,7 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
<div className="flex items-start gap-2 mg:gap-4">
<div className="flex-shrink-0 lg:w-16">
<div className="w-12 h-12 lg:w-16 lg:h-16 bg-blue-600 rounded-lg flex items-center justify-center text-white text-xl lg:text-2xl">
<img src={item.icon.__icon_url__} className='w-full h-full object-contain' alt={item.icon.__icon_query__} />
<img src={item.icon.icon_url_} className='w-full h-full object-contain' alt={item.icon.icon_query_} />
</div>
</div>
<div>
@ -125,7 +125,7 @@ const Type6SlideLayout: React.FC<Type6SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4">
<div className="w-16 h-16 lg:w-20 lg:h-20 bg-blue-600 rounded-lg flex items-center justify-center text-white text-2xl lg:text-3xl mx-auto mb-4">
<img src={item.icon.__icon_url__} className='w-full h-full object-contain' alt={item.icon.__icon_query__} />
<img src={item.icon.icon_url_} className='w-full h-full object-contain' alt={item.icon.icon_query_} />
</div>
</div>
<div className="lg:space-y-4 mt-2 lg:mt-4">

View file

@ -18,8 +18,8 @@ const type7SlideSchema = z.object({
description: "Item description",
}),
icon: IconSchema.default({
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Default icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Default icon'
}).meta({
description: "Icon for the item",
})
@ -28,32 +28,32 @@ const type7SlideSchema = z.object({
heading: 'Professional Service',
description: 'High-quality professional services tailored to your specific needs and requirements',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Professional service icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Professional service icon'
}
},
{
heading: 'Expert Consultation',
description: 'Expert advice and consultation from experienced professionals in the field',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Expert consultation icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Expert consultation icon'
}
},
{
heading: 'Quality Assurance',
description: 'Comprehensive quality assurance processes to ensure excellent results',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Quality assurance icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Quality assurance icon'
}
},
{
heading: 'Customer Support',
description: 'Dedicated customer support available to assist you throughout the process',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Customer support icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Customer support icon'
}
}
]).meta({
@ -100,8 +100,8 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
<div className="flex-shrink-0 lg:w-16">
<div className="w-12 h-12 lg:w-16 lg:h-16 bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
<img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
src={item.icon?.icon_url_ || ''}
alt={item.icon?.icon_query_ || item.heading}
className="w-full h-full object-cover"
/>
</div>
@ -134,9 +134,9 @@ const Type7SlideLayout: React.FC<Type7SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4">
<div className="w-16 h-16 lg:w-20 lg:h-20 bg-blue-600 rounded-lg flex items-center justify-center mx-auto mb-4 overflow-hidden">
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
{item.icon?.icon_url_ && <img
src={item.icon?.icon_url_ || ''}
alt={item.icon?.icon_query_ || item.heading}
className="w-full h-full object-cover"
/>}
</div>

View file

@ -21,8 +21,8 @@ const type8SlideSchema = z.object({
description: "Item description",
}),
icon: IconSchema.default({
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Default icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Default icon'
}).meta({
description: "Icon for the item",
})
@ -31,24 +31,24 @@ const type8SlideSchema = z.object({
heading: 'Advanced Features',
description: 'Cutting-edge functionality designed to enhance productivity and user experience',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Advanced features icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Advanced features icon'
}
},
{
heading: 'Reliable Performance',
description: 'Consistent and dependable performance across all platforms and devices',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Reliable performance icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Reliable performance icon'
}
},
{
heading: 'Secure Environment',
description: 'Enterprise-grade security measures to protect your data and privacy',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'Secure environment icon'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'Secure environment icon'
}
}
]).meta({
@ -82,9 +82,9 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
>
<div className="text-center mb-4">
<div className="w-16 h-16 lg:w-20 lg:h-20 bg-blue-600 rounded-lg flex items-center justify-center mx-auto mb-4 overflow-hidden">
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
{item.icon?.icon_url_ && <img
src={item.icon?.icon_url_ || ''}
alt={item.icon?.icon_query_ || item.heading}
className="w-full h-full object-cover"
/>}
</div>
@ -116,9 +116,9 @@ const Type8SlideLayout: React.FC<Type8SlideLayoutProps> = ({ data: slideData })
<div className="flex items-start gap-4">
<div className="w-[64px] h-[64px]">
<div className="w-full h-full bg-blue-600 rounded-lg flex items-center justify-center overflow-hidden">
{item.icon?.__icon_url__ && <img
src={item.icon?.__icon_url__ || ''}
alt={item.icon?.__icon_query__ || item.heading}
{item.icon?.icon_url_ && <img
src={item.icon?.icon_url_ || ''}
alt={item.icon?.icon_query_ || item.heading}
className="w-full h-full object-cover"
/>}
</div>

View file

@ -1,19 +1,19 @@
import * as z from "zod";
export const ImageSchema = z.object({
__image_url__: z.url().meta({
image_url_: z.url().meta({
description: "URL to image",
}),
__image_prompt__: z.string().meta({
image_prompt_: z.string().meta({
description: "Prompt used to generate the image",
}).min(10).max(50),
})
export const IconSchema = z.object({
__icon_url__: z.string().meta({
icon_url_: z.string().meta({
description: "URL to icon",
}),
__icon_query__: z.string().meta({
icon_query_: z.string().meta({
description: "Query used to search the icon",
}).min(5).max(20),
})

View file

@ -14,8 +14,8 @@ const basicInfoSlideSchema = z.object({
description: "Main description text content",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Business team in meeting room discussing product features and solutions'
image_url_: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Business team in meeting room discussing product features and solutions'
}).meta({
description: "Supporting image for the slide",
})
@ -54,8 +54,8 @@ const BasicInfoSlideLayout: React.FC<BasicInfoSlideLayoutProps> = ({ data: slide
<div className="flex-1 flex items-center justify-center pr-8">
<div className="w-full max-w-lg h-80 rounded-2xl overflow-hidden shadow-lg">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover"
/>
</div>

View file

@ -11,8 +11,8 @@ const bulletIconsOnlySlideSchema = z.object({
description: "Main title of the slide",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Business professionals collaborating and discussing solutions'
image_url_: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Business professionals collaborating and discussing solutions'
}).meta({
description: "Supporting image for the slide",
}),
@ -29,32 +29,32 @@ const bulletIconsOnlySlideSchema = z.object({
title: 'Custom Software',
subtitle: 'We create tailored software to optimize processes and boost efficiency.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'code software development'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'code software development'
}
},
{
title: 'Digital Consulting',
subtitle: 'Our consultants guide organizations in leveraging the latest technologies.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'users consulting team'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'users consulting team'
}
},
{
title: 'Support Services',
subtitle: 'We provide ongoing support to help businesses adapt and maintain performance.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'headphones support service'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'headphones support service'
}
},
{
title: 'Scalable Marketing',
subtitle: 'Our data-driven strategies help businesses expand their reach and engagement.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'trending up marketing growth'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'trending up marketing growth'
}
}
]).meta({
@ -131,8 +131,8 @@ const BulletIconsOnlySlideLayout: React.FC<BulletIconsOnlySlideLayoutProps> = ({
{/* Icon */}
<div className="flex-shrink-0 w-12 h-12 bg-purple-600 rounded-full flex items-center justify-center">
<img
src={bullet.icon.__icon_url__}
alt={bullet.icon.__icon_query__}
src={bullet.icon.icon_url_}
alt={bullet.icon.icon_query_}
className="w-6 h-6 object-contain brightness-0 invert"
/>
</div>
@ -176,8 +176,8 @@ const BulletIconsOnlySlideLayout: React.FC<BulletIconsOnlySlideLayoutProps> = ({
{/* Main Image */}
<div className="w-full h-80 rounded-2xl overflow-hidden shadow-lg">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover"
/>
</div>

View file

@ -14,8 +14,8 @@ const bulletWithIconsSlideSchema = z.object({
description: "Main description text explaining the problem or topic",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Business people analyzing documents and charts in office'
image_url_: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Business people analyzing documents and charts in office'
}).meta({
description: "Supporting image for the slide",
}),
@ -32,16 +32,16 @@ const bulletWithIconsSlideSchema = z.object({
title: 'Inefficiency',
description: 'Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'warning alert inefficiency'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'warning alert inefficiency'
}
},
{
title: 'High Costs',
description: 'Outdated systems increase expenses, while small businesses struggle to expand their market reach.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'trending up costs chart'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'trending up costs chart'
}
}
]).meta({
@ -105,8 +105,8 @@ const BulletWithIconsSlideLayout: React.FC<BulletWithIconsSlideLayoutProps> = ({
<div className="relative z-10 h-full flex items-center justify-center p-4">
<div className="w-full max-w-md h-80 rounded-2xl overflow-hidden shadow-lg">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover"
/>
</div>
@ -134,8 +134,8 @@ const BulletWithIconsSlideLayout: React.FC<BulletWithIconsSlideLayoutProps> = ({
{/* Icon */}
<div className="flex-shrink-0 w-12 h-12 bg-white rounded-lg shadow-md flex items-center justify-center">
<img
src={bullet.icon.__icon_url__}
alt={bullet.icon.__icon_query__}
src={bullet.icon.icon_url_}
alt={bullet.icon.icon_query_}
className="w-6 h-6 object-contain text-gray-700"
/>
</div>

View file

@ -64,24 +64,24 @@ const chartWithBulletsSlideSchema = z.object({
title: 'Total Addressable Market',
description: 'Companies can use TAM to plan future expansion and investment.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'target market scope'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'target market scope'
}
},
{
title: 'Serviceable Available Market',
description: 'Indicates more measurable market segments for sales efforts.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'pie chart analysis'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'pie chart analysis'
}
},
{
title: 'Serviceable Obtainable Market',
description: 'Help companies plan development strategies according to the market.',
icon: {
__icon_url__: '/static/icons/placeholder.png',
__icon_query__: 'trending up growth'
icon_url_: '/static/icons/placeholder.png',
icon_query_: 'trending up growth'
}
}
]).meta({
@ -270,8 +270,8 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
<div className="flex items-center space-x-3 mb-3">
<div className="w-8 h-8 bg-white/20 rounded-lg flex items-center justify-center">
<img
src={bullet.icon.__icon_url__}
alt={bullet.icon.__icon_query__}
src={bullet.icon.icon_url_}
alt={bullet.icon.icon_query_}
className="w-5 h-5 object-contain brightness-0 invert"
/>
</div>

View file

@ -20,8 +20,8 @@ const introSlideSchema = z.object({
description: "Date of the presentation",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Business team in meeting room discussing product features and solutions'
image_url_: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Business team in meeting room discussing product features and solutions'
}).meta({
description: "Supporting image for the slide",
})
@ -64,8 +64,8 @@ const IntroSlideLayout: React.FC<IntroSlideLayoutProps> = ({ data: slideData })
<div className="flex-1 flex items-center justify-center pr-8">
<div className="w-full max-w-lg h-80 rounded-2xl overflow-hidden shadow-lg">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover"
/>
</div>

View file

@ -14,8 +14,8 @@ const metricsWithImageSlideSchema = z.object({
description: "Description text below the title",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Person holding tablet with analytics dashboard and charts'
image_url_: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Person holding tablet with analytics dashboard and charts'
}).meta({
description: "Supporting image for the slide",
}),
@ -86,8 +86,8 @@ const MetricsWithImageSlideLayout: React.FC<MetricsWithImageSlideLayoutProps> =
<div className="flex-1 flex items-center justify-center pr-8">
<div className="w-full max-w-lg h-96 rounded-2xl overflow-hidden shadow-lg">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover"
/>
</div>

View file

@ -11,8 +11,8 @@ const numberedBulletsSlideSchema = z.object({
description: "Main title of the slide",
}),
image: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
__image_prompt__: 'Business people analyzing charts and data on wall'
image_url_: 'https://images.unsplash.com/photo-1552664730-d307ca884978?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80',
image_prompt_: 'Business people analyzing charts and data on wall'
}).meta({
description: "Supporting image for the slide",
}),
@ -87,8 +87,8 @@ const NumberedBulletsSlideLayout: React.FC<NumberedBulletsSlideLayoutProps> = ({
{/* Image Section */}
<div className="flex-shrink-0 w-80 h-48">
<img
src={slideData?.image?.__image_url__ || ''}
alt={slideData?.image?.__image_prompt__ || slideData?.title || ''}
src={slideData?.image?.image_url_ || ''}
alt={slideData?.image?.image_prompt_ || slideData?.title || ''}
className="w-full h-full object-cover rounded-lg shadow-md"
/>
</div>

View file

@ -17,8 +17,8 @@ const quoteSlideSchema = z.object({
description: "Author of the quote",
}),
backgroundImage: ImageSchema.default({
__image_url__: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2000&q=80',
__image_prompt__: 'Inspirational mountain landscape with dramatic sky and clouds'
image_url_: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2000&q=80',
image_prompt_: 'Inspirational mountain landscape with dramatic sky and clouds'
}).meta({
description: "Background image for the slide",
})
@ -51,7 +51,7 @@ const QuoteSlideLayout: React.FC<QuoteSlideLayoutProps> = ({ data: slideData })
<div
className="absolute inset-0 w-full h-full bg-cover bg-center bg-no-repeat"
style={{
backgroundImage: `url('${slideData?.backgroundImage?.__image_url__ || ''}')`,
backgroundImage: `url('${slideData?.backgroundImage?.image_url_ || ''}')`,
}}
/>

View file

@ -32,8 +32,8 @@ const teamSlideSchema = z.object({
position: 'CEO',
description: 'Strategic leader with 15+ years experience in digital transformation and business growth.',
image: {
__image_url__: 'https://images.unsplash.com/photo-1494790108755-2616b612994a?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
__image_prompt__: 'Professional businesswoman CEO headshot'
image_url_: 'https://images.unsplash.com/photo-1494790108755-2616b612994a?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
image_prompt_: 'Professional businesswoman CEO headshot'
}
},
{
@ -41,8 +41,8 @@ const teamSlideSchema = z.object({
position: 'CTO',
description: 'Technology expert specializing in scalable solutions and innovative software architecture.',
image: {
__image_url__: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
__image_prompt__: 'Professional businessman CTO headshot'
image_url_: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
image_prompt_: 'Professional businessman CTO headshot'
}
},
{
@ -50,8 +50,8 @@ const teamSlideSchema = z.object({
position: 'COO',
description: 'Operations leader focused on efficiency, process optimization, and team development.',
image: {
__image_url__: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
__image_prompt__: 'Professional businessman COO headshot'
image_url_: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
image_prompt_: 'Professional businessman COO headshot'
}
},
{
@ -59,8 +59,8 @@ const teamSlideSchema = z.object({
position: 'CMO',
description: 'Marketing strategist with expertise in brand development and customer engagement.',
image: {
__image_url__: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
__image_prompt__: 'Professional businesswoman CMO headshot'
image_url_: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
image_prompt_: 'Professional businesswoman CMO headshot'
}
}
]).meta({
@ -138,8 +138,8 @@ const TeamSlideLayout: React.FC<TeamSlideLayoutProps> = ({ data: slideData }) =>
{/* Member Photo */}
<div className="w-32 h-32 mx-auto rounded-lg overflow-hidden shadow-md">
<img
src={member.image.__image_url__ || ''}
alt={member.image.__image_prompt__ || member.name}
src={member.image.image_url_ || ''}
alt={member.image.image_prompt_ || member.name}
className="w-full h-full object-cover"
/>
</div>

View file

@ -71,8 +71,8 @@ const AboutCompanySlideLayout: React.FC<AboutCompanySlideLayoutProps> = ({
<div className="w-full h-96 overflow-hidden">
{slideData?.image ? (
<img
src={slideData.image.__image_url__}
alt={slideData.image.__image_prompt__}
src={slideData.image.image_url_}
alt={slideData.image.image_prompt_}
className="w-full h-full object-cover"
/>
) : (

View file

@ -43,9 +43,9 @@ const problemStatementSlideSchema = z.object({
description:
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
icon_url_:
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
icon_query_: "warning alert inefficiency",
},
},
{
@ -53,9 +53,9 @@ const problemStatementSlideSchema = z.object({
description:
"Outdated systems increase expenses, while small businesses struggle to expand their market reach.",
icon: {
__icon_url__:
icon_url_:
"/static/icons/placeholder.png",
__icon_query__: "trending up costs chart",
icon_query_: "trending up costs chart",
},
},
{
@ -63,9 +63,9 @@ const problemStatementSlideSchema = z.object({
description:
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
icon_url_:
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
icon_query_: "warning alert inefficiency",
},
},
{
@ -73,9 +73,9 @@ const problemStatementSlideSchema = z.object({
description:
"Businesses struggle to find digital tools that meet their needs, causing operational slowdowns.",
icon: {
__icon_url__:
icon_url_:
"/static/icons/placeholder.png",
__icon_query__: "warning alert inefficiency",
icon_query_: "warning alert inefficiency",
},
},
])
@ -150,10 +150,10 @@ const ProblemStatementSlideLayout: React.FC<
className="flex items-start gap-5 bg-white bg-opacity-5 rounded-lg p-5"
>
<div className="flex-shrink-0">
{category.icon?.__icon_url__ && (
{category.icon?.icon_url_ && (
<img
src={category.icon?.__icon_url__}
alt={category.icon?.__icon_query__}
src={category.icon?.icon_url_}
alt={category.icon?.icon_query_}
className="w-12 h-12"
style={{ filter: "invert(1)" }}
/>

View file

@ -49,8 +49,8 @@ const solutionSlideSchema = z.object({
description:
"Innovative and widely accepted. Innovative and widely accepted. Innovative and widely accepted.",
icon: {
__icon_query__: "market innovation",
__icon_url__:
icon_query_: "market innovation",
icon_url_:
"/static/icons/placeholder.png",
},
},
@ -58,8 +58,8 @@ const solutionSlideSchema = z.object({
title: "Industry",
description: "Based on sound market decisions.",
icon: {
__icon_query__: "industry building",
__icon_url__:
icon_query_: "industry building",
icon_url_:
"/static/icons/placeholder.png",
},
},
@ -67,8 +67,8 @@ const solutionSlideSchema = z.object({
title: "SEM",
description: "Driven by precise data and analysis.",
icon: {
__icon_query__: "SEM data analysis",
__icon_url__:
icon_query_: "SEM data analysis",
icon_url_:
"/static/icons/placeholder.png",
},
},
@ -76,8 +76,8 @@ const solutionSlideSchema = z.object({
title: "End User",
description: "Focused on real user impact.",
icon: {
__icon_query__: "end user impact",
__icon_url__:
icon_query_: "end user impact",
icon_url_:
"/static/icons/placeholder.png",
},
},
@ -140,10 +140,10 @@ const SolutionSlideLayout: React.FC<SolutionSlideLayoutProps> = ({
className="flex flex-col items-center text-center bg-[#F5F8FE] rounded-lg shadow px-3 py-4 "
>
<div className="mb-2">
{section?.icon?.__icon_url__ && (
{section?.icon?.icon_url_ && (
<img
src={section.icon.__icon_url__}
alt={section.icon.__icon_query__}
src={section.icon.icon_url_}
alt={section.icon.icon_query_}
className="w-12 h-12 mb-2"
/>
)}

View file

@ -52,9 +52,9 @@ const productOverviewSlideSchema = z.object({
description:
"Detail and explain each product. Our examination of community and market issues increases with additional products/services.",
image: {
__image_url__:
image_url_:
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=300&h=200&fit=crop",
__image_prompt__: "Person working on electronics with headphones",
image_prompt_: "Person working on electronics with headphones",
},
isBlueBackground: true,
},
@ -63,9 +63,9 @@ const productOverviewSlideSchema = z.object({
description:
"Our alternate product category is available. Our products must work together to solve social and economic issues.",
image: {
__image_url__:
image_url_:
"https://images.unsplash.com/photo-1573164713988-8665fc963095?w=300&h=200&fit=crop",
__image_prompt__:
image_prompt_:
"Woman working at computer with technical equipment",
},
isBlueBackground: true,
@ -163,9 +163,9 @@ const ProductOverviewSlideLayout: React.FC<ProductOverviewSlideLayoutProps> = ({
style={{ height: `${IMAGE_SECTION_HEIGHT + 28}px` }}
>
<img
src={products[0].image.__image_url__}
src={products[0].image.image_url_}
alt={
products[0].image.__image_prompt__ || products[0].title
products[0].image.image_prompt_ || products[0].title
}
className="w-full h-full object-cover"
/>
@ -189,9 +189,9 @@ const ProductOverviewSlideLayout: React.FC<ProductOverviewSlideLayoutProps> = ({
style={{ height: `${IMAGE_SECTION_HEIGHT + 28}px` }}
>
<img
src={products[1].image.__image_url__}
src={products[1].image.image_url_}
alt={
products[1].image.__image_prompt__ || products[1].title
products[1].image.image_prompt_ || products[1].title
}
className="w-full h-full object-cover"
/>

View file

@ -18,9 +18,9 @@ const marketSizeSlideSchema = z.object({
description: "Today Date displayed in header",
}),
mapImage: ImageSchema.default({
__image_url__:
image_url_:
"https://upload.wikimedia.org/wikipedia/commons/8/80/World_map_-_low_resolution.svg", // You can quickly find a world map image via a Google search or use a free resource like Wikimedia Commons
__image_prompt__: "World map with location pins or points",
image_prompt_: "World map with location pins or points",
}),
marketStats: z
.array(
@ -111,9 +111,9 @@ const MarketSizeSlideLayout: React.FC<MarketSizeSlideProps> = ({
{slideData?.title || "Market Size"}
</h1>
<div className="w-full bg-[#CBE3CC] rounded-md mb-8 flex items-center justify-center">
{slideData?.mapImage?.__image_url__ && (
{slideData?.mapImage?.image_url_ && (
<img
src={slideData?.mapImage?.__image_url__}
src={slideData?.mapImage?.image_url_}
alt="Market World Map with Points"
className="w-full object-contain rounded-md"
style={{ maxHeight: 220 }}

View file

@ -41,9 +41,9 @@ const modernTeamSlideSchema = z.object({
description:
"Strategic leader with 15+ years experience in technology and business development. Former VP at Fortune 500 company.",
image: {
__image_url__:
image_url_:
"https://plus.unsplash.com/premium_photo-1661589856899-6dd0871f9db6?fm=jpg&q=60&w=3000&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NXx8YnVzaW5lc3N3b21lbnxlbnwwfHwwfHx8MA%3D%3D",
__image_prompt__: "Professional businesswoman CEO headshot",
image_prompt_: "Professional businesswoman CEO headshot",
},
},
{
@ -52,9 +52,9 @@ const modernTeamSlideSchema = z.object({
description:
"Technology expert specializing in scalable architecture and AI solutions. PhD in Computer Science from MIT.",
image: {
__image_url__:
image_url_:
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional businessman CTO headshot",
image_prompt_: "Professional businessman CTO headshot",
},
},
{
@ -63,9 +63,9 @@ const modernTeamSlideSchema = z.object({
description:
"Sales leader with proven track record of building high-performing teams and driving revenue growth in B2B markets.",
image: {
__image_url__:
image_url_:
"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional businesswoman VP headshot",
image_prompt_: "Professional businesswoman VP headshot",
},
},
{
@ -74,9 +74,9 @@ const modernTeamSlideSchema = z.object({
description:
"Product strategist focused on user experience and market-driven solutions. Former product manager at leading tech companies.",
image: {
__image_url__:
image_url_:
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional businessman product manager headshot",
image_prompt_: "Professional businessman product manager headshot",
},
},
])
@ -145,10 +145,10 @@ const ModernTeamSlideLayout: React.FC<ModernTeamSlideLayoutProps> = ({
>
{/* Photo */}
<div className="relative w-28 h-28 mb-4 rounded overflow-hidden bg-white border-2 border-blue-100 flex items-center justify-center">
{member.image.__image_url__ && (
{member.image.image_url_ && (
<img
src={member.image.__image_url__}
alt={member.image.__image_prompt__ || member.name}
src={member.image.image_url_}
alt={member.image.image_prompt_ || member.name}
className="w-full h-full object-cover"
/>
)}

View file

@ -39,8 +39,8 @@ export const Schema = z.object({
}),
featuredImage: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Professional business team analyzing data and working collaboratively"
image_url_: "https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Professional business team analyzing data and working collaboratively"
}).meta({
description: "Primary visual that represents the organization's work or environment",
}),
@ -127,11 +127,11 @@ const AboutUsSlide = ({ data }: { data: Partial<SchemaType> }) => {
)}
{/* Business Image - Left positioned */}
{featuredImage?.__image_url__ && (
{featuredImage?.image_url_ && (
<div className="absolute right-36 top-1/2 -translate-y-1/2 h-[500px] w-[350px] z-20 shadow-lg">
<img
src={featuredImage.__image_url__}
alt={featuredImage.__image_prompt__}
src={featuredImage.image_url_}
alt={featuredImage.image_prompt_}
className="w-full h-full object-cover"
/>
</div>

View file

@ -33,8 +33,8 @@ export const Schema = z.object({
}),
headerVisual: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1559136555-9303baea8ebd?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Business strategy meeting with charts, graphs and team collaboration"
image_url_: "https://images.unsplash.com/photo-1559136555-9303baea8ebd?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Business strategy meeting with charts, graphs and team collaboration"
}).meta({
description: "Header visual representing the topic area - ADAPT the image prompt to match presentation topic (e.g., 'Climate scientists analyzing global warming data', 'Medical team reviewing patient care protocols', 'Teachers planning educational curriculum')",
}),
@ -92,11 +92,11 @@ const BusinessModelSlide = ({ data }: { data: Partial<SchemaType> }) => {
return (
<div className="aspect-video max-w-[1280px] w-full bg-white relative overflow-hidden">
{/* Header Image Section */}
{headerVisual?.__image_url__ && (
{headerVisual?.image_url_ && (
<div className="h-32 w-full relative">
<img
src={headerVisual.__image_url__}
alt={headerVisual.__image_prompt__}
src={headerVisual.image_url_}
alt={headerVisual.image_prompt_}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-black bg-opacity-40"></div>

View file

@ -46,8 +46,8 @@ export const Schema = z.object({
}),
visualRepresentation: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1597149962419-0d900ac2b46c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "World map showing global market reach and geographic distribution"
image_url_: "https://images.unsplash.com/photo-1597149962419-0d900ac2b46c?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "World map showing global market reach and geographic distribution"
}).meta({
description: "Visual that represents market scope - could be a world map, chart, or geographic visualization",
}),
@ -135,11 +135,11 @@ const MarketSizeSlide = ({ data }: { data: Partial<SchemaType> }) => {
)}
{/* Visual Representation */}
{visualRepresentation?.__image_url__ && (
{visualRepresentation?.image_url_ && (
<div className="absolute inset-8 shadow-lg">
<img
src={visualRepresentation.__image_url__}
alt={visualRepresentation.__image_prompt__}
src={visualRepresentation.image_url_}
alt={visualRepresentation.image_prompt_}
className="w-full h-full object-cover rounded-lg"
/>
</div>

View file

@ -32,8 +32,8 @@ export const Schema = z.object({
}),
serviceHighlight: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1556761175-b413da4baf72?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Professional service delivery or team working on client solutions"
image_url_: "https://images.unsplash.com/photo-1556761175-b413da4baf72?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Professional service delivery or team working on client solutions"
}).meta({
description: "Visual that represents service delivery, expertise, or client collaboration",
}),
@ -102,11 +102,11 @@ const OurServiceSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Right - Service Highlight */}
<div className="w-1/2 relative">
{/* Service Highlight Image */}
{serviceHighlight?.__image_url__ && (
{serviceHighlight?.image_url_ && (
<div className="h-full w-full">
<img
src={serviceHighlight.__image_url__}
alt={serviceHighlight.__image_prompt__}
src={serviceHighlight.image_url_}
alt={serviceHighlight.image_prompt_}
className="w-full h-full object-cover"
/>
</div>

View file

@ -46,8 +46,8 @@ export const Schema = z.object({
}),
supportingVisual: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Professional workspace showing analysis and problem-solving activities"
image_url_: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Professional workspace showing analysis and problem-solving activities"
}).meta({
description: "Visual that supports the problem discussion - could show analysis, challenges, or work environment",
}),
@ -129,11 +129,11 @@ const ProblemsSlide = ({ data }: { data: Partial<SchemaType> }) => {
)}
{/* Supporting Visual */}
{supportingVisual?.__image_url__ && (
{supportingVisual?.image_url_ && (
<div className="absolute top-8 right-8 bottom-20 left-4 shadow-lg">
<img
src={supportingVisual.__image_url__}
alt={supportingVisual.__image_prompt__}
src={supportingVisual.image_url_}
alt={supportingVisual.image_prompt_}
className="w-full h-full object-cover rounded-lg"
/>
</div>

View file

@ -46,15 +46,15 @@ export const Schema = z.object({
}),
primaryVisual: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1560472354-b33ff0c44a43?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Modern workspace with team collaboration and strategic planning"
image_url_: "https://images.unsplash.com/photo-1560472354-b33ff0c44a43?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Modern workspace with team collaboration and strategic planning"
}).meta({
description: "Primary visual representing teamwork, strategy, or solution implementation",
}),
brandingVisual: ImageSchema.default({
__image_url__: "https://via.placeholder.com/150x80/22C55E/FFFFFF?text=LOGO",
__image_prompt__: "Organization logo or brand mark"
image_url_: "https://via.placeholder.com/150x80/22C55E/FFFFFF?text=LOGO",
image_prompt_: "Organization logo or brand mark"
}).meta({
description: "Logo or branding element to maintain visual identity",
}),
@ -93,11 +93,11 @@ const SolutionsSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Left Side - Images and Branding */}
<div className="w-2/5 relative bg-gray-100 flex flex-col">
{/* Top Image Area */}
{primaryVisual?.__image_url__ && (
{primaryVisual?.image_url_ && (
<div className="flex-1 relative">
<img
src={primaryVisual.__image_url__}
alt={primaryVisual.__image_prompt__}
src={primaryVisual.image_url_}
alt={primaryVisual.image_prompt_}
className="w-full h-full object-cover"
/>
</div>
@ -105,10 +105,10 @@ const SolutionsSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Bottom Branding Area */}
<div className="h-24 bg-white flex items-center justify-center px-8">
{brandingVisual?.__image_url__ && (
{brandingVisual?.image_url_ && (
<img
src={brandingVisual.__image_url__}
alt={brandingVisual.__image_prompt__}
src={brandingVisual.image_url_}
alt={brandingVisual.image_prompt_}
className="h-12 object-contain"
/>
)}

View file

@ -29,8 +29,8 @@ export const Schema = z.object({
}),
brandLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
__image_prompt__: "Professional organization logo - clean and modern design"
image_url_: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
image_prompt_: "Professional organization logo - clean and modern design"
}).meta({
description: "Logo or brand mark representing the organization",
}),
@ -67,8 +67,8 @@ export const Schema = z.object({
}),
companyLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C",
__image_prompt__: "Clean modern company logo icon in white"
image_url_: "https://via.placeholder.com/40x40/FFFFFF/1D9A8A?text=C",
image_prompt_: "Clean modern company logo icon in white"
}).meta({
description: "Company logo icon",
}),
@ -128,11 +128,11 @@ const StatisticCircularSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Right - Company Branding */}
<div className="w-1/2 bg-teal-600 px-16 py-8 flex items-center justify-end">
<div className="flex items-center space-x-3">
{companyLogo?.__image_url__ && (
{companyLogo?.image_url_ && (
<div className="w-10 h-10">
<img
src={companyLogo.__image_url__}
alt={companyLogo.__image_prompt__}
src={companyLogo.image_url_}
alt={companyLogo.image_prompt_}
className="w-full h-full object-contain"
/>
</div>

View file

@ -24,8 +24,8 @@ export const Schema = z.object({
}),
brandLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
__image_prompt__: "Professional organization logo - clean and modern design"
image_url_: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
image_prompt_: "Professional organization logo - clean and modern design"
}).meta({
description: "Logo or brand mark representing the organization",
}),
@ -130,11 +130,11 @@ const StatisticDualChartSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Company Branding */}
<div className="flex items-center space-x-3">
{brandLogo?.__image_url__ && (
{brandLogo?.image_url_ && (
<div className="w-8 h-8">
<img
src={brandLogo.__image_url__}
alt={brandLogo.__image_prompt__}
src={brandLogo.image_url_}
alt={brandLogo.image_prompt_}
className="w-full h-full object-contain"
/>
</div>

View file

@ -40,8 +40,8 @@ export const Schema = z.object({
}),
supportingVisual: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Business analytics dashboard with charts and data visualization"
image_url_: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Business analytics dashboard with charts and data visualization"
}).meta({
description: "ADAPT the image prompt to match the presentation topic: For global warming: 'Climate monitoring station with temperature sensors and weather equipment', 'Scientists analyzing ice core data in Arctic research facility'. For healthcare: 'Medical monitoring equipment displaying patient vital signs', 'Healthcare analytics dashboard showing treatment outcomes'. For education: 'Educational assessment data on computer screens', 'Students using digital learning platforms'.",
}),
@ -148,12 +148,12 @@ const StatisticSlide = ({ data }: { data: Partial<SchemaType> }) => {
</div>
{/* Business Image */}
{supportingVisual?.__image_url__ && (
{supportingVisual?.image_url_ && (
<div className="flex-1 flex items-end">
<div className="w-full h-48">
<img
src={supportingVisual.__image_url__}
alt={supportingVisual.__image_prompt__}
src={supportingVisual.image_url_}
alt={supportingVisual.image_prompt_}
className="w-full h-full object-cover rounded-lg"
/>
</div>

View file

@ -61,8 +61,8 @@ export const Schema = z.object({
}),
brandingVisual: ImageSchema.default({
__image_url__: "https://via.placeholder.com/200x100/22C55E/FFFFFF?text=BRAND",
__image_prompt__: "Organization logo or brand visual element"
image_url_: "https://via.placeholder.com/200x100/22C55E/FFFFFF?text=BRAND",
image_prompt_: "Organization logo or brand visual element"
}).meta({
description: "Logo or branding element displayed prominently for visual identity",
}),
@ -146,11 +146,11 @@ const TableOfContentsSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Right Side - Branding and Visual Elements */}
<div className="w-2/5 relative bg-gray-50 flex items-center justify-center">
{/* Branding Visual */}
{brandingVisual?.__image_url__ && (
{brandingVisual?.image_url_ && (
<div className="text-center">
<img
src={brandingVisual.__image_url__}
alt={brandingVisual.__image_prompt__}
src={brandingVisual.image_url_}
alt={brandingVisual.image_prompt_}
className="max-w-64 max-h-32 object-contain mx-auto"
/>
</div>

View file

@ -22,8 +22,8 @@ export const Schema = z.object({
}),
brandLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
__image_prompt__: "Professional organization logo - clean and modern design"
image_url_: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
image_prompt_: "Professional organization logo - clean and modern design"
}).meta({
description: "Logo or brand mark representing the organization",
}),
@ -43,8 +43,8 @@ export const Schema = z.object({
testimonialText: "Working with this team has been transformative for our business. Their expertise, dedication, and innovative approach exceeded our expectations and delivered remarkable results.",
rating: 5,
clientPhoto: {
__image_url__: "https://images.unsplash.com/photo-1494790108755-2616b612b830?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional businesswoman headshot"
image_url_: "https://images.unsplash.com/photo-1494790108755-2616b612b830?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
image_prompt_: "Professional businesswoman headshot"
}
},
{
@ -54,8 +54,8 @@ export const Schema = z.object({
testimonialText: "The level of professionalism and quality of service provided was outstanding. They understood our needs perfectly and delivered solutions that truly made a difference.",
rating: 5,
clientPhoto: {
__image_url__: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional businessman headshot"
image_url_: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
image_prompt_: "Professional businessman headshot"
}
},
{
@ -65,8 +65,8 @@ export const Schema = z.object({
testimonialText: "Exceptional service and results that spoke for themselves. The team's attention to detail and commitment to excellence made our collaboration highly successful.",
rating: 5,
clientPhoto: {
__image_url__: "https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
__image_prompt__: "Professional woman headshot"
image_url_: "https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80",
image_prompt_: "Professional woman headshot"
}
}
]).meta({
@ -121,11 +121,11 @@ const TestimonialSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Company Branding */}
<div className="flex items-center space-x-3">
{brandLogo?.__image_url__ && (
{brandLogo?.image_url_ && (
<div className="w-8 h-8">
<img
src={brandLogo.__image_url__}
alt={brandLogo.__image_prompt__}
src={brandLogo.image_url_}
alt={brandLogo.image_prompt_}
className="w-full h-full object-contain"
/>
</div>
@ -164,11 +164,11 @@ const TestimonialSlide = ({ data }: { data: Partial<SchemaType> }) => {
{/* Client Info */}
<div className="flex items-center space-x-4">
{/* Client Photo */}
{showClientPhotos && item.clientPhoto?.__image_url__ && (
{showClientPhotos && item.clientPhoto?.image_url_ && (
<div className="w-12 h-12 rounded-full overflow-hidden flex-shrink-0">
<img
src={item.clientPhoto.__image_url__}
alt={item.clientPhoto.__image_prompt__}
src={item.clientPhoto.image_url_}
alt={item.clientPhoto.image_prompt_}
className="w-full h-full object-cover"
/>
</div>

View file

@ -30,8 +30,8 @@ export const Schema = z.object({
}),
brandLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
__image_prompt__: "Professional organization logo - clean and modern design"
image_url_: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
image_prompt_: "Professional organization logo - clean and modern design"
}).meta({
description: "Logo or brand mark representing the presenting organization",
}),
@ -89,11 +89,11 @@ const ThankYouSlide = ({ data }: { data: Partial<SchemaType> }) => {
<div className="absolute top-0 left-0 right-0 px-16 py-8 flex justify-between items-center z-20">
{/* Company Logo and Name */}
<div className="flex items-center space-x-3">
{brandLogo?.__image_url__ && (
{brandLogo?.image_url_ && (
<div className="w-10 h-10">
<img
src={brandLogo.__image_url__}
alt={brandLogo.__image_prompt__}
src={brandLogo.image_url_}
alt={brandLogo.image_prompt_}
className="w-full h-full object-contain"
/>
</div>

View file

@ -30,8 +30,8 @@ export const Schema = z.object({
}),
brandLogo: ImageSchema.default({
__image_url__: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
__image_prompt__: "Professional organization logo - clean and modern design"
image_url_: "https://via.placeholder.com/40x40/22C55E/FFFFFF?text=L",
image_prompt_: "Professional organization logo - clean and modern design"
}).meta({
description: "Logo or brand mark representing the presenting organization",
}),
@ -84,11 +84,11 @@ const ThynkTitleSlide = ({ data }: { data: Partial<SchemaType> }) => {
<div className="absolute top-0 left-0 right-0 px-16 py-8 flex justify-between items-center z-20">
{/* Company Logo and Name */}
<div className="flex items-center space-x-3">
{brandLogo?.__image_url__ && (
{brandLogo?.image_url_ && (
<div className="w-10 h-10">
<img
src={brandLogo.__image_url__}
alt={brandLogo.__image_prompt__}
src={brandLogo.image_url_}
alt={brandLogo.image_prompt_}
className="w-full h-full object-contain"
/>
</div>

View file

@ -40,8 +40,8 @@ export const Schema = z.object({
}),
supportingVisual: ImageSchema.default({
__image_url__: "https://images.unsplash.com/photo-1522202176988-66273c2fd55f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
__image_prompt__: "Diverse team collaborating and planning together in modern workspace"
image_url_: "https://images.unsplash.com/photo-1522202176988-66273c2fd55f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80",
image_prompt_: "Diverse team collaborating and planning together in modern workspace"
}).meta({
description: "Visual that represents collaboration, vision, or organizational culture",
}),
@ -73,11 +73,11 @@ const WhatWeBelieveSlide = ({ data }: { data: Partial<SchemaType> }) => {
<div className="h-full flex">
{/* Left Side - Image */}
<div className="w-2/5 relative">
{supportingVisual?.__image_url__ && (
{supportingVisual?.image_url_ && (
<div className="absolute inset-8 shadow-lg">
<img
src={supportingVisual.__image_url__}
alt={supportingVisual.__image_prompt__}
src={supportingVisual.image_url_}
alt={supportingVisual.image_prompt_}
className="w-full h-full object-cover rounded-lg"
/>
</div>

View file

@ -260,8 +260,8 @@ const presentationGenerationSlice = createSlice({
// Preserve existing properties if the target already exists
const updatedValue = {
...(target && typeof target === 'object' ? target : {}),
__image_url__: url,
__image_prompt__: promptText || (target?.__image_prompt__) || ''
image_url_: url,
image_prompt_: promptText || (target?.image_prompt_) || ''
};
if (isNaN(Number(finalKey))) {
@ -359,8 +359,8 @@ const presentationGenerationSlice = createSlice({
// Preserve existing properties if the target already exists
const updatedValue = {
...(target && typeof target === 'object' ? target : {}),
__icon_url__: url,
__icon_query__: queryText || (target?.__icon_query__) || ''
icon_url_: url,
icon_query_: queryText || (target?.icon_query_) || ''
};
if (isNaN(Number(finalKey))) {