Shivansh Shukla
Published © Apache-2.0

AI assistant and voice translator using Raspberry Pi 3

A Raspberry Pi 3 AI assistant with English-Hindi translation, Wikipedia access, weather, playing music and system info. Smart & Bilingual!

BeginnerFull instructions providedOver 1 day379
AI assistant and voice translator using Raspberry Pi 3

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
Arduino UNO R-3
×1
zeb pluto speaker
×1
usb microphone
×1
rgb module
×1

Software apps and online services

Google Maps
Google Maps

Hand tools and fabrication machines

10 Pc. Jumper Wire Kit, 5 cm Long
10 Pc. Jumper Wire Kit, 5 cm Long

Story

Read more

Custom parts and enclosures

Prototype Enclosure & Design Roadmap

The current enclosure is a custom-made cardboard prototype designed to house the dual speakers and the USB microphone at an optimal angle for voice reception. I am planning to convert this physical design into a 3D STL file for 3D printing in the next phase of the project

Schematics

Hardware Architecture & Hybrid Connections

This section details the hardware interconnections of the project. I have used a Raspberry Pi 3 as the primary controller, connected to an Arduino Uno via a USB A-to-B cable for serial communication. The setup includes a USB microphone for voice input and a dual-speaker system for audio output. An RGB LED module is interfaced with the Arduino to provide visual status updates (Listening, Processing, and Errors). The entire system is powered by a portable power bank, making it a standalone prototype.

Code

Bilingual Voice Intelligence Logic (Python)

Python
Step 1: Raspberry Pi ka terminal kholein.
Step 2: Zaruri libraries install karein: pip install gTTS SpeechRecognition googletrans==4.0.0-rc1 pygame psutil yt-dlp.
Step 3: Check karein ki Arduino USB port /dev/ttyACM0 par connected hai.
Step 4: Command run karein: python3 main.py.
# ai_assistant.py
# By Shivansh (merged & stable)

import speech_recognition as sr
from googletrans import Translator
from gtts import gTTS
import tempfile, os, time, re, requests, wikipedia, datetime, threading, subprocess, random
import pygame
import psutil
from dateutil import tz
import webbrowser
import urllib.parse



# -------------- CONFIG --------------
OPENWEATHER_API_KEY = "259ad0a2e3545e5051f5df22a79d52db"   # <-- YOUR KEY
NEWS_API_KEY = ""   # optional
DEFAULT_CITY = "Jaunpur"

LANG_EN = "en"
LANG_HI = "hi"
# -------------------------------------

# Init audio & translator
pygame.mixer.pre_init(frequency=44100, size=-16, channels=2, buffer=4096)
pygame.mixer.init()
recognizer = sr.Recognizer()
translator = Translator()

# Arduino serial
try:
    import serial
    arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
    time.sleep(2)
    print("Arduino connected")
except Exception as e:
    arduino = None
    print("Arduino not connected:", e)

def led(state):
    if arduino:
        try:
            arduino.write(state.encode())
        except:
            pass

def speak(text, lang='en'):
    print("Assistant:", text)
    led('S')
    try:
        tts = gTTS(text=text, lang=lang, tld='co.in', slow=False)
        with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
            tts.save(fp.name)
            pygame.mixer.music.load(fp.name)
            pygame.mixer.music.play()
            while pygame.mixer.music.get_busy():
                time.sleep(0.1)
        os.remove(fp.name)
    except Exception as e:
        print("TTS error:", e)
        led('E')

def wait_for_internet(timeout=30):
    import socket
    for i in range(timeout):
        try:
            socket.create_connection(("8.8.8.8", 53), timeout=2)
            print("Internet up")
            return True
        except:
            time.sleep(1)
    return False

# -------- TIME / DATE / WEATHER --------
def get_time_str():
    return datetime.datetime.now().strftime("%I:%M %p")

def get_date_str():
    return datetime.date.today().strftime("%d %B %Y")

def get_weather(city=DEFAULT_CITY):
    if not OPENWEATHER_API_KEY:
        return None
    try:
        url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&units=metric&appid={OPENWEATHER_API_KEY}"
        r = requests.get(url, timeout=8)
        if r.status_code != 200:
            return None
        data = r.json()
        temp = data['main']['temp']
        desc = data['weather'][0]['description']
        return f"{city} ka mausam: {temp} degree Celsius, {desc}."
    except:
        return None

