diff --git a/.env.template b/.env.template index 9c4b9b0..2382458 100644 --- a/.env.template +++ b/.env.template @@ -20,6 +20,9 @@ AZURE_OPENAI_MODEL_CHAT="gpt-5" AZURE_OPENAI_MODEL_EMBEDDING="text-embedding-3-small" AZURE_OPENAI_MODEL_REASONING="o4-mini" +## Ollama Settings +OLLAMA_MODEL_CHAT="gemma3:270m" + # --------- # Tools # --------- diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml index 1963b6f..78f408f 100644 --- a/.github/workflows/labeler.yaml +++ b/.github/workflows/labeler.yaml @@ -8,6 +8,7 @@ jobs: permissions: contents: read pull-requests: write + issues: write runs-on: ubuntu-latest steps: - name: labeler action diff --git a/scripts/ollama_operator.py b/scripts/ollama_operator.py index fb12280..52e7fa4 100644 --- a/scripts/ollama_operator.py +++ b/scripts/ollama_operator.py @@ -2,10 +2,23 @@ import typer from dotenv import load_dotenv +from langchain_core.messages import HumanMessage +from pydantic import BaseModel, Field from template_langgraph.llms.ollamas import OllamaWrapper from template_langgraph.loggers import get_logger + +class Profile(BaseModel): + first_name: str = Field(..., description="First name of the user") + last_name: str = Field(..., description="Last name of the user") + age: int = Field(..., description="Age of the user") + origin: str = Field( + ..., + description="Origin of the user, e.g., country or city", + ) + + # Initialize the Typer application app = typer.Typer( add_completion=False, @@ -17,9 +30,9 @@ @app.command() -def run( +def chat( query: str = typer.Option( - "What is the weather like today?", + "Explain the concept of Fourier transform.", "--query", "-q", help="Query to run against the Ollama model", @@ -30,6 +43,12 @@ def run( "-v", help="Enable verbose output", ), + stream: bool = typer.Option( + False, + "--stream", + "-s", + help="Enable streaming output", + ), ): # Set up logging if verbose: @@ -37,16 +56,65 @@ def run( logger.info("Running...") chat_model = OllamaWrapper().chat_model - response = chat_model.invoke( - input=query, - ) - logger.debug( - response.model_dump_json( - indent=2, - exclude_none=True, + + if stream: + response = "" + for chunk in chat_model.stream( + input=[ + HumanMessage(content=query), + ], + ): + print( + chunk.content, + end="", + flush=True, + ) + response += str(chunk.content) + logger.info(f"Output: {response}") + else: + response = chat_model.invoke( + input=[ + HumanMessage(content=query), + ], ) + logger.debug( + response.model_dump_json( + indent=2, + exclude_none=True, + ) + ) + logger.info(f"Output: {response.content}") + + +@app.command() +def structured_output( + query: str = typer.Option( + "I'm Taro Okamoto from Japan. 30 years old.", + "--query", + "-q", + help="Query to run against the Ollama model", + ), + verbose: bool = typer.Option( + False, + "--verbose", + "-v", + help="Enable verbose output", + ), +): + # Set up logging + if verbose: + logger.setLevel(logging.DEBUG) + + logger.info("Running...") + chat_model = OllamaWrapper().chat_model + profile = chat_model.with_structured_output( + schema=Profile, + ).invoke( + input=[ + HumanMessage(content=query), + ], ) - logger.info(f"Output: {response.content}") + logger.info(f"Output: {profile.model_dump_json(indent=2, exclude_none=True)}") if __name__ == "__main__": diff --git a/template_langgraph/llms/ollamas.py b/template_langgraph/llms/ollamas.py index c3e7ff6..69e0e48 100644 --- a/template_langgraph/llms/ollamas.py +++ b/template_langgraph/llms/ollamas.py @@ -5,7 +5,7 @@ class Settings(BaseSettings): - ollama_model_chat: str = "phi3:latest" + ollama_model_chat: str = "gemma3:270m" model_config = SettingsConfigDict( env_file=".env",