From 2dd82ff8036caf4f7eaf4761fb7ff69454466bdd Mon Sep 17 00:00:00 2001 From: Mathias Scheider Date: Tue, 29 Sep 2026 22:22:10 +0200 Subject: [PATCH] some more skeleton --- src/photools3/llm_session.py | 32 +++++++++++++++++++++++++------- src/photools3/models.py | 28 ++++++++++++++++++++++++---- src/photools3/settings.py | 9 +++++++++ 3 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 src/photools3/settings.py diff --git a/src/photools3/llm_session.py b/src/photools3/llm_session.py index 9f88844..0ca5d3f 100644 --- a/src/photools3/llm_session.py +++ b/src/photools3/llm_session.py @@ -1,13 +1,31 @@ +from openai import OpenAI +from openai.types.chat import ChatCompletion -from photools3.models import LlmRequest, LlmResponse +from photools3.models import LlmRequest +from photools3.settings import Settings + +settings = Settings() class LlmSession: - def __init__(self): - ... + base_url: str = str(settings.llm_api_base_url) + api_key: str = settings.llm_api_key - def prompt(self, request: LlmRequest) -> LlmResponse: - ... + def __init__(self, system_prompt: str): + self._models: list = [] - def close(self): - ... + self.system_prompt = system_prompt + + self.client = OpenAI( + base_url=self.base_url, + api_key=self.api_key, + ) + + @property + def models(self): + if not self._models: + self._models = self.client.models.list().data + return self._models + + def call_raw(self, request: LlmRequest) -> ChatCompletion: + return self.client.chat.completions.create(**request.model_dump()) diff --git a/src/photools3/models.py b/src/photools3/models.py index 3c38652..0f35a81 100644 --- a/src/photools3/models.py +++ b/src/photools3/models.py @@ -1,8 +1,28 @@ -from pydantic import BaseModel +from typing import Literal + +from pydantic import BaseModel, model_validator class LlmRequest(BaseModel): - ... + model_id: int + messages: list[LlmRequestMessage] + temperature: float | None = None -class LlmResponse(BaseModel): - ... + +class LlmRequestMessage(BaseModel): + role: Literal["system", "user"] + content: list[LlmMessageContent] + + +class LlmMessageContent(BaseModel): + type: Literal["text", "image_url"] + text: str | None = None + image_url: str | None = None + + @model_validator(mode="after") + def _type_matches_content(self): + if self.type == "text" and self.text is None: + raise ValueError("text must be set when type is 'text'") + if self.type == "image_url" and self.image_url is None: + raise ValueError("image_url must be set when type is 'image_url'") + return self diff --git a/src/photools3/settings.py b/src/photools3/settings.py new file mode 100644 index 0000000..3fb5f46 --- /dev/null +++ b/src/photools3/settings.py @@ -0,0 +1,9 @@ +from pydantic_core import Url +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + model_config = SettingsConfigDict(env_file=".env") + + llm_api_base_url: Url + llm_api_key: str