Gunakan Microsoft Web IQ SDK untuk Python dan TypeScript

SDK resmi untuk MICROSOFT Web IQ API, tersedia di Python dan TypeScript. SDK-SDK ini memberi aplikasi Anda akses real-time ke pencarian web, pencarian video, penelusuran, pencarian berita, dan pencarian gambar — dirancang untuk mendasarkan respons LLM pada informasi akurat dan terkini.

Python TypeScript
Paket pip install webiq npm install @microsoft/webiq
Runtime Python 3.11+ Node.js 22+
Lisensi MIT MIT

Installation

Python

pip install webiq

TypeScript

npm install @microsoft/webiq

Quickstart

Panduan Python

import os
from webiq import WebIQClient
from webiq.types import BrowseContentFormat, ContentFormat

with WebIQClient(api_key=os.environ["WEBIQ_API_KEY"]) as client:
    # Web search
    web = client.web.search(
        "Python programming",
        max_results=5,
        content_format=ContentFormat.passage,
    )
    for r in web.webResults or []:
        print(r.title, r.url)

    # Videos search
    videos = client.videos.search("machine learning tutorial", max_results=5)
    for v in videos.videoResults or []:
        print(v.title, v.length)

    # Browse a URL
    page = client.browse.fetch("https://www.microsoft.com", content_format=BrowseContentFormat.markdown)
    print(page.content)

    # News search
    news = client.news.search("technology", max_results=5)
    for item in news.newsResults or []:
        print(item.title, "-", item.source)

    # Image search
    images = client.images.search("golden gate bridge", max_results=5)
    for img in images.imageResults or []:
        print(img.title, img.url)

Panduan TypeScript

import { WebIQClient, BrowseContentFormat, ContentFormat } from '@microsoft/webiq';

async function main() {
  const client = new WebIQClient({ apiKey: process.env.WEBIQ_API_KEY });

  // Web search
  const web = await client.web.search('TypeScript programming', {
    maxResults: 5,
    contentFormat: ContentFormat.PASSAGE,
  });
  for (const r of web.webResults ?? []) console.log(r.title, r.url);

  // Videos search
  const videos = await client.videos.search('machine learning tutorial');
  for (const v of videos.videoResults ?? []) console.log(v.title, v.length);

  // Browse a URL
  const page = await client.browse.fetch('https://www.microsoft.com', {
    contentFormat: BrowseContentFormat.MARKDOWN,
  });
  console.log(page.content);

  // News search
  const news = await client.news.search('technology', { maxResults: 5 });
  for (const item of news.newsResults ?? []) console.log(item.title, '-', item.source);

  // Image search
  const images = await client.images.search('golden gate bridge', { maxResults: 5 });
  for (const img of images.imageResults ?? []) console.log(img.title, img.url);

  await client.close();
}

main().catch(console.error);

Authentication

Kunci API

# Python
import os
from webiq import WebIQClient

client = WebIQClient(api_key=os.environ["WEBIQ_API_KEY"])
// TypeScript
import { WebIQClient } from '@microsoft/webiq';

const client = new WebIQClient({ apiKey: process.env.WEBIQ_API_KEY });

Microsoft Entra ID

Teruskan Azure Identity TokenCredential apa pun.

# Python — uses `azure-identity`
from azure.identity import DefaultAzureCredential
from webiq import WebIQClient

client = WebIQClient(credential=DefaultAzureCredential())
// TypeScript — uses `@azure/identity`
import { DefaultAzureCredential } from '@azure/identity';
import { WebIQClient } from '@microsoft/webiq';

const client = new WebIQClient({
  credential: new DefaultAzureCredential(),
});

Sumber daya dan metode SDK

Klien mengekspos lima namespace sumber daya: web, videos, browse, news, dan images.

client.web.search() — Cari web dan dapatkan konten halaman untuk dasar referensi.

response = client.web.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=10,                # 1–50 (default 10)
    language="en",                 # ISO 639-1 code
    region="US",                   # Country/region code
    location="lat:40.7;long:-74.0",  # Optional
    content_format=ContentFormat.passage,   # passage (default) | text | html | markdown (full-page content)
    max_length=3000,               # Max content chars (default 3000)
)
# response.webResults → list of { title, url, content, lastUpdatedAt, crawledAt, language, isAdult }

client.videos.search() — Temukan konten video yang relevan dengan dukungan daftar putar opsional.

