Skip to content

Commit

Permalink
Merge pull request #39 from Makes-Innovation-Hub/return-question--ans…
Browse files Browse the repository at this point in the history
…wers-to-ui-11

Return question  answers to UI 11
  • Loading branch information
yishain11 authored Aug 6, 2024
2 parents cb6b42c + 20df634 commit 2e49381
Show file tree
Hide file tree
Showing 11 changed files with 449 additions and 21 deletions.
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,16 @@ celerybeat.pid
*.sage.py

# Environments
.env
.env_dev
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

.env_prod
.env
.env_*
# Spyder project settings
.spyderproject
.spyproject
Expand Down Expand Up @@ -159,4 +161,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
14 changes: 12 additions & 2 deletions CONTRIBUTION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,39 @@ Thank you for contributing to our project! To maintain a high standard of code q
## Before Working on an Issue

1. **Open a New Branch for the Issue**
- Always create a new branch while you are on the `main` branch.
- Always create a new branch while you are on the `dev` branch.
- Make sure the branch name includes the issue topic and number.
- **Do NOT** put the issue number at the beginning of the branch name.
- Example: `feature/issue-123-improve-login`
NOT:
NOT:
- `#34-new-login-button`

## Before Opening a Pull Request (PR) - YOU MUST:

1. **Review the Original Issue**

- Ensure you have completed all tasks and met all requirements specified in the issue.

2. **Clean Your Code**

- Remove unnecessary comments and spaces.
- Ensure logical positioning and proper naming conventions are followed.

3. **Add Tests and Error Handling**

- Make sure you have added testing for the main features and proper error handling.

4. **Verify Code Stability**

- Stop the running code and restart to ensure there are no errors and everything runs smoothly.

5. **Sync with Dev Branch**
- Pull from the `dev` branch.
- Fix any merge conflicts and commit your fixes.
- run all the unit tests and make sure all tests pass.

## Opening a Pull Request

- PRs should be opened from your branch to the `dev` branch, **not** the `main` branch.

By following these guidelines, you help ensure that our codebase remains clean, stable, and easy to maintain. Thank you for your cooperation and happy coding!
78 changes: 62 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,64 @@
# code-genie-bot
telegram bot for code genie \
The Code Genie bot will assist graduates in maintaining their study habits and tracking their progress through interactive sessions and resources.
## Team Members
Basel Amin\
Mohammad Shaheen\
Hasan Masalha\
Aya Abbas\
Shaden Hakim
## Product Goal
This Telegram bot, named Code Genie, is designed to help graduates continue their studies and stay committed to practicing even after graduation
## General Architecture
### Telegram Bot:
User Interface: Interacts with users via the Telegram platform. \
Bot Logic: Handles commands and messages from users, processes requests, and sends responses.

User <----> Bot <---> Server <-----> Database
# code-genie-bot
telegram bot for code genie

=======
# Environment Variables (Explanation)
In `.env_dev` file save the following vars:
- `BOT_TOKEN_DEV`: The telegram bot token for full control. Example: **123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi_jklmnopqrstuvwx
**
- `SERVER_URL_DEV`: The backend server url for making requests. Example: **http://localhost:8000/"**

In `.env_prod` file save the following vars:
- `BOT_TOKEN_PROD`: The telegram bot token for full control. Example: **123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi_jklmnopqrstuvwx
**
- `SERVER_URL_PROD`: The backend server url for making requests. Example: **http://localhost:8000/"**
# Environment Variables (Usage)
To load environment variables from a `.env` file in Python, you can use the `python-dotenv` package. Here’s how you can do it:

