Skip to content
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

initial UI #241

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docs/pages/contribution/contribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Please refer to [Dev Containers](https://containers.dev/supporting#editors) to s

You can also set up the development environment without Dev Containers. There are three things you will need to set up manually:

- Python and uv: Please start from an environment supporting Python 3.10+ and install uv using `pip install uv; uv sync --all-extra`.
- Python and uv: Please start from an environment supporting Python 3.10+ and install uv using `pip install uv; uv sync --all-extras`. (Note that this will install all the extra dependencies)
- Redis: Please refer to introduction page for the set up of Redis.
- Local LLM (optional): If you don't have access to model endpoints (e.g. OpenAI, Anthropic or others), you can use a local model. You can use Ollama, Llama.cpp, vLLM or many others which support OpenAI compatible endpoints.

Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ examples = ["transformers", "datasets", "scipy", "torch", "pandas"]
api = [
"fastapi[standard]",
"uvicorn",
"streamlit",
"websockets"
]
test = ["pytest", "pytest-cov", "pytest-asyncio"]

Expand Down
8 changes: 8 additions & 0 deletions sotopia/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
> [!CAUTION]
> Work in progress: the API endpoints are being implemented. And will be released in the future major version.

## Streamlit UI
To run the Streamlit UI, run the following command:
```bash
cd sotopia/ui/streamlit_ui
uv run streamlit run app.py
```


## FastAPI Server

The API server is a FastAPI application that is used to connect the Sotopia UI to the Sotopia backend.
Expand Down
11 changes: 11 additions & 0 deletions sotopia/ui/streamlit_ui/.streamlit/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[theme]
base="light"
primaryColor = "#26184e"
backgroundColor="#FFFFFF"
secondaryBackgroundColor="#F0F2F6"
textColor="#31333F"
font="sans serif"


[server]
enableStaticServing = true
7 changes: 7 additions & 0 deletions sotopia/ui/streamlit_ui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .utils import reset_database
from .rendering.rendering_utils import (
_agent_profile_to_friendabove_self,
render_for_humans,
)

__all__ = ["reset_database", "_agent_profile_to_friendabove_self", "render_for_humans"]
79 changes: 79 additions & 0 deletions sotopia/ui/streamlit_ui/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import os

import streamlit as st

from sotopia.ui.streamlit_ui.utils import reset_database


def update_database_callback() -> None:
new_database_url = st.session_state.new_database_url
updated_url = (
new_database_url if new_database_url != "" else st.session_state.DEFAULT_DB_URL
)
try:
reset_database(updated_url)
except Exception as e:
st.error(f"Error occurred while updating database: {e}, please try again.")

st.session_state.current_database_url = updated_url
print("Updated DB URL: ", st.session_state.current_database_url)


# Page Configuration
st.set_page_config(page_title="SocialStream_Demo", page_icon="🧊", layout="wide")

display_intro = st.Page(
"./pages/intro.py", title="Introduction", icon=":material/home:"
)
display_episodes = st.Page(
"./pages/display_episodes.py", title="Episode", icon=":material/photo_library:"
)
display_scenarios = st.Page(
"./pages/display_scenarios.py",
title="Scenarios",
icon=":material/insert_drive_file:",
)
display_characters = st.Page(
"./pages/display_characters.py", title="Characters", icon=":material/people:"
)

display_chat = st.Page(
"./pages/render_chat_websocket.py", title="Simulation", icon=":material/add:"
)

pg = st.navigation(
[
display_intro,
display_scenarios,
display_episodes,
display_characters,
display_chat,
]
)

# Reset active agent when switching modes across pages
if "mode" not in st.session_state or pg.title != st.session_state.get("mode", None):
if "active" in st.session_state:
del st.session_state["active"]
# print("Active agent reset.")

st.session_state.mode = pg.title


# DB URL Configuration
if "DEFAULT_DB_URL" not in st.session_state:
st.session_state.DEFAULT_DB_URL = os.environ.get("REDIS_OM_URL", "")
st.session_state.current_database_url = st.session_state.DEFAULT_DB_URL
print("Default DB URL: ", st.session_state.DEFAULT_DB_URL)

# impl 2: popup update URL
with st.sidebar.popover("(Optional) Enter Database URL"):
new_database_url = st.text_input(
"URL: (starting in redis://)",
value="",
on_change=update_database_callback,
key="new_database_url",
)


pg.run()
28 changes: 28 additions & 0 deletions sotopia/ui/streamlit_ui/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.truncate{
max-height: 2em;
text-overflow: ellipsis;
margin-bottom: 12px;
cursor: pointer;
word-break: break-all;
overflow:hidden;
white-space: nowrap;
transition: max-height 1s, white-space 1s;
}
.truncate:hover{
overflow: auto;
overflow-y: scroll;
white-space: normal;
max-height: 200px;
}
/*
[data-testid="stAppViewContainer"] {
background-image: url("https://images.unsplash.com/photo-1729096532452-50549f2bb63c");
background-size: 40%;
background-position: top right;
background-repeat: no-repeat;
background-attachment: local;
} */

[data-testid="stHeader"] {
background: rgba(0,0,0,0);
}
Empty file.
85 changes: 85 additions & 0 deletions sotopia/ui/streamlit_ui/pages/display_characters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import streamlit as st

from sotopia.database import AgentProfile


def local_css(file_name: str) -> None:
with open(file_name) as f:
st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)


