یک پلی‌فیل آزمایشی برای Prompt API

منتشر شده: ۱۴ مه ۲۰۲۶

با استفاده از Prompt API در کروم، می‌توانید با استفاده از یک API مرورگر سطح بالا در window.LanguageModel با یک LLM تعامل داشته باشید. با این حال، هنوز پشتیبانی محدودی برای این امر وجود دارد و پیاده‌سازی آن فرآیندی پیچیده است.

مرورگر سیستم عامل پشتیبانی شده سیستم عامل پشتیبانی نشده موقعیت
کروم ویندوز، macOS، لینوکس، ChromeOS (کروم‌بوک پلاس) اندروید، آی‌او‌اس ✅ پشتیبانی شده
لبه ویندوز، macOS اندروید، آی‌او‌اس ✅ پشتیبانی شده
سافاری 📋 موقعیت مشخص شد
فایرفاکس 📋 موقعیت مشخص شد

در عین حال، توسعه‌دهندگان در برنامه پیش‌نمایش اولیه، اشتیاق خود را برای رابط برنامه‌نویسی کاربردی Prompt به اشتراک گذاشته‌اند. در دسترس بودن این رابط برنامه‌نویسی کاربردی، چالش سازگاری را برای آینده‌ای قابل پیش‌بینی ایجاد می‌کند.

راه حل

به همین دلیل است که ما در حال انتشار یک چندمنظوره آزمایشی Prompt API سازگار با مشخصات هستیم (به کد منبع در GitHub مراجعه کنید) که به طور دقیق Prompt API را بر روی ارائه دهندگان backend ابری قابل تنظیم و همچنین بر روی یک ارائه دهنده backend محلی در قالب Transformers.js پیاده سازی می کند.

از پلی‌فیل استفاده کنید

برای استفاده از polyfill، مراحل زیر را انجام دهید:

  1. دانلود polyfill از npm :

    npm install prompt-api-polyfill
    
  2. انتخاب کنید که آیا می‌خواهید از یک ارائه‌دهنده‌ی بک‌اند ابری یا یک ارائه‌دهنده‌ی بک‌اند محلی استفاده کنید:

    • ارائه‌دهنده خدمات ابری: داده‌های کاربر برای پردازش از راه دور به فضای ابری ارسال می‌شود، اما لازم نیست منتظر بمانید تا یک مدل محلی در دسترس قرار گیرد. شما مسئول هرگونه هزینه متحمل شده طبق اطلاعات قیمت‌گذاری ارائه‌دهنده فضای ابری خود هستید.
    • ارائه‌دهنده بک‌اند محلی: داده‌های کاربر در مرورگر باقی می‌ماند و به صورت محلی پردازش می‌شود، اما شما باید یک مدل را دانلود کنید که برخلاف API واقعی Prompt، نمی‌تواند بین منابع مختلف به اشتراک گذاشته شود. پردازش محلی هیچ هزینه‌ای ندارد.

فضای ابری

از بین بک‌اندهای ابری، یکی را انتخاب کنید و یک کلید API (و هرگونه اعتبارنامه اضافی) برای ارائه‌دهنده بک‌اند خود دریافت کنید.

وقتی کلید API خود را دریافت کردید، جزئیات را در فایل پیکربندی .env.json خود وارد کنید. اگر modelName مشخص نکنید، polyfill از مدل پیش‌فرض هر backend استفاده می‌کند، اما اگر این کار را انجام دهید، می‌توانید یکی از مدل‌های پشتیبانی شده توسط هر backend را انتخاب کنید.

{
  "apiKey": "y0ur-Api-k3Y",
  "modelName": "model-name"
}

بک‌اند محلی

اگر تصمیم دارید از یک ارائه‌دهنده بک‌اند محلی مبتنی بر Transformers.js استفاده کنید، فقط به یک کلید API ساختگی نیاز دارید. با این حال، می‌توانید دستگاهی را که Transformers.js باید از آن استفاده کند، پیکربندی کنید. برای حداکثر کارایی، "webgpu" و برای حداکثر سازگاری "wasm" را انتخاب کنید. می‌توانید تنظیمات پیش‌فرض را به صورت اختیاری تغییر دهید. مدل دیگری را از کاتالوگ مدل‌های سازگار Hugging Face انتخاب کنید. برای برخی از مدل‌ها، می‌توانید با استفاده از پارامتر dtype ، از بین کوانتیزاسیون‌های مختلف انتخاب کنید.

{
  "apiKey": "dummy",
  "device": "webgpu",
  "dtype": "q4f16",
  "modelName": "onnx-community/gemma-3-1b-it-ONNX-GQA"
};

پیکربندی چندپر کردنی (polyfill)

