Files
superwork/vscode/webview-ui/src/codeReader/qaImages.ts
T

62 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 「问 AI」输入框里贴图、拖图的规则(不碰 React):认哪些格式、每张多大、最多几张,
* 贴进来还没发的图片在页面上的样子,发给扩展端的样子。
*/
import type { AskImage } from './types'
/** 认的格式:Claude 认的这几种 */
export const IMAGE_TYPES: readonly string[] = ['image/png', 'image/jpeg', 'image/gif', 'image/webp']
export const MAX_IMAGE_BYTES = 5 * 1024 * 1024
/** 一个问题最多带几张 */
export const MAX_IMAGES = 6
/** 贴进输入框、还没发的一张图片:url 是 data: 地址,缩略图、大图、发送都用它 */
export interface PendingImage {
id: number
mediaType: string
url: string
}
/** 剪贴板 / 拖进来的东西里的文件;文字、网页片段这些不算(照常粘成文字) */
export function transferFiles<F>(items: ArrayLike<{ kind: string, getAsFile: () => F | null }>): F[] {
return Array.from(items).flatMap(item => item.kind === 'file' ? item.getAsFile() ?? [] : [])
}
/**
* 挑出能带上的:只认 PNG、JPEG、GIF、WebP,每张不超过 MAX_IMAGE_BYTES,连同已经有的 have 张最多 MAX_IMAGES 张,按先后取;
* 有没加上的给一句原因。
*/
export function pickImages<F extends { type: string, size: number }>(files: readonly F[], have: number): { accepted: F[], notice?: string } {
const images = files.filter(file => IMAGE_TYPES.includes(file.type))
const small = images.filter(file => file.size <= MAX_IMAGE_BYTES)
const accepted = small.slice(0, Math.max(0, MAX_IMAGES - have))
const reasons = [
...(images.length < files.length ? ['只能贴 PNG、JPEG、GIF、WebP 图片'] : []),
...(small.length < images.length ? [`每张图片不能超过 ${MAX_IMAGE_BYTES / 1024 / 1024} MB`] : []),
...(accepted.length < small.length ? [`一个问题最多带 ${MAX_IMAGES} 张图片`] : []),
]
return reasons.length === 0
? { accepted }
: { accepted, notice: `${reasons.join(';')},有 ${files.length - accepted.length} 个没加上。` }
}
let imageCounter = 0
/** 读成 data: 地址(缩略图直接用,页面的安全策略允许 data: 图片) */
export function readImage(file: File): Promise<PendingImage> {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve({ id: ++imageCounter, mediaType: file.type, url: String(reader.result) })
reader.onerror = () => reject(reader.error ?? new Error('读不出图片'))
reader.readAsDataURL(file)
})
}
/** 发给扩展端的样子:data: 地址去掉前缀剩下的 base64 */
export function toAskImage(image: PendingImage): AskImage {
return { mediaType: image.mediaType, base64: image.url.slice(image.url.indexOf(',') + 1) }
}