def get_forecast(city=DEFAULT_CITY):
    if not OPENWEATHER_API_KEY:
        return None
    try:
        url = f"https://api.openweathermap.org/data/2.5/forecast?q={city}&units=metric&appid={OPENWEATHER_API_KEY}"
        r = requests.get(url, timeout=8)
        if r.status_code != 200:
            return None
        data = r.json()
        lines = []
        for i in range(0, min(24, len(data['list'])), 8):
            item = data['list'][i]
            dt = item['dt_txt'].split()[0]
            temp = item['main']['temp']
            desc = item['weather'][0]['description']
            lines.append(f"{dt}: {temp}°C, {desc}")
        return " ; ".join(lines)
    except:
        return None

# -------- WIKIPEDIA --------
def wiki_search(query):
    try:
        wikipedia.set_lang("en")
        return wikipedia.summary(query, sentences=2)
    except:
        return None

# -------- NEWS --------


# -------- SAFE MATH --------
MATH_ALLOWED = re.compile(r'^[0-9\.\+\-\*\/\(\) %]+$')
def safe_calc(expr):
    expr = expr.replace('x','*').replace('X','*').strip()
    if not MATH_ALLOWED.match(expr):
        return None
    try:
        return str(eval(expr, {'__builtins__': None}, {}))
    except:
        return None

# -------- DICTIONARY API --------
def define_word_api(word):
    try:
        r = requests.get(f"https://api.dictionaryapi.dev/api/v2/entries/en/{word}", timeout=6)
        if r.status_code != 200:
            return None
        d = r.json()
        return d[0]['meanings'][0]['definitions'][0]['definition']
    except:
        return None
    
    
def youtube_web_play(song):
    try:
        query = urllib.parse.quote(song)
        url = f"https://m.youtube.com/results?search_query={query}"
        webbrowser.open(url)
        return True
    except Exception as e:
        print("Youtube Web Error:", e)
        return False




# -------- COMMAND PATTERNS --------
COMMAND_PATTERNS = [
    (r'\b(time|samay)\b', 'time'),
    (r'\b(date|tareekh|tarikh)\b', 'date'),
    (r'\b(weather in )\s*([A-Za-z ]+)', 'weather_city'),
    (r'\b(weather|mausam|temperature)\b', 'weather'),
    (r'\b(forecast)\b', 'forecast'),
    (r'\b(who is|what is|tell me about|ke baare mein|kaun hai|kya hai)\b', 'wiki'),
    (r'\b(solve|calculate|compute|solve:)\b\s*(.*)', 'math'),
    (r'\b(joke|jokes|joke sunao)\b', 'joke'),
    (r'\b(alarm|set alarm)\b\s*([0-2]?\d[:\.][0-5]\d)', 'alarm'),
    (r'\b(timer|set timer|timer set)\b\s*([0-9]+)\b', 'timer'),
    (r'\b(play|music|gana|song)\b\s*(.*)', 'music'),
    (r'\b(meaning of|define|definition of|what does)\b\s*(.*)', 'dictionary'),
    (r'\b(good morning|namaste|hello|hi)\b', 'greeting'),
    (r'\b(system info|status|uptime)\b', 'sysinfo'),
    (r'\b(exit|stop|quit|band karo)\b', 'exit'),
]

def detect_command(text):
    t = text.lower()
    for pat, cmd in COMMAND_PATTERNS:
        m = re.search(pat, t)
        if m:
            return cmd, m.groups()
    return None, None

# -------- LISTEN --------
def listen_once(timeout=25, phrase_time_limit=35):
    with sr.Microphone() as source:
        recognizer.adjust_for_ambient_noise(source, duration=1)
        led('L')
        print("Listening...")
        try:
            audio = recognizer.listen(source, timeout=timeout, phrase_time_limit=phrase_time_limit)
        except sr.WaitTimeoutError:
            led('E')
            speak("I didn't hear anything.", LANG_EN)
            return None
    try:
        text = recognizer.recognize_google(audio)
        print("User:", text)
        return text
    except sr.UnknownValueError:
        led('E')
        speak("Sorry, I didn't catch that. Please repeat.", LANG_EN)
        return None
    except sr.RequestError:
        led('E')
        speak("Speech service is unavailable.", LANG_EN)
        return None

# -------- ALARM --------
alarms = []
def alarm_worker():
    while True:
        now = datetime.datetime.now().strftime("%H:%M")
        for a in alarms[:]:
            if a == now:
                speak("Alarm! It's " + now, LANG_EN)
                alarms.remove(a)
        time.sleep(10)

threading.Thread(target=alarm_worker, daemon=True).start()

