@umituz/react-native-ai-pruna-provider 1.0.7 → 1.0.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-pruna-provider",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Pruna AI provider for React Native - implements IAIProvider interface for unified AI generation",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Endpoints:
6
6
  * POST /v1/predictions — submit generation (with Try-Sync header for immediate results)
7
- * POST /v1/files — upload images for p-video (requires file URL, not base64)
7
+ * POST /v1/files — upload files (images, audio) for p-video (requires file URL, not base64)
8
8
  * GET {poll_url} — poll async results
9
9
  *
10
10
  * Authentication: `apikey` header
@@ -14,45 +14,11 @@
14
14
  import type { PrunaModelId, PrunaPredictionResponse, PrunaFileUploadResponse } from "../../domain/entities/pruna.types";
15
15
  import { PRUNA_BASE_URL, PRUNA_PREDICTIONS_URL, PRUNA_FILES_URL } from "./pruna-provider.constants";
16
16
  import { generationLogCollector } from "../utils/log-collector";
17
+ import { detectMimeType } from "../utils/mime-detection.util";
18
+ import { getExtensionForMime } from "../utils/constants/mime.constants";
17
19
 
18
20
  const TAG = 'pruna-api';
19
21
 
20
- /**
21
- * Detect MIME type from raw binary bytes.
22
- * Supports image (png, jpeg, webp) and audio (mp3, wav, flac, m4a/aac) formats.
23
- */
24
- function detectMimeType(bytes: Uint8Array): string {
25
- // JPEG
26
- if (bytes[0] === 0xFF && bytes[1] === 0xD8) return 'image/jpeg';
27
- // PNG
28
- if (bytes[0] === 0x89 && bytes[1] === 0x50) return 'image/png';
29
- // RIFF container — WAV or WebP
30
- if (bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46) {
31
- if (bytes.length > 11 && bytes[8] === 0x57 && bytes[9] === 0x41 && bytes[10] === 0x56 && bytes[11] === 0x45) return 'audio/wav';
32
- return 'image/webp';
33
- }
34
- // MP3 with ID3 tag
35
- if (bytes[0] === 0x49 && bytes[1] === 0x44 && bytes[2] === 0x33) return 'audio/mpeg';
36
- // MP3 sync word (0xFF followed by 0xE0-0xFF)
37
- if (bytes[0] === 0xFF && (bytes[1] & 0xE0) === 0xE0 && bytes[1] !== 0xFF) return 'audio/mpeg';
38
- // FLAC
39
- if (bytes[0] === 0x66 && bytes[1] === 0x4C && bytes[2] === 0x61 && bytes[3] === 0x43) return 'audio/flac';
40
- // M4A/AAC (MP4 container — ftyp box at offset 4)
41
- if (bytes.length > 7 && bytes[4] === 0x66 && bytes[5] === 0x74 && bytes[6] === 0x79 && bytes[7] === 0x70) return 'audio/mp4';
42
- // Default
43
- return 'image/png';
44
- }
45
-
46
- const MIME_EXTENSION_MAP: Record<string, string> = {
47
- 'image/png': 'png',
48
- 'image/jpeg': 'jpg',
49
- 'image/webp': 'webp',
50
- 'audio/mpeg': 'mp3',
51
- 'audio/wav': 'wav',
52
- 'audio/flac': 'flac',
53
- 'audio/mp4': 'm4a',
54
- };
55
-
56
22
  /**
57
23
  * Upload a base64 file (image or audio) to Pruna's file storage.
58
24
  * p-video requires file URLs (not raw base64).
@@ -87,7 +53,7 @@ export async function uploadFileToStorage(
87
53
  }
88
54
 
89
55
  const mime = detectMimeType(bytes);
90
- const ext = MIME_EXTENSION_MAP[mime] || mime.split('/')[1];
56
+ const ext = getExtensionForMime(mime);
91
57
  const blob = new Blob([bytes], { type: mime });
92
58
  const formData = new FormData();
93
59
  formData.append('content', blob, `upload.${ext}`);
@@ -0,0 +1,12 @@
1
+ export {
2
+ MIME_IMAGE_PNG,
3
+ MIME_IMAGE_JPEG,
4
+ MIME_IMAGE_WEBP,
5
+ MIME_AUDIO_MPEG,
6
+ MIME_AUDIO_WAV,
7
+ MIME_AUDIO_FLAC,
8
+ MIME_AUDIO_MP4,
9
+ MIME_DEFAULT,
10
+ MIME_TO_EXTENSION,
11
+ getExtensionForMime,
12
+ } from "./mime.constants";
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MIME Type Constants
3
+ * Supported media types for Pruna file uploads (images + audio)
4
+ */
5
+
6
+ // ── Image MIME types ────────────────────────────────────────
7
+ export const MIME_IMAGE_PNG = 'image/png' as const;
8
+ export const MIME_IMAGE_JPEG = 'image/jpeg' as const;
9
+ export const MIME_IMAGE_WEBP = 'image/webp' as const;
10
+
11
+ // ── Audio MIME types (p-video audio input: flac, mp3, wav) ──
12
+ export const MIME_AUDIO_MPEG = 'audio/mpeg' as const;
13
+ export const MIME_AUDIO_WAV = 'audio/wav' as const;
14
+ export const MIME_AUDIO_FLAC = 'audio/flac' as const;
15
+ export const MIME_AUDIO_MP4 = 'audio/mp4' as const;
16
+
17
+ // ── Fallback ────────────────────────────────────────────────
18
+ export const MIME_DEFAULT = MIME_IMAGE_PNG;
19
+
20
+ /** Maps MIME type → file extension for upload naming */
21
+ export const MIME_TO_EXTENSION: Readonly<Record<string, string>> = {
22
+ [MIME_IMAGE_PNG]: 'png',
23
+ [MIME_IMAGE_JPEG]: 'jpg',
24
+ [MIME_IMAGE_WEBP]: 'webp',
25
+ [MIME_AUDIO_MPEG]: 'mp3',
26
+ [MIME_AUDIO_WAV]: 'wav',
27
+ [MIME_AUDIO_FLAC]: 'flac',
28
+ [MIME_AUDIO_MP4]: 'm4a',
29
+ };
30
+
31
+ /**
32
+ * Get file extension for a MIME type.
33
+ * Falls back to the subtype (e.g. "png" from "image/png").
34
+ */
35
+ export function getExtensionForMime(mime: string): string {
36
+ return MIME_TO_EXTENSION[mime] || mime.split('/')[1] || 'bin';
37
+ }
@@ -28,3 +28,9 @@ export {
28
28
 
29
29
  export { generationLogCollector } from "./log-collector";
30
30
  export type { LogEntry } from "./log-collector";
31
+
32
+ export { detectMimeType } from "./mime-detection.util";
33
+ export {
34
+ MIME_TO_EXTENSION,
35
+ getExtensionForMime,
36
+ } from "./constants/mime.constants";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * MIME Type Detection Utility
3
+ * Detects file type from binary content using magic byte signatures.
4
+ *
5
+ * Supported formats:
6
+ * Image: PNG, JPEG, WebP
7
+ * Audio: MP3 (ID3 + sync word), WAV (RIFF/WAVE), FLAC, M4A/AAC (MP4 ftyp)
8
+ */
9
+
10
+ import {
11
+ MIME_IMAGE_PNG,
12
+ MIME_IMAGE_JPEG,
13
+ MIME_IMAGE_WEBP,
14
+ MIME_AUDIO_MPEG,
15
+ MIME_AUDIO_WAV,
16
+ MIME_AUDIO_FLAC,
17
+ MIME_AUDIO_MP4,
18
+ MIME_DEFAULT,
19
+ } from "./constants/mime.constants";
20
+
21
+ /**
22
+ * Detect MIME type from raw binary bytes using magic number signatures.
23
+ *
24
+ * Detection order is intentional:
25
+ * 1. JPEG (0xFF 0xD8) — checked before MP3 sync word to avoid false positives
26
+ * 2. PNG (0x89 0x50)
27
+ * 3. RIFF container → distinguish WAV vs WebP via subformat at offset 8-11
28
+ * 4. MP3 with ID3 tag (0x49 0x44 0x33)
29
+ * 5. MP3 sync word (0xFF 0xE_) — after JPEG to prevent overlap
30
+ * 6. FLAC (fLaC)
31
+ * 7. M4A/AAC (ftyp box at offset 4)
32
+ */
33
+ export function detectMimeType(bytes: Uint8Array): string {
34
+ if (bytes.length < 4) return MIME_DEFAULT;
35
+
36
+ // ── Image formats ───────────────────────────────────────
37
+ // JPEG: FF D8
38
+ if (bytes[0] === 0xFF && bytes[1] === 0xD8) return MIME_IMAGE_JPEG;
39
+
40
+ // PNG: 89 50 4E 47
41
+ if (bytes[0] === 0x89 && bytes[1] === 0x50) return MIME_IMAGE_PNG;
42
+
43
+ // RIFF container — WAV (RIFF....WAVE) or WebP (RIFF....WEBP)
44
+ if (bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46) {
45
+ if (bytes.length > 11) {
46
+ // WAVE at offset 8
47
+ if (bytes[8] === 0x57 && bytes[9] === 0x41 && bytes[10] === 0x56 && bytes[11] === 0x45) return MIME_AUDIO_WAV;
48
+ // WEBP at offset 8
49
+ if (bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) return MIME_IMAGE_WEBP;
50
+ }
51
+ return MIME_IMAGE_WEBP;
52
+ }
53
+
54
+ // ── Audio formats ───────────────────────────────────────
55
+ // MP3 with ID3v2 tag: 49 44 33
56
+ if (bytes[0] === 0x49 && bytes[1] === 0x44 && bytes[2] === 0x33) return MIME_AUDIO_MPEG;
57
+
58
+ // MP3 frame sync word: FF Ex/Fx (but not FF FF)
59
+ if (bytes[0] === 0xFF && (bytes[1] & 0xE0) === 0xE0 && bytes[1] !== 0xFF) return MIME_AUDIO_MPEG;
60
+
61
+ // FLAC: 66 4C 61 43 ("fLaC")
62
+ if (bytes[0] === 0x66 && bytes[1] === 0x4C && bytes[2] === 0x61 && bytes[3] === 0x43) return MIME_AUDIO_FLAC;
63
+
64
+ // M4A / AAC in MP4 container: ftyp box at offset 4
65
+ if (bytes.length > 7 && bytes[4] === 0x66 && bytes[5] === 0x74 && bytes[6] === 0x79 && bytes[7] === 0x70) return MIME_AUDIO_MP4;
66
+
67
+ return MIME_DEFAULT;
68
+ }