import tkinter as tk
from tkinter import ttk, messagebox
import pandas as pd
import sv_ttk
import random
import cv2
import os
from deepface import DeepFace
from PIL import Image, ImageTk
import nltk
from nltk.sentiment import SentimentIntensityAnalyzer
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.pdfgen import canvas
import google.generativeai as genai# Set your OpenAI API key
# Ensure the required NLTK data is downloaded
nltk.download('vader_lexicon')
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
global voter_id_start
voter_id_start = None
genai.configure(api_key="AIzaSyAUwfsqPqDOEUCWI-wvi8fBNVsymdobums")
model = genai.GenerativeModel("gemini-1.5-flash")
# Create an Excel file and define voter data in the code
def create_voter_data():
voter_data = {'VoterID': ['VOTER123', 'VOTER456', 'VOTER789', 'VOTER1011', 'VOTER1213', 'ADMIN123', 'ADMIN456']}
df = pd.DataFrame(voter_data)
df.to_excel('voter_data.xlsx', index=False)
print("Voter data has been saved to 'voter_data.xlsx'.")
def load_voter_data():
try:
df = pd.read_excel('voter_data.xlsx')
return df['VoterID'].tolist()
except Exception as e:
print("Error loading voter data:", e)
return []
class VoteVistaApp(tk.Tk):
def __init__(self):
super().__init__()
sv_ttk.set_theme("dark")
self.title("VoteVista - Desktop Application")
self.geometry("400x200")
self.resizable(False, False)
create_voter_data()
self.voter_data = load_voter_data()
if not self.voter_data:
messagebox.showerror("Error", "No voter data found.")
self.quit()
self.sia = SentimentIntensityAnalyzer() # Initialize Sentiment Analyzer
self.login_page()
def center_window(self, width, height):
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
position_top = int(screen_height / 2 - height / 2)
position_left = int(screen_width / 2 - width / 2)
self.geometry(f'{width}x{height}+{position_left}+{position_top}')
def login_page(self):
for widget in self.winfo_children():
widget.destroy()
self.center_window(400, 200)
login_frame = ttk.Frame(self)
login_frame.place(relx=0.5, rely=0.5, anchor="center")
ttk.Label(login_frame, text="Voter Login", font=("Arial", 18)).grid(row=0, column=0, pady=(0, 20))
ttk.Label(login_frame, text="Enter Voter ID:").grid(row=1, column=0, pady=(10, 5))
self.voter_id_entry = ttk.Entry(login_frame, width=40)
self.voter_id_entry.grid(row=2, column=0, pady=5)
self.login_button = ttk.Button(login_frame, text="Login", command=self.check_voter_id, width=40)
self.login_button.grid(row=3, column=0, pady=(10, 5))
def check_voter_id(self):
voter_id = self.voter_id_entry.get()
global voter_id_start
voter_id_start = voter_id
print(voter_id_start)
if voter_id in self.voter_data:
messagebox.showinfo("Success", "Voter ID Verified!")
self.adhar_num_otp()
else:
messagebox.showerror("Error", "Invalid Voter ID")
def adhar_num_otp(self):
self.center_window(400, 300)
for widget in self.winfo_children():
widget.destroy() # Clear the screen
def validate_otp():
if otp_input.get() == "1234":
self.face_scan_page()
else:
error_label.config(text="Invalid OTP. Please try again.")
# Frame to hold widgets and align them to center
main_frame = ttk.Frame(self)
main_frame.pack(expand=True) # This will center the main_frame in the window
# Aadhaar number input
ttk.Label(main_frame, text="Enter Aadhaar Number:").pack(pady=5, anchor="center")
adhar_num_input = ttk.Entry(main_frame, width=40)
adhar_num_input.pack(pady=5, anchor="center")
# OTP input
ttk.Label(main_frame, text="Enter OTP:").pack(pady=5, anchor="center")
otp_input = ttk.Entry(main_frame, show="*", width=40)
otp_input.pack(pady=5, anchor="center")
# Button to validate OTP
validate_button = ttk.Button(main_frame, text="Submit OTP", command=validate_otp, width=30)
validate_button.pack(pady=10, anchor="center")
# Error message label
error_label = ttk.Label(main_frame, text="", foreground="red")
error_label.pack(anchor="center")
def face_scan_page(self):
for widget in self.winfo_children():
widget.destroy()
self.center_window(800, 400)
scan_frame = ttk.Frame(self)
scan_frame.pack(expand=True)
ttk.Label(scan_frame, text="Face Scan Verification", font=("Arial", 18)).pack(pady=20)
ttk.Label(scan_frame, text="Place your face in front of the camera.").pack(pady=10)
ttk.Button(scan_frame, text="Verify Face", command=self.verify_face).pack(pady=20)
def verify_face(self):
print(voter_id_start)
cap = cv2.VideoCapture(0)
if not cap.isOpened():
messagebox.showerror("Error", "Unable to access webcam.")
return
ret, frame = cap.read()
if ret:
webcam_image_path = "deepface/capture_img.jpg"
cv2.imwrite(webcam_image_path, frame)
messagebox.showinfo("Success", "Image captured, verifying face...")
try:
# Use the voter_id_start variable to form the path for the pre-existing image
pre_existing_image_path = f"deepface/{voter_id_start}.jpg"
print(pre_existing_image_path)
# Check if the pre-existing image file exists
if not os.path.exists(pre_existing_image_path):
messagebox.showerror("Error", f"No image found for Voter ID: {voter_id_start}")
return
# Perform the face verification using the dynamically created image path
result = DeepFace.verify(webcam_image_path, pre_existing_image_path)
if result["verified"]:
messagebox.showinfo("Success", "Face verified successfully!")
self.show_captured_image(webcam_image_path)
else:
messagebox.showerror("Error", "Face verification failed.")
except Exception as e:
messagebox.showerror("Error", f"Face verification failed: {str(e)}")
else:
messagebox.showerror("Error", "Failed to capture image.")
cap.release()
def show_captured_image(self, image_path):
for widget in self.winfo_children():
widget.destroy()
self.center_window(800, 600)
# Create a frame for the image and button
image_frame = ttk.Frame(self)
image_frame.pack(expand=True)
# Display the captured image
img = cv2.imread(image_path)
img = cv2.resize(img, (600, 400)) # Resize to fit the window
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convert color to RGB for Tkinter compatibility
# Convert image to PhotoImage for Tkinter
img_pil = Image.fromarray(img) # Convert to PIL Image
img_tk = ImageTk.PhotoImage(img_pil) # Convert to Tkinter PhotoImage
image_label = ttk.Label(image_frame, image=img_tk)
image_label.image = img_tk # Keep a reference to avoid garbage collection
image_label.pack(pady=20)
# Button to proceed
proceed_button = ttk.Button(image_frame, text="Proceed", command=self.personal_questions_verification_page,
width=40)
proceed_button.pack(pady=20)
def personal_questions_verification_page(self):
"""
This phase comes after face scan and image display.
The voter must answer personal questions correctly before proceeding to sentiment analysis.
"""
for widget in self.winfo_children():
widget.destroy()
self.center_window(600, 400)
question_frame = ttk.Frame(self)
question_frame.pack(expand=True)
ttk.Label(question_frame, text="Personal Questions Verification", font=("Arial", 18)).pack(pady=20)
self.preassigned_answers = {
"What is your favorite color?": "blue",
"What is your pet's name?": "buddy",
"What is your hometown?": "springfield",
}
# Randomly select a question
self.current_question, self.correct_answer = random.choice(list(self.preassigned_answers.items()))
ttk.Label(question_frame, text=self.current_question).pack(pady=10)
self.answer_entry = ttk.Entry(question_frame, width=50)
self.answer_entry.pack(pady=5)
submit_btn = ttk.Button(question_frame, text="Submit", command=self.validate_personal_question, width=40)
submit_btn.pack(pady=20)
def validate_personal_question(self):
"""
Validate the voter's answer to the personal question.
If correct, proceed to sentiment analysis; otherwise, show an error.
"""
answer = self.answer_entry.get().strip().lower() # Normalize the answer for comparison
if answer == self.correct_answer.lower():
messagebox.showinfo("Success", "Answer verified successfully! Proceeding to sentiment analysis.")
self.personal_questions_page() # Proceed to sentiment analysis
else:
messagebox.showerror("Error", "Incorrect answer. Please try again.")
def personal_questions_page(self):
for widget in self.winfo_children():
widget.destroy()
self.center_window(400, 400)
question_frame = ttk.Frame(self)
question_frame.pack(expand=True)
ttk.Label(question_frame, text="Personal Questions", font=("Arial", 18)).pack(pady=20)
questions = [
"Why are you voting?",
"What are your expectations from the election?",
"Which issues are most important to you in this election?",
"What are your thoughts on the current political scenario?"
]
self.selected_question = random.choice(questions)
ttk.Label(question_frame, text=self.selected_question).pack(pady=10)
self.answer_entry = ttk.Entry(question_frame, width=50)
self.answer_entry.pack(pady=5)
self.submit = ttk.Button(question_frame, text="Submit", command=self.validate_answer, width=37)
self.submit.pack(pady=5)
def validate_answer(self):
answer = self.answer_entry.get()
if not answer.strip():
messagebox.showerror("Error", "Answer cannot be empty.")
return
sentiment = self.sia.polarity_scores(answer)
if sentiment["compound"] > 0.2: # Threshold for positive/neutral sentiment
messagebox.showinfo("Success", "Valid answer. Proceeding to main screen.")
for widget in self.winfo_children():
widget.destroy()
if voter_id_start=='ADMIN123':
self.main_screen_admin()
else:
self.main_screen()
else:
messagebox.showerror("Error", "Invalid answer. Please provide a more meaningful response.")
def main_screen_admin(self):
self.center_window(700, 600)
# Create frame for admin screen
admin_frame = tk.Frame(self)
admin_frame.pack(fill=tk.BOTH, expand=True)
# Title
ttk.Label(admin_frame, text='Vote Records', font=('Arial', 18)).pack(pady=20, anchor="center")
# Search input and button
search_frame = tk.Frame(admin_frame)
search_frame.pack(pady=(10, 30), anchor="center")
ttk.Label(search_frame, text="Search:").pack(side=tk.LEFT, padx=5)
search_input = ttk.Entry(search_frame, width=30)
search_input.pack(side=tk.LEFT, padx=5)
search_button = ttk.Button(search_frame, text="Search", command=lambda: search_records())
search_button.pack(side=tk.LEFT, padx=5)
# Treeview and Scrollbar
tree_frame = tk.Frame(admin_frame)
tree_frame.pack(pady=10, anchor="center")
columns = ('VoterID', 'State', 'Party')
tree = ttk.Treeview(tree_frame, columns=columns, show='headings', height=15)
tree.heading('VoterID', text='Voter ID')
tree.heading('State', text='State')
tree.heading('Party', text='Party')
tree.column('VoterID', width=150)
tree.column('State', width=200)
tree.column('Party', width=200)
scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
tree.pack(side=tk.LEFT)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Reset records button
reset_button = ttk.Button(admin_frame, text="Reset Records", command=lambda: load_records(), width=65)
reset_button.pack(pady=10, anchor="center")
def load_records():
"""Load all records from the Excel sheet into the Treeview."""
try:
df = pd.read_excel('votes.xlsx')
tree.delete(*tree.get_children()) # Clear the Treeview
for _, row in df.iterrows():
tree.insert("", "end", values=(row['VoterID'], row['State'], row['Party']))
except FileNotFoundError:
messagebox.showerror("Error", "votes.xlsx file not found.")
except Exception as e:
messagebox.showerror("Error", f"Failed to load data: {e}")
def search_records():
"""Search for a specific value in the Excel sheet and display the result."""
search_value = search_input.get().strip()
if not search_value:
messagebox.showerror("Error", "Search field cannot be empty.")
return
try:
df = pd.read_excel('votes.xlsx')
search_results = df[
df.apply(lambda row: search_value.lower() in row.astype(str).str.lower().values, axis=1)]
if search_results.empty:
messagebox.showerror("Error", f"No record found for '{search_value}'.")
else:
tree.delete(*tree.get_children()) # Clear the Treeview
for _, row in search_results.iterrows():
tree.insert("", "end", values=(row['VoterID'], row['State'], row['Party']))
except FileNotFoundError:
messagebox.showerror("Error", "votes.xlsx file not found.")
except Exception as e:
messagebox.showerror("Error", f"Failed to search records: {e}")
# Load initial records
load_records()
def main_screen(self):
for widget in self.winfo_children():
widget.destroy()
self.center_window(1000, 800)
# Frame for the menu bar
menu_bar_color = '#383838'
menu_bar_frame = tk.Frame(self, bg=menu_bar_color)
menu_bar_frame.pack(side=tk.LEFT, fill=tk.Y, pady=4, padx=3)
menu_bar_frame.configure(width=45)
# Frame for dynamic page content
page_frame = tk.Frame(self)
page_frame.place(relwidth=1.0, relheight=1.0, x=50)
# Load images for menu buttons
toggle_icon = ImageTk.PhotoImage(Image.open('images/toggle_btn_icon.png'))
home_icon = ImageTk.PhotoImage(Image.open('images/home_icon.png'))
service_icon = ImageTk.PhotoImage(Image.open('images/services_icon.png'))
close_icon = ImageTk.PhotoImage(Image.open('images/close_btn_icon.png'))
# Define the Home page
def home_page(parent):
service_frame = ttk.Frame(parent)
service_frame.pack(fill=tk.BOTH, expand=True)
# Create an inner frame for centering contents
inner_frame = ttk.Frame(service_frame, padding=20)
inner_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Center the frame in the parent
# Title Label
lb = ttk.Label(inner_frame, text="Analyse", font=('Arial', 18, 'bold'))
lb.pack(pady=(10, 30))
# Chatbot response display box (non-editable) with starter text
response_box = tk.Text(inner_frame, height=20, width=80, state="normal", wrap="word", bd=0)
response_box.insert(
tk.END,
"Welcome to Vote-Bot. Here before voting, you can analyse current events and even get glimpses of the future if one particular party wins or analyze a character of a particular leader. "
"This chatbot helps in making the right decisions to vote and create a greater impact in society."
)
response_box.config(state="disabled") # Disable editing
response_box.pack(pady=10)
# Label above the input field
input_label = ttk.Label(inner_frame, text="I want to vote for:", font=('Arial', 12))
input_label.pack(pady=(10, 5))
# User input field
user_input = ttk.Entry(inner_frame, width=100)
user_input.pack(pady=10)
# Generate response function
def generate_response():
party_name = user_input.get().strip()
if party_name:
try:
# Generate the response using the model or API
response = model.generate_content(
f"Provide a short list of ministers in {party_name} in 100 words, "
f"a short paragraph about what the party has done in the past in 100 words, "
f"a short analysis of the party's character in 100 words, "
f"a short passage about the party's future plans in 100 words, "
f"and an 80-word prediction of how the country would look in 2 years if {party_name} won."
)
# Format and display the response
response_box.config(state="normal") # Enable editing
response_box.delete(1.0, tk.END) # Clear any existing text
response_box.insert(tk.END,
f"Response for {party_name}:\n\n{response.text}") # Insert generated text
response_box.config(state="disabled") # Disable editing again
except Exception as e:
print(f"Error in generating response: {e}")
response_box.config(state="normal")
response_box.delete(1.0, tk.END)
response_box.insert(tk.END, "Error generating response.")
response_box.config(state="disabled")
# Submit button
submit_btn = ttk.Button(inner_frame, text="Submit", command=generate_response, width=75)
submit_btn.pack(pady=10)
# Define the Analyze page
# Define the Analyze page
def service_page(parent):
home_page_fm = tk.Frame(parent)
home_page_fm.pack(fill=tk.BOTH, expand=True)
lb = tk.Label(home_page_fm, text='Vote here', font=('Arial', 18, 'bold'))
lb.pack(pady=20)
# Treeview with parties
columns = ('Party Name', 'Region')
tree = ttk.Treeview(home_page_fm, columns=columns, show='headings')
tree.heading('Party Name', text='Party Name')
tree.heading('Region', text='Region')
tree.column('Party Name', width=210)
tree.column('Region', width=250)
# Add 28 parties in India with their regions
parties = [
("BJP", "Pan India"), ("INC", "Pan India"), ("AAP", "Delhi, Punjab"),
("TMC", "West Bengal"), ("SP", "Uttar Pradesh"), ("BSP", "Uttar Pradesh"),
("DMK", "Tamil Nadu"), ("AIADMK", "Tamil Nadu"), ("YSRCP", "Andhra Pradesh"),
("TRS", "Telangana"), ("JDU", "Bihar"), ("RJD", "Bihar"),
("NCP", "Maharashtra"), ("Shiv Sena", "Maharashtra"), ("SAD", "Punjab"),
("JD(S)", "Karnataka"), ("TDP", "Andhra Pradesh"), ("BJD", "Odisha"),
("MNS", "Maharashtra"), ("CPI", "Pan India"), ("CPIM", "Pan India"),
("RSP", "Kerala"), ("MIM", "Telangana, Uttar Pradesh"), ("LJP", "Bihar"),
("INLD", "Haryana"), ("AGP", "Assam"), ("JKNC", "Jammu & Kashmir"),
("NPP", "Meghalaya"), ("LDF", "Kerala")
]
for party in parties:
tree.insert("", "end", values=party)
# Adjust the width of the table to match the input and button widths
tree.pack(pady=10, expand=True)
scrollbar = ttk.Scrollbar(home_page_fm, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
# Input fields and submit button
ttk.Label(home_page_fm, text="Enter your state:").pack(pady=10)
state_input = ttk.Entry(home_page_fm, width=75)
state_input.pack(pady=5)
ttk.Label(home_page_fm, text="Select Party:").pack(pady=10)
party_input = ttk.Entry(home_page_fm, width=75)
party_input.pack(pady=5)
ttk.Button(home_page_fm, text="Submit", command=lambda: submit_vote(state_input, party_input),
width=56).pack(pady=40)
def submit_vote(state_input, party_input):
# Use the first voter ID for now
state = state_input.get()
party = party_input.get()
# Check if the voter has already voted
try:
df = pd.read_excel('votes.xlsx')
if voter_id_start in df['VoterID'].values:
messagebox.showerror("Error", "You have already voted.")
return
except:
df = pd.DataFrame(columns=['VoterID', 'State', 'Party'])
# Add the vote
new_vote = {'VoterID': voter_id_start, 'State': state, 'Party': party}
df = pd.concat([df, pd.DataFrame([new_vote])], ignore_index=True)
df.to_excel('votes.xlsx', index=False)
# Generate PDF with voting details
generate_pdf(voter_id_start, party, state)
messagebox.showinfo("Success", "Your vote has been cast successfully!")
def generate_pdf(voter_id, party, state):
# Path to the captured image
webcam_image_path = "deepface/capture_img.jpg"
# Define the PDF file name and path
pdf_output_path = f"vote_details_{voter_id}.pdf"
# Create a canvas object
c = canvas.Canvas(pdf_output_path, pagesize=letter)
# Add voter details text to the PDF
c.setFont("Helvetica-Bold", 14)
c.drawString(30, 750, f"Voter ID: {voter_id}")
c.drawString(30, 730, f"Voted Party: {party}")
c.drawString(30, 710, f"State: {state}")
# Add the image to the PDF (make sure the image exists)
try:
if os.path.exists(webcam_image_path):
c.drawImage(webcam_image_path, 30, 500, width=100, height=100) # Adjust image size and position
except Exception as e:
print(f"Error adding image to PDF: {e}")
# Save the PDF file
c.save()
# Optionally, share the file (if needed)
# file_sharer = FileSharer()
# file_sharer.send_file(pdf_output_path)
# Clean up after saving the PDF (remove image file if needed)
# os.remove(webcam_image_path)
# Sidebar toggle functionality
def toggle_menu():
if menu_bar_frame.winfo_width() > 45:
# Collapse the menu
for widget in menu_bar_frame.winfo_children():
if isinstance(widget, tk.Button):
widget.place_forget()
menu_bar_frame.configure(width=45)
else:
# Expand the menu and recreate buttons
menu_bar_frame.configure(width=200)
setup_menu() # Recreate the buttons
# Page switch functionality
def switch_to_home():
for widget in page_frame.winfo_children():
widget.destroy()
home_page(page_frame)
def switch_to_service():
for widget in page_frame.winfo_children():
widget.destroy()
service_page(page_frame)
# Sidebar buttons
def setup_menu():
toggle_menu_btn = tk.Button(menu_bar_frame, image=toggle_icon, bg=menu_bar_color, bd=0,
activebackground=menu_bar_color)
toggle_menu_btn.image = toggle_icon
toggle_menu_btn.place(x=4, y=10)
home_btn = tk.Button(menu_bar_frame, image=home_icon, bg=menu_bar_color, bd=0,
activebackground=menu_bar_color, command=switch_to_home)
home_btn.image = home_icon
home_btn.place(x=9, y=130, width=30, height=40)
home_page_lb = tk.Label(menu_bar_frame, text='Vote', bg=menu_bar_color, fg='white',
font=('bold', 15), anchor=tk.W)
home_page_lb.place(x=45, y=130, width=130, height=40)
home_page_lb.bind('<Button-1>', lambda e: switch_to_home())
service_btn = tk.Button(menu_bar_frame, image=service_icon, bg=menu_bar_color, bd=0,
activebackground=menu_bar_color, command=switch_to_service)
service_btn.image = service_icon
service_btn.place(x=9, y=190, width=30, height=40)
service_page_lb = tk.Label(menu_bar_frame, text='Analyze', bg=menu_bar_color, fg='white',
font=('bold', 15), anchor=tk.W)
service_page_lb.place(x=45, y=190, width=130, height=40)
service_page_lb.bind('<Button-1>', lambda e: switch_to_service())
setup_menu()
switch_to_home() # Default to Home page
if __name__ == "__main__":
app = VoteVistaApp()
app.mainloop()