diff --git a/sincere-singularities/.env.example b/sincere-singularities/.env.example new file mode 100644 index 0000000..ef8e5db --- /dev/null +++ b/sincere-singularities/.env.example @@ -0,0 +1,5 @@ +BOT_TOKEN= + +DB_HOST="172.17.0.2" +DB_PORT="27017" +DB_NAME = "bot_db" diff --git a/sincere-singularities/.github/workflows/lint.yaml b/sincere-singularities/.github/workflows/lint.yaml new file mode 100644 index 0000000..335a9bc --- /dev/null +++ b/sincere-singularities/.github/workflows/lint.yaml @@ -0,0 +1,35 @@ +# GitHub Action workflow enforcing our code style. + +name: Lint + +# Trigger the workflow on both push (to the main repository, on the main branch) +# and pull requests (against the main repository, but from any repo, from any branch). +on: + push: + branches: + - main + pull_request: + +# Brand new concurrency setting! This ensures that not more than one run can be triggered for the same commit. +# It is useful for pull requests coming from the main repository since both triggers will match. +concurrency: lint-${{ github.sha }} + +jobs: + lint: + runs-on: ubuntu-latest + + env: + # The Python version your project uses. Feel free to change this if required. + PYTHON_VERSION: "3.11" + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Run pre-commit hooks + uses: pre-commit/action@v3.0.1 diff --git a/sincere-singularities/.gitignore b/sincere-singularities/.gitignore new file mode 100644 index 0000000..7f15786 --- /dev/null +++ b/sincere-singularities/.gitignore @@ -0,0 +1,41 @@ +# Files generated by the interpreter +__pycache__/ +*.py[cod] + +# Environment specific +.venv +venv +.env +env + +# Unittest reports +.coverage* + +# Logs +*.log + +# PyEnv version selector +.python-version + +# Built objects +*.so +dist/ +build/ + +# Distribution / packaging +*.egg-info/ + +# IDEs +# PyCharm +.idea/ +# VSCode +.vscode/ +# MacOS +.DS_Store + +# json files for test cases +orders.json +states.json + +# MyPy +.mypy_cache/ diff --git a/sincere-singularities/.pre-commit-config.yaml b/sincere-singularities/.pre-commit-config.yaml new file mode 100644 index 0000000..58fa585 --- /dev/null +++ b/sincere-singularities/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +# Pre-commit configuration. +# See https://github.com/python-discord/code-jam-template/tree/main#pre-commit-run-linting-before-committing + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + - id: check-ast + - id: check-case-conflict + - id: check-json + - id: check-toml + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.5.2 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.10.1 + hooks: + - id: mypy + # args: [--strict] # Put config in pyproject.toml. If it doesn't work, put it here. diff --git a/sincere-singularities/LICENSE.txt b/sincere-singularities/LICENSE.txt new file mode 100644 index 0000000..d5f910f --- /dev/null +++ b/sincere-singularities/LICENSE.txt @@ -0,0 +1,33 @@ +MIT License + +Copyright (c) 2024 Sincere Singularities + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +The Software incorporates code from which is under the following license: + +Copyright 2021 Python Discord + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/sincere-singularities/README.md b/sincere-singularities/README.md new file mode 100644 index 0000000..eb60495 --- /dev/null +++ b/sincere-singularities/README.md @@ -0,0 +1,178 @@ +# Restaurant Rush: Kitchen Chaos + +**Sincere Singularities** Python Discord Summer CodeJam 2024 project. +The technology is **Discord Application**, the theme is **Information Overload**, and our chosen framework +is [Disnake](https://github.com/DisnakeDev/disnake/). + +--- + +Did you ever want to experience the information overload and stress of a phone operator? +Well, then you're at the right place! + +We've created the first stressful Discord game, in which you play a phone operator for multiple restaurants. +No matter what dishes, customers, or special orders you have to serve, don't lose focus, or you might get overwhelmed by +the information overload! + + + +## Getting Started +See [Installation](https://github.com/SincereSingularities/SincereSingularities?tab=readme-ov-file#installation) and [Running](#running) for detailed instructions. + +1. Python 3.11 is [recommended](https://github.com/DisnakeDev/disnake/pull/1135#issuecomment-1847303628). Python 3.10 - 3.12 will probably work. +2. Setup a [Discord Bot](https://docs.disnake.dev/en/stable/discord.html). See [Discord Bot Installation Guide](#discord-bot-installation-guide). +3. Clone the repository : + ```shell + git clone https://github.com/SincereSingularities/SincereSingularities/ + cd SincereSingularities + pip install -e . + ``` +4. Setup and run [MongoDB Community Edition](https://www.mongodb.com/docs/manual/administration/install-community/) +5. Set the `BOT_TOKEN`, `DB_HOST`, `DB_PORT` and `DB_NAME` environment variables using the `.env` file. +6. Run The Game: + ```shell + python -m sincere_singularities + ``` +7. Play! + +## Video Presentation +[Video Presentation / Description](https://streamable.com/3rcyc0) + + +## Installation +
+ Detailed Installation Guide ⚙️ + +### 1. Requirements: + 1. [Python 3.11](https://www.python.org/downloads/release/python-3110/) + 2. [MongoDB Community Edition](https://www.mongodb.com/docs/manual/administration/install-community/). See [MongoDB Installation Guide](#mongodb-community-edition-installation-guide) + 3. [Discord Bot](https://docs.disnake.dev/en/stable/discord.html). See [Discord Bot SetUp Guide](#discord-bot-installation-guide) +### 2. Download: +Run this command in the directory you want to download it to. + ```shell + git clone https://github.com/SincereSingularities/SincereSingularities/ + cd SincereSingularities + ``` +### 3. Install the Game as a package via pip: + ```shell + pip install -e . + ``` +### 4. Setup local environment values: +Create and Edit an .env file (see .env.example) +``` +BOT_TOKEN (Your Discord Bot Token) +DB_HOST (The IP address of your MongoDB Server) +DB_PORT (The port of your MongoDB Server) +DB_NAME (Your preferred name for the MongoDB Database, defaults to `bot_db`) +``` + +
+ +## Running +
+ Detailed Running Guide ⚙️ + +### 1. Start your [MongoDB Server](https://www.mongodb.com/docs/manual/administration/install-community/). See [MongoDB Installation Guide](#mongodb-community-edition-installation-guide) +### 2. Run the Game: + ```shell + python -m sincere_singularities + ``` +### 3. Start a Game Session in a Text Channel: + ``` + /start_game + ``` +
+ +## Gameplay +
+ Gameplay Explanation 💡 + +1. Choose a text channel. +2. Run the `/start_game` command. That will create a thread. +3. The bot will send the menu. This contains multiple restaurants that you can buy. You already own the first one. +4. You will get orders in the thread as messages. Choose and enter the appropriate restaurant, and select the menu items that the customer requested. +5. Then enter the customer's information which consists of: + - Order ID + - Customer Name + - Customer Address + - Delivery Time + - Extra Wishes +6. Submit the order. You will get points based on the accuracy of the order. With your earned coins you can buy new restaurants. +7. From time to time, you will get Order Conditions. Pay attention to these Conditions when fulfilling a order. They will also disappear after some time. +
+ +## Helper Commands +
+ Helper Commands 🔨 + +- /clear_threads +
+ ``Clears the Threads in the Text Channel the Command was executed in. Requires the Author to have manage_threads permissions.`` +- /clear_webhooks +
+ ``Clears the Webhooks in the Text Channel the Command was executed in. Requires the Author to have manage_webhooks permissions.`` +
+ +## Discord Bot Installation Guide +
+ Discord Bot Installation Guide 🤖 + +Extended from [Disnake Bot Guide](https://docs.disnake.dev/en/stable/discord.html) +1. Create a new [Discord Application](https://discord.com/developers/applications). +2. Navigate to the Bot Tab. You can customize your bot. Reset the bot token and copy the freshly created one. +3. Navigate to the OAuth2 Tab. + 1. Under `Scopes`, check `bot` and `applications.commands`. + 2. Under `Bot Permissions`, check `Manage Webhooks`, `Send Messages`, `Create Public Threads`, `Send Messages in Threads`, `Manage Messages`, `Manage Threads`, + 3. Copy the `Generated URL` +4. Paste the `Generated URL` in your browser and invite the bot to your server. +
+ +## MongoDB Community Edition Installation Guide +
+ MongoDB Server Installation Guide 💾 + +Extended from [MongoDB Community Edition Installer](https://www.mongodb.com/docs/manual/administration/install-community/) +1. Install on Windows + 1. For Installation, follow [Windows Installation Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-windows/#install-mongodb-community-edition) + 2. To Run MongoDB, follow [Windows Running Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-windows/#run-mongodb-community-edition-from-the-command-interpreter) +2. Install on MacOS + 1. For Installation, follow [MacOS Installation Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#install-mongodb-community-edition) + 2. To Run MongoDB, follow [MacOS Running Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#run-mongodb-community-edition) +3. Install on Ubuntu + 1. For Installation, follow [Ubuntu Installation Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/#install-mongodb-community-edition) + 2. To Run MongoDB, follow [Ubuntu Running Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/#run-mongodb-community-edition) +4. Install on Debian + 1. For Installation, follow [Debian Installation Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-debian/#install-mongodb-community-edition) + 2. To Run MongoDB, follow [Debian Running Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-debian/#run-mongodb-community-edition) +5. Install on SUSE + 1. For Installation, follow [SUSE Installation Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-suse/#install-mongodb-community-edition) + 2. To Run MongoDB, follow [SUSE Running Guide](https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-suse/#run-mongodb-community-edition) + +
+ +## Preview Images +
+ Preview Images 📸 + +#### Main Menu: + + +#### Restaurant Menu: + + +#### Easy Order (Pizzaria): + + +#### Medium Order (Fast Food): + + +#### Hard Order (Sushi): + +
+ +# Credits +This project was created by (in order of contributed LOC): + +| [Vinyzu](https://github.com/Vinyzu) | [koviubi1](https://github.com/koviubi56) | [WassCodeur](https://github.com/WassCodeur) | [clucker_m8](https://github.com/clucker-m8) | [FoxFil](https://github.com/foxfil) | +|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| +| [vinyzu](https://github.com/vinyzu) | [koviubi1](https://github.com/koviubi56) | [WassCodeur](https://github.com/WassCodeur) | [clucker_m8](https://github.com/clucker-m8) | [FoxFil](https://github.com/foxfil) | +| Game | Game | Database | Order Generation | Restaurant Menus | diff --git a/sincere-singularities/pyproject.toml b/sincere-singularities/pyproject.toml new file mode 100644 index 0000000..f1dad0b --- /dev/null +++ b/sincere-singularities/pyproject.toml @@ -0,0 +1,118 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "sincere_singularities" +version = "1.0.0" # no need to change the version +description = "Sincere Singularities Python Discord Summer CodeJam 2024 project." +readme = "README.md" +requires-python = ">=3.11" +license = { text = "MIT" } +authors = [ + { name = "clucker-m8" }, + { name = "FoxFil" }, + { name = "koviubi56" }, + { name = "Vinyzu" }, + { name = "WassCodeur" }, +] +classifiers = [ + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Games/Entertainment", + "Typing :: Typed", +] +dynamic = ["dependencies", "optional-dependencies"] + +[tool.setuptools.dynamic] +dependencies = { file = "requirements.txt" } +optional-dependencies.dev = { file = ["requirements-dev.txt"] } + +[tool.setuptools.package-data] +sincere_singularities = ["py.typed"] + +[project.urls] +Homepage = "https://github.com/SincereSingularities/SincereSingularities" + +[project.scripts] +sincere_singularities = "sincere_singularities.__main__:main" + +[tool.ruff] +# Increase the line length. This breaks PEP8 but it is way easier to work with. +# The original reason for this limit was a standard vim terminal is only 79 characters, +# but this doesn't really apply anymore. +line-length = 119 +# Target Python 3.12. If you decide to use a different version of Python +# you will need to update this value. +target-version = "py312" +# Automatically fix auto-fixable issues. +fix = true +# The directory containing the source code. If you choose a different project layout +# you will need to update this value. +src = ["src"] + +[tool.ruff.lint] +# Enable all linting rules. +select = ["ALL"] +# Ignore some of the most obnoxious linting errors. +ignore = [ + # Missing docstrings. + "D100", + "D104", + "D105", + "D106", + "D107", + # Docstring whitespace. + "D203", + "D212", + # Docstring punctuation. + "D415", + # Docstring quotes. + "D301", + # Print statements. + "T20", + # TODOs. + "TD002", + "TD003", + "FIX", + # Annotations. + "ANN101", + "ANN102", + # Future annotations. + "FA", + # Error messages. + "EM", + # Type Keyword (3.12+) + "UP040", + # Exceptions + "TRY003", + # Recommended by Ruff + "ISC001", + "COM812", + # Pseudo-Random Generators + "S311", + # Asserts + "S101", + # Function Arguments + "PLR0913", + # Magic Values + "PLR2004", + # Positional Boolean + "FBT001" +] + +[tool.ruff.lint.pydocstyle] +# Use Google-style docstrings. +convention = "google" +ignore-decorators = ["typing.overload"] + +[tool.mypy] +strict = true +disallow_untyped_decorators = false +disallow_subclassing_any = false diff --git a/sincere-singularities/requirements-dev.txt b/sincere-singularities/requirements-dev.txt new file mode 100644 index 0000000..4167392 --- /dev/null +++ b/sincere-singularities/requirements-dev.txt @@ -0,0 +1,4 @@ +# This file contains all the development requirements for our linting toolchain. + +ruff~=0.5.0 +pre-commit~=3.7.1 diff --git a/sincere-singularities/requirements.txt b/sincere-singularities/requirements.txt new file mode 100644 index 0000000..c44abaf --- /dev/null +++ b/sincere-singularities/requirements.txt @@ -0,0 +1,10 @@ +# This file contains all the requirements needed to run the project. +disnake~=2.9.2 +python-dotenv~=1.0.1 +dacite~=1.8.1 +pymongo~=4.8.0 +torch~=2.3.1 +sentence-transformers~=3.0.1 +transformers~=4.43.2 +numpy<2 +faker~=26.0.0 diff --git a/sincere-singularities/setup.py b/sincere-singularities/setup.py new file mode 100644 index 0000000..6068493 --- /dev/null +++ b/sincere-singularities/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/sincere-singularities/src/sincere_singularities/__init__.py b/sincere-singularities/src/sincere_singularities/__init__.py new file mode 100644 index 0000000..8278509 --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/__init__.py @@ -0,0 +1,4 @@ +from sincere_singularities.data.savestates import SaveStates + +# Load SaveStates Database +save_states = SaveStates() diff --git a/sincere-singularities/src/sincere_singularities/__main__.py b/sincere-singularities/src/sincere_singularities/__main__.py new file mode 100644 index 0000000..407d61b --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/__main__.py @@ -0,0 +1,16 @@ +import os + +import dotenv + +from sincere_singularities.bot import bot + + +def main() -> None: + """Load .env, and run the bot.""" + dotenv.load_dotenv() + token = os.getenv("BOT_TOKEN") + bot.run(token) + + +if __name__ == "__main__": + main() diff --git a/sincere-singularities/src/sincere_singularities/bot.py b/sincere-singularities/src/sincere_singularities/bot.py new file mode 100644 index 0000000..00e6aed --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/bot.py @@ -0,0 +1,179 @@ +import asyncio +from typing import cast + +import disnake +from disnake import ApplicationCommandInteraction, Embed, Intents, Member, MessageInteraction, TextChannel +from disnake.ext import commands + +from sincere_singularities import save_states +from sincere_singularities.modules.conditions import ConditionManager +from sincere_singularities.modules.order_queue import OrderQueue +from sincere_singularities.modules.restaurants_view import Restaurants + +# Load Disnake Related Objects +intents = Intents.default() +bot = commands.InteractionBot(intents=intents) +# This global set is used to ensure that a (non-weak) reference is kept to background tasks created that aren't +# awaited. These tasks get added to this set, then once they're done, they remove themselves. +# See RUF006 +background_tasks: set[asyncio.Task[None]] = set() + + +@bot.slash_command(name="clear_webhooks", description="Clears the webhooks in a channel.") +async def clear_webhooks(interaction: ApplicationCommandInteraction) -> None: + """ + Clears the webhooks in a channel. + + Args: + interaction (ApplicationCommandInteraction): The Disnake application command interaction. + """ + # Check if the message was sent in a text channel + if not isinstance(interaction.channel, TextChannel): + await interaction.response.send_message( + "I'm only able to clear webhooks inside of a text channel!", ephemeral=True + ) + return + + # Check user permissions + # We know this is a Member because interaction.channel is a guild text channel + permissions = interaction.channel.permissions_for(cast(Member, interaction.author)) + if not permissions.manage_webhooks: + await interaction.response.send_message("You don't have the permissions to manage webhooks!", ephemeral=True) + return + + await interaction.response.send_message("Webhooks cleared!", ephemeral=True) + + webhooks = await interaction.channel.webhooks() + for webhook in webhooks: + await webhook.delete() + + +@bot.slash_command(name="clear_threads", description="Clears the threads in a channel.") +async def clear_threads(interaction: ApplicationCommandInteraction) -> None: + """ + Clears the threads in a channel. + + Args: + interaction (ApplicationCommandInteraction): The Disnake application command interaction. + """ + # Check if the message was sent in a text channel + if not isinstance(interaction.channel, TextChannel): + await interaction.response.send_message( + "I'm only able to clear threads inside of a text channel!", ephemeral=True + ) + return + + # Check user permissions + # We know this is a Member because interaction.channel is a guild text channel + permissions = interaction.channel.permissions_for(cast(Member, interaction.author)) + if not permissions.manage_threads: + await interaction.response.send_message("You don't have the permissions to manage threads!", ephemeral=True) + return + + await interaction.response.send_message("Threads cleared!", ephemeral=True) + + for thread in interaction.channel.threads: + await thread.delete() + + +class IntroductionView(disnake.ui.View): + """View for the introduction to the game.""" + + @disnake.ui.button(style=disnake.ButtonStyle.success, label="Start!") + async def _start(self, _: disnake.ui.Button, interaction: MessageInteraction) -> None: + await start_the_game(interaction) + + +@bot.slash_command(name="start_game", description="Starts the game.") +async def start_game(interaction: ApplicationCommandInteraction) -> None: + """ + Start the game. + + Args: + interaction (ApplicationCommandInteraction): The Disnake application command interaction. + """ + # Check if the message was sent in a text channel + if not isinstance(interaction.channel, TextChannel): + await interaction.response.send_message( + "You can only start a game session inside of a text channel!", + ephemeral=True, + ) + return + + try: + save_states.load_game_state(interaction.user.id) + except ValueError: + embed = Embed( + title="Introduction", + description="Welcome to Restaurant Rush: Kitchen Chaos! In this game, you manage orders from customers for" + " multiple restaurants, but make sure you don't get overwhelmed by the information overload.", + ) + embed.add_field( + name="Starting the game", + description="Once you start the game, the orders will be sent as messages in a thread which will be" + " created in this channel. The bot will also send the game menu where you can enter restaurants and" + " add orders. You can buy restaurants with coins, but you already own the first one.", + inline=False, + ) + embed.add_field( + name="Adding an order", + description="When you get a new order, select the appropriate restaurant from the menu and enter it." + " Press the buttons to add the menu items that the user requested. Then, input the customer" + " information and click done. You will receive coins based on how correct you were.", + inline=False, + ) + embed.add_field( + name="The information overload", + description="The more you play the game, the more difficult it gets. Be quick because being slow will" + " result in penalties!", + inline=False, + ) + embed.add_field( + name="Buying restaurants", + description="Once you gain enough coins, you can buy other restaurants.", + inline=False, + ) + interaction.response.send_message(embed=embed, view=IntroductionView()) + else: + await start_the_game(interaction) + + +async def start_the_game(interaction: ApplicationCommandInteraction | MessageInteraction) -> None: + """ + Actually start the game. + + Args: + interaction (ApplicationCommandInteraction | MessageInteraction): The interaction that led to the start of + the game. + """ + # Start order queue + order_queue = await OrderQueue.new(interaction) + if not order_queue: + # Return if we can't start the game (the user is already warned) + return + # Load Restaurants + condition_manager = ConditionManager(order_queue) + restaurants = Restaurants(interaction, order_queue, condition_manager) + condition_manager.restaurants = restaurants + + # Sending start menu + await interaction.response.send_message(embed=restaurants.embeds[0], view=restaurants.view, ephemeral=True) + + # Spawning orders + task = asyncio.create_task(order_queue.start_orders()) + background_tasks.add(task) + task.add_done_callback(background_tasks.discard) + + # Spawning conditions + task = asyncio.create_task(condition_manager.spawn_conditions()) + background_tasks.add(task) + task.add_done_callback(background_tasks.discard) + + +@bot.event +async def on_ready() -> None: + """Bot information logging when starting up.""" + print( + f"Logged in as {bot.user} (ID: {bot.user.id}).\n" + f"Running on {len(bot.guilds)} servers with {bot.latency * 1000:,.2f} ms latency.", + ) diff --git a/sincere-singularities/src/sincere_singularities/data/__init__.py b/sincere-singularities/src/sincere_singularities/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sincere-singularities/src/sincere_singularities/data/db.py b/sincere-singularities/src/sincere_singularities/data/db.py new file mode 100644 index 0000000..b7f7c01 --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/data/db.py @@ -0,0 +1,216 @@ +import os +from collections.abc import Iterable +from datetime import UTC, datetime +from typing import Any + +from dotenv import load_dotenv +from pymongo import MongoClient, errors + +load_dotenv() + +DB_HOST = os.getenv("DB_HOST") +DB_PORT = os.getenv("DB_PORT") +DB_NAME = os.getenv("DB_NAME") or "bot_db" +DB_URI = f"mongodb://{DB_HOST}:{DB_PORT}" +utc_timezone = UTC + + +class ConnectError(Exception): + """Connection error""" + + def __init__(self, message: str) -> None: + self.message = message + super().__init__(self.message) + + def __str__(self) -> str: + return self.message + + +class DbClient: + """db client""" + + def __init__(self) -> None: + self.connected = False + try: + self.client = MongoClient(DB_URI) + self.connected = True + self.client.server_info() + self.db = self.client[DB_NAME] + self.restaurants = self.db.restaurants + except errors.ConnectionFailure as err: + self.connected = False + print(f"Error: {err}") + raise err from None + + def is_connected(self) -> bool: + """Check if connected + + Returns: + bool: True if connected, False otherwise + """ + return self.connected + + def add_element(self, collection: str, data: dict[str, Any]) -> None: + """Add element + + Args: + collection (str): Collection name + data (dict[str, Any]): Data to add + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + name = data["name"] + # Check if it already exists + if not self.db[collection].find_one({"name": name}): + current_time = datetime.now(utc_timezone) + data["created_at"] = current_time + data["updated_at"] = current_time + self.db[collection].insert_one(data) + + def add_many(self, collection: str, datas: Iterable[Any]) -> None: + """Add many elements + + Args: + collection (str): Collection name + datas (Iterable[Any]): list of Datas to add + + Returns: + None + """ + for data in datas: + self.add_element(collection, data) + + def delete_all(self, collection: str) -> None: + """Delete all elements + + Args: + collection (str): Collection name + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + self.db[collection].delete_many({}) + + def delete_many(self, collection: str, datas: Iterable[Any]) -> None: + """Delete many elements + + Args: + collection (str): Collection name + datas (Iterable[Any]): list of datas to delete + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + for data in datas: + if not self.show_one(collection, data): + raise ValueError("Element not found") + self.db[collection].delete_one(data) + + def delete_one(self, collection: str, data: dict[str, Any]) -> None: + """Delete one element + + Args: + collection (str): Collection name + data (dict[str, Any]): Data to delete + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + if not self.show_one(collection, data): + raise ValueError("Element not found") + self.db[collection].delete_one(data) + + def show_all(self, collection: str) -> list[dict[str, Any]]: + """Show all elements + + Args: + collection (str): Collection name + + Returns: + list[Any]: All elements in the collection + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + elements = self.db[collection].find({}) + return [dict(element) for element in elements] + + def show_one(self, collection: str, data: dict[str, Any]) -> dict[str, Any]: + """Show one element + + Args: + collection (str): Collection name + data (dict[str, Any]): Data to show + + Returns: + dict[str, Any]: Element found + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + element = self.db[collection].find_one(data) + if not element: + raise ValueError("Element not found") + return dict(element) + + def update_one( + self, + collection: str, + data: dict[str, Any], + new_data: dict[str, Any], + *, + upsert: bool = False, + ) -> None: + """Update one element in the collection + + Args: + collection (str): Collection name + data (dict[str, Any]): Data to update + new_data (dict[str, Any]): New data to update + upsert (bool, optional): Whether to upsert. Defaults to False. + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + if not upsert: + element = self.show_one(collection, data) + + if not element: + raise ValueError("Element not found") + + current_time = datetime.now(utc_timezone) + new_data["updated_at"] = current_time + self.db[collection].update_one(data, {"$set": new_data}, upsert=upsert) + + def update_many(self, collection: str, datas: Iterable[Any], new_datas: Iterable[Any]) -> None: + """Update many elements in the collection + + Args: + collection (str): Collection name + datas (Iterable[Any]): list of datas to update + new_datas (Iterable[Any]): list of new datas to update + + Returns: + None + """ + if not self.connected: + raise ConnectError("Not connected to the database") + + for data, new_data in zip(datas, new_datas, strict=False): + if not self.show_one(collection, data): + raise ValueError("Element not found") + self.db[collection].update_one(data, {"$set": new_data}) diff --git a/sincere-singularities/src/sincere_singularities/data/extra_wishes.py b/sincere-singularities/src/sincere_singularities/data/extra_wishes.py new file mode 100644 index 0000000..9f9c256 --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/data/extra_wishes.py @@ -0,0 +1,73 @@ +EXTRA_WISHES_WITH_ADDITIONS = { + "Please don't ring the bell": "Oh, and tell the delivery guy to not ring the bell", + "Make sure the food isn't cold": "It's crucial the food arrives hot, please.", + "Add some spice to the main dishes": "Could you kick up the heat a bit?", + "No onions, please": "I really can't stand onions, thanks.", + "Extra napkins, please": "And please toss in a few extra napkins.", + "Include utensils": "Don't forget the utensils, please.", + "Extra ketchup packets": "I could use a few more ketchup packets.", + "Leave the food at the door": "Just leave it at the door, no need to knock.", + "Add extra cheese": "I'd love some extra cheese on that.", + "Gluten-free option if available": "If there's a gluten-free option, I'll take it.", + "Please deliver exactly on time": "Timeliness is key; please be punctual.", + "Include straws": "Straws would be great, thanks.", + "Make it extra crispy": "Make it as crispy as you can, please.", + "Add extra sauce": "More sauce, please, I love it saucy.", + "Separate the sauces, please": "Could you keep the sauces separate?", + "Add a side of avocado": "A side of avocado would be perfect.", + "More soy sauce packets": "I'd like some extra soy sauce packets.", + "No nuts, please": "Please ensure there are no nuts, I'm allergic.", + "Extra lime wedges": "A few extra lime wedges would be nice.", + "No cilantro, please": "Hold the cilantro, please.", + "Extra spicy, please": "Make it extra spicy for me.", + "Make it mild": "Could you make it mild? Thanks.", + "Add extra jalapenos": "Throw in some extra jalapenos.", + "No dairy, please": "Please make sure there's no dairy.", + "More lemon slices": "I'd appreciate more lemon slices.", + "Make it vegetarian": "I'd like it to be vegetarian, please.", + "Include hot sauce packets": "Hot sauce packets would be great.", + "Add a side of ranch": "A side of ranch, please.", + "More napkins, please": "I need more napkins, if possible.", + "Use olive oil instead of butter": "Olive oil instead of butter, please.", + "Extra ice, please": "Could you add extra ice?", + "No green peppers": "Please, no green peppers.", + "Include a side of gravy": "I'd like a side of gravy.", + "More hot mustard packets": "More hot mustard packets, please.", + "Add extra olives": "I'd love extra olives, thanks.", + "Add a side of honey": "A side of honey would be nice.", + "No garlic, please": "Make sure there's no garlic, please.", + "Extra fresh herbs": "I'd love some extra fresh herbs.", + "Include chopsticks": "Could you include chopsticks, please?", + "Add extra mint leaves": "Extra mint leaves would be appreciated.", + "No pepper on the food": "No pepper on my food, please.", + "Extra tartar sauce": "More tartar sauce, please.", + "Make it extra saucy": "Could you make it extra saucy?", + "Add a side of coleslaw": "A side of coleslaw would be great.", + "Include extra bread rolls": "Extra bread rolls would be awesome.", + "No eggs, please": "Please ensure there are no eggs.", + "Extra dill pickles": "I love dill pickles, so extra, please.", + "Make it low-sodium": "Could you make it low-sodium?", + "Add extra croutons": "Extra croutons, please.", + "More barbecue sauce": "I'd like more barbecue sauce.", + "Include a side of fruit": "A side of fruit would be nice.", + "Make it light on the dressing": "Go easy on the dressing, please.", + "No mushrooms, please": "Please, no mushrooms.", + "Extra whipped cream": "I'd love extra whipped cream.", + "Add a side of marinara sauce": "A side of marinara sauce would be perfect.", + "More green onions": "Could you add more green onions?", + "Include a side of sour cream": "A side of sour cream, please.", + "Make it kid-friendly": "Make sure it's kid-friendly.", + "Extra black pepper": "I'd like extra black pepper.", + "Add a side of steamed vegetables": "A side of steamed vegetables would be great.", + "Extra cranberry sauce": "I love cranberry sauce, so extra, please.", + "Add a side of mac and cheese": "A side of mac and cheese, please.", + "Include a side of rice": "Could you include a side of rice?", + "Extra caramel sauce": "More caramel sauce, please.", + "Add a side of hummus": "A side of hummus would be nice.", + "More pickled vegetables": "I'd like more pickled vegetables.", + "Include a side of salsa": "Salsa on the side would be great.", + "Make it with extra love": "Please make it with extra love!", + "No sesame oil": "Please, no sesame oil.", + "Extra lemon zest": "Extra lemon zest would be wonderful.", + "Add a side of tzatziki": "A side of tzatziki, please.", +} diff --git a/sincere-singularities/src/sincere_singularities/data/intros_outros.py b/sincere-singularities/src/sincere_singularities/data/intros_outros.py new file mode 100644 index 0000000..c2b0808 --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/data/intros_outros.py @@ -0,0 +1,69 @@ +INTROS = { + "intros_with_name": [ + "Hello, here!", + "Hi there, speaking!", + "Hey there, here!", + "Howdy, speaking!", + "What's up, here!", + "What's poppin', speaking!", + "Hiya, here!", + "Good day, speaking!", + "Yo, here!", + "Hey you, speaking!", + "Hi, here!", + "Greetings, speaking!", + "Hello there, here!", + "Hiya, speaking!", + ], + "intros_without_name": [ + "Hello!", + "Hi there!", + "Hey there!", + "Howdy!", + "What's up?", + "What's poppin'!", + "Hiya!", + "Good day!", + "Yo!", + "Hey you!", + "Hi!", + "Greetings!", + "Hello there!", + "Hiya!", + ], +} + +OUTROS = { + "outros_with_name": [ + "Goodbye, !", + "See you later, !", + "Take care, !", + "Farewell, !", + "Catch you later, !", + "Later, !", + "Bye for now, !", + "Until next time, !", + "Adios, !", + "So long, !", + "Peace out, !", + "Cheers, !", + "Good night, !", + "Bye-bye, !", + ], + "outros_without_name": [ + "Goodbye!", + "See you later!", + "Take care!", + "Farewell!", + "Catch you later!", + "Later!", + "Bye for now!", + "Until next time!", + "Adios!", + "So long!", + "Peace out!", + "Cheers!", + "Good night!", + "Bye-bye!", + ], +} diff --git a/sincere-singularities/src/sincere_singularities/data/noise.py b/sincere-singularities/src/sincere_singularities/data/noise.py new file mode 100644 index 0000000..407aaec --- /dev/null +++ b/sincere-singularities/src/sincere_singularities/data/noise.py @@ -0,0 +1,344 @@ +from dataclasses import dataclass + + +@dataclass +class EmbeddableNoiseFoods: + """EmbeddableNoiseFoods""" + + starters: list[str] + main: list[str] + desserts: list[str] + drinks: list[str] + + +@dataclass +class EmbeddableNoise: + """EmbeddableNoise""" + + addresses: list[str] + foods: EmbeddableNoiseFoods + times: list[str] + restaurants: list[str] + + +@dataclass +class NoiseData: + """NoiseData""" + + noise: list[str] + relevant_noise: list[str] + embeddable_noise: EmbeddableNoise + + +NOISE = NoiseData( + noise=[ + "It's such a sunny day today, perfect for a walk in the park.", + "Yesterday was unbelievable with how much it rained, flooding the streets.", + "The sky looks so clear and blue, not a cloud in sight.", + "This morning, I had a great time at the park watching the ducks.", + "My cat knocked over my plant again, creating quite the mess.", + "Finally finished reading that book I've been working on for weeks.", + "Dinner last night was fantastic, especially the dessert.", + "I can't wait for the weekend to relax and maybe go hiking.", + "Traffic was terrible this morning, making me late for work.", + "Planning to bake cookies later with a new recipe I found.", + "Have you seen the latest movie that's causing such a buzz?", + "My dog loves playing fetch in the yard, never gets tired.", + "Groceries are on my list after work, running low on essentials.", + "The sunset yesterday was absolutely beautiful, with vibrant colors.", + "Cleaned my entire house today, feels so refreshing now.", + "Thinking about redecorating my living room, maybe new curtains.", + "The flowers in my garden are blooming nicely, adding color to the yard.", + "Spent the afternoon organizing my closet, found some old treasures.", + "Tried a new recipe for lunch today, it was surprisingly good.", + "Can't find my keys anywhere, looked in all the usual spots.", + "Neighbors are having a barbecue this weekend, invited the whole block.", + "Need to take my car for a service, it's been making weird noises.", + "Power went out for a couple of hours, had to use candles.", + "Learning to play the guitar, slowly but surely improving.", + "Had a lovely walk by the beach, the sound of waves was soothing.", + "Friend is coming over for coffee tomorrow, can't wait to catch up.", + "Watering the plants before I leave, they look a bit dry.", + "The birds are singing so loudly today, feels like a symphony.", + "Saw a beautiful rainbow after the rain, it was magical.", + "Need to finish my project by the end of the week, deadlines are tight.", + "The coffee shop on the corner makes the best lattes, a must-try.", + "Love the smell of fresh laundry, so clean and crisp.", + "Had the most delicious breakfast this morning, pancakes and syrup.", + "Replace the light bulb in the kitchen, it's been flickering.", + "Found a great deal on a new laptop, couldn't resist buying it.", + "The air feels so fresh after the rain, perfect for a run.", + "Planning a surprise party for my friend, hope she loves it.", + "Just bought a new set of paints, excited to start a new project.", + "Weather forecast says it will be sunny all week, time for outdoor fun.", + "Love listening to music while I cook, makes it more enjoyable.", + "Can't believe it's already July, time flies so fast.", + "My plants are growing so fast, need to repot some of them.", + "Book a dentist appointment, it's been a while since my last check-up.", + "Spent the day hiking in the mountains, the views were breathtaking.", + "Tried yoga for the first time today, felt incredibly relaxing.", + "The stars are so bright tonight, perfect for stargazing.", + "Finally organized my desk, now it looks neat and tidy.", + "Planning to visit my grandparents this weekend, always a pleasure.", + "Love the sound of rain on the roof, so calming.", + "Need to buy a new phone charger, mine is fraying.", + "Had a picnic in the park today, the weather was perfect.", + "The autumn leaves are so beautiful, love the vibrant colors.", + "Vacuum the living room, it's starting to look a bit dusty.", + "Thinking about getting a new pet, maybe a rabbit.", + "Found a new favorite TV show, binge-watched the first season.", + "The sunrise was stunning this morning, worth waking up early for.", + "Do the dishes before bed, don't want a messy kitchen in the morning.", + "Spent the evening reading a great book, couldn't put it down.", + "Neighborhood kids are playing outside, their laughter is contagious.", + "Need to clean out the garage, it's getting cluttered.", + "Love the feeling of fresh sheets on the bed, so comfortable.", + "Went for a bike ride along the river, the scenery was beautiful.", + "Can't wait to try the new restaurant in town, heard great reviews.", + "Bought a new rug for the living room, adds a nice touch.", + "Looking forward to the holiday season, always so festive.", + "The flowers smell amazing in the garden, such a pleasant aroma.", + "Had a relaxing bath after a long day, felt rejuvenating.", + "Found my old photo albums in the attic, such memories.", + "Love making smoothies for breakfast, so refreshing and healthy.", + "Wash the car this weekend, it's covered in dust.", + "Spent the afternoon painting, lost track of time.", + "The dog park was full of happy dogs, running and playing.", + "Buy a new alarm clock, mine stopped working.", + "Love watching the sunset from my balcony, a daily highlight.", + "Went to the farmers' market this morning, got fresh produce.", + "The moon is so bright tonight, lighting up the whole yard.", + "Fix the leaky faucet in the bathroom, the dripping is annoying.", + "Had a fun game night with friends, lots of laughs.", + "Love the scent of fresh flowers, brightens my day.", + "Found a great recipe for dinner, can't wait to try it.", + "Take out the trash, the bin is overflowing.", + "The backyard is a great place to relax, especially in the evening.", + "Love the taste of fresh fruit, so juicy and sweet.", + "Organize my bookshelf, it's starting to overflow.", + "Went for a run in the park, the fresh air was invigorating.", + "Bought a new pillow for my bed, sleep should be even better now.", + "Planning a road trip next month, excited for the adventure.", + "The streetlights are glowing softly, creating a serene atmosphere.", + "Pick up my dry cleaning, need my favorite dress for an event.", + "Love the feeling of the sun on my skin, so warm and soothing.", + "Had a delicious cup of tea this morning, perfect start to the day.", + "Mow the lawn this weekend, it's getting too long.", + "Spent the day at the beach, the sound of waves was relaxing.", + "Love the sound of birds in the morning, nature's alarm clock.", + "Get a haircut soon, my hair is getting too long.", + "Had a great workout at the gym, feeling energized.", + "The sky is so clear and beautiful, perfect for photography.", + "Send some emails, catching up on correspondence.", + "Went for a drive in the countryside, the views were stunning.", + "Love the color of the leaves in fall, such a beautiful transformation.", + "Replace the batteries in the remote, it's not working properly.", + "Had a productive day at work, accomplished a lot.", + "Love trying new recipes, cooking is so much fun.", + "Update my calendar, lots of events coming up.", + "The garden looks so green after the rain, so refreshing.", + "Had a relaxing afternoon nap, felt so good.", + "Buy some new clothes, need a wardrobe update.", + "Love the quietness of the morning, so peaceful.", + "Had a fun time at the zoo, the animals were fascinating.", + "Plan my next vacation, thinking of going somewhere tropical.", + "Love the feeling of clean floors, makes the house feel fresh.", + "Had a nice chat with my neighbor, they're really friendly.", + "Make a grocery list, running low on essentials.", + "Love the coziness of my living room, perfect for movie nights.", + "Had a great time at the concert, the music was amazing.", + "Clean the windows, they're looking a bit dirty.", + "Love the taste of homemade bread, so much better than store-bought.", + "Had a peaceful evening at home, watched a good movie.", + "Enjoyed a quiet evening reading my favorite book, so relaxing.", + "Organize my kitchen pantry this weekend, it's getting messy.", + ], + relevant_noise=[ + "My neighbor at 123 Darwin Avenue threw a huge party last night.", + "I used to live at 456 Elm Street when I was a kid.", + "We visited my aunt at 789 Maple Lane during the holidays.", + "There's a beautiful park near 101 Birch Road that we often visit.", + "The new bakery on 234 Pine Street has the best pastries.", + "Our family friend lives at 567 Oak Avenue and has a lovely garden.", + "I received a package meant for 890 Cedar Drive by mistake.", + "The house at 345 Willow Lane is up for sale.", + "I walked past 678 Cherry Street on my way to work.", + "We had a great barbecue at 901 Ash Boulevard last summer.", + "My cousin just moved to 123 Birch Drive and loves it there.", + "There's a nice coffee shop at 456 Maple Street that I frequent.", + "My best friend grew up at 789 Elm Avenue and has many stories.", + "We held our annual family reunion at 101 Oak Drive.", + "There's a new gym opening at 234 Cedar Lane next month.", + "The house at 567 Pine Boulevard has a fantastic view.", + "I left my umbrella at 890 Willow Street last week.", + "The kids love playing at the park on 345 Ash Avenue.", + "We had our wedding reception at 678 Birch Road.", + "My grandparents lived at 901 Maple Lane for over 50 years.", + "My friend Sarah loves pizza, especially from Joe's Pizzeria.", + "For dinner last night, we had spaghetti with garlic bread.", + "At the new restaurant, I tried sushi for the first time.", + "My mom makes the best chocolate cake, hands down.", + "During our trip, we had fresh seafood by the beach.", + "My brother's favorite snack is a peanut butter and jelly sandwich.", + "We enjoyed a delicious brunch with pancakes and bacon.", + "My dad prefers his steak well-done with a side of mashed potatoes.", + "We all shared a large bowl of popcorn during the movie night.", + "I had a refreshing fruit salad for lunch yesterday.", + "My cousin always orders fried chicken when we eat out.", + "The pasta primavera at the Italian place was amazing.", + "We celebrated with a big slice of cheesecake each.", + "My grandma's homemade soup is perfect on a cold day.", + "For breakfast, I usually have oatmeal with fresh berries.", + "We had a wonderful Thanksgiving dinner with all the trimmings.", + "I tried a new recipe for tacos, and it was a hit.", + "My niece loves ice cream, especially chocolate flavor.", + "We had a picnic with sandwiches and lemonade by the lake.", + "The bakery's croissants were buttery and delicious.", + "I woke up at 7am this morning to go for a run.", + "We have a meeting scheduled at 10:30am tomorrow.", + "Dinner is usually served at our house around 6pm.", + "The concert starts at 8pm, so we should leave by 7.", + "Our flight departs at 9:15am, so we need to be at the airport early.", + "I usually get off work at 5pm and head straight home.", + "The train to the city leaves at 7:45am sharp.", + "We had a family gathering at noon to celebrate the holiday.", + "The fireworks show begins at 9pm every Fourth of July.", + "The library closes at 8pm, so let's hurry up.", + "I went for a walk at 6am to enjoy the sunrise.", + "We have a reservation at the restaurant for 7:30pm.", + "The store opens at 9am, perfect for early shopping.", + "Our appointment is at 3pm, don't forget to bring the documents.", + "The meeting was postponed to 2pm due to unforeseen circumstances.", + "I usually have lunch around 1pm during weekdays.", + "The gym class starts at 5:30pm, be there on time.", + "The movie premiere is at 7pm, let's get good seats.", + "My alarm goes off at 6:30am every morning.", + "The football match kicks off at 4pm this Sunday.", + "I recently visited Paris, France, and it was beautiful.", + "My best friend, Emily Johnson, is moving to New York City.", + "We went hiking in the Rocky Mountains last summer.", + "I met John Smith at a conference last year.", + "Our family vacationed in San Diego, California, last year.", + "I work with a colleague named Alice Brown, who is very talented.", + "We spent a weekend exploring Washington, D.C.", + "My old neighbor, Michael Davis, just got married.", + "We traveled to Tokyo, Japan, for a cultural experience.", + "My cousin, Laura Wilson, is a great cook.", + "I attended a workshop in Boston, Massachusetts.", + "My friend, David Lee, is an excellent guitarist.", + "We visited the Grand Canyon during our road trip.", + "I have a mentor named Sarah Thomas, who is very inspiring.", + "Our trip to London, England, was unforgettable.", + "My neighbor, Robert Martinez, has a beautiful garden.", + "We took a cruise to the Bahamas last winter.", + "My colleague, Jessica White, received an award for her work.", + "We toured the museums in Berlin, Germany, last spring.", + "I recently met a writer named Charles Moore at a book signing.", + ], + embeddable_noise=EmbeddableNoise( + addresses=[ + "Can you deliver this to
?", + "I'd like to order this to
.", + "Please send this to
.", + "I need this delivered to
.", + "The order should go to
.", + "Please arrange for this to be delivered to
.", + "Can the delivery be made to
?", + "I'd like this sent to
.", + "The meal needs to go to
.", + "Please have this dropped off at
.", + "Make sure this arrives at
.", + "I want this shipped to
.", + "This should be sent to
.", + "Deliver this order to
.", + "I would like this to be delivered to
.", + "Please ensure this is delivered to
.", + "Send this to
, please.", + "The delivery address is
.", + "This order is for
.", + "Can you make sure this gets to
?", + ], + foods=EmbeddableNoiseFoods( + starters=[ + "I'd like to order .", + "Can I have with that?", + "I'd like to start with .", + "Can you add to my order?", + "Please include as an appetizer.", + "Can you add to that?", + "Please add to my meal.", + ], + main=[ + "Please add
to my order.", + "I want
as my main dish.", + "For my main course, I'll have
.", + "I'll have
with a side.", + "I'd like
for my entrée.", + "I'd like to order
for dinner.", + "I'd like
as my main course.", + ], + desserts=[ + "I'd like for dessert.", + "Please include in my order.", + "I'll take for dessert.", + "I'd like to finish with .", + "For dessert, I'll have .", + "I'll take to finish.", + "For dessert, I'll have .", + ], + drinks=[ + "I'd like to order beverage.", + "Can I have with that?", + "Please include beverage with my meal.", + "I'd like to add to my order.", + "Can you add beverage to that?", + "I'll take with my meal.", + "Please add beverage to my order.", + ], + ), + times=[ + "I need this delivered by