Skip to content

Commit 27ae35f

Browse files
committed
Rn fixes
1 parent be140be commit 27ae35f

4 files changed

Lines changed: 112 additions & 14 deletions

File tree

examples/react-native/RunAnywhereAI/src/hooks/useVLMCamera.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,12 @@ export function useVLMCamera(cameraRef: React.RefObject<Camera>): VLMCameraHook
135135
enableShutterSound: false
136136
});
137137

138+
// Strip file:// prefix if present (VisionCamera may return a URI)
139+
const cleanPath = photo.path.replace('file://', '');
140+
138141
// Use the service to describe with a callback for streaming
139142
await vlmService.describeImage(
140-
photo.path,
143+
cleanPath,
141144
SINGLE_CAPTURE_PROMPT,
142145
SINGLE_CAPTURE_MAX_TOKENS,
143146
(token) => {
@@ -194,9 +197,12 @@ export function useVLMCamera(cameraRef: React.RefObject<Camera>): VLMCameraHook
194197
enableShutterSound: false
195198
});
196199

200+
// Strip file:// prefix if present (VisionCamera may return a URI)
201+
const cleanPath = photo.path.replace('file://', '');
202+
197203
let accumulatedText = '';
198204
await vlmService.describeImage(
199-
photo.path,
205+
cleanPath,
200206
AUTO_STREAM_PROMPT,
201207
AUTO_STREAM_MAX_TOKENS,
202208
(token) => {

sdk/runanywhere-react-native/packages/core/cpp/bridges/FileManagerBridge.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "FileManagerBridge.hpp"
1010

11+
#include "rac_error.h"
12+
1113
#include <cstring>
1214
#include <cstdlib>
1315
#include <sys/stat.h>
@@ -53,7 +55,7 @@ static rac_result_t posixCreateDirectory(const char* path, int recursive, void*
5355
if (mkdir(path, 0755) == 0 || errno == EEXIST) {
5456
return RAC_SUCCESS;
5557
}
56-
return RAC_ERROR_FILE_IO;
58+
return RAC_ERROR_DIRECTORY_CREATION_FAILED;
5759
}
5860

5961
static rac_result_t posixDeletePath(const char* path, int recursive, void* /*userData*/) {
@@ -66,14 +68,14 @@ static rac_result_t posixDeletePath(const char* path, int recursive, void* /*use
6668

6769
// Handle symlinks: remove the link itself, don't follow it
6870
if (S_ISLNK(st.st_mode)) {
69-
return unlink(path) == 0 ? RAC_SUCCESS : RAC_ERROR_FILE_IO;
71+
return unlink(path) == 0 ? RAC_SUCCESS : RAC_ERROR_FILE_DELETE_FAILED;
7072
}
7173

7274
if (S_ISDIR(st.st_mode)) {
7375
if (recursive) {
7476
// Recursively delete directory contents
7577
DIR* dir = opendir(path);
76-
if (!dir) return RAC_ERROR_FILE_IO;
78+
if (!dir) return RAC_ERROR_DIRECTORY_NOT_FOUND;
7779

7880
struct dirent* entry;
7981
while ((entry = readdir(dir)) != nullptr) {
@@ -85,9 +87,9 @@ static rac_result_t posixDeletePath(const char* path, int recursive, void* /*use
8587
}
8688
closedir(dir);
8789
}
88-
return (rmdir(path) == 0) ? RAC_SUCCESS : RAC_ERROR_FILE_IO;
90+
return (rmdir(path) == 0) ? RAC_SUCCESS : RAC_ERROR_FILE_DELETE_FAILED;
8991
} else {
90-
return (unlink(path) == 0) ? RAC_SUCCESS : RAC_ERROR_FILE_IO;
92+
return (unlink(path) == 0) ? RAC_SUCCESS : RAC_ERROR_FILE_DELETE_FAILED;
9193
}
9294
}
9395

@@ -120,7 +122,7 @@ static rac_result_t posixListDirectory(const char* path, char*** outEntries,
120122
char** entries = static_cast<char**>(malloc(count * sizeof(char*)));
121123
if (!entries) {
122124
closedir(dir);
123-
return RAC_ERROR_FILE_IO;
125+
return RAC_ERROR_OUT_OF_MEMORY;
124126
}
125127

126128
// Second pass: fill entries

sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere+Models.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,16 +438,59 @@ export async function downloadModel(
438438

439439
try {
440440
// Multi-file model: download all files into the same directory
441+
// Follows Swift SDK's AlamofireDownloadService.downloadMultiFileModel() pattern:
442+
// - Sequential download of each file
443+
// - Proportional progress distribution (offset/scale per file)
444+
// - C++ path resolution via FileSystem.getModelFolder()
441445
const multiFileDescriptors = MultiFileModelCache.get(modelId);
442446
if (multiFileDescriptors && multiFileDescriptors.length > 0) {
443447
logger.info('Starting multi-file download:', { modelId, fileCount: multiFileDescriptors.length });
444448

445-
const destFolder = await FileSystem.downloadMultiFileModel(
446-
modelId,
447-
multiFileDescriptors,
448-
progressHandler,
449-
framework
450-
);
449+
const frameworkDir = framework || 'ONNX';
450+
const destFolder = FileSystem.getModelFolder(modelId, frameworkDir);
451+
452+
// Ensure directory structure exists
453+
await FileSystem.ensureDirectory(FileSystem.getRunAnywhereDirectory());
454+
await FileSystem.ensureDirectory(FileSystem.getModelsDirectory());
455+
await FileSystem.ensureDirectory(FileSystem.getFrameworkDirectory(frameworkDir));
456+
await FileSystem.ensureDirectory(destFolder);
457+
458+
const fileCount = multiFileDescriptors.length;
459+
460+
for (let index = 0; index < fileCount; index++) {
461+
const fileDescriptor = multiFileDescriptors[index];
462+
const fileDestination = `${destFolder}/${fileDescriptor.filename}`;
463+
464+
// Skip if file already exists
465+
if (await FileSystem.fileExists(fileDestination)) {
466+
logger.info(`File already exists, skipping: ${fileDescriptor.filename}`);
467+
continue;
468+
}
469+
470+
logger.info(`Downloading file ${index + 1}/${fileCount}: ${fileDescriptor.filename}`);
471+
472+
// Progress distribution: offset/scale pattern (mirrors Swift performDownload)
473+
const progressOffset = index / fileCount;
474+
const progressScale = 1.0 / fileCount;
475+
476+
await FileSystem.downloadFile(
477+
fileDescriptor.url,
478+
fileDestination,
479+
(fileProgress) => {
480+
const scaledProgress = progressOffset + (fileProgress.progress * progressScale);
481+
if (onProgress) {
482+
onProgress({
483+
modelId,
484+
bytesDownloaded: fileProgress.bytesWritten,
485+
totalBytes: fileProgress.contentLength || modelInfo.downloadSize || 0,
486+
progress: scaledProgress,
487+
});
488+
}
489+
}
490+
);
491+
492+
logger.info(`Completed file ${index + 1}/${fileCount}: ${fileDescriptor.filename}`);
493+
}
451494

452495
logger.info('Multi-file download completed:', { modelId, destFolder });
453496

sdk/runanywhere-react-native/packages/core/src/services/FileSystem.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,53 @@ export const FileSystem = {
502502
}
503503
},
504504

505+
/**
506+
* Download a single file to a specific destination path.
507+
* Used by multi-file download orchestration in RunAnywhere+Models.
508+
*
509+
* Reference: Swift SDK's AlamofireDownloadService.performDownload()
510+
*/
511+
async downloadFile(
512+
url: string,
513+
destinationPath: string,
514+
onProgress?: (progress: DownloadProgress) => void
515+
): Promise<number> {
516+
if (!RNFS) {
517+
throw new Error('react-native-fs not installed');
518+
}
519+
520+
const downloadResult = RNFS.downloadFile({
521+
fromUrl: url,
522+
toFile: destinationPath,
523+
background: true,
524+
progressDivider: 1,
525+
begin: (res) => {
526+
logger.info(`Download started: ${res.contentLength} bytes`);
527+
},
528+
progress: (res) => {
529+
const progress = res.contentLength > 0
530+
? res.bytesWritten / res.contentLength
531+
: 0;
532+
533+
if (onProgress) {
534+
onProgress({
535+
bytesWritten: res.bytesWritten,
536+
contentLength: res.contentLength,
537+
progress,
538+
});
539+
}
540+
},
541+
});
542+
543+
const result = await downloadResult.promise;
544+
545+
if (result.statusCode !== 200) {
546+
throw new Error(`Download failed with status: ${result.statusCode}`);
547+
}
548+
549+
return result.bytesWritten;
550+
},
551+
505552
/**
506553
* Delete a model
507554
*/

0 commit comments

Comments
 (0)