feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="coz_image_broken">
<g id="Union">
<path
d="M42.7765 5.33301H7.99935C5.06602 5.33301 2.66602 7.73301 2.66602 10.6663V53.333C2.66602 56.2663 5.06602 58.6663 7.99935 58.6663H11.9844L15.0636 53.333H7.99935V10.6663H39.6973L42.7765 5.33301Z"
fill="#060709" fill-opacity="0.3" />
<path
d="M25.1667 35.8339L24.5648 35.232C24.2524 34.9196 23.7459 34.9196 23.4335 35.232L12.0315 46.634C11.5275 47.138 11.8845 47.9997 12.5972 47.9997H18.1428L25.1667 35.8339Z"
fill="#060709" fill-opacity="0.3" />
<path
d="M27.3804 47.9997L31.9997 39.9989L49.2999 22.6987C49.8039 22.1947 50.6656 22.5517 50.6656 23.2644V47.1997C50.6656 47.6415 50.3074 47.9997 49.8656 47.9997H35.4041L35.4011 47.9997H27.3804Z"
fill="#060709" fill-opacity="0.3" />
<path
d="M24.3012 53.333H55.9994V10.6663H48.9349L52.0141 5.33301H55.9994C58.9327 5.33301 61.3327 7.73301 61.3327 10.6663V53.333C61.3327 56.2663 58.9327 58.6663 55.9994 58.6663H21.222L24.3012 53.333Z"
fill="#060709" fill-opacity="0.3" />
<path
d="M23.9993 21.333C23.9993 24.2785 21.6115 26.6663 18.666 26.6663C15.7205 26.6663 13.3327 24.2785 13.3327 21.333C13.3327 18.3875 15.7205 15.9997 18.666 15.9997C21.6115 15.9997 23.9993 18.3875 23.9993 21.333Z"
fill="#060709" fill-opacity="0.3" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,13 @@
<svg width="32" height="40" viewBox="0 0 32 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon">
<path id="Rectangle 2526"
d="M1 5.00032C1 3.15938 2.49238 1.66699 4.33333 1.66699H20.3096C20.7517 1.66699 21.1756 1.84259 21.4882 2.15515L30.5118 11.1788C30.8244 11.4914 31 11.9153 31 12.3573V35.0003C31 36.8413 29.5076 38.3337 27.6667 38.3337H4.33333C2.49238 38.3337 1 36.8413 1 35.0003V5.00032Z"
fill="#F22435" />
<path id="Rectangle 2527"
d="M21 2.27054C21 2.04782 21.2693 1.93628 21.4268 2.09377L30.5732 11.2402C30.7307 11.3977 30.6192 11.667 30.3964 11.667H24.3333C22.4924 11.667 21 10.1746 21 8.33366V2.27054Z"
fill="white" fill-opacity="0.6" />
<path id="icon_file_pdf_nor"
d="M25.2518 25.9187C24.8381 25.4344 23.9899 25.1989 22.6586 25.1989C21.8847 25.1989 20.8187 25.2184 19.7474 25.3774C16.8213 23.2679 16.1355 21.0018 16.1355 21.0018C16.1355 21.0018 16.6352 19.7474 16.6669 17.6985C16.687 16.4033 16.4817 15.4373 15.958 15.0221C15.735 14.8452 15.4111 14.6973 15.085 14.6973C14.8305 14.6973 14.5922 14.771 14.397 14.9118C12.8758 16.0093 14.5366 21.1831 14.581 21.321C13.8632 23.0629 12.9589 24.9084 12.0281 26.53C11.7257 27.0568 11.7257 27.067 11.5226 27.3062C11.5226 27.3062 8.85979 28.6268 7.61117 30.091C6.90568 30.9184 6.88279 31.4864 6.92024 31.9121C6.9806 32.4226 7.6314 32.8791 8.28657 32.8791C8.31375 32.8791 8.34109 32.8783 8.36787 32.8766C9.03373 32.8361 9.7744 32.6529 10.5986 31.8733C11.1953 31.3089 11.8662 29.7761 12.7288 28.2763C15.2036 27.5821 17.3816 27.0877 19.2069 26.8058C20.5454 27.516 22.5368 28.3204 23.8925 28.3204C24.3472 28.3204 24.713 28.229 24.9797 28.0487C25.2988 27.8331 25.4343 27.5644 25.5185 27.067C25.6028 26.5696 25.4855 26.1924 25.2518 25.9187ZM22.3422 26.6973C23.5782 26.6973 24.2475 26.9154 24.5913 27.0983C24.6973 27.1547 24.7744 27.2092 24.8291 27.2546C24.7322 27.3297 24.5417 27.4246 24.1973 27.4246C23.6263 27.4246 22.8767 27.1826 21.9626 26.7039C22.0926 26.6995 22.2192 26.6973 22.3422 26.6973ZM15.2435 15.7934L15.2456 15.7882C15.4385 15.9303 15.5286 16.9284 15.5105 17.5071C15.4862 18.2837 15.4805 18.5838 15.383 19.0609C15.1187 18.0662 15.1 16.2782 15.2435 15.7934ZM15.3044 23.0609C15.9073 24.0539 16.6717 25.0594 17.5331 25.8273C15.8519 26.1877 14.4559 26.5184 13.4514 26.87C14.5281 25.0053 15.2338 23.2457 15.3044 23.0609ZM8.51616 31.4741C8.66829 31.2491 9.08392 30.8131 10.138 29.97C9.57227 31.2731 8.93696 31.4741 8.34636 31.7881C8.39094 31.6848 8.44702 31.5764 8.51616 31.4741Z"
fill="white" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,53 @@
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVG" clip-path="url(#clip0_2697_59356)">
<path id="Vector" d="M100.749 191.987C106.964 191.429 109.45 182.788 111.108 176.935L116.08 191.987H100.749Z"
fill="black" stroke="black" />
<path id="Vector_2"
d="M103.973 62.9743C100.032 57.9437 102.024 49.1557 111.318 39.9402C124.298 28.058 136.847 30.6854 137.435 30.9599C138.023 31.2344 150.439 40.0194 162.26 52.2647C174.082 64.5099 186.453 74.9969 186.605 91.7998C186.758 108.603 169.346 114.685 156.573 114.761C143.8 114.837 115.296 114.479 109.821 113.567C106.386 118.074 100.923 122.945 98.9084 124.001C103.135 127.633 118.226 142.977 120.041 146.217C121.856 149.458 129.763 160.736 126.133 178.496C124.47 186.634 117.964 190.801 111.242 192.108C111.242 192.108 102.036 192.056 98.9084 192.108C91.1321 192.238 10.8886 192.108 8.55517 192.108C6.22176 192.108 5.54895 190.015 8.55517 183.91C11.5614 177.805 22.6449 158.542 28.4534 155.104C30.7649 153.8 35.9864 157.174 37.0838 157.956C38.11 158.687 39.1051 159.55 40.5275 159.432C41.95 159.313 49.3663 159.28 51.7358 159.357C47.4505 156.357 31.7026 141.672 29.7782 134.527C28.2489 128.849 30.0789 125.569 30.8916 124.812C22.363 119.824 13.6849 109.92 17.0807 95.2047C18.0332 91.077 20.6119 86.7769 22.5343 85.5382C26.1495 83.2087 38.4161 82.0313 45.8545 81.352C78.5523 78.3659 153.04 79.448 155.302 79.4695C152.184 77.0944 140.103 63.5378 139.822 63.0812C139.049 65.2938 135.994 68.1035 133.711 67.7874C131.685 67.5069 130.558 64.3341 132.902 59.3074C132.095 60.1317 131.256 60.9141 130.411 61.6007C129.167 62.6124 127.607 62.8197 127.041 61.6007C126.542 60.5285 126.708 58.4841 127.86 55.7601C126.628 56.9222 125.401 57.8872 124.299 58.4453C120.61 60.312 119.698 53.2123 124.64 47.1704C117.537 50.6427 115.523 53.479 113.759 57.6388C112.672 60.2028 112.288 62.5533 109.297 63.8825C107.003 64.9022 105.082 64.3905 103.973 62.9743Z"
fill="white" />
<path id="Vector_3"
d="M124.64 47.1704C117.537 50.6427 115.523 53.479 113.759 57.6388C112.672 60.2028 112.288 62.5533 109.297 63.8825C107.003 64.9022 105.082 64.3905 103.973 62.9743C100.032 57.9437 102.024 49.1557 111.318 39.9402C124.298 28.058 136.847 30.6854 137.435 30.9599C138.023 31.2344 150.439 40.0194 162.26 52.2647C174.082 64.5099 186.453 74.9969 186.605 91.7998C186.758 108.603 169.346 114.685 156.573 114.761C143.8 114.837 115.296 114.479 109.821 113.567M124.64 47.1704C131.639 44.5726 131.278 42.1983 130.866 41.7279C130.454 41.2574 126.228 44.4651 124.64 47.1704ZM124.64 47.1704C119.698 53.2123 120.61 60.312 124.299 58.4453C129.147 55.9917 136.386 45.6727 135.941 45.3268C135.625 45.0809 133.867 46.0738 130.62 50.8241C127.079 56.0054 126.275 59.9522 127.041 61.6007C127.607 62.8197 129.167 62.6124 130.411 61.6007C135.204 57.7034 139.821 50.7163 139.575 50.5407C139.329 50.3651 137.732 50.9884 133.966 57.3084C130.287 63.4832 131.428 67.4713 133.711 67.7874C135.994 68.1035 139.049 65.2938 139.822 63.0812C140.103 63.5378 152.184 77.0944 155.302 79.4695M109.821 113.567C106.386 118.074 100.923 122.945 98.9084 124.001M109.821 113.567C113.405 108.653 116.582 103.629 118.134 98.2721M155.302 79.4695C153.04 79.448 78.5523 78.3659 45.8545 81.352C38.4161 82.0313 26.1495 83.2087 22.5343 85.5382C20.6119 86.7769 18.0332 91.077 17.0807 95.2047C13.6849 109.92 22.363 119.824 30.8916 124.812M155.302 79.4695C157.563 79.491 161.438 80.1644 161.106 82.5709C160.89 84.1323 156.389 80.4494 155.302 79.4695ZM98.9084 124.001C103.135 127.633 118.226 142.977 120.041 146.217C121.856 149.458 129.763 160.736 126.133 178.496C124.47 186.634 117.964 190.801 111.242 192.108C111.242 192.108 102.036 192.056 98.9084 192.108C91.1321 192.238 10.8886 192.108 8.55517 192.108C6.22176 192.108 5.54895 190.015 8.55517 183.91C11.5614 177.805 22.6449 158.542 28.4534 155.104C30.7649 153.8 35.9864 157.174 37.0838 157.956C38.11 158.687 39.1051 159.55 40.5275 159.432C41.95 159.313 49.3663 159.28 51.7358 159.357M98.9084 124.001C96.6165 124.001 90.7454 124.001 88.0964 124.001M51.7358 159.357C54.7946 159.456 61.3307 158.866 63.583 160.9C65.6279 162.747 64.1419 165.492 61.0496 164.742C57.4122 163.859 52.9212 160.186 51.7358 159.357ZM51.7358 159.357C47.4505 156.357 31.7026 141.672 29.7782 134.527C28.2489 128.849 30.0789 125.569 30.8916 124.812M88.0964 124.001C80.0087 115.502 70.3925 107.822 65.2849 104.111M88.0964 124.001C88.9352 124.883 89.7576 125.773 90.5567 126.669C92.5002 128.847 99.0319 136.266 99.6817 140.816C100.051 143.403 99.7415 147.609 98.7755 151.776M30.8916 124.812C34.2264 126.6 42.7695 130.887 50.2636 133.724M50.2636 133.724C59.6313 137.271 69.4569 139.982 72.6401 143.62C75.8233 147.258 71.8787 152.292 70.727 156.371C70.4364 157.4 70.1046 158.961 70.4616 159.864C70.9131 161.004 72.2369 161.227 74.2052 159.694C77.7304 156.949 80.8578 150.129 81.5086 148.122C82.1594 146.116 77.0741 156.386 76.5317 160.921C75.9894 165.456 80.0199 164.713 82.7287 160.921C85.9012 156.479 87.5286 151.376 87.7455 150.4C87.9625 149.424 85.0129 155.845 84.1457 159.694C83.912 160.732 83.3026 163.166 84.1457 164.136C85.1047 165.239 87.017 164.95 89.2218 161.41C91.7386 157.368 93.6028 151.702 93.8197 150.4C94.0366 149.099 90.7657 157.706 90.2724 161.898C89.926 164.84 90.935 166.275 94.45 161.898C96.4373 159.423 97.8851 155.616 98.7755 151.776M50.2636 133.724C48.2901 136.441 46.0125 139.015 39.457 140.045M98.7755 151.776C101.959 154.697 106.119 160.024 107.017 165.952C107.915 171.881 107.017 179.415 97.6167 187.298M65.2849 104.111C59.58 99.9652 56.3188 99.5478 53.8284 99.5478C50.1874 99.5478 49.351 101.504 52.6689 102.748C55.9867 103.993 62.0179 104.111 65.2849 104.111ZM65.2849 104.111C67.8362 104.111 70.9808 104.111 72.1994 104.111"
stroke="#515151" />
<path id="Vector_4" fill-rule="evenodd" clip-rule="evenodd"
d="M115.942 192.126L110.767 176.459L110.643 176.896C109.814 179.826 108.782 183.434 107.185 186.38C105.586 189.328 103.443 191.576 100.406 191.848L100.418 192.126H115.942Z"
fill="#515151" />
<path id="Vector_5" fill-rule="evenodd" clip-rule="evenodd"
d="M122.415 137.352L127.509 146.829H120.059L114.965 137.352H122.415Z" fill="#C6CACD" />
<path id="Vector_6" d="M104.096 141.476H138.046L152.872 168.908H118.922L104.096 141.476Z" fill="white"
stroke="#515151" />
<path id="Vector_7" d="M183.117 155.135H139.521V193.996H183.117V155.135Z" fill="#E6E8EA" stroke="#515151" />
<path id="Vector_8" d="M139.868 154.692L149.154 137.852H192.608L183.322 154.692H139.868Z" fill="#E6E8EA"
stroke="#515151" />
<path id="Vector_9" d="M139.407 155.135H111.223V193.996H139.407V155.135Z" fill="#E6E8EA" stroke="#515151" />
<path id="Vector_10" fill-rule="evenodd" clip-rule="evenodd"
d="M166.556 154.913L170.458 147.944H164.326L160.735 154.356H160.423V154.913V167.735H166.556V154.913Z"
fill="#515151" />
<path id="Vector_11"
d="M45.5783 71.8461C63.8982 71.8461 78.7494 56.9949 78.7494 38.675C78.7494 20.3551 63.8982 5.50391 45.5783 5.50391C27.2584 5.50391 12.4072 20.3551 12.4072 38.675C12.4072 56.9949 27.2584 71.8461 45.5783 71.8461Z"
fill="#EAF5FF" />
<path id="Vector_12" fill-rule="evenodd" clip-rule="evenodd"
d="M48.8461 47.665C50.6179 47.215 51.7204 45.5669 51.3111 43.7853C51.0323 42.5717 51.5826 41.3761 52.4498 40.4825C55.4773 37.3627 57.5348 32.7049 56.1132 27.7053C55.3646 24.9884 53.3434 22.6095 50.6833 21.1086C47.7791 19.509 44.2101 19.2031 40.8075 20.2426L40.6361 20.3154C34.8596 22.2833 32.3351 27.3701 32.3805 32.2789C32.3995 34.3262 34.4998 35.484 36.4691 34.924C38.4729 34.3542 39.4418 32.1175 40.1034 30.1421C40.4945 28.9745 41.3603 27.9109 43.0322 27.3905C44.9906 26.7616 46.3829 27.1822 47.1882 27.6496C48.0663 28.2885 48.7729 29.0001 48.9652 29.9299C49.8124 32.4026 48.1401 35.1354 46.2285 36.3514C43.5453 38.0338 43.2021 41.8296 43.7714 45.1416C44.1324 47.2422 46.3165 48.3075 48.3823 47.7828L48.8461 47.665ZM48.8717 50.8187C51.0242 50.1214 53.3344 51.3012 54.0317 53.4537C54.7289 55.6062 53.5492 57.9164 51.3967 58.6136C49.2442 59.3109 46.934 58.1312 46.2367 55.9787C45.5395 53.8262 46.7192 51.5159 48.8717 50.8187Z"
fill="#0064FA" />
<path id="Vector_13" fill-rule="evenodd" clip-rule="evenodd"
d="M98.6325 82.5785L98.522 82.5688L98.4877 82.6743C97.7016 85.0957 96.8311 87.9064 96.9691 90.7095C97.1077 93.5236 98.262 96.323 101.502 98.7181C104.667 101.057 108.08 100.494 110.687 98.5588C113.288 96.6288 115.105 93.324 115.105 90.1368C115.105 88.8872 114.291 87.8175 113.058 86.9175C111.823 86.0155 110.141 85.2636 108.343 84.6522C104.746 83.4288 100.649 82.7556 98.6325 82.5785ZM115.813 104.266C114.483 107.369 111.185 111.947 109.698 113.851L109.813 113.705L115.054 114.077L115.091 113.997C115.323 113.505 115.5 112.803 115.638 111.998C115.776 111.191 115.875 110.269 115.944 109.334C116.082 107.464 116.103 105.529 116.08 104.318L115.813 104.266ZM30.8576 124.273L30.697 124.171L29.3633 129.209L29.4735 129.257C33.8679 131.154 43.5848 133.309 50.5631 133.867L50.625 133.599C42.8485 130.557 34.4308 126.532 30.8576 124.273Z"
fill="#515151" />
<path id="Vector_14" d="M71.0303 48.9888C76.2791 50.2249 87.1498 55.3866 88.6429 66.1442" stroke="#515151" />
<path id="Vector_15"
d="M108.084 96.5774C102.358 96.5774 97.7168 91.936 97.7168 86.2106C97.7168 80.4851 102.358 75.8438 108.084 75.8438C113.809 75.8438 118.451 80.4851 118.451 86.2106C118.451 91.936 113.809 96.5774 108.084 96.5774Z"
fill="white" stroke="#515151" stroke-miterlimit="10" />
<path id="Vector_16" fill-rule="evenodd" clip-rule="evenodd"
d="M110.797 85.8621C110.694 85.6555 110.443 85.5718 110.236 85.6751C108.821 86.3824 107.28 86.5592 106.71 86.5592C106.479 86.5592 106.292 86.7464 106.292 86.9773C106.292 87.2082 106.479 87.3954 106.71 87.3954C107.379 87.3954 109.055 87.2008 110.61 86.4231C110.817 86.3198 110.9 86.0686 110.797 85.8621ZM108.135 89.3776C108.1 88.8916 108.465 88.469 108.951 88.4337C109.437 88.3983 109.86 88.7637 109.895 89.2497C109.93 89.7357 109.565 90.1584 109.079 90.1937C108.593 90.229 108.17 89.8637 108.135 89.3776ZM115.238 88.4333C114.752 88.4687 114.387 88.8913 114.422 89.3773C114.457 89.8633 114.88 90.2286 115.366 90.1933C115.852 90.158 116.217 89.7354 116.182 89.2494C116.147 88.7634 115.724 88.398 115.238 88.4333Z"
fill="#515151" />
<path id="Vector_17"
d="M100.584 87.3134C100.584 87.3134 94.8492 80.6963 99.9223 76.2848C106.54 70.3294 121.097 75.8437 121.097 75.8437C121.097 75.8437 120.877 82.902 116.245 83.7843C111.833 84.446 103.672 81.358 103.672 81.358L100.584 87.3134Z"
fill="#515151" />
<path id="Vector_18"
d="M98.3782 88.637C96.9164 88.637 95.7314 87.452 95.7314 85.9902C95.7314 84.5283 96.9164 83.3433 98.3782 83.3433C99.8401 83.3433 101.025 84.5283 101.025 85.9902C101.025 87.452 99.8401 88.637 98.3782 88.637Z"
fill="white" stroke="#515151" stroke-miterlimit="10" />
</g>
<defs>
<clipPath id="clip0_2697_59356">
<rect width="200" height="200" fill="white" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,55 @@
.wrapper {
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
width: 640px;
min-width: 640px;
max-width: 640px;
min-height: 480px;
padding: 16px 24px 24px;
background: var(--coz-bg-plus, #F9F9F9);
border-radius: var(--default, 8px)
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 32px;
min-height: 32px;
}
.body {
display: flex;
flex: 1 0 0;
flex-direction: column;
align-items: center;
justify-content: center;
}
.footer {
@apply flex items-center justify-end w-full;
}
.title {
font-size: 20px;
font-weight: 500;
font-style: normal;
line-height: 28px; /* 140% */
color: var(--coz-fg-plus, rgba(6, 7, 9, 96%));
}
.error-txt {
margin-top: 16px;
font-size: 14px;
font-weight: 400;
font-style: normal;
line-height: normal;
color: var(--Light-usage-text---color-text-1, rgba(28, 31, 35, 80%));
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { I18n } from '@coze-arch/i18n';
import { IconCozCross } from '@coze-arch/coze-design/icons';
import { Button } from '@coze-arch/coze-design';
import styles from '../index.module.less';
import { ReactComponent as IconImageBroken } from '../../assets/coz_image_broken.svg';
interface LoadErrorProps {
onClose?: VoidFunction;
}
export const LoadError = ({ onClose }: LoadErrorProps) => (
<div className={styles.wrapper}>
<div className={styles.header}>
<div className={styles.title}>
{I18n.t('analytics_query_aigc_infopanel_title')}
</div>
<Button
icon={<IconCozCross className="w-4 h-4" />}
color="secondary"
className="w-4 h-4"
onClick={onClose}
></Button>
</div>
<div className={styles.body}>
<IconImageBroken className="w-[64px] h-[64px]" />
<span className={styles['error-txt']}>
{I18n.t('analytics_query_aigc_errorpanel_context')}
</span>
</div>
<div className={styles.footer}>
<Button type="primary" size="default" onClick={onClose}>
{I18n.t('analytics_query_aigc_errorpanel_ok')}
</Button>
</div>
</div>
);

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState } from 'react';
import { logger } from '@coze-arch/logger';
import { I18n } from '@coze-arch/i18n';
import { IconCozCross } from '@coze-arch/coze-design/icons';
import { Button } from '@coze-arch/coze-design';
import styles from '../index.module.less';
import { fetchResource, downloadFile } from '../../utils/download';
import { ReactComponent as IconImageBroken } from '../../assets/not-support.svg';
interface LoadErrorProps {
onClose?: VoidFunction;
url: string;
filename?: string;
}
export const NotSupport = ({ onClose, url, filename }: LoadErrorProps) => {
const [loading, setLoading] = useState(false);
const handleDownload = async () => {
try {
setLoading(true);
const blob = await fetchResource(url);
downloadFile(blob, filename);
setLoading(false);
} catch (error) {
logger.error({
eventName: 'LoadError-page',
error: error as Error,
});
setLoading(false);
}
};
return (
<div className={styles.wrapper}>
<div className={styles.header}>
<div className={styles.title}>
{I18n.t('analytics_query_aigc_inforpanel_title_file')}
</div>
<Button
icon={<IconCozCross className="w-4 h-4" />}
color="secondary"
className="w-4 h-4"
onClick={onClose}
></Button>
</div>
<div className={styles.body}>
<IconImageBroken className="w-[200px] h-[200px]" />
<span className={styles['error-txt']}>
{I18n.t('analytics_query_aigc_infopanel_context')}
</span>
</div>
<div className={styles.footer}>
<Button
type="primary"
size="default"
onClick={onClose}
color="primary"
className="mr-2"
>
{I18n.t('analytics_query_aigc_infopanel_cancel')}
</Button>
<Button
type="primary"
size="default"
onClick={handleDownload}
loading={loading}
>
{I18n.t('analytics_query_aigc_infopanel_download')}
</Button>
</div>
</div>
);
};

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ReactDOM from 'react-dom';
import React from 'react';
import { IconCozCrossFill } from '@coze-arch/coze-design/icons';
let overlayContainer: HTMLDivElement | null = null;
interface OverlayProps {
onClose?: VoidFunction;
children?: React.ReactNode;
withMask?: boolean;
}
const Overlay = ({ onClose, children, withMask }: OverlayProps) => (
<div
className="p-5"
style={
withMask
? {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.70)',
zIndex: 1000,
}
: {}
}
>
<div
className="absolute top-5 right-5 rounded-[50%] w-[40px] h-[40px] p-[11px] flex items-center justify-center bg-[rgba(255,255,255,0.12)] backdrop-blur-md cursor-pointer"
style={{
zIndex: 10010,
}}
onClick={onClose}
>
<IconCozCrossFill className="w-[18px] h-[18px] text-white" />
</div>
{children}
</div>
);
const createOverlayContainer = () => {
overlayContainer = document.createElement('div');
document.body.appendChild(overlayContainer);
};
const show = (params: {
content: (onClose: VoidFunction) => React.ReactNode;
withMask?: boolean;
}) => {
const { content, withMask = true } = params;
if (!overlayContainer) {
createOverlayContainer();
}
const close = () => {
overlayContainer && ReactDOM.unmountComponentAtNode(overlayContainer);
};
ReactDOM.render(
<Overlay onClose={close} children={content?.(close)} withMask={withMask} />,
overlayContainer,
);
return close;
};
const OverlayAPI = {
show,
};
export default OverlayAPI;

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState, useEffect } from 'react';
function useResourceSize(url: string) {
const [size, setSize] = useState<number>(0);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string>('');
useEffect(() => {
if (!url) {
setLoading(false);
return;
}
const fetchSize = async () => {
try {
const response = await fetch(url, { method: 'HEAD' });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const contentLength = response.headers.get('content-length');
if (contentLength) {
setSize(parseInt(contentLength, 10));
} else {
setSize(0);
}
} catch (e: unknown) {
if (e instanceof Error) {
setError(e.message);
}
} finally {
setLoading(false);
}
};
fetchSize();
}, [url]);
return { size, loading, error };
}
export { useResourceSize };

