Skip to content

Commit

Permalink
feat: Use URL query params to set initial chat settings (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
yoomlam authored Aug 6, 2024
1 parent f2522c1 commit ce5bc9a
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 24 deletions.
64 changes: 40 additions & 24 deletions app/src/chainlit.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@

@cl.on_chat_start
async def start() -> None:
engine_id = engine_url_query_value()
url = cl.user_session.get("http_referer")
logger.debug("Referer URL: %s", url)
query_values = url_query_values(url)

engine_id = query_values.pop("engine", app_config.chat_engine)
logger.info("Engine ID: %s", engine_id)

engine = _init_chat_engine(engine_id)
Expand All @@ -31,14 +35,33 @@ async def start() -> None:
).send()
return

settings = await _init_chat_settings(engine)
input_widgets = _init_chat_settings(engine, query_values)
settings = await cl.ChatSettings(input_widgets).send()
logger.info("Initialized settings: %s", pprint.pformat(settings, indent=4))
if query_values:
logger.warning("Unused URL query parameters: %r", query_values)
await cl.Message(
author="backend",
metadata={"url": url},
content=f"Unused URL query parameters: {query_values}",
).send()

await cl.Message(
author="backend",
metadata={"engine": engine_id, "settings": str(settings)},
content=f"{engine.name} started with settings:\n{pprint.pformat(settings, indent=3)}",
).send()


def url_query_values(url: str) -> dict[str, str]:
# Using this suggestion: https://github.com/Chainlit/chainlit/issues/144#issuecomment-2227543547
parsed_url = urlparse(url)
# For a given query key, only the first value is used
query_values = {key: values[0] for key, values in parse_qs(parsed_url.query).items()}
logger.info("URL query values: %r", query_values)
return query_values


def _init_chat_engine(engine_id: str) -> ChatEngineInterface | None:
engine = chat_engine.create_engine(engine_id)
if engine:
Expand All @@ -47,16 +70,19 @@ def _init_chat_engine(engine_id: str) -> ChatEngineInterface | None:
return None


async def _init_chat_settings(engine: ChatEngineInterface) -> dict[str, Any]:
def _init_chat_settings(
engine: ChatEngineInterface, query_values: dict[str, str]
) -> list[InputWidget]:
input_widgets: list[InputWidget] = [
_WIDGET_FACTORIES[setting_name](getattr(engine, setting_name))
_WIDGET_FACTORIES[setting_name](
query_values.pop(setting_name, None)
or getattr(app_config, setting_name, None)
or getattr(engine, setting_name)
)
for setting_name in engine.user_settings
if setting_name in _WIDGET_FACTORIES
]
input_widgets.append(_WIDGET_FACTORIES["llm"](app_config.llm or getattr(engine, "llm", None)))
settings = await cl.ChatSettings(input_widgets).send()
logger.info("Initialized settings: %s", pprint.pformat(settings, indent=4))
return settings
return input_widgets


@cl.on_settings_update
Expand All @@ -83,43 +109,33 @@ def update_settings(settings: dict[str, Any]) -> Any:
max=10,
step=1,
),
"retrieval_k_min_score": lambda default_value: Slider(
"retrieval_k_min_score": lambda initial_value: Slider(
id="retrieval_k_min_score",
label="Minimum document score required for generating LLM response",
initial=default_value,
initial=initial_value,
min=-1,
max=1,
step=0.25,
),
"docs_shown_max_num": lambda default_value: Slider(
"docs_shown_max_num": lambda initial_value: Slider(
id="docs_shown_max_num",
label="Maximum number of retrieved documents to show in the UI",
initial=default_value,
initial=initial_value,
min=0,
max=10,
step=1,
),
"docs_shown_min_score": lambda default_value: Slider(
"docs_shown_min_score": lambda initial_value: Slider(
id="docs_shown_min_score",
label="Minimum document score required to show document in the UI",
initial=default_value,
initial=initial_value,
min=-1,
max=1,
step=0.25,
),
}


def engine_url_query_value() -> str:
url = cl.user_session.get("http_referer")
logger.debug("Referer URL: %s", url)

# Using this suggestion: https://github.com/Chainlit/chainlit/issues/144#issuecomment-2227543547
parsed_url = urlparse(url)
qs = parse_qs(parsed_url.query)
return qs.get("engine", [app_config.chat_engine])[0]


@cl.on_message
async def on_message(message: cl.Message) -> None:
logger.info("Received: %r", message.content)
Expand Down
1 change: 1 addition & 0 deletions app/src/chat_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class GuruBaseEngine(ChatEngineInterface):
retrieval_k_min_score: float = 0.45

user_settings = [
"llm",
"retrieval_k",
"retrieval_k_min_score",
"docs_shown_max_num",
Expand Down
18 changes: 18 additions & 0 deletions app/tests/src/test_chainlit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from src import chainlit, chat_engine


def test_url_query_values(monkeypatch):
monkeypatch.setenv("OPENAI_API_KEY", "mock_key")

url = "https://example.com/chat/?engine=guru-snap&llm=gpt-4o&retrieval_k=3&someunknownparam=42"
query_values = chainlit.url_query_values(url)
engine_id = query_values.pop("engine")
assert engine_id == "guru-snap"

engine = chat_engine.create_engine(engine_id)
input_widgets = chainlit._init_chat_settings(engine, query_values)
assert len(input_widgets) == len(engine.user_settings)

# Only 1 query parameter remains
assert len(query_values) == 1
assert query_values["someunknownparam"] == "42"

0 comments on commit ce5bc9a

Please sign in to comment.