الصورة الرمزية أبو بكر عابد


قبل بضعة أسابيع، كتبنا عن تطبيقات الويب الكاملة ذات اللقطة الواحدة gr.HTML: إنشاء واجهات أمامية غنية وتفاعلية بالكامل داخل Gradio باستخدام HTML وCSS وJavaScript المخصصين. لقد فتح ذلك الكثير. ولكن ماذا لو لم يكن هذا كافيا؟

ماذا لو كنت تريد قم بالبناء باستخدام إطار الواجهة الأمامية الخاص بك بالكامل مثل React أو Svelte أو حتى HTML/JS العادي، مع الاستمرار في الاستفادة من نظام قائمة الانتظار الخاص بـ Gradio والبنية التحتية لواجهة برمجة التطبيقات (API) ودعم MCP وZeroGPU on Spaces؟

هذه هي المشكلة بالضبط gradio.Server يحل. وهو يغير ما هو ممكن مع Gradio وHugging Face Spaces.

ما أردنا بناءه

النص خلف الصورة : محرر حيث تقوم بتحميل صورة، تتم إزالة الخلفية باستخدام نموذج ML، ثم تقوم بوضع نص منمق بين الموضوع الأمامي والخلفية. يبدو أن النص موجود خلف الشخص أو الكائن الموجود في الصورة.

هذا يحتاج إلى:

  • أ قماش السحب والإفلات مع عرض الطبقات (الخلفية → النص → المقدمة)
  • أ لوحة تحكم غنية مع أشرطة تمرير لحجم الخط، والوزن، وتباعد الحروف، واللون، والعتامة، والحد، والظل، والبثق ثلاثي الأبعاد، وتحويلات المنظور، والمزيد
  • أ نقطة نهاية ML الخلفية الذي يقوم بتشغيل نموذج إزالة الخلفية وإرجاع PNG شفافة
  • تصدير إلى PNG على جانب العميل

لا توجد طريقة للتعبير عن واجهة المستخدم هذه في مكونات Gradio. إنه تطبيق ويب كامل. ولكننا ما زلنا نرغب في الحصول على قوة الواجهة الخلفية لـ Gradio: قوائم الانتظار، وإدارة التزامن، ودعم ZeroGPU، والاستضافة على HF Spaces دون مشاكل في البنية التحتية.

يدخل gradio.Server

gradio.Server يمتد FastAPI. فهو يمنحك القوة الكاملة لـ FastAPI (المسارات المخصصة والبرامج الوسيطة وتحميل الملفات وأي نوع استجابة) مع إضافة محرك Gradio’s API في الأعلى: قائمة الانتظار، وبث SSE، والتحكم في التزامن، و gradio_client التوافق.

إليك الواجهة الخلفية الكاملة للنص خلف الصورة:

import os
import torch
from PIL import Image
from torchvision import transforms
from transformers import AutoModelForImageSegmentation
from gradio import Server
from gradio.data_classes import FileData
from fastapi.responses import HTMLResponse
import spaces

torch.set_float32_matmul_precision("high")

birefnet = AutoModelForImageSegmentation.from_pretrained(
    "ZhengPeng7/BiRefNet", trust_remote_code=True
)
birefnet.to("cuda")
birefnet.float()

transform_image = transforms.Compose([
    transforms.Resize((1024, 1024)),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])

app = Server()


@spaces.GPU
def segment(image: Image.Image) -> Image.Image:
    """Run BiRefNet segmentation to produce a transparency mask."""
    image_size = image.size
    input_images = transform_image(image).unsqueeze(0).to("cuda")
    with torch.no_grad():
        preds = birefnet(input_images)[-1].sigmoid().cpu()
    pred = preds[0].squeeze()
    mask = transforms.ToPILImage()(pred).resize(image_size)
    image.putalpha(mask)
    return image


@app.api(name="remove_background")
def remove_background(image_path: FileData) -> FileData:
    """Remove background from an image. Returns transparent PNG."""
    im = Image.open(image_path["path"]).convert("RGB")
    result = segment(im)
    out_path = image_path["path"].rsplit(".", 1)[0] + ".png"
    result.save(out_path)
    return FileData(path=out_path)


@app.get("https://huggingface.co/", response_class=HTMLResponse)
async def homepage():
    html_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")
    with open(html_path, "r", encoding="utf-8") as f:
        return f.read()


app.launch(show_error=True)

هذا كل شيء. ~ 50 سطرًا من لغة بايثون. يتم تحميل النموذج عند بدء التشغيل، @spaces.GPU يتعامل مع تخصيص ZeroGPU، و gradio.Server يدير قائمة الانتظار والتزامن. دعونا نحلل ما يحدث.

لماذا @app.api() بدلاً من طريق FastAPI العادي؟

إذا كان هذا تطبيق FastAPI عاديًا، فيمكنك تحديد @app.post() الطريق لإزالة الخلفية. يعمل ذلك، حتى يقوم مستخدمان بضربه في وقت واحد. بدون إدارة التزامن، يتقاتل كلا الطلبين من أجل وحدة معالجة الرسومات، ويتعطل التطبيق أو يُرجع البيانات المهملة.