View File

@@ -0,0 +1,19 @@
.json-link-preview {
/* stylelint-disable-next-line declaration-no-important */
font-size: 12px !important;
.link {
cursor: pointer;
overflow: hidden;
font-size: 14px;
font-weight: 400;
font-style: normal;
line-height: 20px;
color: var(--coz-fg-hglt, #4E40E5);
text-decoration-line: underline;
text-overflow: ellipsis;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, type ReactNode } from 'react';
import { isEmpty, last } from 'lodash-es';
import JsonView, { ValueQuote } from '@uiw/react-json-view';
import { I18n } from '@coze-arch/i18n';
import { Tooltip, Typography } from '@coze-arch/coze-design';
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
import { isValidHttpUrl } from './utils/url';
import { type Result, parse, type JsonValue } from './utils/parse';
import { ImagePreview, type JsonPreviewBasePlugin } from './plugins';
import OverlayAPI from './common/overlay';
import { NotSupport } from './common/not-support';
import styles from './index.module.less';
interface JsonLinkPreviewProps {
src: unknown[];
bot_id?: string;
space_id: string;
entityId?: string;
}
export class JsonLinkPreview extends Component<JsonLinkPreviewProps> {
parse: (inputValue: JsonValue[]) => Record<string, Result>;
linkMap: Record<string, Result>;
plugins: JsonPreviewBasePlugin[];
constructor(props: JsonLinkPreviewProps) {
super(props);
this.parse = parse;
this.linkMap = this.parse(props.src as JsonValue[]);
this.plugins = [new ImagePreview()];
}
componentDidUpdate(prevProps: Readonly<JsonLinkPreviewProps>): void {
this.linkMap = this.parse(this.props.src as JsonValue[]);
}
handleClick = (
link: string,
contentType: string,
extraInfo?: Record<string, string>,
) => {
sendTeaEvent(EVENT_NAMES.preview_link_click, {
host: window.location.href,
content_type: contentType,
bot_id: this.props.bot_id || this.props.entityId || '',
space_id: this.props.space_id,
});
const renderPlugins = this.plugins.filter(plugin =>
plugin.match(contentType),
);
if (isEmpty(renderPlugins)) {
OverlayAPI.show({
content(onClose) {
return (
<div className="w-full h-full flex items-center justify-center">
<NotSupport
onClose={onClose}
url={link}
filename={extraInfo?.fileName}
/>
</div>
);
},
});
return;
}
renderPlugins.sort((a, b) => a.priority - b.priority);
const renderPlugin = last(renderPlugins);
renderPlugin?.render(link, extraInfo);
};
render(): ReactNode {
return (
<JsonView
className={styles['json-link-preview']}
style={{
fontSize: '12px !important',
}}
value={this.props.src}
enableClipboard={false}
displayDataTypes={false}
indentWidth={2}
collapsed={5}
shortenTextAfterLength={300}
highlightUpdates={false}
>
<JsonView.String
render={(_, { type, value }) => {
if (
type === 'value' &&
typeof value === 'string' &&
isValidHttpUrl(value)
) {
return (
<Tooltip
content={
<Typography.Text
link
onClick={() => {
this.handleClick(
value,
this.linkMap[value]?.contentType || '',
this.linkMap[value]?.extraInfo,
);
}}
>
{I18n.t('analytics_query_aigc_detail')}
</Typography.Text>
}
>
<a
href={value}
className={styles.link}
onClick={event => {
event.preventDefault();
}}
>
<ValueQuote />
{value}
<ValueQuote />
</a>
</Tooltip>
);
}
}}
/>
</JsonView>
);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const DEFAULT_PRIORITY = 0;
export abstract class JsonPreviewBasePlugin {
abstract match: (contentType: string) => boolean;
abstract name: string;
priority = DEFAULT_PRIORITY;
abstract render: (
link: string,
extraInfo?: Record<string, string>,
) => React.ReactNode;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState, useEffect } from 'react';
const useImage = (src: string) => {
const [isLoaded, setIsLoaded] = useState(false);
const [hasError, setHasError] = useState(false);
const [image, setImage] = useState<HTMLImageElement | null>(null);
useEffect(() => {
const img = new Image();
img.src = src;
img.onload = () => {
setIsLoaded(true);
setImage(img);
};
img.onerror = () => {
setHasError(true);
};
}, [src]);
return { isLoaded, hasError, image };
};
export default useImage;

View File

@@ -0,0 +1,60 @@
/* stylelint-disable declaration-no-important */
.image-preview-container {
@apply max-w-full max-h-full relative flex w-full h-full justify-center items-center;
:global {
.semi-image-preview {
opacity: 1 !important;
}
.semi-icon-chevron_left,
.semi-image-preview-footer-page {
display: none;
}
}
}
.image-preview-wrapper {
:global {
.semi-image-preview-footer-content {
height: 48px;
min-height: 48px;
max-height: 48px;
padding: 8px;
opacity: 1 !important;
border-radius: 12px;
&> div:nth-child(4) {
display: none;
}
.semi-slider-rail {
background-color: var(--semi-color-white) !important;
}
}
.semi-icon-chevron_left,
.semi-image-preview-footer-page,
.semi-icon-chevron_right {
display: none;
}
.semi-divider-vertical:first-child {
display: none;
}
.semi-icon-rotate {
display: none;
}
.semi-icon-download {
margin-left: 0;
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JsonPreviewBasePlugin } from '../base';
import OverlayAPI from '../../common/overlay';
import { ImagePreviewContent } from './preview';
export class ImagePreview extends JsonPreviewBasePlugin {
render = (link: string, extraInfo?: Record<string, string>) => {
OverlayAPI.show({
content: onclose => <ImagePreviewContent src={link} onClose={onclose} />,
withMask: false,
});
return <></>;
};
name = 'Image';
match = (contentType: string) => contentType === 'image';
override priority = 0;
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Spin, ImagePreview } from '@coze-arch/coze-design';
import { LoadError } from '../../common/load-error';
import useImage from './hooks';
import styles from './index.module.less';
interface ImagePreviewContentProps {
src: string;
onClose?: VoidFunction;
}
export const ImagePreviewContent = ({
src,
onClose,
}: ImagePreviewContentProps) => {
const { hasError, image, isLoaded } = useImage(src);
if (hasError) {
return (
<div className="w-full h-full items-center justify-center flex">
<LoadError onClose={onClose} />
</div>
);
}
if (!isLoaded) {
return (
<div className="w-full h-full items-center justify-center flex">
<Spin />
</div>
);
}
return (
<div className={styles['image-preview-container']}>
<ImagePreview
src={image?.src}
visible
previewCls={styles['image-preview-wrapper']}
closable={false}
/>
</div>
);
};

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { PdfPreview } from './pdf';
export { ImagePreview } from './image';
export { JsonPreviewBasePlugin } from './base';

View File

@@ -0,0 +1,41 @@
.control-bar {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
display: inline-flex;
gap: 8px;
align-items: center;
height: 48px;
min-height: 48px;
max-height: 48px;
padding: 8px;
background: var(--coz-bg-max, #FFF);
border: 1px solid var(--coz-stroke-primary, rgba(6, 7, 9, 10%));
border-radius: 12px;
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 8%), 0 8px 24px 0 rgba(0, 0, 0, 4%);
.page-number {
margin: 0 4px;
/* COZText16Regular */
font-size: 16px;
font-weight: 400;
font-style: normal;
line-height: 22px; /* 137.5% */
color: var(--coz-fg-plus, rgba(6, 7, 9, 96%));
}
}
.pdf-title {
margin-left: 8px;
font-size: 16px;
font-weight: 500;
font-style: normal;
line-height: 22px; /* 137.5% */
color: var(--coz-fg-plus, rgba(6, 7, 9, 96%));
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 目前拿不到文件的 size 信息 文件过大会导致浏览器卡顿 PDF 暂时不需要注册进去 之后放开
import { JsonPreviewBasePlugin } from '../base';
import OverlayAPI from '../../common/overlay';
import PdfPreviewContent from './preview';
export class PdfPreview extends JsonPreviewBasePlugin {
name = 'pdf';
match = (contentType: string) => contentType === 'pdf';
override priority = 0;
render = (link: string, extraInfo?: Record<string, string>) => {
OverlayAPI.show({
content: onclose => (
<PdfPreviewContent src={link} extraInfo={extraInfo} onClose={onclose} />
),
});
return <></>;
};
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable @coze-arch/max-line-per-function */
import { useCallback, useEffect, useRef, useState } from 'react';
import { throttle } from 'lodash-es';
import {
initPdfJsWorker,
getDocument,
generatePdfAssetsUrl,
type PDFDocumentProxy,
} from '@coze-arch/pdfjs-shadow';
import { logger } from '@coze-arch/logger';
import {
IconCozDownload,
IconCozArrowLeft,
IconCozArrowRight,
} from '@coze-arch/coze-design/icons';
import { Spin, Button, Typography } from '@coze-arch/coze-design';
import { downloadFile, fetchResource } from '../../utils/download';
import { LoadError } from '../../common/load-error';
import { ReactComponent as IconPDF } from '../../assets/icon.svg';
import styles from './index.module.less';
initPdfJsWorker();
interface PdfPreviewContentProps {
src: string;
extraInfo?: Record<string, string>;
onClose: VoidFunction;
}
export default function PdfPreviewContent({
src,
extraInfo,
onClose,
}: PdfPreviewContentProps) {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const [pdfDoc, setPdfDoc] = useState<PDFDocumentProxy | null>(null);
const [pageNumber, setPageNumber] = useState(1);
const [pageCount, setPageCount] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const containerRef = useRef<HTMLDivElement>(null);
const [containerStyle, setContainerStyle] = useState({});
const [downloadLoading, setDownloadLoading] = useState(false);
const [hasError, setHasError] = useState(false);
useEffect(() => {
setIsLoading(true);
getDocument({
url: src,
cMapUrl: generatePdfAssetsUrl('cmaps'),
})
.promise.then(pdf => {
setPdfDoc(pdf);
setPageCount(pdf.numPages);
})
.catch(error => {
setHasError(true);
console.error('PdfPreviewContent error', error);
})
.finally(() => {
setIsLoading(false);
});
}, [src]);
const renderPdfPage = useCallback(() => {
if (!pdfDoc) {
return;
}
pdfDoc.getPage(pageNumber).then(page => {
const canvas = canvasRef.current;
if (!canvas) {
return;
}
const context = canvas.getContext('2d');
if (!context) {
return;
}
const deviceRatio = window.devicePixelRatio || 1;
const pdfOriginViewport = page.getViewport({ scale: 1 });
const windowHeight = window.innerHeight - (90 + 32);
const realViewport = page.getViewport({
scale: (windowHeight / pdfOriginViewport.height) * deviceRatio,
});
canvas.width = Math.floor(realViewport.width * deviceRatio);
canvas.height = Math.floor(realViewport.height * deviceRatio);
canvas.style.width = `${realViewport.width}px`;
canvas.style.height = `${realViewport.height}px`;
canvas.style.transform = `scale(${1 / deviceRatio})`;
canvas.style.transformOrigin = '0 0';
setContainerStyle({
width: realViewport.width * (1 / deviceRatio),
});
const renderContext = {
canvasContext: context,
viewport: realViewport,
transform: [deviceRatio, 0, 0, deviceRatio, 0, 0],
enhanceTextSelection: true,
};
page.render(renderContext);
});
}, [pageNumber, pdfDoc]);
const throttleRenderPdfPage = throttle(renderPdfPage);
useEffect(() => {
renderPdfPage();
}, [renderPdfPage]);
useEffect(() => {
window.addEventListener('resize', throttleRenderPdfPage);
return () => {
window.removeEventListener('resize', throttleRenderPdfPage);
};
}, [throttleRenderPdfPage]);
const changePage = (offset: number) => {
setPageNumber(prevPageNum => prevPageNum + offset);
};
const handleDownload = async () => {
try {
setDownloadLoading(true);
const blob = await fetchResource(src);
downloadFile(blob, extraInfo?.fileName);
setDownloadLoading(false);
} catch (error) {
logger.error({
eventName: 'pdf-download',
error: error as Error,
});
setDownloadLoading(false);
}
};
return (
<div className="flex justify-center items-start relative w-full h-full">
<div
ref={containerRef}
style={{
display: isLoading || hasError ? 'none' : 'block',
...containerStyle,
}}
className="rounded-lg overflow-hidden relative"
>
<div
className="header flex items-center justify-between w-full px-6 bg-white py-4"
style={{
borderBottom:
'1px solid var(--Stroke-COZ-stroke-primary, rgba(6, 7, 9, 0.10))',
}}
>
<div className="flex items-center">
<IconPDF />
<Typography.Text
className={styles['pdf-title']}
ellipsis={{
showTooltip: {
opts: {
content: extraInfo?.fileName || '--',
},
},
}}
>
{extraInfo?.fileName ?? '-'}
</Typography.Text>
</div>
<div>
<Button
icon={<IconCozDownload />}
color="secondary"
className="w-4 h-4"
loading={downloadLoading}
onClick={() => {
handleDownload();
}}
></Button>
</div>
</div>
<canvas
ref={canvasRef}
className="max-h-full overflow-hidden rounded-b-lg bg-white"
/>
</div>
{!isLoading && !hasError && (
<div className={styles['control-bar']}>
<Button
icon={<IconCozArrowLeft />}
onClick={() => changePage(-1)}
disabled={pageNumber <= 1}
color="secondary"
className="w-4 h-4"
></Button>
<span className={styles['page-number']}>
{pageNumber}/{pageCount}
</span>
<Button
icon={<IconCozArrowRight />}
onClick={() => changePage(1)}
disabled={pageNumber >= pageCount}
color="secondary"
className="w-4 h-4"
></Button>
</div>
)}
{isLoading ? (
<div className="absolute flex justify-center items-center top-0 right-0 bottom-0 left-0 h-full w-full pointer-events-none">
<Spin />
</div>
) : null}
{hasError ? (
<div className="w-full h-full flex justify-center items-center">
<LoadError onClose={onClose} />
</div>
) : null}
</div>
);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types='@coze-arch/bot-typings' />
declare module '*.less' {
const resource: { [key: string]: string };
export = resource;
}
declare module '*.svg' {
export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement>
>;
/**
* The default export type depends on the svgDefaultExport config,
* it can be a string or a ReactComponent
* */
const content: any;
export default content;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const fetchResource = async (url: string) => {
const response = await fetch(url);
const blob = await response.blob();
return blob;
};
export const downloadFile = (blob: Blob, filename?: string) => {
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.style.display = 'none';
link.href = downloadUrl;
link.setAttribute('download', filename || 'document');
document.body.appendChild(link);
link.click();
link.remove();
};

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface JsonValue {
content_type: string;
content: {
text: string | null;
image_url: null | {
url: string;
name: string;
};
file_url: null | {
url: string;
file_name: string;
suffix_type: string;
};
};
}
const supportedType = new Set(['image', 'file']);
export interface Result {
link: string;
contentType: string;
extraInfo?: Record<string, string>;
}
export const parse = (inputValue: JsonValue[]) => {
const result: Record<string, Result> = {};
inputValue.forEach(item => {
if (!supportedType.has(item.content_type)) {
return;
}
if (item.content_type === 'image') {
const link = item.content.image_url?.url ?? '';
result[link] = {
link,
contentType: 'image',
};
}
if (item.content_type === 'file') {
const suffixType = item.content.file_url?.suffix_type ?? '';
const link = item.content.file_url?.url ?? '';
result[link] = {
link,
contentType: suffixType,
extraInfo: {
fileName: item.content.file_url?.file_name ?? '',
},
};
}
});
return result;
};

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const httpUrlRegex =
/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/;
export function isValidHttpUrl(url: string): boolean {
return httpUrlRegex.test(url);
}