SicheateR99 commited on
Commit
b1746dd
·
verified ·
1 Parent(s): 9b8c56c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -31
app.py CHANGED
@@ -40,65 +40,82 @@ class TextRequest(BaseModel):
40
  text: str
41
 
42
  # =========================================================
43
- # OPERASI BEDAH FILE .KERAS (Solusi Definitif Error JSON)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  # =========================================================
45
  def patch_keras_model(original_path):
46
  patched_path = "patched_" + original_path
47
- # Jika sudah pernah dibedah, langsung gunakan hasilnya
48
- if os.path.exists(patched_path):
49
- return patched_path
50
 
51
- print(f"Membedah {original_path} untuk menghapus quantization_config...")
52
  try:
53
  with zipfile.ZipFile(original_path, 'r') as zin:
54
  with zipfile.ZipFile(patched_path, 'w') as zout:
55
  for item in zin.infolist():
56
  content = zin.read(item.filename)
57
  if item.filename == 'config.json':
58
- # Bongkar JSON-nya
59
  config_dict = json.loads(content.decode('utf-8'))
60
-
61
- # Fungsi rekursif untuk mencari dan menghapus quantization_config di semua layer
62
  def hapus_biang_kerok(d):
63
  if isinstance(d, dict):
64
  d.pop('quantization_config', None)
65
- for k, v in d.items():
66
- hapus_biang_kerok(v)
67
  elif isinstance(d, list):
68
- for i in d:
69
- hapus_biang_kerok(i)
70
-
71
  hapus_biang_kerok(config_dict)
72
- # Bungkus kembali jadi JSON
73
  content = json.dumps(config_dict).encode('utf-8')
74
-
75
  zout.writestr(item, content)
76
  return patched_path
77
  except Exception as e:
78
  print(f"Gagal membedah model: {e}")
79
- return original_path # Fallback ke file asli jika gagal
80
-
81
- # =========================================================
82
- # LAZY LOAD MENGGUNAKAN MODEL YANG SUDAH DIBEDAH
83
- # =========================================================
84
- def get_ner_model():
85
- global ner_model, vocab
86
- if ner_model is None:
87
- with open("vocab.pkl", "rb") as f:
88
- vocab = pickle.load(f)
89
- patched_file = patch_keras_model("receipt_ner_model.keras")
90
- ner_model = tf.keras.models.load_model(patched_file, compile=False)
91
- return ner_model, vocab
92
 
93
  def get_clf_model():
94
  global clf_model, clf_encoder
95
  if clf_model is None:
96
  with open('penerjemah_kategori.pkl', 'rb') as file:
97
  clf_encoder = pickle.load(file)
 
98
  patched_file = patch_keras_model("model_strukly.keras")
99
  clf_model = tf.keras.models.load_model(patched_file, compile=False)
100
  return clf_model, clf_encoder
101
 
 
 
 
102
  def normalize_token(token: str):
103
  token = token.strip()
104
  if re.fullmatch(r"\d{1,3}([.,]\d{3})*", token): return PRICE_TOKEN
@@ -122,15 +139,14 @@ def predict_ner(request: TextRequest):
122
 
123
  if tokens:
124
  norm_tokens = [normalize_token(t) for t in tokens]
 
125
  X = np.zeros((1, MAX_SEQ_LEN), dtype=np.int32)
126
- mask = np.zeros((1, MAX_SEQ_LEN), dtype=np.float32)
127
  length = min(len(norm_tokens), MAX_SEQ_LEN)
128
 
129
  for i in range(length):
130
  X[0, i] = vcb.get(norm_tokens[i], vcb.get(UNK_TOKEN, 0))
131
- mask[0, i] = 1.0
132
 
133
- probs = model([X, mask], training=False).numpy()
134
  labels = [IDX2LABEL[int(np.argmax(probs[0, i]))] for i in range(length)]
135
 
136
  current_type = None
 
40
  text: str
41
 
42
  # =========================================================
