From d3efb2155f995565b9a40fd51f8b1dccff98c869 Mon Sep 17 00:00:00 2001 From: Poppin420 <125458768+Poppin420@users.noreply.github.com> Date: Sat, 6 Dec 2025 01:12:08 +0200 Subject: [PATCH] Add files via upload --- synais8hmata/app .py | 321 ++++++++++++++++++++++++++++++++++ synais8hmata/requirements.txt | 6 + 2 files changed, 327 insertions(+) create mode 100644 synais8hmata/app .py create mode 100644 synais8hmata/requirements.txt diff --git a/synais8hmata/app .py b/synais8hmata/app .py new file mode 100644 index 00000000..6bad1224 --- /dev/null +++ b/synais8hmata/app .py @@ -0,0 +1,321 @@ +# ========================================================= +# ΜΕΡΟΣ Β: FLASK WEB APP ΓΙΑ ΤΗΝ ΕΡΓΑΣΙΑ +# Αποθήκευσέ το ως app.py +# ========================================================= + +import os +import cv2 +from flask import Flask, request, render_template_string, send_from_directory +from fer import FER +from openai import OpenAI + +# ========================================================= +# ΡΥΘΜΙΣΕΙΣ OPENAI (ΠΑΛΙΟ ΙΔΙΟ CONCEPT) +# ========================================================= + +OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "") # ή βάλε σταθερά αν θες +client = None +if OPENAI_API_KEY: + client = OpenAI(api_key=OPENAI_API_KEY) + +LLM_MODEL = "gpt-4.1-mini" + +# ========================================================= +# ΔΗΜΙΟΥΡΓΙΑ FLASK APP +# ========================================================= + +app = Flask(__name__) + +# Φάκελοι για uploads / annotated +UPLOAD_FOLDER = "static/uploads" +ANNOTATED_FOLDER = "static/annotated" + +os.makedirs(UPLOAD_FOLDER, exist_ok=True) +os.makedirs(ANNOTATED_FOLDER, exist_ok=True) + +# Δημιουργία detector +emotion_detector = FER(mtcnn=True) + +# ========================================================= +# ΒΟΗΘΗΤΙΚΕΣ ΣΥΝΑΡΤΗΣΕΙΣ (ΙΔΙΕΣ ΛΟΓΙΚΑ ΜΕ ΤΟ NOTEBOOK) +# ========================================================= + +def allowed_emotions(): + return ["angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"] + + +def detect_emotions_in_image(image_path: str): + img_bgr = cv2.imread(image_path) + if img_bgr is None: + raise FileNotFoundError(f"Η εικόνα δεν βρέθηκε: {image_path}") + + img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) + raw = emotion_detector.detect_emotions(img_rgb) + + results = [] + for det in raw: + box = det.get("box", [0, 0, 0, 0]) + emo = det.get("emotions", {}) + if emo: + label = max(emo, key=emo.get) + conf = float(emo[label]) + else: + label = "unknown" + conf = 0.0 + + results.append({ + "box": tuple(box), + "emotion": label, + "confidence": conf, + "emotions": {k: float(v) for k, v in emo.items()} + }) + return results + + +def aggregate_emotions(detections): + base = {e: 0.0 for e in allowed_emotions()} + if not detections: + return base + + count = 0 + for det in detections: + emo = det["emotions"] + if emo: + count += 1 + for e in allowed_emotions(): + base[e] += float(emo.get(e, 0.0)) + + if count == 0: + return base + + for e in base: + base[e] /= count + + return base + + +def annotate_image(image_path: str, detections, save_path: str): + """ + Φορτώνει την εικόνα, ζωγραφίζει τα κουτιά και την αποθηκεύει στο save_path. + """ + img = cv2.imread(image_path) + if img is None: + raise FileNotFoundError("Αποτυχία φόρτωσης εικόνας.") + + for det in detections: + x, y, w, h = det["box"] + emotion = det["emotion"] + conf = det["confidence"] + + cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) + label = f"{emotion} ({conf:.2f})" + cv2.putText( + img, + label, + (x, y - 10), + cv2.FONT_HERSHEY_SIMPLEX, + 0.6, + (0, 255, 0), + 2, + cv2.LINE_AA + ) + + cv2.imwrite(save_path, img) + + +emotion_to_playlist = { + "happy": "uplifting_pop_playlist", + "sad": "chill_ambient_playlist", + "angry": "rock_energy_playlist", + "fear": "calm_piano_playlist", + "disgust": "neutral_focus_playlist", + "surprise": "random_discovery_playlist", + "neutral": "lofi_study_playlist", +} + +def map_emotion_to_playlist(dominant_emotion: str) -> str: + return emotion_to_playlist.get(dominant_emotion, "lofi_study_playlist") + + +def llm_description(summary: dict): + if client is None: + return "LLM δεν κλήθηκε (δεν έχει οριστεί OPENAI_API_KEY)." + + text = ", ".join([f"{e}: {v:.2f}" for e, v in summary.items()]) + + prompt = ( + "You are an assistant that describes emotional state based on probabilities.\n" + f"Emotion probabilities: {text}\n" + "Write a short, clear emotional interpretation in English." + ) + + try: + response = client.chat.completions.create( + model=LLM_MODEL, + messages=[ + {"role": "system", "content": "You explain emotional states accurately."}, + {"role": "user", "content": prompt} + ], + max_tokens=120, + temperature=0.4 + ) + return response.choices[0].message.content.strip() + except Exception as e: + return f"LLM error: {e}" + + +# ========================================================= +# ΑΠΛΟ HTML TEMPLATE ΣΕ CHAT-STYLE +# ========================================================= + +HTML_TEMPLATE = """ + + +
+ +Ανέβασε μία εικόνα προσώπου. Το σύστημα θα ανιχνεύσει το συναίσθημα, θα προτείνει playlist και θα δώσει περιγραφή μέσω LLM.
+ + + + {% if user_message %} +