Spaces:
Paused
Paused
Download app/services/encoding_service.py from Jetsada117/backend_project: direct link, hf CLI and curl.
- Browser
- Download file 11.5 kB
-
https://huggingface.co/spaces/Jetsada117/backend_project/resolve/main/app/services/encoding_service.py
- Command line
-
hf download hf://spaces/Jetsada117/backend_project/app/services/encoding_service.py
-
curl -L -o encoding_service.py https://huggingface.co/spaces/Jetsada117/backend_project/resolve/main/app/services/encoding_service.py
11.5 kB
| import re | |
| import numpy as np | |
| import pandas as pd | |
| class FeatureEncoder: | |
| """ | |
| แปลงข้อความลักษณะใบหน้าเป็น Feature Vector และแปลงกลับเป็นข้อความ | |
| """ | |
| def __init__(self): | |
| """ | |
| กำหนดหมวดหมู่ Feature ทั้งหมดและสร้าง Compiled Regex สำหรับสกัดช่วงวัย | |
| """ | |
| self.age_categories = [ | |
| "วัยเด็กเล็ก", | |
| "วัยเด็กโต", | |
| "วัยรุ่น", | |
| "วัยผู้ใหญ่ตอนต้น", | |
| "วัยผู้ใหญ่ตอนกลาง", | |
| "วัยสูงอายุ", | |
| ] | |
| self.gender_categories = [ | |
| "หญิง", | |
| "ชาย", | |
| ] | |
| self.hair_color_categories = [ | |
| "ผมเทา", | |
| "ผมบลอนด์", | |
| "ผมดำ", | |
| ] | |
| self.hair_style_categories = ["ศีรษะล้าน", "ผมตรง", "ผมหยักศก"] | |
| self.eyebrow_categories = [ | |
| "คิ้วโก่ง", | |
| "คิ้วหนา", | |
| "คิ้วตรง", | |
| "คิ้วบาง", | |
| ] | |
| self.skin_categories = [ | |
| "ผิวขาว", | |
| "ผิวขาวเหลือง", | |
| "ผิวสองสี", | |
| "ผิวคล้ำ", | |
| ] | |
| self.beard_categories = [ | |
| "ไรหนวด", | |
| "หนวดเข้ม", | |
| "เคราแพะ", | |
| "จอน", | |
| ] | |
| 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_groups = { | |
| "วัยเด็กเล็ก": ["เด็กเล็ก", "เด็กน้อย", "ทารก", "อนุบาล", "วัยเด็กเล็ก"], | |
| "วัยเด็กโต": ["เด็กประถม", "เด็กโต", "ประถม", "วัยเด็กโต"], | |
| "วัยรุ่น": ["เด็กมัธยม", "มหาวิทยาลัย", "มัธยม", "มหาลัย", "วัยเรียน", "วัยรุ่น"], | |
| "วัยผู้ใหญ่ตอนต้น": ["ผู้ใหญ่ตอนต้น", "คนวัยทำงาน", "วัยทำงาน"], | |
| "วัยผู้ใหญ่ตอนกลาง": ["ผู้ใหญ่ตอนกลาง", "คนวัยกลางคน", "วัยกลางคน"], | |
| "วัยสูงอายุ": ["ผู้สูงอายุ", "สูงอายุ", "คนแก่", "คนชรา", "วัยชรา", "ผู้เฒ่า"], | |
| } | |
| self.age_keyword_to_category = { | |
| keyword: category | |
| for category, keywords in self.age_groups.items() | |
| for keyword in keywords | |
| } | |
| sorted_age_keywords = sorted( | |
| self.age_keyword_to_category.keys(), key=len, reverse=True | |
| ) | |
| self.age_pattern = re.compile( | |
| "|".join(re.escape(kw) for kw in sorted_age_keywords) | |
| ) | |
| def _encode_one_hot(self, target_value, category_list): | |
| """ | |
| แปลง target_value เป็น One-Hot Vector ตาม category_list | |
| """ | |
| return [1 if target_value == category else 0 for category in category_list] | |
| def _encode_multi_hot(self, target_list, category_list): | |
| """ | |
| แปลง target_list เป็น Multi-Hot Vector สำหรับ Feature ที่มีได้หลายค่า | |
| """ | |
| return [1 if category in target_list else 0 for category in category_list] | |
| def parse_text(self, text): | |
| """ | |
| สกัด Feature แต่ละประเภทจากข้อความและ Return เป็น 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 | |
| if "ศีรษะล้าน" in text: | |
| extracted_features["hair_style"] = "ศีรษะล้าน" | |
| 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 | |
| age_match = self.age_pattern.search(text) | |
| if age_match: | |
| extracted_features["age"] = self.age_keyword_to_category[age_match.group(0)] | |
| if "ไรหนวด" in text or "เคราบาง" in text: | |
| extracted_features["beard"].append("ไรหนวด") | |
| elif "หนวดเข้ม" in text or "หนวด" 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): | |
| """ | |
| แปลงข้อความลักษณะใบหน้าเป็น Feature Vector แบบ NumPy Array | |
| """ | |
| 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, ...] กลับเป็นรายการคำภาษาไทย โดยอิงจาก 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 and "ศีรษะล้าน" not in matched_features: | |
| matched_features.append("ศีรษะล้าน") | |
| return matched_features | |
| def to_dataframe(self, vector): | |
| """ | |
| แปลง Vector เป็น DataFrame แนวตั้งสำหรับแสดงผลและ Debug | |
| """ | |
| df = pd.DataFrame([vector], columns=self.feature_names) | |
| return df.T | |
| def combine_results_to_vector(self, pred_dict: dict) -> list: | |
| """ | |
| รวมผลลัพธ์จาก Models ทุกตัวเป็น Feature 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: | |
| """ | |
| แปลงผลลัพธ์จาก Models เป็นข้อความภาษาไทยสำหรับแต่ละ Feature | |
| """ | |
| try: | |
| 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 = "" | |
| if sum(pred_dict["haircolor_result"]) > 0: | |
| haircolor_text = self.hair_color_categories[ | |
| np.argmax(pred_dict["haircolor_result"]) | |
| ] | |
| if hairstyle_text == "ศีรษะล้าน": | |
| haircolor_text = "" | |
| skin_text = self.skin_categories[np.argmax(pred_dict["skin_result"])] | |
| eyebrow_texts = [ | |
| cat | |
| for i, cat in enumerate(self.eyebrow_categories) | |
| if pred_dict["eyebrows_result"][i] == 1 | |
| ] | |
| eyebrow_string = ", ".join(eyebrow_texts) | |
| beard_texts = [ | |
| cat | |
| for i, cat in enumerate(self.beard_categories) | |
| if pred_dict["beard_result"][i] == 1 | |
| ] | |
| beard_string = ", ".join(beard_texts) | |
| 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() | |