Spaces:
Paused
Paused
bayan-proxy: README.md
Browse files
README.md
CHANGED
|
@@ -1,10 +1,91 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji: 🐨
|
| 4 |
-
colorFrom: red
|
| 5 |
-
colorTo: blue
|
| 6 |
sdk: docker
|
|
|
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Muaalem Proxy
|
|
|
|
|
|
|
|
|
|
| 3 |
sdk: docker
|
| 4 |
+
app_port: 7860
|
| 5 |
pinned: false
|
| 6 |
---
|
| 7 |
|
| 8 |
+
# وسيط «بيان» — Muaalem Proxy
|
| 9 |
+
|
| 10 |
+
المصدر الرسميّ لِـHF Space `hatimqman-muaalem-proxy`. كان يعيش صندوقًا أسود على HF فقط؛
|
| 11 |
+
هذا مصدره الحقيقيّ داخل المستودع (`Quran_Rateel/hf-endpoint/proxy/`).
|
| 12 |
+
|
| 13 |
+
يجلس بين عميل **بيان** المنشور على Cloudflare Pages وبين ثلاث نقاط HF Inference، فيؤدّي:
|
| 14 |
+
|
| 15 |
+
- **يحمل توكن HF سرًّا** (من متغيّر البيئة `HF_TOKEN`) ويحقنه في نداء النقطة — لا يصل التوكن للعميل أبدًا.
|
| 16 |
+
- **يتجاوز حجب Cloudflare 1010**: العميل ينادي هذا الـSpace، والـSpace ينادي خادم HF.
|
| 17 |
+
- **فان-آوت** لثلاث نقاط علويّة عبر ثلاثة مسارات.
|
| 18 |
+
- **يقبل جسمًا مسطّحًا** ويغلّفه `{ "inputs": { … } }` قبل تمريره للنقطة، فيبقى `STT_URL` و`MUAALEM_URL`
|
| 19 |
+
في `bayan/web/app.js` بلا تغيير عنوان.
|
| 20 |
+
- **CORS** لنطاق Pages، **حدّ معدّل** لكلّ IP، **إعادة محاولة** على البدء البارد (scale-to-zero)،
|
| 21 |
+
و**تدهورٌ آمن**: أيّ فشلٍ للنقطة يُرجَع خطأ HTTP نظيفًا (لا استثناء) فيتجاهله العميل بصمتٍ.
|
| 22 |
+
|
| 23 |
+
## المسارات (واجهة العميل — مسطّحة)
|
| 24 |
+
|
| 25 |
+
| المسار | يقبل من العميل | يُمرَّر للنقطة | النقطة العلويّة |
|
| 26 |
+
|---|---|---|---|
|
| 27 |
+
| `POST /stt` | `{pcm}` أو `{pcm, ref}` | `{inputs:{pcm, ref?}}` | `STT_ENDPOINT_URL` (الطبقة الصوتية) |
|
| 28 |
+
| `POST /analyze` | `{pcm, surah, ayahs\|ayah, mode?, scope?, sifat?}` | `{inputs:{…}}` | `ANALYZE_ENDPOINT_URL` (المُعلِّم QPS) |
|
| 29 |
+
| `WS /stream?kind=tlog\|clean` | إطارات int16 PCM 16k + نصّ `"end"` | تمريرٌ شفّاف | `STREAM_ENDPOINT_URL` (بثّ احتياطيّ) |
|
| 30 |
+
| `GET /health` | — | — | فحص جهوزيّة (يكشف أيّ نقطةٍ مُهيَّأة) |
|
| 31 |
+
|
| 32 |
+
### عقد `POST /analyze`
|
| 33 |
+
|
| 34 |
+
```
|
| 35 |
+
req {"pcm":"<b64 PCM16 LE 16k أحاديّ>", "surah":1, "ayahs":[1,2,3,4,5,6,7],
|
| 36 |
+
"mode?":"whole|teacher", "scope?":{…}, "sifat?":true}
|
| 37 |
+
// أو "ayah":n لآيةٍ مفردة بدل ayahs
|
| 38 |
+
res ردّ النقطة كما هو: {uthmani, match, per, words:[{w,hard,soft, …}],
|
| 39 |
+
word_hard, word_soft, flagged, ops, ref_phonemes, pred_phonemes, mode, …}
|
| 40 |
+
```
|
| 41 |
+
`mode`/`scope`/`sifat` تُمرَّر شفّافةً؛ النقطة الحاليّة تتجاهلها بأمان، وطبقتا P1/P2 تستهلكانها.
|
| 42 |
+
|
| 43 |
+
### عقد `POST /stt`
|
| 44 |
+
|
| 45 |
+
```
|
| 46 |
+
req {"pcm":"<b64 PCM16 LE 16k>", "ref?":"<كلمات التشكيل للمحاذاة القسريّة>"}
|
| 47 |
+
res {"text":"…", "words?":[{w,start_ms,end_ms,prob,gop,status}], "provider":"quran-stt-acoustic"}
|
| 48 |
+
```
|
| 49 |
+
بلا `ref`: نصّ فقط. مع `ref`: محاذاة قسريّة + توقيت/GOP/رأس نطق.
|
| 50 |
+
|
| 51 |
+
## متغيّرات البيئة (Settings → Variables and secrets)
|
| 52 |
+
|
| 53 |
+
| المتغيّر | النوع | الافتراضيّ | الوصف |
|
| 54 |
+
|---|---|---|---|
|
| 55 |
+
| `HF_TOKEN` | **سرّ** | — | توكن HF (Bearer) لنقاط الاستدلال. **إلزاميّ** إن كانت النقاط محميّة. |
|
| 56 |
+
| `STT_ENDPOINT_URL` | متغيّر | — | URL كامل لنقطة الطبقة الصوتية. فارغٌ ⇒ `/stt` يُرجِع 503 نظيفًا. |
|
| 57 |
+
| `ANALYZE_ENDPOINT_URL` | متغيّر | — | URL كامل لنقطة المُعلِّم QPS. فارغٌ ⇒ `/analyze` يُرجِع 503 نظيفًا. |
|
| 58 |
+
| `STREAM_ENDPOINT_URL` | متغيّر | — | URL كامل لنقطة البثّ (`ws://`/`wss://`). فارغٌ ⇒ `/stream` يُغلَق بلطف. |
|
| 59 |
+
| `ALLOWED_ORIGINS` | متغيّر | — | أصولٌ صريحة مفصولة بفواصل (بجانب النمط أدناه). |
|
| 60 |
+
| `ALLOWED_ORIGIN_REGEX` | متغيّر | `*.pages.dev`/`*.workers.dev`/localhost | نمط CORS. عدِّله لتقييده على نطاق Pages بعينه. |
|
| 61 |
+
| `RATE_LIMIT_PER_MIN` | متغيّر | `40` | سقف الطلبات لكلّ IP في الدقيقة. `0` = مُعطَّل. |
|
| 62 |
+
| `UPSTREAM_TIMEOUT` | متغيّر | `150` | سقف ميزانية الطلب الكلّيّة (ث) عبر كلّ المحاولات. |
|
| 63 |
+
| `ATTEMPT_TIMEOUT` | متغيّر | `60` | مهلة قراءة المحاولة الواحدة (ث). |
|
| 64 |
+
| `MAX_RETRIES` | متغيّر | `6` | أقصى عدد محاولات على البدء البارد. |
|
| 65 |
+
| `RETRY_BACKOFF` | متغيّر | `4` | أساس التراجع الخطّيّ (ث). |
|
| 66 |
+
| `RETRY_BACKOFF_MAX` | متغيّر | `20` | سقف التراجع بين المحاولات (ث). |
|
| 67 |
+
| `MAX_BODY_BYTES` | متغيّر | `25165824` | سقف حجم جسم الطلب (~24MB). |
|
| 68 |
+
| `LOG_LEVEL` | متغيّر | `INFO` | مستوى السجلّ. |
|
| 69 |
+
|
| 70 |
+
> إعادة المحاولة تُطلَق على حالات `500/502/503/504` (النقطة تستيقظ من scale-to-zero) وعلى أخطاء
|
| 71 |
+
> الاتصال/المهلة. أمّا `4xx` الحتميّة فتُعاد فورًا بلا إعادة محاولة.
|
| 72 |
+
|
| 73 |
+
## التشغيل المحلّيّ
|
| 74 |
+
|
| 75 |
+
```bash
|
| 76 |
+
pip install -r requirements.txt
|
| 77 |
+
export HF_TOKEN=hf_xxx
|
| 78 |
+
export ANALYZE_ENDPOINT_URL=https://<endpoint>.endpoints.huggingface.cloud
|
| 79 |
+
export STT_ENDPOINT_URL=https://<endpoint>.endpoints.huggingface.cloud
|
| 80 |
+
python app.py # يستمع على :7860 (أو $PORT)
|
| 81 |
+
# فحص: curl localhost:7860/health
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
## النشر على HF Space
|
| 85 |
+
|
| 86 |
+
1. أنشئ Space من نوع **Docker**.
|
| 87 |
+
2. ارفع `app.py` و`requirements.txt` و`Dockerfile` و`README.md` (front matter أعلاه يضبط `app_port=7860`).
|
| 88 |
+
3. أضِف الأسرار/المتغيّرات من الجدول أعلاه (`HF_TOKEN` سرًّا؛ عناوين النقاط متغيّراتٍ).
|
| 89 |
+
4. أبقِ `MUAALEM_URL`/`STT_URL` في `bayan/web/app.js` على `https://<space>.hf.space/{analyze,stt}` بلا تغيير.
|
| 90 |
+
|
| 91 |
+
**لا شيء هنا يَنشُر تلقائيًّا — كودٌ فقط.**
|