-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
870dadb
commit 16aa183
Showing
11 changed files
with
425 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import requests | ||
|
||
class AIResponse: | ||
def __init__(self, api_key): | ||
self.api_key = api_key | ||
|
||
def get_ai_answer(self, question): | ||
url = 'https://api.aimlapi.com/v1/chat/completions' | ||
headers = { | ||
'Authorization': f'Bearer {self.api_key}', | ||
'Content-Type': 'application/json' | ||
} | ||
payload = { | ||
'text': question | ||
} | ||
|
||
try: | ||
response = requests.post(url, headers=headers, json=payload) | ||
response.raise_for_status() # will raise an error for 4xx/5xx responses | ||
result = response.json() | ||
return result.get('answer', 'AI could not provide an answer.') | ||
except requests.exceptions.HTTPError as http_err: | ||
print(f"HTTP error occurred: {http_err}") | ||
return 'AI API error: Unable to get a response.' | ||
except Exception as err: | ||
print(f"Other error occurred: {err}") | ||
return 'AI API error: Unable to get a response.' | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# [email protected] | ||
# Poing1981@ | ||
# https://meet.google.com/ikb-byyj-bui |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# auth.py | ||
import time | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.webdriver.support import expected_conditions as EC | ||
|
||
class Authenticator: | ||
def __init__(self, driver, email, password): | ||
self.driver = driver | ||
self.email = email | ||
self.password = password | ||
|
||
def login(self): | ||
try: | ||
self.driver.get('https://accounts.google.com/ServiceLogin') | ||
self.driver.find_element(By.ID, "identifierId").send_keys(self.email) | ||
self.driver.find_element(By.ID, "identifierNext").click() | ||
|
||
password_field = WebDriverWait(self.driver, 10).until( | ||
EC.element_to_be_clickable((By.XPATH, '//*[@id="password"]/div[1]/div/div[1]/input'))) | ||
password_field.send_keys(self.password) | ||
|
||
WebDriverWait(self.driver, 10).until(EC.url_contains("google.com")) | ||
print("Login successful!") | ||
except Exception as e: | ||
print(f"Error during login: {e}") | ||
self.driver.quit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# controls.py | ||
import time | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.webdriver.support import expected_conditions as EC | ||
from selenium.common.exceptions import TimeoutException | ||
|
||
class MeetControls: | ||
def __init__(self, driver): | ||
self.driver = driver | ||
|
||
def turn_off_mic_cam(self): | ||
try: | ||
time.sleep(5) | ||
mic_button = WebDriverWait(self.driver, 10).until( | ||
EC.element_to_be_clickable((By.XPATH, '//*[contains(concat(" ", @class, " "), concat(" ", "crqnQb", " "))]'))) | ||
mic_button.click() | ||
print("Microphone turned off.") | ||
except TimeoutException: | ||
print("TimeoutException: Element not found or not clickable within specified time.") | ||
except Exception as e: | ||
print(f"An error occurred while turning off mic/cam: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# driver_setup.py | ||
from selenium import webdriver | ||
from selenium.webdriver.chrome.service import Service | ||
from selenium.webdriver.chrome.options import Options | ||
|
||
def setup_driver(): | ||
options = Options() | ||
options.add_argument('--disable-blink-features=AutomationControlled') | ||
options.add_argument('--start-maximized') | ||
options.add_experimental_option("prefs", { | ||
"profile.default_content_setting_values.media_stream_mic": 1, | ||
"profile.default_content_setting_values.media_stream_camera": 1, | ||
"profile.default_content_setting_values.geolocation": 0, | ||
"profile.default_content_setting_values.notifications": 1 | ||
}) | ||
|
||
# You can also specify the path to your ChromeDriver if needed | ||
# service = Service('/path/to/chromedriver') | ||
# return webdriver.Chrome(service=service, options=options) | ||
|
||
return webdriver.Chrome(options=options) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# google_meet_bot.py | ||
import time | ||
import threading | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.webdriver.support import expected_conditions as EC | ||
from selenium.common.exceptions import TimeoutException | ||
from driver_setup import setup_driver | ||
from translator import TextTranslator | ||
from question_checker import QuestionChecker | ||
from AI import AIResponse | ||
from auth import Authenticator # Import the Authenticator class | ||
from controls import MeetControls # Import the MeetControls class | ||
from subtitle_saver import SubtitleSaver # Import the SubtitleSaver class | ||
|
||
class GoogleMeetBot: | ||
def __init__(self, email, password, api_key, ai_api_key, update_signal): | ||
self.email = email | ||
self.password = password | ||
self.api_key = api_key | ||
self.ai_response = AIResponse(ai_api_key) | ||
self.driver = setup_driver() | ||
self.translator = TextTranslator() | ||
self.question_checker = QuestionChecker(api_key) | ||
self.authenticator = Authenticator(self.driver, self.email, self.password) | ||
self.controls = MeetControls(self.driver) # Initialize MeetControls | ||
self.subtitle_saver = SubtitleSaver(self.driver, self.translator, self.question_checker, update_signal) | ||
|
||
def login(self): | ||
self.authenticator.login() # Use the Authenticator class for login | ||
|
||
def turn_off_mic_cam(self): | ||
self.controls.turn_off_mic_cam() # Use the MeetControls class for turning off mic/cam | ||
|
||
def start(self, meeting_link): | ||
self.login() | ||
self.driver.get(meeting_link) | ||
self.turn_off_mic_cam() | ||
|
||
subtitle_thread = threading.Thread(target=self.subtitle_saver.save_subtitles, daemon=True) # Use SubtitleSaver | ||
subtitle_thread.start() | ||
|
||
try: | ||
while True: | ||
time.sleep(1) | ||
except KeyboardInterrupt: | ||
print("Program terminated by user.") | ||
finally: | ||
self.driver.quit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import sys | ||
import time | ||
from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, | ||
QLineEdit, QPushButton, QTextEdit, QFileDialog) | ||
from PyQt6.QtCore import QThread, pyqtSignal | ||
import driver_setup | ||
from google_meet_bot import GoogleMeetBot | ||
from subtitle_saver import SubtitleSaver | ||
|
||
class MeetingThread(QThread): | ||
update_output = pyqtSignal(str) | ||
|
||
def __init__(self, email, password, meeting_link, api_key, ai_api_key, translator, question_checker): | ||
super().__init__() | ||
self.email = email | ||
self.password = password | ||
self.meeting_link = meeting_link | ||
self.api_key = api_key | ||
self.ai_api_key = ai_api_key | ||
self.driver = driver_setup | ||
self.translator = translator | ||
self.question_checker = question_checker | ||
|
||
def run(self): | ||
self.update_output.emit("Starting the meeting...") | ||
self.bot = GoogleMeetBot(self.email, self.password, self.api_key, self.ai_api_key, self.update_output) | ||
self.bot.start(self.meeting_link) | ||
|
||
# Sending update_output as update_signal | ||
subtitle_saver = SubtitleSaver(self.driver, self.translator, self.question_checker, self.update_output) | ||
subtitle_saver.save_subtitles() # This method runs concurrently | ||
|
||
class MainWindow(QWidget): | ||
def __init__(self): | ||
super().__init__() | ||
self.setWindowTitle("Google Meet Bot") | ||
self.setGeometry(400, 400, 800, 800) | ||
|
||
# Assume you initialize translator and question_checker here | ||
self.translator = None # Replace with actual translator | ||
self.question_checker = None # Replace with actual question_checker | ||
|
||
layout = QVBoxLayout() | ||
|
||
self.email_input = QLineEdit(self) | ||
self.email_input.setPlaceholderText("Enter your email") | ||
self.email_input.setFixedHeight(40) # Increased height | ||
layout.addWidget(self.email_input) | ||
|
||
self.password_input = QLineEdit(self) | ||
self.password_input.setPlaceholderText("Enter your password") | ||
self.password_input.setEchoMode(QLineEdit.EchoMode.Password) | ||
self.password_input.setFixedHeight(40) # Increased height | ||
layout.addWidget(self.password_input) | ||
|
||
self.meeting_link_input = QLineEdit(self) | ||
self.meeting_link_input.setPlaceholderText("Enter meeting link") | ||
self.meeting_link_input.setFixedHeight(40) # Increased height | ||
layout.addWidget(self.meeting_link_input) | ||
|
||
self.start_button = QPushButton("Start Meeting", self) | ||
self.start_button.setStyleSheet("background-color: blue; font-size: 16px;") # Change button color | ||
self.start_button.setFixedHeight(40) # In | ||
self.start_button.clicked.connect(self.start_meeting) | ||
layout.addWidget(self.start_button) | ||
|
||
self.output_area = QTextEdit(self) | ||
self.output_area.setReadOnly(True) | ||
self.output_area.setFixedHeight(400) # Set a fixed height for output area | ||
layout.addWidget(self.output_area) | ||
|
||
self.download_button = QPushButton("Download Text File", self) | ||
self.download_button.setStyleSheet("background-color: green; font-size: 16px;") # Change button color | ||
self.download_button.setFixedHeight(40) # In | ||
self.download_button.clicked.connect(self.download_file) | ||
layout.addWidget(self.download_button) | ||
|
||
self.setLayout(layout) | ||
|
||
def start_meeting(self): | ||
email = self.email_input.text() | ||
password = self.password_input.text() | ||
meeting_link = self.meeting_link_input.text() | ||
|
||
if email and password and meeting_link: | ||
self.meeting_thread = MeetingThread(email, password, meeting_link, 'YOUR_API_KEY', 'YOUR_AI_API_KEY', self.translator, self.question_checker) | ||
self.meeting_thread.update_output.connect(self.append_output) | ||
self.meeting_thread.start() | ||
else: | ||
self.output_area.append("Please fill in all fields.") | ||
|
||
def append_output(self, message): | ||
self.output_area.append(message) | ||
|
||
def download_file(self): | ||
file_name, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Text Files (*.txt);;All Files (*)") | ||
if file_name: | ||
with open(file_name, 'w', encoding='utf-8') as file: | ||
file.write(self.output_area.toPlainText()) | ||
self.output_area.append(f"File saved at {file_name}.") | ||
|
||
if __name__ == "__main__": | ||
app = QApplication(sys.argv) | ||
window = MainWindow() | ||
window.show() | ||
sys.exit(app.exec()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# question_checker.py | ||
import requests | ||
|
||
class QuestionChecker: | ||
def __init__(self, api_key): | ||
self.api_key = api_key | ||
|
||
def is_question(self, text): | ||
wh_question_detected = self.contains_wh_question(text) | ||
if wh_question_detected: | ||
return True | ||
|
||
url = 'https://api.aimlapi.com/v1/chat/completions' # Replace with your API endpoint | ||
headers = { | ||
'Authorization': f'Bearer {self.api_key}', | ||
'Content-Type': 'application/json' | ||
} | ||
payload = { | ||
'text': text | ||
} | ||
response = requests.post(url, headers=headers, json=payload) | ||
if response.status_code == 200: | ||
result = response.json() | ||
return result.get('is_question', False) | ||
else: | ||
print(f"API error: {response.status_code}, Message: {response.text}") | ||
return False | ||
|
||
def contains_wh_question(self, text): | ||
wh_words = ['who', 'what', 'where', 'when', 'why', 'which'] | ||
text_lower = text.lower() | ||
return any(wh in text_lower for wh in wh_words) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# subtitle_saver.py | ||
import time | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.webdriver.support import expected_conditions as EC | ||
from selenium.common.exceptions import TimeoutException | ||
|
||
class SubtitleSaver: | ||
def __init__(self, driver, translator, question_checker, update_signal): | ||
self.driver = driver | ||
self.translator = translator | ||
self.question_checker = question_checker | ||
self.previous_subtitles = set() | ||
self.update_signal = update_signal | ||
|
||
def save_subtitles(self): | ||
with open('subtitles.txt', 'a', encoding='utf-8') as f: | ||
while True: | ||
try: | ||
subtitles = WebDriverWait(self.driver, 10).until( | ||
EC.presence_of_element_located((By.XPATH, '//*[contains(concat(" ", @class, " "), concat(" ", "iOzk7", " "))]'))) | ||
subtitle_text = subtitles.text.strip() | ||
|
||
if subtitle_text and subtitle_text not in self.previous_subtitles: | ||
f.write("English: " + subtitle_text + '\n' + "*" * 20 + '\n') | ||
|
||
if self.question_checker.is_question(subtitle_text): | ||
f.write("Type: Question" + '\n' + "*" * 20 + '\n') | ||
else: | ||
f.write("Type: Statement" + '\n' + "*" * 20 + '\n') | ||
|
||
translated_text = self.translator.translate(subtitle_text, dest='fa') | ||
f.write("Persian: " + translated_text + '\n' + "*" * 20 + '\n') | ||
|
||
f.flush() | ||
self.update_signal.emit(f"English: {subtitle_text}\nType: {'Question' if self.question_checker.is_question(subtitle_text) else 'Statement'}\nPersian: {translated_text}") | ||
|
||
self.previous_subtitles.add(subtitle_text) | ||
time.sleep(1) | ||
except TimeoutException: | ||
print("TimeoutException: Element not found.") | ||
except Exception as e: | ||
print(f"Error: {e}") | ||
break |
Oops, something went wrong.