context.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { inject, onBeforeUnmount, provide, ref, watch, type InjectionKey, type Ref } from 'vue'
  2. import type { AgentClient } from '@agent-server/client'
  3. /** 组件只需要带鉴权地下载文件:AgentClient 与 BotClient 都满足 */
  4. export type FileClient = Pick<AgentClient, 'fileBlob'>
  5. const CLIENT_KEY: InjectionKey<FileClient> = Symbol('agent-client')
  6. export function provideClient(client: FileClient) {
  7. provide(CLIENT_KEY, client)
  8. }
  9. export function useClient(): FileClient {
  10. const c = inject(CLIENT_KEY)
  11. if (!c) throw new Error('chat-ui: 缺少 AgentClient(请在外层使用 <AgentChat> 或 provideClient)')
  12. return c
  13. }
  14. /** 带鉴权地加载文件为 object URL(Agent Key 模式下 <img src> 无法携带请求头) */
  15. export function useFileObjectUrl(fileId: Ref<string | null>): Ref<string | null> {
  16. const client = useClient()
  17. const url = ref<string | null>(null)
  18. let current: string | null = null
  19. const release = () => {
  20. if (current) URL.revokeObjectURL(current)
  21. current = null
  22. }
  23. watch(fileId, async id => {
  24. release()
  25. url.value = null
  26. if (!id) return
  27. try {
  28. current = URL.createObjectURL(await client.fileBlob(id))
  29. url.value = current
  30. } catch {
  31. url.value = null
  32. }
  33. }, { immediate: true })
  34. onBeforeUnmount(release)
  35. return url
  36. }
  37. export async function downloadFile(client: FileClient, fileId: string, name: string) {
  38. const blob = await client.fileBlob(fileId)
  39. const href = URL.createObjectURL(blob)
  40. const a = document.createElement('a')
  41. a.href = href
  42. a.download = name
  43. a.click()
  44. setTimeout(() => URL.revokeObjectURL(href), 10_000)
  45. }