| import os |
| import time |
| import datetime |
| import requests |
| from dotenv import load_dotenv |
| from cachier import cachier |
| import logging |
| import gradio as gr |
| from babel import numbers as babel_numbers |
|
|
| logging.getLogger("urllib3.connectionpool").setLevel(logging.WARNING) |
|
|
| load_dotenv() |
| API_KEY = os.getenv("EXCHANGE_API_KEY") |
|
|
| VALID_CURRENCIES = [ |
| "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", |
| "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", |
| "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHF", "CLF", "CLP", |
| "CNH", "CNY", "COP", "CRC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", |
| "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "FOK", "GBP", "GEL", |
| "GGP", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", |
| "HTG", "HUF", "IDR", "ILS", "IMP", "INR", "IQD", "IRR", "ISK", "JEP", |
| "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KID", "KMF", "KRW", "KWD", |
| "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", |
| "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", |
| "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", |
| "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", |
| "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SLL", |
| "SOS", "SRD", "SSP", "STN", "SYP", "SZL", "THB", "TJS", "TMT", "TND", |
| "TOP", "TRY", "TTD", "TVD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", |
| "UZS", "VES", "VND", "VUV", "WST", "XAF", "XCD", "XCG", "XDR", "XOF", |
| "XPF", "YER", "ZAR", "ZMW", "ZWG", "ZWL" |
| ] |
|
|
| currency_choices = [ |
| (f"{babel_numbers.get_currency_name(code, locale='en_US')} ({code})", code) |
| for code in VALID_CURRENCIES |
| ] |
|
|
| SEPARATOR = "=" * 50 |
|
|
| logging.basicConfig(format="%(message)s", level=logging.DEBUG) |
|
|
| if not API_KEY: |
| raise ValueError("EXCHANGE_API_KEY environment variable not set!") |
|
|
| BASE_URL = f"https://v6.exchangerate-api.com/v6/{API_KEY}/latest/" |
|
|
|
|
| @cachier(stale_after=datetime.timedelta(days=1)) |
| def get_exchange_data(base_currency): |
|
|
| url = BASE_URL + base_currency |
| try: |
| response = requests.get(url, timeout=10) |
| if response.status_code == 200: |
| data = response.json() |
| if data.get("result") == "success": |
| logging.info("Fresh data fetched from API") |
| data["_fetched_at"] = time.time() |
| return data |
| else: |
| logging.error(f"API Error: {data.get('error-type')}") |
| else: |
| logging.error(f"HTTP Error: Status Code {response.status_code}") |
| except requests.RequestException as e: |
| logging.error(f"Network Error: {e}") |
|
|
| return None |
|
|
|
|
| def get_valid_currency(prompt): |
| while True: |
| user_input = input(prompt).upper().strip() |
|
|
| if not user_input.isalpha() or len(user_input) != 3: |
| logging.error("Error: Currency code must be 3 letters (e.g., USD).") |
| continue |
|
|
| if user_input not in VALID_CURRENCIES: |
| logging.error( |
| f"Warning: '{user_input}' might not be supported or is invalid." |
| ) |
| continue |
|
|
| return user_input |
|
|
|
|
| def get_valid_amount(currency_name): |
| while True: |
| user_input = input(f"Enter {currency_name} amount: ").strip() |
| try: |
| val = float(user_input) |
| if val < 0: |
| logging.error("Error: Amount cannot be negative.") |
| continue |
| return val |
| except ValueError: |
| logging.error("Error: Please enter a valid numeric amount.") |
|
|
|
|
| def convert_currency(base_currency, target_currency, amount): |
|
|
| data = get_exchange_data(base_currency) |
|
|
| if not data: |
| return None |
|
|
| rates = data.get("conversion_rates", {}) |
| rate = rates.get(target_currency) |
|
|
| if not rate: |
| logging.error(f"Currency {target_currency} not found") |
| return None |
|
|
| exchange_amount = amount * rate |
|
|
| fetch_time = data.get("_fetched_at", 0) |
| is_cached = (time.time() - fetch_time) > 2 |
|
|
| return { |
| "amount": exchange_amount, |
| "rate": rate, |
| "timestamp": data.get("time_last_update_utc"), |
| "from_cache": is_cached, |
| } |
|
|
|
|
| def get_currency_symbol_name(currency): |
| name = babel_numbers.get_currency_name(currency, locale="en_US") |
| sym = babel_numbers.get_currency_symbol(currency, locale="en_US") |
| return sym, name |
|
|
|
|
| def currency_covertor(base_currency, target_currency, amount): |
|
|
| result = convert_currency(base_currency, target_currency, amount) |
| b_sym, b_name = get_currency_symbol_name(base_currency) |
| t_sym, t_name = get_currency_symbol_name(target_currency) |
|
|
| if result: |
| base_output = f"Currency: {b_name}\n" f"Amount: {b_sym} {amount:,.2f}" |
|
|
| if result: |
| target_output = ( |
| f"Currency: {t_name}\n" f"Amount: {t_sym} {result['amount']:,.2f}" |
| ) |
| data = get_exchange_data(base_currency) |
| rates = data.get("conversion_rates", {}) |
| exchange_rate = f"1 {b_name}({base_currency}) is {rates.get(target_currency)} {t_name}({target_currency})" |
|
|
| return base_output, target_output, exchange_rate |
|
|
|
|
| with gr.Blocks(title="Day12-Currency-Converter(using API)") as demo: |
| gr.Markdown("# 💱 Currency-Converter") |
| gr.Markdown("### Select currency types and enter your amount") |
| with gr.Column(): |
| with gr.Row(): |
| base_currency = gr.Dropdown( |
| choices=currency_choices, |
| label="Base Currency", |
| interactive=True, |
| value="USD", |
| ) |
| target_currency = gr.Dropdown( |
| choices=currency_choices, |
| label="Base Currency", |
| interactive=True, |
| value="INR", |
| ) |
| amount = gr.Number( |
| label="Enter amount for your selected base currency", value=100 |
| ) |
|
|
| convert_button = gr.Button("Convert", interactive=True, variant="primary") |
|
|
| with gr.Row(): |
| base_output = gr.Textbox(label="Base Currency Details") |
| target_output = gr.Textbox(label="Target Currency Details") |
| exchange_rate = gr.Textbox(label="Exchange Rate Details") |
|
|
| convert_button.click( |
| fn=currency_covertor, |
| inputs=[base_currency, target_currency, amount], |
| outputs=[base_output, target_output, exchange_rate], |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|