Skip to content

feat(wren-ai-service): create Streamlit UI for configuring LLM models #1690

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 75 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
da42d8d
fix: add fmt.Scanln for debugging missing error report
yichieh-lu Apr 10, 2025
4584b05
Merge branch 'main' into main
cyyeh Apr 10, 2025
462554d
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 10, 2025
96667ab
Merge branch 'main' of https://github.com/yichieh-lu/WrenAI
yichieh-lu Apr 10, 2025
a275e42
Remove redundant code
yichieh-lu Apr 11, 2025
c96f296
Add initial config.grok.yaml to support deploymen
yichieh-lu Apr 12, 2025
e7edbd3
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 14, 2025
398a14c
Remove redundant engine declaration
yichieh-lu Apr 14, 2025
e090cf0
Remove incorrect settings from config_examples YAML files
yichieh-lu Apr 14, 2025
a39d71f
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 16, 2025
d59c6bf
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 21, 2025
1168301
Draft streamlit_ui
yichieh-lu Apr 21, 2025
c70f183
Build a testing streamlit_ui
yichieh-lu Apr 23, 2025
a261c3b
Extract constants to constants.py
yichieh-lu Apr 23, 2025
0cf0ddd
refactor: extract download_config and load_block from custom_llm_ui.py
yichieh-lu Apr 23, 2025
35a9743
refactor: split load_blocks into load_yaml_list and group_blocks
yichieh-lu Apr 23, 2025
66488b1
refactor: move session state handling to ConfigState class in session…
yichieh-lu Apr 23, 2025
54885d7
style: remove trailing whitespace
yichieh-lu Apr 23, 2025
c6bc142
refactor: extract UI layout and elements to ui_components.py
yichieh-lu Apr 23, 2025
01d3208
Refactor app structure and fix data type issues
yichieh-lu Apr 24, 2025
04edc56
feat: check for duplicate alias names
yichieh-lu Apr 24, 2025
fdb2114
refactor: extract preview and generate YAML UI to ui_components.py
yichieh-lu Apr 24, 2025
7f8daca
feat: add pipeline configuration in ui_components.py
yichieh-lu Apr 24, 2025
494fac4
feat: add dry_run_test.py testing api_key and embedding model with li…
yichieh-lu Apr 25, 2025
181eb6f
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 26, 2025
7436303
feat: add validate function ensuring every field can be validated
yichieh-lu Apr 26, 2025
0f8e386
feat: support multiple API keys configuration for different LLMs
yichieh-lu Apr 27, 2025
cf14ae5
feat: support multiple API keys configuration for different LLMs
yichieh-lu Apr 27, 2025
ac81e37
feat: support saving multiple API keys and enable validation for LLM …
yichieh-lu Apr 29, 2025
9d4f0a0
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 29, 2025
90dd5a3
fix: ensure config.yaml is downloaded correctly
yichieh-lu Apr 29, 2025
a608d80
fix: ensure config.yaml is downloaded correctly
yichieh-lu Apr 29, 2025
667043b
feat: add api_base support to render_embedder and session state
yichieh-lu Apr 29, 2025
5a675aa
feat: get the latest WrenAI version in constants.py
yichieh-lu Apr 29, 2025
57077c2
feat: add selectbox for users to choose config.example.yaml by LLM pr…
yichieh-lu Apr 30, 2025
54f133d
chore: improve code comments and docstrings across UI components
yichieh-lu Apr 30, 2025
cad7459
chore: add initial requirements.txt with ui dependencies
yichieh-lu Apr 30, 2025
e9639e4
Merge remote-tracking branch 'upstream/main'
yichieh-lu Apr 30, 2025
05aac3d
chore: updates requirements.txt with ui dependencies
yichieh-lu May 1, 2025
f1b3e45
chore: improve code comments and docstrings across UI components
yichieh-lu May 1, 2025
6533430
feat: add Finished.setting to close Streamlit UI, continue CLI setup,…
yichieh-lu May 2, 2025
366db9f
feat: add Streamlit UI Dockerfile and implement 'custom' launch option
yichieh-lu May 2, 2025
9ce5946
refactor: decouple RunStreamlitUIContainer logic from launch.go and d…
yichieh-lu May 2, 2025
6bed2b4
feat: add 'custom' mode to launch Streamlit UI and ensure config file…
yichieh-lu May 5, 2025
6a068d1
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 5, 2025
d40ae29
chore: rename streamlit-ui to providers-setup and move to tools direc…
yichieh-lu May 6, 2025
011ce4b
feat: rewrite Dockerfile to use Poetry and remove requirements.txt
yichieh-lu May 6, 2025
bb8dab6
chore: rename streamlit-ui to providers-setup
yichieh-lu May 6, 2025
b4d5b4e
update dependencies
cyyeh May 6, 2025
6255290
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 6, 2025
d0d0360
Merge branches 'main' and 'main' of https://github.com/yichieh-lu/WrenAI
yichieh-lu May 6, 2025
8341378
chore: fix Streamlit UI layout
yichieh-lu May 6, 2025
eeedb81
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 7, 2025
d9bd650
Merge branch 'main' into main
cyyeh May 9, 2025
9f830b1
Merge branch 'main' into main
cyyeh May 9, 2025
430c67b
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 13, 2025
fc5ee05
refactor(wren-ai-service): streamline UI components and enhance confi…
yichieh-lu May 13, 2025
efc6529
refactor(wren-ai-service): improve configuration path handling and UI…
yichieh-lu May 13, 2025
095475c
feat(wren-ai-service): add validation for configuration blocks and im…
yichieh-lu May 13, 2025
8f892e6
refactor(wren-ai-service): enhance config extraction and improve UI c…
yichieh-lu May 13, 2025
2dc1b38
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 22, 2025
ea0765c
feat(workflow): add setup provider image workflow
yichieh-lu May 22, 2025
06ccc36
fix(workflow): update IMAGE_NAME to use repository owner
yichieh-lu May 22, 2025
1b80ae1
fix(workflow): update Docker image tags to include registry
yichieh-lu May 22, 2025
1cbeb60
fix(workflow): comment out ARM64 runner configuration in build matrix
yichieh-lu May 22, 2025
de9d460
fix(workflow): enable ARM64 runner configuration in build matrix
yichieh-lu May 22, 2025
f08abae
fix(workflow): enhance setup-provider-image workflow with multi-archi…
yichieh-lu May 22, 2025
b983e36
Merge remote-tracking branch 'upstream/main'
yichieh-lu May 26, 2025
bdd4f9f
feat(pipeline): enhance pipeline initialization to fetch and add miss…
yichieh-lu May 26, 2025
0d236be
feat(ui): add context window size configuration to LLM setup and vali…
yichieh-lu May 28, 2025
a706d3b
Merge branch 'main' into feature/providers-setup
yichieh-lu Jun 5, 2025
8afc269
fix: update local path for .env file and improve error handling in em…
yichieh-lu Jun 5, 2025
0b991c6
feat: enhance Streamlit UI container setup with configurable port and…
yichieh-lu Jun 5, 2025
d43e7cf
Update wren-ai-service/tools/providers-setup/ui_components.py
yichieh-lu Jun 5, 2025
2c4614b
Merge branch 'main' into feature/providers-setup
cyyeh Jun 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: improve code comments and docstrings across UI components
  • Loading branch information
