-
Notifications
You must be signed in to change notification settings - Fork 11
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
Initial submission #1
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work 💯
left a few comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking fabulous and thank you for submitting! ❤️ I have a few requested changes I think would help improve the documentation aspect of the app.
to avoid a huge wave of comments all at once, i'm going to split reviewing into different parts, starting with the README - leaving the first round of feedback for the README. in the next pass, I will re-review the README and then review the ai
directory, and so on (each pass I'll note what specific sections I'm reviewing for clarity)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙌 phenomenal! This iteration I reviewed the README
again as well as all files in ai
folder, manifest.json
, requirements.txt
, and slack.json
- I will cover /listeners
next and also start testing the functionality of the app more in the next iteration! 🙌
ai/ai_utils/get_available_apis.py
Outdated
from ai.providers.openai import OpenAI_API | ||
|
||
""" | ||
New providers need to be added below |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New providers need to be added below | |
New AI providers must be added below |
Maybe also add a note of what the file does in this comment! Ex: This file _________. New AI providers must be added below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work already! Left a few comments but you don't need to resolve all of them at all! Hope some of these help you polish the details!
ai/ai_utils/handle_response.py
Outdated
return AnthropicAPI() | ||
|
||
|
||
def get_ai_response(user_id: str, prompt: str, context: list = [], system_content=DEFAULT_SYSTEM_CONTENT): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing a mutable object as the default argument value is a common pitfall in python; you can change the argument type to Optional[List[X]]
and set None
as the default value instead: https://docs.quantifiedcode.com/python-anti-patterns/correctness/mutable_default_value_as_argument.html
ai/providers/anthropic.py
Outdated
raise ValueError("Invalid model") | ||
self.current_model = model_name | ||
|
||
def get_models(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice-to-have but having return more types can make the code maintenance easier
def get_models(self): | |
def get_models(self) -> dict: |
ai/providers/base_provider.py
Outdated
self.api_key: str | ||
|
||
def set_model(self, model_name: str): | ||
self.current_model = model_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you raise an exception here, this line of code won't be used
self.current_model = model_name |
ai/providers/openai.py
Outdated
|
||
def generate_response(self, prompt: str, system_content: str) -> str: | ||
try: | ||
client = openai.OpenAI(api_key=self.api_key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can set up this instance within the constructor and have the instance as an instance field (self.client) to eliminate a very slight overhead here
) | ||
return response.choices[0].message.content | ||
except openai.APIConnectionError as e: | ||
Logger.error(f"Server could not be reached: {e.__cause__}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Printing error logs is a good idea! If this app wants to tell the end-user what's happening, this code may want to return the text to display in Slack UI rather than returning nothing.
manifest.json
Outdated
"channel_id":{ | ||
"type":"slack#/types/channel_id", | ||
"title":"Channel", | ||
"description":"Channel that user joined", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this app's bot user has to be a member of the channel, right? If yes, this app may want to have the permission to use conversations.join API. If it's not suitable for this app, the description should mention the workflow user has to manually invite the bot.
state_store/state_store.py
Outdated
from .user_identity import UserIdentity | ||
|
||
|
||
class StateStore: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: UserStateStore may sound even clearer to me.
ai/providers/base_provider.py
Outdated
# A base class for API providers, defining the interface and common properties for subclasses. | ||
|
||
|
||
class BaseProvider: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, having "API" in the name (e.g., BaseAPIProvider) may be clearer.
ai/ai_utils/handle_response.py
Outdated
""" | ||
|
||
|
||
def _get_provider(api_name: str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: these strings are actually names of the service providers, not the API names (I mean "Chat Completions" is an API name). renaming the argument to provider_name: str and the method to _resolve_api_provider() may be an alternative way to name them.
state_store/user_identity.py
Outdated
|
||
class UserIdentity(TypedDict): | ||
user_id: str | ||
api: str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this can be either "openai" or "anthoropic", it sounds like "provider"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when trying to run the slash command or dm bolty, I keep getting the following error: missing 1 required positional argument: 'msg'
😢 do you know what could be causing this?
README.md
Outdated
@@ -19,18 +29,20 @@ Before you can run the app, you'll need to store some environment variables. | |||
2. Click ***Basic Information** from the left hand menu and follow the steps in the App-Level Tokens section to create an app-level token with the `connections:write` scope. Copy this token. You will store this in your environment as `SLACK_APP_TOKEN`. | |||
|
|||
```zsh | |||
# Replace with your app token and bot token | |||
# Replace with your app token, bot token, and the token for whichever API(s) you plan on using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specify how to configure these env vars - by running in terminal
ai/__init__.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is empty, do we need it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mentioning the bot results in the following error: ERROR:app.py:app_mentioned_callback:parse_conversation() takes 1 positional argument but 2 were given
listeners/commands/ask_command.py
Outdated
from ai.ai_utils.handle_response import get_ai_response | ||
|
||
|
||
def ask_callback(ack: Ack, command, say: Say, logger: Logger, context: BoltContext): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's add a comment for this callback detailing what feature it's connected to and what it does!
listeners/events/app_home_opened.py
Outdated
|
||
|
||
def app_home_opened_callback(client, event, logger: Logger): | ||
# ignore the app_home_opened event for anything but the Home tab | ||
def app_home_opened_callback(event, logger: Logger, client: WebClient, context: BoltContext): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's add a comment for this callback detailing what feature it's connected to and what it does!
Did it create a user file for you? It usually means it cant find your provider selection. |
i removed bot_id from the parameters for parse_conversation(). my bad, i missed that! |
It did! 😲 maybe it's having trouble reading it? |
unblocked on my end - errors were being thrown because i didn't have credits on my account 😢 got some working API keys for each service and it's working now, will test more tomorrow and leave an updated review ❤️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Big fan of the magic with Bolty ⚡ 🤖
The code is looking great and the feature set is so solid. Approving it now but I think some of the comments are worth addressing before merging- also feel free to ping me for more review! 🔍
Most of the comments I left are around file structure and naming which isn't too important but I think a few changes might make it easier to start changing things as an exploring developer. This will be quite a nice sample to explore 😄 🚀
manifest.json
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can this file be linted for indentation- https://jsonlint.com? 🙏
Edit- I'm a fan of 2
or 4
spaces but can never decide myself lol. I would just avoid 3
or 5
or 1
or even 11
with all importance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its black's formatting. should the readme instructions be black *.py
instead of black .
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might also have a extra space indentation 👾
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* `handle_response.py`: Processes responses from API providers. | ||
<a name="byo-llm"></a> | ||
#### `ai/providers` | ||
This module contains classes for communicating with different API providers, such as [Anthropic](https://www.anthropic.com/) and [OpenAI](https://openai.com/). To add your own LLM, create a new class for it using the `base_provider.py` as an example, then update `get_available_apis.py` and `handle_response.py` to include and utilize your new class for API communication. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A section on state_store
would also be nice to have here 📚 👀
state_store/state_store.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the get_user_state
and set_user_state
methods be moved into this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set_user_state creates a FileStateStore object which inherits from UserStateStore though
listeners/events/app_home_opened.py
Outdated
# add an empty option if the user has no previously selected model. | ||
options.append( | ||
{ | ||
"text": {"type": "plain_text", "text": " ", "emoji": True}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we change this the text to "None selected" or something similar? Blank might be confusing at first glance 👁️🗨️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about Select a provider
ai/ai_utils/handle_response.py
Outdated
def _get_provider(provider_name: str): | ||
if provider_name.lower() == "openai": | ||
return OpenAI_API() | ||
if provider_name.lower() == "anthropic": | ||
return AnthropicAPI() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also not sure if this is possible, but it'd be neat if this could be from __new__
in an ai/providers/__init__.py
file
.gitignore
Outdated
!data/.gitkeep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be replaced with the following in a data/.gitignore
instead 👀
*
!.gitignore
.gitignore
Outdated
data/* | ||
!data/.gitkeep | ||
.slack/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll just want to recommend ignoring
.slack/apps.dev.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think these utils can be moved to the top level listeners
for easier editing. IMO these could even be one conversation.py
file but this can also be ignored altogether!
manifest.json
Outdated
"oauth_config": { | ||
"scopes": { | ||
"bot": [ | ||
"commands", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit but it's nice to alphabetize these lists for fast scanning
# and formats it as a string with user IDs and their messages. | ||
# Used in `app_mentioned_callback`, `dm_sent_callback`, | ||
# and `handle_summary_function_callback`. | ||
def parse_conversation(conversation: str) -> Optional[List[dict]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
conversation's type hint looks incorrect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: Running https://github.com/google/pytype may help you detect this type of error
|
||
# Change into this project directory | ||
cd bolt-python-starter-template | ||
cd bolt-python-ai-chatbot | ||
|
||
# Setup your python virtual environment | ||
python3 -m venv .venv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can add a note here after the setup instructions to also make sure you select a provider from the app home before you try mentioning the bot, using slash commands, or dming them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with the new error handling the bot tells them directly when they interact with it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, excellent work! This is such a great addition to our collection of samples! 🙌
Type of change (place an x in the [ ] that applies)
Summary
This PR introduces a new sample app that uses OpenAI and Anthropic APIs to generate responses to user prompts. The app showcases various interaction methods including DMs, app mentions, and a custom /ask command, while also supporting Bring Your Own Bot (BYOB) functionality and custom function implementation.
Requirements (place an x in each [ ] that applies)