File size: 9,556 Bytes
1b7f275
 
 
 
 
 
c971021
1b7f275
 
 
 
 
 
 
c971021
1b7f275
 
 
c971021
1b7f275
 
 
 
c971021
 
1b7f275
 
 
 
 
c971021
1b7f275
 
 
 
 
c971021
9c17ac8
 
1b7f275
 
 
 
c971021
 
 
 
 
 
 
 
 
1b7f275
 
 
 
 
 
9c17ac8
 
1b7f275
 
 
 
c971021
1b7f275
 
c971021
1b7f275
 
c971021
1b7f275
c971021
1b7f275
 
 
 
ac3bd23
1b7f275
 
 
 
c971021
 
 
1b7f275
c971021
 
 
1b7f275
c971021
 
 
1b7f275
c971021
 
e69ad56
1b7f275
c971021
 
 
1b7f275
 
 
 
c971021
1b7f275
41db9aa
 
 
 
1b7f275
c971021
1b7f275
c971021
1b7f275
c971021
1b7f275
 
 
 
 
 
 
 
c971021
 
 
1b7f275
c971021
 
1b7f275
c971021
 
1b7f275
c971021
 
1b7f275
c971021
 
 
 
 
 
 
 
1b7f275
 
c971021
1b7f275
ac3bd23
 
 
c971021
ac3bd23
 
 
 
c971021
ac3bd23
9c17ac8
 
 
 
 
 
 
 
 
 
 
ac3bd23
 
1b7f275
 
c971021
1b7f275
 
5e80152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b7f275
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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()