43
+ # JURUS 1: BYPASS ARSITEKTUR MANUAL UNTUK NER (Anti-Error LSTM)
44
+ # =========================================================
45
+ def build_manual_ner_model(vocab_size=7929, max_len=64, num_classes=8):
46
+ inputs = tf.keras.Input(shape=(max_len,), dtype='int32', name='tokens')
47
+ x = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=64, mask_zero=True, name='embedding')(inputs)
48
+ x = tf.keras.layers.SpatialDropout1D(0.3, name='spatial_dropout1d')(x)
49
+
50
+ lstm1_f = tf.keras.layers.LSTM(128, return_sequences=True, dropout=0.4, name='forward_lstm')
51
+ lstm1_b = tf.keras.layers.LSTM(128, return_sequences=True, go_backwards=True, dropout=0.4, name='backward_lstm')
52
+ x = tf.keras.layers.Bidirectional(lstm1_f, backward_layer=lstm1_b, name='bilstm_1')(x)
53
+
54
+ lstm2_f = tf.keras.layers.LSTM(64, return_sequences=True, dropout=0.4, name='forward_lstm_1')
55
+ lstm2_b = tf.keras.layers.LSTM(64, return_sequences=True, go_backwards=True, dropout=0.4, name='backward_lstm_1')
56
+ x = tf.keras.layers.Bidirectional(lstm2_f, backward_layer=lstm2_b, name='bilstm_2')(x)
57
+
58
+ dense1 = tf.keras.layers.Dense(64, activation='relu', name='dense')
59
+ x = tf.keras.layers.TimeDistributed(dense1, name='proj')(x)
60
+ x = tf.keras.layers.Dropout(0.4, name='dropout')(x)
61
+
62
+ dense2 = tf.keras.layers.Dense(num_classes, activation='linear', name='dense_1')
63
+ x = tf.keras.layers.TimeDistributed(dense2, name='logits')(x)
64
+ probs = tf.keras.layers.Activation('softmax', name='probabilities')(x)
65
+
66
+ return tf.keras.Model(inputs=inputs, outputs=probs, name='BiLSTM_NER')
67
+
68
+ def get_ner_model():
69
+ global ner_model, vocab
70
+ if ner_model is None:
71
+ with open("vocab.pkl", "rb") as f:
72
+ vocab = pickle.load(f)
73
+ # Load kerangka manual, isi dengan weights
74
+ ner_model = build_manual_ner_model()
75
+ ner_model.load_weights("receipt_ner_model.keras")
76
+ return ner_model, vocab
77
+
78
+ # =========================================================
79
+ # JURUS 2: BEDAH JSON UNTUK KLASIFIKASI (Menyelamatkan Kamus Kata)
80
  # =========================================================
81
  def patch_keras_model(original_path):
82
  patched_path = "patched_" + original_path
83
+ if os.path.exists(patched_path): return patched_path
 
 
84
 
 
85
  try:
86
  with zipfile.ZipFile(original_path, 'r') as zin:
87
  with zipfile.ZipFile(patched_path, 'w') as zout:
88
  for item in zin.infolist():
89
  content = zin.read(item.filename)
90
  if item.filename == 'config.json':
 
91
  config_dict = json.loads(content.decode('utf-8'))
 
 
92
  def hapus_biang_kerok(d):
93
  if isinstance(d, dict):
94
  d.pop('quantization_config', None)
95
+ for v in d.values(): hapus_biang_kerok(v)
 
96
  elif isinstance(d, list):
97
+ for i in d: hapus_biang_kerok(i)
 
 
98
  hapus_biang_kerok(config_dict)
 
99
  content = json.dumps(config_dict).encode('utf-8')
 
100
  zout.writestr(item, content)
101
  return patched_path
102
  except Exception as e:
103
  print(f"Gagal membedah model: {e}")
104
+ return original_path
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  def get_clf_model():
107
  global clf_model, clf_encoder
108
  if clf_model is None:
109
  with open('penerjemah_kategori.pkl', 'rb') as file:
110
  clf_encoder = pickle.load(file)
111
+ # Bedah JSON lalu load utuh agar TextVectorization bekerja
112
  patched_file = patch_keras_model("model_strukly.keras")
113
  clf_model = tf.keras.models.load_model(patched_file, compile=False)
114
  return clf_model, clf_encoder
115
 
116
+ # =========================================================
117
+ # FUNGSI UTAMA
118
+ # =========================================================
119
  def normalize_token(token: str):
120
  token = token.strip()
121
  if re.fullmatch(r"\d{1,3}([.,]\d{3})*", token): return PRICE_TOKEN
 
139
 
140
  if tokens:
141
  norm_tokens = [normalize_token(t) for t in tokens]
142
+ # Karena pakai arsitektur manual, mask tidak perlu dibuat eksplisit (otomatis di layer Embedding)
143
  X = np.zeros((1, MAX_SEQ_LEN), dtype=np.int32)
 
144
  length = min(len(norm_tokens), MAX_SEQ_LEN)
145
 
146
  for i in range(length):
147
  X[0, i] = vcb.get(norm_tokens[i], vcb.get(UNK_TOKEN, 0))
 
148
 
149
+ probs = model(X, training=False).numpy()
150
  labels = [IDX2LABEL[int(np.argmax(probs[0, i]))] for i in range(length)]
151
 
152
  current_type = None