با قرار دادن فایل پیکربندی، اکنون می‌توانید استفاده از polyfill را در برنامه خود شروع کنید.

  1. فایل پیکربندی را وارد کنید و آن را به یک متغیر سراسری با نام مناسب اختصاص دهید، که در آن $BACKEND همان backend انتخابی شما است: window.$BACKEND_CONFIG .
  2. از یک ایمپورت پویا برای بارگذاری پلی‌فیل فقط زمانی که مرورگر اصلی از آن پشتیبانی نمی‌کند، استفاده کنید.
  3. توابع API مربوط به Prompt را فراخوانی کنید .
import config from './.env.json' with { type: 'json' };

// Set $BACKEND_CONFIG to select a backend
window.$BACKEND_CONFIG = config;

if (!('LanguageModel' in window)) {
  await import('prompt-api-polyfill');
}

const session = await LanguageModel.create({
  expectedInputs: [{type: 'text', languages: ['en']}],
  expectedOutputs: [{type: 'text', languages: ['en']}],
});
await session.prompt('Tell me a joke!');

این polyfill از خروجی ساختاریافته پشتیبانی می‌کند (به جز برای بک‌اند Transformers.js)، با ورودی چندوجهی سروکار دارد (به جز برای بک‌اند OpenAI که صدا و تصویر را با هم پشتیبانی نمی‌کند، فقط به صورت جداگانه) و در برابر مجموعه کامل تست‌های پلتفرم وب برای LanguageModel آزمایش می‌شود.

برای اطلاعات بیشتر در مورد پیشینه و جزئیات استفاده و همچنین کد منبع، به فایل README در مخزن GitHub مراجعه کنید.

تفاوت با API Prompt مرورگر

اگر polyfill توسط مدل‌های ابری پشتیبانی شود، برخی از مزایای اجرای سمت کلاینت دیگر اعمال نمی‌شوند. یعنی، شما دیگر نمی‌توانید پردازش محلی داده‌های حساس را تضمین کنید، اگرچه سیاست‌های حفظ حریم خصوصی ارائه‌دهنده backend شما همچنان اعمال می‌شود. همچنین برنامه شما دیگر نمی‌تواند از هوش مصنوعی در زمانی که کاربر آفلاین است استفاده کند. برای فهمیدن اینکه آیا آنلاین هستید یا آفلاین، می‌توانید به رویدادهای مربوطه گوش دهید.

window.addEventListener("offline", (e) => {
  console.log("offline");
});

window.addEventListener("online", (e) => {
  console.log("online");
});

اگر استنتاج هوش مصنوعی بر روی یک مدل در فضای ابری اجرا شود، هیچ مدل محلی برای دانلود وجود ندارد. پلی‌فیل رویدادهای downloadprogress جعل می‌کند، بنابراین برای برنامه شما طوری به نظر می‌رسد که انگار مدل داخلی از قبل دانلود شده است، به این معنی که دو رویداد وجود خواهد داشت، یکی با مقدار loaded 0 و دیگری با 1 ، که همان چیزی است که مشخصات لازم دارد.

در استنتاج مبتنی بر ابر، برخلاف استنتاج روی دستگاه، هنگام فراخوانی APIها از ارائه‌دهنده بک‌اند مورد نظر شما، هزینه بالقوه‌ای وجود دارد. اطلاعات قیمت‌گذاری را بررسی کنید، مانند اطلاعات مربوط به Gemini API . اگر هزینه هر توکن را می‌دانید، می‌توانید از اطلاعات contextUsage مربوط به Prompt API برای محاسبه هزینه استفاده کنید.

const COST_PER_TOKEN = 123;
const COST_LIMIT = 456;

let costSoFar = 0;

const session = await LanguageModel.create(options);

/…/

if (costSoFar < COST_LIMIT) {
  await session.prompt('Tell me a joke.');
  costSoFar = session.contextUsage * COST_PER_TOKEN;
} else {
  // Show premium AI plan promo.
}

وقتی مستقیماً از یک برنامه تلفن همراه یا وب، یک API ابری را فراخوانی می‌کنید (برای مثال، APIهایی که امکان دسترسی به مدل‌های هوش مصنوعی مولد را فراهم می‌کنند)، کلید API در برابر سوءاستفاده توسط کلاینت‌های غیرمجاز آسیب‌پذیر است. برای کمک به محافظت از این APIها، اگر از Firebase AI Logic Hybrid SDK استفاده می‌کنید، باید از Firebase App Check استفاده کنید تا تأیید کنید که تمام فراخوانی‌های API ورودی از برنامه واقعی شما هستند. با برخی از ارائه‌دهندگان ابری مانند گوگل، می‌توانید بررسی‌های دقیقی در مورد مبدا نیز اعمال کنید تا مطمئن شوید که فقط وب‌سایت‌های مجاز می‌توانند از API استفاده کنند.

