Skip to content

Commit

Permalink
Merge pull request #26 from 1eeing/main
Browse files Browse the repository at this point in the history
update im 10.3.0
  • Loading branch information
shine2008 authored Jul 16, 2024
2 parents 74c826c + 2594c0d commit 4cf5990
Show file tree
Hide file tree
Showing 112 changed files with 5,162 additions and 1,477 deletions.
10 changes: 5 additions & 5 deletions react/src/YXUIKit/im-kit-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xkit-yx/im-kit-ui",
"version": "10.0.1",
"version": "10.3.0",
"description": "云信即时通讯组件",
"license": "MIT",
"main": "lib/index.js",
Expand Down Expand Up @@ -54,13 +54,13 @@
},
"dependencies": {
"@ant-design/icons": "^5.0.1",
"@xkit-yx/im-store-v2": "^0.1.1",
"@xkit-yx/utils": "^0.6.0",
"@xkit-yx/im-store-v2": "^0.2.0",
"@xkit-yx/utils": "^0.7.1",
"antd": "^4.16.3",
"mobx": "^6.6.1",
"mobx-react": "^7.5.2",
"nim-web-sdk-ng": "10.2.700",
"nim-web-sdk-ng": "10.3.0",
"react-string-replace": "^1.1.0"
},
"gitHead": "4e09464e7bb40f8b578b2704e7931ea1e6928417"
"gitHead": "5309f0b247ec3584301aa3ec5f8df0c3cbcd0966"
}
2 changes: 1 addition & 1 deletion react/src/YXUIKit/im-kit-ui/src/chat/Container.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ReactNode } from 'react'
import P2pChatContainer from './containers/p2pChatContainer'
import TeamChatContainer from './containers/teamChatContainer'
import { useStateContext, useEventTracking, Welcome, Utils } from '../common'
import { useStateContext, useEventTracking, Welcome } from '../common'
import { RenderP2pCustomMessageOptions } from './components/ChatP2pMessageList'
import { RenderTeamCustomMessageOptions } from './components/ChatTeamMessageList'
import { ChatMessageInputProps } from './components/ChatMessageInput'
Expand Down
119 changes: 119 additions & 0 deletions react/src/YXUIKit/im-kit-ui/src/chat/components/ChatAISearch/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Drawer, Input, message } from 'antd'
import { observer } from 'mobx-react'
import React, { FC, useState } from 'react'
import { useStateContext, useTranslation } from '../../../common'
import { LoadingOutlined } from '@ant-design/icons'
import { V2NIMAIModelRoleType } from 'nim-web-sdk-ng/dist/v2/NIM_BROWSER_SDK/V2NIMAIService'
import { getAIErrorMap } from '../../../utils'

export interface ChatAISearchProps {
prefix?: string
}

