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

Final version #1

Merged
merged 1 commit into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
47 changes: 47 additions & 0 deletions Final Bot/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from db import connection
import db

# THE LATEST CURRENCY
cur = connection.cursor()
latest = []

# Query each table and retrieve the latest row
for table_name in ['USD', 'PLN', 'NOK', 'TL']:
cur.execute(f"SELECT TOP 1 * FROM {table_name} ORDER BY theDate DESC")
result = cur.fetchone()
latest.append(result)

rates = {"EUR": 1, "USD": latest[0][0], "PLN": latest[1][0], "NOK": latest[2][0], "TRY": latest[3][0]}


# ALL DATA WITH THE DATES FOR THE GRAPH AND THE PREDICTION

db.cursor.execute("""
SELECT 'USD' as currency, Rate, theDate FROM USD
UNION ALL
SELECT 'NOK' as currency, Rate, theDate FROM NOK
UNION ALL
SELECT 'TRY' as currency, Rate, theDate FROM TL
UNION ALL
SELECT 'PLN' as currency, Rate, theDate FROM PLN
ORDER BY theDate ASC
""")
results = db.cursor.fetchall()

# Store the data in a dictionary
data = {}

for row in results:
currency = row[0]
rate = row[1]
date = row[2]
if currency not in data:
data[currency] = {'rates': [], 'dates': []}
data[currency]['rates'].append(rate)
data[currency]['dates'].append(date)




cur.close()
connection.close()
51 changes: 51 additions & 0 deletions Final Bot/graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import matplotlib.pyplot as plt
import io
from datetime import datetime
import data


def send_currency_exchange_graph(cr):
# Retrieve the data from the database
datas = data.data

currencies = cr

# Create a subplot for each currency if there is more than one currency
if len(currencies) > 1:
num_plots = len(currencies)
fig, axes = plt.subplots(num_plots, 1, figsize=(12, 6 * num_plots), sharex=True)

# Plot the exchange rates for each currency
for i, currency in enumerate(currencies):
rates = datas[currency]['rates']
dates = datas[currency]['dates']
dates = [datetime.strptime(str(d), '%Y-%m-%d').strftime('%m-%d') for d in dates]
axes[i].plot(dates, rates, linewidth=2.0)
axes[i].set_title(f'{currency} Exchange Rate')
axes[i].set_ylabel('Exchange Rate')

# Set the x-axis label
axes[-1].set_xlabel('Date')

# Otherwise, just plot the exchange rates for the single currency
else:
currency = currencies[0]
rates = datas[currency]['rates']
dates = datas[currency]['dates']
dates = [datetime.strptime(str(d), '%Y-%m-%d').strftime('%m-%d') for d in dates]
fig, ax = plt.subplots(figsize=(12, 6))
ax.plot(dates, rates, linewidth=2.0)
ax.set_title(f'{currency} Exchange Rate')
ax.set_ylabel('Exchange Rate')
ax.set_xlabel('Date')

# Create a bytes buffer and save the graph to it
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)

# Close the plot to free up memory
plt.close()

# Return the buffer
return buf.getvalue()
155 changes: 155 additions & 0 deletions Final Bot/mainBot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import telebot
import BOT_KEY
import graph
import prediction
import data

bot = telebot.TeleBot(BOT_KEY.KEY)

# main menu keyboard creation
menu_keyboard = telebot.types.ReplyKeyboardMarkup(resize_keyboard=True).add(
telebot.types.KeyboardButton("Exchange"),
telebot.types.KeyboardButton("Rates"),
telebot.types.KeyboardButton("Graphs"),
telebot.types.KeyboardButton("Prediction")
)

# takes keys from rates dictionary made in db.py file and uses them to create keys for currencies
currency_keyboard = telebot.types.ReplyKeyboardMarkup(resize_keyboard=True).add(
*[telebot.types.KeyboardButton(currency) for currency in data.rates.keys()]
)
graph_keyboard = telebot.types.ReplyKeyboardMarkup(resize_keyboard=True).add(
*[telebot.types.KeyboardButton(currency) for currency in data.rates.keys() if currency != "EUR"]
).add(
telebot.types.KeyboardButton("None")
)

pred_keyboard = telebot.types.ReplyKeyboardMarkup(resize_keyboard=True).add(
*[telebot.types.KeyboardButton(currency) for currency in data.rates.keys() if currency != "EUR"]
)


# used to start/reset bot
@bot.message_handler(commands=['start'])
def handle_start(message):
bot.send_message(message.chat.id, "Welcome to the currency converter bot! Please select an option:",
reply_markup=menu_keyboard)


# after "Exchange" is either sent by a button click or manually user is asked question below
@bot.message_handler(func=lambda message: message.text == "Exchange")
def handle_exchange(message):
bot.send_message(message.chat.id, "How much do you want to convert?")
bot.register_next_step_handler(message, handle_exchange_amount)


# user gave a number, now this function sends a message asking [...] and showing a keyboard with currency codes
def handle_exchange_amount(message):
amount = float(message.text)
bot.send_message(message.chat.id,
f"From which currency do you want to convert {amount:.2f}? Please select from the options below:",
reply_markup=currency_keyboard)
# passing all we got so far to the function below
bot.register_next_step_handler(message, handle_exchange_source, amount)


# again a currency codes keyboard is shown, user picks one
def handle_exchange_source(message, amount):
source_currency = message.text
bot.send_message(message.chat.id,
f"What currency do you want to convert {amount:.2f} {source_currency} to? Please select from the options below:",
reply_markup=currency_keyboard)
# and everything is passed to the function below
bot.register_next_step_handler(message, handle_exchange_target, amount, source_currency)


# here all collected data is converted into what user will see in the end
def handle_exchange_target(message, amount, source_currency):
target_currency = message.text
conversion_rates = data.rates
rate = conversion_rates[target_currency] / conversion_rates[source_currency] # conversion rate is calculated here
converted_amount = amount * rate
# final response with converted value
bot.send_message(message.chat.id,
f"{amount:.2f} {source_currency} is equivalent to {converted_amount:.2f} {target_currency}")
# after the work is done user sees menu keys again so there's no need to use /start
bot.send_message(message.chat.id, "What else can I help you with?", reply_markup=menu_keyboard)


# handling user picking "Rates" option and is shown a currency code keyboard, after clicking one function bellow is triggered
@bot.message_handler(func=lambda message: message.text == "Rates")
def handle_rates(message):
bot.send_message(message.chat.id, "Please select the source currency:", reply_markup=currency_keyboard)
bot.register_next_step_handler(message, handle_rates_source)


# user clicks a button for their target currency
def handle_rates_source(message):
source_currency = message.text
bot.send_message(message.chat.id, f"Please select the target currency for {source_currency}:",
reply_markup=currency_keyboard)
bot.register_next_step_handler(message, handle_rates_target, source_currency)


# previous function sends both target and source here, this function calculates rate
def handle_rates_target(message, source_currency):
target_currency = message.text
conversion_rates = data.rates
# here
exchange_rate = conversion_rates[target_currency] / conversion_rates[source_currency]
# and sends it to the chat
bot.send_message(message.chat.id,
f"The exchange rate between {source_currency} and {target_currency} is {exchange_rate:.4f}")
# and shows menu keyboard again
bot.send_message(message.chat.id, "What else can I help you with?", reply_markup=menu_keyboard)


@bot.message_handler(func=lambda message: message.text == "Graphs")
def handle_exchange(message):
# bot.send_photo(chat_id=message.chat.id, photo=graph.send_currency_exchange_graph("X"))
bot.send_message(message.chat.id, "What currency do you want to graph?", reply_markup=currency_keyboard)
currency = []
bot.register_next_step_handler(message, handle_graph_currencies, currency)


def handle_graph_currencies(message, currency):
curr = message.text
if curr != "No":
if curr == "EUR":
bot.send_message(message.chat.id, "Graphing for EUR is not available. Please choose another currency.", reply_markup=graph_keyboard)
bot.register_next_step_handler(message, handle_graph_currencies, currency)
else:
currency.append(curr)
bot.send_message(message.chat.id, "What other currency do you want to graph?", reply_markup=graph_keyboard)
bot.register_next_step_handler(message, handle_graph_currencies, currency)
else:
bot.send_photo(chat_id=message.chat.id, photo=graph.send_currency_exchange_graph(currency))
# and shows menu keyboard again
bot.send_message(message.chat.id, "What else can I help you with?", reply_markup=menu_keyboard)


@bot.message_handler(func=lambda message: message.text == "Prediction")
def handle_predictions(message):
bot.send_message(message.chat.id, "Predictions are EUR based, ")
bot.send_message(message.chat.id, "Which currency do you want predictions about?", reply_markup=pred_keyboard)
bot.register_next_step_handler(message, handle_currency_predictions)


def handle_currency_predictions(message):
currency = message.text
if currency == "EUR":
bot.send_message(message.chat.id, "Predictions for EUR is not available. Please choose another currency.",reply_markup=pred_keyboard)
bot.register_next_step_handler(message, handle_currency_predictions, currency)
else:
predictions = prediction.send_currency_predict(currency)
bot.send_message(message.chat.id, f"Based on linear regression calculations {currency}/EUR will be {predictions:.2f} this week.")
bot.send_message(message.chat.id, "What else can I help you with?", reply_markup=menu_keyboard)

# bot start
bot.polling()

# keys basically send set messages to the chat and message.text collects them and puts in variables, so they can be used
# that's why user can also just send a message manually and if for some reason keyboard doesn't show, if the message
# is correct everything will work if not it'll be just ignored until correct message is provided. What I used for buttons
# works only on mobile, stuff that theoretically should work both on mobile and web app doesn't work in neither of those
# places (and didn't work in class too) and this version looks nicer.
20 changes: 20 additions & 0 deletions Final Bot/prediction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sklearn.linear_model import LinearRegression
import numpy as np
import data


def send_currency_predict(cr):
currency = cr
dates = []
rates = []
for i in range(len(data.data[currency]['dates'])):
date = data.data[currency]['dates'][i]
date_numeric = date.toordinal()
dates.append([date_numeric])
rates.append(data.data[currency]['rates'][i])
model = LinearRegression()
model.fit(dates, rates)

predictions = model.predict(dates)

return np.mean(predictions)