Spaces:
Runtime error
Runtime error
Rename server.py to app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# این فایل app.py در Hugging Face Space شما قرار می گیرد
|
| 2 |
+
# این کد شامل:
|
| 3 |
+
# - بارگذاری مدل Sentence Transformer پارسی 'heydariAI/persian-embeddings'
|
| 4 |
+
# - تعریف اپلیکیشن Flask
|
| 5 |
+
# - اندپوینت /get_embedding برای دریافت سوال و ارسال بردار آن
|
| 6 |
+
# - لاگ گیری برای عیب یابی در لاگ های Space و یک فایل جداگانه
|
| 7 |
+
# - مدیریت خطاهای اولیه در بارگذاری مدل و پردازش درخواست ها
|
| 8 |
+
|
| 9 |
+
from sentence_transformers import SentenceTransformer
|
| 10 |
+
from flask import Flask, request, jsonify
|
| 11 |
+
import numpy as np
|
| 12 |
+
import logging
|
| 13 |
+
import os
|
| 14 |
+
# import torch # اگر از GPU استفاده می کنید و torch نصب کرده اید، این خط را فعال نگه دارید.
|
| 15 |
+
|
| 16 |
+
# تنظیمات اولیه لاگینگ برای نمایش در لاگ های استاندارد Space
|
| 17 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 18 |
+
|
| 19 |
+
# مسیر فایل لاگ جداگانه در فضای Hugging Face (برای عیب یابی بیشتر)
|
| 20 |
+
# نکته: نوشتن در فایل در برخی محیط های Space ممکن است نیاز به تنظیمات مجوز داشته باشد.
|
| 21 |
+
log_file_path = "app_log.txt"
|
| 22 |
+
|
| 23 |
+
# تابع برای افزودن پیام به فایل لاگ
|
| 24 |
+
def log_message(message):
|
| 25 |
+
try:
|
| 26 |
+
with open(log_file_path, "a", encoding="utf-8") as f:
|
| 27 |
+
f.write(message + "\n")
|
| 28 |
+
except Exception as e:
|
| 29 |
+
logging.error(f"Error writing to log file {log_file_path}: {e}")
|
| 30 |
+
|
| 31 |
+
# ****** نام مدل Sentence Transformer که می خواهیم در این سرور استفاده کنیم ******
|
| 32 |
+
# این مدل برای Space جدید: heydariAI/persian-embeddings
|
| 33 |
+
model_name_to_load = 'heydariAI/persian-embeddings'
|
| 34 |
+
# ***************************************************************************
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
# ****** بارگذاری مدل Sentence Transformer در هنگام راه اندازی سرور ******
|
| 38 |
+
logging.info(f"Attempting to load Sentence Transformer model: {model_name_to_load}...")
|
| 39 |
+
log_message(f"Attempting to load Sentence Transformer model: {model_name_to_load}...")
|
| 40 |
+
|
| 41 |
+
try:
|
| 42 |
+
# بارگذاری مدل. اگر GPU دارید و torch نصب شده، می توانید device='cuda' را اضافه کنید.
|
| 43 |
+
model = SentenceTransformer(model_name_to_load)
|
| 44 |
+
|
| 45 |
+
# ****** افزودن لاگ تأیید پس از بارگذاری موفق مدل ******
|
| 46 |
+
logging.info(f"SUCCESS: Model '{model_name_to_load}' loaded successfully.")
|
| 47 |
+
log_message(f"SUCCESS: Model '{model_name_to_load}' loaded successfully.")
|
| 48 |
+
# ******************************************************
|
| 49 |
+
|
| 50 |
+
except Exception as e:
|
| 51 |
+
# ****** مدیریت خطا در صورت عدم بارگذاری مدل ******
|
| 52 |
+
error_msg = f"ERROR: Failed to load model {model_name_to_load}: {e}"
|
| 53 |
+
logging.error(error_msg)
|
| 54 |
+
log_message(error_msg)
|
| 55 |
+
model = None
|
| 56 |
+
# *************************************************
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
# تعریف اپلیکیشن Flask
|
| 60 |
+
app = Flask(__name__)
|
| 61 |
+
|
| 62 |
+
@app.route('/')
|
| 63 |
+
def index():
|
| 64 |
+
if model is None:
|
| 65 |
+
return "Sentiment Embedding Server is running, but model failed to load. Check Space logs for details.", 500
|
| 66 |
+
return f"Sentiment Embedding Server is running successfully with model: {model_name_to_load}"
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@app.route('/get_embedding', methods=['POST'])
|
| 70 |
+
def get_embedding():
|
| 71 |
+
if model is None:
|
| 72 |
+
error_msg = "Model is not loaded on the server due to a previous error. Check Space logs."
|
| 73 |
+
log_message(f"Received request but model is not loaded: {error_msg}")
|
| 74 |
+
return jsonify({"error": error_msg}), 500
|
| 75 |
+
|
| 76 |
+
try:
|
| 77 |
+
data = request.get_json()
|
| 78 |
+
query = data.get('query')
|
| 79 |
+
|
| 80 |
+
if not query or not isinstance(query, str) or not query.strip():
|
| 81 |
+
log_message(f"Received invalid or empty query in /get_embedding: {data}")
|
| 82 |
+
return jsonify({"error": "Invalid or empty query text provided"}), 400
|
| 83 |
+
|
| 84 |
+
log_message(f"Received query in /get_embedding: '{query}'")
|
| 85 |
+
logging.info(f"Processing query in /get_embedding: '{query[:50]}...'")
|
| 86 |
+
|
| 87 |
+
embedding = model.encode(query, convert_to_numpy=True, pooling_mode='mean', normalize=True)
|
| 88 |
+
|
| 89 |
+
embedding_list = embedding.tolist()
|
| 90 |
+
|
| 91 |
+
log_message(f"Successfully generated embedding for query in /get_embedding.")
|
| 92 |
+
|
| 93 |
+
return jsonify({"embedding": embedding_list}), 200
|
| 94 |
+
|
| 95 |
+
except Exception as e:
|
| 96 |
+
error_message = f"An error occurred during embedding generation in /get_embedding: {e}"
|
| 97 |
+
logging.error(error_message)
|
| 98 |
+
log_message(error_message)
|
| 99 |
+
return jsonify({"error": error_message}), 500
|
| 100 |
+
|
| 101 |
+
# خط زیر فقط در صورتی که فایل server.py مستقیماً اجرا شود، سرور Flask را اجرا می کند.
|
| 102 |
+
# در Hugging Face Space، خود زیرساخت Space مسئول اجرای برنامه شماست و این بخش معمولاً غیرفعال است.
|
| 103 |
+
# if __name__ == '__main__':
|
| 104 |
+
# app.run(host='0.0.0.0', port=7860, debug=False)
|
server.py
DELETED
|
@@ -1,84 +0,0 @@
|
|
| 1 |
-
# این کد، برنامه سرور پایتون شما برای تولید Embedding سوال با قابلیت CORS است.
|
| 2 |
-
# از فریمورک Flask و افزونه Flask-CORS استفاده شده است.
|
| 3 |
-
|
| 4 |
-
from flask import Flask, request, jsonify
|
| 5 |
-
from flask_cors import CORS # ایمپورت کردن افزونه CORS
|
| 6 |
-
from sentence_transformers import SentenceTransformer
|
| 7 |
-
import numpy as np
|
| 8 |
-
import logging
|
| 9 |
-
|
| 10 |
-
# تنظیمات اولیه لاگینگ برای مشاهده پیام ها در کنسول سرور
|
| 11 |
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 12 |
-
|
| 13 |
-
app = Flask(__name__)
|
| 14 |
-
# اضافه کردن CORS به برنامه Flask
|
| 15 |
-
# این خط به سرور شما اجازه میدهد به درخواست هایی از مبدا 'http://localhost:8000' پاسخ دهد
|
| 16 |
-
CORS(app, origins=["http://localhost:8000"])
|
| 17 |
-
|
| 18 |
-
# ****** نام مدل Sentence Transformer که برای بردارسازی سوال استفاده میشود ******
|
| 19 |
-
# این مدل باید همان مدلی باشد که برای تولید Embeddings JSON استفاده شده است
|
| 20 |
-
# مدل PartAI/Tooka-SBERT با ابعاد 1024 - بهترین مدل در تست ها
|
| 21 |
-
model_name = 'PartAI/Tooka-SBERT'
|
| 22 |
-
# ******************************************************************************
|
| 23 |
-
|
| 24 |
-
model = None # متغیری برای نگهداری مدل بارگذاری شده
|
| 25 |
-
|
| 26 |
-
# تابع برای بارگذاری مدل هوش مصنوعی هنگام شروع سرور
|
| 27 |
-
def load_model(model_name):
|
| 28 |
-
global model
|
| 29 |
-
if model is None:
|
| 30 |
-
logging.info(f"Loading Sentence Transformer model: {model_name} for server...")
|
| 31 |
-
try:
|
| 32 |
-
# بارگذاری مدل
|
| 33 |
-
# ممکن است نیاز به تعیین device='cpu' باشد اگر به صورت خودکار شناسایی نشود
|
| 34 |
-
# import torch # اگر از torch استفاده میکنید
|
| 35 |
-
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 36 |
-
# model = SentenceTransformer(model_name, device=device)
|
| 37 |
-
model = SentenceTransformer(model_name) # بارگذاری با تشخیص خودکار دستگاه
|
| 38 |
-
logging.info("Model loaded successfully on the server.")
|
| 39 |
-
except Exception as e:
|
| 40 |
-
logging.error(f"Error loading model on the server: {e}")
|
| 41 |
-
model = None # در صورت خطا مدل را None نگه میداریم
|
| 42 |
-
|
| 43 |
-
# مسیر API برای دریافت سوال و ارسال بردار آن
|
| 44 |
-
@app.route('/get_embedding', methods=['POST']) # مسیر دریافت بردار سوال
|
| 45 |
-
def get_embedding():
|
| 46 |
-
# چک میکنیم که آیا مدل با موفقیت بارگذاری شده است یا خیر
|
| 47 |
-
if model is None:
|
| 48 |
-
logging.error("Attempted to process request but AI model is not loaded.")
|
| 49 |
-
return jsonify({"error": "AI model not loaded on server."}), 500
|
| 50 |
-
|
| 51 |
-
# چک میکنیم که درخواست دریافتی شامل داده JSON و فیلد 'query' باشد
|
| 52 |
-
if not request.json or 'query' not in request.json:
|
| 53 |
-
logging.warning("Received invalid request: Missing JSON or 'query' field.")
|
| 54 |
-
return jsonify({"error": "Invalid request. Please send JSON with a 'query' field."}), 400
|
| 55 |
-
|
| 56 |
-
query = request.json['query']
|
| 57 |
-
logging.info(f"Received query for embedding: '{query}'")
|
| 58 |
-
|
| 59 |
-
try:
|
| 60 |
-
# تولید بردار معنایی برای سوال دریافتی
|
| 61 |
-
# pooling='mean' و normalize=True باید با آنچه در تولید Embeddings JSON استفاده شد یکسان باشد
|
| 62 |
-
query_embedding = model.encode(query, convert_to_numpy=True, pooling_mode='mean', normalize=True)
|
| 63 |
-
|
| 64 |
-
# تبدیل بردار numpy به لیست پایتون برای ارسال در پاسخ JSON
|
| 65 |
-
query_embedding_list = query_embedding.tolist()
|
| 66 |
-
|
| 67 |
-
logging.info("Query embedding generated successfully.")
|
| 68 |
-
# ارسال بردار تولید شده به عنوان پاسخ JSON به مرورگر
|
| 69 |
-
return jsonify({"embedding": query_embedding_list})
|
| 70 |
-
|
| 71 |
-
except Exception as e:
|
| 72 |
-
logging.error(f"Error generating embedding on server: {e}", exc_info=True) # لاگ کامل خطا
|
| 73 |
-
return jsonify({"error": "Error generating embedding."}), 500
|
| 74 |
-
|
| 75 |
-
# تابع اصلی برای اجرای سرور
|
| 76 |
-
if __name__ == '__main__':
|
| 77 |
-
# بارگذاری مدل هنگام اجرای اسکریپت سرور
|
| 78 |
-
load_model(model_name)
|
| 79 |
-
# اجرای سرور Flask
|
| 80 |
-
# debug=True فقط برای توسعه - برای محیط نهایی باید False شود
|
| 81 |
-
# host='0.0.0.0' برای دسترسی از شبکه محلی
|
| 82 |
-
# port=5000 پورتی که سرور روی آن گوش میدهد
|
| 83 |
-
# threaded=True می تواند به مدیریت درخواست های همزمان کمک کند (برای توسعه کافی است)
|
| 84 |
-
app.run(debug=True, port=5000, host='0.0.0.0', threaded=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|