Używaj zestawów SDK Microsoft Web IQ dla języków Python i TypeScript

Oficjalne zestawy SDK dla internetowego interfejsu API IQ Microsoft dostępne w Python i TypeScript. Te zestawy SDK zapewniają aplikacjom dostęp w czasie rzeczywistym do wyszukiwania w Internecie, wyszukiwania wideo, przeglądania, wyszukiwania wiadomości i wyszukiwania obrazów — zaprojektowane po to, aby ugruntować odpowiedzi modeli LLM za pomocą dokładnych i aktualnych informacji.

Python TypeScript
Pakiet pip install webiq npm install @microsoft/webiq
Czas działania Python 3.11+ Node.js 22+
Licencja MIT MIT

Installation

Python

pip install webiq

TypeScript

npm install @microsoft/webiq

Szybki start

Przewodnik po Pythonie

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)

Przewodnik 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

Klucz 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

Przekaż dowolny Azure Identity TokenCredential.

# 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(),
});

Zasoby i metody zestawu SDK

Klient uwidacznia pięć przestrzeni nazw zasobów: web, browse, videos, news i images.

client.web.search() — Wyszukaj w internecie i pobierz zawartość strony na potrzeby ugruntowania odpowiedzi.

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() — Znajdź odpowiednią zawartość wideo z opcjonalną obsługą listy odtwarzania.

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[] }

Przeglądaj

client.browse.fetch() — Wyodrębnij zawartość z dowolnego adresu URL. Obsługuje przeszukiwanie na żywo i renderowanie 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() — Uzyskaj najnowsze artykuły z wiadomościami z fragmentami najbardziej istotnymi dla zapytania.

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() — Znajdź obrazy z filtrowaniem według współczynnika proporcji, rozmiaru i bezpiecznego wyszukiwania.

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

Metody TypeScript używają tych samych parametrów w camelCase (np. maxResults, contentFormat, liveCrawl, aspectRatio). Zapoznaj się z powyższym przewodnikiem Szybki start języka TypeScript, aby zapoznać się z konwencją wywołań.


Wsparcie asynchroniczne

Obsługa Pythona

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())

Obsługa języka TypeScript

Język TypeScript jest natywnie asynchroniczny. Użyj Promise.all dla współbieżności:

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

Configuration

Limit czasu i ponowienie próby

Klient akceptuje timeout i retry jako opcje najwyższego poziomu. Ustawienie dla każdego wywołania timeout w każdej metodzie zasobu zastępuje wartość domyślną na poziomie klienta. Zestaw SDK automatycznie ponawia 408, 502, 500, 503, 504 z wykładniczym opóźnieniem i jitterem; jeśli body odpowiedzi zawiera pole retryAfter (np. "30s"), zestaw SDK czeka na tę wskazówkę zamiast opóźnienia backoff. 429 i 430nigdy nie są automatycznie ponawiane — są natychmiast zwracane jako RateLimitError, aby aplikacja mogła zastosować własną strategię ponawiania z opóźnieniem. Limity czasu po stronie klienta również nie są ponawiane (powodują zgłoszenie 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,
  }),
});

Dostosowany klient HTTP (serwer proxy, TLS, ...)

Zaawansowane ustawienia HTTP — serwer proxy, niestandardowy protokół TLS, pula połączeń itp. Zestaw SDK nie zamyka klientów należących do wywołującego.

# 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 }),
});

Anulowanie (TypeScript)

Każda metoda zasobu TypeScript akceptuje AbortSignal za pośrednictwem options.signal. Po przerwaniu sygnału żądanie w locie zostanie anulowane, ponowne próby zostaną zatrzymane, a element reason sygnału zostanie ponownie zgłoszony bez zmian (bez zawijania 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 telemetrii

Monitoruj każde żądanie/odpowiedź na potrzeby rejestrowania, metryk lub debugowania.

# 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)`);
  },
});

Pola TelemetryEvent:

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

Obsługa błędów

Oba zestawy SDK zapewniają wyjątki typizowane do ustrukturyzowanej obsługi błędów. Wszystkie błędy dziedziczą z WebIQError.

Wyjątek Status HTTP Wyzwalacz
AuthenticationError 401 Nieprawidłowy lub brak klucza interfejsu API
PermissionDeniedError 403 Uwierzytelnione, ale brak uprawnień do zasobu
RateLimitError 429, 430 Przekroczono limit liczby żądań / limit żądań współbieżnych
APIStatusError 400, 404, 500, 503, 504, ... Wszystkie inne błędy HTTP
APIConnectionError — Problemy z siecią, błędy DNS, przekroczenia limitu czasu
WebIQError — Klasa podstawowa dla wszystkich błędów zestawu SDK

PermissionDeniedError i RateLimitError są oba podklasami APIStatusError, więc szersza procedura obsługi w APIStatusError nadal je przechwytuje. Zestaw SDK nie ponawia automatycznie odpowiedzi HTTP/API 429 / 430 — wskazówka dotycząca opóźnienia ponowienia jest udostępniana w error.retry_after (Python) / error.retryAfter (TypeScript), aby aplikacja mogła odpowiednio zareagować.

# 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);
  }
}

Sprawdzanie szczegółów błędu

Wszystkie APIStatusError wystąpienia (w tym PermissionDeniedError i RateLimitError) udostępniają pełną treść ciała odpowiedzi błędu. Większość problemów z walidacją danych wejściowych w zestawie SDK Python (np. max_results poza zakresem, puste query) jest przechwytywana po stronie klienta przez Pydantic i zgłaszana pydantic.ValidationError przed wysłaniem żądania; wzorzec poniżej ma zastosowanie, gdy serwer odrzuca żądanie. browse.fetch to wygodny sposób wywołania takiego błędu — brakujący lub odfiltrowany adres URL pojawia się jako błąd ustrukturyzowany:

# 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);

Wskazówki dotyczące debugowania

  • traceId — każda odpowiedź zawiera pole traceId do debugowania end-to-end. Dołącz go podczas kontaktowania się z pomocą techniczną.
  • Hook telemetrii — dołącz wywołanie zwrotne w celu rejestrowania każdej próby żądania, kodu stanu i czasów.
  • Treść błędu — APIStatusError.body zawiera pełną odpowiedź serwera, w tym errorCode, errorCategory, technicalDetailsi traceId.