fetch-meta.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const models = require('../../models');
  2. const fetch = require('node-fetch');
  3. /**
  4. *
  5. curl --location 'https://ark.cn-beijing.volces.com/api/v3/chat/completions' \
  6. --header 'Authorization: Bearer fb8942c2-fe94-4092-80fc-233e252f7090' \
  7. --header 'Content-Type: application/json' \
  8. --data '{
  9. "model": "ep-20250206115552-7qg5c",
  10. "messages": [
  11. {"role": "user", "content": [
  12. {
  13. "type":"text",
  14. "text": "根据图片生成标题(title, 60个字符以内)、简要描述(description, 用于网站SEO的meta description,160个字符以内,尽量包含Coloring Page关键字)、文案描述(copy, 200字左右,尽量包含Coloring Page 关键字)。 以json格式输出,支持语言中文(zh)、英语(en)、西班牙语(es)、葡萄牙语(pt)、日语(ja),形如: { title: {zh:'', en:'', es: '', pt: '', ja: ''}, description: {zh:'', en:'', es: '', pt: '', ja: ''}, copy:{zh:'', en:'', es: '', pt: '', ja: ''} }"
  15. },
  16. {
  17. "type": "image_url",
  18. "image_url": {
  19. "url": "https://color.jccytech.cn/thumbs/v2/work/320/67a241674f9d65537938e36d.png"
  20. }
  21. }
  22. ]}
  23. ]
  24. }'
  25. */
  26. let apiKey = require('process').env.ARK_API_KEY;
  27. const url = "https://ark.cn-beijing.volces.com/api/v3/chat/completions";
  28. let headers = {
  29. 'Authorization': `Bearer ${apiKey}`,
  30. 'Content-Type': 'application/json'
  31. }
  32. /**
  33. * 从豆包获取图片的标题和文案描述
  34. * @param {*} imageUrl
  35. */
  36. async function fetchMetaFromDoubao(imageUrl) {
  37. let data = {
  38. "model": "ep-20250206115552-7qg5c", // Doubao-1.5...ion-pro-32k 当前最新,贵,响应慢,效果好
  39. // "model": "ep-20250204231910-4phb8", // Doubao-vision-lite-32k 便宜点,相应速度快
  40. "messages": [
  41. {
  42. "role": "user", "content": [
  43. {
  44. "type": "text",
  45. "text": "根据图片生成标题(title, 60个字符以内)、简要描述(description, 用于网站SEO的meta description,160个字符以内,尽量包含Coloring Page关键字)、文案描述(copy, 200字左右,尽量包含Coloring Page 关键字)。 以json格式输出,支持语言中文(zh)、英语(en)、西班牙语(es)、葡萄牙语(pt)、日语(ja),形如: { title: {zh:'', en:'', es: '', pt: '', ja: ''}, description: {zh:'', en:'', es: '', pt: '', ja: ''}, copy:{zh:'', en:'', es: '', pt: '', ja: ''} }"
  46. },
  47. {
  48. "type": "image_url",
  49. "image_url": {
  50. "url": `${imageUrl}`
  51. }
  52. }
  53. ]
  54. }
  55. ]
  56. }
  57. const jsonData = JSON.stringify(data);
  58. const response = await fetch(url, { method: 'POST', headers, body: jsonData });
  59. let responseJson = await response.json();
  60. console.log(responseJson);
  61. return responseJson.choices[0].message.content;
  62. }
  63. async function run() {
  64. let done = 0;
  65. let duration = 0;
  66. let hour, minute, second;
  67. let start = Date.now();
  68. // 筛选出所有已经ready并且还没有title的图
  69. let query = { status: { $gte: 7000 }, open: true, $or: [{ copy: { $exists: false } }, { copy: null }] };
  70. let docs = await models.Art.find(query).sort({ publishTime: 'desc' }); // 内存有限,每次跑1000个
  71. let total = docs.length;
  72. console.log('total:', total);
  73. if (total <= 0) return;
  74. for (let doc of docs) {
  75. console.log(`process ${doc._id}`);
  76. let thumbUrl = `http://color.jccytech.cn/thumbs/v2/work/320/${doc._id}.png`;
  77. if (doc.hasSpecial) {
  78. thumbUrl = `http://color.jccytech.cn/thumbs/v2/special/320/${doc._id}.png`;
  79. }
  80. console.time(doc._id);
  81. try {
  82. let metaInfo = await fetchMetaFromDoubao(thumbUrl);
  83. console.log(metaInfo);
  84. let metaInfoJson = JSON.parse(metaInfo);
  85. let titleJson = metaInfoJson.title;
  86. let descJson = metaInfoJson.description;
  87. let copyJson = metaInfoJson.copy;
  88. let title = JSON.stringify(titleJson);
  89. let desc = JSON.stringify(descJson);
  90. let copy = JSON.stringify(copyJson);
  91. doc.title = title;
  92. doc.desc = desc;
  93. doc.copy = copy;
  94. await doc.save();
  95. } catch (e) {
  96. console.error(e.message);
  97. }
  98. console.timeEnd(doc._id);
  99. done++;
  100. duration = (Date.now() - start) / 1000;
  101. hour = (Math.floor(duration / 60 / 60)).toString().padStart(2, '0');
  102. minute = (Math.floor(duration / 60) % 60).toString().padStart(2, '0');
  103. second = (Math.floor(duration) % 60).toString().padStart(2, '0');
  104. console.log('progress: ' + Math.floor((100 * done / total)) + '% used time: ' + hour + ':' + minute + ':' + second);
  105. }
  106. run();
  107. }
  108. async function test() {
  109. let metaInfo = await fetchMetaFromDoubao("https://color.jccytech.cn/thumbs/v2/work/640/67a254ec4f9d65537938e5c5.png");
  110. console.log(metaInfo);
  111. let metaInfoJson = JSON.parse(metaInfo);
  112. let titleJson = metaInfoJson.title;
  113. let descJson = metaInfoJson.copy;
  114. let title = JSON.stringify(titleJson);
  115. let desc = JSON.stringify(descJson);
  116. console.log(title);
  117. console.log(desc);
  118. }
  119. module.exports = { run }
  120. if (require.main == module) {
  121. run();
  122. }