GenCN UI

GenUI Provider

Provider component for Chrome AI APIs (Summarizer, Selection Summarizer, Writer, Rewriter, Language Detector).

Preview

Loading preview...

Installation

npx shadcn@latest add https://gencn-ui.encatch.com/r/genui-provider.json
"use client";

import * as React from "react";
import { SummarizeSelection } from "./genui-summarize-selection";
import {
  SummarizeOptions,
  SummarizerOptions,
} from "@/registry/new-york/gencn-ui/items/shared/genui-types";
import {
  WriterOptions,
  RewriterOptions,
  WriteOptions,
  RewriteOptions,
  LanguageDetectorOptions,
  DetectedLanguage,
  AvailabilityStatus,
  LanguageModelAvailabilityStatus,
  PromptOptions,
} from "@/registry/new-york/gencn-ui/items/shared/genui-types";


export interface GenUIContextValue extends LanguageModelAvailabilityStatus {
  // State
  isSupported: boolean | null;
  isWriterSupported: boolean | null;
  isRewriterSupported: boolean | null;
  isLanguageDetectorSupported: boolean | null;
  availability: AvailabilityStatus;
  writerAvailability: AvailabilityStatus;
  rewriterAvailability: AvailabilityStatus;
  languageDetectorAvailability: AvailabilityStatus;
  downloadProgress: number;
  writerDownloadProgress: number;
  rewriterDownloadProgress: number;
  languageDetectorDownloadProgress: number;
  isDownloading: boolean;
  isWriterDownloading: boolean;
  isRewriterDownloading: boolean;
  isLanguageDetectorDownloading: boolean;
  error: string | null;

  // Functions
  checkAvailability: () => Promise<AvailabilityStatus>;
  checkWriterAvailability: () => Promise<AvailabilityStatus>;
  checkRewriterAvailability: () => Promise<AvailabilityStatus>;
  checkLanguageDetectorAvailability: () => Promise<AvailabilityStatus>;
  createSummarizer: (options?: SummarizerOptions) => Promise<any>;
  createWriter: (options?: WriterOptions) => Promise<any>;
  createRewriter: (options?: RewriterOptions) => Promise<any>;
  createLanguageDetector: (options?: LanguageDetectorOptions) => Promise<any>;
  summarize: (
    text: string,
    options?: SummarizeOptions & {
      streaming?: boolean;
      onChunk?: (chunk: string) => void;
    }
  ) => Promise<string>;
  write: (
    prompt: string,
    options?: WriteOptions & {
      streaming?: boolean;
      onChunk?: (chunk: string) => void;
    }
  ) => Promise<string>;
  rewrite: (
    text: string,
    options?: RewriteOptions & {
      streaming?: boolean;
      onChunk?: (chunk: string) => void;
    }
  ) => Promise<string>;
  detectLanguage: (text: string) => Promise<DetectedLanguage[]>;
  resetError: () => void;
}

const GenUIContext = React.createContext<GenUIContextValue | undefined>(
  undefined
);

export interface GenUIProviderProps {
  children: React.ReactNode;
  defaultOptions?: SummarizerOptions;
  defaultWriterOptions?: WriterOptions;
  defaultRewriterOptions?: RewriterOptions;
  defaultLanguageDetectorOptions?: LanguageDetectorOptions;
  enableSelectionSummarizer?: boolean;
}

