8000 Deploy the api to modal by bugsz Β· Pull Request #267 Β· sotopia-lab/sotopia Β· GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Deploy the api to modal #267

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

Merged
merged 8 commits into from
Dec 28, 2024
Merged
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
6 changes: 6 additions & 0 deletions docs/pages/examples/deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Deploy Sotopia Python API to Modal
We offer a script to deploy Sotopia Python API to [Modal](https://modal.com/).
To do so, simply go to the `sotopia/sotopia/ui` directory and run the following command:
```bash
modal deploy sotopia/ui/modal_api_server.py
```
102 changes: 102 additions & 0 deletions scripts/modal/modal_api_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import modal
import subprocess
import time
import os

import redis
from sotopia.ui.fastapi_server import SotopiaFastAPI

# Create persistent volume for Redis data
redis_volume = modal.Volume.from_name("sotopia-api", create_if_missing=True)


def initialize_redis_data() -> None:
"""Download Redis data if it doesn't exist"""
if not os.path.exists("/vol/redis/dump.rdb"):
os.makedirs("/vol/redis", exist_ok=True)
print("Downloading initial Redis data...")
subprocess.run(
"curl -L https://cmu.box.com/shared/static/e3vd31r7916jb70j9cgtcq9etryrxml0.rdb --output /vol/redis/dump.rdb",
shell=True,
check=True,
)
print("Redis data downloaded")


# Create image with all necessary dependencies
image = (
modal.Image.debian_slim(python_version="3.11")
.apt_install(
"git",
"curl",
"gpg",
"lsb-release",
"wget",
"procps", # for ps command
"redis-tools", # for redis-cli
)
.run_commands(
# Update and install basic dependencies
"apt-get update",
"apt-get install -y curl gpg lsb-release",
# Add Redis Stack repository
"curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg",
"chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg",
'echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list',
"apt-get update",
"apt-get install -y redis-stack-server",
)
.pip_install(
"sotopia>=0.1.2",
"fastapi>0.100", # TODO: remove this dependency after pypi release
"uvicorn", # TODO: remove this dependency after pypi release
)
)
redis_volume = modal.Volume.from_name("sotopia-api", create_if_missing=True)

# Create stub for the application
app = modal.App("sotopia-fastapi", image=image, volumes={"/vol/redis": redis_volume})


@app.cls(
image=image,
concurrency_limit=1,
allow_concurrent_inputs=5,
secrets=[modal.Secret.from_name("openai-secret")],
)
class WebAPI:
def __init__(self) -> None:
self.web_app = SotopiaFastAPI()

@modal.enter()
def setup(self) -> None:
# Start Redis server
subprocess.Popen(
["redis-stack-server", "--dir", "/vol/redis", "--port", "6379"]
)

# Wait for Redis to be ready
max_retries = 30
for _ in range(max_retries):
try:
initialize_redis_data()
# Attempt to create Redis client and ping the server
temp_client = redis.Redis(host="localhost", port=6379, db=0)
temp_client.ping()
self.redis_client = temp_client
print("Successfully connected to Redis")
return
except (redis.exceptions.ConnectionError, redis.exceptions.ResponseError):
print("Waiting for Redis to be ready...")
time.sleep(1)

raise Exception("Could not connect to Redis after multiple attempts")

@modal.exit()
def cleanup(self) -> None:
if hasattr(self, "redis_client"):
self.redis_client.close()

@modal.asgi_app()
def serve(self) -> SotopiaFastAPI:
return self.web_app
9 changes: 8 additions & 1 deletion sotopia/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ returns:
**WSMessageType**
| Type | Direction | Description |
|-----------|--------|-------------|
| SERVER_MSG | Server β†’ Client | Standard message from server (payload: `messageForRendering` [here](https://github.com/sotopia-lab/sotopia-demo/blob/main/socialstream/rendering_utils.py) ) |
| SERVER_MSG | Server β†’ Client | Standard message from server (payload: `EpisodeLog`) |
| CLIENT_MSG | Client β†’ Server | Standard message from client (payload: TBD) |
| ERROR | Server β†’ Client | Error notification (payload: TBD) |
| START_SIM | Client β†’ Server | Initialize simulation (payload: `SimulationEpisodeInitialization`) |
Expand All @@ -179,6 +179,13 @@ returns:

**Implementation plan**: Currently only support LLM-LLM simulation based on [this function](https://github.com/sotopia-lab/sotopia/blob/19d39e068c3bca9246fc366e5759414f62284f93/sotopia/server.py#L108).

**SERVER_MSG payload**
The server message is a dictionary that has the following keys:
- type: str, indicates the type of the message, typically it is "messages"
- messages: Any. Typically this is the dictionary of the `EpisodeLog` for the current simulation state. (Which means the reward part could be empty)




## An example to run simulation with the API

Expand Down
Loading
Loading
0