export const ChatAISearch: FC<ChatAISearchProps> = observer(
({ prefix = 'chat' }) => {
const _prefix = `${prefix}-ai-search`

const { store } = useStateContext()
const { t } = useTranslation()

const aiErrorMap = getAIErrorMap(t)

const [inputValue, setInputValue] = useState('')

const title = store.aiUserStore.aiProxying ? (
<div className={`${_prefix}-title`}>
<LoadingOutlined style={{ color: '#1861df' }} />
<span style={{ marginLeft: '5px' }}>{t('aiSearchingText')}</span>
</div>
) : (
<div>{t('aiSearchText')}</div>
)

const onInputChangeHandler = (
e: React.ChangeEvent<HTMLTextAreaElement>
) => {
setInputValue(e.target.value)
}

const onPressEnterHandler = (
e: React.KeyboardEvent<HTMLTextAreaElement>
) => {
const trimValue = inputValue.trim()

if (!e.shiftKey) {
e.preventDefault()
if (!trimValue) {
message.warning(t('sendEmptyText'))
return
}

const aiSearchUser = store.aiUserStore.getAISearchUser()

if (aiSearchUser) {
store.aiUserStore
.sendAIProxyActive({
accountId: aiSearchUser.accountId,
content: { msg: trimValue, type: 0 },
messages: store.aiUserStore.aiReqMsgs.map((item) => ({
role: 'user' as V2NIMAIModelRoleType,
...item,
})),
onSendAIProxyErrorHandler: (code: number) => {
const errorText = aiErrorMap[code] || t('aiProxyFailedText')

message.error(errorText)
},
})
.catch(() => {
//
})
}

setInputValue('')
}
}

const onCloseHandler = () => {
store.aiUserStore.resetAIProxy()
}

return (
<Drawer
mask={false}
maskClosable={false}
placement="bottom"
open={store.aiUserStore.isAISearching()}
closable={true}
getContainer={false}
title={title}
onClose={onCloseHandler}
keyboard={false}
className={_prefix}
>
<div className={`${_prefix}-content`}>
<Input.TextArea
placeholder={t('aiSearchInputPlaceholder')}
bordered={true}
className={`${_prefix}-textarea`}
value={inputValue}
onInput={onInputChangeHandler}
onPressEnter={onPressEnterHandler}
autoSize={{ maxRows: 3 }}
/>
<div className={`${_prefix}-tip`}>{t('searchTipText')}</div>
<div className={`${_prefix}-list`}>
{store.aiUserStore.aiResMsgs
.slice()
.reverse()
.map((item, index) => (
<div key={`${item}_${index}`} className={`${_prefix}-item`}>
{item}
</div>
))}
</div>
</div>
</Drawer>
)
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@import '../../../style/theme.less';
@import '~antd/lib/style/themes/variable.less';

@prefix-cls: ~'@{chat-prefix}-ai-search';

.@{prefix-cls} {
&-content {
display: flex;
flex-direction: column;
color: @yx-primary-text-color;
font-size: @yx-primary-font-size;
height: 100%;
}

.@{ant-prefix}-drawer-header-title {
flex-flow: row-reverse;
}

&-title {
display: flex;
align-items: center;
}

&-textarea {
resize: 'none';
line-height: '22px';
padding: 12px;

&.@{ant-prefix}-input {
min-height: 48px;
}
}

&-tip {
color: @yx-text-color-2;
font-size: @yx-font-size-12;
text-align: right;
margin-top: 5px;
}

&-list {
overflow-y: auto;
padding: 0 16px;
}

&-item {
padding: 16px 0;
&:not(:last-child) {
border-bottom: 1px solid @yx-border-color-3;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'antd/lib/input/style'
import 'antd/lib/drawer/style'
import 'antd/lib/message/style'

import './index.less'
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { observer } from 'mobx-react'
import React, { FC, useEffect, useState } from 'react'
import { useStateContext, useTranslation } from '../../../common'
import { Select, Button, message } from 'antd'
import {
ArrowDownOutlined,
CloseOutlined,
LoadingOutlined,
} from '@ant-design/icons'
import { getAIErrorMap, logger } from '../../../utils'
import { V2NIMError } from 'nim-web-sdk-ng/dist/v2/NIM_BROWSER_SDK/types'

export interface ChatAITranslateProps {
inputValue: string
setInputValue: (value: string) => void
onClose: () => void
visible: boolean

prefix?: string
}

export const ChatAITranslate: FC<ChatAITranslateProps> = observer(
({ inputValue, setInputValue, onClose, visible, prefix = 'chat' }) => {
const _prefix = `${prefix}-ai-translate`

const { store } = useStateContext()
const { t } = useTranslation()

const aiErrorMap = getAIErrorMap(t)

const options = store.aiUserStore.getAITranslateLangs().map((lang) => ({
label: lang,
value: lang,
}))

const resonpse = store.aiUserStore.isAITranslating()
? store.aiUserStore.aiResMsgs[0]
: ''

const [selectedLang, setSelectedLang] = useState(options[0].value)

const resetState = () => {
setSelectedLang(options[0].value)
}

useEffect(() => {
resetState()
store.aiUserStore.resetAIProxy()
}, [visible, store.aiUserStore])

useEffect(() => {
store.aiUserStore.resetAIProxy()
}, [inputValue, store.aiUserStore, selectedLang])

const onUseTranslateHandler = () => {
setInputValue(resonpse)
}

const onTranslateHandler = async () => {
if (!inputValue) {
message.warning(t('aiTranslateEmptyText'))
return
}

const aiTranslateUser = store.aiUserStore.getAITranslateUser()

if (aiTranslateUser) {
try {
await store.aiUserStore.sendAIProxyActive({
accountId: aiTranslateUser.accountId,
requestId: Math.random().toString(36).slice(2),
content: { msg: inputValue, type: 0 },
promptVariables: JSON.stringify({ Language: selectedLang }),
onSendAIProxyErrorHandler: (code: number) => {
const errorText = aiErrorMap[code] || t('aiProxyFailedText')

message.error(errorText)
},
})
} catch (error) {
logger.error('AI 翻译失败', (error as V2NIMError).toString())
}
}
}

const renderBtn = () => {
return store.aiUserStore.aiProxying ? (
<div className={`${_prefix}-btn`}>
<LoadingOutlined />
<span style={{ marginLeft: '5px' }}>{t('aiTranslatingText')}</span>
</div>
) : resonpse ? (
<Button
type="link"
className={`${_prefix}-btn`}
onClick={onUseTranslateHandler}
>
<span>{t('aiTranslatedText')}</span>
<ArrowDownOutlined style={{ fontSize: 12 }} />
</Button>
) : (
<Button
type="link"
className={`${_prefix}-btn`}
onClick={onTranslateHandler}
>
{t('aiTranslateText')}
</Button>
)
}

return visible ? (
<div className={_prefix}>
<Select
options={options}
value={selectedLang}
onSelect={setSelectedLang}
className={`${_prefix}-select`}
showArrow={false}
dropdownMatchSelectWidth={120}
/>
<div className={`${_prefix}-content`}>
{resonpse ? (
resonpse
) : (
<span className={`${_prefix}-tip`}>
{t('aiTranslatePlaceholder')}
</span>
)}
</div>
{renderBtn()}
<Button
type="text"
icon={<CloseOutlined style={{ fontSize: 12 }} />}
onClick={onClose}
></Button>
</div>
) : null
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import '../../../style/theme.less';
@import '~antd/lib/style/themes/variable.less';

@prefix-cls: ~'@{chat-prefix}-ai-translate';

.@{prefix-cls} {
display: flex;
flex-direction: row;
align-items: center;
padding: 9px 12px;
background-color: @yx-background-color-4;
border-top: 1px solid @yx-border-color-8;
border-radius: 4px 4px 0 0;
font-size: @yx-primary-font-size;
color: @yx-primary-text-color;

&-content {
flex: 1;
word-wrap: break-word;
max-height: 46px;
overflow-y: auto;
margin: 0 5px;
}

&-tip {
color: @yx-text-color-3;
}

&-btn {
color: @yx-primary-button-color;
display: flex;
flex-direction: row;
align-items: center;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'antd/lib/button/style'
import 'antd/lib/select/style'
import 'antd/lib/message/style'

import './index.less'
Loading

0 comments on commit 4cf5990

Please sign in to comment.