yichieh-lu committed Apr 30, 2025
commit 54f133da4f54e95b981a649501b8a02b8a52dc1f
42 changes: 27 additions & 15 deletions wren-ai-service/streamlit-ui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,56 @@
)
import streamlit as st


# Set Streamlit page layout
st.set_page_config(
layout="wide", # 使用寬屏模式
initial_sidebar_state="expanded" # 控制側邊欄的初始狀態
layout="wide", # Use a wide layout for better horizontal space
initial_sidebar_state="expanded" # Expand sidebar by default
)

# Load and group configuration blocks from YAML
yaml_list = load_config_yaml_blocks()
blocks = group_blocks(yaml_list)

# Retrieve individual configuration sections
llm_block = blocks.get("llm", {})
embedder_block = blocks.get("embedder", {})
document_store_block = blocks.get("document_store", {})
document_store_block = blocks.get("document_store", {})
engine_blocks = blocks.get("engine", [])
pipeline_block = blocks.get("pipeline", {})
settings_block = blocks.get("settings", {})

# Initialize session state with default or imported config values
ConfigState.init(llm_block, embedder_block, document_store_block, pipeline_block)

# --- Streamlit UI --
st.title(" Custom LLM Config Generator")
st.markdown("")
col1, col2 = st.columns([1.5, 1]) # 左右欄位
# ----------------------
# Streamlit UI rendering
# ----------------------
st.title("Custom LLM Config Generator")