export function GenUIProvider({
  children,
  defaultOptions,
  defaultWriterOptions,
  defaultLanguageDetectorOptions,
  defaultRewriterOptions,
  enableSelectionSummarizer = false,
}: GenUIProviderProps) {
  const [isSupported, setIsSupported] = React.useState<boolean | null>(null);
  const [isWriterSupported, setIsWriterSupported] = React.useState<
    boolean | null
  >(null);
  const [isRewriterSupported, setIsRewriterSupported] = React.useState<
    boolean | null
  >(null);
  const [isLanguageDetectorSupported, setIsLanguageDetectorSupported] =
    React.useState<boolean | null>(null);
  const [availability, setAvailability] =
    React.useState<AvailabilityStatus>(null);
  const [writerAvailability, setWriterAvailability] =
    React.useState<AvailabilityStatus>(null);
  const [rewriterAvailability, setRewriterAvailability] =
    React.useState<AvailabilityStatus>(null);
  const [languageDetectorAvailability, setLanguageDetectorAvailability] =
    React.useState<AvailabilityStatus>(null);
  const [downloadProgress, setDownloadProgress] = React.useState(0);
  const [writerDownloadProgress, setWriterDownloadProgress] = React.useState(0);
  const [rewriterDownloadProgress, setRewriterDownloadProgress] =
    React.useState(0);
  const [
    languageDetectorDownloadProgress,
    setLanguageDetectorDownloadProgress,
  ] = React.useState(0);
  const [isDownloading, setIsDownloading] = React.useState(false);
  const [isWriterDownloading, setIsWriterDownloading] = React.useState(false);
  const [isRewriterDownloading, setIsRewriterDownloading] =
    React.useState(false);
  const [isLanguageDetectorDownloading, setIsLanguageDetectorDownloading] =
    React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const hasCheckedAvailability = React.useRef(false);
  const hasCheckedWriterAvailability = React.useRef(false);
  const hasCheckedRewriterAvailability = React.useRef(false);
  const hasCheckedLanguageDetectorAvailability = React.useRef(false);

  // LanguageModel Prompt API state
  const [isLanguageModelSupported, setIsLanguageModelSupported] =
    React.useState<boolean | null>(null);
  const [languageModelAvailability, setLanguageModelAvailability] =
    React.useState<AvailabilityStatus>(null);
  const [languageModelError, setLanguageModelError] = React.useState<
    string | null
  >(null);
  const hasCheckedLanguageModelAvailability = React.useRef(false);

  // Check if Chrome Summarizer API is supported
  React.useEffect(() => {
    const checkSupport = () => {
      const hasSummarizer = "Summarizer" in self;
      const hasWriter = "Writer" in self;
      const hasLanguageDetector = "LanguageDetector" in self;
      const hasRewriter = "Rewriter" in self;

      setIsSupported(hasSummarizer);
      setIsWriterSupported(hasWriter);
      setIsRewriterSupported(hasRewriter);
      setIsLanguageDetectorSupported(hasLanguageDetector);

      if (
        !hasSummarizer &&
        !hasWriter &&
        !hasRewriter &&
        !hasLanguageDetector
      ) {
        const errorMsg =
          "Chrome AI APIs are not supported in this browser. Please use Chrome 137+ with the required hardware specifications.";
        setError(errorMsg);
      }
    };

    checkSupport();
  }, []);

  // Check if Chrome LanguageModel Prompt API is supported
  React.useEffect(() => {
    const checkLanguageModelSupport = () => {
      if ("LanguageModel" in self) {
        setIsLanguageModelSupported(true);
      } else {
        setIsLanguageModelSupported(false);
        const errorMsg =
          "Chrome Prompt API (LanguageModel) is not supported in this browser. Please use Chrome 138+ with the required hardware specifications.";
        setLanguageModelError(errorMsg);
      }
    };

    checkLanguageModelSupport();
  }, []);

  // Check model availability
  const checkAvailability =
    React.useCallback(async (): Promise<AvailabilityStatus> => {
      if (!isSupported) {
        const errorMsg = "Chrome Summarizer API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const availabilityStatus = await (
          self as any
        ).Summarizer.availability();

        if (availabilityStatus === "unavailable") {
          const errorMsg =
            "Summarizer API is not available on this device. Please check hardware requirements.";
          setError(errorMsg);
          setAvailability("unavailable");
          return "unavailable";
        }

        setAvailability(availabilityStatus);
        setError(null);

        if (availabilityStatus === "downloadable") {
          setIsDownloading(true);
          setDownloadProgress(0);
        }

        return availabilityStatus;
      } catch (err) {
        const errorMsg =
          "Failed to check summarizer availability: " + (err as Error).message;
        setError(errorMsg);
        setAvailability(null);
        return null;
      }
    }, [isSupported]);

  // Check Writer model availability
  const checkWriterAvailability =
    React.useCallback(async (): Promise<AvailabilityStatus> => {
      if (!isWriterSupported) {
        const errorMsg = "Chrome Writer API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const availabilityStatus = await (self as any).Writer.availability();

        if (availabilityStatus === "unavailable") {
          const errorMsg =
            "Writer API is not available on this device. Please check hardware requirements.";
          setError(errorMsg);
          setWriterAvailability("unavailable");
          return "unavailable";
        }

        setWriterAvailability(availabilityStatus);
        setError(null);

        if (availabilityStatus === "downloadable") {
          setIsWriterDownloading(true);
          setWriterDownloadProgress(0);
        }

        return availabilityStatus;
      } catch (err) {
        const errorMsg =
          "Failed to check writer availability: " + (err as Error).message;
        setError(errorMsg);
        setWriterAvailability(null);
        return null;
      }
    }, [isWriterSupported]);

  // Automatically check availability when support is confirmed
  React.useEffect(() => {
    if (isSupported === true && !hasCheckedAvailability.current) {
      hasCheckedAvailability.current = true;
      checkAvailability();
    }
  }, [isSupported, checkAvailability]);

  // Check Language Detector model availability
  const checkLanguageDetectorAvailability =
    React.useCallback(async (): Promise<AvailabilityStatus> => {
      if (!isLanguageDetectorSupported) {
        const errorMsg = "Chrome Language Detector API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const availabilityStatus = await (
          self as any
        ).LanguageDetector.availability();

        if (availabilityStatus === "unavailable") {
          const errorMsg =
            "Language Detector API is not available on this device. Please check hardware requirements.";
          setError(errorMsg);
          setLanguageDetectorAvailability("unavailable");
          return "unavailable";
        }

        setLanguageDetectorAvailability(availabilityStatus);
        setError(null);

        if (availabilityStatus === "downloadable") {
          setIsLanguageDetectorDownloading(true);
          setLanguageDetectorDownloadProgress(0);
        }

        return availabilityStatus;
      } catch (err) {
        const errorMsg =
          "Failed to check language detector availability: " +
          (err as Error).message;
        setError(errorMsg);
        setLanguageDetectorAvailability(null);
        return null;
      }
    }, [isLanguageDetectorSupported]);

  // Automatically check writer availability when support is confirmed
  React.useEffect(() => {
    if (isWriterSupported === true && !hasCheckedWriterAvailability.current) {
      hasCheckedWriterAvailability.current = true;
      checkWriterAvailability();
    }
  }, [isWriterSupported, checkWriterAvailability]);

  // Check Rewriter model availability
  const checkRewriterAvailability =
    React.useCallback(async (): Promise<AvailabilityStatus> => {
      if (!isRewriterSupported) {
        const errorMsg = "Chrome Rewriter API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const availabilityStatus = await (self as any).Rewriter.availability();

        if (availabilityStatus === "unavailable") {
          const errorMsg =
            "Rewriter API is not available on this device. Please check hardware requirements.";
          setError(errorMsg);
          setRewriterAvailability("unavailable");
          return "unavailable";
        }

        setRewriterAvailability(availabilityStatus);
        setError(null);

        if (availabilityStatus === "downloadable") {
          setIsRewriterDownloading(true);
          setRewriterDownloadProgress(0);
        }

        return availabilityStatus;
      } catch (err) {
        const errorMsg =
          "Failed to check rewriter availability: " + (err as Error).message;
        setError(errorMsg);
        setRewriterAvailability(null);
        return null;
      }
    }, [isRewriterSupported]);

  // Automatically check rewriter availability when support is confirmed
  React.useEffect(() => {
    if (
      isRewriterSupported === true &&
      !hasCheckedRewriterAvailability.current
    ) {
      hasCheckedRewriterAvailability.current = true;
      checkRewriterAvailability();
    }
  }, [isRewriterSupported, checkRewriterAvailability]);

  // Automatically check language detector availability when support is confirmed
  React.useEffect(() => {
    if (
      isLanguageDetectorSupported === true &&
      !hasCheckedLanguageDetectorAvailability.current
    ) {
      hasCheckedLanguageDetectorAvailability.current = true;
      checkLanguageDetectorAvailability();
    }
  }, [isLanguageDetectorSupported, checkLanguageDetectorAvailability]);

  // Create summarizer instance
  const createSummarizer = React.useCallback(
    async (options?: SummarizerOptions): Promise<any> => {
      if (!isSupported) {
        const errorMsg = "Chrome Summarizer API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const summarizerOptions: SummarizerOptions = {
          ...defaultOptions,
          ...options,
          monitor: (monitor) => {
            // Merge with user-provided monitor if exists
            if (options?.monitor) {
              options.monitor(monitor);
            }

            monitor.addEventListener("downloadprogress", (e: any) => {
              const progress = e.loaded * 100;
              setDownloadProgress(progress);
            });
          },
        };

        const summarizer = await (self as any).Summarizer.create(
          summarizerOptions
        );
        setIsDownloading(false);
        setDownloadProgress(100);
        setError(null);
        return summarizer;
      } catch (err) {
        const errorMsg =
          "Failed to create summarizer: " + (err as Error).message;
        setError(errorMsg);
        setIsDownloading(false);
        return null;
      }
    },
    [isSupported, defaultOptions]
  );

  // Summarize function (batch or streaming)
  const summarize = React.useCallback(
    async (
      text: string,
      options?: SummarizeOptions & {
        streaming?: boolean;
        onChunk?: (chunk: string) => void;
      }
    ): Promise<string> => {
      if (!text.trim()) {
        const errorMsg = "Please enter some text to summarize.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      if (!isSupported) {
        const errorMsg = "Chrome Summarizer API is not supported.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      try {
        // Check availability first
        const availabilityStatus = await checkAvailability();
        if (
          availabilityStatus === "unavailable" ||
          availabilityStatus === null
        ) {
          throw new Error("Summarizer is not available.");
        }

        // Create summarizer
        const summarizer = await createSummarizer();
        if (!summarizer) {
          throw new Error("Failed to create summarizer.");
        }

        const summarizeOptions: SummarizeOptions = {
          context:
            options?.context ||
            defaultOptions?.sharedContext ||
            "This text is being summarized for better understanding.",
        };

        // Perform summarization
        if (options?.streaming) {
          const stream = summarizer.summarizeStreaming(text, summarizeOptions);
          let result = "";

          for await (const chunk of stream) {
            result += chunk;
            options?.onChunk?.(result);
          }

          return result;
        } else {
          const result = await summarizer.summarize(text, summarizeOptions);
          return result;
        }
      } catch (err) {
        const errorMsg = (err as Error).message;
        setError(errorMsg);
        throw err;
      }
    },
    [isSupported, checkAvailability, createSummarizer, defaultOptions]
  );

  // Create writer instance
  const createWriter = React.useCallback(
    async (options?: WriterOptions): Promise<any> => {
      if (!isWriterSupported) {
        const errorMsg = "Chrome Writer API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const writerOptions: WriterOptions = {
          ...defaultWriterOptions,
          ...options,
          monitor: (monitor) => {
            // Merge with user-provided monitor if exists
            if (options?.monitor) {
              options.monitor(monitor);
            }

            monitor.addEventListener("downloadprogress", (e: any) => {
              const progress = e.loaded * 100;
              setWriterDownloadProgress(progress);
            });
          },
        };

        const writer = await (self as any).Writer.create(writerOptions);
        setIsWriterDownloading(false);
        setWriterDownloadProgress(100);
        setError(null);
        return writer;
      } catch (err) {
        const errorMsg = "Failed to create writer: " + (err as Error).message;
        setError(errorMsg);
        setIsWriterDownloading(false);
        return null;
      }
    },
    [isWriterSupported, defaultWriterOptions]
  );

  // Write function (batch or streaming)
  const write = React.useCallback(
    async (
      prompt: string,
      options?: WriteOptions & {
        streaming?: boolean;
        onChunk?: (chunk: string) => void;
      }
    ): Promise<string> => {
      if (!prompt.trim()) {
        const errorMsg = "Please enter a prompt to write content.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      if (!isWriterSupported) {
        const errorMsg = "Chrome Writer API is not supported.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      try {
        // Check availability first
        const availabilityStatus = await checkWriterAvailability();
        if (
          availabilityStatus === "unavailable" ||
          availabilityStatus === null
        ) {
          throw new Error("Writer is not available.");
        }

        // Create writer
        const writer = await createWriter();
        if (!writer) {
          throw new Error("Failed to create writer.");
        }

        const writeOptions: WriteOptions = {
          context:
            options?.context ||
            defaultWriterOptions?.sharedContext ||
            "Generate helpful and appropriate content.",
        };

        // Perform writing
        if (options?.streaming) {
          const stream = writer.writeStreaming(prompt, writeOptions);
          let result = "";

          for await (const chunk of stream) {
            result += chunk;
            options?.onChunk?.(result);
          }

          return result;
        } else {
          const result = await writer.write(prompt, writeOptions);
          return result;
        }
      } catch (err) {
        const errorMsg = (err as Error).message;
        setError(errorMsg);
        throw err;
      }
    },
    [
      isWriterSupported,
      checkWriterAvailability,
      createWriter,
      defaultWriterOptions,
    ]
  );

  // Create rewriter instance
  const createRewriter = React.useCallback(
    async (options?: RewriterOptions): Promise<any> => {
      if (!isRewriterSupported) {
        const errorMsg = "Chrome Rewriter API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const rewriterOptions: RewriterOptions = {
          ...defaultRewriterOptions,
          ...options,
          monitor: (monitor) => {
            if (options?.monitor) {
              options.monitor(monitor);
            }
            monitor.addEventListener("downloadprogress", (e: any) => {
              const progress = e.loaded * 100;
              setRewriterDownloadProgress(progress);
            });
          },
        };

        const rewriter = await (self as any).Rewriter.create(rewriterOptions);
        setIsRewriterDownloading(false);
        setRewriterDownloadProgress(100);
        setError(null);
        return rewriter;
      } catch (err) {
        const errorMsg = "Failed to create rewriter: " + (err as Error).message;
        setError(errorMsg);
        setIsRewriterDownloading(false);
        return null;
      }
    },
    [isRewriterSupported, defaultRewriterOptions]
  );

  // Rewrite function (batch or streaming)
  const rewrite = React.useCallback(
    async (
      text: string,
      options?: RewriteOptions & {
        streaming?: boolean;
        onChunk?: (chunk: string) => void;
      }
    ): Promise<string> => {
      if (!text.trim()) {
        const errorMsg = "Please enter some text to improve.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      if (!isRewriterSupported) {
        const errorMsg = "Chrome Rewriter API is not supported.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      try {
        const availabilityStatus = await checkRewriterAvailability();
        if (
          availabilityStatus === "unavailable" ||
          availabilityStatus === null
        ) {
          throw new Error("Rewriter is not available.");
        }

        const rewriter = await createRewriter();
        if (!rewriter) {
          throw new Error("Failed to create rewriter.");
        }

        const rewriteOptions: RewriteOptions = {
          context:
            options?.context ||
            defaultRewriterOptions?.sharedContext ||
            "Improve clarity and readability without changing meaning.",
          signal: options?.signal,
        };

        if (options?.streaming) {
          const stream = rewriter.rewriteStreaming(text, rewriteOptions);
          let result = "";
          for await (const chunk of stream) {
            result += chunk;
            options?.onChunk?.(result);
          }
          return result;
        } else {
          const result = await rewriter.rewrite(text, rewriteOptions);
          return result;
        }
      } catch (err) {
        const errorMsg = (err as Error).message;
        setError(errorMsg);
        throw err;
      }
    },
    [
      isRewriterSupported,
      checkRewriterAvailability,
      createRewriter,
      defaultRewriterOptions,
    ]
  );

  // Create language detector instance
  const createLanguageDetector = React.useCallback(
    async (options?: LanguageDetectorOptions): Promise<any> => {
      if (!isLanguageDetectorSupported) {
        const errorMsg = "Chrome Language Detector API is not supported.";
        setError(errorMsg);
        return null;
      }

      try {
        const detectorOptions: LanguageDetectorOptions = {
          ...defaultLanguageDetectorOptions,
          ...options,
          monitor: (monitor) => {
            // Merge with user-provided monitor if exists
            if (options?.monitor) {
              options.monitor(monitor);
            }

            monitor.addEventListener("downloadprogress", (e: any) => {
              const progress = e.loaded * 100;
              setLanguageDetectorDownloadProgress(progress);
            });
          },
        };

        const detector = await (self as any).LanguageDetector.create(
          detectorOptions
        );
        setIsLanguageDetectorDownloading(false);
        setLanguageDetectorDownloadProgress(100);
        setError(null);
        return detector;
      } catch (err) {
        const errorMsg =
          "Failed to create language detector: " + (err as Error).message;
        setError(errorMsg);
        setIsLanguageDetectorDownloading(false);
        return null;
      }
    },
    [isLanguageDetectorSupported, defaultLanguageDetectorOptions]
  );

  // Detect language function
  const detectLanguage = React.useCallback(
    async (text: string): Promise<DetectedLanguage[]> => {
      if (!text.trim()) {
        const errorMsg = "Please enter some text to detect language.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      if (!isLanguageDetectorSupported) {
        const errorMsg = "Chrome Language Detector API is not supported.";
        setError(errorMsg);
        throw new Error(errorMsg);
      }

      try {
        // Check availability first
        const availabilityStatus = await checkLanguageDetectorAvailability();
        if (
          availabilityStatus === "unavailable" ||
          availabilityStatus === null
        ) {
          throw new Error("Language Detector is not available.");
        }

        // Create language detector
        const detector = await createLanguageDetector();
        if (!detector) {
          throw new Error("Failed to create language detector.");
        }

        // Perform language detection
        const results = await detector.detect(text);
        return results;
      } catch (err) {
        const errorMsg = (err as Error).message;
        setError(errorMsg);
        throw err;
      }
    },
    [
      isLanguageDetectorSupported,
      checkLanguageDetectorAvailability,
      createLanguageDetector,
    ]
  );

  // Check LanguageModel availability
  const checkLanguageModelAvailability = React.useCallback(
    async (options?: PromptOptions): Promise<AvailabilityStatus> => {
      if (!isLanguageModelSupported) {
        const errorMsg = "Chrome Prompt API (LanguageModel) is not supported.";
        setLanguageModelError(errorMsg);
        return null;
      }
      try {
        // Always pass the same options to availability() that will be used in prompt()
        const availabilityStatus = await (
          self as any
        ).LanguageModel.availability(options);

        if (availabilityStatus === "unavailable") {
          const errorMsg =
            "Prompt API (LanguageModel) is not available on this device. Please check hardware requirements.";
          setLanguageModelError(errorMsg);
          setLanguageModelAvailability("unavailable");
          return "unavailable";
        }

        setLanguageModelAvailability(availabilityStatus);
        setLanguageModelError(null);
        return availabilityStatus;
      } catch (err) {
        const errorMsg =
          "Failed to check LanguageModel availability: " +
          (err as Error).message;
        setLanguageModelError(errorMsg);
        setLanguageModelAvailability(null);
        return null;
      }
    },
    [isLanguageModelSupported]
  );

  // Automatically check LanguageModel availability when support is confirmed
  React.useEffect(() => {
    if (
      isLanguageModelSupported === true &&
      !hasCheckedLanguageModelAvailability.current
    ) {
      hasCheckedLanguageModelAvailability.current = true;
      checkLanguageModelAvailability();
    }
  }, [isLanguageModelSupported, checkLanguageModelAvailability]);

  // Reset error
  const resetError = React.useCallback(() => {
    setError(null);
  }, []);

  const value: GenUIContextValue = React.useMemo(
    () => ({
      // Summarizer API
      isSupported,
      isWriterSupported,
      isRewriterSupported,
      isLanguageDetectorSupported,
      availability,
      writerAvailability,
      rewriterAvailability,
      languageDetectorAvailability,
      downloadProgress,
      writerDownloadProgress,
      rewriterDownloadProgress,
      languageDetectorDownloadProgress,
      isDownloading,
      isWriterDownloading,
      isRewriterDownloading,
      isLanguageDetectorDownloading,
      error,
      checkAvailability,
      checkWriterAvailability,
      checkRewriterAvailability,
      checkLanguageDetectorAvailability,
      createSummarizer,
      createWriter,
      createRewriter,
      createLanguageDetector,
      summarize,
      write,
      rewrite,
      detectLanguage,
      resetError,
      // LanguageModel Prompt API
      isLanguageModelSupported,
      languageModelAvailability,
      languageModelError,
      checkLanguageModelAvailability,
    }),
    [
      isSupported,
      isWriterSupported,
      isRewriterSupported,
      isLanguageDetectorSupported,
      availability,
      writerAvailability,
      rewriterAvailability,
      languageDetectorAvailability,
      downloadProgress,
      writerDownloadProgress,
      rewriterDownloadProgress,
      languageDetectorDownloadProgress,
      isDownloading,
      isWriterDownloading,
      isRewriterDownloading,
      isLanguageDetectorDownloading,
      error,
      checkAvailability,
      checkWriterAvailability,
      checkRewriterAvailability,
      checkLanguageDetectorAvailability,
      createSummarizer,
      createWriter,
      createRewriter,
      createLanguageDetector,
      summarize,
      write,
      rewrite,
      detectLanguage,
      resetError,
      isLanguageModelSupported,
      languageModelAvailability,
      languageModelError,
      checkLanguageModelAvailability,
    ]
  );

  return (
    <GenUIContext.Provider value={value}>
      {children}
      {enableSelectionSummarizer ? (
        // Lazy import to avoid SSR issues if any consumer renders on server
        <SummarizeSelection defaultOptions={defaultOptions} />
      ) : null}
    </GenUIContext.Provider>
  );
}

// Hook to use Voiceable context
export function useGenUI(): GenUIContextValue {
  const context = React.useContext(GenUIContext);
  if (context === undefined) {
    throw new Error("useGenUI must be used within a GenUIProvider");
  }
  return context;
}

Props

Prop

Type

Dependencies

  • button
  • alert
  • dialog
  • tooltip
  • skeleton