@pipedog/openai 0.0.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ import { type Frame } from "@pipedog/core/frames/frames";
2
+ import { ImageGenService, type ImageGenServiceOptions } from "@pipedog/core/services/image_service";
3
+ import { ImageGenSettings, type ImageGenSettingsOptions } from "@pipedog/core/services/settings";
4
+ import { type NotGiven } from "@pipedog/core/utils/types";
5
+ import OpenAI from "openai";
6
+ /**
7
+ * Hint set for the `size` argument to `images.generate`. The values mirror the
8
+ * literal type the OpenAI SDK accepts on its `size` parameter, redeclared
9
+ * here.
10
+ *
11
+ * Settings fields use this alias in unions like `OpenAIImageSize | string`, so
12
+ * editors show these values as completion hints without rejecting other
13
+ * strings. If OpenAI adds a size before this list is updated, callers can
14
+ * still pass it and we forward it through. Invalid values surface as an
15
+ * OpenAI API error at runtime. Keep in sync on a best-effort basis when
16
+ * bumping the openai dep.
17
+ */
18
+ export type OpenAIImageSize = "auto" | "1024x1024" | "1536x1024" | "1024x1536" | "256x256" | "512x512" | "1792x1024" | "1024x1792";
19
+ /**
20
+ * Hint set for the `quality` argument to `images.generate`, redeclared and
21
+ * used the same way as `OpenAIImageSize` above.
22
+ */
23
+ export type OpenAIImageQuality = "auto" | "low" | "medium" | "high" | "xhigh" | "max" | "standard" | "hd";
24
+ export interface OpenAIImageGenSettingsOptions extends ImageGenSettingsOptions {
25
+ /** Target size for generated images. */
26
+ imageSize?: OpenAIImageSize | (string & {}) | null | NotGiven;
27
+ /**
28
+ * Rendering quality for generated images. Lower tiers generate faster at
29
+ * the cost of detail. `null` lets OpenAI pick the best quality for the
30
+ * model.
31
+ */
32
+ quality?: OpenAIImageQuality | (string & {}) | null | NotGiven;
33
+ }
34
+ /**
35
+ * Settings for the OpenAI image generation service.
36
+ *
37
+ * - `model`: image generation model identifier.
38
+ * - `imageSize`: target size for generated images.
39
+ * - `quality`: rendering quality for generated images. Lower tiers generate
40
+ * faster at the cost of detail. `null` lets OpenAI pick the best quality
41
+ * for the model.
42
+ */
43
+ export declare class OpenAIImageGenSettings extends ImageGenSettings {
44
+ imageSize: OpenAIImageSize | (string & {}) | null | NotGiven;
45
+ quality: OpenAIImageQuality | (string & {}) | null | NotGiven;
46
+ constructor(options?: OpenAIImageGenSettingsOptions);
47
+ }
48
+ /** A decoded image as interleaved RGB pixels. */
49
+ export interface DecodedRgbImage {
50
+ /** The pixels, 3 bytes per pixel. */
51
+ image: Uint8Array;
52
+ /** Width and height. */
53
+ size: [number, number];
54
+ }
55
+ /** Decodes encoded image bytes into RGB pixels. */
56
+ export type ImageDecoder = (bytes: Uint8Array) => Promise<DecodedRgbImage> | DecodedRgbImage;
57
+ /**
58
+ * Decode a PNG and convert it to RGB (Pillow's `Image.open(...).convert("RGB")`):
59
+ * alpha is dropped, grayscale widened and palettes expanded.
60
+ *
61
+ * @param bytes The PNG bytes.
62
+ * @returns The RGB pixels and the image size.
63
+ */
64
+ export declare function decodePngToRgb(bytes: Uint8Array): DecodedRgbImage;
65
+ export interface OpenAIImageGenServiceOptions extends ImageGenServiceOptions {
66
+ /** OpenAI API key for authentication. */
67
+ apiKey: string;
68
+ /** Custom base URL for OpenAI API. If null, uses default. */
69
+ baseUrl?: string | null;
70
+ /**
71
+ * `fetch` used to download hosted results. Defaults to the global `fetch`.
72
+ *
73
+ * DIVERGENCE: replaces upstream's required `aiohttp_session`.
74
+ */
75
+ fetch?: typeof fetch | null;
76
+ /**
77
+ * Decodes the generated image into RGB pixels. Defaults to
78
+ * `decodePngToRgb`.
79
+ *
80
+ * DIVERGENCE: pipedog-only. Upstream decodes with Pillow.
81
+ */
82
+ decodeImage?: ImageDecoder | null;
83
+ /** Runtime-updatable settings. */
84
+ settings?: OpenAIImageGenSettings | null;
85
+ }
86
+ /**
87
+ * OpenAI image generation service.
88
+ *
89
+ * Provides image generation capabilities using OpenAI's GPT Image models.
90
+ * Supports various image sizes and can generate images from text prompts.
91
+ */
92
+ export declare class OpenAIImageGenService extends ImageGenService {
93
+ static Settings: typeof OpenAIImageGenSettings;
94
+ protected _settings: OpenAIImageGenSettings;
95
+ protected _client: OpenAI;
96
+ protected _fetch: typeof fetch;
97
+ protected _decodeImage: ImageDecoder;
98
+ /**
99
+ * Initialize the OpenAI image generation service.
100
+ *
101
+ * @param options.apiKey OpenAI API key for authentication.
102
+ * @param options.baseUrl Custom base URL for OpenAI API. If null, uses default.
103
+ * @param options.fetch `fetch` used to download hosted results.
104
+ * @param options.settings Runtime-updatable settings. Its given fields
105
+ * override the defaults (model "gpt-image-2.5-flare").
106
+ */
107
+ constructor(options: OpenAIImageGenServiceOptions);
108
+ /**
109
+ * Generate an image from a text prompt using OpenAI's Images API.
110
+ *
111
+ * @param prompt Text description of the image to generate.
112
+ * @returns URLImageRawFrame containing the generated image data.
113
+ */
114
+ runImageGen(prompt: string): AsyncGenerator<Frame, void, unknown>;
115
+ }
116
+ //# sourceMappingURL=image.d.ts.map
package/dist/image.js ADDED
@@ -0,0 +1,179 @@
1
+ // Copyright (c) 2024-2026, Daily
2
+ // Copyright (c) 2026, pipedog contributors
3
+ // SPDX-License-Identifier: BSD-2-Clause
4
+ //
5
+ // Ported from pipecat: src/pipecat/services/openai/image.py
6
+ /**
7
+ * OpenAI image generation service implementation.
8
+ *
9
+ * This module provides integration with OpenAI's image generation API for
10
+ * creating images from text prompts.
11
+ *
12
+ * Porting notes:
13
+ * - DIVERGENCE: upstream downloads hosted results with a required
14
+ * `aiohttp_session`. Here the download uses `fetch` (the global one by
15
+ * default, or the `fetch` option).
16
+ * - Upstream decodes the image with Pillow and converts it to RGB. Here PNGs
17
+ * are decoded with `fast-png` (pure JS); `decodeImage` can be passed to
18
+ * decode other formats.
19
+ * - Deprecated APIs are not ported: the `imageSize` and `model` constructor
20
+ * options.
21
+ */
22
+ import { abortable, currentSignal } from "@pipedog/asyncio";
23
+ import { ErrorFrame, URLImageRawFrame } from "@pipedog/core/frames/frames";
24
+ import { ImageGenService } from "@pipedog/core/services/image_service";
25
+ import { ImageGenSettings } from "@pipedog/core/services/settings";
26
+ import { base64ToBytes } from "@pipedog/core/utils/base64";
27
+ import { logger } from "@pipedog/core/utils/logger";
28
+ import { assertGiven, NOT_GIVEN } from "@pipedog/core/utils/types";
29
+ import { convertIndexedToRgb, decode as decodePng } from "fast-png";
30
+ import OpenAI from "openai";
31
+ /**
32
+ * Settings for the OpenAI image generation service.
33
+ *
34
+ * - `model`: image generation model identifier.
35
+ * - `imageSize`: target size for generated images.
36
+ * - `quality`: rendering quality for generated images. Lower tiers generate
37
+ * faster at the cost of detail. `null` lets OpenAI pick the best quality
38
+ * for the model.
39
+ */
40
+ export class OpenAIImageGenSettings extends ImageGenSettings {
41
+ imageSize = NOT_GIVEN;
42
+ quality = NOT_GIVEN;
43
+ constructor(options = {}) {
44
+ super(options);
45
+ this._assignOptions(options);
46
+ }
47
+ }
48
+ /**
49
+ * Decode a PNG and convert it to RGB (Pillow's `Image.open(...).convert("RGB")`):
50
+ * alpha is dropped, grayscale widened and palettes expanded.
51
+ *
52
+ * @param bytes The PNG bytes.
53
+ * @returns The RGB pixels and the image size.
54
+ */
55
+ export function decodePngToRgb(bytes) {
56
+ const png = decodePng(bytes);
57
+ const { width, height } = png;
58
+ const pixelCount = width * height;
59
+ let data = png.data;
60
+ let channels = png.channels;
61
+ let shift = 0;
62
+ if (png.palette) {
63
+ data = convertIndexedToRgb(png);
64
+ channels = png.palette[0]?.length ?? 3;
65
+ }
66
+ else if (png.depth === 16) {
67
+ // Pillow keeps the most significant byte of each 16-bit sample.
68
+ shift = 8;
69
+ }
70
+ else if (png.depth !== 8) {
71
+ throw new Error(`Unsupported PNG bit depth for RGB conversion: ${png.depth}`);
72
+ }
73
+ const rgb = new Uint8Array(pixelCount * 3);
74
+ for (let i = 0; i < pixelCount; i++) {
75
+ const src = i * channels;
76
+ const dst = i * 3;
77
+ if (channels >= 3) {
78
+ rgb[dst] = data[src] >> shift;
79
+ rgb[dst + 1] = data[src + 1] >> shift;
80
+ rgb[dst + 2] = data[src + 2] >> shift;
81
+ }
82
+ else {
83
+ // L or LA: widen the gray value.
84
+ const v = data[src] >> shift;
85
+ rgb[dst] = v;
86
+ rgb[dst + 1] = v;
87
+ rgb[dst + 2] = v;
88
+ }
89
+ }
90
+ return { image: rgb, size: [width, height] };
91
+ }
92
+ /**
93
+ * OpenAI image generation service.
94
+ *
95
+ * Provides image generation capabilities using OpenAI's GPT Image models.
96
+ * Supports various image sizes and can generate images from text prompts.
97
+ */
98
+ export class OpenAIImageGenService extends ImageGenService {
99
+ static Settings = OpenAIImageGenSettings;
100
+ _client;
101
+ _fetch;
102
+ _decodeImage;
103
+ /**
104
+ * Initialize the OpenAI image generation service.
105
+ *
106
+ * @param options.apiKey OpenAI API key for authentication.
107
+ * @param options.baseUrl Custom base URL for OpenAI API. If null, uses default.
108
+ * @param options.fetch `fetch` used to download hosted results.
109
+ * @param options.settings Runtime-updatable settings. Its given fields
110
+ * override the defaults (model "gpt-image-2.5-flare").
111
+ */
112
+ constructor(options) {
113
+ // 1. Initialize default_settings with hardcoded defaults
114
+ const defaultSettings = new new.target.Settings({
115
+ model: "gpt-image-2.5-flare",
116
+ imageSize: null,
117
+ quality: null,
118
+ });
119
+ // 2. Apply settings delta (canonical API, always wins)
120
+ if (options.settings !== undefined && options.settings !== null) {
121
+ defaultSettings.applyUpdate(options.settings);
122
+ }
123
+ super({ settings: defaultSettings });
124
+ this._client = new OpenAI({
125
+ apiKey: options.apiKey,
126
+ baseURL: options.baseUrl ?? undefined,
127
+ });
128
+ this._fetch = options.fetch ?? ((input, init) => fetch(input, init));
129
+ this._decodeImage = options.decodeImage ?? decodePngToRgb;
130
+ }
131
+ /**
132
+ * Generate an image from a text prompt using OpenAI's Images API.
133
+ *
134
+ * @param prompt Text description of the image to generate.
135
+ * @returns URLImageRawFrame containing the generated image data.
136
+ */
137
+ async *runImageGen(prompt) {
138
+ logger.debug(`Generating image from prompt: ${prompt}`);
139
+ const size = assertGiven(this._settings.imageSize);
140
+ const quality = assertGiven(this._settings.quality);
141
+ const image = await abortable(this._client.images.generate({
142
+ prompt,
143
+ model: assertGiven(this._settings.model),
144
+ n: 1,
145
+ size: size,
146
+ quality: quality,
147
+ }, { signal: currentSignal() }));
148
+ if (!image.data || image.data.length === 0) {
149
+ yield new ErrorFrame({ error: "Image generation failed: no data returned" });
150
+ return;
151
+ }
152
+ // The GPT Image models always return the bytes inline; the response
153
+ // carries a URL only when the model supports hosted results.
154
+ const imageUrl = image.data[0].url ?? null;
155
+ const b64Data = image.data[0].b64_json;
156
+ let imageBytes;
157
+ if (imageUrl) {
158
+ const response = await abortable(this._fetch(imageUrl, { signal: currentSignal() }));
159
+ imageBytes = new Uint8Array(await abortable(response.arrayBuffer()));
160
+ }
161
+ else if (b64Data) {
162
+ imageBytes = base64ToBytes(b64Data);
163
+ }
164
+ else {
165
+ yield new ErrorFrame({ error: "Image generation failed" });
166
+ return;
167
+ }
168
+ // GPT Image PNGs can carry an alpha channel, while output transports
169
+ // render RGB video by default.
170
+ const generated = await this._decodeImage(imageBytes);
171
+ yield new URLImageRawFrame({
172
+ image: generated.image,
173
+ size: generated.size,
174
+ format: "RGB",
175
+ url: imageUrl,
176
+ });
177
+ }
178
+ }
179
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1,10 @@
1
+ /** OpenAI services for pipedog. Subpaths mirror `pipecat.services.openai.*` (`/llm`, `/stt`, `/tts`, `/realtime`, `/live`, `/responses`) and the OpenAI adapters. */
2
+ export * from "./base_llm.ts";
3
+ export * from "./image.ts";
4
+ export * from "./llm.ts";
5
+ export * from "./open_ai_live_adapter.ts";
6
+ export * from "./open_ai_realtime_adapter.ts";
7
+ export * from "./open_ai_responses_adapter.ts";
8
+ export * from "./stt.ts";
9
+ export * from "./tts.ts";
10
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ // Copyright (c) 2026, pipedog contributors
2
+ // SPDX-License-Identifier: BSD-2-Clause
3
+ /** OpenAI services for pipedog. Subpaths mirror `pipecat.services.openai.*` (`/llm`, `/stt`, `/tts`, `/realtime`, `/live`, `/responses`) and the OpenAI adapters. */
4
+ export * from "./base_llm.js";
5
+ export * from "./image.js";
6
+ export * from "./llm.js";
7
+ export * from "./open_ai_live_adapter.js";
8
+ export * from "./open_ai_realtime_adapter.js";
9
+ export * from "./open_ai_responses_adapter.js";
10
+ export * from "./stt.js";
11
+ export * from "./tts.js";
12
+ //# sourceMappingURL=index.js.map