Decoder24 commited on
Commit
91ac57d
·
verified ·
1 Parent(s): 5cee8ed

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +3 -0
  2. .history/.gitignore_20251026142232 +0 -0
  3. .history/.gitignore_20251026142256 +1 -0
  4. .history/.gitignore_20251026142259 +1 -0
  5. .history/.gitignore_20251026142438 +1 -0
  6. .history/.gitignore_20251026142440 +2 -0
  7. .history/.gitignore_20251026142441 +2 -0
  8. .history/.gitignore_20251026142443 +2 -0
  9. .history/.gitignore_20251026142445 +2 -0
  10. .history/.gitignore_20251026142503 +3 -0
  11. .history/.gitignore_20251026142504 +3 -0
  12. .history/README_20251026141542.md +0 -0
  13. .history/README_20251026143510.md +0 -0
  14. .history/README_20251026143515.md +0 -0
  15. .history/README_20251026143518.md +0 -0
  16. .history/README_20251026143525.md +0 -0
  17. .history/README_20251026143535.md +0 -0
  18. .history/README_20251026143548.md +0 -0
  19. .history/README_20251026143602.md +0 -0
  20. .history/README_20251026143605.md +0 -0
  21. .history/README_20251026143615.md +0 -0
  22. .history/README_20251026143617.md +0 -0
  23. .history/README_20251026143620.md +0 -0
  24. .history/README_20251026143621.md +0 -0
  25. .history/README_20251026143623.md +0 -0
  26. .history/README_20251026143627.md +0 -0
  27. .history/README_20251026143629.md +0 -0
  28. .history/README_20251026143631.md +0 -0
  29. .history/README_20251026143636.md +0 -0
  30. .history/README_20251026143639.md +0 -0
  31. .history/README_20251026143642.md +0 -0
  32. .history/README_20251026143646.md +0 -0
  33. .history/README_20251026143650.md +0 -0
  34. .history/README_20251026143651.md +0 -0
  35. .history/README_20251026143703.md +0 -0
  36. .history/README_20251026143705.md +0 -0
  37. .history/README_20251026143708.md +0 -0
  38. .history/README_20251026143817.md +0 -0
  39. .history/README_20251026143819.md +0 -0
  40. .history/app_20251026125228.py +0 -0
  41. .history/app_20251026134547.py +107 -0
  42. .history/app_20251026141042.py +107 -0
  43. .history/app_20251026141101.py +107 -0
  44. .history/app_20251026141102.py +107 -0
  45. .history/app_20251026141641.py +189 -0
  46. .history/app_20251026141642.py +189 -0
  47. .history/app_20251026141819.py +189 -0
  48. .history/app_20251026141833.py +198 -0
  49. .history/app_20251026141844.py +198 -0
  50. .history/app_20251026142055.py +201 -0
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /logs
3
+ /results
.history/.gitignore_20251026142232 ADDED
File without changes
.history/.gitignore_20251026142256 ADDED
@@ -0,0 +1 @@
 
 
1
+ /fine_tuned_bert_ner
.history/.gitignore_20251026142259 ADDED
@@ -0,0 +1 @@
 
 
1
+ /fine_tuned_bert_ner
.history/.gitignore_20251026142438 ADDED
@@ -0,0 +1 @@
 
 
1
+ /fine_tuned_bert_ner
.history/.gitignore_20251026142440 ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /l
.history/.gitignore_20251026142441 ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /
.history/.gitignore_20251026142443 ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /logs
.history/.gitignore_20251026142445 ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /logs
.history/.gitignore_20251026142503 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /logs
3
+ /result
.history/.gitignore_20251026142504 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ /fine_tuned_bert_ner
2
+ /logs
3
+ /results
.history/README_20251026141542.md ADDED
Binary file (60 Bytes). View file
 
.history/README_20251026143510.md ADDED
Binary file (2.25 kB). View file
 
.history/README_20251026143515.md ADDED
Binary file (2.24 kB). View file
 
.history/README_20251026143518.md ADDED
Binary file (2.24 kB). View file
 
.history/README_20251026143525.md ADDED
Binary file (2.51 kB). View file
 
.history/README_20251026143535.md ADDED
Binary file (3.02 kB). View file
 
.history/README_20251026143548.md ADDED
Binary file (3.56 kB). View file
 
.history/README_20251026143602.md ADDED
Binary file (3.56 kB). View file
 
.history/README_20251026143605.md ADDED
Binary file (3.5 kB). View file
 
.history/README_20251026143615.md ADDED
Binary file (3.5 kB). View file
 
.history/README_20251026143617.md ADDED
Binary file (3.5 kB). View file
 
.history/README_20251026143620.md ADDED
Binary file (3.57 kB). View file
 
.history/README_20251026143621.md ADDED
Binary file (3.5 kB). View file
 
.history/README_20251026143623.md ADDED
Binary file (3.51 kB). View file
 
.history/README_20251026143627.md ADDED
Binary file (3.53 kB). View file
 
.history/README_20251026143629.md ADDED
Binary file (3.6 kB). View file
 
.history/README_20251026143631.md ADDED
Binary file (3.6 kB). View file
 
.history/README_20251026143636.md ADDED
Binary file (3.61 kB). View file
 
.history/README_20251026143639.md ADDED
Binary file (3.62 kB). View file
 
.history/README_20251026143642.md ADDED
Binary file (3.62 kB). View file
 
.history/README_20251026143646.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143650.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143651.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143703.md ADDED
Binary file (3.65 kB). View file
 
.history/README_20251026143705.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143708.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143817.md ADDED
Binary file (3.64 kB). View file
 
.history/README_20251026143819.md ADDED
Binary file (3.64 kB). View file
 