ConfigState.init(llm_block, embedder_block, document_store_block, pipeline_block)
# Layout: two columns – left for inputs, right for preview/export
col1, col2 = st.columns([1.5, 1])

with col1:
st.subheader("LLM Configuration")
# =====================
# LLM Configuration UI
# =====================

# Upload and parse YAML file into session state
render_import_yaml()

# API key input section
render_apikey()

# LLM model configuration UI
render_llm_config()

# Embedding model configuration UI
render_embedder_config()

# Document store configuration UI
render_document_store_config()

# Pipeline flow configuration UI
render_pipeline_config()

with col2:
# =====================
# preview and generate YAML UI
# =====================
# Final preview and export of the combined configuration as YAML
render_preview_and_generate(engine_blocks, pipeline_block, settings_block)
58 changes: 37 additions & 21 deletions wren-ai-service/streamlit-ui/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from session_state import ConfigState
from pathlib import Path
import constants as cst
from typing import Any, Dict, List
from typing import Any, Dict, List

def load_config_yaml_blocks() -> List[Dict[str, Any]]:
"""
嘗試從本地讀 config.yaml,若不存在則從 GitHub 讀取(不下載)。
Load the config.yaml from local disk if available;
otherwise, fetch it from the GitHub URL without downloading it.
"""
if cst.CONFIG_IN_PATH.exists():
try:
Expand All @@ -18,18 +19,31 @@ def load_config_yaml_blocks() -> List[Dict[str, Any]]:
else:
return fetch_yaml_from_url(cst.CONFIG_URL)

def load_selected_example_yaml(example_name: str) -> List[Dict[str, Any]]:
url = cst.CONFIG_EXAMPLES_SELECTED_URL + example_name
return fetch_yaml_from_url(url)
def load_selected_example_yaml(selected_example: str) -> List[Dict[str, Any]]:
"""
Fetch a selected YAML example file from GitHub and return it as a list of blocks.
"""
selected_url = cst.CONFIG_EXAMPLES_SELECTED_URL + selected_example
try:
response = requests.get(selected_url, timeout=cst.REQUEST_TIMEOUT)
response.raise_for_status()
return list(yaml.safe_load_all(response.text))
except requests.RequestException as e:
print(f"❌ Error loading config from GitHub: {e}")
return []

def fetch_yaml_from_url(url: str) -> List[Dict[str, Any]]:
"""
Fetch and parse a YAML list from a remote URL.
Returns an empty list if fetch or parsing fails.
"""
try:
response = requests.get(url, timeout=cst.REQUEST_TIMEOUT)
response.raise_for_status()
config_list = list(yaml.safe_load_all(response.text))

if not config_list:
raise ValueError(f"⚠️ GitHub 回傳的 YAML 是空的,URL: {url}")
raise ValueError(f"⚠️ Received empty YAML content from: {url}")

return config_list

Expand All @@ -39,7 +53,8 @@ def fetch_yaml_from_url(url: str) -> List[Dict[str, Any]]:

def extract_config_blocks(config_list: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
傳入 YAML List,回傳各 block 分類後的 dict
Convert a flat list of config blocks into grouped dictionary format
with keys like 'llm', 'embedder', 'document_store', and 'pipeline'.
"""
grouped = group_blocks(config_list)
return {
Expand All @@ -49,22 +64,18 @@ def extract_config_blocks(config_list: List[Dict[str, Any]]) -> Dict[str, Any]:
"pipeline": grouped.get("pipeline", {})
}

def load__selected_config_yaml_blocks(selected_examples) -> List[Dict[str, Any]]:
selected_url = cst.CONFIG_EXAMPLES_SELECTED_URL + selected_examples
# return selected_url
try:
response = requests.get(selected_url, timeout=cst.REQUEST_TIMEOUT)
response.raise_for_status()
return list(yaml.safe_load_all(response.text))
except requests.RequestException as e:
print(f"❌ Error loading config from GitHub: {e}")
return []

def load_yaml_list(path: Path) -> List[Dict[str, Any]]:
"""
Load and parse all YAML documents from a file path.
"""
with path.open("r", encoding="utf-8") as f:
return list(yaml.safe_load_all(f))

def group_blocks(blocks: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
Group YAML blocks by their 'type' field.
If multiple blocks share the same type, they are stored as a list.
"""
save_blocks = {}
for block in blocks:
key = block.get("type") or ("settings" if "settings" in block else None)
Expand All @@ -80,7 +91,10 @@ def group_blocks(blocks: List[Dict[str, Any]]) -> Dict[str, Any]:
return save_blocks

def fetch_example_yaml_filenames() -> List[str]:
"""從 GitHub 的 config_examples 目錄中取得所有 .yaml 檔案名稱(不載入內容)"""
"""
Fetch the filenames of all .yaml example configs from the GitHub directory
(does not download the content).
"""
try:
response = requests.get(cst.CONFIG_EXAMPLES_URL, timeout=cst.REQUEST_TIMEOUT)
response.raise_for_status()
Expand All @@ -91,13 +105,15 @@ def fetch_example_yaml_filenames() -> List[str]:
return []

def apply_config_blocks(config_blocks: List[Dict[str, Any]]):
"""
Group and apply config blocks by updating the Streamlit session state via ConfigState.
"""
grouped = extract_config_blocks(config_blocks)

# 更新 ConfigState
ConfigState.init(
grouped["llm"],
grouped["embedder"],
grouped["document_store"],
grouped["pipeline"],
force=True
)
)
45 changes: 38 additions & 7 deletions wren-ai-service/streamlit-ui/constants.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
from pathlib import Path
import requests

# --- 自動取得最新版本 tag ---
# -------------------------------
# Fetch Latest Release Version
# -------------------------------

def get_latest_config_version():
"""
Retrieve the latest release tag from the WrenAI GitHub repository.

Returns:
str: The latest version tag (e.g., "0.20.2") if successful,
or "main" as a fallback if the request fails.
"""
url = "https://api.github.com/repos/Canner/WrenAI/releases/latest"
try:
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
return data["tag_name"] # ← 這裡就是 "0.20.2" 這種版本號
return data["tag_name"] # e.g., "0.20.2"
else:
print(f"Failed to get latest release: {response.status_code}")
except Exception as e:
print(f"Error fetching latest config version: {e}")
return "main" # fallback 版本,如果失敗就用 main branch

# --- constant ---
return "main" # Fallback to 'main' branch if fetch fails


# -------------------------------
# Constants for Config Loading
# -------------------------------

CONFIG_VERSION = get_latest_config_version()

# URL of the default config YAML file (used when no local file is available)
CONFIG_URL = f"https://raw.githubusercontent.com/Canner/WrenAI/{CONFIG_VERSION}/docker/config.example.yaml"
CONFIG_EXAMPLES_URL = f"https://api.github.com/repos/Canner/WrenAI/contents/wren-ai-service/docs/config_examples?ref={CONFIG_VERSION}"
CONFIG_EXAMPLES_SELECTED_URL = f"https://raw.githubusercontent.com/Canner/WrenAI/{CONFIG_VERSION}/wren-ai-service/docs/config_examples/"

# GitHub API URL to list example config files (metadata only, no content)
CONFIG_EXAMPLES_URL = (
f"https://api.github.com/repos/Canner/WrenAI/contents/wren-ai-service/docs/config_examples?ref={CONFIG_VERSION}"
)

# Base URL to fetch actual example YAML content by filename
CONFIG_EXAMPLES_SELECTED_URL = (
f"https://raw.githubusercontent.com/Canner/WrenAI/{CONFIG_VERSION}/wren-ai-service/docs/config_examples/"
)

# Path to local input config file (used if exists)
CONFIG_IN_PATH = Path("config.yaml")

# Path to write the generated config YAML file
CONFIG_OUT_PATH = Path("generated_config.yaml")
REQUEST_TIMEOUT = 10 # seconds

# Timeout duration for HTTP requests (in seconds)
REQUEST_TIMEOUT = 10
Loading
Loading