feat: support coze bot & update comments & fix some ui bug.
This commit is contained in:
parent
dc4124e362
commit
f028bea0c5
@ -41,7 +41,7 @@
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": ["warn", { "trailingComma": "es5", "printWidth": 200 }],
|
||||
"prettier/prettier": ["warn", { "trailingComma": "es5", "printWidth": 100 }],
|
||||
"linebreak-style": "off",
|
||||
"no-console": ["warn", { "allow": ["warn", "error", "log"] }],
|
||||
"no-case-declarations": 0,
|
||||
|
||||
30
README.md
30
README.md
@ -8,11 +8,11 @@
|
||||
## 【必看】环境准备
|
||||
- **Node 版本: 16.0+**
|
||||
1. 需要准备两个 Terminal,分别启动服务端、前端页面。
|
||||
2. 开通 ASR、TTS、LLM、RTC 等服务,可通过 [无代码跑通实时对话式](https://console.volcengine.com/rtc/guide) 快速开通服务, 点击 **快速开始** 中的 **跑通 Demo** 进行服务开通。
|
||||
2. 开通 ASR、TTS、LLM、RTC 等服务,可参考 [开通服务](https://www.volcengine.com/docs/6348/1315561?s=g) 进行相关服务的授权与开通。
|
||||
3. **根据你自定义的
|
||||
RoomId、UserId 以及申请的 AppID、BusinessID(如有)、Token、ASR AppID、TTS AppID,修改 `src/config/config.ts` 文件中 `ConfigFactory` 中 `BaseConfig` 的配置信息**。
|
||||
4. 使用火山引擎控制台账号的 [AK、SK](https://console.volcengine.com/iam/keymanage?s=g)、[SessionToken](https://www.volcengine.com/docs/6348/1315561#sub?s=g)(临时token, 子账号才需要), 修改 `Server/app.js` 文件中的 `ACCOUNT_INFO`。
|
||||
5. 您需要在 [火山方舟-在线推理](https://console.volcengine.com/ark/region:ark+cn-beijing/endpoint?config=%7B%7D&s=g) 中创建接入点, 并将模型对应的接入点 ID 填入 `src/config/common.ts` 文件中的 `ARK_V3_MODEL_ID`, 否则无法正常启动智能体。
|
||||
4. 使用火山引擎控制台账号的 [AK、SK](https://console.volcengine.com/iam/keymanage?s=g), 修改 `Server/app.js` 文件中的 `ACCOUNT_INFO`。
|
||||
5. 若您使用的是官方模型, 需要在 [火山方舟-在线推理](https://console.volcengine.com/ark/region:ark+cn-beijing/endpoint?config=%7B%7D&s=g) 中创建接入点, 并将模型对应的接入点 ID 填入 `src/config/common.ts` 文件中的 `ARK_V3_MODEL_ID`, 否则无法正常启动智能体。
|
||||
6. 如果您已经自行完成了服务端的逻辑,可以不依赖 Demo 中的 Server,直接修改前端代码文件 `src/config/index.ts` 中的 `AIGC_PROXY_HOST` 请求域名和接口,并在 `src/app/api.ts` 中修改接口的参数配置 `APIS_CONFIG`。
|
||||
|
||||
## 快速开始
|
||||
@ -43,12 +43,12 @@ yarn dev
|
||||
### 常见问题
|
||||
| 问题 | 解决方案 |
|
||||
| :-- | :-- |
|
||||
| **启动智能体之后, 对话无反馈,或者一直停留在 "AI 准备中, 请稍侯"** | <li>可能因为控制台中相关权限没有正常授予,请参考[流程](https://www.volcengine.com/docs/6348/1315561?s=g)再次确认下是否完成相关操作。此问题的可能性较大,建议仔细对照是否已经将相应的权限开通。</li><li>参数传递可能有问题, 例如参数大小写、类型等问题,请再次确认下这类型问题是否存在。</li><li>相关资源可能未开通或者用量不足,请再次确认。</li><li>**请检查当前使用的模型 ID 等内容都是正确且可用的。**</li> |
|
||||
| `Server/app.js` 中的 `sessionToken` 是什么,该怎么填,为什么要填 | `sessionToken` 是火山引擎子账号发起 OpenAPI 请求时所必须携带的临时 Token,获取方式可参考 [此文章末尾](https://www.volcengine.com/docs/6348/1315561?s=g)。 |
|
||||
| **浏览器报了 `Uncaught (in promise) r: token_error` 错误** | 请检查您填在项目中的 RTC Token 是否合法,检测用于生成 Token 的 UserId、RoomId 是否与项目中填写的一致;或者 Token 可能过期, 可尝试重新生成下。 |
|
||||
| 如何使用第三方模型、Coze Bot | 点击页面上的 "修改 AI 设定" 进入配置页,可切换 官方模型/Coze/第三方模型,填写对应参数即可,相关代码对应 `src/components/AISettings/index.tsx` 文件。 |
|
||||
| **启动智能体之后, 对话无反馈,或者一直停留在 "AI 准备中, 请稍侯"** | <li>可能因为控制台中相关权限没有正常授予,请参考[流程](https://www.volcengine.com/docs/6348/1315561?s=g)再次确认下是否完成相关操作。此问题的可能性较大,建议仔细对照是否已经将相应的权限开通。</li><li>参数传递可能有问题, 例如参数大小写、类型等问题,请再次确认下这类型问题是否存在。</li><li>相关资源可能未开通或者用量不足/欠费,请再次确认。</li><li>**请检查当前使用的模型 ID 等内容都是正确且可用的。**</li> |
|
||||
| **浏览器报了 `Uncaught (in promise) r: token_error` 错误** | 请检查您填在项目中的 RTC Token 是否合法,检测用于生成 Token 的 UserId、RoomId 以及 Token 本身是否与项目中填写的一致;或者 Token 可能过期, 可尝试重新生成下。 |
|
||||
| **[StartVoiceChat]Failed(Reason: The task has been started. Please do not call the startup task interface repeatedly.)** 报错 | 由于目前设置的 RoomId、UserId 为固定值,重复调用 startAudioBot 会导致出错,只需先调用 stopAudioBot 后再重新 startAudioBot 即可。 |
|
||||
| 为什么我的麦克风正常、摄像头也正常,但是设备没有正常工作? | 可能是设备权限未授予,详情可参考 [Web 排查设备权限获取失败问题](https://www.volcengine.com/docs/6348/1356355?s=g)。 |
|
||||
| 接口调用时, 返回 "Invalid 'Authorization' header, Pls check your authorization header" 错误 | `Server/app.js` 中的 AK/SK/SessionToken 不正确 |
|
||||
| 接口调用时, 返回 "Invalid 'Authorization' header, Pls check your authorization header" 错误 | `Server/app.js` 中的 AK/SK 不正确 |
|
||||
| 什么是 RTC | **R**eal **T**ime **C**ommunication, RTC 的概念可参考[官网文档](https://www.volcengine.com/docs/6348/66812?s=g)。 |
|
||||
| 不清楚什么是主账号,什么是子账号 | 可以参考[官方概念](https://www.volcengine.com/docs/6257/64963?hyperlink_open_type=lark.open_in_browser&s=g) 。|
|
||||
|
||||
@ -61,7 +61,21 @@ yarn dev
|
||||
|
||||
## 更新日志
|
||||
|
||||
### [1.5.0] - [2025-03-31]
|
||||
### OpenAPI 更新
|
||||
参考 [OpenAPI 更新](https://www.volcengine.com/docs/6348/116363?s=g) 中与 实时对话式 AI 相关的更新内容。
|
||||
|
||||
### Demo 更新
|
||||
#### [1.6.0] - [2025-04-16]
|
||||
- 支持 Coze Bot
|
||||
- 更新部分注释和文档内容
|
||||
- 删除子账号的 SessionToken 配置, 子账号调用无须 SessionToken
|
||||
- 修复通话前修改内容,在通话后配置消失的问题
|
||||
|
||||
#### [1.5.1] - [2025-04-11]
|
||||
- 移除无用代码和依赖
|
||||
- 修复字幕逻辑
|
||||
|
||||
#### [1.5.0] - [2025-03-31]
|
||||
- 修复部分 UI 问题
|
||||
- 追加屏幕共享能力 (视觉模型可用,**读屏助手** 人设下可使用)
|
||||
- 修改字幕逻辑,避免字幕回调中标点符号、大小写不一致引起的字幕重复问题
|
||||
|
||||
@ -27,11 +27,6 @@ const ACCOUNT_INFO = {
|
||||
* @notes 必填, 在 https://console.volcengine.com/iam/keymanage/ 获取
|
||||
*/
|
||||
secretKey: 'Your SK',
|
||||
/**
|
||||
* @notes 非必填, 主账号无须传入, 子账号须传, 获取方式可参考
|
||||
* https://www.volcengine.com/docs/6348/1315561 中的 步骤 4-使用子账号调用智能体接口 一节
|
||||
*/
|
||||
// sessionToken: 'Your SessionToken',
|
||||
}
|
||||
|
||||
app.use(bodyParser());
|
||||
@ -67,9 +62,7 @@ app.use(async ctx => {
|
||||
/** 参考 https://www.volcengine.com/docs/6348/69828 可获取更多 OpenAPI 的信息 */
|
||||
const result = await fetch(`https://rtc.volcengineapi.com?Action=${Action}&Version=${Version}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...openApiRequestData.headers,
|
||||
},
|
||||
headers: openApiRequestData.headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const volcResponse = await result.json();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aigc",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
@ -91,6 +91,12 @@
|
||||
flex-direction: column;
|
||||
gap: 36px;
|
||||
|
||||
.ai-settings-radio {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
position: absolute;
|
||||
border-bottom: 12px solid white;
|
||||
@ -104,6 +110,7 @@
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: -16px;
|
||||
gap: 24px;
|
||||
|
||||
.ai-settings-wrapper {
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
* SPDX-license-identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
import { Button, Drawer, Input, Message } from '@arco-design/web-react';
|
||||
import { Button, Drawer, Input, Message, Radio, Tooltip } from '@arco-design/web-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { IconSwap } from '@arco-design/web-react/icon';
|
||||
import { IconExclamationCircle } from '@arco-design/web-react/icon';
|
||||
import { StreamIndex } from '@volcengine/rtc';
|
||||
import CheckIcon from '../CheckIcon';
|
||||
import Config, {
|
||||
@ -18,7 +18,7 @@ import Config, {
|
||||
Voice,
|
||||
Model,
|
||||
AI_MODEL,
|
||||
ModelSourceType,
|
||||
MODEL_MODE,
|
||||
VOICE_INFO_MAP,
|
||||
VOICE_TYPE,
|
||||
isVisionMode,
|
||||
@ -26,7 +26,7 @@ import Config, {
|
||||
import TitleCard from '../TitleCard';
|
||||
import CheckBoxSelector from '@/components/CheckBoxSelector';
|
||||
import RtcClient from '@/lib/RtcClient';
|
||||
import { clearHistoryMsg, updateAIConfig, updateScene } from '@/store/slices/room';
|
||||
import { clearHistoryMsg, updateAIConfig, updateModelMode, updateScene } from '@/store/slices/room';
|
||||
import { RootState } from '@/store';
|
||||
import utils from '@/utils/utils';
|
||||
import { useDeviceState } from '@/lib/useCommon';
|
||||
@ -42,6 +42,8 @@ export interface IAISettingsProps {
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
const SCENES = [
|
||||
SCENE.INTELLIGENT_ASSISTANT,
|
||||
SCENE.SCREEN_READER,
|
||||
@ -59,17 +61,19 @@ function AISettings({ open, onCancel, onOk }: IAISettingsProps) {
|
||||
useDeviceState();
|
||||
const room = useSelector((state: RootState) => state.room);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [use3Part, setUse3Part] = useState(false);
|
||||
const [modelMode, setModelMode] = useState<MODEL_MODE>(room.modelMode);
|
||||
const [scene, setScene] = useState(room.scene);
|
||||
const [data, setData] = useState({
|
||||
prompt: Prompt[scene],
|
||||
welcome: Welcome[scene],
|
||||
voice: Voice[scene],
|
||||
model: Model[scene],
|
||||
prompt: Config.Prompt || Prompt[scene],
|
||||
welcome: Config.WelcomeSpeech || Welcome[scene],
|
||||
voice: Config.VoiceType || Voice[scene],
|
||||
model: Config.Model || Model[scene],
|
||||
|
||||
Url: '',
|
||||
APIKey: '',
|
||||
customModelName: '',
|
||||
Url: Config.Url || '',
|
||||
APIKey: Config.APIKey || '',
|
||||
customModelName: (Config.Model || '') as string,
|
||||
|
||||
BotID: Config.BotID || '',
|
||||
});
|
||||
|
||||
const handleVoiceTypeChanged = (key: string) => {
|
||||
@ -90,35 +94,55 @@ function AISettings({ open, onCancel, onOk }: IAISettingsProps) {
|
||||
}));
|
||||
};
|
||||
|
||||
const handleUseThirdPart = () => {
|
||||
setUse3Part(!use3Part);
|
||||
Config.ModeSourceType = use3Part ? ModelSourceType.Custom : ModelSourceType.Available;
|
||||
const handleUseThirdPart = (val: MODEL_MODE) => {
|
||||
setModelMode(val);
|
||||
Config.ModeSourceType = val;
|
||||
};
|
||||
|
||||
const handleUpdateConfig = async () => {
|
||||
dispatch(updateScene({ scene }));
|
||||
if (use3Part) {
|
||||
if (!data.Url) {
|
||||
Message.error('请输入正确的第三方模型地址');
|
||||
return;
|
||||
}
|
||||
if (!data.Url.startsWith('http://') && !data.Url.startsWith('https://')) {
|
||||
Message.error('第三方模型请求地址格式不正确, 请以 http:// 或 https:// 为开头');
|
||||
return;
|
||||
}
|
||||
Config.Url = data.Url;
|
||||
Config.APIKey = data.APIKey;
|
||||
Config.ModeSourceType = ModelSourceType.Custom;
|
||||
} else {
|
||||
Config.Url = undefined;
|
||||
Config.APIKey = undefined;
|
||||
Config.ModeSourceType = ModelSourceType.Available;
|
||||
Config.ModeSourceType = modelMode;
|
||||
switch (modelMode) {
|
||||
case MODEL_MODE.ORIGINAL:
|
||||
Config.Url = undefined;
|
||||
Config.APIKey = undefined;
|
||||
break;
|
||||
case MODEL_MODE.COZE:
|
||||
if (!data.APIKey) {
|
||||
Message.error('访问令牌必填');
|
||||
return;
|
||||
}
|
||||
if (!data.BotID) {
|
||||
Message.error('智能体 ID 必填');
|
||||
return;
|
||||
}
|
||||
Config.APIKey = data.APIKey;
|
||||
Config.BotID = data.BotID;
|
||||
break;
|
||||
case MODEL_MODE.VENDOR:
|
||||
if (!data.Url) {
|
||||
Message.error('请输入正确的第三方模型地址');
|
||||
return;
|
||||
}
|
||||
if (!data.Url.startsWith('http://') && !data.Url.startsWith('https://')) {
|
||||
Message.error('第三方模型请求地址格式不正确, 请以 http:// 或 https:// 为开头');
|
||||
return;
|
||||
}
|
||||
Config.Url = data.Url;
|
||||
Config.APIKey = data.APIKey;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setLoading(true);
|
||||
Config.Model = use3Part ? (data.customModelName as AI_MODEL) : (data.model as AI_MODEL);
|
||||
Config.Model =
|
||||
modelMode === MODEL_MODE.VENDOR
|
||||
? (data.customModelName as AI_MODEL)
|
||||
: (data.model as AI_MODEL);
|
||||
Config.Prompt = data.prompt;
|
||||
Config.VoiceType = data.voice;
|
||||
Config.WelcomeSpeech = data.welcome;
|
||||
dispatch(updateModelMode(modelMode));
|
||||
dispatch(updateAIConfig(Config.aigcConfig));
|
||||
|
||||
if (isVisionMode(data.model)) {
|
||||
@ -218,32 +242,85 @@ function AISettings({ open, onCancel, onOk }: IAISettingsProps) {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<TitleCard title="Prompt">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.prompt}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
prompt: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入你需要的 Prompt 设定"
|
||||
/>
|
||||
</TitleCard>
|
||||
<TitleCard title="欢迎语">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.welcome}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
welcome: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入欢迎语"
|
||||
/>
|
||||
</TitleCard>
|
||||
<RadioGroup
|
||||
options={[
|
||||
{
|
||||
value: MODEL_MODE.ORIGINAL,
|
||||
label: '官方模型',
|
||||
},
|
||||
{
|
||||
value: MODEL_MODE.COZE,
|
||||
label: (
|
||||
<div className={styles['radio-text']}>
|
||||
<span style={{ marginRight: '4px' }}>Coze</span>
|
||||
<Tooltip
|
||||
content={
|
||||
<div>
|
||||
访问令牌可参考{' '}
|
||||
<a
|
||||
href="https://www.coze.cn/open/docs/developer_guides/pat"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{ color: 'gray' }}
|
||||
>
|
||||
添加个人访问令牌
|
||||
</a>{' '}
|
||||
获取。
|
||||
<br />
|
||||
智能体 ID 可参考{' '}
|
||||
<a
|
||||
href="https://www.coze.cn/open/docs/developer_guides/coze_api_overview#c5ac4993"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{ color: 'gray' }}
|
||||
>
|
||||
发送请求
|
||||
</a>{' '}
|
||||
获取。
|
||||
<br />
|
||||
请注意智能体发布时须勾选 API 调用能力,否则无法成功对话。
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconExclamationCircle />
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: MODEL_MODE.VENDOR,
|
||||
label: (
|
||||
<div className={styles['radio-text']}>
|
||||
<span style={{ marginRight: '4px' }}>第三方模型</span>
|
||||
<Tooltip
|
||||
content={
|
||||
<div>
|
||||
如第三方模型使用失败, 可前往{' '}
|
||||
<a
|
||||
href="https://www.volcengine.com/docs/6348/1399966"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{ color: 'gray' }}
|
||||
>
|
||||
第三方模型接口验证工具
|
||||
</a>{' '}
|
||||
下载工具定位原因。
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconExclamationCircle />
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
value={modelMode}
|
||||
size="mini"
|
||||
type="button"
|
||||
defaultValue="Beijing"
|
||||
className={styles['ai-settings-radio']}
|
||||
onChange={handleUseThirdPart}
|
||||
/>
|
||||
<div
|
||||
className={styles['ai-settings']}
|
||||
style={{
|
||||
@ -272,7 +349,29 @@ function AISettings({ open, onCancel, onOk }: IAISettingsProps) {
|
||||
</div>
|
||||
</TitleCard>
|
||||
<div className={styles['ai-settings-model']}>
|
||||
{use3Part ? (
|
||||
{modelMode === MODEL_MODE.ORIGINAL && (
|
||||
<TitleCard title="官方模型">
|
||||
<CheckBoxSelector
|
||||
label="模型选择"
|
||||
data={Object.keys(AI_MODEL).map((type) => ({
|
||||
key: AI_MODEL[type as keyof typeof AI_MODEL],
|
||||
label: type.replaceAll('_', ' '),
|
||||
icon: DoubaoModelSVG,
|
||||
}))}
|
||||
moreIcon={ModelChangeSVG}
|
||||
moreText="更换模型"
|
||||
placeHolder="请选择你需要的模型"
|
||||
onChange={(key) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
model: key as AI_MODEL,
|
||||
}));
|
||||
}}
|
||||
value={data.model}
|
||||
/>
|
||||
</TitleCard>
|
||||
)}
|
||||
{modelMode === MODEL_MODE.VENDOR && (
|
||||
<>
|
||||
<TitleCard required title="第三方模型地址">
|
||||
<Input.TextArea
|
||||
@ -314,34 +413,68 @@ function AISettings({ open, onCancel, onOk }: IAISettingsProps) {
|
||||
/>
|
||||
</TitleCard>
|
||||
</>
|
||||
) : (
|
||||
<TitleCard title="官方模型">
|
||||
<CheckBoxSelector
|
||||
label="模型选择"
|
||||
data={Object.keys(AI_MODEL).map((type) => ({
|
||||
key: AI_MODEL[type as keyof typeof AI_MODEL],
|
||||
label: type.replaceAll('_', ' '),
|
||||
icon: DoubaoModelSVG,
|
||||
}))}
|
||||
moreIcon={ModelChangeSVG}
|
||||
moreText="更换模型"
|
||||
placeHolder="请选择你需要的模型"
|
||||
onChange={(key) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
model: key as AI_MODEL,
|
||||
}));
|
||||
}}
|
||||
value={data.model}
|
||||
/>
|
||||
</TitleCard>
|
||||
)}
|
||||
|
||||
<Button size="mini" type="text" onClick={handleUseThirdPart}>
|
||||
{use3Part ? '使用官方模型' : '使用第三方模型'} <IconSwap />
|
||||
</Button>
|
||||
{modelMode === MODEL_MODE.COZE && (
|
||||
<>
|
||||
<TitleCard required title="请求地址">
|
||||
<Input.TextArea autoSize disabled value="https://api.coze.cn" />
|
||||
</TitleCard>
|
||||
<TitleCard required title="访问令牌">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.APIKey}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
APIKey: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入访问令牌"
|
||||
/>
|
||||
</TitleCard>
|
||||
<TitleCard required title="智能体 ID">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.BotID}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
BotID: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入智能体 ID"
|
||||
/>
|
||||
</TitleCard>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<TitleCard title="系统 Prompt">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.prompt}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
prompt: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入你需要的 Prompt 设定"
|
||||
/>
|
||||
</TitleCard>
|
||||
<TitleCard title="欢迎语">
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
value={data.welcome}
|
||||
onChange={(val) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
welcome: val,
|
||||
}));
|
||||
}}
|
||||
placeholder="请输入欢迎语"
|
||||
/>
|
||||
</TitleCard>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
@ -10,7 +10,7 @@ import AISettings from '../AISettings';
|
||||
import style from './index.module.less';
|
||||
import DouBaoAvatar from '@/assets/img/DoubaoAvatarGIF.webp';
|
||||
import { RootState } from '@/store';
|
||||
import { Name, VOICE_TYPE } from '@/config';
|
||||
import { MODEL_MODE, Name, VOICE_TYPE } from '@/config';
|
||||
|
||||
interface IAvatarCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
avatar?: string;
|
||||
@ -24,11 +24,16 @@ const ReversedVoiceType = Object.entries(VOICE_TYPE).reduce<Record<string, strin
|
||||
{}
|
||||
);
|
||||
|
||||
const SourceName = {
|
||||
[MODEL_MODE.VENDOR]: '第三方模型',
|
||||
[MODEL_MODE.COZE]: 'Coze',
|
||||
};
|
||||
|
||||
function AvatarCard(props: IAvatarCardProps) {
|
||||
const room = useSelector((state: RootState) => state.room);
|
||||
const { scene, aiConfig, modelMode } = room;
|
||||
const [open, setOpen] = useState(false);
|
||||
const scene = room.scene;
|
||||
const { LLMConfig, TTSConfig } = room.aiConfig.Config || {};
|
||||
const { LLMConfig, TTSConfig } = aiConfig.Config || {};
|
||||
const { avatar, className, ...rest } = props;
|
||||
const voice = TTSConfig.ProviderParams.audio.voice_type;
|
||||
|
||||
@ -51,7 +56,11 @@ function AvatarCard(props: IAvatarCardProps) {
|
||||
<div className={style['user-info']}>
|
||||
<div className={style.title}>{Name[scene]}</div>
|
||||
<div className={style.description}>声源来自 {ReversedVoiceType[voice || '']}</div>
|
||||
<div className={style.description}>模型 {LLMConfig.ModelName}</div>
|
||||
<div className={style.description}>
|
||||
{modelMode === MODEL_MODE.ORIGINAL
|
||||
? `模型 ${LLMConfig.ModelName}`
|
||||
: `模型来源 ${SourceName[modelMode]}`}
|
||||
</div>
|
||||
<AISettings open={open} onOk={handleCloseDrawer} onCancel={handleCloseDrawer} />
|
||||
<Button className={style.button} onClick={handleOpenDrawer}>
|
||||
<div className={style['button-text']}>修改 AI 设定</div>
|
||||
|
||||
@ -24,6 +24,12 @@ export enum CustomParamsType {
|
||||
LLM = 'LLM',
|
||||
}
|
||||
|
||||
export enum MODEL_MODE {
|
||||
ORIGINAL = 'original',
|
||||
VENDOR = 'vendor',
|
||||
COZE = 'coze',
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AI 音色可选值
|
||||
* @default 通用女声
|
||||
@ -328,4 +334,4 @@ export const Prompt = {
|
||||
[SCENE.CUSTOM]: '',
|
||||
};
|
||||
|
||||
export const isVisionMode = (model: AI_MODEL) => model.startsWith('Vision');
|
||||
export const isVisionMode = (model?: AI_MODEL) => model?.startsWith('Vision');
|
||||
|
||||
@ -7,13 +7,12 @@ import { StreamIndex } from '@volcengine/rtc';
|
||||
import {
|
||||
TTS_CLUSTER,
|
||||
ARK_V3_MODEL_ID,
|
||||
ModelSourceType,
|
||||
MODEL_MODE,
|
||||
SCENE,
|
||||
Prompt,
|
||||
Welcome,
|
||||
Model,
|
||||
Voice,
|
||||
// LLM_BOT_ID,
|
||||
AI_MODEL,
|
||||
AI_MODE_MAP,
|
||||
AI_MODEL_MODE,
|
||||
@ -98,7 +97,11 @@ export class ConfigFactory {
|
||||
*/
|
||||
WelcomeSpeech = Welcome[SCENE.INTELLIGENT_ASSISTANT];
|
||||
|
||||
ModeSourceType = ModelSourceType.Available;
|
||||
/**
|
||||
* @note 当前使用的模型来源, 具体可参考 MODEL_MODE 定义。
|
||||
* 通过 UI 修改, 无须手动配置。
|
||||
*/
|
||||
ModeSourceType = MODEL_MODE.ORIGINAL;
|
||||
|
||||
/**
|
||||
* @note 非必填, 第三方模型才需要使用, 用火山方舟模型时无需关注。
|
||||
@ -116,6 +119,11 @@ export class ConfigFactory {
|
||||
*/
|
||||
BotName = 'RobotMan_';
|
||||
|
||||
/**
|
||||
* @note Coze 智能体 ID,可通过 UI 配置,也可以在此直接定义。
|
||||
*/
|
||||
BotID = '';
|
||||
|
||||
/**
|
||||
* @brief 是否为打断模式
|
||||
*/
|
||||
@ -130,7 +138,6 @@ export class ConfigFactory {
|
||||
const params: Record<string, unknown> = {
|
||||
Mode: AI_MODE_MAP[this.Model || ''] || AI_MODEL_MODE.CUSTOM,
|
||||
EndPointId: ARK_V3_MODEL_ID[this.Model],
|
||||
// BotId: LLM_BOT_ID[this.Model],
|
||||
MaxTokens: 1024,
|
||||
Temperature: 0.1,
|
||||
TopP: 0.3,
|
||||
@ -139,7 +146,6 @@ export class ConfigFactory {
|
||||
ModelName: this.Model,
|
||||
ModelVersion: '1.0',
|
||||
WelcomeSpeech: this.WelcomeSpeech,
|
||||
ModeSourceType: this.ModeSourceType,
|
||||
APIKey: this.APIKey,
|
||||
Url: this.Url,
|
||||
Feature: JSON.stringify({ Http: true }),
|
||||
@ -154,6 +160,23 @@ export class ConfigFactory {
|
||||
},
|
||||
};
|
||||
}
|
||||
if (this.ModeSourceType === MODEL_MODE.COZE) {
|
||||
/**
|
||||
* @note Coze 智能体配置的相关参数, 可参考: https://www.volcengine.com/docs/6348/1404673?s=g#llmconfig%EF%BC%88coze%E5%B9%B3%E5%8F%B0%EF%BC%89
|
||||
*/
|
||||
return {
|
||||
Mode: 'CozeBot',
|
||||
CozeBotConfig: {
|
||||
Url: 'https://api.coze.cn',
|
||||
BotID: this.BotID,
|
||||
APIKey: this.APIKey,
|
||||
UserId: this.BaseConfig.UserId,
|
||||
HistoryLength: 10,
|
||||
Prefill: false,
|
||||
EnableConversation: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ import { ConfigFactory } from './config';
|
||||
export * from './common';
|
||||
|
||||
export const AIGC_PROXY_HOST = 'http://localhost:3001/proxyAIGCFetch';
|
||||
export const DEMO_VERSION = '1.4.0';
|
||||
|
||||
export const Config = ConfigFactory;
|
||||
export default new ConfigFactory();
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
NetworkQuality,
|
||||
RemoteAudioStats,
|
||||
} from '@volcengine/rtc';
|
||||
import config, { SCENE } from '@/config';
|
||||
import config, { MODEL_MODE, SCENE } from '@/config';
|
||||
|
||||
export interface IUser {
|
||||
username?: string;
|
||||
@ -71,6 +71,10 @@ export interface RoomState {
|
||||
* @brief AI 基础配置
|
||||
*/
|
||||
aiConfig: ReturnType<any>;
|
||||
/**
|
||||
* @brief 当前模型的类型
|
||||
*/
|
||||
modelMode: MODEL_MODE;
|
||||
/**
|
||||
* @brief 网络质量
|
||||
*/
|
||||
@ -116,6 +120,7 @@ const initialState: RoomState = {
|
||||
networkQuality: NetworkQuality.UNKNOWN,
|
||||
|
||||
aiConfig: config.aigcConfig,
|
||||
modelMode: MODEL_MODE.ORIGINAL,
|
||||
|
||||
msgHistory: [],
|
||||
currentConversation: {},
|
||||
@ -225,6 +230,9 @@ export const roomSlice = createSlice({
|
||||
updateAIConfig: (state, { payload }) => {
|
||||
state.aiConfig = Object.assign(state.aiConfig, payload);
|
||||
},
|
||||
updateModelMode: (state, { payload }) => {
|
||||
state.modelMode = payload;
|
||||
},
|
||||
clearHistoryMsg: (state) => {
|
||||
state.msgHistory = [];
|
||||
},
|
||||
@ -307,6 +315,7 @@ export const {
|
||||
updateAITalkState,
|
||||
updateAIThinkState,
|
||||
updateAIConfig,
|
||||
updateModelMode,
|
||||
setHistoryMsg,
|
||||
clearHistoryMsg,
|
||||
clearCurrentMsg,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user