.history/app_20251026125228.py ADDED
File without changes
.history/app_20251026134547.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+
8
+ # Tentukan path ke model yang sudah disimpan
9
+ MODEL_DIR = "./ner_bert_model"
10
+
11
+ # --- Fungsi untuk Memuat Model dan Tokenizer ---
12
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
13
+ @st.cache_resource
14
+ def load_model_and_tokenizer(model_dir):
15
+ try:
16
+ model = BertForTokenClassification.from_pretrained(model_dir)
17
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
18
+
19
+ # Muat tag_values
20
+ with open(os.path.join(model_dir, 'tag_values.json'), 'r') as f:
21
+ tag_values = json.load(f)
22
+
23
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
+ model.to(device)
25
+ model.eval() # Set model ke mode evaluasi
26
+
27
+ return model, tokenizer, tag_values, device
28
+ except Exception as e:
29
+ st.error(f"Error saat memuat model: {e}")
30
+ return None, None, None, None
31
+
32
+ # --- Fungsi untuk Prediksi ---
33
+ def predict(text, model, tokenizer, tag_values, device):
34
+ tokenized_sentence = tokenizer.encode(text)
35
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
36
+
37
+ with torch.no_grad():
38
+ output = model(input_ids)
39
+
40
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
41
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
42
+
43
+ # Logika dari sel 36 (menggabungkan token BPE '##')
44
+ new_tokens, new_labels = [], []
45
+ for token, label_idx in zip(tokens, label_indices[0]):
46
+ if token.startswith("##"):
47
+ new_tokens[-1] = new_tokens[-1] + token[2:]
48
+ else:
49
+ new_labels.append(tag_values[label_idx])
50
+ new_tokens.append(token)
51
+
52
+ # Menggabungkan token dan label
53
+ results = []
54
+ for token, label in zip(new_tokens, new_labels):
55
+ # Abaikan token spesial [CLS] dan [SEP]
56
+ if token not in ['[CLS]', '[SEP]']:
57
+ results.append((token, label))
58
+ return results
59
+
60
+ # --- Setup UI Streamlit ---
61
+ st.set_page_config(layout="wide")
62
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
63
+ st.write("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
64
+
65
+ # Muat model
66
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
67
+
68
+ if model:
69
+ # Ambil contoh teks dari notebook Anda
70
+ default_text = """
71
+ Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4.
72
+ Evaluation of transdermal penetration enhancers using a novel skin alternative.
73
+ """
74
+
75
+ # Buat Text Area untuk input pengguna
76
+ user_input = st.text_area("Masukkan teks untuk dianalisis:", default_text, height=150)
77
+
78
+ if st.button("🚀 Analisis Teks"):
79
+ if user_input:
80
+ with st.spinner("Menganalisis..."):
81
+ results = predict(user_input, model, tokenizer, tag_values, device)
82
+
83
+ st.subheader("Hasil Analisis:")
84
+
85
+ # Menampilkan hasil dengan styling
86
+ # (Ini adalah cara sederhana, bisa juga pakai st.dataframe)
87
+
88
+ # Kita buat 2 kolom agar lebih rapi
89
+ col1, col2 = st.columns(2)
90
+
91
+ with col1:
92
+ st.markdown("**Token**")
93
+ for token, label in results:
94
+ st.write(token)
95
+
96
+ with col2:
97
+ st.markdown("**Tag (Entitas)**")
98
+ for token, label in results:
99
+ if label == "O":
100
+ st.write(label)
101
+ else:
102
+ # Beri tanda jika bukan 'O'
103
+ st.success(f"**{label}**")
104
+ else:
105
+ st.warning("Silakan masukkan teks terlebih dahulu.")
106
+ else:
107
+ st.error("Model tidak dapat dimuat. Pastikan folder `ner_bert_model` ada di direktori yang sama dengan `app.py`.")
.history/app_20251026141042.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+
8
+ # Tentukan path ke model yang sudah disimpan
9
+ MODEL_DIR = "./fine_tuned_bert_ner"
10
+
11
+ # --- Fungsi untuk Memuat Model dan Tokenizer ---
12
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
13
+ @st.cache_resource
14
+ def load_model_and_tokenizer(model_dir):
15
+ try:
16
+ model = BertForTokenClassification.from_pretrained(model_dir)
17
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
18
+
19
+ # Muat tag_values
20
+ with open(os.path.join(model_dir, 'tag_values.json'), 'r') as f:
21
+ tag_values = json.load(f)
22
+
23
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
+ model.to(device)
25
+ model.eval() # Set model ke mode evaluasi
26
+
27
+ return model, tokenizer, tag_values, device
28
+ except Exception as e:
29
+ st.error(f"Error saat memuat model: {e}")
30
+ return None, None, None, None
31
+
32
+ # --- Fungsi untuk Prediksi ---
33
+ def predict(text, model, tokenizer, tag_values, device):
34
+ tokenized_sentence = tokenizer.encode(text)
35
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
36
+
37
+ with torch.no_grad():
38
+ output = model(input_ids)
39
+
40
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
41
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
42
+
43
+ # Logika dari sel 36 (menggabungkan token BPE '##')
44
+ new_tokens, new_labels = [], []
45
+ for token, label_idx in zip(tokens, label_indices[0]):
46
+ if token.startswith("##"):
47
+ new_tokens[-1] = new_tokens[-1] + token[2:]
48
+ else:
49
+ new_labels.append(tag_values[label_idx])
50
+ new_tokens.append(token)
51
+
52
+ # Menggabungkan token dan label
53
+ results = []
54
+ for token, label in zip(new_tokens, new_labels):
55
+ # Abaikan token spesial [CLS] dan [SEP]
56
+ if token not in ['[CLS]', '[SEP]']:
57
+ results.append((token, label))
58
+ return results
59
+
60
+ # --- Setup UI Streamlit ---
61
+ st.set_page_config(layout="wide")
62
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
63
+ st.write("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
64
+
65
+ # Muat model
66
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
67
+
68
+ if model:
69
+ # Ambil contoh teks dari notebook Anda
70
+ default_text = """
71
+ Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4.
72
+ Evaluation of transdermal penetration enhancers using a novel skin alternative.
73
+ """
74
+
75
+ # Buat Text Area untuk input pengguna
76
+ user_input = st.text_area("Masukkan teks untuk dianalisis:", default_text, height=150)
77
+
78
+ if st.button("🚀 Analisis Teks"):
79
+ if user_input:
80
+ with st.spinner("Menganalisis..."):
81
+ results = predict(user_input, model, tokenizer, tag_values, device)
82
+
83
+ st.subheader("Hasil Analisis:")
84
+
85
+ # Menampilkan hasil dengan styling
86
+ # (Ini adalah cara sederhana, bisa juga pakai st.dataframe)
87
+
88
+ # Kita buat 2 kolom agar lebih rapi
89
+ col1, col2 = st.columns(2)
90
+
91
+ with col1:
92
+ st.markdown("**Token**")
93
+ for token, label in results:
94
+ st.write(token)
95
+
96
+ with col2:
97
+ st.markdown("**Tag (Entitas)**")
98
+ for token, label in results:
99
+ if label == "O":
100
+ st.write(label)
101
+ else:
102
+ # Beri tanda jika bukan 'O'
103
+ st.success(f"**{label}**")
104
+ else:
105
+ st.warning("Silakan masukkan teks terlebih dahulu.")
106
+ else:
107
+ st.error("Model tidak dapat dimuat. Pastikan folder `ner_bert_model` ada di direktori yang sama dengan `app.py`.")
.history/app_20251026141101.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+
8
+ # Tentukan path ke model yang sudah disimpan
9
+ MODEL_DIR = "./fine_tuned_bert_ner"
10
+
11
+ # --- Fungsi untuk Memuat Model dan Tokenizer ---
12
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
13
+ @st.cache_resource
14
+ def load_model_and_tokenizer(model_dir):
15
+ try:
16
+ model = BertForTokenClassification.from_pretrained(model_dir)
17
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
18
+
19
+ # Muat tag_values
20
+ with open(os.path.join(model_dir, 'tag_values.json'), 'r') as f:
21
+ tag_values = json.load(f)
22
+
23
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
+ model.to(device)
25
+ model.eval() # Set model ke mode evaluasi
26
+
27
+ return model, tokenizer, tag_values, device
28
+ except Exception as e:
29
+ st.error(f"Error saat memuat model: {e}")
30
+ return None, None, None, None
31
+
32
+ # --- Fungsi untuk Prediksi ---
33
+ def predict(text, model, tokenizer, tag_values, device):
34
+ tokenized_sentence = tokenizer.encode(text)
35
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
36
+
37
+ with torch.no_grad():
38
+ output = model(input_ids)
39
+
40
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
41
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
42
+
43
+ # Logika dari sel 36 (menggabungkan token BPE '##')
44
+ new_tokens, new_labels = [], []
45
+ for token, label_idx in zip(tokens, label_indices[0]):
46
+ if token.startswith("##"):
47
+ new_tokens[-1] = new_tokens[-1] + token[2:]
48
+ else:
49
+ new_labels.append(tag_values[label_idx])
50
+ new_tokens.append(token)
51
+
52
+ # Menggabungkan token dan label
53
+ results = []
54
+ for token, label in zip(new_tokens, new_labels):
55
+ # Abaikan token spesial [CLS] dan [SEP]
56
+ if token not in ['[CLS]', '[SEP]']:
57
+ results.append((token, label))
58
+ return results
59
+
60
+ # --- Setup UI Streamlit ---
61
+ st.set_page_config(layout="wide")
62
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
63
+ st.write("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
64
+
65
+ # Muat model
66
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
67
+
68
+ if model:
69
+ # Ambil contoh teks dari notebook Anda
70
+ default_text = """
71
+ Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4.
72
+ Evaluation of transdermal penetration enhancers using a novel skin alternative.
73
+ """
74
+
75
+ # Buat Text Area untuk input pengguna
76
+ user_input = st.text_area("Masukkan teks untuk dianalisis:", default_text, height=150)
77
+
78
+ if st.button("🚀 Analisis Teks"):
79
+ if user_input:
80
+ with st.spinner("Menganalisis..."):
81
+ results = predict(user_input, model, tokenizer, tag_values, device)
82
+
83
+ st.subheader("Hasil Analisis:")
84
+
85
+ # Menampilkan hasil dengan styling
86
+ # (Ini adalah cara sederhana, bisa juga pakai st.dataframe)
87
+
88
+ # Kita buat 2 kolom agar lebih rapi
89
+ col1, col2 = st.columns(2)
90
+
91
+ with col1:
92
+ st.markdown("**Token**")
93
+ for token, label in results:
94
+ st.write(token)
95
+
96
+ with col2:
97
+ st.markdown("**Tag (Entitas)**")
98
+ for token, label in results:
99
+ if label == "O":
100
+ st.write(label)
101
+ else:
102
+ # Beri tanda jika bukan 'O'
103
+ st.success(f"**{label}**")
104
+ else:
105
+ st.warning("Silakan masukkan teks terlebih dahulu.")
106
+ else:
107
+ st.error("Model tidak dapat dimuat. Pastikan folder `ner_bert_model` ada di direktori yang sama dengan `app.py`.")
.history/app_20251026141102.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+
8
+ # Tentukan path ke model yang sudah disimpan
9
+ MODEL_DIR = "./fine_tuned_bert_ner"
10
+
11
+ # --- Fungsi untuk Memuat Model dan Tokenizer ---
12
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
13
+ @st.cache_resource
14
+ def load_model_and_tokenizer(model_dir):
15
+ try:
16
+ model = BertForTokenClassification.from_pretrained(model_dir)
17
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
18
+
19
+ # Muat tag_values
20
+ with open(os.path.join(model_dir, 'tag_values.json'), 'r') as f:
21
+ tag_values = json.load(f)
22
+
23
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
+ model.to(device)
25
+ model.eval() # Set model ke mode evaluasi
26
+
27
+ return model, tokenizer, tag_values, device
28
+ except Exception as e:
29
+ st.error(f"Error saat memuat model: {e}")
30
+ return None, None, None, None
31
+
32
+ # --- Fungsi untuk Prediksi ---
33
+ def predict(text, model, tokenizer, tag_values, device):
34
+ tokenized_sentence = tokenizer.encode(text)
35
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
36
+
37
+ with torch.no_grad():
38
+ output = model(input_ids)
39
+
40
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
41
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
42
+
43
+ # Logika dari sel 36 (menggabungkan token BPE '##')
44
+ new_tokens, new_labels = [], []
45
+ for token, label_idx in zip(tokens, label_indices[0]):
46
+ if token.startswith("##"):
47
+ new_tokens[-1] = new_tokens[-1] + token[2:]
48
+ else:
49
+ new_labels.append(tag_values[label_idx])
50
+ new_tokens.append(token)
51
+
52
+ # Menggabungkan token dan label
53
+ results = []
54
+ for token, label in zip(new_tokens, new_labels):
55
+ # Abaikan token spesial [CLS] dan [SEP]
56
+ if token not in ['[CLS]', '[SEP]']:
57
+ results.append((token, label))
58
+ return results
59
+
60
+ # --- Setup UI Streamlit ---
61
+ st.set_page_config(layout="wide")
62
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
63
+ st.write("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
64
+
65
+ # Muat model
66
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
67
+
68
+ if model:
69
+ # Ambil contoh teks dari notebook Anda
70
+ default_text = """
71
+ Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4.
72
+ Evaluation of transdermal penetration enhancers using a novel skin alternative.
73
+ """
74
+
75
+ # Buat Text Area untuk input pengguna
76
+ user_input = st.text_area("Masukkan teks untuk dianalisis:", default_text, height=150)
77
+
78
+ if st.button("🚀 Analisis Teks"):
79
+ if user_input:
80
+ with st.spinner("Menganalisis..."):
81
+ results = predict(user_input, model, tokenizer, tag_values, device)
82
+
83
+ st.subheader("Hasil Analisis:")
84
+
85
+ # Menampilkan hasil dengan styling
86
+ # (Ini adalah cara sederhana, bisa juga pakai st.dataframe)
87
+
88
+ # Kita buat 2 kolom agar lebih rapi
89
+ col1, col2 = st.columns(2)
90
+
91
+ with col1:
92
+ st.markdown("**Token**")
93
+ for token, label in results:
94
+ st.write(token)
95
+
96
+ with col2:
97
+ st.markdown("**Tag (Entitas)**")
98
+ for token, label in results:
99
+ if label == "O":
100
+ st.write(label)
101
+ else:
102
+ # Beri tanda jika bukan 'O'
103
+ st.success(f"**{label}**")
104
+ else:
105
+ st.warning("Silakan masukkan teks terlebih dahulu.")
106
+ else:
107
+ st.error("Model tidak dapat dimuat. Pastikan folder `ner_bert_model` ada di direktori yang sama dengan `app.py`.")
.history/app_20251026141641.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {"0": "O", "1": "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+ tag_values = [model.config.id2label[str(i)] for i in range(len(model.config.id2label))]
39
+
40
+ # Tentukan device (GPU jika ada, jika tidak CPU)
41
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
42
+ model.to(device)
43
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
44
+
45
+ return model, tokenizer, tag_values, device
46
+
47
+ except Exception as e:
48
+ # Tangani error jika folder model tidak ditemukan
49
+ st.error(f"Error saat memuat model: {e}")
50
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
51
+ return None, None, None, None
52
+
53
+ # --- FUNGSI UNTUK PREDIKSI ---
54
+ def predict(text, model, tokenizer, tag_values, device):
55
+ """
56
+ Melakukan prediksi NER pada teks input.
57
+ """
58
+ # Tokenisasi teks input
59
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
60
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
61
+
62
+ # Lakukan prediksi
63
+ with torch.no_grad():
64
+ output = model(input_ids)
65
+
66
+ # Ambil label dengan skor tertinggi (argmax)
67
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
68
+
69
+ # Ubah ID token kembali menjadi token (kata)
70
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
71
+
72
+ # --- Logika dari Notebook (menggabungkan token '##') ---
73
+ new_tokens, new_labels = [], []
74
+ for token, label_idx in zip(tokens, label_indices[0]):
75
+ # Abaikan token spesial [CLS] dan [SEP]
76
+ if token in ['[CLS]', '[SEP]']:
77
+ continue
78
+
79
+ if token.startswith("##"):
80
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
81
+ if new_tokens:
82
+ new_tokens[-1] = new_tokens[-1] + token[2:]
83
+ else:
84
+ # Jika token utuh, tambahkan token dan labelnya
85
+ new_labels.append(tag_values[label_idx])
86
+ new_tokens.append(token)
87
+
88
+ return list(zip(new_tokens, new_labels))
89
+
90
+ # --- FUNGSI UNTUK TAMPILAN UI ---
91
+ def display_highlighted_text(results):
92
+ """
93
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
94
+ """
95
+ # Definisikan warna untuk entitas.
96
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
97
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
98
+ STYLE = """
99
+ <mark style="
100
+ background-color: #89CFF0;
101
+ padding: 2px 5px;
102
+ margin: 0px 3px;
103
+ border-radius: 5px;
104
+ border: 1px solid #008ECC;
105
+ ">
106
+ {token}
107
+ <sub style="
108
+ font-size: 0.7em;
109
+ opacity: 0.7;
110
+ margin-left: 3px;
111
+ vertical-align: sub;
112
+ ">
113
+ {label}
114
+ </sub>
115
+ </mark>
116
+ """
117
+
118
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
119
+
120
+ for token, label in results:
121
+ if label == "O":
122
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
123
+ html_output += f" {token}"
124
+ else:
125
+ # Jika entitas, tampilkan dengan highlight
126
+ html_output += STYLE.format(token=token, label=label)
127
+
128
+ html_output += "</div>"
129
+ st.markdown(html_output, unsafe_allow_html=True)
130
+
131
+ # --- FUNGSI UTAMA APLIKASI ---
132
+ def main():
133
+ # Konfigurasi halaman
134
+ st.set_page_config(
135
+ page_title="Aplikasi NER Medis",
136
+ page_icon="🧪",
137
+ layout="wide"
138
+ )
139
+
140
+ # --- Header ---
141
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
142
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis (berdasarkan notebook Anda).")
143
+
144
+ # --- Memuat Model ---
145
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
146
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
147
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
148
+
149
+ # Hanya lanjutkan jika model berhasil dimuat
150
+ if model and tokenizer and tag_values and device:
151
+
152
+ st.success("Model berhasil dimuat!")
153
+
154
+ # --- Area Input ---
155
+ st.header("Analisis Teks Anda")
156
+
157
+ # Contoh teks diambil dari notebook Anda
158
+ default_text = (
159
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
160
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
161
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
162
+ )
163
+
164
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
165
+
166
+ if st.button("🚀 Analisis Teks", type="primary"):
167
+ if user_input:
168
+ # Tampilkan spinner saat proses analisis
169
+ with st.spinner("Menganalisis teks..."):
170
+ results = predict(user_input, model, tokenizer, tag_values, device)
171
+
172
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
173
+ display_highlighted_text(results)
174
+
175
+ # --- Tampilkan Data Mentah di dalam Expander ---
176
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
177
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
178
+ entities_only = [res for res in results if res[1] != 'O']
179
+ if entities_only:
180
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
181
+ st.dataframe(df, use_container_width=True)
182
+ else:
183
+ st.info("Tidak ada entitas yang ditemukan.")
184
+ else:
185
+ st.warning("Silakan masukkan teks terlebih dahulu.")
186
+
187
+ # Menjalankan aplikasi
188
+ if __name__ == "__main__":
189
+ main()
.history/app_20251026141642.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {"0": "O", "1": "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+ tag_values = [model.config.id2label[str(i)] for i in range(len(model.config.id2label))]
39
+
40
+ # Tentukan device (GPU jika ada, jika tidak CPU)
41
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
42
+ model.to(device)
43
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
44
+
45
+ return model, tokenizer, tag_values, device
46
+
47
+ except Exception as e:
48
+ # Tangani error jika folder model tidak ditemukan
49
+ st.error(f"Error saat memuat model: {e}")
50
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
51
+ return None, None, None, None
52
+
53
+ # --- FUNGSI UNTUK PREDIKSI ---
54
+ def predict(text, model, tokenizer, tag_values, device):
55
+ """
56
+ Melakukan prediksi NER pada teks input.
57
+ """
58
+ # Tokenisasi teks input
59
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
60
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
61
+
62
+ # Lakukan prediksi
63
+ with torch.no_grad():
64
+ output = model(input_ids)
65
+
66
+ # Ambil label dengan skor tertinggi (argmax)
67
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
68
+
69
+ # Ubah ID token kembali menjadi token (kata)
70
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
71
+
72
+ # --- Logika dari Notebook (menggabungkan token '##') ---
73
+ new_tokens, new_labels = [], []
74
+ for token, label_idx in zip(tokens, label_indices[0]):
75
+ # Abaikan token spesial [CLS] dan [SEP]
76
+ if token in ['[CLS]', '[SEP]']:
77
+ continue
78
+
79
+ if token.startswith("##"):
80
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
81
+ if new_tokens:
82
+ new_tokens[-1] = new_tokens[-1] + token[2:]
83
+ else:
84
+ # Jika token utuh, tambahkan token dan labelnya
85
+ new_labels.append(tag_values[label_idx])
86
+ new_tokens.append(token)
87
+
88
+ return list(zip(new_tokens, new_labels))
89
+
90
+ # --- FUNGSI UNTUK TAMPILAN UI ---
91
+ def display_highlighted_text(results):
92
+ """
93
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
94
+ """
95
+ # Definisikan warna untuk entitas.
96
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
97
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
98
+ STYLE = """
99
+ <mark style="
100
+ background-color: #89CFF0;
101
+ padding: 2px 5px;
102
+ margin: 0px 3px;
103
+ border-radius: 5px;
104
+ border: 1px solid #008ECC;
105
+ ">
106
+ {token}
107
+ <sub style="
108
+ font-size: 0.7em;
109
+ opacity: 0.7;
110
+ margin-left: 3px;
111
+ vertical-align: sub;
112
+ ">
113
+ {label}
114
+ </sub>
115
+ </mark>
116
+ """
117
+
118
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
119
+
120
+ for token, label in results:
121
+ if label == "O":
122
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
123
+ html_output += f" {token}"
124
+ else:
125
+ # Jika entitas, tampilkan dengan highlight
126
+ html_output += STYLE.format(token=token, label=label)
127
+
128
+ html_output += "</div>"
129
+ st.markdown(html_output, unsafe_allow_html=True)
130
+
131
+ # --- FUNGSI UTAMA APLIKASI ---
132
+ def main():
133
+ # Konfigurasi halaman
134
+ st.set_page_config(
135
+ page_title="Aplikasi NER Medis",
136
+ page_icon="🧪",
137
+ layout="wide"
138
+ )
139
+
140
+ # --- Header ---
141
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
142
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis (berdasarkan notebook Anda).")
143
+
144
+ # --- Memuat Model ---
145
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
146
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
147
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
148
+
149
+ # Hanya lanjutkan jika model berhasil dimuat
150
+ if model and tokenizer and tag_values and device:
151
+
152
+ st.success("Model berhasil dimuat!")
153
+
154
+ # --- Area Input ---
155
+ st.header("Analisis Teks Anda")
156
+
157
+ # Contoh teks diambil dari notebook Anda
158
+ default_text = (
159
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
160
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
161
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
162
+ )
163
+
164
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
165
+
166
+ if st.button("🚀 Analisis Teks", type="primary"):
167
+ if user_input:
168
+ # Tampilkan spinner saat proses analisis
169
+ with st.spinner("Menganalisis teks..."):
170
+ results = predict(user_input, model, tokenizer, tag_values, device)
171
+
172
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
173
+ display_highlighted_text(results)
174
+
175
+ # --- Tampilkan Data Mentah di dalam Expander ---
176
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
177
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
178
+ entities_only = [res for res in results if res[1] != 'O']
179
+ if entities_only:
180
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
181
+ st.dataframe(df, use_container_width=True)
182
+ else:
183
+ st.info("Tidak ada entitas yang ditemukan.")
184
+ else:
185
+ st.warning("Silakan masukkan teks terlebih dahulu.")
186
+
187
+ # Menjalankan aplikasi
188
+ if __name__ == "__main__":
189
+ main()
.history/app_20251026141819.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {"0": "O", "1": "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+ tag_values = [model.config.id2label[str(i)] for i in range(len(model.config.id2label))]
39
+
40
+ # Tentukan device (GPU jika ada, jika tidak CPU)
41
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
42
+ model.to(device)
43
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
44
+
45
+ return model, tokenizer, tag_values, device
46
+
47
+ except Exception as e:
48
+ # Tangani error jika folder model tidak ditemukan
49
+ st.error(f"Error saat memuat model: {e}")
50
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
51
+ return None, None, None, None
52
+
53
+ # --- FUNGSI UNTUK PREDIKSI ---
54
+ def predict(text, model, tokenizer, tag_values, device):
55
+ """
56
+ Melakukan prediksi NER pada teks input.
57
+ """
58
+ # Tokenisasi teks input
59
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
60
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
61
+
62
+ # Lakukan prediksi
63
+ with torch.no_grad():
64
+ output = model(input_ids)
65
+
66
+ # Ambil label dengan skor tertinggi (argmax)
67
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
68
+
69
+ # Ubah ID token kembali menjadi token (kata)
70
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
71
+
72
+ # --- Logika dari Notebook (menggabungkan token '##') ---
73
+ new_tokens, new_labels = [], []
74
+ for token, label_idx in zip(tokens, label_indices[0]):
75
+ # Abaikan token spesial [CLS] dan [SEP]
76
+ if token in ['[CLS]', '[SEP]']:
77
+ continue
78
+
79
+ if token.startswith("##"):
80
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
81
+ if new_tokens:
82
+ new_tokens[-1] = new_tokens[-1] + token[2:]
83
+ else:
84
+ # Jika token utuh, tambahkan token dan labelnya
85
+ new_labels.append(tag_values[label_idx])
86
+ new_tokens.append(token)
87
+
88
+ return list(zip(new_tokens, new_labels))
89
+
90
+ # --- FUNGSI UNTUK TAMPILAN UI ---
91
+ def display_highlighted_text(results):
92
+ """
93
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
94
+ """
95
+ # Definisikan warna untuk entitas.
96
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
97
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
98
+ STYLE = """
99
+ <mark style="
100
+ background-color: #89CFF0;
101
+ padding: 2px 5px;
102
+ margin: 0px 3px;
103
+ border-radius: 5px;
104
+ border: 1px solid #008ECC;
105
+ ">
106
+ {token}
107
+ <sub style="
108
+ font-size: 0.7em;
109
+ opacity: 0.7;
110
+ margin-left: 3px;
111
+ vertical-align: sub;
112
+ ">
113
+ {label}
114
+ </sub>
115
+ </mark>
116
+ """
117
+
118
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
119
+
120
+ for token, label in results:
121
+ if label == "O":
122
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
123
+ html_output += f" {token}"
124
+ else:
125
+ # Jika entitas, tampilkan dengan highlight
126
+ html_output += STYLE.format(token=token, label=label)
127
+
128
+ html_output += "</div>"
129
+ st.markdown(html_output, unsafe_allow_html=True)
130
+
131
+ # --- FUNGSI UTAMA APLIKASI ---
132
+ def main():
133
+ # Konfigurasi halaman
134
+ st.set_page_config(
135
+ page_title="Aplikasi NER Medis",
136
+ page_icon="🧪",
137
+ layout="wide"
138
+ )
139
+
140
+ # --- Header ---
141
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
142
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
143
+
144
+ # --- Memuat Model ---
145
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
146
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
147
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
148
+
149
+ # Hanya lanjutkan jika model berhasil dimuat
150
+ if model and tokenizer and tag_values and device:
151
+
152
+ st.success("Model berhasil dimuat!")
153
+
154
+ # --- Area Input ---
155
+ st.header("Analisis Teks Anda")
156
+
157
+ # Contoh teks diambil dari notebook Anda
158
+ default_text = (
159
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
160
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
161
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
162
+ )
163
+
164
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
165
+
166
+ if st.button("🚀 Analisis Teks", type="primary"):
167
+ if user_input:
168
+ # Tampilkan spinner saat proses analisis
169
+ with st.spinner("Menganalisis teks..."):
170
+ results = predict(user_input, model, tokenizer, tag_values, device)
171
+
172
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
173
+ display_highlighted_text(results)
174
+
175
+ # --- Tampilkan Data Mentah di dalam Expander ---
176
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
177
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
178
+ entities_only = [res for res in results if res[1] != 'O']
179
+ if entities_only:
180
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
181
+ st.dataframe(df, use_container_width=True)
182
+ else:
183
+ st.info("Tidak ada entitas yang ditemukan.")
184
+ else:
185
+ st.warning("Silakan masukkan teks terlebih dahulu.")
186
+
187
+ # Menjalankan aplikasi
188
+ if __name__ == "__main__":
189
+ main()
.history/app_20251026141833.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {0: "O", 1: "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+
39
+ # --- INI ADALAH PERBAIKAN UNTUK KeyError: '0' ---
40
+ # Mengubah str(i) menjadi i, karena keys-nya adalah integer
41
+ tag_values = [model.config.id2label[i] for i in range(len(model.config.id2label))]
42
+
43
+ # Tentukan device (GPU jika ada, jika tidak CPU)
44
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
45
+ model.to(device)
46
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
47
+
48
+ return model, tokenizer, tag_values, device
49
+
50
+ except KeyError as e:
51
+ # Tangani KeyError secara spesifik
52
+ st.error(f"Error saat memuat model (KeyError): {e}")
53
+ st.error("Ini biasanya terjadi jika 'id2label' di config.json tidak dimulai dari 0 atau key-nya bukan integer.")
54
+ return None, None, None, None
55
+ except Exception as e:
56
+ # Tangani error umum lainnya
57
+ st.error(f"Error saat memuat model: {e}")
58
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
59
+ return None, None, None, None
60
+
61
+ # --- FUNGSI UNTUK PREDIKSI ---
62
+ def predict(text, model, tokenizer, tag_values, device):
63
+ """
64
+ Melakukan prediksi NER pada teks input.
65
+ """
66
+ # Tokenisasi teks input
67
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
68
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
69
+
70
+ # Lakukan prediksi
71
+ with torch.no_grad():
72
+ output = model(input_ids)
73
+
74
+ # Ambil label dengan skor tertinggi (argmax)
75
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
76
+
77
+ # Ubah ID token kembali menjadi token (kata)
78
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
79
+
80
+ # --- Logika dari Notebook (menggabungkan token '##') ---
81
+ new_tokens, new_labels = [], []
82
+ for token, label_idx in zip(tokens, label_indices[0]):
83
+ # Abaikan token spesial [CLS] dan [SEP]
84
+ if token in ['[CLS]', '[SEP]']:
85
+ continue
86
+
87
+ if token.startswith("##"):
88
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
89
+ if new_tokens:
90
+ new_tokens[-1] = new_tokens[-1] + token[2:]
91
+ else:
92
+ # Jika token utuh, tambahkan token dan labelnya
93
+ new_labels.append(tag_values[label_idx])
94
+ new_tokens.append(token)
95
+
96
+ return list(zip(new_tokens, new_labels))
97
+
98
+ # --- FUNGSI UNTUK TAMPILAN UI ---
99
+ def display_highlighted_text(results):
100
+ """
101
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
102
+ """
103
+ # Definisikan warna untuk entitas.
104
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
105
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
106
+ STYLE = """
107
+ <mark style="
108
+ background-color: #89CFF0;
109
+ padding: 2px 5px;
110
+ margin: 0px 3px;
111
+ border-radius: 5px;
112
+ border: 1px solid #008ECC;
113
+ ">
114
+ {token}
115
+ <sub style="
116
+ font-size: 0.7em;
117
+ opacity: 0.7;
118
+ margin-left: 3px;
119
+ vertical-align: sub;
120
+ ">
121
+ {label}
122
+ </sub>
123
+ </mark>
124
+ """
125
+
126
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
127
+
128
+ for token, label in results:
129
+ if label == "O":
130
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
131
+ html_output += f" {token}"
132
+ else:
133
+ # Jika entitas, tampilkan dengan highlight
134
+ html_output += STYLE.format(token=token, label=label)
135
+
136
+ html_output += "</div>"
137
+ st.markdown(html_output, unsafe_allow_html=True)
138
+
139
+ # --- FUNGSI UTAMA APLIKASI ---
140
+ def main():
141
+ # Konfigurasi halaman
142
+ st.set_page_config(
143
+ page_title="Aplikasi NER Medis",
144
+ page_icon="🧪",
145
+ layout="wide"
146
+ )
147
+
148
+ # --- Header ---
149
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
150
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis (berdasarkan notebook Anda).")
151
+
152
+ # --- Memuat Model ---
153
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
154
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
155
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
156
+
157
+ # Hanya lanjutkan jika model berhasil dimuat
158
+ if model and tokenizer and tag_values and device:
159
+
160
+ st.success("Model berhasil dimuat!")
161
+
162
+ # --- Area Input ---
163
+ st.header("Analisis Teks Anda")
164
+
165
+ # Contoh teks diambil dari notebook Anda
166
+ default_text = (
167
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
168
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
169
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
170
+ )
171
+
172
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
173
+
174
+ if st.button("🚀 Analisis Teks", type="primary"):
175
+ if user_input:
176
+ # Tampilkan spinner saat proses analisis
177
+ with st.spinner("Menganalisis teks..."):
178
+ results = predict(user_input, model, tokenizer, tag_values, device)
179
+
180
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
181
+ display_highlighted_text(results)
182
+
183
+ # --- Tampilkan Data Mentah di dalam Expander ---
184
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
185
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
186
+ entities_only = [res for res in results if res[1] != 'O']
187
+ if entities_only:
188
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
189
+ st.dataframe(df, use_container_width=True)
190
+ else:
191
+ st.info("Tidak ada entitas yang ditemukan.")
192
+ else:
193
+ st.warning("Silakan masukkan teks terlebih dahulu.")
194
+
195
+ # Menjalankan aplikasi
196
+ if __name__ == "__main__":
197
+ main()
198
+
.history/app_20251026141844.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {0: "O", 1: "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+
39
+ # --- INI ADALAH PERBAIKAN UNTUK KeyError: '0' ---
40
+ # Mengubah str(i) menjadi i, karena keys-nya adalah integer
41
+ tag_values = [model.config.id2label[i] for i in range(len(model.config.id2label))]
42
+
43
+ # Tentukan device (GPU jika ada, jika tidak CPU)
44
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
45
+ model.to(device)
46
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
47
+
48
+ return model, tokenizer, tag_values, device
49
+
50
+ except KeyError as e:
51
+ # Tangani KeyError secara spesifik
52
+ st.error(f"Error saat memuat model (KeyError): {e}")
53
+ st.error("Ini biasanya terjadi jika 'id2label' di config.json tidak dimulai dari 0 atau key-nya bukan integer.")
54
+ return None, None, None, None
55
+ except Exception as e:
56
+ # Tangani error umum lainnya
57
+ st.error(f"Error saat memuat model: {e}")
58
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
59
+ return None, None, None, None
60
+
61
+ # --- FUNGSI UNTUK PREDIKSI ---
62
+ def predict(text, model, tokenizer, tag_values, device):
63
+ """
64
+ Melakukan prediksi NER pada teks input.
65
+ """
66
+ # Tokenisasi teks input
67
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
68
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
69
+
70
+ # Lakukan prediksi
71
+ with torch.no_grad():
72
+ output = model(input_ids)
73
+
74
+ # Ambil label dengan skor tertinggi (argmax)
75
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
76
+
77
+ # Ubah ID token kembali menjadi token (kata)
78
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
79
+
80
+ # --- Logika dari Notebook (menggabungkan token '##') ---
81
+ new_tokens, new_labels = [], []
82
+ for token, label_idx in zip(tokens, label_indices[0]):
83
+ # Abaikan token spesial [CLS] dan [SEP]
84
+ if token in ['[CLS]', '[SEP]']:
85
+ continue
86
+
87
+ if token.startswith("##"):
88
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
89
+ if new_tokens:
90
+ new_tokens[-1] = new_tokens[-1] + token[2:]
91
+ else:
92
+ # Jika token utuh, tambahkan token dan labelnya
93
+ new_labels.append(tag_values[label_idx])
94
+ new_tokens.append(token)
95
+
96
+ return list(zip(new_tokens, new_labels))
97
+
98
+ # --- FUNGSI UNTUK TAMPILAN UI ---
99
+ def display_highlighted_text(results):
100
+ """
101
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
102
+ """
103
+ # Definisikan warna untuk entitas.
104
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
105
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
106
+ STYLE = """
107
+ <mark style="
108
+ background-color: #89CFF0;
109
+ padding: 2px 5px;
110
+ margin: 0px 3px;
111
+ border-radius: 5px;
112
+ border: 1px solid #008ECC;
113
+ ">
114
+ {token}
115
+ <sub style="
116
+ font-size: 0.7em;
117
+ opacity: 0.7;
118
+ margin-left: 3px;
119
+ vertical-align: sub;
120
+ ">
121
+ {label}
122
+ </sub>
123
+ </mark>
124
+ """
125
+
126
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
127
+
128
+ for token, label in results:
129
+ if label == "O":
130
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
131
+ html_output += f" {token}"
132
+ else:
133
+ # Jika entitas, tampilkan dengan highlight
134
+ html_output += STYLE.format(token=token, label=label)
135
+
136
+ html_output += "</div>"
137
+ st.markdown(html_output, unsafe_allow_html=True)
138
+
139
+ # --- FUNGSI UTAMA APLIKASI ---
140
+ def main():
141
+ # Konfigurasi halaman
142
+ st.set_page_config(
143
+ page_title="Aplikasi NER Medis",
144
+ page_icon="🧪",
145
+ layout="wide"
146
+ )
147
+
148
+ # --- Header ---
149
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
150
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis.")
151
+
152
+ # --- Memuat Model ---
153
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
154
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
155
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
156
+
157
+ # Hanya lanjutkan jika model berhasil dimuat
158
+ if model and tokenizer and tag_values and device:
159
+
160
+ st.success("Model berhasil dimuat!")
161
+
162
+ # --- Area Input ---
163
+ st.header("Analisis Teks Anda")
164
+
165
+ # Contoh teks diambil dari notebook Anda
166
+ default_text = (
167
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
168
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
169
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
170
+ )
171
+
172
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
173
+
174
+ if st.button("🚀 Analisis Teks", type="primary"):
175
+ if user_input:
176
+ # Tampilkan spinner saat proses analisis
177
+ with st.spinner("Menganalisis teks..."):
178
+ results = predict(user_input, model, tokenizer, tag_values, device)
179
+
180
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
181
+ display_highlighted_text(results)
182
+
183
+ # --- Tampilkan Data Mentah di dalam Expander ---
184
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
185
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
186
+ entities_only = [res for res in results if res[1] != 'O']
187
+ if entities_only:
188
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
189
+ st.dataframe(df, use_container_width=True)
190
+ else:
191
+ st.info("Tidak ada entitas yang ditemukan.")
192
+ else:
193
+ st.warning("Silakan masukkan teks terlebih dahulu.")
194
+
195
+ # Menjalankan aplikasi
196
+ if __name__ == "__main__":
197
+ main()
198
+
.history/app_20251026142055.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import numpy as np
4
+ from transformers import BertTokenizer, BertForTokenClassification
5
+ import json
6
+ import os
7
+ import pandas as pd # Kita tambahkan pandas untuk menampilkan tabel
8
+
9
+ # --- KONFIGURASI ---
10
+ # Pastikan nama folder ini SAMA PERSIS dengan folder model Anda
11
+ MODEL_DIR = "./fine_tuned_bert_ner"
12
+
13
+ # --- FUNGSI UNTUK MEMUAT MODEL (VERSI PERBAIKAN) ---
14
+ # @st.cache_resource akan menyimpan model di cache agar tidak di-load ulang
15
+ # Ini adalah fungsi yang sudah diperbaiki untuk membaca 'id2label' dari config
16
+ @st.cache_resource
17
+ def load_model_and_tokenizer(model_dir):
18
+ """
19
+ Memuat model, tokenizer, dan daftar tag dari direktori yang disimpan.
20
+ """
21
+ try:
22
+ # Muat model dan tokenizer
23
+ model = BertForTokenClassification.from_pretrained(model_dir)
24
+ tokenizer = BertTokenizer.from_pretrained(model_dir)
25
+
26
+ # --- PERBAIKAN DARI ERROR SEBELUMNYA ---
27
+ # Kita tidak lagi mencari 'tag_values.json'.
28
+ # Sebagai gantinya, kita membaca 'id2label' dari file config.json model.
29
+ # Ini dimuat secara otomatis ke dalam 'model.config'
30
+
31
+ if not hasattr(model.config, 'id2label'):
32
+ st.error("Error: 'id2label' tidak ditemukan di dalam config.json model.")
33
+ return None, None, None, None
34
+
35
+ # model.config.id2label adalah dictionary: {0: "O", 1: "B-indications", ...}
36
+ # Kita ubah menjadi list: ["O", "B-indications", ...]
37
+ # Ini penting agar kita bisa mapping output (angka) kembali ke label (teks)
38
+
39
+ # --- INI ADALAH PERBAIKAN UNTUK KeyError: '0' ---
40
+ # Mengubah str(i) menjadi i, karena keys-nya adalah integer
41
+ tag_values = [model.config.id2label[i] for i in range(len(model.config.id2label))]
42
+
43
+ # Tentukan device (GPU jika ada, jika tidak CPU)
44
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
45
+ model.to(device)
46
+ model.eval() # Set model ke mode evaluasi (penting untuk prediksi)
47
+
48
+ return model, tokenizer, tag_values, device
49
+
50
+ except KeyError as e:
51
+ # Tangani KeyError secara spesifik
52
+ st.error(f"Error saat memuat model (KeyError): {e}")
53
+ st.error("Ini biasanya terjadi jika 'id2label' di config.json tidak dimulai dari 0 atau key-nya bukan integer.")
54
+ return None, None, None, None
55
+ except Exception as e:
56
+ # Tangani error umum lainnya
57
+ st.error(f"Error saat memuat model: {e}")
58
+ st.error(f"Pastikan folder '{model_dir}' ada di direktori yang sama dengan app.py")
59
+ return None, None, None, None
60
+
61
+ # --- FUNGSI UNTUK PREDIKSI ---
62
+ def predict(text, model, tokenizer, tag_values, device):
63
+ """
64
+ Melakukan prediksi NER pada teks input.
65
+ """
66
+ # Tokenisasi teks input
67
+ tokenized_sentence = tokenizer.encode(text, truncation=True, max_length=512)
68
+ input_ids = torch.tensor([tokenized_sentence]).to(device)
69
+
70
+ # Lakukan prediksi
71
+ with torch.no_grad():
72
+ output = model(input_ids)
73
+
74
+ # Ambil label dengan skor tertinggi (argmax)
75
+ label_indices = np.argmax(output[0].to('cpu').numpy(), axis=2)
76
+
77
+ # Ubah ID token kembali menjadi token (kata)
78
+ tokens = tokenizer.convert_ids_to_tokens(input_ids.to('cpu').numpy()[0])
79
+
80
+ # --- Logika dari Notebook (menggabungkan token '##') ---
81
+ new_tokens, new_labels = [], []
82
+ for token, label_idx in zip(tokens, label_indices[0]):
83
+ # Abaikan token spesial [CLS] dan [SEP]
84
+ if token in ['[CLS]', '[SEP]']:
85
+ continue
86
+
87
+ if token.startswith("##"):
88
+ # Jika token adalah BPE (sub-word), gabungkan dengan token sebelumnya
89
+ if new_tokens:
90
+ new_tokens[-1] = new_tokens[-1] + token[2:]
91
+ else:
92
+ # Jika token utuh, tambahkan token dan labelnya
93
+ new_labels.append(tag_values[label_idx])
94
+ new_tokens.append(token)
95
+
96
+ return list(zip(new_tokens, new_labels))
97
+
98
+ # --- FUNGSI UNTUK TAMPILAN UI ---
99
+ def display_highlighted_text(results):
100
+ """
101
+ Menampilkan hasil sebagai teks yang di-highlight (UI Menarik)
102
+ """
103
+ # Definisikan warna untuk entitas.
104
+ # Anda bisa tambahkan jika punya banyak tipe entitas.
105
+ # Di sini kita buat simpel: semua entitas akan berwarna biru muda.
106
+ STYLE = """
107
+ <mark style="
108
+ background-color: #89CFF0;
109
+ padding: 2px 5px;
110
+ margin: 0px 3px;
111
+ border-radius: 5px;
112
+ border: 1px solid #008ECC;
113
+ ">
114
+ {token}
115
+ <sub style="
116
+ font-size: 0.7em;
117
+ opacity: 0.7;
118
+ margin-left: 3px;
119
+ vertical-align: sub;
120
+ ">
121
+ {label}
122
+ </sub>
123
+ </mark>
124
+ """
125
+
126
+ html_output = '<div style="font-size: 1.1em; line-height: 2.0;">'
127
+
128
+ for token, label in results:
129
+ if label == "O":
130
+ # Jika 'O' (Outside), tampilkan sebagai teks biasa
131
+ html_output += f" {token}"
132
+ else:
133
+ # Jika entitas, tampilkan dengan highlight
134
+ html_output += STYLE.format(token=token, label=label)
135
+
136
+ html_output += "</div>"
137
+
138
+ # --- INI ADALAH PERBAIKANNYA ---
139
+ # Tambahkan unsafe_allow_html=True agar Streamlit merender HTML-nya
140
+ st.markdown(html_output, unsafe_allow_html=True)
141
+
142
+ # --- FUNGSI UTAMA APLIKASI ---
143
+ def main():
144
+ # Konfigurasi halaman
145
+ st.set_page_config(
146
+ page_title="Aplikasi NER Medis",
147
+ page_icon="🧪",
148
+ layout="wide"
149
+ )
150
+
151
+ # --- Header ---
152
+ st.title("🧪 Aplikasi Named Entity Recognition (NER) dengan BERT")
153
+ st.markdown("Aplikasi ini menggunakan model BERT yang di-fine-tune untuk mengenali entitas dari teks medis (berdasarkan notebook Anda).")
154
+
155
+ # --- Memuat Model ---
156
+ # Gunakan st.spinner agar terlihat loading saat model dimuat
157
+ with st.spinner("Memuat model... Ini mungkin perlu beberapa saat..."):
158
+ model, tokenizer, tag_values, device = load_model_and_tokenizer(MODEL_DIR)
159
+
160
+ # Hanya lanjutkan jika model berhasil dimuat
161
+ if model and tokenizer and tag_values and device:
162
+
163
+ st.success("Model berhasil dimuat!")
164
+
165
+ # --- Area Input ---
166
+ st.header("Analisis Teks Anda")
167
+
168
+ # Contoh teks diambil dari notebook Anda
169
+ default_text = (
170
+ "Pasteurellosis in japanese quail (Coturnix coturnix japonica) caused by Pasteurella multocida multocida A:4. \n\n"
171
+ "Evaluation of transdermal penetration enhancers using a novel skin alternative. \n\n"
172
+ "A novel alternative to animal skin models was developed in order to aid in the screening of transdermal penetration enhancer."
173
+ )
174
+
175
+ user_input = st.text_area("Masukkan teks untuk dianalisis di sini:", default_text, height=150)
176
+
177
+ if st.button("🚀 Analisis Teks", type="primary"):
178
+ if user_input:
179
+ # Tampilkan spinner saat proses analisis
180
+ with st.spinner("Menganalisis teks..."):
181
+ results = predict(user_input, model, tokenizer, tag_values, device)
182
+
183
+ st.subheader("Hasil Analisis (Teks dengan Highlight)")
184
+ display_highlighted_text(results)
185
+
186
+ # --- Tampilkan Data Mentah di dalam Expander ---
187
+ with st.expander("Lihat Data Mentah (Token & Tag)"):
188
+ # Filter hanya token yang BUKAN 'O' untuk data mentah
189
+ entities_only = [res for res in results if res[1] != 'O']
190
+ if entities_only:
191
+ df = pd.DataFrame(entities_only, columns=["Token", "Tag"])
192
+ st.dataframe(df, use_container_width=True)
193
+ else:
194
+ st.info("Tidak ada entitas yang ditemukan.")
195
+ else:
196
+ st.warning("Silakan masukkan teks terlebih dahulu.")
197
+
198
+ # Menjalankan aplikasi
199
+ if __name__ == "__main__":
200
+ main()
201
+