Vote-Vista - a Clear Vision for Secure Voting and Global Insights

by ElectraFlame in Circuits > Software

60 Views, 1 Favorites, 0 Comments

Vote-Vista - a Clear Vision for Secure Voting and Global Insights

vote-vista-30_m0VrADmS

This is a project developed by Binary Flame.

not heard of yet? cuz its yet to thrive enterprise...... only after the CEO is old enough....


Problem Statement

Traditional voting systems face several critical challenges, including vulnerability to fraud, voter impersonation, and the inability of individuals residing abroad or unavailable at polling stations to cast their votes. Additionally, long queues at polling booths often discourage voter participation, consuming significant time and effort. Moreover, many voters lack confidence in making informed decisions due to insufficient access to reliable information about candidates and parties.


Innovative Solution

Our project addresses these challenges by developing a secure and user-friendly voting software. This software integrates multi-layered verification processes and advanced technologies to ensure transparency, security, and accessibility. It provides voters with a seamless voting experience and incorporates features to make informed decisions about political parties and candidates. A PDF receipt is generated as a software copy of the vote, including details like voter ID, state, party, and the image of the voter, which can also be printed. Additionally, the system uses a cloud storage platform for secure and scalable data management.


Key Features

Multi-Layered Verification:

  1. Voter ID Validation: Ensures the voter’s identity is legitimate.
  2. Aadhaar and OTP Verification: Confirms voter’s credentials through Aadhaar-based OTP authentication.
  3. Face Recognition: Uses AI models for precise identity verification.
  4. Personal Security Questions: Adds an extra layer of security unique to each voter.
  5. =Sentiment Analysis: Detects suspicious or fraudulent voting behavior.


Main Interface with Two Tabs:

  1. Analyze Party Tab:
  2. Helps voters analyze a party by taking input of the party name.
  3. Provides a detailed synopsis including:
  4. Party members.
  5. Party past actions.
  6. Party future plans.
  7. Representative analysis.
  8. Future insights on what the next two years might look like if the party wins.


  1. Vote Tab: Allows voters to securely cast their vote, generating a PDF receipt and securely storing the data on a cloud platform.


Admin Panel:

  1. Displays total votes counted and includes a search functionality to monitor voting activity in detail.


Beneficiaries

  1. Voters: Ensures a secure, time-saving, and accessible voting experience, especially for individuals abroad or unable to visit polling stations.
  2. Election Commissions: Enhances transparency and minimizes fraud, ensuring public trust in the voting process.
  3. Governments: Streamlines the electoral process, reducing costs and improving efficiency.


Feasibility

The project leverages widely available tools and technologies to ensure cost-effective and efficient implementation. Its modular design allows scalability and easy integration with existing systems. Adding biometric fingerprint recognition and more robust cloud-based features in the future will enhance its functionality further.


Tools, Frameworks, and Platforms

  1. Gemini Flash 1.5 API: Provides real-time party analysis based on API requests.
  2. OpenCV and DeepFace: Powers the face recognition system using pre-trained AI models.
  3. Vader NLTK: Used for sentiment analysis to detect voter intent and identify fraudulent activity.
  4. Platforms: Cloud-based storage for secure and scalable data management.


Conclusion

This innovative voting software transforms traditional voting into a secure, efficient, and transparent process. By addressing key challenges and enhancing voter experience, it paves the way for a more reliable and accessible electoral system.

Supplies

The supplies are simple libraries that needs to be installed. The import commands are provided below


  1. NLTK [ model "Vader" is advised to use since its efficient to analyze sentiment ]
  2. Tkinter [ custom Tkinter can also be used ]
  3. Pandas
  4. SV_TTK - sun valley theme of Tkinter for better GUI
  5. random
  6. cv2 - Computer vision
  7. OS -to get administrator permission
  8. DeepFace - face recognition
  9. Pillow
  10. nltk.sentiment - import SentimentIntensityAnalyzer
  11. report lab - pdf generation
  12. google generative ai - API access


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


*nltk.download('vader_lexicon')

Planning the Structure of Working Application

Electronic-Voting-Blog---Image----1-.png