response = client.videos.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=30,                # 1–30 (default 30)
    language="en",
    region="US",
    enable_playlist=True,          # Include playlist results
    freshness="month",             # week | month | year
)
# response.videoResults → list of { title, url, description, length, viewCount, moments[], thumbnailUrl, ... }
# response.playlists   → list of { title, videos[] }

Jelajah

client.browse.fetch() — Ekstrak konten dari URL apa pun. Mendukung perayapan langsung dan rendering JavaScript.

response = client.browse.fetch(
    url="https://www.microsoft.com",   # Required
    max_length=10000,                  # Max content chars, 1–500000
    live_crawl="fallback",             # "none" (cached only, default) | "fallback" (crawl if not cached) | "force" (always crawl, bypass cache)
    include_web_links=True,            # Include outbound hyperlinks
    include_image_links=True,          # Include image URLs
    render_dynamic_pages=False,        # JS rendering (requires live_crawl="fallback")
    content_format=BrowseContentFormat.markdown,   # text | html | markdown
)
# response → { url, title, content, isAdult, lastUpdatedAt, crawledAt, retryAfter, traceId }

client.news.search() — Dapatkan artikel berita terbaru dengan bagian yang paling relevan dengan kueri.

response = client.news.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=10,                # 1–20 (default 10)
    language="en",
    region="US",
    location="lat:40.7;long:-74.0",  # Optional
    content_format=ContentFormat.passage,
    max_length=3000,
)
# response.newsResults → list of { title, url, content, source, lastUpdatedAt, thumbnail, isAdult }

client.images.search() — Temukan gambar dengan pemfilteran berdasarkan rasio aspek, ukuran, dan pencarian yang aman.

from webiq.types import ImageAspectRatio, ImageSize, SafeSearch

response = client.images.search(
    query="search terms",          # Required, 1–1000 chars
    max_results=30,                # 1–30 (default 30)
    language="en",
    region="US",
    aspect_ratio=ImageAspectRatio.wide,   # square | wide | tall
    image_size=ImageSize.large,           # small | medium | large | extraLarge
    safe_search=SafeSearch.strict,        # off | strict
    watermark_free=True,
)
# response.imageResults → list of { title, url, hostPageUrl, caption, width, height, thumbnailUrl, ... }

Note

Metode TypeScript menggunakan parameter yang sama dalam camelCase (misalnya, maxResults, contentFormat, liveCrawl, aspectRatio). Lihat Mulai Cepat TypeScript di atas untuk konvensi pemanggilan.


Dukungan Asinkron

Dukungan Python

import asyncio
from webiq import WebIQAsyncClient

async def main():
    async with WebIQAsyncClient(api_key="your-api-key") as client:
        web, news = await asyncio.gather(
            client.web.search("async Python"),
            client.news.search("programming"),
        )
        for r in web.webResults or []:
            print(r.title)

asyncio.run(main())

Dukungan TypeScript

TypeScript mendukung asinkron secara bawaan. Gunakan Promise.all untuk konkurensi:

const [web, news, videos] = await Promise.all([
  client.web.search('TypeScript'),
  client.news.search('programming'),
  client.videos.search('tutorial'),
]);

Configuration

Batas Waktu dan Coba Ulang

Klien menerima timeout dan retry sebagai opsi tingkat atas. Per-panggilan timeout pada setiap metode sumber daya menggantikan default tingkat klien. SDK mencoba kembali 408, 500, 502, 503, 504 secara otomatis dengan backoff eksponensial dan jitter; jika body respons menyertakan bidang retryAfter (misalnya "30s"), SDK menunggu petunjuk tersebut alih-alih penundaan backoff. 429 dan 430tidak pernah dicoba ulang secara otomatis — keduanya segera muncul sebagai RateLimitError sehingga aplikasi Anda dapat menerapkan kebijakan back-off sendiri. Batas waktu sisi klien juga tidak dicoba kembali (akan memunculkan APIConnectionError).

# Python
from webiq import WebIQClient, RetryPolicy

client = WebIQClient(
    api_key="your-api-key",
    timeout=10.0,                  # seconds (default: 10.0)
    retry=RetryPolicy(
        max_retries=2,             # defaults shown
        base_delay_s=0.25,
        max_delay_s=4.0,
    ),
)

# Per-call override
response = client.web.search("query", language="de", region="DE", timeout=30.0)
// TypeScript
import { WebIQClient, RetryPolicy } from '@microsoft/webiq';

const client = new WebIQClient({
  apiKey: 'your-api-key',
  timeout: 10000, // milliseconds (default: 10000)
  retry: new RetryPolicy({
    maxRetries: 2, // defaults shown
    baseDelaySeconds: 0.25,
    maxDelaySeconds: 4.0,
  }),
});

