feat(web): chat ui upgrade

This commit is contained in:
zhaoying
2026-03-20 15:48:58 +08:00
parent b1b53f6b1d
commit 0775fad5f0
27 changed files with 495 additions and 323 deletions

View File

@@ -1,17 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 15</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-默认对话" transform="translate(-745, -726)" stroke="#212332">
<g id="聊天页面" transform="translate(258, 128)">
<g id="输入框" transform="translate(16, 512)">
<g id="编组-7" transform="translate(471, 86)">
<g id="语音" transform="translate(4, 4)">
<g id="编组-8" transform="translate(4, 2.25)">
<line x1="4" y1="9" x2="4" y2="11.0054105" id="路径-46"></line>
<line x1="2" y1="11.0054105" x2="5.995474" y2="11.0054105" id="路径-48" stroke-linecap="round"></line>
<rect id="矩形" x="2" y="0" width="4" height="7" rx="2"></rect>
<path d="M8,4 L8,5 C8,7.209139 6.209139,9 4,9 C1.790861,9 0,7.209139 0,5 L0,4" id="路径" stroke-linecap="round" stroke-linejoin="round"></path>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>语音</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="多模态对话" transform="translate(-1181, -742)" stroke="#171719" stroke-width="1.1">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="编组-18" transform="translate(485, 80)">
<g id="编组-10" transform="translate(150, 0)">
<g id="编组-15" transform="translate(6, 6)">
<g id="编组-8" transform="translate(4, 2)">
<line x1="4" y1="9.38688799" x2="4" y2="11.4785062" id="路径-46"></line>
<line x1="2" y1="11.4785062" x2="5.995474" y2="11.4785062" id="路径-48" stroke-linecap="round"></line>
<rect id="矩形" x="2" y="0" width="4" height="7.30091288" rx="2"></rect>
<path d="M8,4.17195022 L8,5.21493777 C8,7.51904225 6.209139,9.38688799 4,9.38688799 C1.790861,9.38688799 0,7.51904225 0,5.21493777 L0,4.17195022" id="路径" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 15</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-交互-2" transform="translate(-1208, -335)">
<g id="输入框" transform="translate(737, 180)">
<g id="编组-15" transform="translate(471, 155)">
<rect id="矩形" fill-opacity="0.08" fill="#155EEF" x="0" y="0" width="24" height="24" rx="6"></rect>
<g id="214声波、语音消息" transform="translate(4, 4)">
<rect id="矩形" fill="#000000" fill-rule="nonzero" opacity="0" x="0" y="0" width="16" height="16"></rect>
<rect id="矩形" fill="#155EEF" x="1.5" y="6" width="1" height="4" rx="0.5"></rect>
<rect id="矩形" fill="#155EEF" x="13.5" y="6" width="1" height="4" rx="0.5"></rect>
<rect id="矩形" fill="#155EEF" x="4.5" y="5" width="1" height="6" rx="0.5"></rect>
<rect id="矩形" fill="#155EEF" x="10.5" y="5" width="1" height="6" rx="0.5"></rect>
<rect id="矩形" fill="#155EEF" x="7.5" y="3" width="1" height="10" rx="0.5"></rect>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -5,7 +5,7 @@
<g id="红熊空间-记忆对话-交互-2" transform="translate(-237, -514)">
<g id="输入框备份" transform="translate(43, 506)">
<g id="编组-3" transform="translate(194, 8)">
<circle id="椭圆形" fill="#5B6167" cx="7" cy="7" r="7"></circle>
<circle id="椭圆形" fill="#171719" cx="7" cy="7" r="7"></circle>
<g id="关闭" transform="translate(2, 2)" fill="#FFFFFF" fill-rule="nonzero">
<polygon id="路径" points="5.62500061 5 8.33333333 7.70833272 7.70833272 8.33333333 5 5.62500061 2.29166728 8.33333333 1.66666667 7.70833272 4.37499939 5 1.66666667 2.29166728 2.29166728 1.66666667 5 4.37499939 7.70833272 1.66666667 8.33333333 2.29166728"></polygon>
</g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,18 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>链接</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-默认对话" transform="translate(-284, -726)">
<g id="聊天页面" transform="translate(258, 128)">
<g id="输入框" transform="translate(16, 512)">
<g id="链接" transform="translate(10, 86)">
<rect id="矩形" stroke="#DFE4ED" x="0.5" y="0.5" width="23" height="23" rx="6"></rect>
<g id="编组-6" transform="translate(5, 5)" stroke="#212332" stroke-linecap="round" stroke-linejoin="round">
<g transform="translate(7.1064, 7.1064) rotate(45) translate(-7.1064, -7.1064)translate(3.9564, 1.8564)" id="路径">
<path d="M4.14483263e-14,7.00494523 L4.14483263e-14,2.33333333 C4.14483263e-14,1.04466892 0.992435471,0 2.21666667,0 C3.44089786,0 4.43333333,1.04466892 4.43333333,2.33333333 L4.43333333,5.85907842"></path>
<path d="M6.3,2.518727 L6.3,7.175 C6.3,9.01134679 4.88969696,10.5 3.15,10.5 C1.41030304,10.5 0,9.01134679 0,7.175 L0,2.33333333"></path>
<path d="M4.43333333,2.33333333 L4.43333333,7 C4.43333333,7.64433221 3.91099887,8.16666667 3.26666667,8.16666667 C2.62233446,8.16666667 2.1,7.64433221 2.1,7 L2.1,3.5201611"></path>
</g>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 6</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="多模态对话" transform="translate(-558, -742)" stroke="#171719" stroke-width="1.1">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="附件" transform="translate(12, 80)">
<g id="编组-6" transform="translate(6, 6)">
<g transform="translate(8.1216, 8.1216) rotate(45) translate(-8.1216, -8.1216)translate(4.5216, 2.1216)" id="路径">
<path d="M4.44722907e-13,8.0056517 L4.44722907e-13,2.66666667 C4.44722907e-13,1.19390733 1.13421197,1.99211235e-13 2.53333333,1.99211235e-13 C3.9324547,1.99211235e-13 5.06666667,1.19390733 5.06666667,2.66666667 L5.06666667,6.69608962"></path>
<path d="M7.2,2.87854514 L7.2,8.2 C7.2,10.298682 5.5882251,12 3.6,12 C1.6117749,12 1.78485196e-12,10.298682 1.78485196e-12,8.2 L1.78485196e-12,2.66666667"></path>
<path d="M5.06666667,2.66666667 L5.06666667,8 C5.06666667,8.73637967 4.469713,9.33333333 3.73333333,9.33333333 C2.99695367,9.33333333 2.4,8.73637967 2.4,8 L2.4,4.02304126"></path>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,13 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 5</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-交互-2" transform="translate(-558, -337)">
<g id="输入框" transform="translate(45, 180)">
<g id="编组-7" transform="translate(471, 155)">
<g id="编组-5" transform="translate(42, 2)">
<circle id="椭圆形" stroke="#212332" stroke-width="1.5" cx="10" cy="10" r="9.25"></circle>
<rect id="矩形" fill="#212332" x="6.5" y="6.5" width="7" height="7" rx="2"></rect>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 14</title>
<defs>
<filter x="-3.4%" y="-9.4%" width="106.8%" height="121.1%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="记忆验证-交互" transform="translate(-593, -349)">
<g id="输入框1" filter="url(#filter-1)" transform="translate(67, 203)">
<g id="编组-14" transform="translate(520, 140)">
<g id="编组-5" transform="translate(6, 6)">
<circle id="椭圆形" stroke="#171719" cx="8" cy="8" r="7.5"></circle>
<rect id="矩形" fill="#171719" x="5" y="5" width="6" height="6" rx="2"></rect>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 895 B

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,15 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>brain-2-line</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linejoin="round">
<g id="红熊空间-记忆对话-默认对话" transform="translate(-324, -730)" stroke="#212332">
<g id="聊天页面" transform="translate(258, 128)">
<g id="输入框" transform="translate(16, 512)">
<g id="1" transform="translate(42, 86)">
<g id="brain-2-line" transform="translate(8, 4)">
<g id="编组-25" transform="translate(3, 3)">
<path d="M3.33333333,0 C4.20536189,0 4.92097069,0.670068175 4.99388234,1.52366891 L5,1.66755165 L4.99986288,8.05913792 C4.99995421,8.06685294 5,8.07457892 5,8.0823156 L4.999,8.107 L5,8.33775827 L4.98310752,8.33803625 C4.85815555,9.27624509 4.05522059,10 3.08333333,10 C2.02478756,10 1.16666667,9.14142345 1.16666667,8.0823156 C1.16666667,7.94759059 1.18055226,7.81611046 1.20696967,7.68922971 C0.51077752,7.49098524 0,6.84838576 0,6.08642446 C0,5.66523785 0.156068428,5.28052233 0.413500665,4.98701157 C0.156068428,4.69487819 0,4.31016267 0,3.88897606 C0,2.96801271 0.746192084,2.2214244 1.66666667,2.2214244 C1.69896402,2.2214244 1.73104681,2.22234356 1.76289032,2.22415717 C1.70039312,2.05126095 1.66666667,1.86334701 1.66666667,1.66755165 C1.66666667,0.746588306 2.41285875,0 3.33333333,0 Z" id="形状结合"></path>
<path d="M8.33333333,0 C9.20536189,0 9.92097069,0.670068175 9.99388234,1.52366891 L10,1.66755165 L9.99986288,8.05913792 C9.99995421,8.06685294 10,8.07457892 10,8.0823156 L9.999,8.107 L10,8.33775827 L9.98310752,8.33803625 C9.85815555,9.27624509 9.05522059,10 8.08333333,10 C7.02478756,10 6.16666667,9.14142345 6.16666667,8.0823156 C6.16666667,7.94759059 6.18055226,7.81611046 6.20696967,7.68922971 C5.51077752,7.49098524 5,6.84838576 5,6.08642446 C5,5.66523785 5.15606843,5.28052233 5.41350066,4.98701157 C5.15606843,4.69487819 5,4.31016267 5,3.88897606 C5,2.96801271 5.74619208,2.2214244 6.66666667,2.2214244 C6.69896402,2.2214244 6.73104681,2.22234356 6.76289032,2.22415717 C6.70039312,2.05126095 6.66666667,1.86334701 6.66666667,1.66755165 C6.66666667,0.746588306 7.41285875,0 8.33333333,0 Z" id="形状结合" transform="translate(7.5, 5) scale(-1, 1) translate(-7.5, -5)"></path>
<title>1</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linejoin="round">
<g id="多模态对话" transform="translate(-1109, -742)" stroke="#171719" stroke-width="1.1">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="编组-18" transform="translate(485, 80)">
<g id="联网" transform="translate(78, 0)">
<g id="brain-2-line" transform="translate(6, 6)">
<g id="编组-25" transform="translate(2.5, 2.5)">
<path d="M3.66666667,0 C4.67918871,0 5.5,0.821247137 5.5,1.83430682 L5.499,1.855 L5.49984003,8.86429101 C5.49994658,8.87303037 5.5,8.88178252 5.5,8.89054716 L5.499,8.915 L5.5,9.1715341 L5.48139006,9.17205165 C5.34385028,10.2039785 4.46066953,11 3.39166667,11 C2.22726632,11 1.28333333,10.0555658 1.28333333,8.89054716 C1.28333333,8.74208151 1.29866281,8.59719816 1.32782451,8.45739516 C0.560859111,8.23882985 0,7.53248099 0,6.69506691 C0,6.2318134 0.17163691,5.80866913 0.454755816,5.48582095 C0.17163691,5.16427144 0,4.74112717 0,4.27787366 C0,3.26481398 0.820811292,2.44356684 1.83333333,2.44356684 C1.86910911,2.44356684 1.90464555,2.44459213 1.9399149,2.44661492 C1.87033304,2.25583284 1.83333333,2.049393 1.83333333,1.83430682 C1.83333333,0.821247137 2.65414463,0 3.66666667,0 Z" id="形状结合"></path>
<path d="M9.16666667,0 C10.1791887,0 11,0.821247137 11,1.83430682 L10.999,1.855 L10.99984,8.86429101 C10.9999466,8.87303037 11,8.88178252 11,8.89054716 L10.999,8.915 L11,9.1715341 L10.9813901,9.17205165 C10.8438503,10.2039785 9.96066953,11 8.89166667,11 C7.72726632,11 6.78333333,10.0555658 6.78333333,8.89054716 C6.78333333,8.74208151 6.79866281,8.59719816 6.82782451,8.45739516 C6.06085911,8.23882985 5.5,7.53248099 5.5,6.69506691 C5.5,6.2318134 5.67163691,5.80866913 5.95475582,5.48582095 C5.67163691,5.16427144 5.5,4.74112717 5.5,4.27787366 C5.5,3.26481398 6.32081129,2.44356684 7.33333333,2.44356684 C7.36910911,2.44356684 7.40464555,2.44459213 7.4399149,2.44661492 C7.37033304,2.25583284 7.33333333,2.049393 7.33333333,1.83430682 C7.33333333,0.821247137 8.15414463,0 9.16666667,0 Z" id="形状结合" transform="translate(8.25, 5.5) scale(-1, 1) translate(-8.25, -5.5)"></path>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,14 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>brain-2-line</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linejoin="round">
<g id="红熊空间-记忆对话-交互-2" transform="translate(-787, -339)" stroke="#155EEF">
<g id="输入框" transform="translate(737, 180)">
<g id="1" transform="translate(42, 155)">
<g id="brain-2-line" transform="translate(8, 4)">
<g id="编组-25" transform="translate(3, 3)">
<path d="M3.33333333,0 C4.20536189,0 4.92097069,0.670068175 4.99388234,1.52366891 L5,1.66755165 L4.99986288,8.05913792 C4.99995421,8.06685294 5,8.07457892 5,8.0823156 L4.999,8.107 L5,8.33775827 L4.98310752,8.33803625 C4.85815555,9.27624509 4.05522059,10 3.08333333,10 C2.02478756,10 1.16666667,9.14142345 1.16666667,8.0823156 C1.16666667,7.94759059 1.18055226,7.81611046 1.20696967,7.68922971 C0.51077752,7.49098524 0,6.84838576 0,6.08642446 C0,5.66523785 0.156068428,5.28052233 0.413500665,4.98701157 C0.156068428,4.69487819 0,4.31016267 0,3.88897606 C0,2.96801271 0.746192084,2.2214244 1.66666667,2.2214244 C1.69896402,2.2214244 1.73104681,2.22234356 1.76289032,2.22415717 C1.70039312,2.05126095 1.66666667,1.86334701 1.66666667,1.66755165 C1.66666667,0.746588306 2.41285875,0 3.33333333,0 Z" id="形状结合"></path>
<path d="M8.33333333,0 C9.20536189,0 9.92097069,0.670068175 9.99388234,1.52366891 L10,1.66755165 L9.99986288,8.05913792 C9.99995421,8.06685294 10,8.07457892 10,8.0823156 L9.999,8.107 L10,8.33775827 L9.98310752,8.33803625 C9.85815555,9.27624509 9.05522059,10 8.08333333,10 C7.02478756,10 6.16666667,9.14142345 6.16666667,8.0823156 C6.16666667,7.94759059 6.18055226,7.81611046 6.20696967,7.68922971 C5.51077752,7.49098524 5,6.84838576 5,6.08642446 C5,5.66523785 5.15606843,5.28052233 5.41350066,4.98701157 C5.15606843,4.69487819 5,4.31016267 5,3.88897606 C5,2.96801271 5.74619208,2.2214244 6.66666667,2.2214244 C6.69896402,2.2214244 6.73104681,2.22234356 6.76289032,2.22415717 C6.70039312,2.05126095 6.66666667,1.86334701 6.66666667,1.66755165 C6.66666667,0.746588306 7.41285875,0 8.33333333,0 Z" id="形状结合" transform="translate(7.5, 5) scale(-1, 1) translate(-7.5, -5)"></path>
<title>1</title>
<defs>
<filter x="-2.6%" y="-9.4%" width="105.3%" height="121.1%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linejoin="round">
<g id="多模态对话-3" transform="translate(-1109, -806)" stroke="#155EEF" stroke-width="1.1">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 660)">
<g id="编组-18" transform="translate(485, 140)">
<g id="1" transform="translate(78, 0)">
<g id="brain-2-line" transform="translate(6, 6)">
<g id="编组-25" transform="translate(2.5, 2.5)">
<path d="M3.66666667,0 C4.67918871,0 5.5,0.821247137 5.5,1.83430682 L5.499,1.855 L5.49984003,8.86429101 C5.49994658,8.87303037 5.5,8.88178252 5.5,8.89054716 L5.499,8.915 L5.5,9.1715341 L5.48139006,9.17205165 C5.34385028,10.2039785 4.46066953,11 3.39166667,11 C2.22726632,11 1.28333333,10.0555658 1.28333333,8.89054716 C1.28333333,8.74208151 1.29866281,8.59719816 1.32782451,8.45739516 C0.560859111,8.23882985 0,7.53248099 0,6.69506691 C0,6.2318134 0.17163691,5.80866913 0.454755816,5.48582095 C0.17163691,5.16427144 0,4.74112717 0,4.27787366 C0,3.26481398 0.820811292,2.44356684 1.83333333,2.44356684 C1.86910911,2.44356684 1.90464555,2.44459213 1.9399149,2.44661492 C1.87033304,2.25583284 1.83333333,2.049393 1.83333333,1.83430682 C1.83333333,0.821247137 2.65414463,0 3.66666667,0 Z" id="形状结合"></path>
<path d="M9.16666667,0 C10.1791887,0 11,0.821247137 11,1.83430682 L10.999,1.855 L10.99984,8.86429101 C10.9999466,8.87303037 11,8.88178252 11,8.89054716 L10.999,8.915 L11,9.1715341 L10.9813901,9.17205165 C10.8438503,10.2039785 9.96066953,11 8.89166667,11 C7.72726632,11 6.78333333,10.0555658 6.78333333,8.89054716 C6.78333333,8.74208151 6.79866281,8.59719816 6.82782451,8.45739516 C6.06085911,8.23882985 5.5,7.53248099 5.5,6.69506691 C5.5,6.2318134 5.67163691,5.80866913 5.95475582,5.48582095 C5.67163691,5.16427144 5.5,4.74112717 5.5,4.27787366 C5.5,3.26481398 6.32081129,2.44356684 7.33333333,2.44356684 C7.36910911,2.44356684 7.40464555,2.44459213 7.4399149,2.44661492 C7.37033304,2.25583284 7.33333333,2.049393 7.33333333,1.83430682 C7.33333333,0.821247137 8.15414463,0 9.16666667,0 Z" id="形状结合" transform="translate(8.25, 5.5) scale(-1, 1) translate(-8.25, -5.5)"></path>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,17 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>联网</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-默认对话" transform="translate(-463, -730)" stroke="#212332">
<g id="聊天页面" transform="translate(258, 128)">
<g id="输入框" transform="translate(16, 512)">
<g id="2" transform="translate(181, 86)">
<g id="互联网" transform="translate(8, 4)">
<g id="编组-11" transform="translate(2.5, 2.5)">
<circle id="椭圆形" cx="5.5" cy="5.5" r="5"></circle>
<line x1="0.785714286" y1="3.53571429" x2="10.2142857" y2="3.53571429" id="路径-6"></line>
<path d="M4.27288123,0.591487342 C3.82349401,1.74340425 3.53571429,3.51415883 3.53571429,5.5 C3.53571429,7.49845355 3.82716108,9.27907975 4.28146314,10.4303857 M6.66018951,10.572683 C7.14773377,9.4289068 7.46428571,7.58274887 7.46428571,5.5 C7.46428571,3.4620778 7.16121333,1.65067191 6.69143044,0.502140402" id="形状"></path>
<line x1="0.772766423" y1="7.07142857" x2="10.2013379" y2="7.07142857" id="路径-6"></line>
<title>联网</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="多模态对话" transform="translate(-1145, -742)" stroke="#171719">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="编组-18" transform="translate(485, 80)">
<g id="记忆" transform="translate(114, 0)">
<g id="互联网" transform="translate(6, 6)">
<g id="编组-11" transform="translate(2, 2)">
<circle id="椭圆形" cx="6" cy="6" r="5.5"></circle>
<line x1="0.857142857" y1="3.85714286" x2="11.1428571" y2="3.85714286" id="路径-6"></line>
<path d="M4.66132498,0.645258919 C4.17108437,1.90189554 3.85714286,3.83362782 3.85714286,6 C3.85714286,8.18013114 4.17508482,10.1226325 4.67068706,11.3786026 M7.26566129,11.533836 C7.79752775,10.2860801 8.14285714,8.27208968 8.14285714,6 C8.14285714,3.77681214 7.81223272,1.80073299 7.2997423,0.54778953" id="形状"></path>
<line x1="0.843017916" y1="7.71428571" x2="11.1287322" y2="7.71428571" id="路径-6"></line>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,16 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>联网</title>
<g id="V1.0版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="红熊空间-记忆对话-交互-2" transform="translate(-928, -339)" stroke="#155EEF">
<g id="输入框" transform="translate(737, 180)">
<g id="2" transform="translate(183, 155)">
<g id="互联网" transform="translate(8, 4)">
<g id="编组-11" transform="translate(2.5, 2.5)">
<circle id="椭圆形" cx="5.5" cy="5.5" r="5"></circle>
<line x1="0.785714286" y1="3.53571429" x2="10.2142857" y2="3.53571429" id="路径-6"></line>
<path d="M4.27288123,0.591487342 C3.82349401,1.74340425 3.53571429,3.51415883 3.53571429,5.5 C3.53571429,7.49845355 3.82716108,9.27907975 4.28146314,10.4303857 M6.66018951,10.572683 C7.14773377,9.4289068 7.46428571,7.58274887 7.46428571,5.5 C7.46428571,3.4620778 7.16121333,1.65067191 6.69143044,0.502140402" id="形状"></path>
<line x1="0.772766423" y1="7.07142857" x2="10.2013379" y2="7.07142857" id="路径-6"></line>
<title>联网</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="多模态对话" transform="translate(-1145, -742)" stroke="#155EEF">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="编组-18" transform="translate(485, 80)">
<g id="记忆" transform="translate(114, 0)">
<g id="互联网" transform="translate(6, 6)">
<g id="编组-11" transform="translate(2, 2)">
<circle id="椭圆形" cx="6" cy="6" r="5.5"></circle>
<line x1="0.857142857" y1="3.85714286" x2="11.1428571" y2="3.85714286" id="路径-6"></line>
<path d="M4.66132498,0.645258919 C4.17108437,1.90189554 3.85714286,3.83362782 3.85714286,6 C3.85714286,8.18013114 4.17508482,10.1226325 4.67068706,11.3786026 M7.26566129,11.533836 C7.79752775,10.2860801 8.14285714,8.27208968 8.14285714,6 C8.14285714,3.77681214 7.81223272,1.80073299 7.2997423,0.54778953" id="形状"></path>
<line x1="0.843017916" y1="7.71428571" x2="11.1287322" y2="7.71428571" id="路径-6"></line>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,12 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>发送-2备份</title>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="发送-2备份">
<circle id="椭圆形" fill="#171719" cx="14" cy="14" r="14"></circle>
<g id="编组-50" transform="translate(9.5455, 8.9091)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
<polyline id="路径" points="0 4.45454545 4.45454545 0 8.90909091 4.45454545"></polyline>
<line x1="4.45454545" y1="0.442246469" x2="4.45454545" y2="11.2604283" id="路径-49"></line>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>发送-2@2x</title>
<defs>
<filter x="-3.4%" y="-9.4%" width="106.8%" height="121.1%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="记忆验证-2" transform="translate(-789, -742)" stroke="#FFFFFF" stroke-width="1.5">
<g id="编组-16" transform="translate(253, 108)">
<g id="输入框" filter="url(#filter-1)" transform="translate(12, 488)">
<g id="发送-2" transform="translate(518, 140)">
<g id="编组-50" transform="translate(6, 6)">
<g id="编组-14" transform="translate(4, 3)">
<polyline id="路径" points="0 4 4 0 8 4"></polyline>
<line x1="4" y1="-1.65043138e-17" x2="4" y2="10" id="路径-49"></line>
</g>
</g>
</g>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>发送-2</title>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>发送-2@2x</title>
<defs>
<filter x="-2.5%" y="-17.7%" width="105.0%" height="139.6%" filterUnits="objectBoundingBox" id="filter-1">
<filter x="-3.4%" y="-14.2%" width="106.8%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
@@ -12,15 +12,16 @@
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="应用管理-Agent-配置-3" transform="translate(-1374, -734)">
<g id="编组-12" transform="translate(632, 76)">
<g id="输入框" filter="url(#filter-1)" transform="translate(16, 600)">
<g id="发送-2" transform="translate(726, 58)">
<circle id="椭圆形" fill="#F6F6F6" cx="14" cy="14" r="14"></circle>
<g id="编组-50" transform="translate(9.5455, 8.9091)" stroke="#A8A9AA" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
<polyline id="路径" points="0 4.45454545 4.45454545 0 8.90909091 4.45454545"></polyline>
<line x1="4.45454545" y1="0.442246469" x2="4.45454545" y2="11.2604283" id="路径-49"></line>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="记忆验证" transform="translate(-787, -742)" stroke="#A8A9AA" stroke-width="1.5">
<g id="编组-16" transform="translate(252, 108)">
<g id="输入框" filter="url(#filter-1)" transform="translate(11, 548)">
<g id="发送-2" transform="translate(518, 80)">
<g id="编组-50" transform="translate(6, 6)">
<g id="编组-14" transform="translate(4, 3)">
<polyline id="路径" points="0 4 4 0 8 4"></polyline>
<line x1="4" y1="-1.65043138e-17" x2="4" y2="10" id="路径-49"></line>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>变量 (1)</title>
<defs>
<filter x="-2.6%" y="-14.2%" width="105.3%" height="131.7%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="6" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.0901960784 0 0 0 0 0.0901960784 0 0 0 0 0.0980392157 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="多模态对话" transform="translate(-630, -742)" fill="#000000" fill-rule="nonzero">
<g id="输入框" filter="url(#filter-1)" transform="translate(540, 656)">
<g id="变量" transform="translate(84, 80)">
<g id="变量-(1)" transform="translate(6, 6)">
<g id="local_variable" transform="translate(1.1, 2)">
<path d="M4.38472,2.88803156 C4.38472,2.56775449 4.64232,2.30839467 4.96156,2.30839467 L5.66904,2.30839467 C5.95424,2.30839467 6.2284,2.38500273 6.463,2.58529128 C6.6746,2.76527407 6.80524,3.0070971 6.9046,3.23138335 C6.99936,3.44459373 7.09228,3.70856849 7.19348,3.99746395 L7.21188,4.0500743 C7.32412,4.36665942 7.45568,4.73770086 7.62956,5.17335152 L7.63048,5.1751975 C7.80988,5.62653896 7.94328,6.00957926 8.05276,6.3243184 L8.05644,6.33447127 C8.16684,6.65197937 8.24412,6.87534263 8.31956,7.04517255 C8.38948,7.2039266 8.43364,7.25653696 8.44836,7.27038179 L8.4548,7.27130477 C8.464,7.27315075 8.47688,7.27407374 8.49712,7.27407374 L9.2046,7.27407374 C9.5144737,7.28648663 9.75930946,7.54212108 9.75930946,7.85324913 C9.75930946,8.16437719 9.5144737,8.42001164 9.2046,8.43242453 L8.49712,8.43242453 C8.20809037,8.44042248 7.92609201,8.34228859 7.70408,8.15645091 C7.49248,7.97646812 7.36184,7.73649107 7.2634,7.5140508 C7.16956,7.29991742 7.07756,7.03686565 6.9782,6.75073916 L6.96256,6.70458973 C6.83587483,6.33485387 6.70090729,5.96802673 6.55776,5.60438723 C6.37376,5.14473887 6.23576,4.75523765 6.12352,4.43496058 L6.11524,4.41280885 C6.00484,4.09622374 5.92572,3.87193749 5.85028,3.70210757 C5.77668,3.53873858 5.73252,3.48520523 5.7178,3.47043741 C5.70169877,3.46766941 5.68537294,3.46643327 5.66904,3.46674546 L4.96156,3.46674546 C4.64298006,3.46674546 4.38472,3.20764642 4.38472,2.88803156 L4.38472,2.88803156 Z" id="路径"></path>
<path d="M8.77128,4.13775823 C8.32784,4.58356176 7.91108,5.16412163 7.56148,5.69022518 C7.20452,6.22832757 6.73624,6.88918746 6.20908,7.41898296 C5.70124,7.92662673 5.0278,8.42965556 4.255,8.42965556 C4.04957228,8.42965556 3.85974924,8.31970517 3.75703537,8.14122161 C3.65432151,7.96273805 3.65432151,7.74283723 3.75703537,7.56435367 C3.85974924,7.38587011 4.04957228,7.27591971 4.255,7.27591972 C4.54296,7.27591972 4.93028,7.07009324 5.3958,6.60213799 C5.83924,6.15725744 6.25508,5.57669757 6.60468,5.05059402 C6.96256,4.51249163 7.42992,3.85163174 7.958,3.32183624 C8.46492,2.81419247 9.13928,2.31024065 9.91208,2.31024065 C10.2296437,2.31024065 10.48708,2.56851322 10.48708,2.88710857 C10.48708,3.20570393 10.2296437,3.46397649 9.91208,3.46397649 C9.62412,3.46397649 9.2368,3.67072596 8.77128,4.13775823 L8.77128,4.13775823 Z" id="路径"></path>
<path d="M4.301,9.69230407 L9.591,9.69230407 C9.97433333,9.69230407 10.166,9.88459337 10.166,10.269172 L10.166,10.269172 C10.166,10.6537506 9.97433333,10.8460399 9.591,10.8460399 L4.301,10.8460399 C3.91766667,10.8460399 3.726,10.6537506 3.726,10.269172 L3.726,10.269172 C3.726,9.88459337 3.91766667,9.69230407 4.301,9.69230407 Z" id="路径"></path>
<path d="M2.80324,11.9997758 C2.66536377,12.0039507 2.53211105,11.9496723 2.43616,11.8502516 C0.81972,10.2368674 0,8.2875153 0,6.03726892 C0,3.74917999 0.8188,1.78136814 2.43616,0.149524165 C2.53448735,0.0536953264 2.66615588,0 2.80324,0 L2.8244,0 C3.21264,0 3.45,0.394116164 3.21264,0.674704721 C1.89704,2.23086363 1.25028,4.01223177 1.25028,6.01880914 C1.25028,8.00508077 1.89796,9.76798914 3.21264,11.324148 C3.42884,11.6047366 3.21264,11.9988528 2.80324,11.9988528 L2.80324,11.9997758 Z M10.99676,11.9997758 C11.14764,11.9997758 11.27736,11.9443964 11.36384,11.8502516 C12.98028,10.2377904 13.8,8.2875153 13.8,6.03819191 C13.8,3.75010298 12.9812,1.78229113 11.36384,0.150447154 C11.2655127,0.0546183151 11.1338441,0.000922988674 10.99676,0.000922988674 L10.9756,0.000922988674 C10.58736,0.000922988674 10.35,0.395039153 10.58736,0.675627709 C11.90296,2.23178661 12.54972,4.01315476 12.54972,6.01973213 C12.54972,8.00600376 11.90204,9.76891213 10.58736,11.325071 C10.37116,11.6056596 10.58736,11.9997758 10.99676,11.9997758 L10.99676,11.9997758 Z" id="形状"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -2,12 +2,13 @@
* @Author: ZhaoYing
* @Date: 2026-02-06 21:11:51
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-17 18:39:09
* @Last Modified time: 2026-03-20 14:25:26
*/
import { type FC, useRef, useState } from 'react'
import RecordRTC from 'recordrtc'
import { App } from 'antd'
import { App, Tooltip } from 'antd'
import { useTranslation } from 'react-i18next';
import clsx from 'clsx';
import { fileUploadUrlWithoutApiPrefix } from '@/api/fileStorage'
import { request } from '@/utils/request'
@@ -91,14 +92,17 @@ const AudioRecorder: FC<AudioRecorderProps> = ({
// Toggle between recording/idle states on click;
// swap background image to reflect current state
return (
<div
className={`rb:size-5.5 rb:bg-cover ${disabled ? 'rb:opacity-65 rb:cursor-not-allowed' : 'rb:cursor-pointer'} ${className} ${
isRecording
? `rb:bg-[url('@/assets/images/conversation/audio_ing.gif')]`
: `rb:bg-[url('@/assets/images/conversation/audio.svg')]`
}`}
onClick={isRecording ? stopRecording : startRecording}
/>
<Tooltip title={isRecording ? t('memoryConversation.stopAudioRecorder') : t('memoryConversation.startAudioRecorder')}>
<div
className={clsx("rb:bg-cover", className, {
'rb:cursor-pointer': !disabled,
'rb:opacity-65 rb:cursor-not-allowed': disabled,
"rb:size-4 rb:bg-[url('@/assets/images/conversation/audio.svg')]": !isRecording,
"rb:size-6 rb:bg-[url('@/assets/images/conversation/audio_ing.gif')]": isRecording,
})}
onClick={isRecording ? stopRecording : startRecording}
/>
</Tooltip>
)
}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2025-12-10 16:46:14
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-19 20:46:45
* @Last Modified time: 2026-03-20 15:39:33
*/
import { type FC, useEffect, useMemo, useState } from 'react'
import { Flex, Input, Form } from 'antd'
@@ -77,85 +77,95 @@ const ChatInput: FC<ChatInputProps> = ({
return (
<div className={`rb:absolute rb:bottom-3 rb:left-0 rb:right-0 rb:w-full ${className}`}>
<Flex vertical justify="space-between" className={clsx("rb-border rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)] rb:rounded-3xl rb:min-h-30", {
<Flex gap={0} vertical justify="space-between" className={clsx("rb-border rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)] rb:rounded-3xl rb:min-h-30", {
' rb:border-[#171719]!': isFocus
})}>
{previewFileList.length > 0 && <div className="rb:overflow-x-auto rb:max-w-full"><Flex gap={14} className="rb:mx-3! rb:mt-3! rb:w-max!">
{previewFileList.map((file) => {
if (file.type.includes('image')) {
{previewFileList.length > 0 && <div className="rb:overflow-x-auto rb:max-w-full">
<Flex gap={14} className="rb:mx-3! rb:mt-3! rb:w-max! rb:mb-2!">
{previewFileList.map((file) => {
if (file.type.includes('image')) {
return (
<div key={file.url || file.uid} className="rb:inline-block rb:group rb:relative rb:rounded-lg rb:bg-[#F6F6F6] rb:border rb:border-[#F6F6F6]">
<img src={file.url} alt={file.name} className="rb:size-12! rb:rounded-lg rb:object-cover" />
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
)
}
if (file.type.includes('video')) {
return (
<div key={file.url || file.uid} className="rb:w-45 rb:h-12 rb:inline-block rb:group rb:relative rb:rounded-lg rb:border rb:border-[#F6F6F6]">
<video src={file.url} controls className="rb:w-45 rb:h-12 rb:rounded-lg rb:object-cover" />
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
)
}
if (file.type.includes('audio')) {
return (
<div key={file.url || file.uid} className="rb:w-45 rb:h-12 rb:inline-flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F6F6F6] rb:py-2 rb:px-2.5 rb:gap-2 rb:border rb:border-[#F6F6F6]">
<audio src={file.url} controls className="rb:w-45 rb:h-12" />
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
)
}
return (
<div key={file.url || file.uid} className="rb:inline-block rb:group rb:relative rb:rounded-lg">
<img src={file.url} alt={file.name} className="rb:size-12! rb:rounded-lg rb:object-cover rb:cursor-pointer" />
<Flex
key={file.url || file.uid}
align="center"
gap={10}
className="rb:w-45 rb:text-[12px] rb:group rb:relative rb:rounded-lg rb:bg-[#F6F6F6] rb:py-2! rb:px-2.5! rb:border rb:border-[#F6F6F6]"
>
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
className={clsx(
"rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/pdf_disabled.svg')]",
file.type.includes('pdf')
? "rb:bg-[url('src/assets/images/file/pdf.svg')]"
: (file.type.includes('excel') || file.type.includes('spreadsheetml.sheet'))
? "rb:bg-[url('src/assets/images/file/excel.svg')]"
: file.type.includes('csv')
? "rb:bg-[url('src/assets/images/file/csv.svg')]"
: file.type.includes('html')
? "rb:bg-[url('src/assets/images/file/html.svg')]"
: file.type.includes('json')
? "rb:bg-[url('src/assets/images/file/json.svg')]"
: file.type.includes('ppt')
? "rb:bg-[url('src/assets/images/file/ppt.svg')]"
: file.type.includes('text')
? "rb:bg-[url('src/assets/images/file/txt.svg')]"
: file.type.includes('markdown')
? "rb:bg-[url('src/assets/images/file/md.svg')]"
: (file.type.includes('doc') || file.type.includes('docx') || file.type.includes('word') || file.type.includes('wordprocessingml.document'))
? "rb:bg-[url('src/assets/images/file/word.svg')]"
: null
)}
></div>
<div className="rb:flex-1 rb:w-32.5">
<div className="rb:leading-4 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{file.name}</div>
<div className="rb:leading-3.5 rb:mt-0.5 rb:text-[#5B6167] rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{file.type.split('/')[file.type.split('/').length - 1]} · {file.size}</div>
</div>
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
</Flex>
)
}
if (file.type.includes('video')) {
return (
<div key={file.url || file.uid} className="rb:w-45 rb:h-16 rb:inline-block rb:group rb:relative rb:rounded-lg">
<video src={file.url} controls className="rb:w-45 rb:h-16 rb:rounded-lg rb:object-cover rb:cursor-pointer" />
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
)
}
if (file.type.includes('audio')) {
return (
<div key={file.url || file.uid} className="rb:w-45 rb:h-16 rb:inline-flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2 rb:px-2.5 rb:gap-2">
<audio src={file.url} controls className="rb:w-45 rb:h-16" />
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
onClick={() => handleDelete(file)}
></div>
</div>
)
}
return (
<Flex
key={file.url || file.uid}
align="center"
gap={10}
className="rb:w-45 rb:text-[12px] rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2! rb:px-2.5!"
>
{file.type.includes('pdf')
? <div
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/pdf_disabled.svg')] rb:hover:bg-[url('@/assets/images/conversation/pdf.svg')]"
></div>
: (file.type.includes('excel') || file.type.includes('spreadsheetml.sheet') || file.type.includes('csv'))
? <div
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/excel_disabled.svg')] rb:hover:bg-[url('@/assets/images/conversation/excel.svg')]"
></div>
: (file.type.includes('doc') || file.type.includes('docx') || file.type.includes('word') || file.type.includes('wordprocessingml.document'))
? <div
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/word_disabled.svg')] rb:hover:bg-[url('@/assets/images/conversation/word.svg')]"
></div>
: null
}
<div className="rb:flex-1 rb:w-32.5">
<div className="rb:leading-4 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{file.name}</div>
<div className="rb:leading-3.5 rb:mt-0.5 rb:text-[#5B6167] rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{file.type} · {file.size}</div>
</div>
<div
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
onClick={() => handleDelete(file)}
></div>
</Flex>
)
})}
</Flex>
})}
</Flex>
</div>}
{/* Message input form */}
<Form form={form} layout="vertical">
<Form.Item name="message" noStyle>
<Input.TextArea
className="rb:m-[10px_12px_10px_12px]! rb:p-0! rb:w-[calc(100%-24px)]! rb:flex-[1_1_auto]"
className="rb:m-[10px_12px_10px_12px]! rb:p-0! rb:w-[calc(100%-24px)]! rb:flex-[1_1_auto] rb:h-15! rb:resize-none! rb:rounded-none!"
variant="borderless"
autoSize={{ minRows: 2, maxRows: 2 }}
onChange={(e) => onChange?.(e.target.value)}
onKeyDown={(e) => {
// Enter to send, Shift+Enter for new line
@@ -171,17 +181,21 @@ const ChatInput: FC<ChatInputProps> = ({
</Form>
{/* Bottom action area */}
<Flex align="center" justify="space-between" className="rb:mx-2.5! rb:mt-0! rb:mb-2.5!">
<Flex align="center" justify="space-between" gap={8} className="rb:mx-2.5! rb:mb-2.5!">
{/* Child component content (such as buttons) */}
<div className="rb:flex-1">{children}</div>
<Flex align="center">
{/* Send button - display different icons based on state */}
{loading
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/loading.svg')]"></div>
: !values || !values?.message || values?.message?.trim() === ''
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]"></div>
: <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/send.svg')]" onClick={handleSend}></div>
}
<Flex align="center" justify="center"
className={clsx('rb:size-7 rb:rounded-full rb:shadow-[0px 2px 12px 0px rgba(23,23,25,0.1)]', {
'rb:cursor-not-allowed rb:bg-[#F6F6F6]': loading || !values || !values?.message || values?.message?.trim() === '',
'rb:cursor-pointer rb:bg-[#171719]': !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}
onClick={handleSend}
>
<div className={clsx("rb:size-4 rb:bg-cover", {
"rb:bg-[url('@/assets/images/conversation/loading.svg')]": loading,
"rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]": !loading && (!values || !values?.message || values?.message?.trim() === ''),
"rb:bg-[url('@/assets/images/conversation/send.svg')]": !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}></div>
</Flex>
</Flex>
</Flex>

View File

@@ -2,12 +2,11 @@
* @Author: ZhaoYing
* @Date: 2026-03-17 14:22:25
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-18 15:55:13
* @Last Modified time: 2026-03-20 15:44:48
*/
// Toolbar component for chat input area, supporting file upload, audio recording, and variable configuration
import { useRef, forwardRef, useImperativeHandle, type ReactNode, useEffect } from 'react'
import { Flex, Dropdown, Divider, App, Form, type MenuProps } from 'antd'
import { SettingOutlined } from '@ant-design/icons'
import { Flex, Dropdown, Divider, App, Form, type MenuProps, Tooltip } from 'antd'
import { useTranslation } from 'react-i18next'
import clsx from 'clsx'
@@ -31,7 +30,8 @@ export interface ChatToolbarRef {
// Props for configuring toolbar features, upload settings, and event callbacks
export interface ChatToolbarProps {
features: FeaturesConfigForm
extra?: ReactNode
leftExtra?: ReactNode;
rightExtra?: ReactNode
uploadAction?: string
uploadRequestConfig?: {
data?: Record<string, string | number | boolean>
@@ -51,7 +51,8 @@ interface FormValues {
const ChatToolbar = forwardRef<ChatToolbarRef, ChatToolbarProps>(({
features,
extra,
leftExtra,
rightExtra,
uploadAction,
uploadRequestConfig,
onFilesChange,
@@ -154,28 +155,34 @@ const ChatToolbar = forwardRef<ChatToolbarRef, ChatToolbarProps>(({
return (
<Form form={form} initialValues={{ files: [], variables: [] }}>
<Flex justify="space-between" className="rb:flex-1">
<Flex gap={8} align="center">
<Flex gap={8} align="center" justify="start">
<Form.Item name="files" noStyle hidden={!file_upload?.enabled || fileMenus.length === 0}>
<Dropdown menu={{ items: fileMenus }}>
<div className="rb:size-6 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/link.svg')] rb:hover:bg-[url('@/assets/images/conversation/link_hover.svg')]" />
<Flex justify="center" align="center" className="rb:size-7 rb-border rb:cursor-pointer rb:hover:bg-[#F6F6F6] rb:rounded-full rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)]">
<div className="rb:size-4 rb:bg-cover rb:bg-[url('@/assets/images/conversation/link.svg')]" />
</Flex>
</Dropdown>
</Form.Item>
{extra}
{leftExtra}
<Form.Item name="variables" className="rb:mb-0!" hidden={queryValues?.variables?.length < 1}>
<div
className={clsx('rb:flex rb:items-center rb:border rb:rounded-lg rb:px-2 rb:text-[12px] rb:h-6 rb:cursor-pointer rb:hover:bg-[#F0F3F8] rb:text-[#212332]', {
'rb:border-[#FF5D34] rb:text-[#FF5D34]': isNeedVariableConfig,
'rb:border-[#DFE4ED]': !isNeedVariableConfig,
})}
onClick={() => variableConfigModalRef.current?.handleOpen(queryValues.variables)}
>
<SettingOutlined className="rb:mr-1" />
{t('memoryConversation.variableConfig')}
</div>
<Tooltip title={t('memoryConversation.variableConfig')}>
<Flex justify="center" align="center"
className={clsx("rb:size-7 rb:border rb:cursor-pointer rb:hover:bg-[#F6F6F6] rb:rounded-full rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)]", {
'rb:border-[#FF5D34]': isNeedVariableConfig,
'rb:border-[#EBEBEB]': !isNeedVariableConfig,
})}
onClick={() => variableConfigModalRef.current?.handleOpen(queryValues.variables)}
>
<div className="rb:size-4 rb:bg-cover rb:bg-[url('@/assets/images/conversation/variables.svg')]" />
</Flex>
</Tooltip>
</Form.Item>
</Flex>
{file_upload?.audio_enabled && file_upload?.allowed_transfer_methods?.includes('local_file') && (
<Flex align="center">
<Flex align="center" justify="end" gap={8}>
{rightExtra}
{file_upload?.audio_enabled && file_upload?.allowed_transfer_methods?.includes('local_file') &&
<AudioRecorder
disabled={(queryValues?.files?.length || 0) >= file_upload.max_file_count}
action={uploadAction}
@@ -183,9 +190,9 @@ const ChatToolbar = forwardRef<ChatToolbarRef, ChatToolbarProps>(({
onRecordingComplete={handleRecordingComplete}
maxSize={file_upload?.audio_max_size_mb}
/>
<Divider type="vertical" className="rb:ml-1.5! rb:mr-3!" />
</Flex>
)}
}
{(rightExtra || (file_upload?.audio_enabled && file_upload?.allowed_transfer_methods?.includes('local_file'))) && <Divider type="vertical" className="rb:ml-1.5! rb:mr-0! rb:h-4!" />}
</Flex>
</Flex>
<UploadFileListModal

View File

@@ -3,7 +3,7 @@ import type { CommunityD3Node, D3Link, HullDatum, CommunityGraphData, RawCommuni
// ─── Colors ───────────────────────────────────────────────────────────────────
export const GRAPH_COLORS = ['#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048']
export const GRAPH_COLORS = ['#171719', '#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048']
export const colorAt = (i: number) => GRAPH_COLORS[i % GRAPH_COLORS.length]
export function connectionToRadius(connections: number): number {
@@ -336,7 +336,6 @@ export function initCommunityGraph(
const svg = d3.select(container).append('svg')
.attr('width', width).attr('height', height)
.style('width', '100%').style('height', '100%')
.style('background', '#F6F8FC')
const g = svg.append('g')

View File

@@ -1,5 +1,5 @@
.page-tabs:global(.ant-segmented) {
background-color: rgba(91, 97, 103, 0.08);
background-color: #F6F6F6;
padding: 4px;
}
.page-tabs:global(.ant-segmented .ant-segmented-item-label) {

View File

@@ -1803,6 +1803,8 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
chatTitle: 'Red Bear Space',
memoryCancelTipTitle: 'Are you sure you want to disable conversation memory? Conversations will no longer be saved to the memory store.',
memoryTipTitle: 'Are you sure you want to enable conversation memory? Conversations will be saved to the memory store.',
stopAudioRecorder: 'Stop Recording',
startAudioRecorder: 'Start Recording',
},
login: {
title: 'Red Bear Memory Science',

View File

@@ -1799,6 +1799,8 @@ export const zh = {
chatTitle: '记忆熊空间',
memoryCancelTipTitle: '确定关闭对话记忆功能吗?关闭后对话将不会保存到记忆库中',
memoryTipTitle: '确定打开对话记忆功能吗?打开后对话将会保存到记忆库中',
stopAudioRecorder: '停止录音',
startAudioRecorder: '开始录音',
},
login: {
title: '红熊记忆科学',

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:29:33
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-19 21:03:01
* @Last Modified time: 2026-03-20 15:16:25
*/
import { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
@@ -197,7 +197,7 @@ const Cluster = forwardRef<ClusterRef, { onFeaturesLoad?: (features: FeaturesCon
return (
<>
{loading && <Spin fullscreen></Spin>}
<Row className="rb:h-[calc(100vh-88px)]" gutter={12}>
<Row className="rb:h-[calc(100vh-89px)]" gutter={12}>
<Col span={12} className="rb:h-full rb:overflow-x-auto rb:border-r rb:border-[#DFE4ED]">
<Form form={form} layout="vertical">
<Flex gap={16} vertical>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:26:44
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-07 17:12:25
* @Last Modified time: 2026-03-20 13:53:05
*/
/**
* AI Prompt Assistant Modal
@@ -91,7 +91,7 @@ const AiPromptModal = forwardRef<AiPromptModalRef, AiPromptModalProps>(({
};
/** Send user message and get AI response */
const handleSend = () => {
if (!promptSession) return
if (!promptSession || loading || !values.message || values.message.trim() == '') return
if (!values.model_id) {
message.warning(t('common.selectPlaceholder', { title: t(`${source}.model`) }))
return
@@ -243,12 +243,20 @@ const AiPromptModal = forwardRef<AiPromptModalRef, AiPromptModalProps>(({
onBlur={handleBlur}
/>
</Form.Item>
{loading
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/loading.svg')]"></div>
: !values || !values?.message || values?.message?.trim() === ''
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]"></div>
: <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/send.svg')]" onClick={handleSend}></div>
}
<Flex align="center" justify="center"
className={clsx('rb:size-7 rb:rounded-full rb:shadow-[0px 2px 12px 0px rgba(23,23,25,0.1)]', {
'rb:cursor-not-allowed rb:bg-[#F6F6F6]': loading || !values || !values?.message || values?.message?.trim() === '',
'rb:cursor-pointer rb:bg-[#171719]': !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}
onClick={handleSend}
>
<div className={clsx("rb:size-4 rb:bg-cover", {
"rb:bg-[url('@/assets/images/conversation/loading.svg')]": loading,
"rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]": !loading && (!values || !values?.message || values?.message?.trim() === ''),
"rb:bg-[url('@/assets/images/conversation/send.svg')]": !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}></div>
</Flex>
</Flex>
</div>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:27:39
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 11:38:45
* @Last Modified time: 2026-03-20 15:40:44
*/
/**
* Chat debugging component for application testing
@@ -14,8 +14,7 @@ import { type FC, useEffect, useState, useRef, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom'
import clsx from 'clsx'
import { App, Flex } from 'antd';
import { SettingOutlined } from '@ant-design/icons'
import { App, Flex, Tooltip } from 'antd';
import ChatIcon from '@/assets/images/application/chat.png'
import DebuggingEmpty from '@/assets/images/application/debuggingEmpty.png'
@@ -84,7 +83,7 @@ const Chat: FC<ChatProps> = ({
setIsCluster(source === 'multi_agent')
toolbarRef.current?.setFiles([])
setMessage(undefined)
}, [source])
}, [source, toolbarRef.current])
/** Add user message to all chat lists */
const addUserMessage = (message: string, files: any[]) => {
@@ -428,7 +427,7 @@ const Chat: FC<ChatProps> = ({
updateChatList(chatList.filter((_, voIndex) => voIndex !== index))
}
const isHasLabel = useMemo(() => chatList.some(item => item.label), [chatList])
const isNeedVariableConfig = useMemo(() => chatVariables?.some(vo => vo.required && !vo.value), [chatVariables])
return (
<Flex vertical className="rb:relative rb:h-full">
{chatList.length === 0
@@ -461,9 +460,11 @@ const Chat: FC<ChatProps> = ({
<ChatContent
classNames={{
'rb:mb-3 rb:mt-5': isHasLabel,
'rb:mb-3': !isHasLabel,
'rb:h-[calc(100vh-292px)]': isCluster,
'rb:h-[calc(100vh-353px)]': !isCluster,
'rb:mb-0!': !isHasLabel,
'rb:h-[calc(100vh-297px)]': isCluster && (!fileList || fileList.length === 0),
'rb:h-[calc(100vh-365px)]': !isCluster && (!fileList || fileList.length === 0),
'rb:h-[calc(100vh-362px)]': isCluster && fileList?.length > 0,
'rb:h-[calc(100vh-433px)]': !isCluster && fileList?.length > 0,
"rb:pr-4": index !== chatList.length - 1 && chatList.length > 1,
"rb:pl-4": index !== 0 && chatList.length > 1,
}}
@@ -492,10 +493,10 @@ const Chat: FC<ChatProps> = ({
</Flex>
))}
</div>
<div className="rb:relative rb:flex rb:items-center rb:gap-2.5 rb:mt-4 rb:mb-1">
<div className="rb:relative rb:flex rb:items-center rb:gap-2.5 rb:mt-4">
<ChatInput
message={message}
className="rb:relative!"
className="rb:relative! rb:bottom-0!"
loading={loading}
fileChange={(list) => {
setFileList(list || [])
@@ -509,19 +510,20 @@ const Chat: FC<ChatProps> = ({
ref={toolbarRef}
features={features}
onFilesChange={setFileList}
extra={
chatVariables && chatVariables.length > 0 ? (
<div
className={clsx('rb:flex rb:items-center rb:border rb:rounded-lg rb:px-2 rb:text-[12px] rb:h-6 rb:cursor-pointer rb:hover:bg-[#F0F3F8] rb:text-[#212332]', {
'rb:border-[#FF5D34] rb:text-[#FF5D34]': chatVariables.some(vo => vo.required && !vo.value),
'rb:border-[#DFE4ED]': !chatVariables.some(vo => vo.required && !vo.value),
})}
onClick={handleEditVariables}
>
<SettingOutlined className="rb:mr-1" />
{t('memoryConversation.variableConfig')}
</div>
) : null
leftExtra={
chatVariables && chatVariables.length > 0 ?(
<Tooltip title={t('memoryConversation.variableConfig')}>
<Flex justify="center" align="center"
className={clsx("rb:size-7 rb:border rb:cursor-pointer rb:hover:bg-[#F6F6F6] rb:rounded-full rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)]", {
'rb:border-[#FF5D34]': isNeedVariableConfig,
'rb:border-[#EBEBEB]': !isNeedVariableConfig,
})}
onClick={handleEditVariables}
>
<div className="rb:size-4 rb:bg-cover rb:bg-[url('@/assets/images/conversation/variables.svg')]" />
</Flex>
</Tooltip>
): null
}
/>
</ChatInput>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:58:03
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-19 21:32:05
* @Last Modified time: 2026-03-20 15:38:36
*/
/**
* Conversation Page
@@ -14,7 +14,7 @@ import { type FC, useState, useEffect, useRef } from 'react'
import { useParams, useLocation } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import InfiniteScroll from 'react-infinite-scroll-component';
import { Flex, Skeleton, App } from 'antd'
import { Flex, Skeleton, App, Tooltip } from 'antd'
import clsx from 'clsx'
import dayjs from 'dayjs'
@@ -26,11 +26,6 @@ import { randomString } from '@/utils/common'
import ChatEmpty from '@/assets/images/empty/chatEmpty.png'
import Chat from '@/components/Chat'
import type { ChatItem } from '@/components/Chat/types'
import ButtonCheckbox from '@/components/ButtonCheckbox'
import MemoryFunctionIcon from '@/assets/images/conversation/memoryFunction.svg'
import OnlineIcon from '@/assets/images/conversation/online.svg'
import OnlineCheckedIcon from '@/assets/images/conversation/onlineChecked.svg'
import MemoryFunctionCheckedIcon from '@/assets/images/conversation/memoryFunctionChecked.svg'
import { type SSEMessage } from '@/utils/stream'
import { shareFileUploadUrlWithoutApiPrefix } from '@/api/fileStorage'
import ChatToolbar, { type ChatToolbarRef } from '@/components/Chat/ChatToolbar'
@@ -284,8 +279,9 @@ const Conversation: FC = () => {
})
}
const handleChangeMemory = (value: boolean) => {
const handleChangeMemory = () => {
if (config.app_type === 'workflow') return;
let value = !memory
modal.confirm({
title: value ? t('memoryConversation.memoryTipTitle') : t('memoryConversation.memoryCancelTipTitle'),
okText: t('common.confirm'),
@@ -354,10 +350,10 @@ const Conversation: FC = () => {
</div>
<div className="rb:relative rb:h-screen rb:px-4 rb:flex-[1_1_auto]">
<div className='rb:w-190 rb:h-screen rb:mx-auto rb:pt-10'>
<div className='rb:w-190 rb:h-screen rb:mx-auto rb:pt-10 rb:pb-3'>
<Chat
empty={<Empty url={ChatEmpty} className="rb:h-full" size={[320,180]} title={t('memoryConversation.chatEmpty')} subTitle={t('memoryConversation.emptyDesc')} />}
contentClassName={!fileList.length ? "rb:h-[calc(100%-144px)]" : "rb:h-[calc(100%-208px)]"}
contentClassName={!fileList.length ? "rb:h-[calc(100%-144px)] rb:w-full" : "rb:h-[calc(100%-208px)] rb:w-full"}
data={chatList}
streamLoading={streamLoading}
loading={loading}
@@ -381,30 +377,43 @@ const Conversation: FC = () => {
Authorization: `Bearer ${shareToken || ''}`,
}
}}
extra={
<>
rightExtra={
<Flex align="center" justify="end" gap={8}>
{features?.web_search?.enabled &&
<ButtonCheckbox
icon={OnlineIcon}
checkedIcon={OnlineCheckedIcon}
checked={webSearch}
onChange={setWebSearch}
>
{t('memoryConversation.web_search')}
</ButtonCheckbox>
<Tooltip title={t('memoryConversation.web_search')}>
<Flex justify="center" align="center"
className={clsx("rb:size-7 rb:border rb:cursor-pointer rb:hover:bg-[#F6F6F6] rb:rounded-full rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)]", {
'rb:bg-[rgba(21,94,239,0.06)] rb:border-[rgba(21,94,239,0.25)]': webSearch,
'rb:border-[#EBEBEB]': !webSearch,
})}
onClick={() => setWebSearch(prev => !prev)}
>
<div className={clsx("rb:size-4 rb:bg-cover", {
"rb:bg-[url('@/assets/images/conversation/online.svg')]": !webSearch,
"rb:bg-[url('@/assets/images/conversation/onlineChecked.svg')]": webSearch
})} />
</Flex>
</Tooltip>
}
{isHasMemory &&
<ButtonCheckbox
icon={MemoryFunctionIcon}
checkedIcon={MemoryFunctionCheckedIcon}
checked={memory}
disabled={config.app_type === 'workflow'}
onChange={handleChangeMemory}
>
{t('memoryConversation.memory')}
</ButtonCheckbox>
<Tooltip title={t('memoryConversation.memory')}>
<Flex justify="center" align="center"
className={clsx("rb:size-7 rb:border rb:hover:bg-[#F6F6F6] rb:rounded-full rb:shadow-[0px_2px_12px_0px_rgba(23,23,25,0.12)]", {
'rb:bg-[rgba(21,94,239,0.06)] rb:border-[rgba(21,94,239,0.25)]': memory,
'rb:border-[#EBEBEB]': !memory,
'rb:cursor-pointer': config.app_type !== 'workflow',
'rb:cursor-not-allowed rb:opacity-65': config.app_type === 'workflow',
})}
onClick={handleChangeMemory}
>
<div className={clsx("rb:size-4 rb:bg-cover", {
"rb:bg-[url('@/assets/images/conversation/memoryFunction.svg')]": !memory,
"rb:bg-[url('@/assets/images/conversation/memoryFunctionChecked.svg')]": memory
})} />
</Flex>
</Tooltip>
}
</>
</Flex>
}
/>
</Chat>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 17:44:15
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-07 17:15:05
* @Last Modified time: 2026-03-20 13:52:09
*/
/**
* Prompt Editor Component
@@ -72,7 +72,7 @@ const Prompt: FC = () => {
/** Send message to AI for prompt optimization */
const handleSend = () => {
if (!promptSession) return
if (!promptSession || loading || !values.message || values.message.trim() == '') return
if (!values.model_id) {
message.warning(t('common.selectPlaceholder', { title: t('prompt.model') }))
return
@@ -216,12 +216,19 @@ const Prompt: FC = () => {
onBlur={handleBlur}
/>
</Form.Item>
{loading
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/loading.svg')]"></div>
: !values || !values?.message || values?.message?.trim() === ''
? <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]"></div>
: <div className="rb:size-7 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/send.svg')]" onClick={handleSend}></div>
}
<Flex align="center" justify="center"
className={clsx('rb:size-7 rb:rounded-full rb:shadow-[0px 2px 12px 0px rgba(23,23,25,0.1)]', {
'rb:cursor-not-allowed rb:bg-[#F6F6F6]': loading || !values || !values?.message || values?.message?.trim() === '',
'rb:cursor-pointer rb:bg-[#171719]': !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}
onClick={handleSend}
>
<div className={clsx("rb:size-4 rb:bg-cover", {
"rb:bg-[url('@/assets/images/conversation/loading.svg')]": loading,
"rb:bg-[url('@/assets/images/conversation/sendDisabled.svg')]": !loading && (!values || !values?.message || values?.message?.trim() === ''),
"rb:bg-[url('@/assets/images/conversation/send.svg')]": !loading && !(!values || !values?.message || values?.message?.trim() === '')
})}></div>
</Flex>
</Flex>
</RbCard>

View File

@@ -66,7 +66,7 @@ const CommunityNetwork: FC<{ onSelectCommunity?: (node: RawCommunityNode) => voi
if (loading) {
return <Flex align="center" justify="center" className="rb:w-full rb:h-full">
<Spin tip={t('userMemory.communityLoadingTip')} size="large">
<Spin tip={t('userMemory.communityLoadingTip')} size="large" className="rb:text-[#5B6167]!">
<div className="rb:w-64 rb:h-64" />
</Spin>
</Flex>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:00
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 11:45:16
* @Last Modified time: 2026-03-20 12:14:43
*/
/**
* Relationship Network Component
@@ -13,8 +13,9 @@
import React, { type FC, useEffect, useState, useCallback, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams, useNavigate } from 'react-router-dom'
import { Space, Tabs, Flex, Divider } from 'antd'
import { Space, Flex, Divider, type SegmentedProps } from 'antd'
import dayjs from 'dayjs'
import clsx from 'clsx'
import RbCard from '@/components/RbCard/Card'
import type { GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types'
@@ -25,6 +26,7 @@ import {
import Tag from '@/components/Tag'
import GraphNetworkChart, { type Node, type Edge } from '@/components/Charts/GraphNetworkChart'
import CommunityNetwork from './CommunityNetwork'
import PageTabs from '@/components/PageTabs'
const RelationshipNetwork: FC = () => {
const { t } = useTranslation()
@@ -35,7 +37,7 @@ const RelationshipNetwork: FC = () => {
const [selectedNode, setSelectedNode] = useState<Node | RawCommunityNode | null>(null)
// const [fullScreen, setFullScreen] = useState<boolean>(false)
const navigate = useNavigate()
const [activeTab, setActiveTab] = useState('relationshipNetwork')
const [activeTab, setActiveTab] = useState<SegmentedProps['value']>('relationshipNetwork')
console.log('categories', categories)
const edgeAbortRef = useRef<AbortController | null>(null)
@@ -137,7 +139,7 @@ const RelationshipNetwork: FC = () => {
})
navigate(`/user-memory/detail/${id}/GRAPH?${params.toString()}`)
}
const handleChangeTab = (tab: string) => {
const handleChangeTab = (tab: SegmentedProps['value']) => {
if (tab === 'communityNetwork') {
edgeAbortRef.current?.abort()
} else {
@@ -149,14 +151,17 @@ const RelationshipNetwork: FC = () => {
return (
<div className="rb:flex-1 rb:relative">
<Tabs
activeKey={activeTab}
onChange={handleChangeTab}
items={['relationshipNetwork', 'communityNetwork'].map(key => ({
key,
label: t(`userMemory.${key}`)
}))}
/>
<div className="rb:absolute rb:z-111 rb:bottom-10 rb:left-[calc(50%-96px)] rb:transition-transform-[translateX(-50%]">
<PageTabs
value={activeTab}
options={['relationshipNetwork', 'communityNetwork'].map(value => ({
value,
label: t(`userMemory.${value}`)
}))}
onChange={handleChangeTab}
className=""
/>
</div>
{activeTab === 'communityNetwork'
? <CommunityNetwork onSelectCommunity={community => setSelectedNode(community)} />
: <GraphNetworkChart
@@ -174,12 +179,18 @@ const RelationshipNetwork: FC = () => {
className="rb:absolute! rb:top-4 rb:right-0 rb:w-100! rb:bg-white!"
headerType="borderless"
headerClassName="rb:min-h-[60px]!"
bodyClassName='rb:px-5! rb:pb-[76px]! rb:pt-0! rb:h-auto!'
bodyClassName={clsx('rb:px-5! rb:pt-0! rb:h-auto!', {
'rb:pb-[76px]!': activeTab !== 'communityNetwork',
'rb:pb-3!': activeTab === 'communityNetwork',
})}
extra={<div className="rb:cursor-pointer rb:size-4 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/close.svg')]" onClick={() => setSelectedNode(null)}></div>}
>
<div className="rb:max-h-[calc(100vh-269px)] rb:overflow-auto">
<div className={clsx("rb:max-h-[calc(100vh-269px)] rb:overflow-auto", {
'rb:max-h-[calc(100vh-269px)]': activeTab !== 'communityNetwork',
'rb:max-h-[calc(100vh-205px)]': activeTab == 'communityNetwork',
})}>
{(selectedNode as RawCommunityNode).properties.community_id
? <div className="rb:p-3 rb:pt-0">
? <div>
<div className="rb:font-medium rb:text-[#212332] rb:text-[16px] rb:leading-5.5 rb:pl-1">
{(selectedNode as RawCommunityNode).properties.name}
</div>
@@ -274,9 +285,9 @@ const RelationshipNetwork: FC = () => {
</>}
</div>
<Flex align="center" justify="center" className="rb:absolute rb:bottom-3 rb:left-6 rb:right-6 rb:border rb:border-[#171719] rb:rounded-xl rb:h-11 rb:font-medium rb:leading-5 rb:cursor-pointer" onClick={handleViewAll}>
{activeTab !== 'communityNetwork' && <Flex align="center" justify="center" className="rb:absolute rb:bottom-3 rb:left-6 rb:right-6 rb:border rb:border-[#171719] rb:rounded-xl rb:h-11 rb:font-medium rb:leading-5 rb:cursor-pointer" onClick={handleViewAll}>
{t('userMemory.completeMemory')}
</Flex>
</Flex>}
</RbCard>
}
</div>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-01-07 20:37:34
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 11:22:20
* @Last Modified time: 2026-03-20 11:52:00
*/
import { type FC, useState, useMemo, useRef } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
@@ -114,7 +114,7 @@ const Detail: FC = () => {
</Space>
}
/>
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:p-3">
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:px-3 rb:pb-3">
{type === 'EMOTIONAL_MEMORY' && <StatementDetail ref={statementDetailRef} refresh={handleRefresh} />}
{type === 'FORGET_MEMORY' && <ForgetDetail ref={forgetDetailRef} />}
{type === 'IMPLICIT_MEMORY' && <ImplicitDetail ref={implicitDetailRef} refresh={handleRefresh} />}