Skip to content

Commit

Permalink
add examples, configure for gitpod and add other ways of hosting to t…
Browse files Browse the repository at this point in the history
…he documentation. (poe-platform#3)

Co-authored-by: Anmol Singh <[email protected]>
Co-authored-by: Jelle Zijlstra <[email protected]>
  • Loading branch information
3 people authored May 12, 2023
1 parent 46ad2f0 commit 211f0a1
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
10 changes: 10 additions & 0 deletions .gitpod.yml
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
2 changes: 1 addition & 1 deletion Procfile
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
83 changes: 68 additions & 15 deletions README.md
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).
- ![Screenshot of a Gitpod page with the URL for the server circled.](./images/gitpod.png)
- 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.
109 changes: 109 additions & 0 deletions catbot.py
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())
24 changes: 24 additions & 0 deletions echobot.py
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())
Binary file added images/gitpod.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions langcatbot.py
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)
34 changes: 31 additions & 3 deletions main.py
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)
4 changes: 3 additions & 1 deletion requirements.txt
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

0 comments on commit 211f0a1

Please sign in to comment.