-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* docs: add example Signed-off-by: Isac Byeonghoon Yoo <[email protected]> * docs: update usage Signed-off-by: Isac Byeonghoon Yoo <[email protected]> * docs: update usage Signed-off-by: Isac Byeonghoon Yoo <[email protected]> --------- Signed-off-by: Isac Byeonghoon Yoo <[email protected]>
- Loading branch information
Showing
5 changed files
with
1,024 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FROM python:3.11-slim as build | ||
WORKDIR /opt/app | ||
EXPOSE 8000 | ||
ENTRYPOINT ["poetry", "run", "python", "/opt/app/main.py"] | ||
|
||
COPY poetry.lock pyproject.toml main.py ./ | ||
RUN pip install -U poetry \ | ||
&& poetry install --no-root --sync |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# PlugBear Python SDK Example (FastAPI) | ||
|
||
## Prerequisites | ||
|
||
- Docker | ||
|
||
## Usage | ||
|
||
This will create a math tutor AI. | ||
You can make a query on any integrated channel, like this: ``@PlugBear I need to solve the equation `3x + 11 = 14`. Can you help me?``. | ||
|
||
```shell | ||
docker build . -t plugbear-python-sdk-example | ||
docker run --rm -ti \ | ||
-p 8000:8000 \ | ||
-e PLUGBEAR_API_KEY="YOUR.PLUGBEAR.API.KEY" \ | ||
-e OPENAI_API_KEY="YOUR.OPENAI.API.KEY" \ | ||
plugbear-python-sdk-example | ||
``` | ||
|
||
You can also existing assistant by passing `OPENAI_ASSISTANT_ID` environment to `docker run`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
from __future__ import annotations | ||
|
||
import asyncio | ||
import contextlib | ||
import os | ||
from collections.abc import AsyncGenerator | ||
|
||
from fastapi import FastAPI | ||
from openai import AsyncOpenAI | ||
from openai.pagination import AsyncCursorPage | ||
from openai.types.beta.threads import MessageContentText, ThreadMessage | ||
|
||
import plugbear.fastapi | ||
|
||
|
||
# create a OpenAI Assistant if the user does not enter an OpenAi Assistant ID. | ||
async def _get_openai_assistant_id(client: AsyncOpenAI) -> str: | ||
try: | ||
return os.environ["OPENAI_ASSISTANT_ID"] | ||
except KeyError: | ||
assistant = await client.beta.assistants.create( | ||
name="Math Tutor", | ||
instructions="You are a personal math tutor. Write and run code to answer math questions.", | ||
tools=[{"type": "code_interpreter"}], | ||
model="gpt-4-1106-preview", | ||
) | ||
return assistant.id | ||
|
||
|
||
openai_client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"]) | ||
openai_assistant_id = asyncio.get_event_loop().run_until_complete(_get_openai_assistant_id(openai_client)) | ||
|
||
|
||
async def openai_assistant(request: plugbear.fastapi.Request) -> str: | ||
thread = await openai_client.beta.threads.create() | ||
|
||
joined_msg = "\n".join(m.content for m in request.messages) | ||
await openai_client.beta.threads.messages.create( | ||
thread_id=thread.id, | ||
role="user", | ||
content=joined_msg, | ||
) | ||
|
||
run = await openai_client.beta.threads.runs.create( | ||
thread_id=thread.id, | ||
assistant_id=openai_assistant_id, | ||
instructions="Please address the user as Jane Doe. The user has a premium account.", | ||
) | ||
|
||
while run.status != "completed": | ||
await asyncio.sleep(1) | ||
run = await openai_client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id) | ||
|
||
messages = await openai_client.beta.threads.messages.list(thread_id=thread.id) | ||
print(messages) | ||
return _join_assistant_messages(messages) | ||
|
||
|
||
def _join_assistant_messages(m: AsyncCursorPage[ThreadMessage]) -> str: | ||
messages: list[str] = [] | ||
for data in m.data: | ||
if data.role != "assistant": | ||
continue | ||
|
||
for content in data.content: | ||
if not isinstance(content, MessageContentText): | ||
continue | ||
messages.append(content.text.value) | ||
|
||
return "\n".join(messages) | ||
|
||
|
||
@contextlib.asynccontextmanager | ||
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: | ||
await plugbear.fastapi.register( | ||
app, | ||
llm_func=openai_assistant, | ||
api_key=os.environ["PLUGBEAR_API_KEY"], | ||
endpoint=os.getenv("PLUGBEAR_ENDPOINT", default="/plugbear"), | ||
) | ||
|
||
yield | ||
|
||
|
||
app = FastAPI(lifespan=lifespan) | ||
|
||
if __name__ == "__main__": | ||
import uvicorn | ||
|
||
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", default=8000))) |
Oops, something went wrong.