158 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
|  
 | |
| import {
 | |
|   uploadFileV2,
 | |
|   type EventPayloadMaps as BaseEventPayloadMap,
 | |
|   type UploaderInstance,
 | |
|   type UploadFileV2Param,
 | |
|   type FileItem,
 | |
| } from '@coze-arch/bot-utils/upload-file-v2';
 | |
| import { GetImageScene } from '@coze-arch/bot-api/playground_api';
 | |
| import { PlaygroundApi } from '@coze-arch/bot-api';
 | |
| 
 | |
| export type EventPayloadMap = BaseEventPayloadMap & {
 | |
|   ready: boolean;
 | |
| };
 | |
| 
 | |
| export interface UploadControllerProps {
 | |
|   controllerId: string;
 | |
|   fileList: File[];
 | |
|   userId: string;
 | |
|   onProgress?: (
 | |
|     event: EventPayloadMap['progress'],
 | |
|     controllerId: string,
 | |
|   ) => void;
 | |
|   onComplete?: (
 | |
|     event: {
 | |
|       url: string;
 | |
|       uri: string;
 | |
|     }[],
 | |
|     controllerId: string,
 | |
|   ) => void;
 | |
|   onUploadError?: (event: Error, controllerId: string) => void;
 | |
|   onUploaderReady?: (
 | |
|     event: EventPayloadMap['ready'],
 | |
|     controllerId: string,
 | |
|   ) => void;
 | |
|   onStartUpload?: (
 | |
|     param: Parameters<Required<UploadFileV2Param>['onStartUpload']>[number],
 | |
|     controllerId: string,
 | |
|   ) => void;
 | |
|   onGetUploadInstanceError?: (error: Error, controllerId: string) => void;
 | |
|   onGetTokenError?: (error: Error, controllerId: string) => void;
 | |
|   onAuditFailed?: (controllerId: string) => void;
 | |
| }
 | |
| 
 | |
| const isImage = (file: File) => file.type.startsWith('image/');
 | |
| 
 | |
| export class UploadController {
 | |
|   controllerId: string;
 | |
|   abortController: AbortController;
 | |
|   uploader: UploaderInstance | null;
 | |
|   fileItemList: FileItem[];
 | |
| 
 | |
|   constructor({
 | |
|     controllerId,
 | |
|     fileList,
 | |
|     userId,
 | |
|     onProgress,
 | |
|     onComplete,
 | |
|     onUploadError,
 | |
|     onUploaderReady,
 | |
|     onStartUpload,
 | |
|     onGetTokenError,
 | |
|     onGetUploadInstanceError,
 | |
|     onAuditFailed,
 | |
|   }: UploadControllerProps) {
 | |
|     this.fileItemList = fileList.map(file => ({
 | |
|       file,
 | |
|       fileType: isImage(file) ? 'image' : 'object',
 | |
|     }));
 | |
|     this.controllerId = controllerId;
 | |
|     this.abortController = new AbortController();
 | |
|     this.uploader = null;
 | |
| 
 | |
|     uploadFileV2({
 | |
|       fileItemList: this.fileItemList,
 | |
|       userId,
 | |
|       signal: this.abortController.signal,
 | |
|       timeout: undefined,
 | |
|       onUploaderReady: uploader => {
 | |
|         this.uploader = uploader;
 | |
|         onUploaderReady?.(true, controllerId);
 | |
|       },
 | |
|       onProgress: event => onProgress?.(event, controllerId),
 | |
|       onUploadAllSuccess: async event => {
 | |
|         const uris = event.map(item => {
 | |
|           const uri = item.uploadResult.Uri;
 | |
|           if (!uri) {
 | |
|             throw new Error(`failed to get uri, item: ${item}`);
 | |
|           }
 | |
|           return uri;
 | |
|         });
 | |
|         try {
 | |
|           if (!uris || !uris.length) {
 | |
|             throw new Error(`upload success without uri, uploadID ${event}`);
 | |
|           }
 | |
| 
 | |
|           const result = await PlaygroundApi.GetImagexShortUrl({
 | |
|             uris,
 | |
|             scene: GetImageScene.BackgroundImage,
 | |
|           });
 | |
| 
 | |
|           const list = uris.map(item => {
 | |
|             if (!item) {
 | |
|               throw new Error(`failed to get url, uri: ${item}`);
 | |
|             }
 | |
|             return {
 | |
|               url: result.data?.url_info?.[item].url as string,
 | |
|               uri: item,
 | |
|             };
 | |
|           });
 | |
| 
 | |
|           if (!list) {
 | |
|             throw new Error(`failed to get urls, list: ${list}`);
 | |
|           }
 | |
|           if (!list.some(i => i.url)) {
 | |
|             onAuditFailed?.(controllerId);
 | |
|           } else {
 | |
|             onComplete?.(list, controllerId);
 | |
|           }
 | |
|         } catch (e) {
 | |
|           onUploadError?.(
 | |
|             e instanceof Error ? e : new Error(String(e)),
 | |
|             controllerId,
 | |
|           );
 | |
|         }
 | |
|       },
 | |
|       onUploadError: event => onUploadError?.(event.extra.error, controllerId),
 | |
|       onStartUpload: event => onStartUpload?.(event, controllerId),
 | |
|       onGetUploadInstanceError: error =>
 | |
|         onGetUploadInstanceError?.(error, controllerId),
 | |
|       onGetTokenError: error => onGetTokenError?.(error, controllerId),
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   cancel = () => {
 | |
|     this.abortController.abort();
 | |
|   };
 | |
| 
 | |
|   pause = () => {
 | |
|     this.uploader?.pause();
 | |
|   };
 | |
| }
 |