-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Deploy ChatInterface as a discord bot #4960
Merged
Merged
Changes from 42 commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
3b48c1a
WIP
freddyaboulton 952dfce
Handle queue full message
freddyaboulton e30c4af
Add code
freddyaboulton e1c6c49
Fix types
freddyaboulton 7d7d034
Format
freddyaboulton 24986a5
Add docstring
freddyaboulton 707101f
Rephrase
freddyaboulton 5c5879e
cli conflicts
freddyaboulton 7fafe72
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton 32aeb59
WIP
freddyaboulton 921b510
Handle queue full message
freddyaboulton e71a87a
Add code
freddyaboulton 9903025
Fix types
freddyaboulton f58b365
Format
freddyaboulton 5b4d252
Add docstring
freddyaboulton dc01147
Rephrase
freddyaboulton 1b68ee0
cli conflicts
freddyaboulton 6bcde6c
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton 3e2d27b
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton 8e49ae7
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton cd7ad5b
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton 27fad74
Figure out how slash commands work
freddyaboulton 8fbb183
merge upstream
freddyaboulton e50d83e
Lint
freddyaboulton ecbccce
Fix new name situation
freddyaboulton 5acc555
Dont auto archive
freddyaboulton 993ab61
Merge branch 'main' into deploy-chatinterface-to-discord
abidlabs d3728e6
add code
freddyaboulton 030480d
Explain sync
freddyaboulton e78ad2f
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton 79d0302
add changeset
gradio-pr-bot 08085a2
Update client/python/gradio_client/cli/deploy_discord.py
freddyaboulton 7eb589e
Make more general
freddyaboulton 3fcbbb1
Fix check
freddyaboulton d0d08b3
add changeset
gradio-pr-bot 0694beb
Add guide
freddyaboulton 03a6a04
Merge branch 'deploy-chatinterface-to-discord' of github.com:gradio-a…
freddyaboulton 218aa5a
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton de50c81
Step-by-step guide
freddyaboulton ab5ab8b
Add tip on login via cli
freddyaboulton 3e68391
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton 29e3bfe
Fix template - auto synch
freddyaboulton 355e18a
Add note on space sleeptime
freddyaboulton 0afb767
add changeset
gradio-pr-bot 48269f7
Add more info for feature
freddyaboulton 20ff1f0
Add img
freddyaboulton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,6 @@ | ||
--- | ||
"gradio": minor | ||
"gradio_client": minor | ||
--- | ||
|
||
feat:Deploy ChatInterface as a discord bot |
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,3 @@ | ||
from gradio_client.cli import deploy_discord | ||
|
||
__all__ = ["deploy_discord"] |
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,58 @@ | ||
import argparse | ||
|
||
from gradio_client import Client | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description="Deploy Space as Discord Bot.") | ||
parser.add_argument("deploy-discord") | ||
parser.add_argument( | ||
"--src", | ||
type=str, | ||
help="The space id or url or gradio app you want to deploy as a gradio bot.", | ||
) | ||
parser.add_argument( | ||
"--discord-bot-token", | ||
type=str, | ||
help="Discord bot token. Get one on the discord website.", | ||
) | ||
parser.add_argument( | ||
"--api-names", | ||
nargs="*", | ||
help="Api names to turn into discord bots", | ||
default=[], | ||
) | ||
parser.add_argument( | ||
"--to-id", | ||
type=str, | ||
help="Name of the space used to host the discord bot", | ||
default=None, | ||
) | ||
parser.add_argument( | ||
"--hf-token", | ||
type=str, | ||
help=( | ||
"Hugging Face token. Can be ommitted if you are logged in via huggingface_hub cli. " | ||
"Must be provided if upstream space is private." | ||
), | ||
default=None, | ||
) | ||
parser.add_argument( | ||
"--private", | ||
type=bool, | ||
nargs="?", | ||
help="Whether the discord bot space is private.", | ||
const=True, | ||
default=False, | ||
) | ||
args = parser.parse_args() | ||
for i, name in enumerate(args.api_names): | ||
if "," in name: | ||
args.api_names[i] = tuple(name.split(",")) | ||
Client(args.src).deploy_discord( | ||
discord_bot_token=args.discord_bot_token, | ||
api_names=args.api_names, | ||
to_id=args.to_id, | ||
hf_token=args.hf_token, | ||
private=args.private, | ||
) |
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 |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import json | ||
import os | ||
import re | ||
import secrets | ||
import tempfile | ||
import threading | ||
import time | ||
|
@@ -20,7 +21,7 @@ | |
import huggingface_hub | ||
import requests | ||
import websockets | ||
from huggingface_hub import SpaceHardware, SpaceStage | ||
from huggingface_hub import CommitOperationAdd, SpaceHardware, SpaceStage | ||
from huggingface_hub.utils import ( | ||
RepositoryNotFoundError, | ||
build_hf_headers, | ||
|
@@ -603,6 +604,147 @@ def _get_config(self) -> dict: | |
) | ||
return config | ||
|
||
def deploy_discord( | ||
self, | ||
discord_bot_token: str | None = None, | ||
api_names: list[str | tuple[str, str]] | None = None, | ||
to_id: str | None = None, | ||
hf_token: str | None = None, | ||
private: bool = False, | ||
): | ||
""" | ||
Deploy the upstream app as a discord bot. Currently only supports gr.ChatInterface. | ||
Parameters: | ||
discord_bot_token: This is the "password" needed to be able to launch the bot. Users can get a token by creating a bot app on the discord website. If run the method without specifying a token, the space will explain how to get one. See here: https://huggingface.co/spaces/freddyaboulton/test-discord-bot-v1. | ||
api_names: The api_names of the app to turn into bot commands. This parameter currently has no effect as ChatInterface only has one api_name ('/chat'). | ||
to_id: The name of the space hosting the discord bot. If None, the name will be gradio-discord-bot-{random-substring} | ||
hf_token: HF api token with write priviledges in order to upload the files to HF space. Can be ommitted if logged in via the HuggingFace CLI, unless the upstream space is private. Obtain from: https://huggingface.co/settings/token | ||
private: Whether the space hosting the discord bot is private. The visibility of the discord bot itself is set via the discord website. See https://huggingface.co/spaces/freddyaboulton/test-discord-bot-v1 | ||
""" | ||
|
||
if self.config["mode"] == "chat_interface" and not api_names: | ||
api_names = [("chat", "chat")] | ||
|
||
valid_list = isinstance(api_names, list) and ( | ||
isinstance(n, str) | ||
or ( | ||
isinstance(n, tuple) and isinstance(n[0], str) and isinstance(n[1], str) | ||
) | ||
for n in api_names | ||
) | ||
if api_names is None or not valid_list: | ||
raise ValueError( | ||
f"Each entry in api_names must be either a string or a tuple of strings. Received {api_names}" | ||
) | ||
assert ( | ||
len(api_names) == 1 | ||
), "Currently only one api_name can be deployed to discord." | ||
|
||
for i, name in enumerate(api_names): | ||
if isinstance(name, str): | ||
api_names[i] = (name, name) | ||
|
||
fn = next( | ||
(ep for ep in self.endpoints if ep.api_name == f"/{api_names[0][0]}"), None | ||
) | ||
if not fn: | ||
raise ValueError( | ||
f"api_name {api_names[0][0]} not present in {self.space_id or self.src}" | ||
) | ||
inputs = [ | ||
inp for inp in fn.input_component_types if fn not in utils.SKIP_COMPONENTS | ||
] | ||
outputs = [ | ||
inp for inp in fn.input_component_types if fn not in utils.SKIP_COMPONENTS | ||
] | ||
if not inputs == ["textbox"] and outputs == ["textbox"]: | ||
raise ValueError( | ||
"Currently only api_names with a single textbox as input and output are supported. " | ||
f"Received {inputs} and {outputs}" | ||
) | ||
|
||
is_private = False | ||
if self.space_id: | ||
is_private = huggingface_hub.space_info(self.space_id).private | ||
if is_private: | ||
assert hf_token, ( | ||
f"Since {self.space_id} is private, you must explicitly pass in hf_token " | ||
"so that it can be added as a secret in the discord bot space." | ||
) | ||
|
||
if to_id: | ||
if "/" in to_id: | ||
to_id = to_id.split("/")[1] | ||
space_id = huggingface_hub.get_full_repo_name(to_id, token=hf_token) | ||
else: | ||
if self.space_id: | ||
space_id = f'{self.space_id.split("/")[1]}-gradio-discord-bot' | ||
else: | ||
space_id = f"gradio-discord-bot-{secrets.token_hex(4)}" | ||
space_id = huggingface_hub.get_full_repo_name(space_id, token=hf_token) | ||
|
||
api = huggingface_hub.HfApi() | ||
|
||
try: | ||
huggingface_hub.space_info(space_id) | ||
first_upload = False | ||
except huggingface_hub.utils.RepositoryNotFoundError: | ||
first_upload = True | ||
|
||
huggingface_hub.create_repo( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is doing this really needed? I think you can use |
||
space_id, | ||
repo_type="space", | ||
space_sdk="gradio", | ||
token=hf_token, | ||
exist_ok=True, | ||
private=private, | ||
) | ||
if first_upload: | ||
huggingface_hub.metadata_update( | ||
repo_id=space_id, | ||
repo_type="space", | ||
metadata={"tags": ["gradio-discord-bot"]}, | ||
) | ||
|
||
with open(str(Path(__file__).parent / "templates" / "discord_chat.py")) as f: | ||
app = f.read() | ||
app = app.replace("<<app-src>>", self.src) | ||
app = app.replace("<<api-name>>", api_names[0][0]) | ||
app = app.replace("<<command-name>>", api_names[0][1]) | ||
|
||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as app_file: | ||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as requirements: | ||
app_file.write(app) | ||
requirements.write("\n".join(["discord.py==2.3.1"])) | ||
|
||
operations = [ | ||
CommitOperationAdd(path_in_repo="app.py", path_or_fileobj=app_file.name), | ||
CommitOperationAdd( | ||
path_in_repo="requirements.txt", path_or_fileobj=requirements.name | ||
), | ||
] | ||
|
||
api.create_commit( | ||
repo_id=space_id, | ||
commit_message="Deploy Discord Bot", | ||
repo_type="space", | ||
operations=operations, | ||
token=hf_token, | ||
) | ||
|
||
if discord_bot_token: | ||
huggingface_hub.add_space_secret( | ||
space_id, "DISCORD_TOKEN", discord_bot_token, token=hf_token | ||
) | ||
if is_private: | ||
huggingface_hub.add_space_secret( | ||
space_id, "HF_TOKEN", hf_token, token=hf_token | ||
) | ||
|
||
url = f"https://huggingface.co/spaces/{space_id}" | ||
print(f"See your discord bot here! {url}") | ||
return url | ||
|
||
|
||
class Endpoint: | ||
"""Helper class for storing all the information about a single API endpoint.""" | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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: maybe it should reflect the name of the original Space as well?
gradio-discord-bot-{space-id}-{random-substring}
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.
Fixed this - the name of the bot space will use the upstream space name and add
gradio-discord-bot
ifto_id
is not passed in.