Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

109 lignes
4.0 KiB

  1. import md5 from '~/utils/md5'
  2. /**
  3. * 形象照 / 职业照 / 艺术写真(混元生图 3.0)
  4. *
  5. * 与老照片同一套链路:create 走 multipart 直传原图,避免先传 CDN 再由后端回源下载一次;
  6. * 配置、详情、列表等查询类接口用 useApi() 的普通 POST。
  7. * 一次提交 1~4 张,每张是一个独立的混元子任务、独立计费,失败的不扣点。
  8. */
  9. export function usePortrait() {
  10. const tokenCookie = useCookie('token', { path: '/' })
  11. const macCookie = useCookie('mac', { maxAge: 365 * 24 * 3600, path: '/' })
  12. const openIdCookie = useCookie('open_id', { path: '/' })
  13. const sourceCookie = useCookie('source', { path: '/' })
  14. const { getClientId, getClientIos } = useClientDevice()
  15. const tokenState = useState('auth_token', () => tokenCookie.value || '')
  16. const openIdState = useState('auth_open_id', () => openIdCookie.value || '')
  17. if (import.meta.client && !macCookie.value) {
  18. macCookie.value = createUuid()
  19. }
  20. function createUuid() {
  21. if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID()
  22. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
  23. const random = Math.floor(Math.random() * 16)
  24. const value = char === 'x' ? random : (random & 0x3) | 0x8
  25. return value.toString(16)
  26. })
  27. }
  28. function getNonce() {
  29. const timeStr = Date.now().toString()
  30. return { timeStr, nonce: md5(timeStr).substring(4, 14) }
  31. }
  32. /**
  33. * 提交生成任务
  34. * @param {File} file 人像原图
  35. * @param {object} settings { style, model, ratio, count, extra_prompt, request_id, options }
  36. * options 是「选项组 key -> 选项 key」的映射(如 { background: 'white', outfit: 'formal' }),
  37. * 后端按这些 key 拼提示词,端上不传提示词本身。
  38. */
  39. async function create(file, settings = {}) {
  40. if (!file) throw new Error('请选择一张照片')
  41. const token = tokenState.value || tokenCookie.value || ''
  42. const { timeStr, nonce } = getNonce()
  43. const formData = new FormData()
  44. // ThinkJS 2 会先读公共参数,普通字段必须排在文件字段之前
  45. formData.append('token', token)
  46. formData.append('uid', openIdState.value || openIdCookie.value || '')
  47. formData.append('mac', macCookie.value || 'pc-portrait')
  48. formData.append('base_timestamp', String(Math.floor(Date.now() / 1000)))
  49. formData.append('client', String(getClientId()))
  50. formData.append('source', sourceCookie.value || '')
  51. formData.append('client_ios', String(getClientIos()))
  52. formData.append('version', '1.0.0')
  53. formData.append('version_code', '1')
  54. formData.append('request_id', settings.request_id || createUuid())
  55. formData.append('style', settings.style || '')
  56. formData.append('model', settings.model || '')
  57. formData.append('ratio', settings.ratio || '')
  58. formData.append('count', String(settings.count || 1))
  59. if (settings.extra_prompt) formData.append('extra_prompt', settings.extra_prompt)
  60. Object.entries(settings.options || {}).forEach(([key, value]) => {
  61. if (value) formData.append(key, value)
  62. })
  63. formData.append('file', file)
  64. let result
  65. try {
  66. result = await $fetch('/api/portrait/create', {
  67. method: 'POST',
  68. headers: { token, timestr: timeStr, nonce },
  69. body: formData,
  70. })
  71. } catch (error) {
  72. const data = error?.data
  73. if (data && typeof data === 'object' && data.msg) {
  74. const normalized = new Error(data.msg)
  75. normalized.code = data.code || 1000
  76. normalized.data = data.data || {}
  77. throw normalized
  78. }
  79. throw error
  80. }
  81. if (result.code === 1009) {
  82. const { logout, showLogin } = useUser()
  83. logout()
  84. showLogin.value = true
  85. }
  86. if (result.code !== 0) {
  87. const error = new Error(result.msg || '提交失败,请稍后重试')
  88. error.code = result.code || 1000
  89. error.data = result.data || {}
  90. throw error
  91. }
  92. return result
  93. }
  94. return {
  95. create,
  96. createRequestId: createUuid,
  97. }
  98. }