khatere_khan / server.py
montaghem630's picture
Update server.py
e2f88c4 verified
# این فایل server.py در Hugging Face Space شما قرار می گیرد
# این کد شامل:
# - بارگذاری مدل Sentence Transformer پارسی 'PartAI/Tooka-SBERT'
# - تعریف اپلیکیشن Flask
# - اندپوینت /get_embedding برای دریافت سوال و ارسال بردار آن
# - لاگ گیری برای عیب یابی در لاگ های Space و یک فایل جداگانه
# - مدیریت خطاهای اولیه در بارگذاری مدل و پردازش درخواست ها
# - **رفع خطای 'SentenceTransformer' object has no attribute 'args' با اصلاح لاگ بارگذاری مدل**
from sentence_transformers import SentenceTransformer
from flask import Flask, request, jsonify
import numpy as np
import logging
import os
# import torch # اگر از GPU استفاده می کنید و torch نصب کرده اید، این خط را فعال نگه دارید.
# تنظیمات اولیه لاگینگ برای نمایش در لاگ های استاندارد Space
# این لاگ ها معمولاً در تب "Container logs" دیده می شوند.
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# مسیر فایل لاگ جداگانه در فضای Hugging Face (برای عیب یابی بیشتر)
# نکته: نوشتن در فایل در برخی محیط های Space ممکن است نیاز به تنظیمات مجوز داشته باشد.
log_file_path = "app_log.txt"
# تابع برای افزودن پیام به فایل لاگ
def log_message(message):
try:
# حالت 'a' برای اضافه کردن به انتهای فایل است.
# مطمئن شوید که دایرکتوری برای فایل قابل نوشتن است.
# اگر خطا مجوز می گیرید، می توانید این تابع را موقتا غیرفعال کنید یا مسیر دیگری را امتحان کنید.
with open(log_file_path, "a", encoding="utf-8") as f:
f.write(message + "\n")
except Exception as e:
# اگر نوشتن در فایل لاگ هم با خطا مواجه شد، در لاگ استاندارد Space بنویسید.
# خطای [Errno 13] Permission denied در لاگ قبلی به همین دلیل بود.
logging.error(f"Error writing to log file {log_file_path}: {e}")
# ****** نام مدل Sentence Transformer که می خواهیم در این سرور استفاده کنیم ******
# این مدل باید همان مدلی باشد که برای بردارسازی خاطرات در فایل های JSON استفاده کرده اید.
model_name_to_load = 'sentence-transformers/all-MiniLM-L6-L2day'
# ***************************************************************************
# ****** بارگذاری مدل Sentence Transformer در هنگام راه اندازی سرور ******
logging.info(f"Attempting to load Sentence Transformer model: {model_name_to_load}...") # لاگ قبل از بارگذاری (در لاگ های استاندارد Space)
log_message(f"Attempting to load Sentence Transformer model: {model_name_to_load}...") # لاگ قبل از بارگذاری (در فایل لاگ)
try:
# بارگذاری مدل. اگر GPU دارید و torch نصب شده، می توانید device='cuda' را اضافه کنید.
# اگر خطایی در بارگذاری رخ دهد، Exception گرفته می شود.
# model = SentenceTransformer(model_name_to_load, device='cuda' if torch.cuda.is_available() else 'cpu')
model = SentenceTransformer(model_name_to_load) # بارگذاری با استفاده از CPU یا تنظیمات پیش فرض
# ****** افزودن لاگ تأیید پس از بارگذاری موفق مدل ******
# این پیام ها در لاگ های Space به شما نشان می دهند که مدل با موفقیت بارگذاری شده و نام آن چیست.
# ما نام مدلی که قصد بارگذاریش را داشتیم لاگ می کنیم تا از خطای Attribute Error جلوگیری شود.
logging.info(f"SUCCESS: Model '{model_name_to_load}' loaded successfully.") # لاگ موفقیت (در لاگ های استاندارد Space)
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) # لاگ خطا (در لاگ های استاندارد Space)
log_message(error_msg) # لاگ خطا (در فایل لاگ)
# در صورتی که بارگذاری مدل با خطا مواجه شد، متغیر model را None قرار می دهیم
# تا در تابع get_embedding بتوانیم وضعیت خطا را چک کنیم.
model = None
# *************************************************
# تعریف اپلیکیشن Flask
app = Flask(__name__)
# تعریف اندپوینت اصلی برای تست سلامت سرور
@app.route('/')
def index():
# چک کردن وضعیت مدل قبل از پاسخ به درخواست اصلی
if model is None:
# اگر مدل بارگذاری نشده، پیام خطا نمایش داده می شود.
return "Sentiment Embedding Server is running, but model failed to load. Check Space logs for details.", 500
# اگر مدل با موفقیت بارگذاری شده، پیام موفقیت نمایش داده می شود.
# از نام مدلی که در متغیر ذخیره کردیم استفاده می کنیم.
return f"Sentiment Embedding Server is running successfully with model: {model_name_to_load}"
# تعریف اندپوینت برای دریافت بردار (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."
# این خطا احتمالا قبلا در لاگ ها ثبت شده، اما برای اطمینان مجدد ثبت می کنیم.
# logging.error(error_msg) # لاگ تکراری در صورتیکه بالا هم خطا داده
log_message(f"Received request but model is not loaded: {error_msg}") # ثبت در فایل لاگ
return jsonify({"error": error_msg}), 500 # ارسال پاسخ خطا با کد 500
try:
# دریافت داده ها از درخواست POST (باید شامل فیلد 'query' باشد)
data = request.get_json()
query = data.get('query')
# چک کردن اینکه فیلد 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 # ارسال پاسخ خطا با کد 400
log_message(f"Received query in /get_embedding: '{query}'")
logging.info(f"Processing query in /get_embedding: '{query[:50]}...'") # لاگ در کنسول Space برای درخواست های دریافتی
# تولید بردار (embedding) برای متن سوال با استفاده از مدل لود شده
embedding = model.encode(query, convert_to_numpy=True, pooling_mode='mean', normalize=True)
# تبدیل بردار numpy به لیست Python برای ارسال در پاسخ JSON
embedding_list = embedding.tolist()
log_message(f"Successfully generated embedding for query in /get_embedding.") # لاگ موفقیت در فایل
# logging.info(f"Embedding generated successfully for query.") # لاگ موفقیت در کنسول Space (اختیاری)
# ارسال بردار به عنوان پاسخ JSON
return jsonify({"embedding": embedding_list}), 200 # ارسال پاسخ موفقیت با کد 200
except Exception as e:
# مدیریت و ثبت هرگونه خطای دیگر در طول پردازش درخواست
error_message = f"An error occurred during embedding generation in /get_embedding: {e}"
logging.error(error_message) # لاگ خطا (در لاگ های استاندارد Space)
log_message(error_message) # لاگ خطا (در فایل لاگ)
return jsonify({"error": error_message}), 500 # ارسال پاسخ خطا با کد 500
# خط زیر فقط در صورتی که فایل server.py مستقیماً اجرا شود، سرور Flask را اجرا می کند.
# در Hugging Face Space، خود زیرساخت Space مسئول اجرای برنامه شماست و این بخش معمولاً غیرفعال است.
# if __name__ == '__main__':
# # Hugging Face Spaces از پورت 7860 استفاده می کند.
# # debug=True برای محیط توسعه مفید است اما در محیط پروداکشن توصیه نمی شود.
# app.run(host='0.0.0.0', port=7860, debug=False)