def display_characters() -> None:
st.title("Characters")
all_characters = AgentProfile.find().all()

col1, col2 = st.columns(2, gap="medium")
for i, character in enumerate(all_characters):
with col1 if i % 2 == 0 else col2:
assert isinstance(character, AgentProfile)
rendering_character(character)
st.write("---")


def display_field(label: str, value: str) -> str:
if value:
return f"<p><strong>{label}:</strong> {value}</p>"
return ""


def rendering_character(character: AgentProfile) -> None:
local_css("././css/style.css")

full_name = f"{character.first_name} {character.last_name}"

personal_info = ""
personal_info += display_field("Age", str(character.age))
personal_info += display_field("Occupation", character.occupation)
personal_info += display_field("Gender", character.gender)
personal_info += display_field("Gender Pronoun", character.gender_pronoun)

st.markdown(
f"""
<div style="background-color: #f9f9f9; padding: 10px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); margin-bottom: 20px;">
<p><strong>Name</strong>: {full_name}</p>
<div style="background-color: #D1E9F6; padding: 10px; border-radius: 10px; margin-bottom: 5px;">
<p><strong>Demographic Information</strong></p>
<div class="truncate">
{personal_info}
</div>
</div>

</div>
""",
unsafe_allow_html=True,
)
with st.expander("Additional Information", expanded=False):
additional_info = ""
additional_info += display_field("Public Info", character.public_info)
additional_info += display_field("Big Five", character.big_five)
additional_info += display_field(
"Moral Values", ", ".join(character.moral_values)
)
additional_info += display_field(
"Schwartz Personal Values", ", ".join(character.schwartz_personal_values)
)
additional_info += display_field(
"Personality and Values", character.personality_and_values
)
additional_info += display_field(
"Decision Making Style", character.decision_making_style
)
additional_info += display_field("Secret", character.secret)
additional_info += display_field("Model ID", character.model_id)
additional_info += display_field("MBTI", character.mbti)

st.markdown(
f"""
<div style="background-color: #d0f5d0; padding: 10px; border-radius: 10px; margin-bottom: 12px;">
{additional_info}
</div>
""",
unsafe_allow_html=True,
)


display_characters()
8 changes: 8 additions & 0 deletions sotopia/ui/streamlit_ui/pages/display_episodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import streamlit as st

from sotopia.ui.streamlit_ui.rendering import rendering_episodes

st.title("Episode")

st.write("Here are some instructions about using the episode renderer.")
rendering_episodes()
29 changes: 29 additions & 0 deletions sotopia/ui/streamlit_ui/pages/display_scenarios.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import requests
import streamlit as st
from sotopia.ui.streamlit_ui.rendering.rendering_utils import render_environment_profile
from sotopia.database import EnvironmentProfile


def local_css(file_name: str) -> None:
with open(file_name) as f:
st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)


local_css("./css/style.css")


def display_scenarios() -> None:
st.title("Scenarios")

response = requests.get("http://localhost:8000/scenarios")
scenarios = response.json() if response.status_code == 200 else []

col1, col2 = st.columns(2, gap="medium")
for i, scenario in enumerate(scenarios):
with col1 if i % 2 == 0 else col2:
environment_profile = EnvironmentProfile(**scenario)
render_environment_profile(environment_profile)
st.write("---")


display_scenarios()
7 changes: 7 additions & 0 deletions sotopia/ui/streamlit_ui/pages/intro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import streamlit as st

st.title("Sotopia")
st.write(
"Welcome to the Sotopia Demo App. This app lets you explore various chat scenarios, from basic chats to omniscient editing views, and view episodes in detail."
)
st.markdown("Use the sidebar to navigate between pages.")
Loading
Loading