Chatbot
By design, we do not offer a native API for managing unique conversation UUIDs.
There are many ways to do this (Redis, PostgreSQL, MongoDB), and we don't want to enforce a single method.
Nor do we want to bundle a database. To keep parallem slim and lightweight, storing conversation IDs is outside our scope.
Nonetheless, it can be easily accomplished. After assigning a unique conversation uuid, assign the uuid to be the agent name. The following demonstrates a simple CLI chatbot using polars:
from pathlib import Path
from uuid import uuid4
from dotenv import load_dotenv
import parallem as pllm
import polars as pl
from colorama import Fore, Style, init
init(autoreset=True)
load_dotenv()
# Begin conversation_uuid persistence logic
CONV_UUIDS_LOCATION = Path(".pllm/example/chatbot/conversations.parquet")
def load_conversations():
if CONV_UUIDS_LOCATION.exists():
df = pl.read_parquet(CONV_UUIDS_LOCATION)
else:
df = pl.DataFrame(schema={"conversation_uuid": pl.Utf8, "title": pl.Utf8})
return df
def select_conversation(conv_df):
"""Have the user select a conversation."""
print()
print("Existing conversations")
print("=" * 22)
for i, row in enumerate(conv_df.iter_rows()):
print(f'{Fore.BLUE}{i}{Style.RESET_ALL}: "{row[1]}"')
print(f"{Fore.BLUE}{len(conv_df)}{Style.RESET_ALL}: [New conversation]")
print(f"{Fore.BLUE}Enter{Style.RESET_ALL} to quit")
choice = input("Select a number: ")
if choice == "":
return None
choice = int(choice)
if choice == len(conv_df):
# generate new conversation UUID
new_uuid = str(uuid4())
return new_uuid
else:
return conv_df[choice, "conversation_uuid"]
def update_conversation(conv_df: pl.DataFrame, conv_uuid: str, title: str):
"""Update the title of an existing conversation."""
conv_df = pl.concat(
[
conv_df,
pl.DataFrame({"conversation_uuid": [conv_uuid], "title": [title]}),
]
)
conv_df = conv_df.unique(
subset="conversation_uuid", keep="last", maintain_order=True
)
conv_df.write_parquet(CONV_UUIDS_LOCATION)
return conv_df
def exit_to_quit(x):
out = input(x)
if out.lower() == "":
raise KeyboardInterrupt
return out
# Begin parallem logic
def chatbot(agt: pllm.AgentContext):
conv = agt.get_msg_state().load()
agt.print("Current messages:", conv.resolve())
out = input("Send a message (enter to quit): ")
while out:
conv.append(out)
conv.ask_llm()
agt.print("Response:", conv[-1].resolve())
out = input("Send a message (enter to quit): ")
conv.save()
return conv[0] if len(conv) > 0 else "[empty]"
with pllm.resume_directory(
".pllm/example/chatbot",
provider="openai",
strategy="sync",
dashboard=True,
) as orch:
# Demonstrate a ChatGPT-like chatbot with multiple distinct conversations.
# Use your favorite tool (Postgres, Redis, etc.) to store conversation_uuids.
# Polars is used for demonstration purposes.
conv_df = load_conversations()
conv_uuid = select_conversation(conv_df)
if conv_uuid:
with orch.agent(name=f"chatbot_{conv_uuid}") as agt:
title = chatbot(agt)
update_conversation(conv_df, conv_uuid, title)
Output:
[INFO] Resuming with session_id=24
Existing conversations
======================
0: "Who was president before Lincoln?"
1: "What is the capital of Kyrgyzstan?"
2: [New conversation]
Enter to quit
Select a number: