File size: 5,759 Bytes
5b1f394
 
542f7bc
e16f88f
c77fdcb
542f7bc
5b1f394
 
e16f88f
c77fdcb
 
 
 
 
 
 
e16f88f
 
542f7bc
e16f88f
5b1f394
 
 
 
 
 
 
 
 
 
 
 
 
e16f88f
542f7bc
 
c77fdcb
5b1f394
 
 
 
 
 
 
 
 
 
09e97a9
5b1f394
cfb95da
542f7bc
5b1f394
 
 
 
 
 
 
 
 
 
 
 
e16f88f
5b1f394
bd805c9
 
 
 
 
 
 
 
e16f88f
 
 
542f7bc
e16f88f
542f7bc
 
 
 
09e97a9
5b1f394
09e97a9
 
5b1f394
09e97a9
 
 
 
542f7bc
5b1f394
 
 
 
 
 
 
 
c77fdcb
 
 
5b1f394
c77fdcb
542f7bc
 
5b1f394
542f7bc
 
 
4280507
e16f88f
 
4280507
e16f88f
 
4280507
e16f88f
4280507
e16f88f
4280507
5b1f394
09e97a9
e16f88f
bd805c9
5b1f394
 
bd805c9
 
542f7bc
5b1f394
 
 
09e97a9
4280507
542f7bc
e16f88f
 
542f7bc
 
e16f88f
09e97a9
c77fdcb
4280507
 
 
 
 
 
 
 
 
 
 
 
09e97a9
4280507
 
 
 
f93dc62
 
 
4280507
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from llama_cpp import Llama
import logging
import os
import ssl
import requests

# 🔧 إعداد السجل
logging.basicConfig(
    level=logging.DEBUG,
    format="🪵 [%(asctime)s] [%(levelname)s] %(message)s",
)
logger = logging.getLogger(__name__)

MODEL_REPO = "QuantFactory/Qwen2.5-7B-Instruct-GGUF"
MODEL_FILE = "Qwen2.5-7B-Instruct.Q4_K_M.gguf"
MODEL_PATH = f"/home/user/app/data/cache/{MODEL_FILE}"

# تحقق من SSL لـ Hugging Face Hub
def check_ssl_connection():
    try:
        response = requests.get("https://huggingface.co", verify=True, timeout=5)
        logger.info("✅ الاتصال بـ Hugging Face باستخدام SSL ناجح")
    except requests.exceptions.SSLError as e:
        logger.error(f"❌ خطأ SSL عند الاتصال بـ Hugging Face: {str(e)}")
    except Exception as e:
        logger.error(f"❌ خطأ في الاتصال بـ Hugging Face: {str(e)}")

check_ssl_connection()

# تحميل النموذج
if not os.path.exists(MODEL_PATH):
    from huggingface_hub import hf_hub_download
    os.makedirs("/home/user/app/data/cache", exist_ok=True)
    logger.info("📦 تحميل النموذج من Hugging Face Hub...")
    try:
        hf_hub_download(
            repo_id=MODEL_REPO,
            filename=MODEL_FILE,
            local_dir="/home/user/app/data/cache",
        )
        logger.info(f"✅ النموذج تم تحميله: {MODEL_PATH}")
    except Exception as e:
        logger.error(f"❌ فشل تحميل النموذج: {str(e)}")
        raise
else:
    logger.info(f"✅ النموذج موجود: {MODEL_PATH}")

# تحميل النموذج
try:
    llm = Llama(
        model_path=MODEL_PATH,
        n_ctx=4096,
        n_threads=6,
        n_gpu_layers=0,
        verbose=False
    )
    logger.info("🛠 النموذج تم تحميله بنجاح")
except Exception as e:
    logger.error(f"❌ فشل تحميل النموذج: {str(e)}")
    raise

# 🔍 اختبار النموذج
try:
    logger.info("🔍 يجري اختبار النموذج...")
    test_output = llm("مرحبا", max_tokens=10)
    logger.info(f"✅ اختبار النموذج ناجح: {test_output}")
except Exception as e:
    logger.error(f"❌ فشل اختبار النموذج: {str(e)}")
    raise RuntimeError("فشل تحميل النموذج") from e

SYSTEM_PROMPT = """<|im_start|>system
You are Qwen, created by Alibaba Cloud. You are an AI development assistant. Follow these rules:
1. If request is simple (single file, <50 lines), handle it directly
2. For complex requests (multiple files, >50 lines), just respond with \"CODER\"
3. Always check code for errors before sending
4. Never execute unsafe code<|im_end|>"""

# API setup
app = FastAPI()

# تفعيل CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # يمكن تخصيصه لاحقًا (مثل ["http://localhost:3000"])
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# تحقق من CORS أثناء الطلب
async def check_cors(request: Request):
    origin = request.headers.get("origin")
    if not origin:
        logger.warning("⚠ لا يوجد رأس Origin، قد تكون هناك مشكلة CORS")
    else:
        logger.info(f"🌐 تمتلك الطلب Origin: {origin}")

@app.on_event("startup")
async def startup_event():
    logger.info("🚀 الخادم بدأ بنجاح – /chat جاهز")
    logger.info("🌍 العنوان: https://<اسمك>.hf.space/chat (عند النشر على Hugging Face)")

class ChatRequest(BaseModel):
    message: str
    history: list[tuple[str, str]] = []  # استخدام tuple كما في الكود الأصلي

class ChatResponse(BaseModel):
    response: str
    updated_history: list[tuple[str, str]]

def format_prompt(messages):
    formatted = []
    for role, content in messages:
        if role == "system":
            formatted.append(f"<|im_start|>system\n{content}<|im_end|>")
        elif role == "user":
            formatted.append(f"<|im_start|>user\n{content}<|im_end|>")
        else:
            formatted.append(f"<|im_start|>assistant\n{content}<|im_end|>")
    formatted.append("<|im_start|>assistant\n")
    return "\n".join(formatted)

@app.post("/test")
async def test_endpoint():
    logger.info("📩 طلب تم استلامه على /test")
    return {"status": "success", "message": "النقطة النهائية تعمل"}

@app.post("/chat", response_model=ChatResponse)
async def chat(req: ChatRequest, request: Request):
    await check_cors(request)
    logger.info(f"🟡 تم استقبال الطلب من المتصفح: {req.message}")
    
    messages = [("system", SYSTEM_PROMPT)]
    for user_msg, bot_msg in req.history:
        messages.append(("user", user_msg))
        messages.append(("assistant", bot_msg))
    messages.append(("user", req.message))

    prompt = format_prompt(messages)
    logger.debug(f"📝 prompt المُرسل للنموذج:\n{prompt[:500]}...")

    try:
        output = llm(
            prompt,
            max_tokens=1024,
            temperature=0.7,
            top_p=0.9,
            stop=["<|im_end|>", "<|im_start|>"],
            echo=False
        )
        reply = output["choices"][0]["text"].strip()
        logger.info(f"🤖 رد النموذج: {reply}")
    except Exception as e:
        logger.error(f"حدث خطأ: {str(e)}")
        raise

    updated_history = req.history + [(req.message, reply)]
    return ChatResponse(response=reply, updated_history=updated_history)

@app.get("/")
def root():
    return {"message": "الخادم يعمل", "status": "ok"}