Klien HTTP yang dikustomisasi (proksi, TLS, ...)

Untuk pengaturan HTTP tingkat lanjut — proksi, TLS kustom, pooling koneksi, dll. SDK tidak menutup klien milik pemanggil.

# Python — pass a pre-configured `httpx.Client` via `http_client`
import httpx
from webiq import WebIQClient, WebIQAsyncClient

# sync
http_client = httpx.Client(
  base_url="https://api.microsoft.ai/v3",
  proxy="http://proxy:8080",
)
client = WebIQClient(api_key="your-api-key", http_client=http_client)

# async
http_client = httpx.AsyncClient(
  base_url="https://api.microsoft.ai/v3",
  proxy="http://proxy:8080",
)
client = WebIQAsyncClient(api_key="your-api-key", http_client=http_client)
// TypeScript — pass a custom `fetchFn` that wraps the global `fetch`
import { ProxyAgent } from 'undici';
import { WebIQClient } from '@microsoft/webiq';

const proxyAgent = new ProxyAgent('http://my-proxy:8080');

const client = new WebIQClient({
  apiKey: 'your-api-key',
  // Spread `init` so headers, body, and the SDK's internal `AbortSignal` are preserved.
  fetchFn: (url, init) => fetch(url, { ...init, dispatcher: proxyAgent }),
});

Pembatalan (TypeScript)

Setiap metode sumber daya TypeScript menerima AbortSignal melalui options.signal. Ketika sinyal di-abort, permintaan yang sedang berlangsung dibatalkan, percobaan ulang dihentikan, dan sinyal reason dilemparkan kembali tidak berubah (tidak ada pembungkusan APIConnectionError).

// Apply a wall-clock budget that includes retries (the `timeout` option is per attempt only)
const result = await client.web.search('latest news', {
  signal: AbortSignal.timeout(5_000),
});

// Combine signals (e.g. an inbound request signal plus a wall-clock cap)
const result2 = await client.web.search('latest news', {
  signal: AbortSignal.any([req.signal, AbortSignal.timeout(5_000)]),
});

Hook Telemetri

Pantau setiap permintaan/respons untuk pengelogan, metrik, atau penelusuran kesalahan.

# Python
from webiq import WebIQClient, TelemetryEvent

def on_request(event: TelemetryEvent):
    print(f"{event.method} {event.path} → {event.status_code} ({event.elapsed_ms}ms)")

client = WebIQClient(api_key="your-api-key", telemetry_hook=on_request)
// TypeScript
import { WebIQClient, TelemetryEvent } from '@microsoft/webiq';

const client = new WebIQClient({
  apiKey: 'your-api-key',
  telemetryHook: (event: TelemetryEvent) => {
    console.log(`${event.method} ${event.path} → ${event.statusCode} (${event.elapsedMs}ms)`);
  },
});

Kolom TelemetryEvent adalah:

  • Python (snake_case): method, path, transport, attempt, status_code, request_id, trace_id, retry_after, elapsed_ms, error, error_body
  • TypeScript (camelCase): method, path, transport, statusCode, attempt, requestId, traceId, retryAfter, elapsedMs, error, errorBody

Penanganan Kesalahan

Kedua SDK memberikan exception bertipe untuk penanganan kesalahan terstruktur. Semua kesalahan diwariskan dari WebIQError.

Pengecualian HTTP Status Trigger
AuthenticationError 401 Kunci API tidak valid atau hilang
PermissionDeniedError 403 Terautentikasi, tetapi tidak diizinkan mengakses resource
RateLimitError 429, 430 Batas laju / batas permintaan bersamaan terlampaui
APIStatusError 400, 404, 500, 503, 504, ... Semua kesalahan HTTP lainnya
APIConnectionError — Masalah jaringan, kegagalan DNS, waktu habis
WebIQError — Kelas dasar untuk semua kesalahan SDK

PermissionDeniedError dan RateLimitError keduanya adalah subkelas dari APIStatusError, sehingga handler yang lebih luas pada APIStatusError masih menangkap mereka. SDK tidak secara otomatis mencoba ulang respons 429 / 430 — petunjuk back-off server tersedia melalui error.retry_after (Python) / error.retryAfter (TypeScript) agar aplikasi Anda bertindak.

# Python
from webiq import (
    WebIQError,
    APIConnectionError,
    APIStatusError,
    AuthenticationError,
    PermissionDeniedError,
    RateLimitError,
)

try:
    response = client.web.search("test")
