Skip to content
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 46 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
3b48c1a
WIP
freddyaboulton Jul 18, 2023
952dfce
Handle queue full message
freddyaboulton Jul 18, 2023
e30c4af
Add code
freddyaboulton Jul 18, 2023
e1c6c49
Fix types
freddyaboulton Jul 18, 2023
7d7d034
Format
freddyaboulton Jul 18, 2023
24986a5
Add docstring
freddyaboulton Jul 18, 2023
707101f
Rephrase
freddyaboulton Jul 19, 2023
5c5879e
cli conflicts
freddyaboulton Jul 19, 2023
7fafe72
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton Jul 20, 2023
32aeb59
WIP
freddyaboulton Jul 18, 2023
921b510
Handle queue full message
freddyaboulton Jul 18, 2023
e71a87a
Add code
freddyaboulton Jul 18, 2023
9903025
Fix types
freddyaboulton Jul 18, 2023
f58b365
Format
freddyaboulton Jul 18, 2023
5b4d252
Add docstring
freddyaboulton Jul 18, 2023
dc01147
Rephrase
freddyaboulton Jul 19, 2023
1b68ee0
cli conflicts
freddyaboulton Jul 19, 2023
6bcde6c
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton Jul 21, 2023
3e2d27b
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton Jul 21, 2023
8e49ae7
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton Jul 21, 2023
cd7ad5b
Update client/python/gradio_client/templates/discord_chat.py
freddyaboulton Jul 21, 2023
27fad74
Figure out how slash commands work
freddyaboulton Jul 21, 2023
8fbb183
merge upstream
freddyaboulton Jul 21, 2023
e50d83e
Lint
freddyaboulton Jul 21, 2023
ecbccce
Fix new name situation
freddyaboulton Jul 21, 2023
5acc555
Dont auto archive
freddyaboulton Jul 21, 2023
993ab61
Merge branch 'main' into deploy-chatinterface-to-discord
abidlabs Jul 21, 2023
d3728e6
add code
freddyaboulton Jul 21, 2023
030480d
Explain sync
freddyaboulton Jul 21, 2023
e78ad2f
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton Jul 24, 2023
79d0302
add changeset
gradio-pr-bot Jul 24, 2023
08085a2
Update client/python/gradio_client/cli/deploy_discord.py
freddyaboulton Jul 24, 2023
7eb589e
Make more general
freddyaboulton Jul 25, 2023
3fcbbb1
Fix check
freddyaboulton Jul 25, 2023
d0d08b3
add changeset
gradio-pr-bot Jul 25, 2023
0694beb
Add guide
freddyaboulton Jul 25, 2023
03a6a04
Merge branch 'deploy-chatinterface-to-discord' of github.com:gradio-a…
freddyaboulton Jul 25, 2023
218aa5a
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton Jul 25, 2023
de50c81
Step-by-step guide
freddyaboulton Jul 25, 2023
ab5ab8b
Add tip on login via cli
freddyaboulton Jul 26, 2023
3e68391
Merge branch 'main' into deploy-chatinterface-to-discord
freddyaboulton Jul 26, 2023
29e3bfe
Fix template - auto synch
freddyaboulton Jul 26, 2023
355e18a
Add note on space sleeptime
freddyaboulton Jul 26, 2023
0afb767
add changeset
gradio-pr-bot Jul 26, 2023
48269f7
Add more info for feature
freddyaboulton Jul 26, 2023
20ff1f0
Add img
freddyaboulton Jul 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/eleven-turkeys-talk.md
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
3 changes: 3 additions & 0 deletions client/python/gradio_client/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from gradio_client.cli import deploy_discord

__all__ = ["deploy_discord"]
58 changes: 58 additions & 0 deletions client/python/gradio_client/cli/deploy_discord.py
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,
)
144 changes: 143 additions & 1 deletion client/python/gradio_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
import os
import re
import secrets
import tempfile
import threading
import time
Expand All @@ -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,
Expand Down Expand Up @@ -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}
Copy link
Member

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}

Copy link
Collaborator Author

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 if to_id is not passed in.

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is doing this really needed? I think you can use huggingface_hub.duplicate_space and let it handle the duplication

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."""
Expand Down
Loading