forked from poe-platform/server-bot-quick-start
-
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.
add examples, configure for gitpod and add other ways of hosting to t…
…he documentation. (poe-platform#3) Co-authored-by: Anmol Singh <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
- Loading branch information
1 parent
46ad2f0
commit 211f0a1
Showing
10 changed files
with
294 additions
and
20 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 @@ | ||
.DS_Store |
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,10 @@ | ||
tasks: | ||
- init: pip install -r requirements.txt | ||
command: | | ||
gp open main.py | ||
uvicorn main:app --reload | ||
ports: | ||
- port: 8000 | ||
visibility: public | ||
onOpen: open-preview |
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 |
---|---|---|
@@ -1 +1 @@ | ||
web: WEB_CONCURRENCY=0 python main.py -p $PORT | ||
web: WEB_CONCURRENCY=0 uvicorn main:app --reload --port $PORT |
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 |
---|---|---|
@@ -1,31 +1,84 @@ | ||
# Heroku Poe sample | ||
# API Bot tutorial | ||
|
||
This is a sample repository for creating Poe API bots on Heroku. For more information on | ||
API bots, see [poe-protocol](https://github.com/poe-platform/poe-protocol). | ||
Welcome to the Poe API Bot tutorial. This repository includes starter code and will help | ||
you quickly get a bot running. As part of this tutorial, we will go over how to deploy | ||
this starter code and how to integrate your bot server with poe. For more information on | ||
Poe API bots, see [poe-protocol](https://github.com/poe-platform/poe-protocol). | ||
|
||
## Getting started | ||
## Deploying your bot | ||
|
||
We will go over three ways of deploying your bot. | ||
|
||
- Using `Gitpod`, a cloud-based IDE (this method is the fastest). | ||
- Using `ngrok` (allows you to make public a bot running on your local computer). | ||
- Using a cloud provider like Heroku (most scalable but the most amount of work). | ||
|
||
### Gitpod | ||
|
||
[Gitpod](https://gitpod.io/) is a browser-based IDE. Among other features, it allows you | ||
to run a publicly accessible Web service as part of your project. To get started: | ||
|
||
- Go to [gitpod.io/workspaces](https://gitpod.io/workspaces) and login or create an | ||
account. | ||
- Click "New Workspace". | ||
- Enter the address of this repo (i.e., | ||
https://github.com/poe-platform/api-bot-tutorial) into the "Context URL" field. | ||
- Hit continue. Gitpod will now take a few minutes to spin up the new workspace. | ||
- Note the URL in the address bar above "FastAPI Poe bot server" (see screenshot). | ||
-  | ||
- This is your bot server URL | ||
|
||
### ngrok | ||
|
||
[ngrok](https://ngrok.com/) is a tool to add Internet connectivity to any service. You | ||
can use it, for example, to make a Poe bot running on your local computer accessible on | ||
the Internet: | ||
|
||
- Install ngrok ([instructions](https://ngrok.com/download)) | ||
- Open a terminal and run: | ||
- `git clone https://github.com/poe-platform/api-bot-tutorial` | ||
- `cd api-bot-tutorial` | ||
- `pip install -r requirements.txt` | ||
- Start your bot server using `uvicorn main:app --reload` | ||
- Confirm that it is running locally by running `curl localhost:8000` | ||
- Run `ngrok http 8000` in another terminal and note the URL it provides, which will | ||
look like `https://1865-99-123-141-32.ngrok-free.app` | ||
- Access that URL in your browser to confirm it works. This is your bot server URL. | ||
|
||
### Heroku | ||
|
||
[Heroku](https://heroku.com) is a cloud platform that makes it easy to deploy simple | ||
apps. | ||
|
||
- Create an account on [heroku.com](https://heroku.com) | ||
- On the website, create a new application. Let's name it $YOUR_APP | ||
- [Install](https://devcenter.heroku.com/articles/heroku-cli#install-the-heroku-cli) the | ||
Heroku CLI | ||
- Login using `heroku login` | ||
- Open the [bot creation page](https://poe.com/create_bot?api=1). An API key will be | ||
pre-generated for you. | ||
- Open a terminal and run: | ||
- `git clone https://github.com/poe-platform/heroku-sample.git` | ||
- `cd heroku-sample` | ||
- `git clone https://github.com/poe-platform/api-bot-tutorial` | ||
- `cd api-bot-tutorial` | ||
- `heroku git:remote -a $YOUR_APP` | ||
- `heroku config:set POE_API_KEY=$POE_API_KEY`, where `$POE_API_KEY` is the API key | ||
you got from [bot creation page](https://poe.com/create_bot?api=1) | ||
- `git push heroku main` | ||
- Now your app should be online at `https://$YOUR_APP.herokuapp.com/` | ||
- Add the URL in the bot creation page | ||
- Hit "Create bot" | ||
- Now your bot is live! | ||
- Now your app should be online at `https://$YOUR_APP.herokuapp.com/`. This is your bot | ||
server URL. | ||
|
||
## Integrating with Poe | ||
|
||
Once you have a bot running under a publicly accessible URL, it is time to connect it to | ||
Poe. You can do that on poe.com at | ||
[the bot creation form](https://poe.com/create_bot?api=1). You can also specify a name | ||
and description for your bot. After you fill out the form and click "create bot", your | ||
bot should be ready for use in all Poe clients! | ||
|
||
## Customize your bot | ||
## Where to go from here | ||
|
||
The above instructions just start a simple bot with no AI capabilities. To make your own | ||
bot, modify `main.py` and push to Heroku again. You can see sample code in the | ||
[poe-protocol](https://github.com/poe-platform/poe-protocol) repository or on | ||
[Replit](https://replit.com/@JelleZijlstra2/Poe-API-Template). | ||
- The starter code by default uses the EchoBot which is a simple bot with no AI | ||
capabilities. You can comment/uncomment any of the other example bots to try them out | ||
or build off of them. | ||
- Refer to [poe-protocol](https://github.com/poe-platform/poe-protocol) to understand | ||
the full capabilities offered by Poe API bots. |
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,109 @@ | ||
""" | ||
Demo bot: catbot. | ||
This bot uses all options provided by the Poe protocol. You can use it to get examples | ||
of all the protocol has to offer. | ||
""" | ||
from __future__ import annotations | ||
|
||
import asyncio | ||
import json | ||
from typing import AsyncIterable | ||
|
||
from fastapi_poe import PoeBot, run | ||
from fastapi_poe.types import ( | ||
ContentType, | ||
QueryRequest, | ||
ReportFeedbackRequest, | ||
SettingsRequest, | ||
SettingsResponse, | ||
) | ||
from sse_starlette.sse import ServerSentEvent | ||
|
||
SETTINGS = SettingsResponse( | ||
context_clear_window_secs=60 * 60, allow_user_context_clear=True | ||
) | ||
|
||
|
||
class CatBot(PoeBot): | ||
async def get_response(self, query: QueryRequest) -> AsyncIterable[ServerSentEvent]: | ||
"""Return an async iterator of events to send to the user.""" | ||
last_message = query.query[-1].content.lower() | ||
response_content_type: ContentType = ( | ||
"text/plain" if "plain" in last_message else "text/markdown" | ||
) | ||
yield self.meta_event( | ||
content_type=response_content_type, | ||
linkify=True, | ||
refetch_settings=False, | ||
suggested_replies="dog" not in last_message, | ||
) | ||
if "markdown" in last_message: | ||
yield self.text_event("# Heading 1\n\n") | ||
yield self.text_event("*Bold text* ") | ||
yield self.text_event("**More bold text**\n") | ||
yield self.text_event("\n") | ||
yield self.text_event("A list:\n") | ||
yield self.text_event("- Item 1\n") | ||
yield self.text_event("- Item 2\n") | ||
yield self.text_event("- An item with [a link](https://poe.com)\n") | ||
yield self.text_event("\n") | ||
yield self.text_event("A table:\n\n") | ||
yield self.text_event("| animal | cuteness |\n") | ||
yield self.text_event("|--------|----------|\n") | ||
yield self.text_event("| cat | 10 |\n") | ||
yield self.text_event("| dog | 1 |\n") | ||
yield self.text_event("\n") | ||
if "cardboard" in last_message: | ||
yield self.text_event("crunch ") | ||
yield self.text_event("crunch") | ||
elif ( | ||
"kitchen" in last_message | ||
or "meal" in last_message | ||
or "food" in last_message | ||
): | ||
yield self.text_event("meow ") | ||
yield self.text_event("meow") | ||
yield self.suggested_reply_event("feed the cat") | ||
elif "stranger" in last_message: | ||
for _ in range(10): | ||
yield self.text_event("peek ") | ||
await asyncio.sleep(1) | ||
elif "square" in last_message: | ||
yield self.error_event("Square snacks are not tasty.") | ||
elif "cube" in last_message: | ||
yield self.error_event( | ||
"Cube snacks are even less tasty.", allow_retry=False | ||
) | ||
elif "count" in last_message: | ||
for i in range(1, 11): | ||
yield self.replace_response_event(str(i)) | ||
if "quickly" not in last_message: | ||
await asyncio.sleep(1) | ||
# These messages make the cat do something that's not allowed by the protocol | ||
elif "scratch" in last_message: | ||
yield ServerSentEvent(event="purr", data=json.dumps({"text": "purr"})) | ||
elif "toy" in last_message: | ||
for _ in range(1010): | ||
yield self.text_event("hit ") | ||
elif "bed" in last_message: | ||
yield self.text_event("z" * 10_010) | ||
else: | ||
yield self.text_event("zzz") | ||
|
||
async def on_feedback(self, feedback: ReportFeedbackRequest) -> None: | ||
"""Called when we receive user feedback such as likes.""" | ||
print( | ||
f"User {feedback.user_id} gave feedback on {feedback.conversation_id}" | ||
f"message {feedback.message_id}: {feedback.feedback_type}" | ||
) | ||
|
||
async def get_settings(self, settings: SettingsRequest) -> SettingsResponse: | ||
"""Return the settings for this bot.""" | ||
return SETTINGS | ||
|
||
|
||
if __name__ == "__main__": | ||
run(CatBot()) |
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,24 @@ | ||
""" | ||
Sample bot that echoes back messages. | ||
This is the simplest possible bot and a great place to start if you want to build your own bot. | ||
""" | ||
from __future__ import annotations | ||
|
||
from typing import AsyncIterable | ||
|
||
from fastapi_poe import PoeBot, run | ||
from fastapi_poe.types import QueryRequest | ||
from sse_starlette.sse import ServerSentEvent | ||
|
||
|
||
class EchoBot(PoeBot): | ||
async def get_response(self, query: QueryRequest) -> AsyncIterable[ServerSentEvent]: | ||
last_message = query.query[-1].content | ||
yield self.text_event(last_message) | ||
|
||
|
||
if __name__ == "__main__": | ||
run(EchoBot()) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,47 @@ | ||
""" | ||
Sample bot that uses LangChain to interact with ChatGPT. | ||
You can use this as a sample if you want to build your own bot on top of an existing LLM. | ||
""" | ||
|
||
import asyncio | ||
from dataclasses import dataclass | ||
from typing import AsyncIterable | ||
|
||
from fastapi_poe import PoeBot | ||
from fastapi_poe.types import QueryRequest | ||
from langchain.callbacks import AsyncIteratorCallbackHandler | ||
from langchain.callbacks.manager import AsyncCallbackManager | ||
from langchain.chat_models import ChatOpenAI | ||
from langchain.schema import AIMessage, HumanMessage, SystemMessage | ||
from sse_starlette.sse import ServerSentEvent | ||
|
||
template = """You are an automated cat. | ||
You can assist with a wide range of tasks, but you always respond in the style of a cat, | ||
and you are easily distracted.""" | ||
|
||
|
||
@dataclass | ||
class LangCatBot(PoeBot): | ||
openai_key: str | ||
|
||
async def get_response(self, query: QueryRequest) -> AsyncIterable[ServerSentEvent]: | ||
messages = [SystemMessage(content=template)] | ||
for message in query.query: | ||
if message.role == "bot": | ||
messages.append(AIMessage(content=message.content)) | ||
elif message.role == "user": | ||
messages.append(HumanMessage(content=message.content)) | ||
handler = AsyncIteratorCallbackHandler() | ||
chat = ChatOpenAI( | ||
openai_api_key=self.openai_key, | ||
streaming=True, | ||
callback_manager=AsyncCallbackManager([handler]), | ||
temperature=0, | ||
) | ||
asyncio.create_task(chat.agenerate([messages])) | ||
async for token in handler.aiter(): | ||
yield self.text_event(token) |
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 |
---|---|---|
@@ -1,4 +1,32 @@ | ||
from fastapi_poe import run | ||
from fastapi_poe.samples.catbot import CatBot | ||
# Welcome to the Poe API tutorial. The starter code provided provides you with a quick way to get | ||
# a bot running. By default, the starter code uses the EchoBot, which is a simple bot that echos | ||
# a message back at its user and is a good starting point for your bot, but you can | ||
# comment/uncomment any of the following code to try out other example bots. | ||
|
||
run(CatBot()) | ||
from fastapi_poe import make_app | ||
|
||
# Echo bot is a very simple bot that just echoes back the user's last message. | ||
from echobot import EchoBot | ||
|
||
bot = EchoBot() | ||
|
||
# A sample bot that showcases the capabilities the protocol provides. Please see the | ||
# following link for the full set of available message commands: | ||
# https://github.com/poe-platform/poe-protocol/blob/main/docs/catbot.md | ||
# from catbot import CatBot | ||
# bot = CatBot() | ||
|
||
# A custom chatbot built on top of ChatGPT and LangChain. | ||
# Add your OpenAI key here, e.g. sk-1234 | ||
# You can obtain a key at https://platform.openai.com/account/api-keys | ||
# OPEN_AI_API_KEY = "" | ||
# from langcatbot import LangCatBot | ||
# bot = LangCatBot(OPEN_AI_API_KEY) | ||
|
||
# Optionally add your Poe API key here. You can go to https://poe.com/create_bot?api=1 to generate | ||
# one. We strongly recommend adding this key for a production bot to prevent abuse, | ||
# but the starter example disables the key check for convenience. | ||
# POE_API_KEY = "" | ||
# app = make_app(bot, api_key=POE_API_KEY) | ||
|
||
app = make_app(bot, allow_without_key=True) |
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 |
---|---|---|
@@ -1 +1,3 @@ | ||
fastapi-poe==0.0.11 | ||
fastapi-poe==0.0.12 | ||
langchain==0.0.166 | ||
openai==0.27.6 |