def upload_and_deploy(package: AnyStr, bot_uid: str = None) -> str: """Uploads the given archive, triggering deployment of the chatbot. :param package: Path to the packaged chatbot zip. :param bot_uid: Used to modify an existing bot: the UID of the previously-deployed bot. :return bot_uid: The UID of the deployed bot. """ package = Path(package) deployment_file = package.parent / "_deployment" if deployment_file.exists() and bot_uid is None: with deployment_file.open("r") as f: previous_bot_uid = f.read().strip() print("Detected previous deployment from this location. Use the same bot UID as before?") print(f" [y] (default) Yes. Update the bot ({previous_bot_uid}).") print(f" [n] No. Deploy as a new bot.") input_key = input().lower() if input_key == "y" or input_key == "": bot_uid = previous_bot_uid print(f"Using previous bot UID: {bot_uid}") elif input_key == "n": pass else: raise RuntimeError("Unknown input.") auth = get_auth() try: r = requests.post( ENDPOINT, params={'uid': auth.uid, 'key': auth.key, 'bot_uid': bot_uid} ) try: r.raise_for_status() except Exception: raise RuntimeError(r.json()) except Exception: print(r.content, r.reason) raise RuntimeError("Failed to retrieve signed URL.") url = r.text if bot_uid is None: print("Creating new bot.") bot_uid = parse_signed_url_for_bot_uid(url) print(f"Received bot UID: {bot_uid}") with deployment_file.open("w") as f: f.write(bot_uid) with package.open("rb") as f: r = requests.put(url, data=f, headers={'content-type': 'application/zip'}) r.raise_for_status() print(f"Successfully uploaded {package}.") return bot_uid
class Metadata: """Information required for bot deployment.""" # Name of the bot. name: str # Profile image for the bot. Has to be a valid URL. image_url: str # The alphanumeric part of a hex color code. (E.g. ffffff) color: str # Description of the bot. description: str # Python class (N.B. not object!) that inherits from ChaiBot. input_class: Type[ChaiBot] # Developer Unique ID. developer_uid: str = field(default_factory=lambda: get_auth().uid) # Total available memory for the bot in MB. This includes memory needed to store sources and data. memory: int = 256 def verify(self, bot_file: Path): """Performs basic checks to ensure validity of the metadata.""" assert isinstance(self.name, str) assert len(self.name) >= 3, "Bot name has to be at least 3 characters." assert len(self.description) > 0, "Bot has to have description." assert self.input_class.__init__ is ChaiBot.__init__, \ "Do not override ChaiBot.__init__(). Override the setup() method instead." assert not (bot_file.parent / "main.py").exists( ), "Do not create a main.py file in your bot's root directory." try: verify_image_url(self.image_url) except Exception: raise ValueError(f"Could not verify image url ({self.image_url})") assert isinstance(self.color, str) assert re.search(r"^(?:[0-9a-fA-F]{3}){1,2}$", self.color), \ f"Color has to be provided as the alphanumeric part of the hex code (e.g. ffffff), found {self.color}" assert isinstance( self.memory, int ), f"Attribute .memory has to be an integer (found type {type(self.memory)})." assert self.memory <= MAX_SUPPORTED_MEMORY, f"Attribute .memory has to be less than or equal to {MAX_SUPPORTED_MEMORY} (found {self.memory})."
def delete_bot(bot_uid: str) -> str: """ Uses an HTTPS request to trigger deletion of bot with specified UID. :param bot_uid: :return: The url for the bot. """ auth = get_auth() try: req = requests.delete( url=ENDPOINT, params={'uid': auth.uid, 'key': auth.key, 'bot_uid': bot_uid} ) try: req.raise_for_status() except Exception: raise RuntimeError(req.json()) except Exception as exc: raise RuntimeError(f"Failed to delete bot {bot_uid}.") print(f"Successfully deleted {bot_uid}.") return bot_uid
def get_logs(bot_uid: str, errors: bool = False) -> List[Log]: """Retrieves logs for specified bot. Logs can only be pulled by the bot's developer. :param bot_uid: Bot UID :param errors: If True, only retrieves logs with severity: Error :return: """ auth = get_auth() r = requests.get( ENDPOINT, params={ 'uid': auth.uid, 'key': auth.key, 'bot_uid': bot_uid, 'item': 'logs', 'errors': True if errors else None } ) r.raise_for_status() return r.json()['data']
def get_bot_status(bot_uid: str) -> BotStatus: """Gets the status of the bot. :param bot_uid: :return: """ auth = get_auth() try: req = requests.get( url=ENDPOINT, params={ 'uid': auth.uid, 'key': auth.key, 'bot_uid': bot_uid, 'item': 'status' } ) try: req.raise_for_status() except Exception: raise RuntimeError(req.json()) except Exception: raise RuntimeError(f"Failed to retrieve status for bot {bot_uid}.") return req.json()
def _credentials(): auth = get_auth() return requests.auth.HTTPBasicAuth(auth.uid, auth.key)
def _get_developer_uid(): return get_auth().uid