From cdedbbbda69a9544970038d6c31d4aaff1a71fe5 Mon Sep 17 00:00:00 2001 From: mdrmz <95125171+mdrmz@users.noreply.github.com> Date: Fri, 2 May 2025 16:53:11 +0300 Subject: [PATCH] cursor update v2 --- gemini_chat.py | 114 ++++++ gui_gemini_multiprocess.py | 509 ++++++++++++------------ gui_lm_studio.py | 460 +++++++++++++++++++++ lm_studio_chat.py | 130 ++++++ modern_vision_assistant.py | 573 +++++++++++++++++++++++++++ obj_file/gemini_api_key.txt | 1 + object_info.json | 771 ++++++++++++++++++++++-------------- ses.mp3 | Bin 8832 -> 0 bytes thesis_paper.txt | 280 +++++++++++++ 9 files changed, 2295 insertions(+), 543 deletions(-) create mode 100644 gemini_chat.py create mode 100644 gui_lm_studio.py create mode 100644 lm_studio_chat.py create mode 100644 modern_vision_assistant.py create mode 100644 obj_file/gemini_api_key.txt delete mode 100644 ses.mp3 create mode 100644 thesis_paper.txt diff --git a/gemini_chat.py b/gemini_chat.py new file mode 100644 index 0000000..22d732a --- /dev/null +++ b/gemini_chat.py @@ -0,0 +1,114 @@ +import google.generativeai as genai +import os +import sys +from colorama import init, Fore, Style + +# Colorama'yı başlat +init() + +def clear_screen(): + """Ekranı temizle""" + os.system('cls' if os.name == 'nt' else 'clear') + +def print_colored(text, color=Fore.WHITE, style=Style.NORMAL): + """Renkli metin yazdır""" + print(f"{style}{color}{text}{Style.RESET_ALL}") + +def load_api_key(): + """API anahtarını dosyadan yükle""" + try: + with open("gemini_api_key.txt", "r") as f: + return f.read().strip() + except FileNotFoundError: + return None + +def save_api_key(api_key): + """API anahtarını dosyaya kaydet""" + with open("gemini_api_key.txt", "w") as f: + f.write(api_key) + +def setup_gemini(): + """Gemini API'yi yapılandır""" + api_key = load_api_key() + + if not api_key: + print_colored("Gemini API anahtarı bulunamadı.", Fore.YELLOW) + api_key = input("Lütfen Gemini API anahtarınızı girin: ").strip() + + if api_key: + try: + # API anahtarını test et + genai.configure(api_key=api_key) + model = genai.GenerativeModel('gemini-pro') + response = model.generate_content("Test connection") + + # API anahtarını kaydet + save_api_key(api_key) + print_colored("API anahtarı başarıyla kaydedildi!", Fore.GREEN) + return model + except Exception as e: + print_colored(f"API anahtarı geçersiz: {str(e)}", Fore.RED) + return None + else: + print_colored("API anahtarı girilmedi.", Fore.RED) + return None + else: + try: + genai.configure(api_key=api_key) + return genai.GenerativeModel('v1beta') + except Exception as e: + print_colored(f"API yapılandırma hatası: {str(e)}", Fore.RED) + return None + +def chat_loop(model): + """Ana sohbet döngüsü""" + chat = model.start_chat(history=[]) + + print_colored("\nGemini Chat'e hoş geldiniz!", Fore.CYAN, Style.BRIGHT) + print_colored("Çıkmak için 'quit' veya 'exit' yazın.\n", Fore.YELLOW) + + while True: + try: + # Kullanıcı girdisi + user_input = input(f"{Fore.GREEN}Sen: {Style.RESET_ALL}") + + # Çıkış kontrolü + if user_input.lower() in ['quit', 'exit']: + print_colored("\nGörüşmek üzere!", Fore.CYAN) + break + + # Boş girdi kontrolü + if not user_input.strip(): + continue + + # Gemini'den yanıt al + response = chat.send_message(user_input) + + # Yanıtı göster + print(f"\n{Fore.BLUE}Gemini: {Style.RESET_ALL}{response.text}\n") + + except KeyboardInterrupt: + print_colored("\n\nGörüşmek üzere!", Fore.CYAN) + break + except Exception as e: + print_colored(f"\nBir hata oluştu: {str(e)}", Fore.RED) + print_colored("Yeni bir sohbet başlatılıyor...\n", Fore.YELLOW) + chat = model.start_chat(history=[]) + +def main(): + """Ana program""" + clear_screen() + + # Gemini modelini yapılandır + model = setup_gemini() + + if model: + try: + chat_loop(model) + except Exception as e: + print_colored(f"\nBeklenmeyen bir hata oluştu: {str(e)}", Fore.RED) + else: + print_colored("\nProgram başlatılamadı. Lütfen geçerli bir API anahtarı girin.", Fore.RED) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/gui_gemini_multiprocess.py b/gui_gemini_multiprocess.py index 6cb9a00..18d50b8 100644 --- a/gui_gemini_multiprocess.py +++ b/gui_gemini_multiprocess.py @@ -1,18 +1,19 @@ import sys import cv2 import numpy as np -from PySide6.QtCore import QTimer, Qt, QSize, QThread, Signal, QProcess -from PySide6.QtGui import QImage, QPixmap, QFont +from PySide6.QtCore import QTimer, Qt, QSize, QThread, Signal, QObject +from PySide6.QtGui import QImage, QPixmap, QFont, QPalette, QColor, QIcon from PySide6.QtWidgets import (QApplication, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QFrame, QSizePolicy, QGroupBox, - QLineEdit, QPushButton, QTextEdit, QMessageBox) -import multiprocessing as mp + QLineEdit, QPushButton, QTextEdit, qQMessageBox, + QMainWindow) import time import json import os import google.generativeai as genai from ultralytics import YOLO -from Sound_Project.Sound import ses, diger +from Sound_Project.Sound import ses +import qdarkstyle # --- Configuration --- MODEL_PATH = "yolov8n.pt" @@ -23,42 +24,9 @@ CONFIDENCE_THRESHOLD = 0.6 SOUND_COOLDOWN = 2.0 -class GeminiAPIThread(QThread): - response_ready = Signal(str) - - def __init__(self, api_key, object_info): - super().__init__() - self.api_key = api_key - self.object_info = object_info - self.running = True - - def run(self): - try: - # Configure Gemini API - genai.configure(api_key=self.api_key) - model = genai.GenerativeModel('gemini-pro') - - # Create prompt - prompt = f""" - Describe this object in detail: - Class: {self.object_info['class_name']} - Confidence: {self.object_info['confidence']} - Location: {self.object_info['bounding_box']} - """ - - # Generate response - response = model.generate_content(prompt) - self.response_ready.emit(response.text) - - except Exception as e: - self.response_ready.emit(f"Error: {str(e)}") - - def stop(self): - self.running = False - self.wait() - class DetectionThread(QThread): frame_ready = Signal(np.ndarray, list) + error_occurred = Signal(str) def __init__(self, model_path, camera_index, conf_threshold): super().__init__() @@ -66,25 +34,33 @@ def __init__(self, model_path, camera_index, conf_threshold): self.camera_index = camera_index self.conf_threshold = conf_threshold self.running = True + self.model = None + self.cap = None def run(self): try: - model = YOLO(self.model_path) - cap = cv2.VideoCapture(self.camera_index) + # Initialize YOLO model + self.model = YOLO(self.model_path) + + # Initialize camera + self.cap = cv2.VideoCapture(self.camera_index) + if not self.cap.isOpened(): + raise Exception("Failed to open camera") while self.running: - ret, frame = cap.read() + ret, frame = self.cap.read() if not ret: continue # Run detection - results = model(frame, conf=self.conf_threshold)[0] + results = self.model(frame, conf=self.conf_threshold)[0] detections = [] + # Process detections for box in results.boxes: cls = int(box.cls) conf = float(box.conf[0]) - label = model.names[cls] + label = self.model.names[cls] coords = box.xyxy[0].cpu().numpy().astype(int) x1, y1, x2, y2 = coords @@ -102,12 +78,13 @@ def run(self): }) self.frame_ready.emit(frame, detections) + time.sleep(0.01) # Prevent CPU overload except Exception as e: - print(f"Error in detection thread: {e}") + self.error_occurred.emit(str(e)) finally: - if 'cap' in locals(): - cap.release() + if self.cap is not None: + self.cap.release() def stop(self): self.running = False @@ -115,11 +92,13 @@ def stop(self): class VideoThread(QThread): frame_ready = Signal(np.ndarray) + error_occurred = Signal(str) def __init__(self): super().__init__() self.video_path = None self.running = True + self.cap = None def set_video(self, path): self.video_path = path @@ -128,21 +107,30 @@ def run(self): while self.running: if self.video_path: try: - cap = cv2.VideoCapture(self.video_path) + self.cap = cv2.VideoCapture(self.video_path) + if not self.cap.isOpened(): + raise Exception(f"Failed to open video: {self.video_path}") + while self.running and self.video_path: - ret, frame = cap.read() + ret, frame = self.cap.read() if not ret: - cap.set(cv2.CAP_PROP_POS_FRAMES, 0) + self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0) continue self.frame_ready.emit(frame) - cap.release() + time.sleep(0.01) # Control video playback speed + + if self.cap is not None: + self.cap.release() + except Exception as e: - print(f"Error in video thread: {e}") + self.error_occurred.emit(str(e)) else: time.sleep(0.01) def stop(self): self.running = False + if self.cap is not None: + self.cap.release() self.wait() class SoundThread(QThread): @@ -156,21 +144,48 @@ def play_sound(self, label): current_time = time.time() if (current_time - self.last_sound_time > SOUND_COOLDOWN or self.last_sound_class != label): - ses(f"Detected {label}") - self.last_sound_time = current_time - self.last_sound_class = label + try: + ses(f"Detected {label}") + self.last_sound_time = current_time + self.last_sound_class = label + except Exception as e: + print(f"Sound error: {e}") def stop(self): self.running = False self.wait() -class ObjectDetectionApp(QWidget): - def __init__(self): +class GeminiThread(QThread): + response_ready = Signal(str) + error_occurred = Signal(str) + + def __init__(self, api_key, object_info): super().__init__() + self.api_key = api_key + self.object_info = object_info - self.setWindowTitle("Object Detection with Gemini API") - self.setGeometry(100, 100, 1400, 800) - self.setStyleSheet("background-color: #1C2526;") + def run(self): + try: + genai.configure(api_key=self.api_key) + model = genai.GenerativeModel('gemini-pro') + + prompt = f""" + Describe this object in detail: + Class: {self.object_info['class_name']} + Confidence: {self.object_info['confidence']} + Location: {self.object_info['bounding_box']} + """ + + response = model.generate_content(prompt) + self.response_ready.emit(response.text) + except Exception as e: + self.error_occurred.emit(str(e)) + +class ObjectDetectionApp(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("AI Vision Assistant") + self.setGeometry(100, 100, 1600, 900) # Load data self.json_data = self.load_json_data() @@ -184,7 +199,9 @@ def __init__(self): # Connect signals self.detection_thread.frame_ready.connect(self.update_main_frame) + self.detection_thread.error_occurred.connect(self.handle_detection_error) self.video_thread.frame_ready.connect(self.update_secondary_frame) + self.video_thread.error_occurred.connect(self.handle_video_error) # Start threads self.detection_thread.start() @@ -196,160 +213,81 @@ def __init__(self): self.current_playing_class = None self.current_detections = [] - + + # Apply modern style + self.apply_modern_style() + def init_ui(self): - main_layout = QHBoxLayout(self) - main_layout.setSpacing(10) - main_layout.setContentsMargins(10, 10, 10, 10) + central_widget = QWidget() + self.setCentralWidget(central_widget) + main_layout = QHBoxLayout(central_widget) - # --- Left Panel --- + # Left Panel left_panel = QVBoxLayout() - left_panel.setSpacing(8) - # API Key Input - api_group = QGroupBox("Gemini API Configuration") - api_group.setStyleSheet(""" - QGroupBox { - color: #C9D6DF; - font-size: 14px; - font-weight: bold; - border: 1px solid #52616B; - border-radius: 6px; - margin-top: 10px; - } - QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 5px 10px; - } - """) + # API Configuration + api_group = QGroupBox("AI Configuration") api_layout = QVBoxLayout() self.api_key_input = QLineEdit() self.api_key_input.setPlaceholderText("Enter your Gemini API key") - self.api_key_input.setStyleSheet(""" - QLineEdit { - padding: 8px; - background-color: #2E2E2E; - color: #E8ECEF; - border: 1px solid #52616B; - border-radius: 4px; - } - """) api_layout.addWidget(self.api_key_input) self.save_api_button = QPushButton("Save API Key") - self.save_api_button.setStyleSheet(""" - QPushButton { - padding: 8px; - background-color: #52616B; - color: #E8ECEF; - border: none; - border-radius: 4px; - } - QPushButton:hover { - background-color: #657B83; - } - """) self.save_api_button.clicked.connect(self.save_api_key) api_layout.addWidget(self.save_api_button) api_group.setLayout(api_layout) left_panel.addWidget(api_group) - # Main video screen - self.video_label = QLabel("Waiting for camera...", self) + # Main Video Display + self.video_label = QLabel() self.video_label.setAlignment(Qt.AlignCenter) + self.video_label.setMinimumSize(640, 480) self.video_label.setStyleSheet(""" - background-color: #2E2E2E; - color: #C9D6DF; - border: 2px solid #52616B; - border-radius: 8px; + QLabel { + background-color: #2E2E2E; + border: 2px solid #52616B; + border-radius: 10px; + padding: 10px; + } """) - self.video_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) left_panel.addWidget(self.video_label, 1) - # Object list - objects_group = QGroupBox("Detected Objects") - objects_group.setStyleSheet(""" - QGroupBox { - color: #C9D6DF; - font-size: 14px; - font-weight: bold; - border: 1px solid #52616B; - border-radius: 6px; - margin-top: 10px; - } - QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 5px 10px; - } - """) - objects_layout = QVBoxLayout() + # Detection Results + results_group = QGroupBox("Detection Results") + results_layout = QVBoxLayout() self.objects_text = QTextEdit() self.objects_text.setReadOnly(True) - self.objects_text.setStyleSheet(""" - QTextEdit { - background-color: #2E2E2E; - color: #E8ECEF; - border: 1px solid #52616B; - border-radius: 4px; - padding: 8px; - } - """) - objects_layout.addWidget(self.objects_text) + results_layout.addWidget(self.objects_text) - objects_group.setLayout(objects_layout) - left_panel.addWidget(objects_group) + results_group.setLayout(results_layout) + left_panel.addWidget(results_group) - # --- Right Panel --- + # Right Panel right_panel = QVBoxLayout() - right_panel.setSpacing(8) - # Secondary video screen - self.secondary_video_label = QLabel("Detected object video will be shown here", self) + # Secondary Video Display + self.secondary_video_label = QLabel() self.secondary_video_label.setAlignment(Qt.AlignCenter) + self.secondary_video_label.setMinimumSize(640, 480) self.secondary_video_label.setStyleSheet(""" - background-color: #2E2E2E; - color: #C9D6DF; - border: 2px solid #52616B; - border-radius: 8px; + QLabel { + background-color: #2E2E2E; + border: 2px solid #52616B; + border-radius: 10px; + padding: 10px; + } """) - self.secondary_video_label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) right_panel.addWidget(self.secondary_video_label, 1) - # Gemini API Response - response_group = QGroupBox("Gemini API Response") - response_group.setStyleSheet(""" - QGroupBox { - color: #C9D6DF; - font-size: 14px; - font-weight: bold; - border: 1px solid #52616B; - border-radius: 6px; - margin-top: 10px; - } - QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 5px 10px; - } - """) + # Gemini Response + response_group = QGroupBox("AI Description") response_layout = QVBoxLayout() self.response_text = QTextEdit() self.response_text.setReadOnly(True) - self.response_text.setStyleSheet(""" - QTextEdit { - background-color: #2E2E2E; - color: #E8ECEF; - border: 1px solid #52616B; - border-radius: 4px; - padding: 8px; - } - """) response_layout.addWidget(self.response_text) response_group.setLayout(response_layout) @@ -362,40 +300,61 @@ def init_ui(self): separator.setStyleSheet("background-color: #52616B;") main_layout.addWidget(separator) main_layout.addLayout(right_panel, 1) - - def save_api_key(self): - api_key = self.api_key_input.text().strip() - if api_key: - try: - # Test the API key - genai.configure(api_key=api_key) - model = genai.GenerativeModel('gemini-pro') - response = model.generate_content("Test connection") - - # Save the API key - with open("gemini_api_key.txt", "w") as f: - f.write(api_key) - - QMessageBox.information(self, "Success", "API key saved successfully!") - except Exception as e: - QMessageBox.critical(self, "Error", f"Invalid API key: {str(e)}") - else: - QMessageBox.warning(self, "Warning", "Please enter an API key") - - def load_api_key(self): - try: - with open("gemini_api_key.txt", "r") as f: - return f.read().strip() - except: - return None - + + def apply_modern_style(self): + self.setStyleSheet(qdarkstyle.load_stylesheet()) + + # Set window properties + self.setWindowFlags(Qt.Window | Qt.WindowMinMaxButtonsHint) + + # Apply styles to widgets + style = """ + QGroupBox { + color: #C9D6DF; + font-size: 14px; + font-weight: bold; + border: 1px solid #52616B; + border-radius: 8px; + margin-top: 15px; + padding: 15px; + } + QLineEdit { + padding: 10px; + background-color: #2E2E2E; + color: #E8ECEF; + border: 1px solid #52616B; + border-radius: 6px; + font-size: 13px; + } + QPushButton { + padding: 10px; + background-color: #52616B; + color: #E8ECEF; + border: none; + border-radius: 6px; + font-size: 13px; + } + QPushButton:hover { + background-color: #657B83; + } + QTextEdit { + background-color: #2E2E2E; + color: #E8ECEF; + border: 1px solid #52616B; + border-radius: 6px; + padding: 10px; + font-size: 13px; + } + """ + self.setStyleSheet(self.styleSheet() + style) + def update_main_frame(self, frame, detections): if frame is not None: self.display_image(frame, self.video_label) self.current_detections = detections self.update_objects_list() self.process_detections(detections) - + def update_objects_list(self): text = "" for detection in self.current_detections: @@ -403,36 +362,71 @@ def update_objects_list(self): text += f"({detection['confidence']:.2%} confidence) " text += f"at {detection['bounding_box']}\n" self.objects_text.setText(text) - + def update_secondary_frame(self, frame): if frame is not None: self.display_image(frame, self.secondary_video_label) - + + def display_image(self, frame, label_widget): + if frame is not None: + try: + # Get the label size + label_size = label_widget.size() + + # Calculate the aspect ratio + h, w = frame.shape[:2] + aspect_ratio = w / h + + # Calculate new dimensions while maintaining aspect ratio + if label_size.width() / label_size.height() > aspect_ratio: + new_height = label_size.height() + new_width = int(new_height * aspect_ratio) + else: + new_width = label_size.width() + new_height = int(new_width / aspect_ratio) + + # Resize frame using cv2 for better performance + resized_frame = cv2.resize(frame, (new_width, new_height), + interpolation=cv2.INTER_AREA) + + # Convert frame to RGB + rgb_frame = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2RGB) + + # Convert to QImage + bytes_per_line = 3 * new_width + qt_image = QImage(rgb_frame.data, new_width, new_height, + bytes_per_line, QImage.Format_RGB888) + + # Create pixmap and set it to label + pixmap = QPixmap.fromImage(qt_image) + label_widget.setPixmap(pixmap) + + except Exception as e: + print(f"Error displaying image: {e}") + def process_detections(self, detections): if not detections: + self.stop_secondary_video() return - # Get the detection with highest confidence best_detection = max(detections, key=lambda x: x['confidence']) - # Play video if available if best_detection['class_name'] in self.video_map: self.play_video_based_on_class(best_detection['class_name']) - # Play sound self.sound_thread.play_sound(best_detection['class_name']) - # Get Gemini API description api_key = self.load_api_key() if api_key and self.gemini_thread is None: - self.gemini_thread = GeminiAPIThread(api_key, best_detection) + self.gemini_thread = GeminiThread(api_key, best_detection) self.gemini_thread.response_ready.connect(self.update_gemini_response) + self.gemini_thread.error_occurred.connect(self.handle_gemini_error) self.gemini_thread.start() - + def update_gemini_response(self, response): self.response_text.setText(response) self.gemini_thread = None - + def play_video_based_on_class(self, object_class): if object_class != self.current_playing_class: if object_class in self.video_map: @@ -440,53 +434,53 @@ def play_video_based_on_class(self, object_class): self.current_playing_class = object_class else: self.stop_secondary_video() - + def stop_secondary_video(self): self.video_thread.set_video(None) self.current_playing_class = None - self.clear_label(self.secondary_video_label) - - def display_image(self, frame, label_widget): - if frame is not None: - # Convert frame to RGB - rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - - # Convert to QImage - h, w, ch = rgb_frame.shape - bytes_per_line = ch * w - qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) - - # Scale to fit label while maintaining aspect ratio - scaled_pixmap = QPixmap.fromImage(qt_image).scaled( - label_widget.size(), - Qt.KeepAspectRatio, - Qt.SmoothTransformation - ) - - label_widget.setPixmap(scaled_pixmap) - - def clear_label(self, label_widget, text=""): - label_widget.clear() - if text: - label_widget.setText(text) - - def closeEvent(self, event): - # Stop all threads - self.detection_thread.stop() - self.video_thread.stop() - self.sound_thread.stop() - if self.gemini_thread: - self.gemini_thread.stop() - event.accept() - + self.secondary_video_label.clear() + + def handle_detection_error(self, error_msg): + QMessageBox.critical(self, "Detection Error", f"Error in detection: {error_msg}") + + def handle_video_error(self, error_msg): + QMessageBox.critical(self, "Video Error", f"Error in video playback: {error_msg}") + + def handle_gemini_error(self, error_msg): + QMessageBox.critical(self, "Gemini API Error", f"Error in Gemini API: {error_msg}") + + def save_api_key(self): + api_key = self.api_key_input.text().strip() + if api_key: + try: + # Test the API key + genai.configure(api_key=api_key) + model = genai.GenerativeModel('gemini-pro') + response = model.generate_content("Test connection") + + # Save the API key + with open("gemini_api_key.txt", "w") as f: + f.write(api_key) + + QMessageBox.information(self, "Success", "API key saved successfully!") + except Exception as e: + QMessageBox.critical(self, "Error", f"Invalid API key: {str(e)}") + else: + QMessageBox.warning(self, "Warning", "Please enter an API key") + + def load_api_key(self): + try: + with open("gemini_api_key.txt", "r") as f: + return f.read().strip() + except: + return None + def load_json_data(self): - """Load object information from JSON file or create default if not exists.""" try: if os.path.exists(JSON_PATH): with open(JSON_PATH, 'r', encoding='utf-8') as f: return json.load(f) else: - # Create default JSON structure default_data = { "objects": { "person": { @@ -509,16 +503,14 @@ def load_json_data(self): } } } - # Save default data with open(JSON_PATH, 'w', encoding='utf-8') as f: json.dump(default_data, f, indent=4) return default_data except Exception as e: print(f"Error loading JSON data: {e}") return {"objects": {}} - + def create_video_map(self): - """Create a mapping of object classes to their video files.""" video_map = {} try: if os.path.exists(VIDEO_FOLDER): @@ -530,6 +522,15 @@ def create_video_map(self): print(f"Error creating video map: {e}") return video_map + def closeEvent(self, event): + # Stop all threads + self.detection_thread.stop() + self.video_thread.stop() + self.sound_thread.stop() + if self.gemini_thread: + self.gemini_thread.wait() + event.accept() + if __name__ == "__main__": app = QApplication(sys.argv) window = ObjectDetectionApp() diff --git a/gui_lm_studio.py b/gui_lm_studio.py new file mode 100644 index 0000000..a37fbb1 --- /dev/null +++ b/gui_lm_studio.py @@ -0,0 +1,460 @@ +import sys +import cv2 +import numpy as np +import requests +import json +from PySide6.QtCore import QTimer, Qt, QSize, QThread, Signal, QObject +from PySide6.QtGui import QImage, QPixmap, QFont, QPalette, QColor, QIcon +from PySide6.QtWidgets import (QApplication, QWidget, QLabel, QVBoxLayout, + QHBoxLayout, QFrame, QSizePolicy, QGroupBox, + QLineEdit, QPushButton, QTextEdit, QMessageBox, + QMainWindow, QComboBox) +import time +import os +from ultralytics import YOLO +from Sound_Project.Sound import ses +import qdarkstyle + +# --- Configuration --- +MODEL_PATH = "yolov8n.pt" +CAMERA_INDEX = 0 +TIMER_INTERVAL_MS = 30 +VIDEO_FOLDER = "video" +JSON_PATH = "object_info.json" +CONFIDENCE_THRESHOLD = 0.6 +SOUND_COOLDOWN = 2.0 +LM_STUDIO_BASE_URL = "http://10.52.15.98:40" +LM_STUDIO_URL = f"{LM_STUDIO_BASE_URL}/v1/chat/completions" + +# Available models +AVAILABLE_MODELS = [ + "deepseek-coder-6.7b-instruct.Q4_K_M.gguf", + "deepseek-llm-7b-chat.Q4_K_M.gguf", + "mistral-7b-instruct-v0.2.Q4_K_M.gguf", + "llama-2-7b-chat.Q4_K_M.gguf" +] + +def get_available_models(): + try: + print(f"Modeller alınıyor: {LM_STUDIO_BASE_URL}/v1/models") + response = requests.get(f"{LM_STUDIO_BASE_URL}/v1/models", timeout=5) + print(f"Model listesi yanıtı: {response.status_code}") + + if response.status_code == 200: + models = response.json() + print(f"Bulunan modeller: {models}") + return [model['id'] for model in models] + print(f"Model listesi alınamadı. Varsayılan modeller kullanılacak.") + return AVAILABLE_MODELS + except Exception as e: + print(f"Model listesi hatası: {e}") + return AVAILABLE_MODELS + +class DetectionThread(QThread): + frame_ready = Signal(np.ndarray, list) + error_occurred = Signal(str) + + def __init__(self, model_path, camera_index, conf_threshold): + super().__init__() + self.model_path = model_path + self.camera_index = camera_index + self.conf_threshold = conf_threshold + self.running = True + self.model = None + self.cap = None + + def run(self): + try: + self.model = YOLO(self.model_path) + self.cap = cv2.VideoCapture(self.camera_index) + if not self.cap.isOpened(): + raise Exception("Failed to open camera") + + while self.running: + ret, frame = self.cap.read() + if not ret: + continue + + results = self.model(frame, conf=self.conf_threshold)[0] + detections = [] + + for box in results.boxes: + cls = int(box.cls) + conf = float(box.conf[0]) + label = self.model.names[cls] + coords = box.xyxy[0].cpu().numpy().astype(int) + x1, y1, x2, y2 = coords + + cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) + text = f"{label}: {conf:.2f}" + cv2.putText(frame, text, (x1, y1 - 10), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) + + detections.append({ + 'object_id': len(detections) + 1, + 'class_name': label, + 'confidence': conf, + 'bounding_box': [int(x1), int(y1), int(x2), int(y2)] + }) + + self.frame_ready.emit(frame, detections) + time.sleep(0.01) + + except Exception as e: + self.error_occurred.emit(str(e)) + finally: + if self.cap is not None: + self.cap.release() + + def stop(self): + self.running = False + self.wait() + +class VideoThread(QThread): + frame_ready = Signal(np.ndarray) + error_occurred = Signal(str) + + def __init__(self): + super().__init__() + self.video_path = None + self.running = True + self.cap = None + + def set_video(self, path): + self.video_path = path + + def run(self): + while self.running: + if self.video_path: + try: + self.cap = cv2.VideoCapture(self.video_path) + if not self.cap.isOpened(): + raise Exception(f"Failed to open video: {self.video_path}") + + while self.running and self.video_path: + ret, frame = self.cap.read() + if not ret: + self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0) + continue + self.frame_ready.emit(frame) + time.sleep(0.01) + + if self.cap is not None: + self.cap.release() + + except Exception as e: + self.error_occurred.emit(str(e)) + else: + time.sleep(0.01) + + def stop(self): + self.running = False + if self.cap is not None: + self.cap.release() + self.wait() + +class SoundThread(QThread): + def __init__(self): + super().__init__() + self.last_sound_time = 0 + self.last_sound_class = None + self.running = True + + def play_sound(self, label): + current_time = time.time() + if (current_time - self.last_sound_time > SOUND_COOLDOWN or + self.last_sound_class != label): + try: + ses(f"Detected {label}") + self.last_sound_time = current_time + self.last_sound_class = label + except Exception as e: + print(f"Sound error: {e}") + + def stop(self): + self.running = False + self.wait() + +class LMStudioThread(QThread): + response_ready = Signal(str) + error_occurred = Signal(str) + + def __init__(self, object_info, model_name, json_data): + super().__init__() + self.object_info = object_info + self.model_name = model_name + self.json_data = json_data + + def get_fallback_info(self, class_name): + try: + if 'objects' in self.json_data and class_name in self.json_data['objects']: + obj_info = self.json_data['objects'][class_name] + return f""" + {obj_info['name']} hakkında bilgi: + + 1. Bu nesne nedir? + {obj_info['description']} + + 2. Genel özellikleri: + - {obj_info.get('features', 'Bilgi bulunamadı')} + + 3. Günlük hayatta kullanımı: + - {obj_info.get('usage', 'Bilgi bulunamadı')} + + 4. İlginç bilgiler: + - {obj_info.get('interesting_facts', 'Bilgi bulunamadı')} + """ + return f"Bu {class_name} hakkında hazır bilgi bulunamadı." + except Exception as e: + print(f"Fallback bilgi hatası: {e}") + return f"Bu {class_name} hakkında bilgi yüklenemedi." + + def run(self): + try: + print(f"LM Studio bağlantısı başlatılıyor... Model: {self.model_name}") + + # Önce fallback bilgiyi göster + fallback_info = self.get_fallback_info(self.object_info['class_name']) + self.response_ready.emit(fallback_info + "\n\nLM Studio'dan detaylı bilgi bekleniyor...") + + # API bağlantısını test et + test_url = "http://10.52.15.98:40/v1/models" + print(f"API test isteği gönderiliyor: {test_url}") + test_response = requests.get(test_url, timeout=5) + print(f"API test yanıtı: {test_response.status_code}") + + if test_response.status_code != 200: + raise Exception(f"LM Studio API'sine bağlanılamadı. Durum kodu: {test_response.status_code}") + + headers = { + "Content-Type": "application/json" + } + + prompt = f""" + Lütfen aşağıdaki nesne hakkında detaylı bilgi ver: + + Nesne: {self.object_info['class_name']} + Güven Skoru: {self.object_info['confidence']:.2%} + + Şu başlıklar altında detaylı bir açıklama yap: + 1. Bu nesne nedir? + 2. Genel özellikleri nelerdir? + 3. Günlük hayatta nasıl kullanılır? + 4. İlginç bilgiler ve tarihçesi + + Lütfen Türkçe olarak açık ve anlaşılır bir şekilde yanıt ver. + """ + + print(f"API isteği gönderiliyor... Prompt: {prompt[:100]}...") + + data = { + "model": self.model_name, + "messages": [{"role": "user", "content": prompt}], + "temperature": 0.7, + "max_tokens": 1000, + "stream": False + } + + print(f"API isteği verisi: {data}") + + response = requests.post( + "http://10.52.15.98:40/v1/chat/completions", + headers=headers, + json=data, + timeout=30 + ) + + print(f"API yanıtı alındı. Durum kodu: {response.status_code}") + print(f"API yanıt içeriği: {response.text[:200]}...") + + if response.status_code == 200: + try: + response_data = response.json() + print(f"API yanıtı JSON: {response_data}") + + if 'choices' in response_data and len(response_data['choices']) > 0: + assistant_message = response_data['choices'][0]['message']['content'] + print(f"İşlenmiş yanıt: {assistant_message[:100]}...") + self.response_ready.emit(assistant_message) + else: + error_msg = f"API yanıtı beklenen formatta değil. Yanıt: {response_data}" + print(error_msg) + self.error_occurred.emit(error_msg) + except json.JSONDecodeError as e: + error_msg = f"API yanıtı JSON formatında değil. Hata: {str(e)}" + print(error_msg) + self.error_occurred.emit(error_msg) + else: + error_msg = f"API Hatası: {response.status_code} - {response.text}" + print(error_msg) + self.error_occurred.emit(error_msg) + + except requests.exceptions.Timeout: + error_msg = "API yanıt vermedi (30 saniye zaman aşımı)" + print(error_msg) + self.error_occurred.emit(error_msg) + except requests.exceptions.ConnectionError as e: + error_msg = f"LM Studio sunucusuna bağlanılamadı: {str(e)}" + print(error_msg) + self.error_occurred.emit(error_msg) + except Exception as e: + error_msg = f"LM Studio Hatası: {str(e)}" + print(error_msg) + self.error_occurred.emit(error_msg) + + def handle_lm_studio_error(self, error_msg): + print(f"LM Studio hatası işleniyor: {error_msg}") + QMessageBox.critical(self, "LM Studio Hatası", error_msg) + self.response_text.setText(f"Hata: {error_msg}\n\nLütfen LM Studio'nun çalışır durumda olduğunu ve seçili modelin yüklü olduğunu kontrol edin.") + + def process_detections(self, detections): + if not detections: + self.stop_secondary_video() + return + + best_detection = max(detections, key=lambda x: x['confidence']) + current_time = time.time() + + # Video ve ses işlemleri + if best_detection['class_name'] in self.video_map: + self.play_video_based_on_class(best_detection['class_name']) + + self.sound_thread.play_sound(best_detection['class_name']) + + # LM Studio isteği için kontrol + should_request = False + + # Yeni nesne tespit edildi mi? + if self.last_detected_object != best_detection['class_name']: + should_request = True + print(f"Yeni nesne tespit edildi: {best_detection['class_name']}") + + # Son istekten bu yana yeterli süre geçti mi? + elif current_time - self.last_detection_time > self.detection_cooldown: + should_request = True + print(f"Bekleme süresi doldu: {best_detection['class_name']}") + + # LM Studio isteği gönder + if should_request and (self.lm_studio_thread is None or not self.lm_studio_thread.isRunning()): + self.last_detected_object = best_detection['class_name'] + self.last_detection_time = current_time + + self.response_text.setText(f"Tespit edilen nesne: {best_detection['class_name']}\nAnaliz ediliyor...") + self.lm_studio_thread = LMStudioThread(best_detection, self.model_combo.currentText(), self.json_data) + self.lm_studio_thread.response_ready.connect(self.update_lm_studio_response) + self.lm_studio_thread.error_occurred.connect(self.handle_lm_studio_error) + self.lm_studio_thread.start() + + def update_lm_studio_response(self, response): + self.response_text.setText(response) + self.lm_studio_thread = None + + def play_video_based_on_class(self, object_class): + if object_class != self.current_playing_class: + if object_class in self.video_map: + self.video_thread.set_video(self.video_map[object_class]) + self.current_playing_class = object_class + else: + self.stop_secondary_video() + + def stop_secondary_video(self): + self.video_thread.set_video(None) + self.current_playing_class = None + self.secondary_video_label.clear() + + def handle_detection_error(self, error_msg): + QMessageBox.critical(self, "Detection Error", f"Error in detection: {error_msg}") + + def handle_video_error(self, error_msg): + QMessageBox.critical(self, "Video Error", f"Error in video playback: {error_msg}") + + def handle_lm_studio_error(self, error_msg): + self.handle_lm_studio_error(error_msg) + + def load_json_data(self): + try: + if os.path.exists(JSON_PATH): + with open(JSON_PATH, 'r', encoding='utf-8') as f: + return json.load(f) + else: + default_data = { + "objects": { + "person": { + "name": "Person", + "description": "A human being", + "sound": "person.mp3", + "video": "person.mp4" + }, + "car": { + "name": "Car", + "description": "A motor vehicle", + "sound": "car.mp3", + "video": "car.mp4" + }, + "dog": { + "name": "Dog", + "description": "A domestic animal", + "sound": "dog.mp3", + "video": "dog.mp4" + } + } + } + with open(JSON_PATH, 'w', encoding='utf-8') as f: + json.dump(default_data, f, indent=4) + return default_data + except Exception as e: + print(f"Error loading JSON data: {e}") + return {"objects": {}} + + def create_video_map(self): + video_map = {} + try: + if os.path.exists(VIDEO_FOLDER): + for filename in os.listdir(VIDEO_FOLDER): + if filename.endswith(('.mp4', '.avi', '.mov')): + class_name = os.path.splitext(filename)[0] + video_map[class_name] = os.path.join(VIDEO_FOLDER, filename) + except Exception as e: + print(f"Error creating video map: {e}") + return video_map + + def refresh_models(self): + try: + models = get_available_models() + self.model_combo.clear() + for model in models: + self.model_combo.addItem(model) + if models: + self.model_combo.setCurrentText(models[0]) + QMessageBox.information(self, "Başarılı", "Modeller başarıyla yenilendi!") + except Exception as e: + QMessageBox.critical(self, "Hata", f"Model yenileme hatası: {str(e)}") + + def load_models(self): + try: + print("Modeller yükleniyor...") + models = get_available_models() + self.model_combo.clear() + for model in models: + self.model_combo.addItem(model) + if models: + self.model_combo.setCurrentText(models[0]) + print(f"Seçilen model: {models[0]}") + except Exception as e: + print(f"Model yükleme hatası: {e}") + QMessageBox.warning(self, "Uyarı", "Modeller yüklenemedi. Varsayılan modeller kullanılacak.") + + def closeEvent(self, event): + # Stop all threads + self.detection_thread.stop() + self.video_thread.stop() + self.sound_thread.stop() + if self.lm_studio_thread: + self.lm_studio_thread.wait() + event.accept() + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = ObjectDetectionApp() + window.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/lm_studio_chat.py b/lm_studio_chat.py new file mode 100644 index 0000000..cf25318 --- /dev/null +++ b/lm_studio_chat.py @@ -0,0 +1,130 @@ +import requests +import json +import os +import sys +from colorama import init, Fore, Style + +# Colorama'yı başlat +init() + +# LM Studio API endpoint'i +API_URL = "http://10.52.15.98:40/v1/chat/completions" + +def clear_screen(): + """Ekranı temizle""" + os.system('cls' if os.name == 'nt' else 'clear') + +def print_colored(text, color=Fore.WHITE, style=Style.NORMAL): + """Renkli metin yazdır""" + print(f"{style}{color}{text}{Style.RESET_ALL}") + +def get_available_models(): + """Kullanılabilir modelleri listele""" + try: + response = requests.get("http://10.52.15.98:40/v1/models") + if response.status_code == 200: + models = response.json() + return models.get('data', []) + return [] + except Exception as e: + print_colored(f"Model listesi alınamadı: {str(e)}", Fore.RED) + return [] + +def select_model(): + """Kullanıcıdan model seçmesini iste""" + models = get_available_models() + + if not models: + print_colored("Hiç model bulunamadı!", Fore.RED) + return None + + print_colored("\nKullanılabilir Modeller:", Fore.CYAN) + for i, model in enumerate(models, 1): + print(f"{i}. {model.get('id', 'Bilinmeyen Model')}") + + while True: + try: + choice = int(input("\nLütfen bir model seçin (numara): ")) + if 1 <= choice <= len(models): + return models[choice-1]['id'] + else: + print_colored("Geçersiz seçim! Lütfen tekrar deneyin.", Fore.RED) + except ValueError: + print_colored("Lütfen geçerli bir numara girin!", Fore.RED) + +def chat_with_model(model_id): + """Seçilen model ile sohbet et""" + headers = { + "Content-Type": "application/json" + } + + messages = [] + + print_colored("\nLM Studio Chat'e hoş geldiniz!", Fore.CYAN, Style.BRIGHT) + print_colored("Çıkmak için 'quit' veya 'exit' yazın.\n", Fore.YELLOW) + + while True: + try: + # Kullanıcı girdisi + user_input = input(f"{Fore.GREEN}Sen: {Style.RESET_ALL}") + + # Çıkış kontrolü + if user_input.lower() in ['quit', 'exit']: + print_colored("\nGörüşmek üzere!", Fore.CYAN) + break + + # Boş girdi kontrolü + if not user_input.strip(): + continue + + # Mesajı sohbet geçmişine ekle + messages.append({"role": "user", "content": user_input}) + + # API isteği için veri hazırla + data = { + "model": model_id, + "messages": messages, + "temperature": 0.7, + "max_tokens": 1000 + } + + # API'ye istek gönder + response = requests.post(API_URL, headers=headers, json=data) + + if response.status_code == 200: + response_data = response.json() + assistant_message = response_data['choices'][0]['message']['content'] + + # Asistan yanıtını sohbet geçmişine ekle + messages.append({"role": "assistant", "content": assistant_message}) + + # Yanıtı göster + print(f"\n{Fore.BLUE}Model: {Style.RESET_ALL}{assistant_message}\n") + else: + print_colored(f"\nHata: {response.status_code} - {response.text}", Fore.RED) + + except KeyboardInterrupt: + print_colored("\n\nGörüşmek üzere!", Fore.CYAN) + break + except Exception as e: + print_colored(f"\nBir hata oluştu: {str(e)}", Fore.RED) + print_colored("Yeni bir sohbet başlatılıyor...\n", Fore.YELLOW) + messages = [] + +def main(): + """Ana program""" + clear_screen() + + # Model seç + model_id = select_model() + + if model_id: + try: + chat_with_model(model_id) + except Exception as e: + print_colored(f"\nBeklenmeyen bir hata oluştu: {str(e)}", Fore.RED) + else: + print_colored("\nProgram başlatılamadı. Lütfen LM Studio'nun çalıştığından emin olun.", Fore.RED) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/modern_vision_assistant.py b/modern_vision_assistant.py new file mode 100644 index 0000000..e726574 --- /dev/null +++ b/modern_vision_assistant.py @@ -0,0 +1,573 @@ +import sys +import os +import time +import json +import cv2 +import numpy as np +import requests +from PySide6.QtCore import Qt, QThread, Signal, QSize, QTimer, QPropertyAnimation, QEasingCurve +from PySide6.QtGui import (QImage, QPixmap, QIcon, QFont, QColor, QPalette, + QLinearGradient, QPainter, QBrush) +from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, + QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, + QTextEdit, QGroupBox, QFrame, QMessageBox, + QProgressBar, QSizePolicy, QSpacerItem) +from ultralytics import YOLO +import qdarkstyle + +# --- AYARLAR --- +MODEL_PATH = "yolov8n.pt" +CAMERA_INDEX = 0 +VIDEO_FOLDER = "video" +JSON_PATH = "object_info.json" +CONFIDENCE_THRESHOLD = 0.6 +SOUND_COOLDOWN = 2.0 +LM_STUDIO_BASE_URL = "http://10.52.15.98:40" +LM_STUDIO_URL = f"{LM_STUDIO_BASE_URL}/v1/chat/completions" + +# --- ÖZEL WIDGET'LAR --- +class ModernGroupBox(QGroupBox): + def __init__(self, title, parent=None): + super().__init__(title, parent) + self.setStyleSheet(""" + QGroupBox { + background-color: #2D2D2D; + border: 2px solid #3D3D3D; + border-radius: 10px; + margin-top: 15px; + padding: 15px; + } + QGroupBox::title { + color: #00B4D8; + subcontrol-origin: margin; + left: 10px; + padding: 0 5px; + } + """) + +class ModernButton(QPushButton): + def __init__(self, text, parent=None): + super().__init__(text, parent) + self.setStyleSheet(""" + QPushButton { + background-color: #00B4D8; + color: white; + border: none; + border-radius: 5px; + padding: 8px 15px; + font-weight: bold; + } + QPushButton:hover { + background-color: #0096C7; + } + QPushButton:pressed { + background-color: #0077B6; + } + """) + +class ModernComboBox(QComboBox): + def __init__(self, parent=None): + super().__init__(parent) + self.setStyleSheet(""" + QComboBox { + background-color: #2D2D2D; + color: white; + border: 2px solid #3D3D3D; + border-radius: 5px; + padding: 5px; + min-width: 200px; + } + QComboBox::drop-down { + border: none; + } + QComboBox::down-arrow { + image: url(down_arrow.png); + width: 12px; + height: 12px; + } + QComboBox QAbstractItemView { + background-color: #2D2D2D; + color: white; + selection-background-color: #00B4D8; + } + """) + +class ModernTextEdit(QTextEdit): + def __init__(self, parent=None): + super().__init__(parent) + self.setStyleSheet(""" + QTextEdit { + background-color: #2D2D2D; + color: white; + border: 2px solid #3D3D3D; + border-radius: 5px; + padding: 10px; + } + """) + +class ModernProgressBar(QProgressBar): + def __init__(self, parent=None): + super().__init__(parent) + self.setStyleSheet(""" + QProgressBar { + border: 2px solid #3D3D3D; + border-radius: 5px; + text-align: center; + background-color: #2D2D2D; + } + QProgressBar::chunk { + background-color: #00B4D8; + border-radius: 3px; + } + """) + +# --- YARDIMCI FONKSİYONLAR --- +def get_available_models(): + try: + r = requests.get(f"{LM_STUDIO_BASE_URL}/v1/models", timeout=5) + if r.status_code == 200: + return [m['id'] for m in r.json()] + except Exception as e: + print(f"Model listesi alınamadı: {e}") + return [ + "deepseek-coder-6.7b-instruct.Q4_K_M.gguf", + "deepseek-llm-7b-chat.Q4_K_M.gguf", + "mistral-7b-instruct-v0.2.Q4_K_M.gguf", + "llama-2-7b-chat.Q4_K_M.gguf" + ] + +def load_json_data(): + if os.path.exists(JSON_PATH): + with open(JSON_PATH, "r", encoding="utf-8") as f: + return json.load(f) + return {"objects": {}} + +def create_video_map(): + video_map = {} + if os.path.exists(VIDEO_FOLDER): + for filename in os.listdir(VIDEO_FOLDER): + if filename.endswith(('.mp4', '.avi', '.mov')): + class_name = os.path.splitext(filename)[0] + video_map[class_name] = os.path.join(VIDEO_FOLDER, filename) + return video_map + +def get_fallback_info(class_name, json_data): + try: + if 'objects' in json_data and class_name in json_data['objects']: + obj = json_data['objects'][class_name] + return ( + f"
{obj.get('description', '')}
" + f"{obj.get('features', 'Bilgi yok')}
" + f"{obj.get('usage', 'Bilgi yok')}
" + f"{obj.get('interesting_facts', 'Bilgi yok')}
" + ) + except Exception as e: + print(f"Fallback bilgi hatası: {e}") + return f"{class_name.title()} hakkında hazır bilgi yok.
" + +# --- THREADLER --- +class DetectionThread(QThread): + frame_ready = Signal(np.ndarray, list) + error_occurred = Signal(str) + + def __init__(self, model_path, camera_index, conf_threshold): + super().__init__() + self.model_path = model_path + self.camera_index = camera_index + self.conf_threshold = conf_threshold + self.running = True + + def run(self): + try: + model = YOLO(self.model_path) + cap = cv2.VideoCapture(self.camera_index) + if not cap.isOpened(): + raise Exception("Kamera açılamadı") + + while self.running: + ret, frame = cap.read() + if not ret: + continue + + results = model(frame, conf=self.conf_threshold)[0] + detections = [] + + for box in results.boxes: + cls = int(box.cls) + conf = float(box.conf[0]) + label = model.names[cls] + coords = box.xyxy[0].cpu().numpy().astype(int) + x1, y1, x2, y2 = coords + + # Daha şık bir bounding box + cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 180, 216), 2) + cv2.putText(frame, f'{label}: {conf:.2f}', + (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, + 0.6, (0, 180, 216), 2) + + detections.append({ + 'object_id': len(detections)+1, + 'class_name': label, + 'confidence': conf, + 'bounding_box': [x1, y1, x2, y2] + }) + + self.frame_ready.emit(frame, detections) + time.sleep(0.01) + + cap.release() + except Exception as e: + self.error_occurred.emit(str(e)) + + def stop(self): + self.running = False + self.wait() + +class VideoThread(QThread): + frame_ready = Signal(np.ndarray) + error_occurred = Signal(str) + + def __init__(self): + super().__init__() + self.video_path = None + self.running = True + + def set_video(self, path): + self.video_path = path + + def run(self): + while self.running: + if self.video_path: + try: + cap = cv2.VideoCapture(self.video_path) + if not cap.isOpened(): + raise Exception(f"Video açılamadı: {self.video_path}") + + while self.running and self.video_path: + ret, frame = cap.read() + if not ret: + cap.set(cv2.CAP_PROP_POS_FRAMES, 0) + continue + + self.frame_ready.emit(frame) + time.sleep(0.01) + + cap.release() + except Exception as e: + self.error_occurred.emit(str(e)) + else: + time.sleep(0.01) + + def stop(self): + self.running = False + self.wait() + +class LMStudioThread(QThread): + response_ready = Signal(str) + error_occurred = Signal(str) + + def __init__(self, object_info, model_name, json_data): + super().__init__() + self.object_info = object_info + self.model_name = model_name + self.json_data = json_data + + def run(self): + class_name = self.object_info['class_name'] + fallback = get_fallback_info(class_name, self.json_data) + self.response_ready.emit(fallback + "{best['class_name']}
" + f"Analiz ediliyor..." + ) + + self.progress.setVisible(True) + + if self.lm_studio_thread and self.lm_studio_thread.isRunning(): + self.lm_studio_thread.terminate() + + self.lm_studio_thread = LMStudioThread( + best, + self.model_combo.currentText(), + self.json_data + ) + self.lm_studio_thread.response_ready.connect(self.update_lm_studio_response) + self.lm_studio_thread.error_occurred.connect(self.show_error) + self.lm_studio_thread.start() + + def update_lm_studio_response(self, response): + self.response_text.setHtml(response) + self.progress.setVisible(False) + + def play_video_based_on_class(self, object_class): + if object_class != self.current_playing_class: + if object_class in self.video_map: + self.video_thread.set_video(self.video_map[object_class]) + self.current_playing_class = object_class + else: + self.stop_secondary_video() + + def stop_secondary_video(self): + self.video_thread.set_video(None) + self.current_playing_class = None + self.secondary_video_label.clear() + + def show_error(self, msg): + self.progress.setVisible(False) + QMessageBox.critical(self, "Hata", str(msg)) + + def closeEvent(self, event): + self.detection_thread.stop() + self.video_thread.stop() + if self.lm_studio_thread: + self.lm_studio_thread.terminate() + event.accept() + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = ModernVisionApp() + window.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/obj_file/gemini_api_key.txt b/obj_file/gemini_api_key.txt new file mode 100644 index 0000000..0303c92 --- /dev/null +++ b/obj_file/gemini_api_key.txt @@ -0,0 +1 @@ +AIzaSyCG3a15QL9QlZov28xb4XyxwWE4Vzfpz4c \ No newline at end of file diff --git a/object_info.json b/object_info.json index ed75c71..81dd2d5 100644 --- a/object_info.json +++ b/object_info.json @@ -1,371 +1,564 @@ { "objects": { "person": { - "display_name": "İnsan", - "description": "Bir insan algılandı. Bu, bir birey veya bir grup olabilir.", - "extra_info": "Örnek: Yetişkin, çocuk, sporcu, vb." + "name": "İnsan", + "description": "İnsan, Homo sapiens türüne ait bir primat. İki ayak üzerinde yürüyen, düşünebilen ve konuşabilen bir canlı.", + "features": "İki ayak üzerinde yürüme, düşünme yeteneği, konuşma, alet kullanma, sosyal etkileşim", + "usage": "Toplumsal yaşam, iş gücü, iletişim, üretim, eğitim", + "interesting_facts": "İnsan beyni yaklaşık 86 milyar nöron içerir ve günlük 70.000 düşünce üretir." }, "bicycle": { - "display_name": "Bisiklet", - "description": "Bir bisiklet algılandı.", - "extra_info": "Örnek: Dağ bisikleti, şehir bisikleti, yarış bisikleti, vb." + "name": "Bisiklet", + "description": "İnsan gücüyle hareket eden, iki tekerlekli bir ulaşım aracı.", + "features": "İki tekerlek, pedal sistemi, zincir mekanizması, fren sistemi", + "usage": "Ulaşım, spor, rekreasyon, egzersiz", + "interesting_facts": "İlk bisiklet 1817'de Alman Baron Karl von Drais tarafından icat edildi." }, "car": { - "display_name": "Araba", - "description": "Bir motorlu kara taşıtı algılandı.", - "extra_info": "Örnek: Sedan, SUV, hatchback, vb." + "name": "Araba", + "description": "Motorlu, dört tekerlekli kara taşıtı.", + "features": "Motor, şanzıman, direksiyon, fren sistemi, yakıt deposu", + "usage": "Ulaşım, taşımacılık, seyahat", + "interesting_facts": "İlk benzinli otomobil 1886'da Karl Benz tarafından üretildi." }, "motorcycle": { - "display_name": "Motosiklet", - "description": "Bir motosiklet algılandı.", - "extra_info": "Örnek: Scooter, chopper, yarış motosikleti, vb." + "name": "Motosiklet", + "description": "İki tekerlekli, motorlu taşıt.", + "features": "Motor, şanzıman, direksiyon, fren sistemi", + "usage": "Ulaşım, spor, rekreasyon", + "interesting_facts": "İlk motosiklet 1885'te Gottlieb Daimler tarafından üretildi." }, "airplane": { - "display_name": "Uçak", - "description": "Bir uçak algılandı.", - "extra_info": "Örnek: Yolcu uçağı, savaş uçağı, küçük pervaneli uçak, vb." + "name": "Uçak", + "description": "Havada uçabilen, motorlu hava taşıtı.", + "features": "Kanatlar, motor, iniş takımı, kokpit", + "usage": "Hava ulaşımı, kargo taşımacılığı, askeri operasyonlar", + "interesting_facts": "İlk motorlu uçuş 1903'te Wright Kardeşler tarafından gerçekleştirildi." }, "bus": { - "display_name": "Otobüs", - "description": "Bir otobüs algılandı.", - "extra_info": "Örnek: Şehir içi otobüs, tur otobüsü, okul otobüsü, vb." + "name": "Otobüs", + "description": "Çok sayıda yolcu taşıyabilen, büyük kara taşıtı.", + "features": "Geniş iç mekan, çoklu koltuklar, geniş kapılar", + "usage": "Toplu taşıma, şehirlerarası ulaşım, turizm", + "interesting_facts": "İlk otobüs 1826'da İngiltere'de hizmete girdi." }, "train": { - "display_name": "Tren", - "description": "Bir tren algılandı.", - "extra_info": "Örnek: Yük treni, yolcu treni, hızlı tren, vb." + "name": "Tren", + "description": "Raylar üzerinde hareket eden, çok sayıda vagonu olan taşıt.", + "features": "Lokomotif, vagonlar, raylar, sinyalizasyon sistemi", + "usage": "Toplu taşıma, yük taşımacılığı, şehirlerarası ulaşım", + "interesting_facts": "İlk buharlı tren 1804'te Richard Trevithick tarafından yapıldı." }, "truck": { - "display_name": "Kamyon", - "description": "Bir kamyon algılandı.", - "extra_info": "Örnek: Tır, hafriyat kamyonu, küçük kamyonet, vb." + "name": "Kamyon", + "description": "Büyük yük taşıma kapasitesine sahip motorlu araç.", + "features": "Güçlü motor, geniş yük alanı, dayanıklı şasi", + "usage": "Yük taşımacılığı, nakliyat, inşaat", + "interesting_facts": "İlk kamyon 1896'da Gottlieb Daimler tarafından üretildi." }, "boat": { - "display_name": "Tekne", - "description": "Bir tekne algılandı.", - "extra_info": "Örnek: Yelkenli, motorlu tekne, sandal, vb." + "name": "Tekne", + "description": "Su üzerinde hareket eden, küçük deniz taşıtı.", + "features": "Gövde, motor, dümen, güvenlik ekipmanları", + "usage": "Balıkçılık, rekreasyon, ulaşım", + "interesting_facts": "İlk tekne MÖ 8000 yıllarında kullanılmaya başlandı." }, "traffic light": { - "display_name": "Trafik Işığı", - "description": "Bir trafik ışığı algılandı.", - "extra_info": "Örnek: Kırmızı ışık, yeşil ışık, sarı ışık." + "name": "Trafik Işığı", + "description": "Trafik akışını düzenleyen, renkli sinyal sistemi.", + "features": "Kırmızı, sarı, yeşil ışıklar, zamanlayıcı, sensörler", + "usage": "Trafik kontrolü, güvenlik, düzen sağlama", + "interesting_facts": "İlk trafik ışığı 1868'de Londra'da kullanıldı." }, "fire hydrant": { - "display_name": "Yangın Hidrantı", - "description": "Bir yangın hidrantı algılandı.", - "extra_info": "Örnek: Kırmızı hidrant, yer altı hidrantı, vb." + "name": "Yangın Musluğu", + "description": "Acil durumlarda su temini sağlayan yer altı su sistemi bağlantı noktası.", + "features": "Su bağlantısı, vana sistemi, standart bağlantı noktaları", + "usage": "Yangın söndürme, acil durum müdahalesi", + "interesting_facts": "İlk yangın musluğu 1801'de Frederick Graff tarafından icat edildi." }, "stop sign": { - "display_name": "Dur Tabelası", - "description": "Bir dur tabelası algılandı.", - "extra_info": "Örnek: Standart kırmızı sekizgen tabela." + "name": "Dur İşareti", + "description": "Trafikte durulması gereken noktaları belirten kırmızı sekizgen işaret.", + "features": "Kırmızı renk, sekizgen şekil, beyaz yazı", + "usage": "Trafik kontrolü, güvenlik", + "interesting_facts": "İlk dur işareti 1915'te Michigan'da kullanıldı." }, "parking meter": { - "display_name": "Parkmetre", - "description": "Bir parkmetre algılandı.", - "extra_info": "Örnek: Elektronik parkmetre, mekanik parkmetre." + "name": "Parkmetre", + "description": "Park yeri kullanımı için ücret toplayan cihaz.", + "features": "Para yuvası, zamanlayıcı, gösterge", + "usage": "Park yeri yönetimi, gelir toplama", + "interesting_facts": "İlk parkmetre 1935'te Oklahoma'da kullanıldı." }, "bench": { - "display_name": "Banka", - "description": "Bir oturma bankı algılandı.", - "extra_info": "Örnek: Ahşap banka, metal banka, park bankı." + "name": "Bank", + "description": "Oturmak için tasarlanmış, genellikle açık alanlarda bulunan mobilya.", + "features": "Oturma yüzeyi, ayaklar, dayanıklı malzeme", + "usage": "Dinlenme, bekleme, sosyal etkileşim", + "interesting_facts": "Antik Roma'da ilk banklar taştan yapılıyordu." }, "bird": { - "display_name": "Kuş", - "description": "Bir kuş algılandı.", - "extra_info": "Örnek: Serçe, güvercin, kartal, vb." + "name": "Kuş", + "description": "Tüylü, kanatlı, yumurtlayan omurgalı hayvan.", + "features": "Kanatlar, tüyler, gagalar, yumurtlama", + "usage": "Ekosistem dengesi, tozlaşma, böcek kontrolü", + "interesting_facts": "Dünyada yaklaşık 10.000 kuş türü bulunmaktadır." }, "cat": { - "display_name": "Kedi", - "description": "Bir kedi algılandı.", - "extra_info": "Örnek: Ev kedisi, sokak kedisi, yavru kedi." + "name": "Kedi", + "description": "Evcil, etçil memeli hayvan.", + "features": "Keskin pençeler, hassas bıyıklar, gece görüşü", + "usage": "Evcil hayvan, böcek kontrolü", + "interesting_facts": "Kediler günde ortalama 12-16 saat uyur." }, "dog": { - "display_name": "Köpek", - "description": "Bir köpek algılandı.", - "extra_info": "Örnek: Küçük ırk, büyük ırk, yavru köpek." + "name": "Köpek", + "description": "İnsanın en eski evcil hayvanı, sadık dost.", + "features": "Keskin koku alma, işitme, sadakat", + "usage": "Evcil hayvan, koruma, rehberlik", + "interesting_facts": "Köpekler 10.000 yıldan fazla süredir insanlarla birlikte yaşıyor." }, "horse": { - "display_name": "At", - "description": "Bir at algılandı.", - "extra_info": "Örnek: Yarış atı, yük atı, midilli." + "name": "At", + "description": "Büyük, güçlü, tek tırnaklı memeli.", + "features": "Güçlü kaslar, hızlı koşma yeteneği, dayanıklılık", + "usage": "Ulaşım, spor, tarım, terapi", + "interesting_facts": "Atlar ayakta uyuyabilir ve günde sadece 2-3 saat uykuya ihtiyaç duyar." }, "sheep": { - "display_name": "Koyun", - "description": "Bir koyun algılandı.", - "extra_info": "Örnek: Yetişkin koyun, kuzu, çiftlik koyunu." + "name": "Koyun", + "description": "Yünlü, otçul çiftlik hayvanı.", + "features": "Yün, sürü davranışı, otçul beslenme", + "usage": "Et, süt, yün üretimi", + "interesting_facts": "Koyunlar 360 derece görüş açısına sahiptir." }, "cow": { - "display_name": "İnek", - "description": "Bir inek algılandı.", - "extra_info": "Örnek: Süt ineği, besi ineği." + "name": "İnek", + "description": "Büyükbaş çiftlik hayvanı.", + "features": "Süt üretimi, güçlü yapı, otçul beslenme", + "usage": "Süt, et üretimi, tarım", + "interesting_facts": "İnekler günde ortalama 6-8 saat çiğneme yapar." }, "elephant": { - "display_name": "Fil", - "description": "Bir fil algılandı.", - "extra_info": "Örnek: Afrika fili, Asya fili." + "name": "Fil", + "description": "Dünyanın en büyük kara memelisi.", + "features": "Hortum, büyük kulaklar, uzun dişler", + "usage": "Turizm, eğitim, koruma", + "interesting_facts": "Filler ailelerini 30 yıldan fazla hatırlayabilir." }, "bear": { - "display_name": "Ayı", - "description": "Bir ayı algılandı.", - "extra_info": "Örnek: Kutup ayısı, boz ayı, panda." + "name": "Ayı", + "description": "Büyük, güçlü yırtıcı memeli.", + "features": "Güçlü pençeler, kış uykusu, iyi koku alma", + "usage": "Ekosistem dengesi, turizm", + "interesting_facts": "Ayılar yüzebilir ve ağaçlara tırmanabilir." }, "zebra": { - "display_name": "Zebra", - "description": "Bir zebra algılandı.", - "extra_info": "Örnek: Düz çizgili zebra, dağ zebrası." + "name": "Zebra", + "description": "Siyah-beyaz çizgili, at benzeri memeli.", + "features": "Çizgili desen, hızlı koşma, sürü davranışı", + "usage": "Turizm, eğitim", + "interesting_facts": "Her zebranın çizgileri parmak izi gibi benzersizdir." }, "giraffe": { - "display_name": "Zürafa", - "description": "Bir zürafa algılandı.", - "extra_info": "Örnek: Uzun boylu zürafa, yavru zürafa." + "name": "Zürafa", + "description": "Uzun boyunlu, benekli memeli.", + "features": "Uzun boyun, benekli desen, uzun bacaklar", + "usage": "Turizm, eğitim", + "interesting_facts": "Zürafaların dili 50 cm uzunluğunda olabilir." }, "backpack": { - "display_name": "Sırt Çantası", - "description": "Bir sırt çantası algılandı.", - "extra_info": "Örnek: Okul çantası, kamp çantası." + "name": "Sırt Çantası", + "description": "Sırtta taşınan, eşya taşıma aracı.", + "features": "Omuz askıları, bölmeler, fermuarlar", + "usage": "Eşya taşıma, okul, seyahat", + "interesting_facts": "İlk modern sırt çantası 1938'de tasarlandı." }, "umbrella": { - "display_name": "Şemsiye", - "description": "Bir şemsiye algılandı.", - "extra_info": "Örnek: Katlanır şemsiye, büyük şemsiye." + "name": "Şemsiye", + "description": "Yağmur ve güneşten korunma aracı.", + "features": "Açılır kapanır yapı, saplık, su geçirmez kumaş", + "usage": "Yağmur koruması, güneş koruması", + "interesting_facts": "İlk şemsiye MÖ 4000 yılında kullanıldı." }, "handbag": { - "display_name": "El Çantası", - "description": "Bir el çantası algılandı.", - "extra_info": "Örnek: Omuz çantası, clutch çanta." + "name": "El Çantası", + "description": "Eşya taşımak için kullanılan aksesuar.", + "features": "Sap, bölmeler, fermuarlar", + "usage": "Eşya taşıma, moda aksesuarı", + "interesting_facts": "İlk el çantaları Mısırlılar tarafından kullanıldı." }, "tie": { - "display_name": "Kravat", - "description": "Bir kravat algılandı.", - "extra_info": "Örnek: İpek kravat, desenli kravat." + "name": "Kravat", + "description": "Boyun etrafına bağlanan, resmi kıyafet aksesuarı.", + "features": "Uzun şerit, düğüm, desen", + "usage": "Resmi kıyafet, moda aksesuarı", + "interesting_facts": "İlk kravat 17. yüzyılda Hırvat askerleri tarafından kullanıldı." }, "suitcase": { - "display_name": "Bavul", - "description": "Bir bavul algılandı.", - "extra_info": "Örnek: Seyahat bavulu, kabin boy bavul." + "name": "Bavul", + "description": "Seyahat için eşya taşıma çantası.", + "features": "Sert yapı, tekerlekler, kilit sistemi", + "usage": "Seyahat, eşya taşıma", + "interesting_facts": "İlk tekerlekli bavul 1970'lerde icat edildi." }, "frisbee": { - "display_name": "Frizbi", - "description": "Bir frizbi algılandı.", - "extra_info": "Örnek: Plastik frizbi, profesyonel frizbi." + "name": "Frizbi", + "description": "Havada uçan, disk şeklinde oyun aracı.", + "features": "Yuvarlak disk, hafif malzeme, aerodinamik yapı", + "usage": "Spor, eğlence, oyun", + "interesting_facts": "Frizbi, 1948'de bir pasta kutusundan esinlenilerek icat edildi." }, "skis": { - "display_name": "Kayaklar", - "description": "Bir çift kayak algılandı.", - "extra_info": "Örnek: Alp kayağı, serbest stil kayağı." + "name": "Kayak", + "description": "Karda kaymak için kullanılan uzun tahtalar.", + "features": "Uzun şekil, kaygan yüzey, bağlama sistemi", + "usage": "Kış sporu, eğlence", + "interesting_facts": "İlk kayaklar 5000 yıl önce kullanıldı." }, "snowboard": { - "display_name": "Snowboard", - "description": "Bir snowboard algılandı.", - "extra_info": "Örnek: Freestyle snowboard, yarış snowboardu." + "name": "Snowboard", + "description": "Karda kaymak için kullanılan tek parça tahta.", + "features": "Geniş yüzey, bağlama sistemi, kaygan alt yüzey", + "usage": "Kış sporu, eğlence", + "interesting_facts": "Snowboard 1960'larda sörf tahtasından esinlenilerek icat edildi." }, "sports ball": { - "display_name": "Spor Topu", - "description": "Bir spor topu algılandı.", - "extra_info": "Örnek: Futbol topu, basketbol topu, voleybol topu." + "name": "Spor Topu", + "description": "Çeşitli sporlarda kullanılan yuvarlak oyun aracı.", + "features": "Yuvarlak şekil, esnek yapı, dayanıklı malzeme", + "usage": "Spor, oyun, eğlence", + "interesting_facts": "İlk toplar MÖ 3000 yılında kullanıldı." }, "kite": { - "display_name": "Uçurtma", - "description": "Bir uçurtma algılandı.", - "extra_info": "Örnek: Klasik uçurtma, ejderha uçurtması." + "name": "Uçurtma", + "description": "Rüzgarda uçan, ipe bağlı oyun aracı.", + "features": "Hafif yapı, iplik, kuyruk", + "usage": "Eğlence, spor, gösteri", + "interesting_facts": "İlk uçurtmalar 2000 yıl önce Çin'de kullanıldı." }, "baseball bat": { - "display_name": "Beyzbol Sopası", - "description": "Bir beyzbol sopası algılandı.", - "extra_info": "Örnek: Ahşap beyzbol sopası, alüminyum sopası." + "name": "Beyzbol Sopası", + "description": "Beyzbol oyununda kullanılan uzun sopa.", + "features": "Silindirik yapı, tutma yeri, darbe yüzeyi", + "usage": "Beyzbol sporu", + "interesting_facts": "Profesyonel beyzbol sopaları genellikle akçaağaçtan yapılır." }, "baseball glove": { - "display_name": "Beyzbol Eldiveni", - "description": "Bir beyzbol eldiveni algılandı.", - "extra_info": "Örnek: Sağ el eldiveni, sol el eldiveni." + "name": "Beyzbol Eldiveni", + "description": "Beyzbol oyununda top yakalamak için kullanılan eldiven.", + "features": "Deri yapı, parmak bölmeleri, bağcıklar", + "usage": "Beyzbol sporu, koruma", + "interesting_facts": "İlk beyzbol eldivenleri 1870'lerde kullanıldı." }, "skateboard": { - "display_name": "Kaykay", - "description": "Bir kaykay algılandı.", - "extra_info": "Örnek: Klasik kaykay, elektrikli kaykay." + "name": "Kaykay", + "description": "Tekerlekli, üzerinde kayılan tahta.", + "features": "Tahta platform, tekerlekler, akslar", + "usage": "Spor, ulaşım, eğlence", + "interesting_facts": "İlk kaykay 1950'lerde sörfçüler tarafından icat edildi." }, "surfboard": { - "display_name": "Sörf Tahtası", - "description": "Bir sörf tahtası algılandı.", - "extra_info": "Örnek: Uzun tahta, kısa tahta sörf." + "name": "Sörf Tahtası", + "description": "Dalgalarda sörf yapmak için kullanılan uzun tahta.", + "features": "Uzun şekil, hafif malzeme, kaygan yüzey", + "usage": "Sörf sporu, eğlence", + "interesting_facts": "İlk sörf tahtaları Hawaii'de kullanıldı." }, "tennis racket": { - "display_name": "Tenis Raketi", - "description": "Bir tenis raketi algılandı.", - "extra_info": "Örnek: Profesyonel tenis raketi, çocuk raketi." - }, - "objects": { - "wine glass": { - "display_name": "Şarap Kadehi", - "description": "Bir şarap kadehi algılandı.", - "extra_info": "Örnek: Şampanya kadehi, kırmızı şarap kadehi." - }, - "cup": { - "display_name": "Bardak", - "description": "Bir bardak algılandı.", - "extra_info": "Örnek: Kahve bardağı, su bardağı, çay bardağı." - }, - "fork": { - "display_name": "Çatal", - "description": "Bir çatal algılandı.", - "extra_info": "Örnek: Yemek çatalı, tatlı çatalı." - }, - "knife": { - "display_name": "Bıçak", - "description": "Bir bıçak algılandı.", - "extra_info": "Örnek: Yemek bıçağı, ekmek bıçağı." - }, - "spoon": { - "display_name": "Kaşık", - "description": "Bir kaşık algılandı.", - "extra_info": "Örnek: Yemek kaşığı, tatlı kaşığı." - }, - "bowl": { - "display_name": "Kase", - "description": "Bir kase algılandı.", - "extra_info": "Örnek: Salata kasesi, çorba kasesi." - }, - "banana": { - "display_name": "Muz", - "description": "Bir muz algılandı.", - "extra_info": "Örnek: Sarı muz, yeşil muz." - }, - "apple": { - "display_name": "Elma", - "description": "Bir elma algılandı.", - "extra_info": "Örnek: Kırmızı elma, yeşil elma." - }, - "sandwich": { - "display_name": "Sandviç", - "description": "Bir sandviç algılandı.", - "extra_info": "Örnek: Peynirli sandviç, etli sandviç." - }, - "orange": { - "display_name": "Portakal", - "description": "Bir portakal algılandı.", - "extra_info": "Örnek: Navel portakal, kan portakal." - }, - "broccoli": { - "display_name": "Brokoli", - "description": "Bir brokoli algılandı.", - "extra_info": "Örnek: Yeşil brokoli, çiçekli brokoli." - }, - "carrot": { - "display_name": "Havuç", - "description": "Bir havuç algılandı.", - "extra_info": "Örnek: Kırmızı havuç, beyaz havuç." - }, - "hot dog": { - "display_name": "Hotdog", - "description": "Bir hotdog algılandı.", - "extra_info": "Örnek: Sosisli sandviç, ketçaplı hotdog." - }, - "pizza": { - "display_name": "Pizza", - "description": "Bir pizza algılandı.", - "extra_info": "Örnek: Margarita pizza, sucuklu pizza." - }, - "donut": { - "display_name": "Dondurma", - "description": "Bir donut algılandı.", - "extra_info": "Örnek: Şekerli donut, çikolatalı donut." - }, - "cake": { - "display_name": "Kek", - "description": "Bir kek algılandı.", - "extra_info": "Örnek: Çikolatalı kek, vanilyalı kek." - }, - "chair": { - "display_name": "Sandalye", - "description": "Bir sandalye algılandı.", - "extra_info": "Örnek: Ofis sandalyesi, yemek sandalyesi." - }, - "couch": { - "display_name": "Kanepe", - "description": "Bir kanepe algılandı.", - "extra_info": "Örnek: L şeklinde kanepe, köşe kanepe." - }, - "potted plant": { - "display_name": "Saksı Bitkisi", - "description": "Bir saksı bitkisi algılandı.", - "extra_info": "Örnek: Saksıda çiçek, saksıdaki ağaç." - }, - "bed": { - "display_name": "Yatak", - "description": "Bir yatak algılandı.", - "extra_info": "Örnek: Tek kişilik yatak, çift kişilik yatak." - }, - "dining table": { - "display_name": "Yemek Masası", - "description": "Bir yemek masası algılandı.", - "extra_info": "Örnek: Ahşap yemek masası, cam yemek masası." - }, - "toilet": { - "display_name": "Tuvalet", - "description": "Bir tuvalet algılandı.", - "extra_info": "Örnek: Sedir tipi tuvalet, klozet tipi tuvalet." - }, - "tv": { - "display_name": "Televizyon", - "description": "Bir televizyon algılandı.", - "extra_info": "Örnek: LCD televizyon, Smart televizyon." - }, - "laptop": { - "display_name": "Dizüstü Bilgisayar", - "description": "Bir dizüstü bilgisayar algılandı.", - "extra_info": "Örnek: MacBook, Windows dizüstü." - }, - "mouse": { - "display_name": "Fare", - "description": "Bir bilgisayar faresi algılandı.", - "extra_info": "Örnek: Optik fare, kablosuz fare." - }, - "remote": { - "display_name": "Uzaktan Kumanda", - "description": "Bir uzaktan kumanda algılandı.", - "extra_info": "Örnek: TV kumandası, klima kumandası." - }, - "keyboard": { - "display_name": "Klavye", - "description": "Bir klavye algılandı.", - "extra_info": "Örnek: Mekanik klavye, kablosuz klavye." - }, - "cell phone": { - "display_name": "Cep Telefonu", - "description": "Bir cep telefonu algılandı.", - "extra_info": "Örnek: Akıllı telefon, eski model telefon." - }, - "microwave": { - "display_name": "Mikrodalga Fırın", - "description": "Bir mikrodalga fırın algılandı.", - "extra_info": "Örnek: Dijital mikrodalga, klasik mikrodalga." - }, - "oven": { - "display_name": "Fırın", - "description": "Bir fırın algılandı.", - "extra_info": "Örnek: Elektrikli fırın, gazlı fırın." - }, - "toaster": { - "display_name": "Ekmek Kızartma Makinesi", - "description": "Bir ekmek kızartma makinesi algılandı.", - "extra_info": "Örnek: 2 dilimlik ekmek kızartıcı, 4 dilimlik ekmek kızartıcı." - }, - "sink": { - "display_name": "Lavabo", - "description": "Bir lavabo algılandı.", - "extra_info": "Örnek: Mutfak lavabosu, banyo lavabosu." - }, - "refrigerator": { - "display_name": "Buzdolabı", - "description": "Bir buzdolabı algılandı.", - "extra_info": "Örnek: Tek kapaklı buzdolabı, çift kapaklı buzdolabı." - }, - "bottle": { - "display_name": "Şişe", - "description": "Bir şişe algılandı.", - "extra_info": "Örnek: Su şişesi, cam şişe, plastik şişe." - } + "name": "Tenis Raketi", + "description": "Tenis oyununda top vurmak için kullanılan alet.", + "features": "Kafes yapı, sap, gerilmiş teller", + "usage": "Tenis sporu", + "interesting_facts": "Modern tenis raketleri karbon fiberden yapılır." + }, + "bottle": { + "name": "Şişe", + "description": "Sıvı taşımak için kullanılan kap.", + "features": "Dar boyun, kapak, dayanıklı malzeme", + "usage": "Sıvı taşıma, saklama", + "interesting_facts": "İlk cam şişeler MÖ 1500'de yapıldı." + }, + "wine glass": { + "name": "Şarap Bardağı", + "description": "Şarap içmek için özel tasarlanmış cam.", + "features": "İnce cam, uzun sap, geniş gövdeli", + "usage": "Şarap içme, sunum", + "interesting_facts": "Şarap bardakları şarabın aromasını en iyi şekilde yaymak için tasarlanır." + }, + "cup": { + "name": "Fincan", + "description": "Sıcak içecekler için kullanılan kap.", + "features": "Kulplu yapı, dayanıklı malzeme", + "usage": "İçecek servisi, kullanım", + "interesting_facts": "İlk fincanlar MÖ 4000'de kullanıldı." + }, + "fork": { + "name": "Çatal", + "description": "Yemek yemek için kullanılan çok dişli alet.", + "features": "Dişler, sap, metal yapı", + "usage": "Yemek yeme, servis", + "interesting_facts": "İlk çatallar 11. yüzyılda kullanıldı." + }, + "knife": { + "name": "Bıçak", + "description": "Kesme ve doğrama işlemleri için kullanılan alet.", + "features": "Keskin ağız, sap, metal yapı", + "usage": "Kesme, doğrama, yemek hazırlama", + "interesting_facts": "İlk bıçaklar MÖ 2.5 milyon yıl önce kullanıldı." + }, + "spoon": { + "name": "Kaşık", + "description": "Sıvı ve yumuşak yiyecekleri yemek için kullanılan alet.", + "features": "Kepçe şekli, sap, metal yapı", + "usage": "Yemek yeme, servis", + "interesting_facts": "İlk kaşıklar MÖ 1000'de kullanıldı." + }, + "bowl": { + "name": "Kase", + "description": "Yemek ve içecek servisi için kullanılan derin kap.", + "features": "Derin yapı, geniş ağız, dayanıklı malzeme", + "usage": "Yemek servisi, saklama", + "interesting_facts": "İlk kaseler MÖ 5000'de kullanıldı." + }, + "banana": { + "name": "Muz", + "description": "Sarı, uzun, tatlı meyve.", + "features": "Sarı kabuk, yumuşak et, tatlı lezzet", + "usage": "Yemek, atıştırmalık, tatlı", + "interesting_facts": "Muzlar aslında çilek ailesindendir." + }, + "apple": { + "name": "Elma", + "description": "Yuvarlak, tatlı veya ekşi meyve.", + "features": "Yuvarlak şekil, ince kabuk, sulu et", + "usage": "Yemek, meyve suyu, tatlı", + "interesting_facts": "Dünyada 7500'den fazla elma çeşidi vardır." + }, + "sandwich": { + "name": "Sandviç", + "description": "İki dilim ekmek arasına konulan yiyecek.", + "features": "Ekmek, iç malzeme, katmanlı yapı", + "usage": "Hızlı yemek, atıştırmalık", + "interesting_facts": "İlk sandviç 1762'de İngiltere'de yapıldı." + }, + "orange": { + "name": "Portakal", + "description": "Turuncu, yuvarlak, turunçgil meyvesi.", + "features": "Turuncu kabuk, sulu et, C vitamini", + "usage": "Yemek, meyve suyu, tatlı", + "interesting_facts": "Portakallar aslında yeşil olgunlaşır, soğuk hava turuncu rengi verir." + }, + "broccoli": { + "name": "Brokoli", + "description": "Yeşil, çiçekli sebze.", + "features": "Yeşil renk, çiçekli yapı, besleyici", + "usage": "Yemek, salata, garnitür", + "interesting_facts": "Brokoli, lahana ailesindendir." + }, + "carrot": { + "name": "Havuç", + "description": "Turuncu, uzun kök sebze.", + "features": "Turuncu renk, uzun şekil, tatlı lezzet", + "usage": "Yemek, salata, meyve suyu", + "interesting_facts": "Havuçlar aslında mor, beyaz ve sarı renklerde de olabilir." + }, + "hot dog": { + "name": "Sosisli Sandviç", + "description": "Ekmek arası sosis.", + "features": "Ekmek, sosis, soslar", + "usage": "Hızlı yemek, atıştırmalık", + "interesting_facts": "İlk sosisli sandviç 1904'te St. Louis'de satıldı." + }, + "pizza": { + "name": "Pizza", + "description": "Yuvarlak hamur üzerine malzemeler konularak pişirilen yemek.", + "features": "Hamur, sos, peynir, malzemeler", + "usage": "Ana yemek, atıştırmalık", + "interesting_facts": "İlk pizza 1889'da Napoli'de yapıldı." + }, + "donut": { + "name": "Çörek", + "description": "Halka şeklinde, şekerli hamur tatlısı.", + "features": "Halka şekil, şekerli kaplama, yumuşak hamur", + "usage": "Tatlı, atıştırmalık", + "interesting_facts": "İlk çörek 1847'de yapıldı." + }, + "cake": { + "name": "Pasta", + "description": "Tatlı, katmanlı hamur tatlısı.", + "features": "Katmanlar, krema, süsleme", + "usage": "Tatlı, kutlama", + "interesting_facts": "İlk pastalar Mısır'da MÖ 2000'de yapıldı." + }, + "chair": { + "name": "Sandalye", + "description": "Oturmak için tasarlanmış mobilya.", + "features": "Oturma yüzeyi, ayaklar, sırtlık", + "usage": "Oturma, dinlenme", + "interesting_facts": "İlk sandalyeler MÖ 3000'de kullanıldı." + }, + "couch": { + "name": "Kanepe", + "description": "Birden fazla kişinin oturabileceği büyük mobilya.", + "features": "Geniş oturma alanı, yastıklar, dayanıklı yapı", + "usage": "Oturma, dinlenme, uyuma", + "interesting_facts": "İlk kanepeler 17. yüzyılda kullanıldı." + }, + "potted plant": { + "name": "Saksı Bitkisi", + "description": "Saksıda yetiştirilen bitki.", + "features": "Bitki, saksı, toprak", + "usage": "Dekorasyon, hava temizleme", + "interesting_facts": "Saksı bitkileri havadaki toksinleri temizleyebilir." + }, + "bed": { + "name": "Yatak", + "description": "Uyumak için tasarlanmış mobilya.", + "features": "Şilte, yastık, yorgan", + "usage": "Uyuma, dinlenme", + "interesting_facts": "İnsanlar hayatlarının üçte birini yatakta geçirir." + }, + "dining table": { + "name": "Yemek Masası", + "description": "Yemek yemek için tasarlanmış mobilya.", + "features": "Düz yüzey, ayaklar, dayanıklı yapı", + "usage": "Yemek yeme, toplantı", + "interesting_facts": "İlk yemek masaları MÖ 3000'de kullanıldı." + }, + "toilet": { + "name": "Tuvalet", + "description": "Kişisel hijyen için kullanılan donanım.", + "features": "Oturak, sifon, su deposu", + "usage": "Kişisel hijyen", + "interesting_facts": "İlk modern tuvalet 1596'da icat edildi." + }, + "tv": { + "name": "Televizyon", + "description": "Görüntü ve ses yayını alan elektronik cihaz.", + "features": "Ekran, hoparlörler, uzaktan kumanda", + "usage": "Eğlence, haber, eğitim", + "interesting_facts": "İlk televizyon yayını 1927'de yapıldı." + }, + "laptop": { + "name": "Dizüstü Bilgisayar", + "description": "Taşınabilir kişisel bilgisayar.", + "features": "Ekran, klavye, işlemci", + "usage": "İş, eğitim, eğlence", + "interesting_facts": "İlk dizüstü bilgisayar 1981'de üretildi." + }, + "mouse": { + "name": "Fare", + "description": "Bilgisayar kontrolü için kullanılan cihaz.", + "features": "Tuşlar, tekerlek, sensör", + "usage": "Bilgisayar kontrolü", + "interesting_facts": "İlk bilgisayar faresi 1964'te icat edildi." + }, + "remote": { + "name": "Uzaktan Kumanda", + "description": "Elektronik cihazları uzaktan kontrol eden alet.", + "features": "Tuşlar, kızılötesi verici, pil", + "usage": "Cihaz kontrolü", + "interesting_facts": "İlk uzaktan kumanda 1950'de icat edildi." + }, + "keyboard": { + "name": "Klavye", + "description": "Bilgisayara veri girişi için kullanılan cihaz.", + "features": "Tuşlar, sayısal tuş takımı, fonksiyon tuşları", + "usage": "Veri girişi, yazı yazma", + "interesting_facts": "İlk klavye 1868'de icat edildi." + }, + "cell phone": { + "name": "Cep Telefonu", + "description": "Mobil iletişim cihazı.", + "features": "Ekran, kamera, internet bağlantısı", + "usage": "İletişim, internet, eğlence", + "interesting_facts": "İlk cep telefonu 1973'te icat edildi." + }, + "microwave": { + "name": "Mikrodalga Fırın", + "description": "Mikrodalga ışınlarla ısıtma yapan cihaz.", + "features": "Isıtma odası, kontrol paneli, döner tabla", + "usage": "Yemek ısıtma, pişirme", + "interesting_facts": "İlk mikrodalga fırın 1947'de üretildi." + }, + "oven": { + "name": "Fırın", + "description": "Yemek pişirmek için kullanılan cihaz.", + "features": "Pişirme odası, ısı kontrolü, zamanlayıcı", + "usage": "Yemek pişirme, ısıtma", + "interesting_facts": "İlk fırınlar MÖ 29.000'de kullanıldı." + }, + "toaster": { + "name": "Tost Makinesi", + "description": "Ekmek kızartmak için kullanılan cihaz.", + "features": "Kızartma yuvaları, zamanlayıcı, ısı kontrolü", + "usage": "Ekmek kızartma", + "interesting_facts": "İlk tost makinesi 1893'te icat edildi." + }, + "sink": { + "name": "Lavabo", + "description": "Su kullanımı için tasarlanmış donanım.", + "features": "Su musluğu, gider, tezgah", + "usage": "El yıkama, bulaşık yıkama", + "interesting_facts": "İlk modern lavabolar 1700'lerde kullanıldı." + }, + "refrigerator": { + "name": "Buzdolabı", + "description": "Yiyecekleri soğuk tutmak için kullanılan cihaz.", + "features": "Soğutma sistemi, raflar, dondurucu", + "usage": "Yiyecek saklama, soğutma", + "interesting_facts": "İlk buzdolabı 1834'te icat edildi." + }, + "book": { + "name": "Kitap", + "description": "Yazılı bilgi içeren basılı materyal.", + "features": "Sayfalar, kapak, cilt", + "usage": "Okuma, eğitim, eğlence", + "interesting_facts": "İlk kitap MÖ 2400'de yazıldı." + }, + "clock": { + "name": "Saat", + "description": "Zamanı gösteren cihaz.", + "features": "Kadran, akrep, yelkovan", + "usage": "Zaman ölçümü, dekorasyon", + "interesting_facts": "İlk mekanik saat 1300'lerde icat edildi." + }, + "vase": { + "name": "Vazo", + "description": "Çiçek ve süs eşyaları için kullanılan kap.", + "features": "Geniş ağız, dekoratif yapı, dayanıklı malzeme", + "usage": "Dekorasyon, çiçek düzenleme", + "interesting_facts": "İlk vazolar MÖ 5000'de yapıldı." + }, + "scissors": { + "name": "Makas", + "description": "Kesme işlemi için kullanılan alet.", + "features": "İki bıçak, menteşe, saplar", + "usage": "Kesme, kırpma", + "interesting_facts": "İlk makaslar MÖ 1500'de kullanıldı." + }, + "teddy bear": { + "name": "Oyuncak Ayı", + "description": "Yumuşak, oyuncak ayı.", + "features": "Yumuşak malzeme, doldurulmuş yapı, sevimli görünüm", + "usage": "Oyuncak, dekorasyon", + "interesting_facts": "İlk oyuncak ayı 1902'de yapıldı." + }, + "hair drier": { + "name": "Saç Kurutma Makinesi", + "description": "Saç kurutmak için kullanılan cihaz.", + "features": "Sıcak hava üfleme, güç ayarı, nozul", + "usage": "Saç kurutma, şekillendirme", + "interesting_facts": "İlk saç kurutma makinesi 1890'da icat edildi." + }, + "toothbrush": { + "name": "Diş Fırçası", + "description": "Diş temizliği için kullanılan alet.", + "features": "Fırça kılları, sap, baş", + "usage": "Diş temizliği", + "interesting_facts": "İlk diş fırçası 1498'de icat edildi." } } } \ No newline at end of file diff --git a/ses.mp3 b/ses.mp3 deleted file mode 100644 index 5cfbdeb32d5ee35ec03043ac899a72a093b1aa0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8832 zcmdVdo{Yd62;j37zB)^CHnFz{lw$uD;(S29maCh&+
zCNGb&LM5XfP%|?dmkq_gFRznN?yb&|@x5mHwnagA&TVykl%c}g$Ueb0#x1JpuV{#$
z=ppOx-?%RQa*L$YlMl`1)nV!2hSb(4&0y)NA-mxysZTX@q^|C7++`tI6Mj4y3mhSD
zyH!{YSgA}v*#=aS%es7yKSxR`a^J1T{1R=rMO|g%KjN%@@@j@>LqVV8tNaGq596?x
zDnR?w-HxrSEbzdgIy&aUA!7;%gJrLW`WX31M(3AfDot=M0
zOTxi9;`uGq74dHRS-um+yfmiGT6sd--h{P4$uK_#*{-sx4+-=1Cj}ZlW>E;HA`k~4
zDMar@7G}(c_TP!R