File size: 6,527 Bytes
246325a
 
 
 
 
d40654a
 
246325a
 
 
 
d40654a
246325a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d40654a
 
246325a
d40654a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246325a
 
d40654a
246325a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d40654a
246325a
 
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
# این فایل app.py در Hugging Face Space شما قرار می گیرد
# این کد شامل:
# - بارگذاری مدل Sentence Transformer پارسی 'heydariAI/persian-embeddings'
# - تعریف اپلیکیشن Flask
# - اندپوینت /get_embedding برای دریافت سوال و ارسال بردار آن
# - **سرویس دهی فایل index.html به عنوان صفحه اصلی**
# - **سرویس دهی سایر فایل های ایستا (js, css, json)**
# - لاگ گیری برای عیب یابی در لاگ های Space و یک فایل جداگانه
# - مدیریت خطاهای اولیه در بارگذاری مدل و پردازش درخواست ها

from sentence_transformers import SentenceTransformer
from flask import Flask, request, jsonify, send_from_directory # <--- اضافه کردن send_from_directory
import numpy as np
import logging
import os
# import torch # اگر از GPU استفاده می کنید و torch نصب کرده اید، این خط را فعال نگه دارید.

# تنظیمات اولیه لاگینگ برای نمایش در لاگ های استاندارد Space
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# مسیر فایل لاگ جداگانه در فضای Hugging Face (برای عیب یابی بیشتر)
log_file_path = "app_log.txt"

# تابع برای افزودن پیام به فایل لاگ
def log_message(message):
    try:
        with open(log_file_path, "a", encoding="utf-8") as f:
            f.write(message + "\n")
    except Exception as e:
        logging.error(f"Error writing to log file {log_file_path}: {e}")

# ****** نام مدل Sentence Transformer که می خواهیم در این سرور استفاده کنیم ******
# این مدل برای Space جدید: heydariAI/persian-embeddings
model_name_to_load = 'heydariAI/persian-embeddings'
# ***************************************************************************


# ****** بارگذاری مدل Sentence Transformer در هنگام راه اندازی سرور ******
logging.info(f"Attempting to load Sentence Transformer model: {model_name_to_load}...")
log_message(f"Attempting to load Sentence Transformer model: {model_name_to_load}...")

try:
    # بارگذاری مدل. اگر GPU دارید و torch نصب شده، می توانید device='cuda' را اضافه کنید.
    model = SentenceTransformer(model_name_to_load)

    # ****** افزودن لاگ تأیید پس از بارگذاری موفق مدل ******
    logging.info(f"SUCCESS: Model '{model_name_to_load}' loaded successfully.")
    log_message(f"SUCCESS: Model '{model_name_to_load}' loaded successfully.")
    # ******************************************************

except Exception as e:
    # ****** مدیریت خطا در صورت عدم بارگذاری مدل ******
    error_msg = f"ERROR: Failed to load model {model_name_to_load}: {e}"
    logging.error(error_msg)
    log_message(error_msg)
    model = None
    # *************************************************


# تعریف اپلیکیشن Flask
app = Flask(__name__)

# ****** اضافه کردن روت برای سرویس دهی فایل index.html به عنوان صفحه اصلی ******
# این روت وقتی کاربر به آدرس اصلی Space مراجعه می کند (/) اجرا می شود
@app.route('/')
def serve_index():
    # فرض می کنیم index.html در ریشه دایرکتوری کاری اپلیکیشن (app/) قرار دارد
    # send_from_directory فایل را از دایرکتوری مشخص شده ('.') ارسال می کند
    return send_from_directory('.', 'index.html')

# ****** اضافه کردن روت برای سرویس دهی سایر فایل های ایستا ******
# این روت برای سرویس دهی فایل هایی مانند style.css, script.js, و فایل های JSON استفاده می شود.
# این روت هر فایلی که در ریشه اپلیکیشن قرار دارد و نام آن با روت های تعریف شده مطابقت ندارد را سرویس می دهد.
# <path:filename> یک متغیر مسیر است که شامل نام فایل و هر زیرپوشه ای است.
@app.route('/<path:filename>')
def serve_static(filename):
     # اطمینان حاصل کنید که فایل در دایرکتوری کاری اپلیکیشن وجود دارد
     # از send_from_directory برای جلوگیری از مشکلات امنیتی استفاده کنید.
    logging.info(f"Attempting to serve static file: {filename}")
    try:
        return send_from_directory('.', filename)
    except FileNotFoundError:
        logging.error(f"Static file not found: {filename}")
        return "File not found", 404 # برگرداندن خطای 404 اگر فایل پیدا نشد


# ****** اندپوینت اصلی برای دریافت بردار (embedding) سوال (همانند قبل) ******
@app.route('/get_embedding', methods=['POST'])
def get_embedding():
    if model is None:
        error_msg = "Model is not loaded on the server due to a previous error. Check Space logs."
        log_message(f"Received request but model is not loaded: {error_msg}")
        return jsonify({"error": error_msg}), 500

    try:
        data = request.get_json()
        query = data.get('query')

        if not query or not isinstance(query, str) or not query.strip():
            log_message(f"Received invalid or empty query in /get_embedding: {data}")
            return jsonify({"error": "Invalid or empty query text provided"}), 400

        log_message(f"Received query in /get_embedding: '{query}'")
        logging.info(f"Processing query in /get_embedding: '{query[:50]}...'")

        embedding = model.encode(query, convert_to_numpy=True, pooling_mode='mean', normalize=True)

        embedding_list = embedding.tolist()

        log_message(f"Successfully generated embedding for query in /get_embedding.")

        return jsonify({"embedding": embedding_list}), 200

    except Exception as e:
        error_message = f"An error occurred during embedding generation in /get_embedding: {e}"
        logging.error(error_message)
        log_message(error_message)
        return jsonify({"error": error_message}), 500

# این بخش معمولاً در محیط Hugging Face Space توسط Gunicorn مدیریت می شود.
# if __name__ == '__main__':
#     app.run(host='0.0.0.0', port=7860, debug=False)