chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:08:41 +08:00
commit bcc7968ff6
9988 changed files with 1016778 additions and 0 deletions
View File
+13
View File
@@ -0,0 +1,13 @@
from fastapi import HTTPException
from pydantic import BaseModel
class APIErrorModel(BaseModel):
status_code: int
detail: str
@classmethod
def from_exception(cls, e: Exception) -> "APIErrorModel":
if isinstance(e, HTTPException):
return APIErrorModel(status_code=e.status_code, detail=e.detail)
return APIErrorModel(status_code=500, detail=str(e))
+53
View File
@@ -0,0 +1,53 @@
import uuid
from typing import Literal, Optional
from pydantic import BaseModel, ConfigDict, Field
class ChatAttachment(BaseModel):
type: Literal["document"] = "document"
name: str = Field(min_length=1, max_length=255)
file_path: str = Field(min_length=1, max_length=4000)
mime_type: Optional[str] = Field(default=None, max_length=255)
model_config = ConfigDict(extra="forbid")
class ChatMessageRequest(BaseModel):
presentation_id: uuid.UUID
message: str = Field(min_length=1, max_length=8000)
conversation_id: Optional[uuid.UUID] = None
attachments: list[ChatAttachment] = Field(default_factory=list, max_length=8)
model_config = ConfigDict(extra="forbid")
class ChatMessageResponse(BaseModel):
conversation_id: uuid.UUID
response: str
tool_calls: list[str] = Field(default_factory=list)
model_config = ConfigDict(extra="forbid")
class ChatHistoryMessageItem(BaseModel):
role: str
content: str
created_at: Optional[str] = None
model_config = ConfigDict(extra="forbid")
class ChatHistoryResponse(BaseModel):
presentation_id: uuid.UUID
conversation_id: uuid.UUID
messages: list[ChatHistoryMessageItem]
model_config = ConfigDict(extra="forbid")
class ChatConversationListItem(BaseModel):
conversation_id: uuid.UUID
updated_at: Optional[str] = None
last_message_preview: Optional[str] = None
model_config = ConfigDict(extra="forbid")
@@ -0,0 +1,6 @@
from pydantic import BaseModel
class DecomposedFileInfo(BaseModel):
name: str
file_path: str
+13
View File
@@ -0,0 +1,13 @@
from pydantic import BaseModel
from models.presentation_outline_model import SlideOutlineModel
class DocumentChunk(BaseModel):
heading: str
content: str
heading_index: int
score: float
def to_slide_outline(self) -> SlideOutlineModel:
return SlideOutlineModel(content=f"{self.heading}\n{self.content}")
@@ -0,0 +1,46 @@
from typing import List, Literal, Optional
from pydantic import BaseModel, Field
from enums.tone import Tone
from enums.verbosity import Verbosity
class GeneratePresentationRequest(BaseModel):
content: str = Field(..., description="The content for generating the presentation")
slides_markdown: Optional[List[str]] = Field(
default=None, description="The markdown for the slides"
)
instructions: Optional[str] = Field(
default=None, description="The instruction for generating the presentation"
)
tone: Tone = Field(default=Tone.DEFAULT, description="The tone to use for the text")
verbosity: Verbosity = Field(
default=Verbosity.STANDARD, description="How verbose the presentation should be"
)
web_search: bool = Field(default=False, description="Whether to enable web search")
n_slides: Optional[int] = Field(
default=None,
description="Number of slides to generate. If omitted, model auto-detects slide count.",
)
language: Optional[str] = Field(
default=None,
description="Language for the presentation. If omitted, model auto-detects language.",
)
template: str = Field(
default="general", description="Template to use for the presentation"
)
include_table_of_contents: bool = Field(
default=False, description="Whether to include a table of contents"
)
include_title_slide: bool = Field(
default=True, description="Whether to include a title slide"
)
files: Optional[List[str]] = Field(
default=None, description="Files to use for the presentation"
)
export_as: Literal["pptx", "pdf"] = Field(
default="pptx", description="Export format"
)
trigger_webhook: bool = Field(
default=False, description="Whether to trigger subscribed webhooks"
)
+10
View File
@@ -0,0 +1,10 @@
from typing import Optional
from pydantic import BaseModel
class ImagePrompt(BaseModel):
prompt: str
theme_prompt: Optional[str] = None
def get_image_prompt(self, with_theme: bool = False) -> str:
return f"{self.prompt}, {self.theme_prompt}" if with_theme else self.prompt
+14
View File
@@ -0,0 +1,14 @@
from typing import List
from pydantic import BaseModel
class DictGuide(BaseModel):
key: str
class ListGuide(BaseModel):
index: int
class JsonPathGuide(BaseModel):
guides: List[DictGuide | ListGuide]
@@ -0,0 +1,8 @@
from pydantic import BaseModel
class OllamaModelMetadata(BaseModel):
label: str
value: str
size: str
tested: bool = True
@@ -0,0 +1,12 @@
from typing import Optional
from pydantic import BaseModel
class OllamaModelStatus(BaseModel):
name: str
parameters: Optional[str] = None
size: Optional[int] = None
downloaded: Optional[int] = None
status: str
done: bool
error: Optional[str] = None
@@ -0,0 +1,11 @@
from pydantic import BaseModel
import uuid
class PresentationAndPath(BaseModel):
presentation_id: uuid.UUID
path: str
class PresentationPathAndEditPath(PresentationAndPath):
edit_path: str
@@ -0,0 +1,14 @@
from typing import List, Literal
from pydantic import BaseModel
import uuid
class SlideContentUpdate(BaseModel):
index: int
content: dict
class EditPresentationRequest(BaseModel):
presentation_id: uuid.UUID
slides: List[SlideContentUpdate]
export_as: Literal["pptx", "pdf"] = "pptx"
@@ -0,0 +1,5 @@
"""Re-export layout models defined in `templates.presentation_layout`."""
from templates.presentation_layout import PresentationLayoutModel, SlideLayoutModel
__all__ = ["PresentationLayoutModel", "SlideLayoutModel"]
@@ -0,0 +1,31 @@
from typing import List
from pydantic import BaseModel, Field, field_validator
from constants.presentation import MAX_NUMBER_OF_SLIDES, MAX_OUTLINE_CONTENT_WORDS
from utils.outline_limits import normalize_outline_content
class SlideOutlineModel(BaseModel):
content: str = Field(
...,
description=f"Markdown content for the slide. Maximum {MAX_OUTLINE_CONTENT_WORDS} words.",
)
@field_validator("content", mode="before")
@classmethod
def limit_content_words(cls, value):
return normalize_outline_content(value)
class PresentationOutlineModel(BaseModel):
slides: List[SlideOutlineModel] = Field(
description="List of slide outlines",
max_length=MAX_NUMBER_OF_SLIDES,
)
def to_string(self):
message = ""
for i, slide in enumerate(self.slides):
message += f"## Slide {i+1}:\n"
message += f" - Content: {slide} \n"
return message
@@ -0,0 +1,6 @@
from typing import List
from pydantic import BaseModel, Field
class PresentationStructureModel(BaseModel):
slides: List[int] = Field(description="List of slide layout indexes")
@@ -0,0 +1,29 @@
from typing import Any, List, Optional
from datetime import datetime
import uuid
from pydantic import BaseModel
from models.sql.slide import SlideModel
class PresentationWithSlides(BaseModel):
id: uuid.UUID
version: Optional[str] = None
content: str
n_slides: int
language: str
title: Optional[str] = None
created_at: datetime
updated_at: datetime
tone: Optional[str] = None
verbosity: Optional[str] = None
slides: List[SlideModel]
layout: Optional[dict] = None
structure: Optional[dict] = None
theme: Optional[dict] = None
fonts: Optional[Any] = None
class PresentationDetailWithSlides(PresentationWithSlides):
merged_components: Optional[Any] = None
@@ -0,0 +1,5 @@
from pydantic import BaseModel
class SlideLayoutIndex(BaseModel):
index: int
@@ -0,0 +1,22 @@
from datetime import datetime
import secrets
from typing import Optional
import uuid
from sqlalchemy import JSON, Column
from sqlmodel import Field, SQLModel
class AsyncPresentationGenerationTaskModel(SQLModel, table=True):
__tablename__ = "async_presentation_generation_tasks"
id: str = Field(
default_factory=lambda: f"task-{secrets.token_hex(32)}", primary_key=True
)
status: str
message: Optional[str] = None
error: Optional[dict] = Field(sa_column=Column(JSON), default=None)
created_at: datetime = Field(default_factory=datetime.now)
updated_at: datetime = Field(default_factory=datetime.now)
data: Optional[dict] = Field(sa_column=Column(JSON), default=None)
+37
View File
@@ -0,0 +1,37 @@
from datetime import datetime
import secrets
from typing import Any, Optional
from sqlalchemy import JSON, Column, DateTime
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class AsyncTaskModel(SQLModel, table=True):
__tablename__ = "async_tasks"
id: str = Field(
default_factory=lambda: f"task-{secrets.token_hex(32)}",
primary_key=True,
)
type: str = Field(index=True)
status: str = Field(index=True)
message: Optional[str] = None
error: Optional[dict[str, Any]] = Field(sa_column=Column(JSON), default=None)
data: Optional[dict[str, Any]] = Field(sa_column=Column(JSON), default=None)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True),
nullable=False,
default=get_current_utc_datetime,
)
)
updated_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True),
nullable=False,
default=get_current_utc_datetime,
onupdate=get_current_utc_datetime,
)
)
@@ -0,0 +1,41 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlalchemy import JSON, Column, DateTime, ForeignKey, String, Text
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class ChatHistoryMessageModel(SQLModel, table=True):
__tablename__ = "chat_history_messages"
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
presentation_id: Optional[uuid.UUID] = Field(
default=None,
sa_column=Column(
ForeignKey("presentations.id", ondelete="CASCADE"),
index=True,
nullable=True,
)
)
template_v2_id: Optional[str] = Field(
default=None,
sa_column=Column(
String,
ForeignKey("template_v2.id", ondelete="CASCADE"),
index=True,
nullable=True,
)
)
conversation_id: uuid.UUID = Field(index=True)
position: int = Field(index=True, ge=1)
role: str
content: str = Field(sa_column=Column(Text, nullable=False))
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
)
)
tool_calls: Optional[list[str]] = Field(sa_column=Column(JSON), default=None)
+31
View File
@@ -0,0 +1,31 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlalchemy import JSON, Column, DateTime, Integer, String
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class FontUpload(SQLModel, table=True):
__tablename__ = "font_uploads"
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
),
)
filename: str
path: str
normalized_family_name: str = Field(index=True)
family_name: Optional[str] = Field(sa_column=Column(String), default=None)
subfamily_name: Optional[str] = Field(sa_column=Column(String), default=None)
full_name: Optional[str] = Field(sa_column=Column(String), default=None)
postscript_name: Optional[str] = Field(sa_column=Column(String), default=None)
weight_class: Optional[int] = Field(sa_column=Column(Integer), default=None)
width_class: Optional[int] = Field(sa_column=Column(Integer), default=None)
format: Optional[str] = Field(sa_column=Column(String), default=None)
size_bytes: int
extras: Optional[dict] = Field(sa_column=Column(JSON), default=None)
+20
View File
@@ -0,0 +1,20 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlalchemy import JSON, Column, DateTime
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class ImageAsset(SQLModel, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
),
)
is_uploaded: bool = Field(default=False)
path: str
extras: Optional[dict] = Field(sa_column=Column(JSON), default=None)
+8
View File
@@ -0,0 +1,8 @@
import uuid
from sqlmodel import Field, Column, JSON, SQLModel
class KeyValueSqlModel(SQLModel, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
key: str = Field(index=True)
value: dict = Field(sa_column=Column(JSON))
@@ -0,0 +1,9 @@
from datetime import datetime
import uuid
from sqlmodel import Field, Column, JSON, SQLModel, DateTime
class OllamaPullStatus(SQLModel, table=True):
id: str = Field(primary_key=True)
last_updated: datetime = Field(sa_column=Column(DateTime, default=datetime.now))
status: dict = Field(sa_column=Column(JSON))
+105
View File
@@ -0,0 +1,105 @@
from datetime import datetime
from enum import Enum
from typing import List, Optional
import uuid
import copy
from sqlalchemy import JSON, Column, DateTime, Enum as SAEnum, String
from sqlmodel import Boolean, Field, SQLModel
from models.presentation_outline_model import PresentationOutlineModel
from models.presentation_structure_model import PresentationStructureModel
from models.presentation_layout import PresentationLayoutModel
from utils.datetime_utils import get_current_utc_datetime
class PresentationVersion(str, Enum):
V1_STANDARD = "v1-standard"
V2_STANDARD = "v2-standard"
class PresentationModel(SQLModel, table=True):
__tablename__ = "presentations"
id: uuid.UUID = Field(primary_key=True, default_factory=uuid.uuid4)
version: PresentationVersion = Field(
sa_column=Column(
SAEnum(
PresentationVersion,
values_callable=lambda enum: [item.value for item in enum],
name="presentation_version",
native_enum=False,
create_constraint=True,
),
nullable=False,
),
)
content: str
n_slides: int
language: str
title: Optional[str] = None
file_paths: Optional[List[str]] = Field(sa_column=Column(JSON), default=None)
outlines: Optional[dict] = Field(sa_column=Column(JSON), default=None)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
),
)
updated_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True),
nullable=False,
default=get_current_utc_datetime,
onupdate=get_current_utc_datetime,
),
)
layout: Optional[dict] = Field(sa_column=Column(JSON), default=None)
structure: Optional[dict] = Field(sa_column=Column(JSON), default=None)
instructions: Optional[str] = Field(sa_column=Column(String), default=None)
tone: Optional[str] = Field(sa_column=Column(String), default=None)
verbosity: Optional[str] = Field(sa_column=Column(String), default=None)
include_table_of_contents: bool = Field(sa_column=Column(Boolean), default=False)
include_title_slide: bool = Field(sa_column=Column(Boolean), default=True)
web_search: bool = Field(sa_column=Column(Boolean), default=False)
theme: Optional[dict] = Field(sa_column=Column(JSON), default=None)
fonts: Optional[dict] = Field(sa_column=Column(JSON), default=None)
def get_new_presentation(self):
return PresentationModel(
id=uuid.uuid4(),
version=self.version,
content=self.content,
n_slides=self.n_slides,
language=self.language,
title=self.title,
file_paths=copy.deepcopy(self.file_paths),
outlines=copy.deepcopy(self.outlines),
layout=copy.deepcopy(self.layout),
structure=copy.deepcopy(self.structure),
instructions=self.instructions,
tone=self.tone,
verbosity=self.verbosity,
include_table_of_contents=self.include_table_of_contents,
include_title_slide=self.include_title_slide,
web_search=self.web_search,
theme=copy.deepcopy(self.theme),
fonts=copy.deepcopy(self.fonts),
)
def get_presentation_outline(self):
if not self.outlines:
return None
return PresentationOutlineModel(**self.outlines)
def get_layout(self):
return PresentationLayoutModel(**self.layout)
def set_layout(self, layout: PresentationLayoutModel):
self.layout = layout.model_dump()
def get_structure(self):
if not self.structure:
return None
return PresentationStructureModel(**self.structure)
def set_structure(self, structure: PresentationStructureModel):
self.structure = structure.model_dump()
@@ -0,0 +1,38 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlalchemy import JSON, Column, DateTime, Text
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class PresentationLayoutCodeModel(SQLModel, table=True):
__tablename__ = "presentation_layout_codes"
id: Optional[int] = Field(default=None, primary_key=True)
presentation: uuid.UUID = Field(index=True, description="UUID of the presentation")
layout_id: str = Field(description="Unique identifier for the layout")
layout_name: str = Field(description="Display name of the layout")
layout_code: str = Field(
sa_column=Column(Text), description="TSX/React component code for the layout"
)
fonts: Optional[dict[str, str] | list[str]] = Field(
default=None,
sa_column=Column(JSON, nullable=True),
description="Optional font metadata associated with the layout",
)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
)
)
updated_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True),
nullable=False,
default=get_current_utc_datetime,
onupdate=get_current_utc_datetime,
),
)
+36
View File
@@ -0,0 +1,36 @@
from typing import Optional
import uuid
import copy
from sqlalchemy import ForeignKey
from sqlmodel import Field, Column, JSON, SQLModel
class SlideModel(SQLModel, table=True):
__tablename__ = "slides"
id: uuid.UUID = Field(primary_key=True, default_factory=uuid.uuid4)
presentation: uuid.UUID = Field(
sa_column=Column(ForeignKey("presentations.id", ondelete="CASCADE"), index=True)
)
layout_group: str
layout: str
index: int
content: dict = Field(sa_column=Column(JSON))
html_content: Optional[str] = None
speaker_note: Optional[str] = None
properties: Optional[dict] = Field(sa_column=Column(JSON))
ui: Optional[dict] = Field(default=None, sa_column=Column(JSON, nullable=True))
def get_new_slide(self, presentation: uuid.UUID, content: Optional[dict] = None):
return SlideModel(
id=uuid.uuid4(),
presentation=presentation,
layout_group=self.layout_group,
layout=self.layout,
index=self.index,
speaker_note=self.speaker_note,
content=copy.deepcopy(content or self.content),
html_content=self.html_content,
properties=copy.deepcopy(self.properties),
ui=copy.deepcopy(self.ui),
)
+27
View File
@@ -0,0 +1,27 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlalchemy import Column, DateTime
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class TemplateModel(SQLModel, table=True):
__tablename__ = "templates"
id: uuid.UUID = Field(
default_factory=uuid.uuid4,
primary_key=True,
description="UUID for the template (matches presentation_id)",
)
name: str = Field(description="Human friendly template name")
description: Optional[str] = Field(
default=None, description="Optional template description"
)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
),
)
@@ -0,0 +1,25 @@
from datetime import datetime
import uuid
from sqlalchemy import JSON, Column, DateTime
from sqlmodel import Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class TemplateCreateInfoModel(SQLModel, table=True):
__tablename__ = "template_create_infos"
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
fonts: dict[str, str] | None = Field(
default=None,
sa_column=Column(JSON, nullable=True),
)
pptx_url: str | None = Field(default=None)
slide_htmls: list[str] = Field(sa_column=Column(JSON, nullable=False))
slide_image_urls: list[str] = Field(sa_column=Column(JSON, nullable=False))
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
)
)
+49
View File
@@ -0,0 +1,49 @@
from datetime import datetime
from typing import Optional
import uuid
from sqlmodel import Field, SQLModel
from sqlalchemy import JSON, Column, DateTime
from utils.datetime_utils import get_current_utc_datetime
def _new_template_v2_id() -> str:
return str(uuid.uuid4())
class TemplateV2(SQLModel, table=True):
__tablename__ = "template_v2"
id: str = Field(primary_key=True, default_factory=_new_template_v2_id)
name: str = Field(nullable=False)
description: Optional[str] = Field(default=None, nullable=True)
raw_layouts: Optional[dict] = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
components: Optional[dict] = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
merged_components: Optional[dict] = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
layouts: Optional[dict] = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
assets: Optional[dict] = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
is_default: bool = Field(default=False, nullable=False)
created_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True), nullable=False, default=get_current_utc_datetime
)
)
updated_at: datetime = Field(
sa_column=Column(
DateTime(timezone=True),
nullable=False,
default=get_current_utc_datetime,
onupdate=get_current_utc_datetime,
)
)
@@ -0,0 +1,22 @@
import secrets
from typing import Optional
import uuid
from datetime import datetime
from sqlmodel import Column, DateTime, Field, SQLModel
from utils.datetime_utils import get_current_utc_datetime
class WebhookSubscription(SQLModel, table=True):
__tablename__ = "webhook_subscriptions"
id: str = Field(
default_factory=lambda: f"webhook-{secrets.token_hex(32)}", primary_key=True
)
created_at: datetime = Field(
sa_column=Column(DateTime(timezone=True), nullable=False),
default_factory=get_current_utc_datetime,
)
url: str
secret: Optional[str] = None
event: str = Field(index=True)
+49
View File
@@ -0,0 +1,49 @@
import json
from pydantic import BaseModel
class SSEResponse(BaseModel):
event: str
data: str
def to_string(self):
return f"event: {self.event}\ndata: {self.data}\n\n"
class SSEStatusResponse(BaseModel):
status: str
def to_string(self):
return SSEResponse(
event="response", data=json.dumps({"type": "status", "status": self.status})
).to_string()
class SSETraceResponse(BaseModel):
trace: object
def to_string(self):
return SSEResponse(
event="response", data=json.dumps({"type": "trace", "trace": self.trace})
).to_string()
class SSEErrorResponse(BaseModel):
detail: str
def to_string(self):
return SSEResponse(
event="response", data=json.dumps({"type": "error", "detail": self.detail})
).to_string()
class SSECompleteResponse(BaseModel):
key: str
value: object
def to_string(self):
return SSEResponse(
event="response",
data=json.dumps({"type": "complete", self.key: self.value}),
).to_string()
+41
View File
@@ -0,0 +1,41 @@
from pydantic import BaseModel
from typing import Dict
class ThemeData(BaseModel):
primary: str
background: str
card: str
stroke: str
background_text: str
primary_text: str
graph_0: str
graph_1: str
graph_2: str
graph_3: str
graph_4: str
graph_5: str
graph_6: str
graph_7: str
graph_8: str
graph_9: str
class GeneratedColorPalette(BaseModel):
primary: str
background: str
accent_1: str
accent_2: str
text_1: str
text_2: str
primary_variations: Dict[str, str]
background_variations: Dict[str, str]
accent_1_variations: Dict[str, str]
accent_2_variations: Dict[str, str]
primary_lightness: float
background_lightness: float
accent_1_lightness: float
accent_2_lightness: float
text_1_lightness: float
text_2_lightness: float
+134
View File
@@ -0,0 +1,134 @@
from typing import Optional
from pydantic import BaseModel
class UserConfig(BaseModel):
LLM: Optional[str] = None
# OpenAI
OPENAI_API_KEY: Optional[str] = None
OPENAI_MODEL: Optional[str] = None
# Google
GOOGLE_API_KEY: Optional[str] = None
GOOGLE_MODEL: Optional[str] = None
# Vertex AI
VERTEX_API_KEY: Optional[str] = None
VERTEX_MODEL: Optional[str] = None
VERTEX_PROJECT: Optional[str] = None
VERTEX_LOCATION: Optional[str] = None
VERTEX_BASE_URL: Optional[str] = None
# Azure OpenAI
AZURE_OPENAI_API_KEY: Optional[str] = None
AZURE_OPENAI_MODEL: Optional[str] = None
AZURE_OPENAI_ENDPOINT: Optional[str] = None
AZURE_OPENAI_BASE_URL: Optional[str] = None
AZURE_OPENAI_API_VERSION: Optional[str] = None
AZURE_OPENAI_DEPLOYMENT: Optional[str] = None
# Amazon Bedrock
BEDROCK_REGION: Optional[str] = None
BEDROCK_API_KEY: Optional[str] = None
BEDROCK_AWS_ACCESS_KEY_ID: Optional[str] = None
BEDROCK_AWS_SECRET_ACCESS_KEY: Optional[str] = None
BEDROCK_AWS_SESSION_TOKEN: Optional[str] = None
BEDROCK_PROFILE_NAME: Optional[str] = None
BEDROCK_MODEL: Optional[str] = None
# OpenRouter
OPENROUTER_API_KEY: Optional[str] = None
OPENROUTER_MODEL: Optional[str] = None
OPENROUTER_BASE_URL: Optional[str] = None
# Fireworks
FIREWORKS_API_KEY: Optional[str] = None
FIREWORKS_MODEL: Optional[str] = None
FIREWORKS_BASE_URL: Optional[str] = None
# Together AI
TOGETHER_API_KEY: Optional[str] = None
TOGETHER_MODEL: Optional[str] = None
TOGETHER_BASE_URL: Optional[str] = None
# Cerebras
CEREBRAS_API_KEY: Optional[str] = None
CEREBRAS_MODEL: Optional[str] = None
CEREBRAS_BASE_URL: Optional[str] = None
# LiteLLM (OpenAI-compatible gateway / proxy)
LITELLM_BASE_URL: Optional[str] = None
LITELLM_API_KEY: Optional[str] = None
LITELLM_MODEL: Optional[str] = None
# LM Studio (local OpenAI-compatible server)
LMSTUDIO_BASE_URL: Optional[str] = None
LMSTUDIO_API_KEY: Optional[str] = None
LMSTUDIO_MODEL: Optional[str] = None
# Anthropic
ANTHROPIC_API_KEY: Optional[str] = None
ANTHROPIC_MODEL: Optional[str] = None
# Ollama
OLLAMA_URL: Optional[str] = None
OLLAMA_MODEL: Optional[str] = None
# Custom LLM
CUSTOM_LLM_URL: Optional[str] = None
CUSTOM_LLM_API_KEY: Optional[str] = None
CUSTOM_MODEL: Optional[str] = None
# DeepSeek
DEEPSEEK_BASE_URL: Optional[str] = None
DEEPSEEK_API_KEY: Optional[str] = None
DEEPSEEK_MODEL: Optional[str] = None
# Image Provider
DISABLE_IMAGE_GENERATION: Optional[bool] = None
IMAGE_PROVIDER: Optional[str] = None
PEXELS_API_KEY: Optional[str] = None
PIXABAY_API_KEY: Optional[str] = None
# ComfyUI
COMFYUI_URL: Optional[str] = None
COMFYUI_WORKFLOW: Optional[str] = None
# Open WebUI Image Provider
OPEN_WEBUI_IMAGE_URL: Optional[str] = None
OPEN_WEBUI_IMAGE_API_KEY: Optional[str] = None
# OpenAI Compatible Image Provider
OPENAI_COMPAT_IMAGE_BASE_URL: Optional[str] = None
OPENAI_COMPAT_IMAGE_API_KEY: Optional[str] = None
OPENAI_COMPAT_IMAGE_MODEL: Optional[str] = None
# Dalle 3 Quality
DALL_E_3_QUALITY: Optional[str] = None
# Gpt Image 1.5 Quality
GPT_IMAGE_1_5_QUALITY: Optional[str] = None
# Reasoning
DISABLE_THINKING: Optional[bool] = None
EXTENDED_REASONING: Optional[bool] = None
# Web Search
WEB_GROUNDING: Optional[bool] = None
WEB_SEARCH_PROVIDER: Optional[str] = None
WEB_SEARCH_MAX_RESULTS: Optional[str] = None
SEARXNG_BASE_URL: Optional[str] = None
TAVILY_API_KEY: Optional[str] = None
EXA_API_KEY: Optional[str] = None
BRAVE_SEARCH_API_KEY: Optional[str] = None
SERPER_API_KEY: Optional[str] = None
# Codex OAuth (ChatGPT)
CODEX_MODEL: Optional[str] = None
CODEX_ACCESS_TOKEN: Optional[str] = None
CODEX_REFRESH_TOKEN: Optional[str] = None
CODEX_TOKEN_EXPIRES: Optional[str] = None
CODEX_ACCOUNT_ID: Optional[str] = None
CODEX_USERNAME: Optional[str] = None
CODEX_EMAIL: Optional[str] = None
CODEX_IS_PRO: Optional[bool] = None