193 lines
4.5 KiB
TypeScript
193 lines
4.5 KiB
TypeScript
import { invoke } from '@tauri-apps/api/core';
|
|
import { save } from '@tauri-apps/plugin-dialog';
|
|
import { GroundingSource } from '../types/ragGrounding';
|
|
|
|
/**
|
|
* 图片下载选项
|
|
*/
|
|
export interface ImageDownloadOptions {
|
|
/** 建议的文件名 */
|
|
suggestedName?: string;
|
|
/** 文件扩展名 */
|
|
extension?: string;
|
|
/** 是否显示保存对话框 */
|
|
showSaveDialog?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 图片下载结果
|
|
*/
|
|
export interface ImageDownloadResult {
|
|
/** 是否成功 */
|
|
success: boolean;
|
|
/** 保存的文件路径 */
|
|
filePath?: string;
|
|
/** 错误信息 */
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* 图片下载服务
|
|
* 支持从URI下载图片到本地
|
|
*/
|
|
export class ImageDownloadService {
|
|
/**
|
|
* 下载图片到本地
|
|
*/
|
|
static async downloadImage(
|
|
source: GroundingSource,
|
|
options: ImageDownloadOptions = {}
|
|
): Promise<ImageDownloadResult> {
|
|
try {
|
|
const { suggestedName, extension = 'jpg', showSaveDialog = true } = options;
|
|
|
|
// 检查图片URI
|
|
if (!source.uri) {
|
|
return {
|
|
success: false,
|
|
error: '图片URI不存在'
|
|
};
|
|
}
|
|
|
|
// 生成建议的文件名
|
|
const defaultName = suggestedName || this.generateFileName(source);
|
|
const fileName = `${defaultName}.${extension}`;
|
|
|
|
let filePath: string | null = null;
|
|
|
|
if (showSaveDialog) {
|
|
// 显示保存对话框
|
|
filePath = await save({
|
|
defaultPath: fileName,
|
|
filters: [
|
|
{
|
|
name: '图片文件',
|
|
extensions: ['jpg', 'jpeg', 'png', 'webp', 'gif']
|
|
},
|
|
{
|
|
name: '所有文件',
|
|
extensions: ['*']
|
|
}
|
|
]
|
|
});
|
|
|
|
if (!filePath) {
|
|
return {
|
|
success: false,
|
|
error: '用户取消了保存操作'
|
|
};
|
|
}
|
|
} else {
|
|
// 使用默认下载目录
|
|
filePath = await this.getDefaultDownloadPath(fileName);
|
|
}
|
|
|
|
// 调用后端下载命令
|
|
await invoke('download_image_from_uri', {
|
|
uri: source.uri,
|
|
filePath: filePath
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
filePath: filePath
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('图片下载失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '下载失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量下载图片
|
|
*/
|
|
static async downloadImages(
|
|
sources: GroundingSource[],
|
|
options: ImageDownloadOptions = {}
|
|
): Promise<ImageDownloadResult[]> {
|
|
const results: ImageDownloadResult[] = [];
|
|
|
|
for (const source of sources) {
|
|
const result = await this.downloadImage(source, {
|
|
...options,
|
|
showSaveDialog: false // 批量下载时不显示对话框
|
|
});
|
|
results.push(result);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* 生成文件名
|
|
*/
|
|
private static generateFileName(source: GroundingSource): string {
|
|
const title = source.title || 'fashion_image';
|
|
const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '');
|
|
|
|
// 清理文件名中的特殊字符
|
|
const cleanTitle = title
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/\s+/g, '_')
|
|
.toLowerCase();
|
|
|
|
return `${cleanTitle}_${timestamp}`;
|
|
}
|
|
|
|
/**
|
|
* 获取默认下载路径
|
|
*/
|
|
private static async getDefaultDownloadPath(fileName: string): Promise<string> {
|
|
try {
|
|
// 调用后端获取默认下载目录
|
|
const downloadDir = await invoke<string>('get_default_download_directory');
|
|
return `${downloadDir}/${fileName}`;
|
|
} catch (error) {
|
|
// 如果获取失败,使用当前目录
|
|
return fileName;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查图片是否可下载
|
|
*/
|
|
static isDownloadable(source: GroundingSource): boolean {
|
|
return !!(source.uri && source.uri.startsWith('http'));
|
|
}
|
|
|
|
/**
|
|
* 获取图片信息
|
|
*/
|
|
static getImageInfo(source: GroundingSource): {
|
|
title: string;
|
|
description: string;
|
|
size?: string;
|
|
format?: string;
|
|
} {
|
|
const imageData = source.content?.text || source.content;
|
|
|
|
return {
|
|
title: source.title || '时尚图片',
|
|
description: imageData?.description || '',
|
|
size: imageData?.size,
|
|
format: this.extractImageFormat(source.uri)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 从URI提取图片格式
|
|
*/
|
|
private static extractImageFormat(uri?: string): string | undefined {
|
|
if (!uri) return undefined;
|
|
|
|
const match = uri.match(/\.([a-zA-Z0-9]+)(?:\?|$)/);
|
|
return match ? match[1].toLowerCase() : undefined;
|
|
}
|
|
}
|
|
|
|
export default ImageDownloadService;
|