به جای محدودیت‌های Prompt API، برای مثال، در مورد contextWindow مربوط به session، محدودیت‌های ارائه‌دهنده backend اعمال می‌شود. برای contextWindow ، این محدودیت‌ها معمولاً بسیار بیشتر از روی دستگاه هستند و شما می‌توانید مقادیر بیشتری از داده‌ها را در فضای ابری پردازش کنید، بنابراین اگرچه باید از تفاوت آگاه باشید، در عمل، احتمالاً با این مشکل مواجه نخواهید شد.

بک‌اند خودتان را بسازید

برای افزودن ارائه‌دهنده‌ی بک‌اند خودتان، این مراحل را دنبال کنید:

کلاس پایه backend را گسترش دهید

یک فایل جدید در دایرکتوری backends/ ایجاد کنید، برای مثال، backends/custom-backend.js . شما باید کلاس PolyfillBackend را ارث‌بری کنید و متدهای اصلی که رابط مورد انتظار را برآورده می‌کنند، پیاده‌سازی کنید.

import PolyfillBackend from './base.js';
import { DEFAULT_MODELS } from './defaults.js';

export default class CustomBackend extends PolyfillBackend {
  constructor(config) {
    // config typically comes from a window global (e.g., window.CUSTOM_CONFIG)
    super(config.modelName || DEFAULT_MODELS.custom.modelName);
  }

  // Check if the backend is configured (e.g., API key is present), if given
  // combinations of modelName and options are supported, or, for local model,
  // if the model is available.
  static availability(options) {
    return window.CUSTOM_CONFIG?.apiKey ? 'available' : 'unavailable';
  }

  // Initialize the underlying SDK or API client. With local models, use
  // monitorTarget to report model download progress to the polyfill.
  createSession(options, sessionParams, monitorTarget) {
    // Return the initialized session or client instance
  }

  // Non-streaming prompt execution
  async generateContent(contents) {
    // contents: Array of { role: 'user'|'model', parts: [{ text: string }] }
    // Return: { text: string, usage: number }
  }

  // Streaming prompt execution
  async generateContentStream(contents) {
    // Return: AsyncIterable yielding chunks
  }

  // Token counting for quota/usage tracking
  async countTokens(contents) {
    // Return: total token count (number)
  }
}

پشتیبان خود را ثبت کنید

این polyfill از استراتژی "اولویت تطبیق اول" بر اساس پیکربندی سراسری استفاده می‌کند. شما باید backend خود را در فایل prompt-api-polyfill.js با اضافه کردن آن به آرایه static #backends ثبت کنید:

// prompt-api-polyfill.js
static #backends = [
  // ... existing backends
  {
    config: 'CUSTOM_CONFIG', // The global object to look for on `window`
    path: './backends/custom-backend.js',
  },
];

تنظیم یک مدل پیش‌فرض

شناسه مدل پشتیبان را در backends/defaults.js تعریف کنید. این زمانی استفاده می‌شود که کاربر یک جلسه را بدون مشخص کردن یک modelName خاص، مقداردهی اولیه می‌کند.

// backends/defaults.js
export const DEFAULT_MODELS = {
  // ...
  custom: 'custom-model-pro-v1',
};

فعال کردن توسعه و آزمایش محلی

این پروژه از یک اسکریپت اکتشافی ( scripts/list-backends.js ) برای تولید ماتریس‌های تست استفاده می‌کند. برای افزودن backend جدید خود به اجراکننده تست، یک فایل .env-[name].json (برای مثال، .env-custom.json ) در دایرکتوری ریشه ایجاد کنید:

{
  "apiKey": "your-api-key-here",
  "modelName": "custom-model-pro-v1"
}

تأیید با تست‌های پلتفرم وب (WPT)

مرحله آخر، حصول اطمینان از انطباق با استانداردها است. از آنجا که polyfill بر اساس مشخصات فنی طراحی شده است، هر backend جدید باید تست‌های رسمی (یا آزمایشی) پلتفرم وب را با موفقیت پشت سر بگذارد:

npm run test:wpt

این مرحله‌ی تأیید تضمین می‌کند که backend شما مواردی مانند AbortSignal ، اعلان‌های سیستم و قالب‌بندی تاریخچه را دقیقاً مطابق با مشخصات Prompt API مدیریت می‌کند.

نتیجه‌گیری

این polyfill به شما کمک می‌کند تا از Prompt API در تمام پلتفرم‌ها و دستگاه‌ها استفاده کنید. با کدنویسی بر اساس API خوش‌تعریف Prompt API، خود را از ارائه‌دهندگان ابری مستقل‌تر می‌کنید و تا حد امکان به پلتفرم نزدیک می‌مانید.

در دستگاه‌هایی که از Prompt API پشتیبانی می‌کنند، polyfill حتی بارگذاری نمی‌شود، بنابراین شما از دانلود کدی که کاربران اجرا نمی‌کنند، جلوگیری می‌کنید. اگر بازخوردی دارید یا با مشکلی مواجه شدید، یک مشکل در GitHub باز کنید . از دریافت پاسخ خوشحال می‌شویم!