diff --git a/.env.example b/.env.example index 5d231931..5a5f6429 100644 --- a/.env.example +++ b/.env.example @@ -75,3 +75,10 @@ LANGFLOW_SUPERUSER= LANGFLOW_SUPERUSER_PASSWORD= LANGFLOW_NEW_USER_IS_ACTIVE=False LANGFLOW_ENABLE_SUPERUSER_CLI=False + +# Langfuse tracing (optional) +# Get keys from https://cloud.langfuse.com or your self-hosted instance +LANGFUSE_SECRET_KEY= +LANGFUSE_PUBLIC_KEY= +# Leave empty for Langfuse Cloud, or set for self-hosted (e.g., http://localhost:3002) +LANGFUSE_HOST= diff --git a/docker-compose.yml b/docker-compose.yml index 2a73da89..3058bc71 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -110,7 +110,9 @@ services: ports: - "7860:7860" environment: - - LANGFLOW_DEACTIVATE_TRACING=true + - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY:-} + - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY:-} + - LANGFUSE_HOST=${LANGFUSE_HOST:-} - OPENAI_API_KEY=${OPENAI_API_KEY:-None} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-None} - WATSONX_API_KEY=${WATSONX_API_KEY:-None} diff --git a/src/tui/managers/env_manager.py b/src/tui/managers/env_manager.py index aa5dc2eb..7724b760 100644 --- a/src/tui/managers/env_manager.py +++ b/src/tui/managers/env_manager.py @@ -55,6 +55,11 @@ class EnvConfig: aws_secret_access_key: str = "" langflow_public_url: str = "" + # Langfuse settings (optional) + langfuse_secret_key: str = "" + langfuse_public_key: str = "" + langfuse_host: str = "" + # Langflow auth settings langflow_auto_login: str = "False" langflow_new_user_is_active: str = "False" @@ -190,6 +195,9 @@ class EnvManager: "LANGFLOW_ENABLE_SUPERUSER_CLI": "langflow_enable_superuser_cli", "DISABLE_INGEST_WITH_LANGFLOW": "disable_ingest_with_langflow", "OPENRAG_VERSION": "openrag_version", + "LANGFUSE_SECRET_KEY": "langfuse_secret_key", # pragma: allowlist secret + "LANGFUSE_PUBLIC_KEY": "langfuse_public_key", # pragma: allowlist secret + "LANGFUSE_HOST": "langfuse_host", } loaded_from_file = False @@ -503,6 +511,24 @@ class EnvManager: if optional_written: f.write("\n") + # Langfuse settings (optional) + langfuse_vars = [ + ("LANGFUSE_SECRET_KEY", self.config.langfuse_secret_key), + ("LANGFUSE_PUBLIC_KEY", self.config.langfuse_public_key), + ("LANGFUSE_HOST", self.config.langfuse_host), + ] + + langfuse_written = False + for var_name, var_value in langfuse_vars: + if var_value: + if not langfuse_written: + f.write("# Langfuse settings\n") + langfuse_written = True + f.write(f"{var_name}={self._quote_env_value(var_value)}\n") + + if langfuse_written: + f.write("\n") + return True except Exception as e: diff --git a/src/tui/screens/config.py b/src/tui/screens/config.py index 57f25d08..1cb03477 100644 --- a/src/tui/screens/config.py +++ b/src/tui/screens/config.py @@ -513,6 +513,58 @@ class ConfigScreen(Screen): self.inputs["aws_secret_access_key"] = input_widget yield Static(" ") + # Langfuse Section (available in both basic and full mode) + yield Static("Langfuse (Tracing)", classes="tab-header") + yield Static(" ") + + # Langfuse Secret Key + yield Label("Langfuse Secret Key (optional)") + yield Static( + Text("Get keys from your Langfuse project settings", style="dim"), + classes="helper-text", + ) + current_value = getattr(self.env_manager.config, "langfuse_secret_key", "") + with Horizontal(id="langfuse-secret-key-row"): + input_widget = Input( + placeholder="sk-lf-...", + value=current_value, + password=True, + id="input-langfuse_secret_key", + ) + yield input_widget + self.inputs["langfuse_secret_key"] = input_widget + yield Button("Show", id="toggle-langfuse-secret-key", variant="default") + yield Static(" ") + + # Langfuse Public Key + yield Label("Langfuse Public Key (optional)") + current_value = getattr(self.env_manager.config, "langfuse_public_key", "") + with Horizontal(id="langfuse-public-key-row"): + input_widget = Input( + placeholder="pk-lf-...", + value=current_value, + password=True, + id="input-langfuse_public_key", + ) + yield input_widget + self.inputs["langfuse_public_key"] = input_widget + yield Button("Show", id="toggle-langfuse-public-key", variant="default") + yield Static(" ") + + # Langfuse Base URL + yield Label("Langfuse Host (optional)") + yield Static( + Text("Leave empty for Langfuse Cloud, or set for self-hosted", style="dim"), + classes="helper-text", + ) + current_value = getattr(self.env_manager.config, "langfuse_host", "") + input_widget = Input( + placeholder="https://cloud.langfuse.com", + value=current_value, + id="input-langfuse_host", + ) + yield input_widget + self.inputs["langfuse_host"] = input_widget yield Static(" ") # Other Settings Section @@ -713,6 +765,18 @@ class ConfigScreen(Screen): if input_widget: input_widget.password = not input_widget.password event.button.label = "Hide" if not input_widget.password else "Show" + elif event.button.id == "toggle-langfuse-secret-key": + # Toggle Langfuse secret key visibility + input_widget = self.inputs.get("langfuse_secret_key") + if input_widget: + input_widget.password = not input_widget.password + event.button.label = "Hide" if not input_widget.password else "Show" + elif event.button.id == "toggle-langfuse-public-key": + # Toggle Langfuse public key visibility + input_widget = self.inputs.get("langfuse_public_key") + if input_widget: + input_widget.password = not input_widget.password + event.button.label = "Hide" if not input_widget.password else "Show" def action_generate(self) -> None: """Generate secure passwords for admin accounts."""