# -------- MAIN LOOP --------
def run_assistant():
    wait_for_internet(20)
    speak("Namaste here I am an assistant and voice translator programmed by Shivansh Shukla reading in Class 10th in Harihar Public School,Jaunpur Please say something in Hindi or English.", LANG_HI)
    current_music_player = None

    while True:
        try:
            text = listen_once()
            if not text:
                continue

            try:
                detected_lang = translator.detect(text).lang
            except:
                detected_lang = 'en'
            resp_lang = LANG_EN if detected_lang != 'hi' else LANG_HI

            cmd, groups = detect_command(text)

            # TIME
            if cmd == 'time':
                speak("The time is " + get_time_str(), resp_lang)

            # DATE
            elif cmd == 'date':
                speak("Today's date is " + get_date_str(), resp_lang)

            # WEATHER DEFAULT CITY
            elif cmd == 'weather':
                w = get_weather(DEFAULT_CITY)
                speak(w or "Weather not available.", resp_lang)

            # WEATHER BY CITY
            elif cmd == 'weather_city':
                city = groups[1] if len(groups) > 1 else DEFAULT_CITY
                w = get_weather(city.strip())
                speak(w or f"Weather not available for {city}", resp_lang)

            # FORECAST
            elif cmd == 'forecast':
                f = get_forecast(DEFAULT_CITY)
                speak(f or "Forecast not available.", resp_lang)

            # WIKIPEDIA
            elif cmd == 'wiki':
                q = re.sub(r'^(tell me about|who is|what is|ke baare mein)\s*', '', text, flags=re.I)
                ans = wiki_search(q)
                speak(ans or "I could not find that.", resp_lang)

            # MATH
            elif cmd == 'math':
                expr = groups[1] if len(groups) > 1 else text
                result = safe_calc(expr)
                speak("The answer is " + result if result else "I can't calculate that.", resp_lang)

            # JOKE
            elif cmd == 'joke':
                speak(random.choice([
                    "Why did the computer show up late? It had a hard drive.",
                    "Why do programmers prefer dark mode? Because light attracts bugs.",
                    "My computer needed a break, and it crashed."
                ]), resp_lang)

            # NEWS
            

            # ALARM
            elif cmd == 'alarm':
                if groups and len(groups) >= 2 and groups[1]:
                    time_str = groups[1]
                    alarms.append(time_str)
                    speak("Alarm set for " + time_str, resp_lang)
                else:
                    speak("Please say alarm time like alarm 06:30", resp_lang)

            # TIMER
            elif cmd == 'timer':
                if groups and len(groups) >= 2 and groups[1]:
                    secs = int(groups[1])
                    speak(f"Setting timer for {secs} seconds.", resp_lang)
                    threading.Thread(
                        target=lambda s: (time.sleep(s), speak("Timer finished.", resp_lang)),
                        args=(secs,), 
                        daemon=True
                    ).start()
                else:
                    speak("Say timer in seconds like set timer 10", resp_lang)

            # MUSIC
            elif cmd == 'music':
                song = groups[-1].strip() if groups and groups[-1] else ""
                speak(f"Playing {song}" if song else "Playing music", resp_lang)
                ok =  youtube_web_play(song if song else "music")
                if ok:
                    speak("Please wait playing.", resp_lang)
                else:
                    speak("could not play that song.", resp_lang)
            

            # DICTIONARY
            elif cmd == 'dictionary':
                word = groups[-1].split()[-1]
                meaning = define_word_api(word)
                speak(meaning or "Definition not found.", resp_lang)

            # GREETING
            elif cmd == 'greeting':
                speak("Namaste! Kaise madad karu?", resp_lang)

            # SYSTEM INFO
            elif cmd == 'sysinfo':
                try:
                    cpu = psutil.cpu_percent(interval=1)
                    mem = psutil.virtual_memory().percent
                    speak(f"CPU {cpu}% , RAM {mem}%", resp_lang)
                except:
                    speak("System info not available.", resp_lang)

            # EXIT
            elif cmd == 'exit':
                speak("Goodbye! See you soon.", resp_lang)
                break

            # DEFAULT (Translate or Wiki fallback)
            else:
                if re.search(r"\b(who|what|where|when|why|how|kaun|kya|kahan|kab|kyun)\b", text.lower()):
                    ans = wiki_search(text)
                    if ans:
                        speak(ans, resp_lang)
                        continue

                try:
                    lang = translator.detect(text).lang
                except:
                    lang = 'en'

                if lang == 'hi':
                    out = translator.translate(text, src='hi', dest='en').text
                    speak("The English translation is: " + out, LANG_EN)
                else:
                    out = translator.translate(text, src='en', dest='hi').text
                    speak("Anuvad hai: " + out, LANG_HI)

            time.sleep(0.5)

        except KeyboardInterrupt:
            speak("Stopping assistant. Goodbye!", LANG_EN)
            break
        except Exception as e:
            print("Main error:", e)
            led('E')
            speak("Something went wrong.", LANG_EN)

if __name__ == "__main__":
    run_assistant()

Credits

Shivansh Shukla
1 project • 1 follower

Comments