Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| import numpy as np | |
| import pandas as pd | |
| class FeatureEncoder: | |
| def __init__(self): | |
| self.age_categories = [ | |
| "วัยเด็กเล็ก", | |
| "วัยเด็กโต", | |
| "วัยรุ่น", | |
| "วัยผู้ใหญ่ตอนต้น", | |
| "วัยผู้ใหญ่ตอนกลาง", | |
| "วัยสูงอายุ", | |
| ] | |
| self.gender_categories = [ | |
| "หญิง", | |
| "ชาย", | |
| ] | |
| self.hair_color_categories = [ | |
| "ผมน้ำตาล", | |
| "ผมบลอนด์", | |
| "ผมดำ", | |
| ] | |
| self.hair_style_categories = ["ผมตรง", "ผมหยักศก"] | |
| self.eyebrow_categories = [ | |
| "คิ้วโก่ง", | |
| "คิ้วหนา", | |
| "คิ้วตรง", | |
| "คิ้วบาง", | |
| ] | |
| self.skin_categories = [ | |
| "ผิวขาว", | |
| "ผิวขาวเหลือง", | |
| "ผิวสองสี", | |
| "ผิวคล้ำ", | |
| ] | |
| self.beard_categories = [ | |
| "เคราบาง", | |
| "หนวด", | |
| "เคราแพะ", | |
| "จอน", | |
| ] | |
| # รวมชื่อ Feature ทั้งหมดตามลำดับ | |
| self.feature_names = ( | |
| self.age_categories | |
| + self.gender_categories | |
| + self.hair_color_categories | |
| + self.hair_style_categories | |
| + self.eyebrow_categories | |
| + self.skin_categories | |
| + self.beard_categories | |
| ) | |
| self.age_mapping = { | |
| "เด็กเล็ก": "วัยเด็กเล็ก", | |
| "เด็กโต": "วัยเด็กโต", | |
| "วัยรุ่น": "วัยรุ่น", | |
| "ผู้ใหญ่ตอนต้น": "วัยผู้ใหญ่ตอนต้น", | |
| "ผู้ใหญ่ตอนกลาง": "วัยผู้ใหญ่ตอนกลาง", | |
| "สูงอายุ": "วัยสูงอายุ", | |
| } | |
| def _encode_one_hot(self, target_value, category_list): | |
| return [1 if target_value == category else 0 for category in category_list] | |
| def _encode_multi_hot(self, target_list, category_list): | |
| return [1 if category in target_list else 0 for category in category_list] | |
| def parse_text(self, text): | |
| """ฟังก์ชันสกัดข้อมูลจากข้อความให้อยู่ในรูปแบบ Dictionary""" | |
| text = text.replace(" ", "") | |
| extracted_features = { | |
| "age": None, | |
| "gender": None, | |
| "hair_color": None, | |
| "hair_style": None, | |
| "eyebrow": [], | |
| "skin": None, | |
| "beard": [], | |
| } | |
| for category in self.gender_categories: | |
| if category in text: | |
| extracted_features["gender"] = category | |
| for category in self.hair_color_categories: | |
| if category in text or category.replace("ผม", "") in text: | |
| extracted_features["hair_color"] = category | |
| for category in self.hair_style_categories: | |
| if category in text or category.replace("ผม", "") in text: | |
| extracted_features["hair_style"] = category | |
| for category in self.eyebrow_categories: | |
| if category in text: | |
| extracted_features["eyebrow"].append(category) | |
| for category in sorted(self.skin_categories, key=len, reverse=True): | |
| if category in text: | |
| extracted_features["skin"] = category | |
| break | |
| for key, value in self.age_mapping.items(): | |
| if key in text: | |
| extracted_features["age"] = value | |
| if "เคราบาง" in text: | |
| extracted_features["beard"].append("เคราบาง") | |
| elif "หนวด" in text: | |
| extracted_features["beard"].append("หนวด") | |
| if "เคราแพะ" in text: | |
| extracted_features["beard"].append("เคราแพะ") | |
| if "จอน" in text: | |
| extracted_features["beard"].append("จอน") | |
| return extracted_features | |
| def text_to_vector(self, text, verbose=False): | |
| """ฟังก์ชันแปลงข้อความให้เป็น Vector""" | |
| parsed_data = self.parse_text(text) | |
| if verbose: | |
| print(f"ตีความได้ว่า: {parsed_data}") | |
| encoded_vector = [] | |
| encoded_vector.extend( | |
| self._encode_one_hot(parsed_data["age"], self.age_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_one_hot(parsed_data["gender"], self.gender_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_one_hot(parsed_data["hair_color"], self.hair_color_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_one_hot(parsed_data["hair_style"], self.hair_style_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_multi_hot(parsed_data["eyebrow"], self.eyebrow_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_one_hot(parsed_data["skin"], self.skin_categories) | |
| ) | |
| encoded_vector.extend( | |
| self._encode_multi_hot(parsed_data["beard"], self.beard_categories) | |
| ) | |
| return np.array(encoded_vector) | |
| def vector_to_text(self, vector): | |
| """ | |
| ฟังก์ชันแปลง Vector [0, 1, 0, ...] กลับเป็นคำภาษาไทย | |
| โดยอิงจาก index ของ self.feature_names | |
| """ | |
| matched_features = [] | |
| for i, val in enumerate(vector): | |
| if val == 1: | |
| matched_features.append(self.feature_names[i]) | |
| hair_style_start_idx = ( | |
| len(self.age_categories) | |
| + len(self.gender_categories) | |
| + len(self.hair_color_categories) | |
| ) | |
| hair_style_end_idx = hair_style_start_idx + len(self.hair_style_categories) | |
| hair_style_vector = vector[hair_style_start_idx:hair_style_end_idx] | |
| if sum(hair_style_vector) == 0: | |
| matched_features.append("ศีรษะล้าน") | |
| return matched_features | |
| def to_dataframe(self, vector): | |
| """Helper Method สำหรับแสดงผลในรูปแบบ DataFrame แนวตั้ง""" | |
| df = pd.DataFrame([vector], columns=self.feature_names) | |
| return df.T | |
| def combine_results_to_vector(self, pred_dict: dict) -> list: | |
| """รวมผลจากโมเดลทุกตัวเป็น Vector เดียว (จบในที่เดียว)""" | |
| keys = [ | |
| "age_result", | |
| "gender_result", | |
| "haircolor_result", | |
| "hairstyle_result", | |
| "eyebrows_result", | |
| "skin_result", | |
| "beard_result", | |
| ] | |
| full_vector = [] | |
| for key in keys: | |
| full_vector.extend(pred_dict.get(key) or []) | |
| return full_vector | |
| def get_thai_description_dict(self, pred_dict: dict) -> dict: | |
| """แปลงผลจากโมเดล (Array) เป็นข้อความภาษาไทยสำหรับแต่ละฟีเจอร์""" | |
| try: | |
| # ใช้ np.argmax เพื่อหา Index ที่มีความจุมากที่สุด | |
| age_text = self.age_categories[np.argmax(pred_dict["age_result"])] | |
| gender_text = self.gender_categories[np.argmax(pred_dict["gender_result"])] | |
| if sum(pred_dict["hairstyle_result"]) == 0: | |
| hairstyle_text = "ศีรษะล้าน" | |
| haircolor_text = "ไม่ระบุ" | |
| else: | |
| hairstyle_text = self.hair_style_categories[ | |
| np.argmax(pred_dict["hairstyle_result"]) | |
| ] | |
| haircolor_text = self.hair_color_categories[ | |
| np.argmax(pred_dict["haircolor_result"]) | |
| ] | |
| skin_text = self.skin_categories[np.argmax(pred_dict["skin_result"])] | |
| # Multi-label features | |
| eyebrow_texts = [ | |
| cat | |
| for i, cat in enumerate(self.eyebrow_categories) | |
| if pred_dict["eyebrows_result"][i] == 1 | |
| ] | |
| eyebrow_string = ", ".join(eyebrow_texts) or "ไม่ระบุ" | |
| beard_texts = [ | |
| cat | |
| for i, cat in enumerate(self.beard_categories) | |
| if pred_dict["beard_result"][i] == 1 | |
| ] | |
| beard_string = ", ".join(beard_texts) or "ไม่ระบุ" | |
| return { | |
| "age": age_text, | |
| "gender": gender_text, | |
| "haircolor": haircolor_text, | |
| "hairstyle": hairstyle_text, | |
| "eyebrows": eyebrow_string, | |
| "skin": skin_text, | |
| "beard": beard_string, | |
| } | |
| except (KeyError, IndexError, ValueError) as e: | |
| raise ValueError(f"ข้อมูลผลลัพธ์ไม่ถูกต้อง: {str(e)}") | |
| encoder = FeatureEncoder() | |