import sys import os import logging from typing import AsyncIterator from agents import (Runner, set_default_openai_key, trace) from openai.types.responses import ResponseTextDeltaEvent import streamlit as st from lichtblick import lichtblick_agent # ==================== # Setup logging # ==================== logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(name)s | %(message)s" ) logger = logging.getLogger("Lichtblick") # ============================ # Core async function # ============================ async def llm_response(api_key: str, message: str) -> AsyncIterator[str]: """ Streams the response from the Lichtblick assistant as an async text generator. Args: api_key (str): The OpenAI API key to authenticate requests. message (str): The user's input message to be processed by the agent. Yields: str: Incremental chunks of the assistant's response text as they are streamed. """ set_default_openai_key(api_key) if not api_key or not api_key.startswith("sk-"): logger.error("Missing or invalid OpenAI API key.") yield "๐ค API key is missing or invalid. Please check your .env file." return # Construct context from message history context = "" for msg in st.session_state.messages[-5:]: # Use last 5 turns role = "User" if msg["role"] == "user" else "Assistant" content = msg["content"] context += f"{role}: {content}\n\n" # Double newline for clarity context += f"User: {message}" try: result = Runner.run_streamed(lichtblick_agent, input=message) async for event in result.stream_events(): if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent): if event.data.delta: yield event.data.delta logger.info("Agent streaming complete.") except Exception as e: logger.exception("Error during agent processing.") yield "๐ค Sorry, something went wrong. Please try again." # ============================ # Lichtblick Streamlit App # ============================ st.set_page_config( page_title="Lichtblick", page_icon="๐ฉ๐ช๐", layout="centered", initial_sidebar_state="collapsed" ) # Sidebar with st.sidebar: st.image("assets/lichtblick_mascot.png") openai_api_key = st.sidebar.text_input("OpenAI API Key", type="password") # โ Show "ready" toast only once per session if openai_api_key and openai_api_key.startswith("sk-"): if not st.session_state.get("api_key_validated"): st.toast("๐ก Lichtblick is ready!", icon="โ ") st.session_state.api_key_validated = True elif openai_api_key: st.toast("โ Invalid API key format.", icon="โ ๏ธ") st.session_state.api_key_validated = False # Clear chat + reset session # ๐งน Centered Clear Chat Button in the sidebar st.markdown("