1. Save an `.env` file in your project. **WARNING**: make sure it is found in `.gitignore`. Save the above [Variables](#environment-variables-explanation) in the `.env` file using the exact provided names.
2. **Install the `python-dotenv` package** (if you haven’t already):
```sh
pip install python-dotenv
```
3. A brief example on how to load a specific environment variable:
```python
import os
from dotenv import load_dotenv
load_dotenv('.env')
bot_token = os.getenv('BOT_TOKEN')
```
Run command for genie_bot :
1. To run in dev env:
```sh
python genie_bot.py dev
#or
python genie_bot.py
```
2. To run in production env:

```sh
python genie_bot.py prod
```


├── code-genie-bot \
# Package initialization \
# Main bot entry point \
│ ├── config\
│ │ # managing and loading configuration settings
│ ├── handlers \
│ │ # Handlers package initialization \
│ │ # Handle bot commands \
│ ├── utils \
│ │ # Utils package initialization \
│ │ # Helper functions \
│ │ # Input validation \
├── tests \
# Tests package initialization \
# Handlers tests \
# Utils tests \
# Environment variables \
# Git ignore file \
# requermint list \
# readme
9 changes: 9 additions & 0 deletions config/CONSTANTS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
HELP_COMMAND_TEXT = (
"Available commands:\n"
"/start - Start the bot\n"
"/help - Show this help message\n"
"/ip - Get public ip\n"
"/question - Get a question from the server\n "
"/ip - get public ip\n"
"/api - connect to server"
)
1 change: 1 addition & 0 deletions config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .config_env import *
37 changes: 37 additions & 0 deletions config/config_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os

from dotenv import load_dotenv


def create_config_env(env_name):
try:
if env_name in ['dev', 'prod']:
env_file = f'.env_{env_name}'
print('env_file: ', env_file)
suffix = env_name.upper()
if load_dotenv(env_file):
try:
bot_token = os.getenv(f'BOT_TOKEN_{suffix}')
server_url = os.getenv(f'SERVER_URL_{suffix}')
except Exception as e:
print(e)
raise KeyError(f"error in loading env vars: {e}")
else:
raise FileNotFoundError(f"Error: Ensure that the .env_dev or .env_prod file exists.")
else:
raise ValueError(f"Unknown environment: {env_name}")

if not bot_token or not server_url:
raise ValueError(f"Missing environment variables for {env_name}")

with open('.env', 'w') as f:
f.write(f"BOT_TOKEN={bot_token}\n")
f.write(f"SERVER_URL={server_url}\n")

except FileNotFoundError as fnf_error:
raise fnf_error
except ValueError as val_error:
raise val_error
except Exception as e:
raise e

40 changes: 40 additions & 0 deletions genie_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import argparse
from config.config_env import create_config_env
from handlers.handlers import *
from telegram.ext import ApplicationBuilder, CommandHandler
import os
from dotenv import load_dotenv


def setup_and_load_env():
parser = argparse.ArgumentParser()
parser.add_argument('env', choices=['dev', 'prod'], nargs='?', default='dev')
args = parser.parse_args()
try:
create_config_env(args.env)
except Exception as e:
raise e


def main():
try:
setup_and_load_env()
load_dotenv('.env')
# Create the Application and pass it your bot's token.
application = ApplicationBuilder().token(os.getenv("BOT_TOKEN")).build()

# Register command handlers
application.add_handler(CommandHandler("start", start_command))
application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("ip", get_public_ip_command))
application.add_handler(CommandHandler('question', question_command))
application.add_handler(CommandHandler('api', api_command))

# Start the Bot
application.run_polling()
except Exception as e:
print('e: ', e)
exit(1)

if __name__ == '__main__':
main()
60 changes: 60 additions & 0 deletions handlers/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import os
from telegram import Update
from telegram.ext import ContextTypes, CallbackContext
import requests
from config import CONSTANTS


async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text('Hello! I am your bot. How can I help you?')


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text(CONSTANTS.HELP_COMMAND_TEXT)


async def get_public_ip_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
try:
response = requests.get('https://api.ipify.org?format=json')
public_ip = response.json()['ip']
await update.message.reply_text(f'The public IP address of the bot is: {public_ip}')
return True
except requests.RequestException as e:
await update.message.reply_text(f'Failed to get public IP address: {e}')
return False

async def question_command(update: Update, context: CallbackContext) -> None:
try:
data = {
"topic": "python",
"difficulty": "easy",
"answers_num": 0
}
# Define headers, if required
headers = {
"accept": "application/json",
"Content-Type": "application/json"
}
response = requests.post(
f'{os.getenv("SERVER_URL")}/question/generate',
json=data,
headers=headers
)
response_data = response.json()
question = response_data.get('Question', 'No question found')
to_return = question
await update.message.reply_text(f"{to_return}")
except requests.exceptions.RequestException as e:
await update.message.reply_text(f"An error occurred: {e}")


async def api_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
try:
response = requests.get(os.getenv("SERVER_URL"))
response.raise_for_status()
data = response.json()
await update.message.reply_text(data)
except requests.RequestException as e:
await update.message.reply_text(f"Request failed: {str(e)}")
except Exception as e:
await update.message.reply_text(f"An unexpected error occurred: {str(e)}")
45 changes: 45 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
annotated-types==0.7.0
anyio==4.4.0
certifi==2024.7.4
charset-normalizer==3.3.2
click==8.1.7
colorama==0.4.6
distro==1.9.0
dnspython==2.6.1
email_validator==2.2.0
fastapi==0.111.1
fastapi-cli==0.0.4
h11==0.14.0
httpcore==1.0.5
httptools==0.6.1
httpx==0.27.0
idna==3.7
iniconfig==2.0.0
Jinja2==3.1.4
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
openai==1.36.1
packaging==24.1
pluggy==1.5.0
pydantic==2.8.2
pydantic_core==2.20.1
Pygments==2.18.0
pytest==8.3.1
pytest-asyncio==0.23.8
python-dotenv==1.0.1
python-multipart==0.0.9
python-telegram-bot==21.4
PyYAML==6.0.1
requests==2.32.3
rich==13.7.1
shellingham==1.5.4
sniffio==1.3.1
starlette==0.37.2
tqdm==4.66.4
typer==0.12.3
typing_extensions==4.12.2
urllib3==2.2.2
uvicorn==0.30.3
watchfiles==0.22.0
websockets==12.0
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from.test_bot import *
Loading

0 comments on commit 2e49381

Please sign in to comment.