# این فایل 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 استفاده می شود. # این روت هر فایلی که در ریشه اپلیکیشن قرار دارد و نام آن با روت های تعریف شده مطابقت ندارد را سرویس می دهد. # یک متغیر مسیر است که شامل نام فایل و هر زیرپوشه ای است. @app.route('/') 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)