k
File size: 4,915 Bytes
52614c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from huggingface_hub import hf_hub_download
from llama_cpp import Llama

app = FastAPI()

# 1. تحميل النموذج من المستودع المحدد
model_path = hf_hub_download(
    repo_id="Arabic250/gemma-4-gguf-export", 
    filename="gemma-4-e4b.gguf"
)

# 2. تهيئة النموذج للعمل على CPU فقط
llm = Llama(
    model_path=model_path, 
    n_ctx=2048, 
    n_threads=4,     # مناسب لموارد Hugging Face المجانية
    n_gpu_layers=0   # تعطيل طبقات معالج الرسوميات (CPU Only)
)

class ChatRequest(BaseModel):
    message: str

# 3. واجهة React الأمامية مدمجة كـ HTML
HTML_CONTENT = """
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>Gemma 4 Chat</title>
    <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-4 font-sans">
    <div id="root"></div>
    <script type="text/babel">
        function App() {
            const [messages, setMessages] = React.useState([]);
            const [input, setInput] = React.useState("");
            const [loading, setLoading] = React.useState(false);

            const sendMessage = async () => {
                if (!input.trim()) return;
                const newMessages = [...messages, { role: 'user', text: input }];
                setMessages(newMessages);
                setInput("");
                setLoading(true);

                try {
                    const res = await fetch("/chat", {
                        method: "POST",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({ message: input })
                    });
                    const data = await res.json();
                    setMessages([...newMessages, { role: 'model', text: data.response }]);
                } catch (error) {
                    console.error(error);
                }
                setLoading(false);
            };

            return (
                <div className="max-w-3xl mx-auto bg-white p-6 rounded-lg shadow-lg mt-10 border-t-4 border-blue-500">
                    <h1 className="text-2xl font-bold mb-6 text-center text-gray-800">محادثة Gemma 4 (React)</h1>
                    <div className="h-[28rem] overflow-y-auto mb-4 p-4 border rounded bg-gray-50 flex flex-col gap-3">
                        {messages.map((msg, idx) => (
                            <div key={idx} className={`p-3 rounded-lg w-fit max-w-[80%] ${msg.role === 'user' ? 'bg-blue-100 self-start' : 'bg-green-100 self-end'}`}>
                                <strong className="block mb-1 text-xs text-gray-500">{msg.role === 'user' ? 'أنت' : 'النموذج'}</strong>
                                <span className="text-gray-800">{msg.text}</span>
                            </div>
                        ))}
                        {loading && <div className="text-gray-500 text-sm animate-pulse self-end">النموذج يقوم بالمعالجة الآن...</div>}
                    </div>
                    <div className="flex gap-2">
                        <input 
                            type="text" 
                            value={input} 
                            onChange={(e) => setInput(e.target.value)}
                            onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
                            className="flex-1 p-3 border rounded focus:outline-none focus:ring-2 focus:ring-blue-400"
                            placeholder="اكتب استفسارك هنا..." 
                        />
                        <button onClick={sendMessage} disabled={loading} className="bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700 disabled:opacity-50 transition-colors font-semibold">
                            إرسال
                        </button>
                    </div>
                </div>
            );
        }
        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(<App />);
    </script>
</body>
</html>
"""

@app.get("/")
def read_root():
    return HTMLResponse(content=HTML_CONTENT)

@app.post("/chat")
def chat(request: ChatRequest):
    # بناء سياق Gemma بالشكل الصحيح
    prompt = f"<start_of_turn>user\n{request.message}<end_of_turn>\n<start_of_turn>model\n"
    
    response = llm(
        prompt, 
        max_tokens=512, 
        stop=["<end_of_turn>"]
    )
    
    return {"response": response['choices'][0]['text'].strip()}