mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 09:33:55 +08:00
Merge branch 'main' into update-web-style
This commit is contained in:
@@ -151,6 +151,11 @@ public interface Constant {
|
|||||||
*/
|
*/
|
||||||
String MEMORY_NO_MEM = "Memory_nomem";
|
String MEMORY_NO_MEM = "Memory_nomem";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅上报聊天记录(不总结记忆)
|
||||||
|
*/
|
||||||
|
String MEMORY_MEM_REPORT_ONLY = "Memory_mem_report_only";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 火山引擎双声道语音克隆
|
* 火山引擎双声道语音克隆
|
||||||
*/
|
*/
|
||||||
|
|||||||
+17
-9
@@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import xiaozhi.common.constant.Constant;
|
||||||
import xiaozhi.modules.agent.dto.AgentChatHistoryDTO;
|
import xiaozhi.modules.agent.dto.AgentChatHistoryDTO;
|
||||||
import xiaozhi.modules.agent.dto.AgentChatSummaryDTO;
|
import xiaozhi.modules.agent.dto.AgentChatSummaryDTO;
|
||||||
import xiaozhi.modules.agent.dto.AgentMemoryDTO;
|
import xiaozhi.modules.agent.dto.AgentMemoryDTO;
|
||||||
@@ -90,21 +91,28 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
|||||||
@Override
|
@Override
|
||||||
public boolean generateAndSaveChatSummary(String sessionId) {
|
public boolean generateAndSaveChatSummary(String sessionId) {
|
||||||
try {
|
try {
|
||||||
// 1. 生成总结
|
// 1. 获取设备信息(通过会话关联的设备)
|
||||||
AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId);
|
|
||||||
if (!summaryDTO.isSuccess()) {
|
|
||||||
log.info("生成总结失败: {}", summaryDTO.getErrorMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 获取设备信息(通过会话关联的设备)
|
|
||||||
DeviceEntity device = getDeviceBySessionId(sessionId);
|
DeviceEntity device = getDeviceBySessionId(sessionId);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
log.info("未找到与会话 {} 关联的设备", sessionId);
|
log.info("未找到与会话 {} 关联的设备", sessionId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 更新智能体记忆
|
// 2. 检查记忆模型类型,如果是仅上报聊天记录模式则跳过总结
|
||||||
|
String memModelId = agentService.getAgentById(device.getAgentId()).getMemModelId();
|
||||||
|
if (memModelId != null && memModelId.equals(Constant.MEMORY_MEM_REPORT_ONLY)) {
|
||||||
|
log.info("会话 {} 使用仅上报聊天记录模式,跳过记忆总结", sessionId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 生成总结
|
||||||
|
AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId);
|
||||||
|
if (!summaryDTO.isSuccess()) {
|
||||||
|
log.info("生成总结失败: {}", summaryDTO.getErrorMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 更新智能体记忆
|
||||||
AgentMemoryDTO memoryDTO = new AgentMemoryDTO();
|
AgentMemoryDTO memoryDTO = new AgentMemoryDTO();
|
||||||
memoryDTO.setSummaryMemory(summaryDTO.getSummary());
|
memoryDTO.setSummaryMemory(summaryDTO.getSummary());
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -57,7 +57,8 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
|||||||
.eq("model_type", modelType)
|
.eq("model_type", modelType)
|
||||||
.eq("is_enabled", 1)
|
.eq("is_enabled", 1)
|
||||||
.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
|
.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
|
||||||
.select("id", "model_name"));
|
.select("id", "model_name")
|
||||||
|
.orderByAsc("sort"));
|
||||||
return ConvertUtils.sourceToTarget(entities, ModelBasicInfoDTO.class);
|
return ConvertUtils.sourceToTarget(entities, ModelBasicInfoDTO.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -95,6 +95,7 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
|
|||||||
|
|
||||||
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
|
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
|
||||||
|
queryWrapper.orderByAsc("sort");
|
||||||
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
|
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
|
||||||
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
|
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
|
||||||
}
|
}
|
||||||
@@ -147,7 +148,8 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
|
|||||||
UserDetail user = SecurityUser.getUser();
|
UserDetail user = SecurityUser.getUser();
|
||||||
modelProviderDTO.setUpdater(user.getId());
|
modelProviderDTO.setUpdater(user.getId());
|
||||||
modelProviderDTO.setUpdateDate(new Date());
|
modelProviderDTO.setUpdateDate(new Date());
|
||||||
if (modelProviderDao.updateById(ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class)) == 0) {
|
if (modelProviderDao
|
||||||
|
.updateById(ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class)) == 0) {
|
||||||
throw new RenException(ErrorCode.UPDATE_DATA_FAILED);
|
throw new RenException(ErrorCode.UPDATE_DATA_FAILED);
|
||||||
}
|
}
|
||||||
return ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderDTO.class);
|
return ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderDTO.class);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- 新增仅上报聊天记录记忆模型供应器
|
||||||
|
|
||||||
|
delete from `ai_model_provider` where `id` = 'SYSTEM_Memory_mem_report_only';
|
||||||
|
delete from `ai_model_config` where `id` = 'Memory_mem_report_only';
|
||||||
|
|
||||||
|
INSERT INTO `ai_model_provider` VALUES ('SYSTEM_Memory_mem_report_only', 'Memory', 'mem_report_only', '仅上报聊天记录', '[]', 4, 1, NOW(), 1, NOW());
|
||||||
|
INSERT INTO `ai_model_config` VALUES ('Memory_mem_report_only', 'Memory', 'mem_report_only', '仅上报聊天记录', 0, 1, '{"type": "mem_report_only"}', NULL, '仅上报聊天记录,不总结记忆', 3, NULL, NULL, NULL, NULL);
|
||||||
@@ -571,3 +571,10 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202603111131.sql
|
path: classpath:db/changelog/202603111131.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202603231037
|
||||||
|
author: rainv123
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202603231037.sql
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export default {
|
|||||||
'agent.chatHistory': 'Chat-Verlauf',
|
'agent.chatHistory': 'Chat-Verlauf',
|
||||||
'agent.voiceprintManagement': 'Stimmabdruckverwaltung',
|
'agent.voiceprintManagement': 'Stimmabdruckverwaltung',
|
||||||
'agent.editTitle': 'Agent bearbeiten',
|
'agent.editTitle': 'Agent bearbeiten',
|
||||||
'agent.toolsTitle': 'Funktionen bearbeiten',
|
'agent.toolsTitle': 'Bearbeiten',
|
||||||
'agent.voiceActivityDetection': 'Sprachaktivitätserkennung',
|
'agent.voiceActivityDetection': 'Sprachaktivitätserkennung',
|
||||||
'agent.speechRecognition': 'Spracherkennung',
|
'agent.speechRecognition': 'Spracherkennung',
|
||||||
'agent.largeLanguageModel': 'Großes Sprachmodell',
|
'agent.largeLanguageModel': 'Großes Sprachmodell',
|
||||||
@@ -116,7 +116,7 @@ export default {
|
|||||||
'agent.tts': 'Text-zu-Sprache',
|
'agent.tts': 'Text-zu-Sprache',
|
||||||
'agent.voiceprint': 'Agenten-Stimme',
|
'agent.voiceprint': 'Agenten-Stimme',
|
||||||
'agent.plugins': 'Plugins',
|
'agent.plugins': 'Plugins',
|
||||||
'agent.editFunctions': 'Funktionen bearbeiten',
|
'agent.editFunctions': 'Bearbeiten',
|
||||||
'agent.historyMemory': 'Verlaufsspeicher',
|
'agent.historyMemory': 'Verlaufsspeicher',
|
||||||
'agent.memoryContent': 'Speicherinhalt',
|
'agent.memoryContent': 'Speicherinhalt',
|
||||||
'agent.saving': 'Wird gespeichert...',
|
'agent.saving': 'Wird gespeichert...',
|
||||||
@@ -371,7 +371,7 @@ export default {
|
|||||||
'agent.tools.mcpAccessPoint': 'MCP-Zugangspunkt',
|
'agent.tools.mcpAccessPoint': 'MCP-Zugangspunkt',
|
||||||
'agent.tools.copy': 'Kopieren',
|
'agent.tools.copy': 'Kopieren',
|
||||||
'agent.tools.noTools': 'Keine Werkzeuge verfügbar',
|
'agent.tools.noTools': 'Keine Werkzeuge verfügbar',
|
||||||
'agent.tools.parameterConfig': 'Parameterkonfiguration',
|
'agent.tools.parameterConfig': 'Konfig',
|
||||||
'agent.tools.noParamsNeeded': 'Keine Parameter benötigt',
|
'agent.tools.noParamsNeeded': 'Keine Parameter benötigt',
|
||||||
'agent.tools.pleaseInput': 'Bitte eingeben',
|
'agent.tools.pleaseInput': 'Bitte eingeben',
|
||||||
'agent.tools.inputOneItemPerLine': 'Ein Element pro Zeile eingeben',
|
'agent.tools.inputOneItemPerLine': 'Ein Element pro Zeile eingeben',
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ export default {
|
|||||||
'agent.tools.mcpAccessPoint': 'MCP Access Point',
|
'agent.tools.mcpAccessPoint': 'MCP Access Point',
|
||||||
'agent.tools.copy': 'Copy',
|
'agent.tools.copy': 'Copy',
|
||||||
'agent.tools.noTools': 'No tools available',
|
'agent.tools.noTools': 'No tools available',
|
||||||
'agent.tools.parameterConfig': 'Parameter Configuration',
|
'agent.tools.parameterConfig': 'Param Config',
|
||||||
'agent.tools.noParamsNeeded': 'No parameters needed',
|
'agent.tools.noParamsNeeded': 'No parameters needed',
|
||||||
'agent.tools.pleaseInput': 'Please input',
|
'agent.tools.pleaseInput': 'Please input',
|
||||||
'agent.tools.inputOneItemPerLine': 'Input one item per line',
|
'agent.tools.inputOneItemPerLine': 'Input one item per line',
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ export default {
|
|||||||
'agent.tools.mcpAccessPoint': 'Ponto de Acesso MCP',
|
'agent.tools.mcpAccessPoint': 'Ponto de Acesso MCP',
|
||||||
'agent.tools.copy': 'Copiar',
|
'agent.tools.copy': 'Copiar',
|
||||||
'agent.tools.noTools': 'Nenhuma ferramenta disponível',
|
'agent.tools.noTools': 'Nenhuma ferramenta disponível',
|
||||||
'agent.tools.parameterConfig': 'Configuração de Parâmetros',
|
'agent.tools.parameterConfig': 'Configuração',
|
||||||
'agent.tools.noParamsNeeded': 'Nenhum parâmetro necessário',
|
'agent.tools.noParamsNeeded': 'Nenhum parâmetro necessário',
|
||||||
'agent.tools.pleaseInput': 'Por favor, insira',
|
'agent.tools.pleaseInput': 'Por favor, insira',
|
||||||
'agent.tools.inputOneItemPerLine': 'Insira um item por linha',
|
'agent.tools.inputOneItemPerLine': 'Insira um item por linha',
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ export default {
|
|||||||
'agent.tools.mcpAccessPoint': 'Điểm truy cập MCP',
|
'agent.tools.mcpAccessPoint': 'Điểm truy cập MCP',
|
||||||
'agent.tools.copy': 'Sao chép',
|
'agent.tools.copy': 'Sao chép',
|
||||||
'agent.tools.noTools': 'Không có công cụ nào',
|
'agent.tools.noTools': 'Không có công cụ nào',
|
||||||
'agent.tools.parameterConfig': 'Cấu hình tham số',
|
'agent.tools.parameterConfig': 'Cấu hình',
|
||||||
'agent.tools.noParamsNeeded': 'Không cần tham số',
|
'agent.tools.noParamsNeeded': 'Không cần tham số',
|
||||||
'agent.tools.pleaseInput': 'Vui lòng nhập',
|
'agent.tools.pleaseInput': 'Vui lòng nhập',
|
||||||
'agent.tools.inputOneItemPerLine': 'Nhập một mục mỗi dòng',
|
'agent.tools.inputOneItemPerLine': 'Nhập một mục mỗi dòng',
|
||||||
|
|||||||
@@ -1006,6 +1006,7 @@ onMounted(async () => {
|
|||||||
<wd-action-sheet
|
<wd-action-sheet
|
||||||
v-model="pickerShow.tts"
|
v-model="pickerShow.tts"
|
||||||
:actions="modelOptions.TTS && modelOptions.TTS.map(item => ({ name: item.modelName, value: item.id }))"
|
:actions="modelOptions.TTS && modelOptions.TTS.map(item => ({ name: item.modelName, value: item.id }))"
|
||||||
|
class="custom-sheet-tts"
|
||||||
@close="onPickerCancel('tts')"
|
@close="onPickerCancel('tts')"
|
||||||
@select="({ item }) => onPickerConfirm('tts', item.value, item.name)"
|
@select="({ item }) => onPickerConfirm('tts', item.value, item.name)"
|
||||||
/>
|
/>
|
||||||
@@ -1059,4 +1060,13 @@ onMounted(async () => {
|
|||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
::v-deep .custom-sheet-tts {
|
||||||
|
.wd-action-sheet {
|
||||||
|
padding: 8px 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.wd-action-sheet__actions {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ onMounted(async () => {
|
|||||||
v-if="notSelectedList.length === 0"
|
v-if="notSelectedList.length === 0"
|
||||||
class="h-[400rpx] flex items-center justify-center"
|
class="h-[400rpx] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<wd-status-tip image="content" tip="{{ t('agent.tools.noMorePlugins') }}" />
|
<wd-status-tip image="content" :tip="t('agent.tools.noMorePlugins')" />
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="p-[20rpx] space-y-[20rpx]">
|
<view v-else class="p-[20rpx] space-y-[20rpx]">
|
||||||
<view
|
<view
|
||||||
@@ -347,7 +347,7 @@ onMounted(async () => {
|
|||||||
v-if="selectedList.length === 0"
|
v-if="selectedList.length === 0"
|
||||||
class="h-[400rpx] flex items-center justify-center"
|
class="h-[400rpx] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<wd-status-tip image="content" tip="{{ t('agent.tools.pleaseSelectPlugin') }}" />
|
<wd-status-tip image="content" :tip="t('agent.tools.pleaseSelectPlugin')" />
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="p-[20rpx] space-y-[20rpx]">
|
<view v-else class="p-[20rpx] space-y-[20rpx]">
|
||||||
<view
|
<view
|
||||||
@@ -445,7 +445,7 @@ onMounted(async () => {
|
|||||||
<!-- 参数编辑弹窗 -->
|
<!-- 参数编辑弹窗 -->
|
||||||
<wd-action-sheet
|
<wd-action-sheet
|
||||||
v-model="showParamDialog"
|
v-model="showParamDialog"
|
||||||
:title="`${t('agent.tools.paramConfiguration')} - ${currentFunction?.name || ''}`"
|
:title="`${t('agent.tools.parameterConfig')} - ${currentFunction?.name || ''}`"
|
||||||
custom-header-class="h-[75vh]"
|
custom-header-class="h-[75vh]"
|
||||||
@close="closeParamEdit"
|
@close="closeParamEdit"
|
||||||
>
|
>
|
||||||
@@ -586,3 +586,9 @@ onMounted(async () => {
|
|||||||
</wd-action-sheet>
|
</wd-action-sheet>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
::v-deep .wd-action-sheet__header {
|
||||||
|
padding-right: 30rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { computed, onMounted, ref } from 'vue'
|
|||||||
import { login } from '@/api/auth'
|
import { login } from '@/api/auth'
|
||||||
// 导入国际化相关功能
|
// 导入国际化相关功能
|
||||||
import { changeLanguage, getCurrentLanguage, getSupportedLanguages, initI18n, t } from '@/i18n'
|
import { changeLanguage, getCurrentLanguage, getSupportedLanguages, initI18n, t } from '@/i18n'
|
||||||
import { useConfigStore } from '@/store'
|
import { useConfigStore, useUserStore } from '@/store'
|
||||||
// 导入SM2加密工具
|
// 导入SM2加密工具
|
||||||
import { getEnvBaseUrl, sm2Encrypt } from '@/utils'
|
import { getEnvBaseUrl, sm2Encrypt } from '@/utils'
|
||||||
import { toast } from '@/utils/toast'
|
import { toast } from '@/utils/toast'
|
||||||
@@ -61,6 +61,7 @@ const loginType = ref<'username' | 'mobile'>('username')
|
|||||||
|
|
||||||
// 获取配置store
|
// 获取配置store
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 区号选择相关
|
// 区号选择相关
|
||||||
const showAreaCodeSheet = ref(false)
|
const showAreaCodeSheet = ref(false)
|
||||||
@@ -227,6 +228,7 @@ async function handleLogin() {
|
|||||||
const response = await login(loginData)
|
const response = await login(loginData)
|
||||||
// 存储token
|
// 存储token
|
||||||
uni.setStorageSync('token', JSON.stringify(response))
|
uni.setStorageSync('token', JSON.stringify(response))
|
||||||
|
await userStore.getUserInfo()
|
||||||
|
|
||||||
toast.success(t('message.loginSuccess'))
|
toast.success(t('message.loginSuccess'))
|
||||||
|
|
||||||
@@ -581,7 +583,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
padding: 20rpx 16rpx;
|
padding: 20rpx 16rpx;
|
||||||
border: 2rpx solid #e9ecef;
|
border: 2rpx solid #e9ecef;
|
||||||
|
|||||||
@@ -460,8 +460,11 @@ defineExpose({
|
|||||||
<view class="p-[32rpx]">
|
<view class="p-[32rpx]">
|
||||||
<!-- 声纹向量选择 -->
|
<!-- 声纹向量选择 -->
|
||||||
<view class="mb-[32rpx]">
|
<view class="mb-[32rpx]">
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-red font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.voiceVector') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.voiceVector') }}
|
||||||
</text>
|
</text>
|
||||||
<view
|
<view
|
||||||
class="flex cursor-pointer items-center justify-between border-[1rpx] border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]"
|
class="flex cursor-pointer items-center justify-between border-[1rpx] border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]"
|
||||||
@@ -479,8 +482,11 @@ defineExpose({
|
|||||||
|
|
||||||
<!-- 姓名 -->
|
<!-- 姓名 -->
|
||||||
<view class="mb-[32rpx]">
|
<view class="mb-[32rpx]">
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-red font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.name') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.name') }}
|
||||||
</text>
|
</text>
|
||||||
<input
|
<input
|
||||||
v-model="addForm.sourceName"
|
v-model="addForm.sourceName"
|
||||||
@@ -491,8 +497,11 @@ defineExpose({
|
|||||||
|
|
||||||
<!-- 描述 -->
|
<!-- 描述 -->
|
||||||
<view>
|
<view>
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-red font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.description') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.description') }}
|
||||||
</text>
|
</text>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="addForm.introduce" :maxlength="100" :placeholder="t('voiceprint.pleaseInputDescription')"
|
v-model="addForm.introduce" :maxlength="100" :placeholder="t('voiceprint.pleaseInputDescription')"
|
||||||
@@ -521,7 +530,7 @@ defineExpose({
|
|||||||
safe-area-inset-bottom
|
safe-area-inset-bottom
|
||||||
>
|
>
|
||||||
<view>
|
<view>
|
||||||
<view class="w-full flex items-center justify-between border-b-[2rpx] border-[#eeeeee] p-[32rpx_32rpx_24rpx]">
|
<view class="box-border w-full flex items-center justify-between border-b-[2rpx] border-[#eeeeee] p-[32rpx_32rpx_24rpx]">
|
||||||
<text class="w-full text-center text-[32rpx] text-[#232338] font-semibold">
|
<text class="w-full text-center text-[32rpx] text-[#232338] font-semibold">
|
||||||
{{ t('voiceprint.editSpeaker') }}
|
{{ t('voiceprint.editSpeaker') }}
|
||||||
</text>
|
</text>
|
||||||
@@ -531,7 +540,10 @@ defineExpose({
|
|||||||
<!-- 声纹向量选择 -->
|
<!-- 声纹向量选择 -->
|
||||||
<view class="mb-[32rpx]">
|
<view class="mb-[32rpx]">
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.voiceVector') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.voiceVector') }}
|
||||||
</text>
|
</text>
|
||||||
<view
|
<view
|
||||||
class="flex cursor-pointer items-center justify-between border-[1rpx] border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]"
|
class="flex cursor-pointer items-center justify-between border-[1rpx] border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]"
|
||||||
@@ -550,7 +562,10 @@ defineExpose({
|
|||||||
<!-- 姓名 -->
|
<!-- 姓名 -->
|
||||||
<view class="mb-[32rpx]">
|
<view class="mb-[32rpx]">
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.name') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.name') }}
|
||||||
</text>
|
</text>
|
||||||
<input
|
<input
|
||||||
v-model="editForm.sourceName"
|
v-model="editForm.sourceName"
|
||||||
@@ -562,7 +577,10 @@ defineExpose({
|
|||||||
<!-- 描述 -->
|
<!-- 描述 -->
|
||||||
<view>
|
<view>
|
||||||
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
<text class="mb-[16rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||||
* {{ t('voiceprint.description') }}
|
<text class="text-red">
|
||||||
|
*
|
||||||
|
</text>
|
||||||
|
{{ t('voiceprint.description') }}
|
||||||
</text>
|
</text>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="editForm.introduce" :maxlength="100" :placeholder="t('voiceprint.pleaseInputDescription')"
|
v-model="editForm.introduce" :maxlength="100" :placeholder="t('voiceprint.pleaseInputDescription')"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const userInfoState: UserInfo & { avatar?: string, token?: string } = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore(
|
export const useUserStore = defineStore(
|
||||||
'user',
|
'userInfo',
|
||||||
() => {
|
() => {
|
||||||
// 定义用户信息
|
// 定义用户信息
|
||||||
const userInfo = ref<UserInfo & { avatar?: string, token?: string }>({ ...userInfoState })
|
const userInfo = ref<UserInfo & { avatar?: string, token?: string }>({ ...userInfoState })
|
||||||
@@ -51,16 +51,8 @@ export const useUserStore = defineStore(
|
|||||||
*/
|
*/
|
||||||
const getUserInfo = async () => {
|
const getUserInfo = async () => {
|
||||||
const userData = await _getUserInfo()
|
const userData = await _getUserInfo()
|
||||||
const authInfo = JSON.parse(uni.getStorageSync('token') || '{}')
|
setUserInfo(userData)
|
||||||
const userInfoWithExtras = {
|
return userData
|
||||||
...userData,
|
|
||||||
avatar: userInfoState.avatar,
|
|
||||||
token: authInfo.token || '',
|
|
||||||
}
|
|
||||||
setUserInfo(userInfoWithExtras)
|
|
||||||
uni.setStorageSync('userInfo', userInfoWithExtras)
|
|
||||||
// TODO 这里可以增加获取用户路由的方法 根据用户的角色动态生成路由
|
|
||||||
return userInfoWithExtras
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 退出登录 并 删除用户信息
|
* 退出登录 并 删除用户信息
|
||||||
@@ -79,6 +71,12 @@ export const useUserStore = defineStore(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
persist: true,
|
persist: {
|
||||||
|
key: 'userInfo',
|
||||||
|
serializer: {
|
||||||
|
serialize: state => JSON.stringify(state.userInfo),
|
||||||
|
deserialize: value => ({ userInfo: JSON.parse(value) }),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -751,8 +751,8 @@ class ConnectionHandler:
|
|||||||
memory_type = self.config["Memory"][self.config["selected_module"]["Memory"]][
|
memory_type = self.config["Memory"][self.config["selected_module"]["Memory"]][
|
||||||
"type"
|
"type"
|
||||||
]
|
]
|
||||||
# 如果使用 nomen,直接返回
|
# 如果使用 nomen 或 mem_report_only,直接返回
|
||||||
if memory_type == "nomem":
|
if memory_type == "nomem" or memory_type == "mem_report_only":
|
||||||
return
|
return
|
||||||
# 使用 mem_local_short 模式
|
# 使用 mem_local_short 模式
|
||||||
elif memory_type == "mem_local_short":
|
elif memory_type == "mem_local_short":
|
||||||
|
|||||||
@@ -280,6 +280,8 @@ async def send_tts_message(conn: "ConnectionHandler", state, text=None):
|
|||||||
await sendAudio(conn, audios)
|
await sendAudio(conn, audios)
|
||||||
# 等待所有音频包发送完成
|
# 等待所有音频包发送完成
|
||||||
await _wait_for_audio_completion(conn)
|
await _wait_for_audio_completion(conn)
|
||||||
|
# 停止音频发送循环
|
||||||
|
conn.audio_rate_controller.stop_sending()
|
||||||
# 清除服务端讲话状态
|
# 清除服务端讲话状态
|
||||||
conn.clearSpeakStatus()
|
conn.clearSpeakStatus()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
"""
|
||||||
|
仅上报聊天记录,不进行记忆总结
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ..base import MemoryProviderBase, logger
|
||||||
|
|
||||||
|
TAG = __name__
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryProvider(MemoryProviderBase):
|
||||||
|
def __init__(self, config, summary_memory=None):
|
||||||
|
super().__init__(config)
|
||||||
|
|
||||||
|
async def save_memory(self, msgs, session_id=None):
|
||||||
|
logger.bind(tag=TAG).debug("mem_report_only mode: No memory saving or summarization is performed.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def query_memory(self, query: str) -> str:
|
||||||
|
logger.bind(tag=TAG).debug("mem_report_only mode: No memory query is performed.")
|
||||||
|
return ""
|
||||||
@@ -43,6 +43,14 @@ class AudioRateController:
|
|||||||
|
|
||||||
def add_audio(self, opus_packet):
|
def add_audio(self, opus_packet):
|
||||||
"""添加音频包到队列"""
|
"""添加音频包到队列"""
|
||||||
|
# 如果队列之前为空,需要调整时间戳以保持播放时间连续
|
||||||
|
# 这样工具调用等待期间,新加入的音频不会提前播放
|
||||||
|
if len(self.queue) == 0 and self.play_position > 0:
|
||||||
|
self.start_timestamp = time.monotonic() - (self.play_position / 1000)
|
||||||
|
self.logger.bind(tag=TAG).debug(
|
||||||
|
f"队列从空恢复,重置时间戳,当前播放位置: {self.play_position}ms"
|
||||||
|
)
|
||||||
|
|
||||||
self.queue.append(("audio", opus_packet))
|
self.queue.append(("audio", opus_packet))
|
||||||
# 相关事件处理
|
# 相关事件处理
|
||||||
self.queue_empty_event.clear()
|
self.queue_empty_event.clear()
|
||||||
@@ -55,6 +63,12 @@ class AudioRateController:
|
|||||||
Args:
|
Args:
|
||||||
message_callback: 消息发送回调函数 async def()
|
message_callback: 消息发送回调函数 async def()
|
||||||
"""
|
"""
|
||||||
|
if len(self.queue) == 0 and self.play_position > 0:
|
||||||
|
self.start_timestamp = time.monotonic() - (self.play_position / 1000)
|
||||||
|
self.logger.bind(tag=TAG).debug(
|
||||||
|
f"队列从空恢复,重置时间戳,当前播放位置: {self.play_position}ms"
|
||||||
|
)
|
||||||
|
|
||||||
self.queue.append(("message", message_callback))
|
self.queue.append(("message", message_callback))
|
||||||
# 相关事件处理
|
# 相关事件处理
|
||||||
self.queue_empty_event.clear()
|
self.queue_empty_event.clear()
|
||||||
|
|||||||
Reference in New Issue
Block a user