except PermissionDeniedError as e:
    # 403 — authenticated, but not allowed to call this resource
    print(f"Forbidden (HTTP {e.status_code}): {e}")
except AuthenticationError as e:
    # 401 — invalid or missing API key
    print(f"Auth failed (HTTP {e.status_code}): {e}")
except RateLimitError as e:
    # 429 or 430 — rate limit / concurrent-request limit (never auto-retried)
    print(f"Rate limited. Retry after: {e.retry_after}")
except APIStatusError as e:
    print(f"API error (HTTP {e.status_code}): {e}")
except APIConnectionError as e:
    print(f"Connection failed: {e}")
except WebIQError as e:
    print(f"SDK error: {e}")
// TypeScript
import {
  WebIQError,
  APIConnectionError,
  APIStatusError,
  AuthenticationError,
  PermissionDeniedError,
  RateLimitError,
} from '@microsoft/webiq';

try {
  const results = await client.web.search('test');
} catch (error) {
  if (error instanceof PermissionDeniedError) {
    // 403 — authenticated, but not allowed to call this resource
    console.error(`Forbidden (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof AuthenticationError) {
    // 401 — invalid or missing API key
    console.error(`Auth failed (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof RateLimitError) {
    // 429 or 430 — rate limit / concurrent-request limit (never auto-retried)
    console.error(`Rate limited. Retry after: ${error.retryAfter}`);
  } else if (error instanceof APIStatusError) {
    console.error(`API error (HTTP ${error.statusCode}):`, error.message);
  } else if (error instanceof APIConnectionError) {
    console.error('Connection failed:', error.message);
  }
}

Memeriksa Detail Kesalahan

Semua APIStatusError instans (termasuk PermissionDeniedError dan RateLimitError) mengekspos isi respons kesalahan penuh. Sebagian besar masalah validasi input pada SDK Python (misalnya max_results di luar rentang, kosong query) ditangkap di sisi klien oleh Pydantic dan memunculkan pydantic.ValidationError sebelum permintaan dikirim; pola di bawah ini berlaku ketika server menolak permintaan. browse.fetch adalah cara mudah untuk memicunya — url yang hilang atau difilter muncul sebagai kesalahan terstruktur:

# Python
from webiq import WebIQClient
from webiq.errors import APIStatusError

client = WebIQClient(api_key="your-api-key")

try:
    response = client.browse.fetch("https://www.not-microsoft.com")
except APIStatusError as e:
    print(f"Status: {e.status_code}")                          # e.g. 404
    print(f"Message: {e}")                                      # e.g. "No result is found"
    if isinstance(e.body, dict):
        print(f"Error code: {e.body.get('errorCode')}")        # e.g. "BrowseApiDocNotFound"
        print(f"Category: {e.body.get('errorCategory')}")      # e.g. "UserError"
        print(f"Details: {e.body.get('technicalDetails')}")    # e.g. "NotFound"
        print(f"Trace ID: {e.body.get('traceId')}")
        print(f"Retry after: {e.body.get('retryAfter')}")
// TypeScript
import { WebIQClient, APIStatusError } from '@microsoft/webiq';

async function main() {
  const client = new WebIQClient({ apiKey: 'your-api-key' });

  try {
    await client.browse.fetch('https://www.not-microsoft.com');
  } catch (error) {
    if (error instanceof APIStatusError) {
      console.error(`Status: ${error.statusCode}`); // e.g. 404
      console.error(`Message: ${error.message}`); // e.g. "No result is found"

      // Full error body from the API response
      if (error.body && typeof error.body === 'object') {
        const body = error.body as Record<string, unknown>;
        console.error(`Error code: ${body.errorCode}`); // e.g. "BrowseApiDocNotFound"
        console.error(`Category: ${body.errorCategory}`); // e.g. "UserError"
        console.error(`Details: ${body.technicalDetails}`); // e.g. "NotFound"
        console.error(`Trace ID: ${body.traceId}`); // for debugging with support
        console.error(`Retry after: ${body.retryAfter}`); // for retryable errors
      }
    }
  }
}

main().catch(console.error);

Tips Penelusuran Kesalahan

  • traceId — setiap respons menyertakan traceId bidang untuk penelusuran kesalahan end-to-end. Sertakan saat menghubungi dukungan.
  • hook telemetri — lampirkan panggilan balik untuk mencatat setiap upaya permintaan, kode status, dan waktu.
  • Isi kesalahan — APIStatusError.body ini berisi respons server lengkap, termasuk errorCode, technicalDetails, errorCategory, dan traceId.