| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- import type { UiMessage } from '@/components/messages/types'
- import { normalizeAssistantMediaMarkdown } from '@/utils/mediaMarkdown'
- import type { LibraryKind, UiLibraryItem } from './types'
- const imageExtensions = new Set(['apng', 'avif', 'bmp', 'gif', 'heic', 'heif', 'ico', 'jfif', 'jpeg', 'jpg', 'jxl', 'png', 'svg', 'tif', 'tiff', 'webp'])
- const videoExtensions = new Set(['avi', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'webm'])
- export function previewItemFromUrl(name: string, url: string, id = `local:${url}`, kind?: LibraryKind): UiLibraryItem {
- const extension = name.split('.').at(-1)?.toLocaleLowerCase() || ''
- const inferred = imageExtensions.has(extension) ? 'image'
- : videoExtensions.has(extension) ? 'video'
- : ['mp3', 'wav', 'm4a', 'aac', 'ogg'].includes(extension) ? 'audio'
- : extension === 'pdf' ? 'pdf'
- : ['md', 'markdown', 'txt', 'json', 'yaml', 'yml', 'csv', 'js', 'ts', 'py', 'sh'].includes(extension) ? 'text' : 'file'
- return { id, name, kind: kind || inferred, previewUrl: url, downloadUrl: url }
- }
- export function mediaUrlIdentity(url: string): string {
- try {
- return new URL(url, window.location.origin).href
- } catch {
- return url
- }
- }
- function nameFromUrl(url: string): string {
- try { return decodeURIComponent(new URL(url, window.location.origin).pathname.split('/').at(-1) || '媒体') } catch { return '媒体' }
- }
- /** The ordered image/video sequence visible in one normal or group conversation. */
- export function mediaItemsFromMessages(messages: UiMessage[]): UiLibraryItem[] {
- const result: UiLibraryItem[] = []
- const seen = new Set<string>()
- const append = (item: UiLibraryItem) => {
- if (!item.previewUrl || !['image', 'video'].includes(item.kind)) return
- const identity = mediaUrlIdentity(item.previewUrl)
- if (seen.has(identity)) return
- seen.add(identity)
- result.push(item)
- }
- for (const message of messages) {
- for (const attachment of message.attachments ?? []) {
- if (!attachment.url || !['image', 'video'].includes(attachment.kind || 'file')) continue
- append(previewItemFromUrl(attachment.name, attachment.url, `${message.id}:${attachment.id}`, attachment.kind))
- }
- const content = message.role === 'assistant' ? normalizeAssistantMediaMarkdown(message.content) : message.content
- const markdownMedia = /!\[[^\]]*\]\(([^)\s]+)\)|\[[^\]]+\]\(([^)\s]+)\)/g
- for (let match = markdownMedia.exec(content); match; match = markdownMedia.exec(content)) {
- const url = match[1] || match[2]
- if (!url) continue
- const item = previewItemFromUrl(nameFromUrl(url), url, `${message.id}:${url}`)
- append(item)
- }
- }
- return result
- }
|