@app.api() يحل هذا. فهو يغلف وظيفتك بمحرك قائمة الانتظار الخاص بـ Gradio: يتم إجراء تسلسل للطلبات، ويتم التحكم في التزامن، وفي مساحات ZeroGPU، تتم معالجة تخصيص وحدة معالجة الرسومات تلقائيًا عبر @spaces.GPU. على سبيل المكافأة، أي @app.api() نقطة النهاية قابلة للاستدعاء أيضًا عبر gradio_client، حتى تتمكن التطبيقات أو البرامج النصية الأخرى من استخدام مساحتك برمجيًا:

from gradio_client import Client, handle_file
client = Client("ysharma/text-behind-image")
result = client.predict(
      image_path=handle_file("photo.jpg"),
      api_name="/remove_background"
  )

في أثناء، @app.get("https://huggingface.co/") هو مسار FastAPI القياسي الذي يخدم صفحة HTML. كلاهما يتعايش بشكل طبيعي لأن Server يكون تطبيق FastAPI.

الواجهة الأمامية: HTML/CSS/JS خالصة

ال index.html في هذا المثال، يوجد تطبيق ويب قائم بذاته مكون من 1300 سطر تقريبًا. لا يوجد رد فعل، ولا خطوة بناء، ولا مُجمّع. مجرد HTML الفانيليا مع:

  • أ قماش ثلاث طبقات: صورة الخلفية → طبقة النص → المقدمة (PNG الشفاف) مكدسة باستخدام CSS z-index
  • تحديد موضع النص بالسحب والإفلات باستخدام أحداث المؤشر
  • أ لوحة التحكم مع أكثر من 20 معلمة: عائلة الخطوط (أكثر من 25 خطًا)، والحجم، والوزن، والتباعد، واللون، والعتامة، وملء الخلفية، والسكتة الدماغية، والظل، وعمق البثق والزاوية ثلاثية الأبعاد، والتدوير، والانحراف، وتحويلات منظور CSS الكاملة
  • تصدير PNG من جانب العميل استخدام <canvas> التركيب

تتحدث الواجهة الأمامية إلى الواجهة الخلفية باستخدام عميل Gradio JS:

import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";

const client = await Client.connect(window.location.origin);
const result = await client.predict("/remove_background", {
    image_path: handle_file(file),
});
foregroundLayer.src = result.data[0].url;  

هذا هو الجزء الأساسي: باستخدام عميل Gradio JS بدلاً من البرنامج الخام fetch() عند الاتصال، تمر الواجهة الأمامية عبر قائمة انتظار Gradio. وهذا يعني إدارة التزامن، وعدم تعارض طلبات GPU، ويمكنك حتى إظهار موضع قائمة الانتظار أو التقدم للمستخدم. كل شيء آخر، عرض النص، وتركيب الطبقات، والتصدير، يحدث في المتصفح.

ما يفتح هذا

وهنا ما كان غير ممكن قبل gradio.Server:

قبل بعد
تعني واجهة المستخدم المخصصة مغادرة Gradio بالكامل واجهة مستخدم مخصصة مع محرك Gradio الخلفي
لا توجد طريقة لتقديم HTML ثابت من تطبيق Gradio @app.get("https://huggingface.co/") يخدم أي شيء
gradio_client يعمل فقط مع تطبيقات مكونات Gradio @app.api() نقاط النهاية متوافقة مع العميل
الاختيار بين الأشعة تحت الحمراء وحرية التصميم الخاصة بـ Gradio يمكنك الحصول على حد سواء

مع gradio.Server, يعمل Gradio كإطار عمل خلفي، استخدم نظام واجهة المستخدم الخاص به عندما تريد ذلك، واجلب الواجهة الأمامية الخاصة بك عندما لا تريد ذلك.

إذا كنت تريد واجهة مستخدم Gradio، فيمكنك استخدامها gr.Blocks, gr.Interface, gr.ChatInterface. إذا كنت تريد واجهة المستخدم الخاصة بك، استخدم gradio.Server وإحضار ما تريد من الواجهة الأمامية. وفي كلتا الحالتين، ستحصل على استضافة Spaces، وانتظار API، gradio_client الوصول، والنظام البيئي الكامل للتردد العالي، والمزيد.

جربه

التطبيق مباشر على Spaces: ysharma/نص خلف الصورة

قم بتحميل أي صورة ذات موضوع واضح، وابدأ في وضع النص خلفها. جرب النتوء ثلاثي الأبعاد، وإمالة المنظور، وتأثيرات السكتة الدماغية، فهي تتحد بشكل جيد.

ما هو التالي

غطت هذه المشاركة الفكرة الأساسية: gradio.Server يتيح لك إقران أي واجهة أمامية مع واجهة Gradio الخلفية. هناك المزيد لاستكشافه، بما في ذلك تسجيل أداة MCP مع @app.mcp.tool(), تدفق SSE للحصول على التحديثات في الوقت الحقيقي، معالجة الدفعاتوأنماط إنشاء تطبيقات متعددة الصفحات ذات حالة مشتركة.

سنقوم بالبحث في تلك الموجودة في منشور المتابعة. ابقوا متابعين.

القراءة الموصى بها

شاركها.
اترك تعليقاً