The app first needs to start with a user login [ VOTER / ADMINISTRATOR login ]

I am using predefined voter id and login for temporary use however this can be modified by using databases or excel sheets to store and retrieve data.


The app then proceeds to AADHAR number and OTP verification

Since this app is made with respect to Indian voting system, Aadhar number is a certain government validated id used to verify a resident of India. temporarily the OTP is predefined in code since in order to generate OTP to the connected mobile number, premium package is required.


The app then moves on to face verification page

Face verification is done using the above mentioned library deepface. however in order for the deepface to validate a face, a reference image is required, so there are certain predefined images in the location of the folder that deepface compares the captured image with the predefined reference image in accordance to VOTERID entered at the start of the program.


The app then moves onto the personal questions page

This personal questions page is the fourth layer of verification where certain question are asked to which only the particular voter knows the answer.


The app then proceeds to the sentiment analysis page

In this page the sentiment analysis of the person is done based on the sentiment threshold mentioned and validated.


The app then finally enters the main screen

The main screen consists of two tabs:

  1. Analyze party tab: It presents us with the analysis of the party we want to vote for
  2. Voting tab - It Stores the vote in a excel sheet and generates a pdf receipt for the same

Downloading Models, Declaring Global Variables and Building Api

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")



NLTK vader model is downloaded and initialized

Here global variable is initialized to record as who the voter is entering as

API definition and connection is done with Gemini

Creating Voter Data

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'.")



here voter data is written and formatted and saved to excel sheet

Loading Voter Data

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 []


Loading voter data from excel sheet

Making the App and Defining the Class

hero_dark.png
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()


Here the app is initialized and a class is defined to contain all the app codes

Centering the Window

images.png
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}')


here the window created and aligned to center

Creating Login Page

Screenshot 2025-01-16 185717.png
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))


Here the login page is created and functions are defined

Checking Voter ID

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")


Voter id is validated i.e. verified form excel sheet and then stored to the global variable

AADHAR and OTP Generation

Screenshot 2025-01-16 185717.png
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")


here OTP is predefined in the code since using a premium package was not possible. GUI is also made for OTP generation page.

Making the Face Scan GUI

Screenshot 2025-01-16 190122.png
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)


In this function GUI of the face scan page is made and then a function is called to scan and verify face

Using Webcam and Verifying Image

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()


In this function, webcam is utilized to capture image and then process and compare with specific reference image with corresponding voter id.

Showing the Verified Image

Screenshot 2025-01-16 191129.png
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)


here both the GUI and function of showing the image is defined in this function. This enables the user to confirm if his image is captured or not.

Designing the Personal Questions Page and Validating Answers

Screenshot 2025-01-16 191220.png
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)


There are certain questions and answers pre defined in code for temporary use. the personal questions are validated based on the defined code.

Validating Personal Questions

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.")


Here the personal questions are validated from the defined code above.

Sentiment Analysis Page

Screenshot 2025-01-16 191320.png
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)


here sentiment is analyzed based on defined threshold. The GUI for the same is also defined in the code.

Validating Sentiment

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.")


In this function, the answer is validated based on the VADER model and the defined threshold.

Making the ADMIN Main Screen

Screenshot 2025-01-16 191953.png
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()


Here the GUI is defined, tree view displays the vote data stored and searching records per category feature is also provided to admin

Making the Main Screen for the Voter

Screenshot 2025-01-16 191445.png
Screenshot 2025-01-16 191554.png
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


This code consists of the code for analyze party, where input is received by the API and requests to API are made in format that is required. This way the user is able to analyze the political party efficiently.


This code also consists of the main voting screen accessed via side navigation bar. the main voting is casted in this screen, if the vote has been cast from the particular voter id, the app prompts an error, if not the vote is cast and the receipt is generated based on data input.

Running the App

if __name__ == "__main__":
app = VoteVistaApp()
app.mainloop()


this code runs the whole app along with all its functions.

Whole Code

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()



drive link to view demonstration video and code:

https://drive.google.com/drive/folders/1swvulr_rl2gU1s13po-W7R6cGzSY4f2u