File size: 5,412 Bytes
0d7a9c0
0490e30
b0cb70a
bca7346
b0cb70a
 
 
 
 
609e909
0d7a9c0
 
 
 
0490e30
0d7a9c0
 
 
 
 
 
 
 
 
 
 
 
b0cb70a
0d7a9c0
 
 
b0cb70a
0d7a9c0
 
 
b0cb70a
0d7a9c0
 
 
 
 
 
b0cb70a
 
bca7346
b0cb70a
 
 
 
 
 
0d7a9c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0cb70a
0d7a9c0
 
 
 
b0cb70a
0d7a9c0
 
 
b0cb70a
0d7a9c0
 
 
 
 
b0cb70a
0d7a9c0
 
 
 
b0cb70a
0d7a9c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd64212
0d7a9c0
 
 
b0cb70a
0d7a9c0
 
 
 
 
 
 
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
from flask import Flask, request, jsonify
from flask_cors import CORS
import logging
from pyvi import ViTokenizer

# Cấu hình logging cho app
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

from model import predict_sentiment_3sentiment, predict_sentiment_5sentiment
import pandas as pd

# Khởi tạo Flask app
app = Flask(__name__)
CORS(app)

# Xử lý encoding cho tiếng Việt để hiển thị đúng trong response
app.config['JSON_AS_ASCII'] = False

@app.route("/predict", methods=['POST'])
def predict():
    """
    Dự đoán cảm xúc từ văn bản đầu vào.
    Request body phải là JSON có dạng: {"text": "nội dung bình luận"}
    """
    # Lấy dữ liệu JSON từ request
    json_data = request.get_json()
    logger.info(f"Received predict request: {json_data}")

    # Kiểm tra xem key 'text' có tồn tại và không rỗng không
    if not json_data or 'text' not in json_data or not json_data.get('text', '').strip():
        logger.warning("Missing 'text' in request")
        return jsonify({"error": "Vui lòng cung cấp trường 'text' trong request body."}), 400
    # Kiểm tra xem key 'type' có tồn tại và không rỗng không
    if not json_data or 'type' not in json_data or not json_data.get('type', '').strip():
        logger.warning("Missing 'type' in request")
        return jsonify({"error": "Vui lòng cung cấp trường 'type' trong request body."}), 400
    
    # Lấy văn bản từ dữ liệu
    text_to_predict = json_data['text']
    sentiment_type = json_data['type']
    # Gọi hàm dự đoán từ model
    try:
        if sentiment_type == "3sentiment":
            text_to_predict = ViTokenizer.tokenize(text_to_predict)
            sentiment, score = predict_sentiment_3sentiment(text_to_predict)
        elif sentiment_type == "5sentiment":
            sentiment, score = predict_sentiment_5sentiment(text_to_predict)
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        return jsonify({"error": str(e)}), 500

    # Tạo response
    response = {
        "comment": text_to_predict,
        "sentiment": sentiment,
        "confidence": score
    }

    return jsonify(response)

@app.route("/")
def read_root():
    return jsonify({"message": "Chào mừng đến với API Phân tích Cảm xúc sử dụng Flask!"})

@app.route("/predict-batch", methods=['POST'])
def predict_batch():
    """
    Dự đoán cảm xúc cho một loạt bình luận từ file Excel.
    File Excel phải được gửi dưới dạng form-data với key là 'file'.
    Cột đầu tiên của file Excel sẽ được sử dụng làm cột chứa bình luận.
    """
    # 1. Kiểm tra xem có file trong request không
    if 'file' not in request.files:
        logger.warning("No file part in request")
        return jsonify({"error": "Không tìm thấy file trong request (key phải là 'file')."}), 400

    # Dữ liệu form đi kèm với file sẽ nằm trong request.form
    sentiment_type = request.form.get('type')
    logger.info(f"Received batch predict request for type: {sentiment_type}")

    # Kiểm tra xem key 'type' có tồn tại và không rỗng không
    if not sentiment_type or sentiment_type.strip() not in ["3sentiment", "5sentiment"]:
        logger.warning("Invalid or missing 'type'")
        return jsonify({"error": "Vui lòng cung cấp trường 'type' (3sentiment hoặc 5sentiment) trong form data."}), 400
    file = request.files['file']

    # 2. Kiểm tra xem người dùng có chọn file không
    if file.filename == '':
        logger.warning("No selected file")
        return jsonify({"error": "Chưa chọn file nào."}), 400

    # 3. Kiểm tra định dạng file
    if not file.filename.endswith(('.xlsx', '.xls')):
        logger.warning(f"Invalid file format: {file.filename}")
        return jsonify({"error": "Định dạng file không hợp lệ. Vui lòng sử dụng file .xlsx hoặc .xls."}), 400

    try:
        # 4. Đọc file Excel bằng pandas, sử dụng engine openpyxl
        df = pd.read_excel(file, engine='openpyxl')

        if df.empty:
            return jsonify({"error": "File Excel rỗng."}), 400

        # Lấy tên cột đầu tiên để xử lý
        comments_column = df.columns[0]
        
        results = []
        # 5. Lặp qua từng bình luận (bỏ qua các dòng rỗng) để dự đoán
        for comment in df[comments_column].dropna().astype(str):
            if sentiment_type == "3sentiment":
                sentiment, score = predict_sentiment_3sentiment(comment)
            elif sentiment_type == "5sentiment":
                sentiment, score = predict_sentiment_5sentiment(comment)
            results.append({"comment": comment, "sentiment": sentiment, "confidence": f"{score:.2%}"})
        
        return jsonify(results)
    except Exception as e:
        logger.error(f"Error processing batch file: {e}")
        return jsonify({"error": f"Đã xảy ra lỗi khi xử lý file: {str(e)}"}), 500

if __name__ == "__main__":
    # Chạy app ở chế độ debug để tự động reload khi có thay đổi
    # host='0.0.0.0' để có thể truy cập từ bên ngoài network
    # Lưu ý: Không sử dụng debug=True trong môi trường production
    app.run(host="0.0.0.0", port=8000, debug=True)