├── README.md ├── pdf_audio_CLI.py ├── pdf_audio_GUI.py ├── pdf_audio_reader.py ├── quotes.pdf ├── read.py ├── requirements.txt └── speak.py /README.md: -------------------------------------------------------------------------------- 1 | # PDF ORATEUR 2 | 3 | A **simple** and **offline** PDF audio reader using Python. 4 | 5 | 6 | ## How it works? 7 | 8 | The task can be simply divided into 2 steps: 9 | 10 | 1. Extract text from PDF. Refer [read.py](https://github.com/nikhilkumarsingh/PDF_AUDIO_READER/blob/master/read.py) for a sample. 11 | 12 | 2. Convert text to speech. Refer [speak.py](https://github.com/nikhilkumarsingh/PDF_AUDIO_READER/blob/master/speak.py) for a sample. 13 | 14 | [pdf_audio_reader.py](https://github.com/nikhilkumarsingh/PDF_AUDIO_READER/blob/master/pdf_audio_reader.py) contains the complete code for python script. 15 | [pdf_audio_CLI.py](https://github.com/saberprashant/PDF_AUDIO_READER/blob/prashant/pdf_audio_CLI.py) contains the whole code for the Command Line Interface(CLI) of this project. 16 | [pdf_audio_GUI.py](https://github.com/saberprashant/PDF_AUDIO_READER/blob/prashant/pdf_audio_GUI.py) contains the whole code for the GUI version of this project. 17 | 18 | ## Dependencies 19 | 20 | - [PyPDF2](https://github.com/mstamy2/PyPDF2) 21 | 22 | ``` 23 | pip install PyPDF2 24 | ``` 25 | 26 | - [pyttsx3](https://github.com/nateshmbhat/pyttsx3) 27 | 28 | ``` 29 | pip install pyttsx3 30 | ``` 31 | ``` 32 | pip install pyaudio and pywin32 (if not working) 33 | ``` 34 | 35 | ## TODOs 36 | - [ ] Create a Python package for this project. 37 | 38 | 39 | ## Want to contribute? 40 | 41 | - Fork the repo on GitHub 42 | 43 | - Clone the project to your own machine 44 | 45 | - Commit changes to your own branch 46 | 47 | - Push your work back up to your fork on Github 48 | 49 | - Submit a Pull request! 50 | 51 | 52 | ## Video link: 53 | [](https://www.youtube.com/watch?v=J-o99pzbBJk) 54 | 55 | [Indian Pythonista](https://youtube.com/IndianPythonista) 56 | -------------------------------------------------------------------------------- /pdf_audio_CLI.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | # importing dependency packages 4 | import os 5 | import argparse 6 | import PyPDF2 7 | import pyttsx3 8 | 9 | 10 | # error messages 11 | INVALID_FILETYPE_MSG = "Error: Invalid file format. %s must be a .pdf file. \ 12 | Make sure to add .pdf in the end of file. " 13 | INVALID_PATH_MSG = "Error: Invalid file path/name. Path %s does not exist." 14 | INVALID_VOICE_INPUT = "Error: %s is wrong input for voice. Enter 'm' or 'f' for voice." 15 | 16 | 17 | def validate_file(file_name): 18 | ''' 19 | validate file name(with .pdf) and path. 20 | ''' 21 | if not valid_filetype(file_name): 22 | print(INVALID_FILETYPE_MSG % (file_name)) 23 | quit() 24 | elif not valid_path(file_name): 25 | print(INVALID_PATH_MSG % (file_name)) 26 | quit() 27 | return 28 | 29 | 30 | def valid_filetype(file_name): 31 | # validate file type 32 | return file_name.endswith('.pdf') 33 | 34 | 35 | def valid_path(path): 36 | # validate file path 37 | return os.path.exists(path) 38 | 39 | 40 | def valid_voice(voice): 41 | #validate correct input for male or female voice 42 | voices = ['m', 'f'] 43 | 44 | if voice not in voices: 45 | print(INVALID_VOICE_INPUT % (voice)) 46 | quit() 47 | 48 | 49 | def extract_text(args): 50 | """ 51 | function to extract text from pdf at given filename 52 | and that filename can be used by args.speak[0] 53 | """ 54 | filename = args.speak[0] 55 | validate_file(filename) 56 | pdfFileObj = open(filename, "rb") 57 | pdfReader = PyPDF2.PdfFileReader(pdfFileObj) 58 | 59 | mytext = "" 60 | 61 | for pageNum in range(pdfReader.numPages): 62 | pageObj = pdfReader.getPage(pageNum) 63 | mytext += pageObj.extractText() 64 | 65 | pdfFileObj.close() 66 | 67 | return mytext 68 | 69 | 70 | def speak_text(text, rate, voice): 71 | """ 72 | function to invoke TTS engine to speak the pdf text 73 | """ 74 | engine = pyttsx3.init() 75 | all_voices = engine.getProperty('voices') #getting available voices by system-engine 76 | maleVoice = all_voices[0].id 77 | femaleVoice = all_voices[1].id 78 | voice = maleVoice if voice == 'm' else femaleVoice 79 | engine.setProperty('rate', rate) 80 | engine.setProperty('voice', voice) 81 | engine.say(text) 82 | engine.runAndWait() 83 | 84 | 85 | def main(): 86 | 87 | parser = argparse.ArgumentParser(description=" \"PDF Orateur\" - A PDF Audio Reader! \n \ 88 | \"Authors\" - Nikhil Kumar and Prashant Jain ") 89 | parser.add_argument("speak", type=str, nargs=1, 90 | metavar="file_name", default=None, 91 | help="Opens and reads the specified pdf file in human voice.") 92 | parser.add_argument("-r", "--rate", type=int, nargs=1, 93 | metavar="rate_of_speech", default=None, 94 | help="Select the rate of speech, default is 150.") 95 | parser.add_argument("-v", "--voice", type=str, nargs=1, 96 | metavar="voice", default=None, 97 | help="Select male or female voice. Enter 'm' for male voice or 'f' for \ 98 | female voice preceded by -v. Default voice in male") 99 | 100 | args = parser.parse_args() #parsing all arguments in args var 101 | 102 | if args.rate is not None: 103 | rate = args.rate[0] 104 | else: 105 | rate = 150 #default rate of speech 106 | 107 | if args.voice is not None: 108 | voice = args.voice[0] 109 | valid_voice(voice) 110 | else: 111 | voice = 'm' #default voice of speech -male 112 | 113 | if args.speak is not None: 114 | text = extract_text(args) 115 | speak_text(text, rate, voice) #passing all three arguments 116 | 117 | 118 | if __name__ == "__main__": 119 | main() 120 | -------------------------------------------------------------------------------- /pdf_audio_GUI.py: -------------------------------------------------------------------------------- 1 | #dependencies 2 | # for python 3 3 | from tkinter import * 4 | from tkinter import filedialog 5 | import PyPDF2 6 | import pyttsx3 7 | 8 | # for python 2 uncomment the following and comment the above one 9 | # from Tkinter import * 10 | # import tkFileDialog #change tkFileDialog in line 17 11 | # import PyPDF2 12 | # import pyttsx3 13 | 14 | 15 | def extract_text(): 16 | '''To extract text from chosen PDF file''' 17 | file = filedialog.askopenfile(parent=root, mode='rb', title='Choose a PDF file') 18 | if file != None: 19 | pdfReader = PyPDF2.PdfFileReader(file) 20 | global mytext 21 | mytext = "" 22 | for pageNum in range(pdfReader.numPages): 23 | pageObj = pdfReader.getPage(pageNum) 24 | mytext += pageObj.extractText() 25 | file.close() 26 | 27 | 28 | def stop_speaking(): 29 | '''To stop the TTS engine on Stop click button''' 30 | engine.stop() 31 | 32 | 33 | def speak_text(): 34 | '''Function to invoke TTS engine to speak the pdf text''' 35 | global rate 36 | global male 37 | global female 38 | rate = int(rate.get()) #getting value from rate entry widget 39 | engine.setProperty('rate', rate) #setting inputted rate 40 | male = int(male.get()) 41 | female = int(female.get()) 42 | all_voices = engine.getProperty('voices') #extracting all voices from engine 43 | maleVoice = all_voices[0].id #for male voice 44 | femaleVoice = all_voices[1].id #for female voice 45 | if (male == 0 and female == 0) or (male == 1 and female == 1): #default voice-> male 46 | engine.setProperty('voice', maleVoice) 47 | elif male == 0 and female == 1: 48 | engine.setProperty('voice', femaleVoice) 49 | else: 50 | engine.setProperty('voice', maleVoice) 51 | 52 | engine.say(mytext) 53 | engine.runAndWait() 54 | 55 | 56 | 57 | def Application(root): 58 | '''Whole gui app''' 59 | root.geometry('{}x{}'.format(600, 500)) #for fixed size window 60 | root.resizable(width=False, height=False) 61 | root.title("PDF Orateur") 62 | root.configure(background="#e0ffff") 63 | global rate, male, female 64 | 65 | frame1 = Frame(root, width=500, height=200, bg="#8a2be2") #frame 1 for project name and desc. 66 | frame2 = Frame(root, width=500, height=450, bg="#e0ffff") #frame 2 for rest part 67 | frame1.pack(side="top", fill="both") 68 | frame2.pack(side="top", fill="y") 69 | 70 | #frame 1 widgets 71 | name1 = Label(frame1, text="PDF Orateur", fg="white", bg="#8a2be2", font="Arial 28 bold") 72 | name1.pack() 73 | name2 = Label(frame1, text="A simple PDF Audio Reader for you!", fg="white", 74 | bg="#8a2be2", font="Calibri 15") 75 | name2.pack() 76 | 77 | #frame 2 widgets 78 | btn = Button(frame2, text='Select PDF file', command=extract_text, activeforeground="red", 79 | padx="70", pady="10", fg="white", bg="black", font="Arial 12") 80 | btn.grid(row=0, pady=20, columnspan=2) 81 | 82 | rate_text = Label(frame2, text="Enter Rate of Speech:", fg="black",bg="#e0ffff", 83 | font="Arial 12") 84 | rate_text.grid(row=1, column=0, pady=15, padx=0, sticky=E) 85 | rate = Entry(frame2, text="200", fg="black",bg="white", font="Arial 12") 86 | rate.grid(row=1, column=1, padx=30, pady=15,sticky=W) 87 | # rate.focus_set() 88 | 89 | voice_text = Label(frame2, text="Voice:", fg="black",bg="#e0ffff", font="Arial 12") 90 | voice_text.grid(row=2, column=0, pady=15, padx=0, sticky=E) 91 | male = IntVar() #to store male voice option value 92 | maleOpt = Checkbutton(frame2,text="Male",bg="#e0ffff", 93 | variable=male, 94 | onvalue=1, 95 | offvalue=0) 96 | maleOpt.grid(row=2, column=1, pady=0, padx=30, sticky=W) 97 | female = IntVar() #to store female voice option value 98 | femaleOpt = Checkbutton(frame2,text="Female",bg="#e0ffff", 99 | variable=female, 100 | onvalue=1, 101 | offvalue=0) 102 | femaleOpt.grid(row=3, column=1, pady=0, padx=30, sticky=W) 103 | 104 | submitBtn = Button(frame2, text='Play PDF file', command=speak_text, activeforeground="red", 105 | padx="60", pady="10", fg="white", bg="black", font="Arial 12") 106 | submitBtn.grid(row=4,column=0, pady=65) 107 | 108 | #stop button 109 | stopBtn = Button(frame2, text='Stop playing', command=stop_speaking,activeforeground="red", 110 | padx="60", pady="10", fg="white", bg="black", font="Arial 12") 111 | stopBtn.grid(row=4, column=1, pady=65) 112 | 113 | 114 | 115 | 116 | 117 | if __name__ == "__main__": 118 | mytext, rate, male, female = "", 100, 0, 0 #global vars 119 | engine = pyttsx3.init() 120 | root = Tk() 121 | Application(root) 122 | root.mainloop() 123 | 124 | -------------------------------------------------------------------------------- /pdf_audio_reader.py: -------------------------------------------------------------------------------- 1 | import PyPDF2 2 | import pyttsx3 3 | 4 | 5 | def extract_text(filename): 6 | """ 7 | function to extract text from pdf at given filename 8 | """ 9 | pdfFileObj = open(filename, "rb") 10 | pdfReader = PyPDF2.PdfFileReader(pdfFileObj) 11 | 12 | mytext = "" 13 | 14 | for pageNum in range(pdfReader.numPages): 15 | pageObj = pdfReader.getPage(pageNum) 16 | mytext += pageObj.extractText() 17 | 18 | pdfFileObj.close() 19 | 20 | return mytext 21 | 22 | 23 | def speak_text(text): 24 | """ 25 | function to invoke TTS engine to speak the pdf text 26 | """ 27 | engine = pyttsx3.init() 28 | engine.setProperty('rate', 150) 29 | engine.setProperty('voice', 'en+m7') 30 | engine.say(text) 31 | engine.runAndWait() 32 | 33 | 34 | if __name__ == "__main__": 35 | text = extract_text("quotes.pdf") 36 | speak_text(text) -------------------------------------------------------------------------------- /quotes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikhilkumarsingh/PDF_AUDIO_READER/41e6da5692358792be99bc7b21529bc9219f7941/quotes.pdf -------------------------------------------------------------------------------- /read.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Sample python script to demonstrate text extraction form PDF 3 | ''' 4 | import PyPDF2 5 | 6 | pdfFileObj = open("quotes.pdf", "rb") 7 | 8 | pdfReader = PyPDF2.PdfFileReader(pdfFileObj) 9 | 10 | mytext = "" 11 | 12 | for pageNum in range(pdfReader.numPages): 13 | pageObj = pdfReader.getPage(pageNum) 14 | 15 | mytext += pageObj.extractText() 16 | 17 | pdfFileObj.close() 18 | 19 | print(mytext) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyPDF2==1.26.0 2 | pyttsx3==2.7 3 | -------------------------------------------------------------------------------- /speak.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Sample python script to demonstrate TTS using pyttsx3 3 | ''' 4 | import pyttsx3 5 | 6 | engine = pyttsx3.init() 7 | 8 | engine.setProperty('rate', 150) 9 | 10 | engine.setProperty('voice', 'en+f3') 11 | engine.say("hello") 12 | 13 | engine.runAndWait() --------------------------------------------------------------------------------