Spaces:
Sleeping
Sleeping
VampeeHuntee
commited on
Commit
•
cb1f9b3
1
Parent(s):
ba8ed63
first commit
Browse files- .env +3 -0
- .gitignore +3 -0
- Dockerfile +22 -0
- app.py +26 -0
- modules/model.py +56 -0
- requirements.txt +7 -0
- static/style.css +81 -0
- templates/base.html +25 -0
- templates/demo.html +31 -0
.env
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
MODEL_NAME = "VampeeHuntee/xlm-roberta-base_baseline_syllables"
|
2 |
+
|
3 |
+
SAMPLE_TEXT = "Từ 24 - 7 đến 31 - 7 , bệnh nhân được mẹ là bà H.T.P ( 47 tuổi ) đón về nhà ở phường Phước Hoà ( bằng xe máy ) , không đi đâu chỉ ra Tạp hoá Phượng , chợ Vườn Lài , phường An Sơn cùng mẹ bán tạp hoá ở đây ."
|
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
.vscode
|
3 |
+
test.ipynb
|
Dockerfile
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
# read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
3 |
+
# you will also find guides on how best to write your Dockerfile
|
4 |
+
|
5 |
+
FROM python:3.9.12
|
6 |
+
|
7 |
+
# The two following lines are requirements for the Dev Mode to be functional
|
8 |
+
# Learn more about the Dev Mode at https://huggingface.co/dev-mode-explorers
|
9 |
+
RUN useradd -m -u 1000 user
|
10 |
+
WORKDIR /app
|
11 |
+
|
12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
13 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
14 |
+
|
15 |
+
COPY --chown=user . /app
|
16 |
+
|
17 |
+
USER user
|
18 |
+
|
19 |
+
ENV HOME=/home/user \
|
20 |
+
PATH=/home/user/.local/bin:$PATH
|
21 |
+
|
22 |
+
CMD ["gunicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from flask import Flask
|
3 |
+
from flask import jsonify
|
4 |
+
from flask import render_template
|
5 |
+
from flask import request
|
6 |
+
|
7 |
+
from modules.model import inference
|
8 |
+
|
9 |
+
app = Flask(__name__)
|
10 |
+
|
11 |
+
# app_dir = os.path.dirname(os.path.abspath(__file__))
|
12 |
+
|
13 |
+
@app.route("/", defaults={"js": "demo"})
|
14 |
+
def index(js):
|
15 |
+
return render_template(f"{js}.html", js=js)
|
16 |
+
|
17 |
+
@app.route("/predict", methods=["POST"])
|
18 |
+
def predict():
|
19 |
+
sample = os.getenv('SAMPLE_TEXT')
|
20 |
+
text = request.form.get('text', sample, type=str)
|
21 |
+
text = sample if text == "" else text
|
22 |
+
return jsonify(result=inference(text))
|
23 |
+
|
24 |
+
if __name__ == "__main__":
|
25 |
+
app.run(debug = True)
|
26 |
+
|
modules/model.py
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from transformers import AutoTokenizer, AutoModelForTokenClassification
|
3 |
+
from seqeval.metrics.sequence_labeling import get_entities
|
4 |
+
|
5 |
+
tokenizer = AutoTokenizer.from_pretrained("VampeeHuntee/xlm-roberta-base_baseline_syllables", use_fast = False)
|
6 |
+
model = AutoModelForTokenClassification.from_pretrained("VampeeHuntee/xlm-roberta-base_baseline_syllables")
|
7 |
+
|
8 |
+
def get_words(tokens:list[str]):
|
9 |
+
return tokenizer.convert_tokens_to_string(tokens)
|
10 |
+
|
11 |
+
def format_result(tokens:list[str], labels:list[str]):
|
12 |
+
"""Định dạng kết quả NER thành HTML với các thực thể được đánh dấu."""
|
13 |
+
|
14 |
+
formatted_output = ""
|
15 |
+
current_position = 0
|
16 |
+
start = 0
|
17 |
+
end = 0
|
18 |
+
EntitySpan = '<span class="entity" data-entity="{label}">{word} <span class="entity" label-entity="{label}">{label}</span></span>'
|
19 |
+
|
20 |
+
for label, start, end in get_entities(labels):
|
21 |
+
|
22 |
+
end += 1
|
23 |
+
|
24 |
+
entity = {
|
25 |
+
'word':get_words(tokens[start:end]),
|
26 |
+
'label':label
|
27 |
+
}
|
28 |
+
|
29 |
+
# Thêm phần văn bản trước thực thể (nếu có)
|
30 |
+
if start > current_position:
|
31 |
+
formatted_output += get_words(tokens[current_position: start])
|
32 |
+
|
33 |
+
# Thêm thực thể với thẻ span và nhãn
|
34 |
+
formatted_output += EntitySpan.format(**entity)
|
35 |
+
|
36 |
+
# Cập nhật vị trí hiện tại
|
37 |
+
current_position = end
|
38 |
+
|
39 |
+
# Thêm phần văn bản còn lại sau thực thể cuối cùng (nếu có)
|
40 |
+
if current_position < len(tokens):
|
41 |
+
formatted_output += get_words(tokens[current_position:])
|
42 |
+
|
43 |
+
return formatted_output
|
44 |
+
|
45 |
+
def inference(text:str):
|
46 |
+
|
47 |
+
inputs = tokenizer(text, return_tensors="pt",add_special_tokens=False)
|
48 |
+
|
49 |
+
with torch.no_grad():
|
50 |
+
logits = model(**inputs).logits
|
51 |
+
predictions = torch.argmax(logits, dim=2)
|
52 |
+
labels = [model.config.id2label[t.item()] for t in predictions[0]]
|
53 |
+
|
54 |
+
tokens = [t.detach().numpy() for t in inputs['input_ids']]
|
55 |
+
tokens = tokenizer.convert_ids_to_tokens(tokens[0])
|
56 |
+
return format_result(tokens, labels)
|
requirements.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
-f https://download.pytorch.org/whl/torch_stable.html
|
2 |
+
torch==2.3.0+cpu
|
3 |
+
transformers==4.38.0
|
4 |
+
gunicorn
|
5 |
+
Flask
|
6 |
+
# dynoscale
|
7 |
+
|
static/style.css
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Các kiểu dáng khác */
|
2 |
+
body {
|
3 |
+
font-family: sans-serif;
|
4 |
+
text-align: center; /* Căn giữa nội dung */
|
5 |
+
}
|
6 |
+
|
7 |
+
textarea {
|
8 |
+
width: 80%;
|
9 |
+
height: 150px;
|
10 |
+
margin: 20px auto; /* Căn giữa textarea */
|
11 |
+
padding: 10px;
|
12 |
+
resize: vertical; /* Cho phép thay đổi kích thước theo chiều dọc */
|
13 |
+
}
|
14 |
+
|
15 |
+
button {
|
16 |
+
padding: 20px 70px;
|
17 |
+
background-color: #007bff; /* Màu xanh dương */
|
18 |
+
color: white;
|
19 |
+
border: none;
|
20 |
+
cursor: pointer;
|
21 |
+
border-radius: 5px; /* Bo góc */
|
22 |
+
}
|
23 |
+
|
24 |
+
#output {
|
25 |
+
margin-top: 20px;
|
26 |
+
padding: 10px;
|
27 |
+
border: 1px solid #ccc;
|
28 |
+
width: 80%;
|
29 |
+
margin: 20px auto; /* Căn giữa div kết quả */
|
30 |
+
text-align: left; /* Căn trái văn bản kết quả */
|
31 |
+
white-space: pre-line; /* Giữ nguyên định dạng xuống dòng */
|
32 |
+
}
|
33 |
+
|
34 |
+
/* Kiểu cho các thực thể được nhận diện */
|
35 |
+
[data-entity] {
|
36 |
+
padding: 5px 10px;
|
37 |
+
border-radius: 5px;
|
38 |
+
display: inline-block;
|
39 |
+
}
|
40 |
+
|
41 |
+
[label-entity] {
|
42 |
+
font-size: x-small;
|
43 |
+
padding: 2px 4px;
|
44 |
+
border-radius: 5px;
|
45 |
+
display: inline-block;
|
46 |
+
color: white;
|
47 |
+
}
|
48 |
+
|
49 |
+
/* Màu sắc cho từng loại thực thể */
|
50 |
+
[data-entity="PATIENT_ID"] { background-color: #85cef0; }
|
51 |
+
[label-entity="PATIENT_ID"] { background-color: #01579B; }
|
52 |
+
|
53 |
+
[data-entity="NAME"] { background-color: #ee7fa4 ; }
|
54 |
+
[label-entity="NAME"] { background-color: #C2185B ; }
|
55 |
+
|
56 |
+
[data-entity="GENDER"] { background-color: #ec9f78 ; }
|
57 |
+
[label-entity="GENDER"] { background-color: #4E342E ; }
|
58 |
+
|
59 |
+
[data-entity="AGE"] { background-color: #f7d978 ; }
|
60 |
+
[label-entity="AGE"] { background-color: #F57F17 ; }
|
61 |
+
|
62 |
+
[data-entity="JOB"] { background-color: #e06ff1 ; }
|
63 |
+
[label-entity="JOB"] { background-color: #6A1B9A ; }
|
64 |
+
|
65 |
+
[data-entity="LOCATION"] { background-color: #58fc66 ; }
|
66 |
+
[label-entity="LOCATION"] { background-color: #1B5E20 ; }
|
67 |
+
|
68 |
+
[data-entity="ORGANIZATION"] { background-color: #f17070 ; }
|
69 |
+
[label-entity="ORGANIZATION"] { background-color: #424242 ; }
|
70 |
+
|
71 |
+
[data-entity="DATE"] { background-color: #f3b552 ; }
|
72 |
+
[label-entity="DATE"] { background-color: #E65100 ; }
|
73 |
+
|
74 |
+
[data-entity="SYMPTOM_AND_DISEASE"] { background-color: #66e9e2 ; }
|
75 |
+
[label-entity="SYMPTOM_AND_DISEASE"] { background-color: #006064 ; }
|
76 |
+
|
77 |
+
[data-entity="TRANSPORTATION"] { background-color: #f06758 ; }
|
78 |
+
[label-entity="TRANSPORTATION"] { background-color: #B71C1C ; }
|
79 |
+
|
80 |
+
/*type_entities = ['PATIENT_ID', 'NAME', 'GENDER', 'AGE', 'JOB', 'LOCATION',
|
81 |
+
'ORGANIZATION', 'DATE', 'SYMPTOM_AND_DISEASE', 'TRANSPORTATION']*/
|
templates/base.html
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html>
|
3 |
+
|
4 |
+
<head>
|
5 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
6 |
+
<link rel="icon" href="data:,">
|
7 |
+
<title>Phân loại thực thể</title>
|
8 |
+
</head>
|
9 |
+
|
10 |
+
<body>
|
11 |
+
<p>{% block intro %}{% endblock %}</p>
|
12 |
+
<h1>{% block title %}{% endblock %}</h1>
|
13 |
+
|
14 |
+
<form method="POST", id="input">
|
15 |
+
<textarea name="text" placeholder="Nhập văn bản:"></textarea>
|
16 |
+
<button type="submit">Trích xuất thực thể</button>
|
17 |
+
</form>
|
18 |
+
|
19 |
+
<div id="output"></div>
|
20 |
+
|
21 |
+
{% block script %}{% endblock %}
|
22 |
+
|
23 |
+
</body>
|
24 |
+
|
25 |
+
</html>
|
templates/demo.html
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'base.html' %}
|
2 |
+
|
3 |
+
{% block intro %}
|
4 |
+
<a href="https://huggingface.co/VampeeHuntee"><code>VampireHuntee</code></a>
|
5 |
+
Đây là nơi để các mô hình trong khóa luận tốt nghiệp, bạn có thể sử dụng các mô hình public để thử.
|
6 |
+
{% endblock %}
|
7 |
+
|
8 |
+
{% block title %}
|
9 |
+
Phân loại thực thể
|
10 |
+
{% endblock %}
|
11 |
+
|
12 |
+
{% block script %}
|
13 |
+
<script>
|
14 |
+
function predictSubmit(ev) {
|
15 |
+
ev.preventDefault();
|
16 |
+
var request = new XMLHttpRequest();
|
17 |
+
request.addEventListener('load', resultShow);
|
18 |
+
request.open('POST',"{{ url_for('predict') }}");
|
19 |
+
request.send(new FormData(this));
|
20 |
+
}
|
21 |
+
|
22 |
+
function resultShow() {
|
23 |
+
var data = JSON.parse(this.responseText);
|
24 |
+
var output = document.getElementById('output');
|
25 |
+
output.innerHTML = data.result;
|
26 |
+
}
|
27 |
+
|
28 |
+
var form = document.getElementById('input');
|
29 |
+
form.addEventListener('submit', predictSubmit);
|
30 |
+
</script>
|
31 |
+
{% endblock %}
|