Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
826c1a59
Commit
826c1a59
authored
Jun 30, 2023
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
for testing on mobile phone
parent
da04ff04
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
577 additions
and
0 deletions
+577
-0
index.tsx
web/app/components/app/chat/index.tsx
+15
-0
loading-02.svg
...ents/base/icons/assets/vender/line/general/loading-02.svg
+10
-0
x-close.svg
...ponents/base/icons/assets/vender/line/general/x-close.svg
+5
-0
microphone-01.svg
...cons/assets/vender/line/mediaAndDevices/microphone-01.svg
+5
-0
x-circle.svg
...nents/base/icons/assets/vender/solid/general/x-circle.svg
+3
-0
microphone-01.svg
...ons/assets/vender/solid/mediaAndDevices/microphone-01.svg
+8
-0
stop-circle.svg
...icons/assets/vender/solid/mediaAndDevices/stop-circle.svg
+5
-0
Loading02.json
...ponents/base/icons/src/vender/line/general/Loading02.json
+64
-0
Loading02.tsx
...mponents/base/icons/src/vender/line/general/Loading02.tsx
+14
-0
XClose.json
...components/base/icons/src/vender/line/general/XClose.json
+39
-0
XClose.tsx
.../components/base/icons/src/vender/line/general/XClose.tsx
+14
-0
index.ts
...pp/components/base/icons/src/vender/line/general/index.ts
+2
-0
Microphone01.json
...e/icons/src/vender/line/mediaAndDevices/Microphone01.json
+39
-0
Microphone01.tsx
...se/icons/src/vender/line/mediaAndDevices/Microphone01.tsx
+14
-0
index.ts
...nents/base/icons/src/vender/line/mediaAndDevices/index.ts
+1
-0
XCircle.json
...mponents/base/icons/src/vender/solid/general/XCircle.json
+29
-0
XCircle.tsx
...omponents/base/icons/src/vender/solid/general/XCircle.tsx
+14
-0
index.ts
...p/components/base/icons/src/vender/solid/general/index.ts
+1
-0
Microphone01.json
.../icons/src/vender/solid/mediaAndDevices/Microphone01.json
+55
-0
Microphone01.tsx
...e/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx
+14
-0
StopCircle.json
...se/icons/src/vender/solid/mediaAndDevices/StopCircle.json
+38
-0
StopCircle.tsx
...ase/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx
+14
-0
index.ts
...ents/base/icons/src/vender/solid/mediaAndDevices/index.ts
+2
-0
index.module.css
web/app/components/base/voice-input/index.module.css
+9
-0
index.tsx
web/app/components/base/voice-input/index.tsx
+152
-0
common.en.ts
web/i18n/lang/common.en.ts
+4
-0
common.zh.ts
web/i18n/lang/common.zh.ts
+4
-0
package.json
web/package.json
+3
-0
No files found.
web/app/components/app/chat/index.tsx
View file @
826c1a59
...
...
@@ -19,6 +19,9 @@ import AppContext from '@/context/app-context'
import
{
Markdown
}
from
'@/app/components/base/markdown'
import
{
formatNumber
}
from
'@/utils/format'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
VoiceInput
from
'@/app/components/base/voice-input'
import
{
Microphone01
}
from
'@/app/components/base/icons/src/vender/line/mediaAndDevices'
import
{
Microphone01
as
Microphone01Solid
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
const
stopIcon
=
(
<
svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
...
...
@@ -488,6 +491,8 @@ const Chat: FC<IChatProps> = ({
}
},
[
suggestionList
])
const
[
voiceInputShow
,
setVoiceInputShow
]
=
useState
(
false
)
return
(
<
div
className=
{
cn
(
'px-3.5'
,
'h-full'
)
}
>
{
/* Chat List */
}
...
...
@@ -565,6 +570,13 @@ const Chat: FC<IChatProps> = ({
/>
<
div
className=
"absolute top-0 right-2 flex items-center h-[48px]"
>
<
div
className=
{
`${s.count} mr-4 h-5 leading-5 text-sm bg-gray-50 text-gray-500`
}
>
{
query
.
trim
().
length
}
</
div
>
<
div
className=
'group flex justify-center items-center w-8 h-8 hover:bg-primary-50 rounded-lg cursor-pointer'
onClick=
{
()
=>
setVoiceInputShow
(
true
)
}
>
<
Microphone01
className=
'block w-4 h-4 text-gray-500 group-hover:hidden'
/>
<
Microphone01Solid
className=
'hidden w-4 h-4 text-primary-600 group-hover:block'
/>
</
div
>
{
isMobile
?
sendBtn
:
(
...
...
@@ -581,6 +593,9 @@ const Chat: FC<IChatProps> = ({
</
Tooltip
>
)
}
</
div
>
{
voiceInputShow
&&
<
VoiceInput
onConverted=
{
()
=>
setVoiceInputShow
(
false
)
}
/>
}
</
div
>
</
div
>
)
...
...
web/app/components/base/icons/assets/vender/line/general/loading-02.svg
0 → 100644
View file @
826c1a59
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
clip-path=
"url(#clip0_6037_51601)"
>
<path
d=
"M7.99992 1.33398V4.00065M7.99992 12.0007V14.6673M3.99992 8.00065H1.33325M14.6666 8.00065H11.9999M12.7189 12.7196L10.8333 10.834M12.7189 3.33395L10.8333 5.21956M3.28097 12.7196L5.16659 10.834M3.28097 3.33395L5.16659 5.21956"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
<defs>
<clipPath
id=
"clip0_6037_51601"
>
<rect
width=
"16"
height=
"16"
fill=
"white"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/assets/vender/line/general/x-close.svg
0 → 100644
View file @
826c1a59
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"x-close"
>
<path
id=
"Icon"
d=
"M12 4L4 12M4 4L12 12"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg
0 → 100644
View file @
826c1a59
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"microphone-01"
>
<path
id=
"Icon"
d=
"M12.6666 6.66732V8.00065C12.6666 10.578 10.5772 12.6673 7.99992 12.6673M3.33325 6.66732V8.00065C3.33325 10.578 5.42259 12.6673 7.99992 12.6673M7.99992 12.6673V14.6673M5.33325 14.6673H10.6666M7.99992 10.0007C6.89535 10.0007 5.99992 9.10522 5.99992 8.00065V3.33398C5.99992 2.22941 6.89535 1.33398 7.99992 1.33398C9.10449 1.33398 9.99992 2.22941 9.99992 3.33398V8.00065C9.99992 9.10522 9.10449 10.0007 7.99992 10.0007Z"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/general/x-circle.svg
0 → 100644
View file @
826c1a59
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8.00008 0.666016C3.94999 0.666016 0.666748 3.94926 0.666748 7.99935C0.666748 12.0494 3.94999 15.3327 8.00008 15.3327C12.0502 15.3327 15.3334 12.0494 15.3334 7.99935C15.3334 3.94926 12.0502 0.666016 8.00008 0.666016ZM10.4715 5.52794C10.7318 5.78829 10.7318 6.2104 10.4715 6.47075L8.94289 7.99935L10.4715 9.52794C10.7318 9.78829 10.7318 10.2104 10.4715 10.4708C10.2111 10.7311 9.78903 10.7311 9.52868 10.4708L8.00008 8.94216L6.47149 10.4708C6.21114 10.7311 5.78903 10.7311 5.52868 10.4708C5.26833 10.2104 5.26833 9.78829 5.52868 9.52794L7.05727 7.99935L5.52868 6.47075C5.26833 6.2104 5.26833 5.78829 5.52868 5.52794C5.78903 5.26759 6.21114 5.26759 6.47149 5.52794L8.00008 7.05654L9.52868 5.52794C9.78903 5.26759 10.2111 5.26759 10.4715 5.52794Z"
fill=
"#98A2B3"
/>
</svg>
web/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg
0 → 100644
View file @
826c1a59
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"microphone-01"
>
<g
id=
"Solid"
>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8.00008 0.666016C6.52732 0.666016 5.33341 1.85992 5.33341 3.33268V7.99935C5.33341 9.47211 6.52732 10.666 8.00008 10.666C9.47284 10.666 10.6667 9.47211 10.6667 7.99935V3.33268C10.6667 1.85992 9.47284 0.666016 8.00008 0.666016Z"
fill=
"#155EEF"
/>
<path
d=
"M4.00008 6.66602C4.00008 6.29783 3.7016 5.99935 3.33341 5.99935C2.96522 5.99935 2.66675 6.29783 2.66675 6.66602V7.99935C2.66675 10.7195 4.70319 12.9641 7.33466 13.2916C7.33384 13.3052 7.33341 13.3189 7.33341 13.3327V13.9993H5.33341C4.96522 13.9993 4.66675 14.2978 4.66675 14.666C4.66675 15.0342 4.96522 15.3327 5.33341 15.3327H10.6667C11.0349 15.3327 11.3334 15.0342 11.3334 14.666C11.3334 14.2978 11.0349 13.9993 10.6667 13.9993H8.66675V13.3327C8.66675 13.3189 8.66633 13.3052 8.6655 13.2916C11.297 12.9641 13.3334 10.7195 13.3334 7.99935V6.66602C13.3334 6.29783 13.0349 5.99935 12.6667 5.99935C12.2986 5.99935 12.0001 6.29783 12.0001 6.66602V7.99935C12.0001 10.2085 10.2092 11.9993 8.00008 11.9993C5.79094 11.9993 4.00008 10.2085 4.00008 7.99935V6.66602Z"
fill=
"#155EEF"
/>
</g>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg
0 → 100644
View file @
826c1a59
<svg
width=
"20"
height=
"20"
viewBox=
"0 0 20 20"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"stop-circle"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M9.99992 0.833984C4.93731 0.833984 0.833252 4.93804 0.833252 10.0007C0.833252 15.0633 4.93731 19.1673 9.99992 19.1673C15.0625 19.1673 19.1666 15.0633 19.1666 10.0007C19.1666 4.93804 15.0625 0.833984 9.99992 0.833984ZM6.75741 7.12232C6.66658 7.30058 6.66658 7.53394 6.66658 8.00065V12.0006C6.66658 12.4674 6.66658 12.7007 6.75741 12.879C6.83731 13.0358 6.96479 13.1633 7.12159 13.2432C7.29985 13.334 7.53321 13.334 7.99992 13.334H11.9999C12.4666 13.334 12.7 13.334 12.8782 13.2432C13.035 13.1633 13.1625 13.0358 13.2424 12.879C13.3333 12.7007 13.3333 12.4674 13.3333 12.0006V8.00065C13.3333 7.53394 13.3333 7.30058 13.2424 7.12232C13.1625 6.96552 13.035 6.83804 12.8782 6.75814C12.7 6.66732 12.4666 6.66732 11.9999 6.66732H7.99992C7.53321 6.66732 7.29985 6.66732 7.12159 6.75814C6.96479 6.83804 6.83731 6.96552 6.75741 7.12232Z"
fill=
"#155EEF"
/>
</g>
</svg>
web/app/components/base/icons/src/vender/line/general/Loading02.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"clip-path"
:
"url(#clip0_6037_51601)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M7.99992 1.33398V4.00065M7.99992 12.0007V14.6673M3.99992 8.00065H1.33325M14.6666 8.00065H11.9999M12.7189 12.7196L10.8333 10.834M12.7189 3.33395L10.8333 5.21956M3.28097 12.7196L5.16659 10.834M3.28097 3.33395L5.16659 5.21956"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
},
{
"type"
:
"element"
,
"name"
:
"defs"
,
"attributes"
:
{},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"clipPath"
,
"attributes"
:
{
"id"
:
"clip0_6037_51601"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"fill"
:
"white"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"Loading02"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/general/Loading02.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Loading02.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/general/XClose.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"x-close"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M12 4L4 12M4 4L12 12"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"XClose"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/general/XClose.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./XClose.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/general/index.ts
View file @
826c1a59
export
{
default
as
Loading02
}
from
'./Loading02'
export
{
default
as
Trash03
}
from
'./Trash03'
export
{
default
as
XClose
}
from
'./XClose'
web/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"microphone-01"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M12.6666 6.66732V8.00065C12.6666 10.578 10.5772 12.6673 7.99992 12.6673M3.33325 6.66732V8.00065C3.33325 10.578 5.42259 12.6673 7.99992 12.6673M7.99992 12.6673V14.6673M5.33325 14.6673H10.6666M7.99992 10.0007C6.89535 10.0007 5.99992 9.10522 5.99992 8.00065V3.33398C5.99992 2.22941 6.89535 1.33398 7.99992 1.33398C9.10449 1.33398 9.99992 2.22941 9.99992 3.33398V8.00065C9.99992 9.10522 9.10449 10.0007 7.99992 10.0007Z"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Microphone01"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Microphone01.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts
0 → 100644
View file @
826c1a59
export
{
default
as
Microphone01
}
from
'./Microphone01'
web/app/components/base/icons/src/vender/solid/general/XCircle.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M8.00008 0.666016C3.94999 0.666016 0.666748 3.94926 0.666748 7.99935C0.666748 12.0494 3.94999 15.3327 8.00008 15.3327C12.0502 15.3327 15.3334 12.0494 15.3334 7.99935C15.3334 3.94926 12.0502 0.666016 8.00008 0.666016ZM10.4715 5.52794C10.7318 5.78829 10.7318 6.2104 10.4715 6.47075L8.94289 7.99935L10.4715 9.52794C10.7318 9.78829 10.7318 10.2104 10.4715 10.4708C10.2111 10.7311 9.78903 10.7311 9.52868 10.4708L8.00008 8.94216L6.47149 10.4708C6.21114 10.7311 5.78903 10.7311 5.52868 10.4708C5.26833 10.2104 5.26833 9.78829 5.52868 9.52794L7.05727 7.99935L5.52868 6.47075C5.26833 6.2104 5.26833 5.78829 5.52868 5.52794C5.78903 5.26759 6.21114 5.26759 6.47149 5.52794L8.00008 7.05654L9.52868 5.52794C9.78903 5.26759 10.2111 5.26759 10.4715 5.52794Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
},
"name"
:
"XCircle"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/general/XCircle.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./XCircle.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/solid/general/index.ts
0 → 100644
View file @
826c1a59
export
{
default
as
XCircle
}
from
'./XCircle'
web/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"microphone-01"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"Solid"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M8.00008 0.666016C6.52732 0.666016 5.33341 1.85992 5.33341 3.33268V7.99935C5.33341 9.47211 6.52732 10.666 8.00008 10.666C9.47284 10.666 10.6667 9.47211 10.6667 7.99935V3.33268C10.6667 1.85992 9.47284 0.666016 8.00008 0.666016Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M4.00008 6.66602C4.00008 6.29783 3.7016 5.99935 3.33341 5.99935C2.96522 5.99935 2.66675 6.29783 2.66675 6.66602V7.99935C2.66675 10.7195 4.70319 12.9641 7.33466 13.2916C7.33384 13.3052 7.33341 13.3189 7.33341 13.3327V13.9993H5.33341C4.96522 13.9993 4.66675 14.2978 4.66675 14.666C4.66675 15.0342 4.96522 15.3327 5.33341 15.3327H10.6667C11.0349 15.3327 11.3334 15.0342 11.3334 14.666C11.3334 14.2978 11.0349 13.9993 10.6667 13.9993H8.66675V13.3327C8.66675 13.3189 8.66633 13.3052 8.6655 13.2916C11.297 12.9641 13.3334 10.7195 13.3334 7.99935V6.66602C13.3334 6.29783 13.0349 5.99935 12.6667 5.99935C12.2986 5.99935 12.0001 6.29783 12.0001 6.66602V7.99935C12.0001 10.2085 10.2092 11.9993 8.00008 11.9993C5.79094 11.9993 4.00008 10.2085 4.00008 7.99935V6.66602Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"Microphone01"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Microphone01.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.json
0 → 100644
View file @
826c1a59
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"20"
,
"height"
:
"20"
,
"viewBox"
:
"0 0 20 20"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"stop-circle"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M9.99992 0.833984C4.93731 0.833984 0.833252 4.93804 0.833252 10.0007C0.833252 15.0633 4.93731 19.1673 9.99992 19.1673C15.0625 19.1673 19.1666 15.0633 19.1666 10.0007C19.1666 4.93804 15.0625 0.833984 9.99992 0.833984ZM6.75741 7.12232C6.66658 7.30058 6.66658 7.53394 6.66658 8.00065V12.0006C6.66658 12.4674 6.66658 12.7007 6.75741 12.879C6.83731 13.0358 6.96479 13.1633 7.12159 13.2432C7.29985 13.334 7.53321 13.334 7.99992 13.334H11.9999C12.4666 13.334 12.7 13.334 12.8782 13.2432C13.035 13.1633 13.1625 13.0358 13.2424 12.879C13.3333 12.7007 13.3333 12.4674 13.3333 12.0006V8.00065C13.3333 7.53394 13.3333 7.30058 13.2424 7.12232C13.1625 6.96552 13.035 6.83804 12.8782 6.75814C12.7 6.66732 12.4666 6.66732 11.9999 6.66732H7.99992C7.53321 6.66732 7.29985 6.66732 7.12159 6.75814C6.96479 6.83804 6.83731 6.96552 6.75741 7.12232Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"StopCircle"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx
0 → 100644
View file @
826c1a59
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./StopCircle.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts
0 → 100644
View file @
826c1a59
export
{
default
as
Microphone01
}
from
'./Microphone01'
export
{
default
as
StopCircle
}
from
'./StopCircle'
web/app/components/base/voice-input/index.module.css
0 → 100644
View file @
826c1a59
.wrapper
{
box-shadow
:
0px
4px
6px
-2px
rgba
(
16
,
24
,
40
,
0.03
),
0px
12px
16px
-4px
rgba
(
16
,
24
,
40
,
0.08
);
}
.convert
{
background
:
linear-gradient
(
91.92deg
,
#104AE1
-1.74%
,
#0098EE
75.74%
);
background-clip
:
text
;
color
:
transparent
;
}
\ No newline at end of file
web/app/components/base/voice-input/index.tsx
0 → 100644
View file @
826c1a59
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
Recorder
from
'js-audio-recorder'
import
s
from
'./index.module.css'
import
{
StopCircle
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import
{
Loading02
,
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
type
VoiceInputTypes
=
{
onConverted
:
(
text
:
string
)
=>
void
}
const
VoiceInput
=
({
onConverted
,
}:
VoiceInputTypes
)
=>
{
const
{
t
}
=
useTranslation
()
const
recorder
=
useRef
(
new
Recorder
())
const
canvasRef
=
useRef
<
HTMLCanvasElement
|
null
>
(
null
)
const
ctxRef
=
useRef
<
CanvasRenderingContext2D
|
null
>
(
null
)
const
drawRecordId
=
useRef
<
number
|
null
>
(
null
)
const
[
duration
,
setDuration
]
=
useState
(
'00:00'
)
const
[
startRecord
,
setStartRecord
]
=
useState
(
false
)
const
[
startConvert
,
setStartConvert
]
=
useState
(
false
)
const
drawRecord
=
useCallback
(()
=>
{
drawRecordId
.
current
=
requestAnimationFrame
(
drawRecord
)
const
canvas
=
canvasRef
.
current
!
const
ctx
=
ctxRef
.
current
!
const
dataArray
=
recorder
.
current
.
getRecordAnalyseData
()
const
lineLength
=
parseInt
(
`
${
canvas
.
width
/
3
}
`
)
const
gap
=
parseInt
(
`
${
1024
/
lineLength
}
`
)
ctx
.
clearRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
)
ctx
.
beginPath
()
let
x
=
0
for
(
let
i
=
0
;
i
<
lineLength
;
i
++
)
{
let
v
=
dataArray
[
i
*
gap
]
if
(
v
<
128
)
v
=
128
if
(
v
>
188
)
v
=
188
const
y
=
(
v
-
118
)
/
70
*
canvas
.
height
ctx
.
moveTo
(
x
,
16
)
ctx
.
roundRect
(
x
,
16
-
y
,
2
,
y
,
[
1
,
1
,
0
,
0
])
ctx
.
fill
()
x
+=
4
}
ctx
.
closePath
()
},
[])
const
handleStopRecorder
=
useCallback
(()
=>
{
setStartRecord
(
false
)
setStartConvert
(
true
)
recorder
.
current
.
stop
()
drawRecordId
.
current
&&
cancelAnimationFrame
(
drawRecordId
.
current
)
drawRecordId
.
current
=
null
// const wavBlob = recorder.current.getWAVBlob()
// const wavFile = new File([wavBlob], 'audio.wav', { type: 'audio/wav' })
// onConverted('')
},
[])
const
handleStartRecord
=
()
=>
{
setStartRecord
(
true
)
setStartConvert
(
false
)
recorder
.
current
.
start
()
recorder
.
current
.
onprogress
=
(
params
)
=>
{
const
originDuration
=
params
.
duration
if
(
originDuration
>
65
)
{
console
.
log
(
'stop'
)
handleStopRecorder
()
}
const
minutes
=
parseInt
(
`
${
parseInt
(
`
${
originDuration
}
`
)
/
60
}
`
)
const
seconds
=
parseInt
(
`
${
originDuration
}
`
)
%
60
setDuration
(
`0
${
minutes
.
toFixed
(
0
)}
:
${
seconds
>=
10
?
seconds
:
`0
${
seconds
}
`
}
`
)
}
if
(
canvasRef
.
current
&&
ctxRef
.
current
)
drawRecord
()
}
const
handleStopConvert
=
()
=>
{
handleStartRecord
()
}
const
initCanvas
=
()
=>
{
const
dpr
=
window
.
devicePixelRatio
||
1
const
canvas
=
document
.
getElementById
(
'voice-input-record'
)
as
HTMLCanvasElement
if
(
canvas
)
{
const
{
width
:
cssWidth
,
height
:
cssHeight
}
=
canvas
.
getBoundingClientRect
()
canvas
.
width
=
dpr
*
cssWidth
canvas
.
height
=
dpr
*
cssHeight
canvasRef
.
current
=
canvas
const
ctx
=
canvas
.
getContext
(
'2d'
)
if
(
ctx
)
{
ctx
.
scale
(
dpr
,
dpr
)
ctx
.
fillStyle
=
'rgba(209, 224, 255, 1)'
ctxRef
.
current
=
ctx
}
}
}
useEffect
(()
=>
{
initCanvas
()
handleStartRecord
()
},
[])
return
(
<
div
className=
{
cn
(
s
.
wrapper
,
'flex items-center absolute inset-0 pl-4 pr-2 py-[14px] bg-primary-25 rounded-xl overflow-hidden'
)
}
>
<
canvas
id=
'voice-input-record'
className=
'absolute left-0 bottom-0 w-full h-4'
/>
{
startConvert
&&
<
Loading02
className=
'mr-2 w-4 h-4 text-primary-700'
/>
}
<
div
className=
'grow'
>
{
startRecord
&&
(
<
div
className=
'text-sm text-gray-500'
>
{
t
(
'common.voiceInput.speaking'
)
}
</
div
>
)
}
{
startConvert
&&
(
<
div
className=
{
cn
(
s
.
convert
,
'text-sm'
)
}
>
{
t
(
'common.voiceInput.converting'
)
}
</
div
>
)
}
</
div
>
{
startRecord
&&
(
<
div
className=
'flex justify-center items-center mr-1 w-8 h-8 hover:bg-primary-100 rounded-lg cursor-pointer'
onClick=
{
handleStopRecorder
}
>
<
StopCircle
className=
'w-5 h-5 text-primary-600'
/>
</
div
>
)
}
{
startConvert
&&
(
<
div
className=
'flex justify-center items-center mr-1 w-8 h-8 hover:bg-primary-100 rounded-lg cursor-pointer'
onClick=
{
handleStopConvert
}
>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
)
}
<
div
className=
'w-[45px] pl-1 text-xs font-medium text-gray-700'
>
{
duration
}
</
div
>
</
div
>
)
}
export
default
VoiceInput
web/i18n/lang/common.en.ts
View file @
826c1a59
...
...
@@ -224,6 +224,10 @@ const translation = {
viewDoc
:
'View documentation'
,
relatedApp
:
'linked apps'
,
},
voiceInput
:
{
speaking
:
'Speak now...'
,
converting
:
'Converting to text...'
,
},
}
export
default
translation
web/i18n/lang/common.zh.ts
View file @
826c1a59
...
...
@@ -225,6 +225,10 @@ const translation = {
viewDoc
:
'查看文档'
,
relatedApp
:
'个关联应用'
,
},
voiceInput
:
{
speaking
:
'现在讲...'
,
converting
:
'正在转换为文本...'
,
},
}
export
default
translation
web/package.json
View file @
826c1a59
...
...
@@ -48,6 +48,7 @@
"i18next"
:
"^22.4.13"
,
"i18next-resources-to-backend"
:
"^1.1.3"
,
"immer"
:
"^9.0.19"
,
"js-audio-recorder"
:
"^1.0.7"
,
"js-cookie"
:
"^3.0.1"
,
"katex"
:
"^0.16.7"
,
"lodash-es"
:
"^4.17.21"
,
...
...
@@ -67,6 +68,7 @@
"react-tooltip"
:
"5.8.3"
,
"react-window"
:
"^1.8.9"
,
"react-window-infinite-loader"
:
"^1.0.9"
,
"recordrtc"
:
"^5.6.2"
,
"rehype-katex"
:
"^6.0.2"
,
"remark-breaks"
:
"^3.0.2"
,
"remark-gfm"
:
"^3.0.1"
,
...
...
@@ -87,6 +89,7 @@
"@types/js-cookie"
:
"^3.0.3"
,
"@types/negotiator"
:
"^0.6.1"
,
"@types/qs"
:
"^6.9.7"
,
"@types/recordrtc"
:
"^5.6.11"
,
"@types/sortablejs"
:
"^1.15.1"
,
"eslint-config-next"
:
"^13.4.7"
,
"eslint-plugin-react-hooks"
:
"^4.6.0"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment