feat: support Gemma 4 chat and agent trials
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# SovereignAI Starter
|
||||
|
||||
مشروع تعليمي لبناء مساعد ذكاء اصطناعي محلي قابل للتوسع. النموذج المحمّل حاليًا: `qwen2.5:1.5b-instruct-q4_K_M` (نحو 986 ميغابايت).
|
||||
مشروع تعليمي لبناء مساعد ذكاء اصطناعي محلي قابل للتوسع. النموذج الافتراضي `qwen2.5:1.5b-instruct-q4_K_M` (نحو 986 ميغابايت)، ونموذج `gemma4:e2b` (نحو 7.16 غيغابايت) مثبت للتجربة والمقارنة.
|
||||
|
||||
## مكونات النسخة الأولى
|
||||
- FastAPI كواجهة HTTP محلية.
|
||||
@@ -33,6 +33,15 @@ $env:LOCAL_LLM_BASE_URL = "http://127.0.0.1:11434/v1"
|
||||
$env:LOCAL_MODEL = "qwen2.5:1.5b-instruct-q4_K_M"
|
||||
```
|
||||
|
||||
لتشغيل API على Gemma 4 بدل النموذج الافتراضي في نافذة PowerShell الحالية:
|
||||
|
||||
```powershell
|
||||
$env:LOCAL_MODEL = "gemma4:e2b"
|
||||
.\start-api.ps1
|
||||
```
|
||||
|
||||
يمكن أيضًا اختيار النموذج لكل طلب من `POST /v1/chat/completions` بإرسال `model`، أو من `POST /v1/agent/run` بإرسال `model` مع `task`. يبقى النموذج الافتراضي Qwen ما لم تغيّره من البيئة. على جهاز الاختبار، Gemma 4 E2B اشتغلت محليًا على CPU، لكنها استخدمت قرابة 3.5 غيغابايت من الذاكرة أثناء التحميل؛ قد تختلف السرعة حسب الجهاز.
|
||||
|
||||
راجع رخصة النموذج المختار وشروطه الحالية قبل الاستخدام التجاري. تنزيل النموذج يحتاج اتصال إنترنت ومساحة تخزين.
|
||||
|
||||
5. شغل الـ API على جهازك فقط (أو شغل `start-api.ps1`):
|
||||
@@ -48,6 +57,7 @@ python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
|
||||
- `POST /v1/chat/completions` لإرسال رسالة.
|
||||
- `POST /v1/agent/run` لتجربة الوكيل والأداة الحسابية.
|
||||
- `POST /v1/chat/completions` يمرر الطلب إلى الخادم المحلي عند ضبط المتغيرين أعلاه.
|
||||
- يمكن التبديل في Swagger بين النموذجين بإضافة `model` إلى جسم الطلب، مثل `gemma4:e2b`.
|
||||
|
||||
الخدمة مربوطة بـ `127.0.0.1` عمدًا، فلا تعرضها على الشبكة أو الإنترنت الآن. الوكيل الحالي يمرر السؤال النصي للنموذج، وينفذ الحسابات البسيطة بأداة حساب محلية محدودة. لا يقرأ ملفات ولا ينفذ أوامر النظام.
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ class ChatRequest(BaseModel):
|
||||
|
||||
class AgentRequest(BaseModel):
|
||||
task: str = Field(description="مهمة قصيرة للوكيل المحلي")
|
||||
model: str | None = Field(
|
||||
default=None,
|
||||
description="اسم نموذج Ollama؛ اتركه فارغًا لاستخدام النموذج الافتراضي",
|
||||
)
|
||||
|
||||
|
||||
class StoredMessage(BaseModel):
|
||||
@@ -106,7 +110,7 @@ def get_local_user() -> dict[str, str]:
|
||||
|
||||
def chat_payload(request: ChatRequest, *, stream: bool) -> dict[str, Any]:
|
||||
model = request.model or os.getenv("LOCAL_MODEL", "qwen2.5:1.5b-instruct-q4_K_M")
|
||||
return {
|
||||
payload: dict[str, Any] = {
|
||||
"model": model,
|
||||
"messages": (
|
||||
[message.model_dump() for message in request.messages]
|
||||
@@ -130,6 +134,10 @@ def chat_payload(request: ChatRequest, *, stream: bool) -> dict[str, Any]:
|
||||
),
|
||||
"stream": stream,
|
||||
}
|
||||
# Disable Gemma 4 thinking so Ollama places the answer in `content` for clients.
|
||||
if model.lower().startswith("gemma4"):
|
||||
payload["reasoning_effort"] = "none"
|
||||
return payload
|
||||
|
||||
|
||||
@app.post("/v1/chat/completions")
|
||||
@@ -283,7 +291,7 @@ async def run_agent(request: AgentRequest) -> dict[str, Any]:
|
||||
pass
|
||||
|
||||
base_url = os.getenv("LOCAL_LLM_BASE_URL", "http://127.0.0.1:11434/v1").rstrip("/")
|
||||
model = os.getenv("LOCAL_MODEL", "qwen2.5:1.5b-instruct-q4_K_M")
|
||||
model = request.model or os.getenv("LOCAL_MODEL", "qwen2.5:1.5b-instruct-q4_K_M")
|
||||
payload = {
|
||||
"model": model,
|
||||
"messages": [
|
||||
@@ -292,6 +300,8 @@ async def run_agent(request: AgentRequest) -> dict[str, Any]:
|
||||
],
|
||||
"stream": False,
|
||||
}
|
||||
if model.lower().startswith("gemma4"):
|
||||
payload["reasoning_effort"] = "none"
|
||||
completion = await get_completion(payload, base_url)
|
||||
return {
|
||||
"task": request.task,
|
||||
|
||||
@@ -11,7 +11,11 @@ if ($env:GROQ_API_KEY) {
|
||||
Write-Warning 'GROQ_API_KEY is not configured; local chat works, but voice transcription will return 503.'
|
||||
}
|
||||
$ollama = Invoke-RestMethod -Uri 'http://127.0.0.1:11434/api/tags' -TimeoutSec 5
|
||||
$model = 'qwen2.5:1.5b-instruct-q4_K_M'
|
||||
$model = if ($env:LOCAL_MODEL) {
|
||||
$env:LOCAL_MODEL
|
||||
} else {
|
||||
'qwen2.5:1.5b-instruct-q4_K_M'
|
||||
}
|
||||
if (-not ($ollama.models.name -contains $model)) {
|
||||
throw "Ollama is running, but model '$model' is missing. Run: ollama pull $model"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user