Skip to content

Commit 539b276

Browse files
committed
lmnt-all-voices
1 parent 0fd391c commit 539b276

23 files changed

+567
-0
lines changed

community/lmnt/.env.Example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
LMNT_API_KEY=<your-lmnt-api-key>
2+
3+
# Restack Cloud (Optional)
4+
5+
# RESTACK_ENGINE_ID=<your-engine-id>
6+
# RESTACK_ENGINE_API_KEY=<your-engine-api-key>
7+
# RESTACK_ENGINE_ADDRESS=<your-engine-address>
8+
# RESTACK_ENGINE_API_ADDRESS=<your-engine-api-address>

community/lmnt/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
__pycache__
2+
.pytest_cache
3+
venv
4+
.env
5+
.vscode
6+
poetry.lock
7+
8+
src/media/*
9+
!src/media/.gitkeep
10+

community/lmnt/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM python:3.12-slim
2+
3+
WORKDIR /app
4+
5+
RUN apt-get update && apt-get install -y
6+
7+
RUN pip install poetry
8+
9+
COPY pyproject.toml ./
10+
11+
COPY . .
12+
13+
# Configure poetry to not create virtual environment
14+
RUN poetry config virtualenvs.create false
15+
16+
# Install dependencies
17+
RUN poetry install --no-interaction --no-ansi
18+
19+
# Expose port 80
20+
EXPOSE 80
21+
22+
CMD poetry run python -m src.services

community/lmnt/README.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Restack AI - LMNT Example
2+
3+
This repository contains a simple example project to help you scale with Restack AI.
4+
It demonstrates how to scale reliably to millions of workflows on a local machine with a local LLM provider.
5+
6+
## Walkthrough video
7+
8+
https://www.youtube.com/watch?v=WsUtQYC74og
9+
10+
## Motivation
11+
12+
When scaling AI workflows, you want to make sure that you can handle failures and retries gracefully.
13+
This example demonstrates how to do this with Restack AI.
14+
15+
### Workflow Steps
16+
17+
The table below shows the execution of 50 workflows in parallel, each with three steps.
18+
Steps 2 and 3 are LLM functions that must adhere to a rate limit of 1 concurrent call per second.
19+
20+
| Step | Workflow 1 | Workflow 2 | ... | Workflow 50 |
21+
| ---- | ---------- | ---------- | --- | ----------- |
22+
| 1 | Basic | Basic | ... | Basic |
23+
| 2 | LLM | LLM | ... | LLM |
24+
| 3 | LLM | LLM | ... | LLM |
25+
26+
### Traditional Rate Limit Management
27+
28+
When running multiple workflows in parallel, managing the rate limit for LLM functions is crucial. Here are common strategies:
29+
30+
1. **Task Queue**: Use a task queue (e.g., Celery, RabbitMQ) to schedule LLM calls, ensuring only one is processed at a time.
31+
2. **Rate Limiting Middleware**: Implement middleware to queue requests and process them at the allowed rate.
32+
3. **Semaphore or Locking**: Use a semaphore or lock to control access, ensuring only one LLM function runs per second.
33+
34+
### With Restack
35+
36+
Restack automates rate limit management, eliminating the need for manual strategies. Define the rate limit in the service options, and Restack handles queuing and execution:
37+
38+
```python
39+
client.start_service(
40+
task_queue="llm",
41+
functions=[llm_generate, llm_evaluate],
42+
options=ServiceOptions(
43+
rate_limit=1,
44+
max_concurrent_function_runs=1
45+
)
46+
)
47+
```
48+
49+
Focus on building your logics while Restack ensures efficient and resilient workflow execution.
50+
51+
### On Restack UI
52+
53+
You can see from the parent workflow how long each child workflow stayed in queue and how long was the execution time.
54+
55+
![Parent Workflow](./ui-parent.png)
56+
57+
And for each child workflow, for each step you can see how long the function stayed in queue, how long the function took to execute and how many retries happened.
58+
59+
![Child Workflow](./ui-child.png)
60+
61+
## Prerequisites
62+
63+
- Python 3.10 or higher
64+
- Poetry (for dependency management)
65+
- Docker (for running the Restack services)
66+
- Local LLM provider (we use LMStudio and a Meta Llama 3.1 8B Instruct 4bit model in this example)
67+
68+
## Start LM stduio for local LLM provider
69+
70+
Start local server with Meta Llama 3.1 8B Instruct 4bit model
71+
72+
https://lmstudio.ai
73+
74+
## Prerequisites
75+
76+
- Docker (for running Restack)
77+
- Python 3.10 or higher
78+
79+
## Start Restack
80+
81+
To start the Restack, use the following Docker command:
82+
83+
```bash
84+
docker run -d --pull always --name restack -p 5233:5233 -p 6233:6233 -p 7233:7233 ghcr.io/restackio/restack:main
85+
```
86+
87+
## Start python shell
88+
89+
```bash
90+
poetry env use 3.10 && poetry shell
91+
```
92+
93+
## Install dependencies
94+
95+
```bash
96+
poetry install
97+
```
98+
99+
```bash
100+
poetry env info # Optional: copy the interpreter path to use in your IDE (e.g. Cursor, VSCode, etc.)
101+
```
102+
103+
```bash
104+
poetry run dev
105+
```
106+
107+
## Run workflows
108+
109+
### from UI
110+
111+
You can run workflows from the UI by clicking the "Run" button.
112+
113+
![Run workflows from UI](./ui-endpoints.png)
114+
115+
### from API
116+
117+
You can run one workflow from the API by using the generated endpoint:
118+
119+
`POST http://localhost:6233/api/workflows/ChildWorkflow`
120+
121+
or multiple workflows by using the generated endpoint:
122+
123+
`POST http://localhost:6233/api/workflows/ExampleWorkflow`
124+
125+
### from any client
126+
127+
You can run workflows with any client connected to Restack, for example:
128+
129+
```bash
130+
poetry run schedule
131+
```
132+
133+
executes `schedule_workflow.py` which will connect to Restack and execute the `ChildWorkflow` workflow.
134+
135+
```bash
136+
poetry run scale
137+
```
138+
139+
executes `schedule_scale.py` which will connect to Restack and execute the `ExampleWorkflow` workflow.
140+
141+
```bash
142+
poetry run interval
143+
```
144+
145+
executes `schedule_interval.py` which will connect to Restack and execute the `ChildWorkflow` workflow every second.
146+
147+
## Deploy on Restack Cloud
148+
149+
To deploy the application on Restack, you can create an account at [https://console.restack.io](https://console.restack.io)
150+
151+
## Project Structure
152+
153+
- `src/`: Main source code directory
154+
- `client.py`: Initializes the Restack client
155+
- `functions/`: Contains function definitions
156+
- `workflows/`: Contains workflow definitions
157+
- `services.py`: Sets up and runs the Restack services
158+
- `schedule_workflow.py`: Example script to schedule and run a workflow
159+
- `schedule_interval.py`: Example script to schedule and a workflow every second
160+
- `schedule_scale.py`: Example script to schedule and run 50 workflows at once
161+
162+
# Deployment
163+
164+
Create an account on [Restack Cloud](https://console.restack.io) and follow instructions on site to create a stack and deploy your application on Restack Cloud.

community/lmnt/pyproject.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Project metadata
2+
[tool.poetry]
3+
name = "community_lmnt"
4+
version = "0.0.1"
5+
description = "A simple example to get started with the restack-ai SDK"
6+
authors = [
7+
"Restack Team <[email protected]>",
8+
]
9+
readme = "README.md"
10+
packages = [{include = "src"}]
11+
12+
[tool.poetry.dependencies]
13+
python = ">=3.10,<4.0"
14+
restack-ai = "^0.0.52"
15+
watchfiles = "^1.0.0"
16+
pydantic = "^2.10.5"
17+
lmnt = "1.1.4"
18+
19+
[tool.poetry.dev-dependencies]
20+
pytest = "6.2" # Optional: Add if you want to include tests in your example
21+
22+
# Build system configuration
23+
[build-system]
24+
requires = ["poetry-core"]
25+
build-backend = "poetry.core.masonry.api"
26+
27+
# CLI command configuration
28+
[tool.poetry.scripts]
29+
dev = "src.services:watch_services"
30+
services = "src.services:run_services"
31+
workflow = "schedule_workflow:run_schedule_workflow"
32+
interval = "schedule_interval:run_schedule_interval"
33+
scale = "schedule_scale:run_schedule_scale"

community/lmnt/schedule_interval.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import asyncio
2+
import time
3+
from restack_ai import Restack
4+
from restack_ai.restack import ScheduleSpec, ScheduleIntervalSpec
5+
from datetime import timedelta
6+
7+
async def main():
8+
9+
client = Restack()
10+
11+
workflow_id = f"{int(time.time() * 1000)}-ChildWorkflow"
12+
await client.schedule_workflow(
13+
workflow_name="ChildWorkflow",
14+
workflow_id=workflow_id,
15+
schedule=ScheduleSpec(
16+
intervals=[ScheduleIntervalSpec(
17+
every=timedelta(seconds=1)
18+
)]
19+
)
20+
)
21+
22+
exit(0)
23+
24+
def run_schedule_scale():
25+
asyncio.run(main())
26+
27+
if __name__ == "__main__":
28+
run_schedule_scale()

community/lmnt/schedule_scale.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import asyncio
2+
import time
3+
from restack_ai import Restack
4+
5+
from src.workflows.workflow import ExampleWorkflowInput
6+
7+
async def main():
8+
9+
client = Restack()
10+
11+
workflow_id = f"{int(time.time() * 1000)}-ExampleWorkflow"
12+
await client.schedule_workflow(
13+
workflow_name="ExampleWorkflow",
14+
workflow_id=workflow_id,
15+
input=ExampleWorkflowInput(amount=50)
16+
)
17+
18+
exit(0)
19+
20+
def run_schedule_scale():
21+
asyncio.run(main())
22+
23+
if __name__ == "__main__":
24+
run_schedule_scale()

community/lmnt/schedule_workflow.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import asyncio
2+
import time
3+
from restack_ai import Restack
4+
5+
async def main():
6+
7+
client = Restack()
8+
9+
workflow_id = f"{int(time.time() * 1000)}-ExampleWorkflow"
10+
run_id = await client.schedule_workflow(
11+
workflow_name="ChildWorkflow",
12+
workflow_id=workflow_id
13+
)
14+
15+
await client.get_workflow_result(
16+
workflow_id=workflow_id,
17+
run_id=run_id
18+
)
19+
20+
exit(0)
21+
22+
def run_schedule_workflow():
23+
asyncio.run(main())
24+
25+
if __name__ == "__main__":
26+
run_schedule_workflow()

community/lmnt/src/__init__.py

Whitespace-only changes.

community/lmnt/src/client.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import os
2+
from restack_ai import Restack
3+
from restack_ai.restack import CloudConnectionOptions
4+
from dotenv import load_dotenv
5+
6+
# Load environment variables from a .env file
7+
load_dotenv()
8+
9+
10+
engine_id = os.getenv("RESTACK_ENGINE_ID")
11+
address = os.getenv("RESTACK_ENGINE_ADDRESS")
12+
api_key = os.getenv("RESTACK_ENGINE_API_KEY")
13+
api_address = os.getenv("RESTACK_ENGINE_API_ADDRESS")
14+
15+
connection_options = CloudConnectionOptions(
16+
engine_id=engine_id,
17+
address=address,
18+
api_key=api_key,
19+
api_address=api_address
20+
)
21+
client = Restack(connection_options)

0 commit comments

Comments
 (0)