mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 17:43:55 +08:00
Merge pull request #1673 from goxofy/main
update: newsnow 插件支持前端配置新闻源 && fix issues/1658
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
# get_news_from_newsnow 插件新闻源配置指南
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`get_news_from_newsnow` 插件现在支持通过Web管理界面动态配置新闻源,不再需要修改代码。用户可以在智控台中为每个智能体配置不同的新闻源。
|
||||||
|
|
||||||
|
## 配置方式
|
||||||
|
|
||||||
|
### 1. 通过Web管理界面配置(推荐)
|
||||||
|
|
||||||
|
1. 登录智控台
|
||||||
|
2. 进入"角色配置"页面
|
||||||
|
3. 选择要配置的智能体
|
||||||
|
4. 点击"编辑功能"按钮
|
||||||
|
5. 在右侧参数配置区域找到"newsnow新闻聚合"插件
|
||||||
|
6. 在"新闻源配置"字段中输入JSON格式的新闻源配置
|
||||||
|
|
||||||
|
### 2. 配置文件方式
|
||||||
|
|
||||||
|
在 `config.yaml` 中配置:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
plugins:
|
||||||
|
get_news_from_newsnow:
|
||||||
|
url: "https://newsnow.busiyi.world/api/s?id="
|
||||||
|
news_sources:
|
||||||
|
thepaper: "澎湃新闻"
|
||||||
|
baidu: "百度热搜"
|
||||||
|
cls-depth: "财联社"
|
||||||
|
# 可以添加更多新闻源
|
||||||
|
weibo: "微博头条"
|
||||||
|
douyin: "抖音热搜"
|
||||||
|
solidot: "奇客Solidot"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 新闻源配置格式
|
||||||
|
|
||||||
|
新闻源配置使用JSON格式,格式为:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"source_id": "显示名称",
|
||||||
|
"source_id2": "显示名称2"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 配置示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"thepaper": "澎湃新闻",
|
||||||
|
"baidu": "百度热搜",
|
||||||
|
"cls-depth": "财联社",
|
||||||
|
"weibo": "微博头条",
|
||||||
|
"douyin": "抖音热搜",
|
||||||
|
"solidot": "奇客Solidot"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 默认配置
|
||||||
|
|
||||||
|
如果未配置新闻源,插件将使用以下默认配置:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"thepaper": "澎湃新闻",
|
||||||
|
"baidu": "百度热搜",
|
||||||
|
"cls-depth": "财联社"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
1. **配置新闻源**:在Web界面或配置文件中设置新闻源
|
||||||
|
2. **调用插件**:用户可以说"播报新闻"或"获取新闻"
|
||||||
|
3. **指定新闻源**:用户可以说"播报澎湃新闻"或"获取百度热搜"
|
||||||
|
4. **获取详情**:用户可以说"详细介绍这条新闻"
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 新闻源的 `source_id` 必须与API接口支持的ID一致
|
||||||
|
2. 配置更改后需要重启服务或重新加载配置
|
||||||
|
3. 如果配置的新闻源无效,插件会自动使用默认新闻源
|
||||||
|
4. JSON格式必须正确,否则会使用默认配置
|
||||||
+12
@@ -19,6 +19,8 @@ import xiaozhi.modules.agent.service.AgentChatAudioService;
|
|||||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||||
import xiaozhi.modules.agent.service.AgentService;
|
import xiaozhi.modules.agent.service.AgentService;
|
||||||
import xiaozhi.modules.agent.service.biz.AgentChatHistoryBizService;
|
import xiaozhi.modules.agent.service.biz.AgentChatHistoryBizService;
|
||||||
|
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||||
|
import xiaozhi.modules.device.service.DeviceService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AgentChatHistoryBizService} impl
|
* {@link AgentChatHistoryBizService} impl
|
||||||
@@ -35,6 +37,7 @@ public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizServic
|
|||||||
private final AgentChatHistoryService agentChatHistoryService;
|
private final AgentChatHistoryService agentChatHistoryService;
|
||||||
private final AgentChatAudioService agentChatAudioService;
|
private final AgentChatAudioService agentChatAudioService;
|
||||||
private final RedisUtils redisUtils;
|
private final RedisUtils redisUtils;
|
||||||
|
private final DeviceService deviceService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理聊天记录上报,包括文件上传和相关信息记录
|
* 处理聊天记录上报,包括文件上传和相关信息记录
|
||||||
@@ -68,6 +71,15 @@ public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizServic
|
|||||||
|
|
||||||
// 更新设备最后对话时间
|
// 更新设备最后对话时间
|
||||||
redisUtils.set(RedisKeys.getAgentDeviceLastConnectedAtById(agentId), new Date());
|
redisUtils.set(RedisKeys.getAgentDeviceLastConnectedAtById(agentId), new Date());
|
||||||
|
|
||||||
|
// 更新设备最后连接时间
|
||||||
|
DeviceEntity device = deviceService.getDeviceByMacAddress(macAddress);
|
||||||
|
if (device != null) {
|
||||||
|
deviceService.updateDeviceConnectionInfo(agentId, device.getId(), null);
|
||||||
|
} else {
|
||||||
|
log.warn("聊天记录上报时,未找到mac地址为 {} 的设备", macAddress);
|
||||||
|
}
|
||||||
|
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
@@ -25,6 +25,7 @@ import xiaozhi.common.utils.Result;
|
|||||||
import xiaozhi.modules.device.dto.DeviceRegisterDTO;
|
import xiaozhi.modules.device.dto.DeviceRegisterDTO;
|
||||||
import xiaozhi.modules.device.dto.DeviceUnBindDTO;
|
import xiaozhi.modules.device.dto.DeviceUnBindDTO;
|
||||||
import xiaozhi.modules.device.dto.DeviceUpdateDTO;
|
import xiaozhi.modules.device.dto.DeviceUpdateDTO;
|
||||||
|
import xiaozhi.modules.device.dto.DeviceManualAddDTO;
|
||||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||||
import xiaozhi.modules.device.service.DeviceService;
|
import xiaozhi.modules.device.service.DeviceService;
|
||||||
import xiaozhi.modules.security.user.SecurityUser;
|
import xiaozhi.modules.security.user.SecurityUser;
|
||||||
@@ -99,4 +100,13 @@ public class DeviceController {
|
|||||||
deviceService.updateById(entity);
|
deviceService.updateById(entity);
|
||||||
return new Result<Void>();
|
return new Result<Void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/manual-add")
|
||||||
|
@Operation(summary = "手动添加设备")
|
||||||
|
@RequiresPermissions("sys:role:normal")
|
||||||
|
public Result<Void> manualAddDevice(@RequestBody @Valid DeviceManualAddDTO dto) {
|
||||||
|
UserDetail user = SecurityUser.getUser();
|
||||||
|
deviceService.manualAddDevice(user.getId(), dto);
|
||||||
|
return new Result<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package xiaozhi.modules.device.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DeviceManualAddDTO {
|
||||||
|
private String agentId;
|
||||||
|
private String board; // 设备型号
|
||||||
|
private String appVersion; // 固件版本
|
||||||
|
private String macAddress; // Mac地址
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import xiaozhi.common.service.BaseService;
|
|||||||
import xiaozhi.modules.device.dto.DevicePageUserDTO;
|
import xiaozhi.modules.device.dto.DevicePageUserDTO;
|
||||||
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
|
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
|
||||||
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
|
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
|
||||||
|
import xiaozhi.modules.device.dto.DeviceManualAddDTO;
|
||||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||||
import xiaozhi.modules.device.vo.UserShowDeviceListVO;
|
import xiaozhi.modules.device.vo.UserShowDeviceListVO;
|
||||||
|
|
||||||
@@ -87,5 +88,14 @@ public interface DeviceService extends BaseService<DeviceEntity> {
|
|||||||
*/
|
*/
|
||||||
Date getLatestLastConnectionTime(String agentId);
|
Date getLatestLastConnectionTime(String agentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动添加设备
|
||||||
|
*/
|
||||||
|
void manualAddDevice(Long userId, DeviceManualAddDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设备连接信息
|
||||||
|
*/
|
||||||
|
void updateDeviceConnectionInfo(String agentId, String deviceId, String appVersion);
|
||||||
|
|
||||||
}
|
}
|
||||||
+27
@@ -44,6 +44,7 @@ import xiaozhi.modules.device.vo.UserShowDeviceListVO;
|
|||||||
import xiaozhi.modules.security.user.SecurityUser;
|
import xiaozhi.modules.security.user.SecurityUser;
|
||||||
import xiaozhi.modules.sys.service.SysParamsService;
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
import xiaozhi.modules.sys.service.SysUserUtilService;
|
import xiaozhi.modules.sys.service.SysUserUtilService;
|
||||||
|
import xiaozhi.modules.device.dto.DeviceManualAddDTO;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -410,4 +411,30 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void manualAddDevice(Long userId, DeviceManualAddDTO dto) {
|
||||||
|
// 检查mac是否已存在
|
||||||
|
QueryWrapper<DeviceEntity> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("mac_address", dto.getMacAddress());
|
||||||
|
DeviceEntity exist = baseDao.selectOne(wrapper);
|
||||||
|
if (exist != null) {
|
||||||
|
throw new RenException("该Mac地址已存在");
|
||||||
|
}
|
||||||
|
Date now = new Date();
|
||||||
|
DeviceEntity entity = new DeviceEntity();
|
||||||
|
entity.setId(dto.getMacAddress());
|
||||||
|
entity.setUserId(userId);
|
||||||
|
entity.setAgentId(dto.getAgentId());
|
||||||
|
entity.setBoard(dto.getBoard());
|
||||||
|
entity.setAppVersion(dto.getAppVersion());
|
||||||
|
entity.setMacAddress(dto.getMacAddress());
|
||||||
|
entity.setCreateDate(now);
|
||||||
|
entity.setUpdateDate(now);
|
||||||
|
entity.setLastConnectedAt(now);
|
||||||
|
entity.setCreator(userId);
|
||||||
|
entity.setUpdater(userId);
|
||||||
|
entity.setAutoUpdate(1);
|
||||||
|
baseDao.insert(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-- 更新 get_news_from_newsnow 插件配置,添加新闻源配置字段
|
||||||
|
-- 执行时间:2025-06-25
|
||||||
|
|
||||||
|
-- 更新现有的 get_news_from_newsnow 插件配置
|
||||||
|
UPDATE ai_model_provider
|
||||||
|
SET fields = JSON_ARRAY(
|
||||||
|
JSON_OBJECT(
|
||||||
|
'key', 'url',
|
||||||
|
'type', 'string',
|
||||||
|
'label', '接口地址',
|
||||||
|
'default', 'https://newsnow.busiyi.world/api/s?id='
|
||||||
|
),
|
||||||
|
JSON_OBJECT(
|
||||||
|
'key', 'news_sources',
|
||||||
|
'type', 'json',
|
||||||
|
'label', '新闻源配置',
|
||||||
|
'default', '{"thepaper":"澎湃新闻","baidu":"百度热搜","cls-depth":"财联社"}'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
WHERE provider_code = 'get_news_from_newsnow'
|
||||||
|
AND model_type = 'Plugin';
|
||||||
@@ -219,10 +219,17 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202506191643.sql
|
path: classpath:db/changelog/202506191643.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202506251619
|
||||||
|
author: Tink
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202506251619.sql
|
||||||
- changeSet:
|
- changeSet:
|
||||||
id: 202506261637
|
id: 202506261637
|
||||||
author: hrz
|
author: hrz
|
||||||
changes:
|
changes:
|
||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202506261637.sql
|
path: classpath:db/changelog/202506261637.sql
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import model from './module/model.js'
|
|||||||
import ota from './module/ota.js'
|
import ota from './module/ota.js'
|
||||||
import timbre from "./module/timbre.js"
|
import timbre from "./module/timbre.js"
|
||||||
import user from './module/user.js'
|
import user from './module/user.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口地址
|
* 接口地址
|
||||||
* 开发时自动读取使用.env.development文件
|
* 开发时自动读取使用.env.development文件
|
||||||
@@ -22,7 +23,6 @@ export function getServiceUrl() {
|
|||||||
return DEV_API_SERVICE
|
return DEV_API_SERVICE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** request服务封装 */
|
/** request服务封装 */
|
||||||
export default {
|
export default {
|
||||||
getServiceUrl,
|
getServiceUrl,
|
||||||
|
|||||||
@@ -68,4 +68,21 @@ export default {
|
|||||||
})
|
})
|
||||||
}).send()
|
}).send()
|
||||||
},
|
},
|
||||||
|
// 手动添加设备
|
||||||
|
manualAddDevice(params, callback) {
|
||||||
|
RequestService.sendRequest()
|
||||||
|
.url(`${getServiceUrl()}/device/manual-add`)
|
||||||
|
.method('POST')
|
||||||
|
.data(params)
|
||||||
|
.success((res) => {
|
||||||
|
RequestService.clearRequestTime();
|
||||||
|
callback(res);
|
||||||
|
})
|
||||||
|
.networkFail((err) => {
|
||||||
|
console.error('手动添加设备失败:', err);
|
||||||
|
RequestService.reAjaxFun(() => {
|
||||||
|
this.manualAddDevice(params, callback);
|
||||||
|
});
|
||||||
|
}).send();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="手动添加设备" :visible="visible" @close="handleClose" width="30%" center>
|
||||||
|
<div class="dialog-content">
|
||||||
|
<el-form :model="deviceForm" :rules="rules" ref="deviceForm" label-width="100px">
|
||||||
|
<el-form-item label="设备型号" prop="board">
|
||||||
|
<el-select v-model="deviceForm.board" placeholder="请选择设备型号" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in firmwareTypes"
|
||||||
|
:key="item.key"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.key">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="固件版本" prop="appVersion">
|
||||||
|
<el-input v-model="deviceForm.appVersion" placeholder="请输入固件版本"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Mac地址" prop="macAddress">
|
||||||
|
<el-input v-model="deviceForm.macAddress" placeholder="请输入Mac地址"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;margin: 15px 15px;gap: 7px;">
|
||||||
|
<div class="dialog-btn" @click="submitForm">确定</div>
|
||||||
|
<div class="dialog-btn cancel-btn" @click="cancel">取消</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Api from '@/apis/api';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ManualAddDeviceDialog',
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, required: true },
|
||||||
|
agentId: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
// MAC地址验证规则
|
||||||
|
const validateMac = (rule, value, callback) => {
|
||||||
|
const macRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
||||||
|
if (!value) {
|
||||||
|
callback(new Error('请输入Mac地址'));
|
||||||
|
} else if (!macRegex.test(value)) {
|
||||||
|
callback(new Error('请输入正确的Mac地址格式,例如:00:1A:2B:3C:4D:5E'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
deviceForm: {
|
||||||
|
board: '',
|
||||||
|
appVersion: '',
|
||||||
|
macAddress: ''
|
||||||
|
},
|
||||||
|
firmwareTypes: [],
|
||||||
|
rules: {
|
||||||
|
board: [
|
||||||
|
{ required: true, message: '请选择设备型号', trigger: 'change' }
|
||||||
|
],
|
||||||
|
appVersion: [
|
||||||
|
{ required: true, message: '请输入固件版本', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
macAddress: [
|
||||||
|
{ required: true, validator: validateMac, trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getFirmwareTypes();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getFirmwareTypes() {
|
||||||
|
try {
|
||||||
|
const res = await Api.dict.getDictDataByType('FIRMWARE_TYPE');
|
||||||
|
this.firmwareTypes = res.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取固件类型失败:', error);
|
||||||
|
this.$message.error(error.message || '获取固件类型失败');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitForm() {
|
||||||
|
this.$refs.deviceForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.addDevice();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addDevice() {
|
||||||
|
const params = {
|
||||||
|
agentId: this.agentId,
|
||||||
|
...this.deviceForm
|
||||||
|
};
|
||||||
|
|
||||||
|
Api.device.manualAddDevice(params, ({ data }) => {
|
||||||
|
if (data.code === 0) {
|
||||||
|
this.$message.success('设备添加成功');
|
||||||
|
this.$emit('refresh');
|
||||||
|
this.closeDialog();
|
||||||
|
} else {
|
||||||
|
this.$message.error(data.msg || '添加失败');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closeDialog() {
|
||||||
|
this.$emit('update:visible', false);
|
||||||
|
this.$refs.deviceForm.resetFields();
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
this.closeDialog();
|
||||||
|
},
|
||||||
|
handleClose() {
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dialog-content {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1;
|
||||||
|
border-radius: 23px;
|
||||||
|
background: #5778ff;
|
||||||
|
height: 40px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
background: #e6ebff;
|
||||||
|
border: 1px solid #adbdff;
|
||||||
|
color: #5778ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog__body {
|
||||||
|
padding: 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -77,7 +77,10 @@
|
|||||||
{{ isAllSelected ? '取消全选' : '全选' }}
|
{{ isAllSelected ? '取消全选' : '全选' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" size="mini" class="add-device-btn" @click="handleAddDevice">
|
<el-button type="success" size="mini" class="add-device-btn" @click="handleAddDevice">
|
||||||
新增
|
验证码绑定
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" size="mini" class="add-device-btn" @click="handleManualAddDevice">
|
||||||
|
手动添加
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteSelected">解绑</el-button>
|
<el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteSelected">解绑</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,6 +106,8 @@
|
|||||||
|
|
||||||
<AddDeviceDialog :visible.sync="addDeviceDialogVisible" :agent-id="currentAgentId"
|
<AddDeviceDialog :visible.sync="addDeviceDialogVisible" :agent-id="currentAgentId"
|
||||||
@refresh="fetchBindDevices(currentAgentId)"/>
|
@refresh="fetchBindDevices(currentAgentId)"/>
|
||||||
|
<ManualAddDeviceDialog :visible.sync="manualAddDeviceDialogVisible" :agent-id="currentAgentId"
|
||||||
|
@refresh="fetchBindDevices(currentAgentId)"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -110,13 +115,19 @@
|
|||||||
<script>
|
<script>
|
||||||
import Api from '@/apis/api';
|
import Api from '@/apis/api';
|
||||||
import AddDeviceDialog from "@/components/AddDeviceDialog.vue";
|
import AddDeviceDialog from "@/components/AddDeviceDialog.vue";
|
||||||
|
import ManualAddDeviceDialog from "@/components/ManualAddDeviceDialog.vue";
|
||||||
import HeaderBar from "@/components/HeaderBar.vue";
|
import HeaderBar from "@/components/HeaderBar.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {HeaderBar, AddDeviceDialog},
|
components: {
|
||||||
|
HeaderBar,
|
||||||
|
AddDeviceDialog,
|
||||||
|
ManualAddDeviceDialog
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
addDeviceDialogVisible: false,
|
addDeviceDialogVisible: false,
|
||||||
|
manualAddDeviceDialogVisible: false,
|
||||||
selectedDevices: [],
|
selectedDevices: [],
|
||||||
isAllSelected: false,
|
isAllSelected: false,
|
||||||
searchKeyword: "",
|
searchKeyword: "",
|
||||||
@@ -252,6 +263,9 @@ export default {
|
|||||||
handleAddDevice() {
|
handleAddDevice() {
|
||||||
this.addDeviceDialogVisible = true;
|
this.addDeviceDialogVisible = true;
|
||||||
},
|
},
|
||||||
|
handleManualAddDevice() {
|
||||||
|
this.manualAddDeviceDialogVisible = true;
|
||||||
|
},
|
||||||
submitRemark(row) {
|
submitRemark(row) {
|
||||||
if (row._submitting) return;
|
if (row._submitting) return;
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,12 @@ plugins:
|
|||||||
society_rss_url: "https://www.chinanews.com.cn/rss/society.xml"
|
society_rss_url: "https://www.chinanews.com.cn/rss/society.xml"
|
||||||
world_rss_url: "https://www.chinanews.com.cn/rss/world.xml"
|
world_rss_url: "https://www.chinanews.com.cn/rss/world.xml"
|
||||||
finance_rss_url: "https://www.chinanews.com.cn/rss/finance.xml"
|
finance_rss_url: "https://www.chinanews.com.cn/rss/finance.xml"
|
||||||
get_news_from_newsnow: {"url": "https://newsnow.busiyi.world/api/s?id="}
|
get_news_from_newsnow:
|
||||||
|
url: "https://newsnow.busiyi.world/api/s?id="
|
||||||
|
news_sources:
|
||||||
|
thepaper: "澎湃新闻"
|
||||||
|
baidu: "百度热搜"
|
||||||
|
cls-depth: "财联社"
|
||||||
home_assistant:
|
home_assistant:
|
||||||
devices:
|
devices:
|
||||||
- 客厅,玩具灯,switch.cuco_cn_460494544_cp1_on_p_2_1
|
- 客厅,玩具灯,switch.cuco_cn_460494544_cp1_on_p_2_1
|
||||||
@@ -766,4 +771,4 @@ TTS:
|
|||||||
# 支持声音克隆,可自行上传音频,填入voice参数,voice参数为空时,使用默认声音
|
# 支持声音克隆,可自行上传音频,填入voice参数,voice参数为空时,使用默认声音
|
||||||
access_token: "U4YdYXVfpwWnk2t5Gp822zWPCuORyeJL"
|
access_token: "U4YdYXVfpwWnk2t5Gp822zWPCuORyeJL"
|
||||||
voice: "OUeAo1mhq6IBExi"
|
voice: "OUeAo1mhq6IBExi"
|
||||||
output_dir: tmp/
|
output_dir: tmp/
|
||||||
|
|||||||
@@ -8,38 +8,61 @@ from markitdown import MarkItDown
|
|||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
|
|
||||||
# 新闻来源字典,包含名称和对应的API ID
|
# 默认新闻来源字典,当配置中没有指定时使用
|
||||||
NEWS_SOURCES = {
|
DEFAULT_NEWS_SOURCES = {
|
||||||
"thepaper": "澎湃新闻",
|
"thepaper": "澎湃新闻",
|
||||||
"baidu": "百度热搜",
|
"baidu": "百度热搜",
|
||||||
"cls-depth": "财联社",
|
"cls-depth": "财联社",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# 动态生成新闻源描述
|
def get_news_sources_from_config(conn):
|
||||||
def generate_news_sources_description():
|
"""从配置中获取新闻源字典"""
|
||||||
sources_desc = []
|
try:
|
||||||
for source_id, source_name in NEWS_SOURCES.items():
|
# 尝试从插件配置中获取新闻源
|
||||||
sources_desc.append(f"{source_name}({source_id})")
|
if (conn.config.get("plugins") and
|
||||||
return "、".join(sources_desc)
|
conn.config["plugins"].get("get_news_from_newsnow") and
|
||||||
|
conn.config["plugins"]["get_news_from_newsnow"].get("news_sources")):
|
||||||
|
|
||||||
|
# 如果配置中是字符串,尝试解析JSON
|
||||||
|
news_sources_config = conn.config["plugins"]["get_news_from_newsnow"]["news_sources"]
|
||||||
|
if isinstance(news_sources_config, str):
|
||||||
|
try:
|
||||||
|
return json.loads(news_sources_config)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logger.bind(tag=TAG).warning("新闻源配置JSON格式错误,使用默认配置")
|
||||||
|
return DEFAULT_NEWS_SOURCES
|
||||||
|
elif isinstance(news_sources_config, dict):
|
||||||
|
return news_sources_config
|
||||||
|
else:
|
||||||
|
logger.bind(tag=TAG).warning("新闻源配置格式错误,使用默认配置")
|
||||||
|
return DEFAULT_NEWS_SOURCES
|
||||||
|
else:
|
||||||
|
logger.bind(tag=TAG).debug("未找到新闻源配置,使用默认配置")
|
||||||
|
return DEFAULT_NEWS_SOURCES
|
||||||
|
except Exception as e:
|
||||||
|
logger.bind(tag=TAG).error(f"获取新闻源配置失败: {e},使用默认配置")
|
||||||
|
return DEFAULT_NEWS_SOURCES
|
||||||
|
|
||||||
|
|
||||||
|
# 静态函数描述,使用默认新闻源生成描述
|
||||||
GET_NEWS_FROM_NEWSNOW_FUNCTION_DESC = {
|
GET_NEWS_FROM_NEWSNOW_FUNCTION_DESC = {
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "get_news_from_newsnow",
|
"name": "get_news_from_newsnow",
|
||||||
"description": (
|
"description": (
|
||||||
"获取最新新闻,随机选择一条新闻进行播报。"
|
"获取最新新闻,随机选择一条新闻进行播报。"
|
||||||
f"用户可以选择不同的新闻源,如{generate_news_sources_description()}等。"
|
"用户可以选择不同的新闻源,如澎湃新闻(thepaper)、百度热搜(baidu)、财联社(cls-depth)等。"
|
||||||
"如果没有指定,默认从澎湃新闻获取。"
|
"如果没有指定,默认从澎湃新闻获取。"
|
||||||
"用户可以要求获取详细内容,此时会获取新闻的详细内容。"
|
"用户可以要求获取详细内容,此时会获取新闻的详细内容。"
|
||||||
|
"注意:实际可用的新闻源取决于系统配置。"
|
||||||
),
|
),
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"source": {
|
"source": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": f"新闻源,例如{generate_news_sources_description()}等。可选参数,如果不提供则使用默认新闻源",
|
"description": "新闻源,例如thepaper、baidu、cls-depth等。可选参数,如果不提供则使用默认新闻源",
|
||||||
},
|
},
|
||||||
"detail": {
|
"detail": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -115,6 +138,9 @@ def get_news_from_newsnow(
|
|||||||
):
|
):
|
||||||
"""获取新闻并随机选择一条进行播报,或获取上一条新闻的详细内容"""
|
"""获取新闻并随机选择一条进行播报,或获取上一条新闻的详细内容"""
|
||||||
try:
|
try:
|
||||||
|
# 获取当前配置的新闻源
|
||||||
|
news_sources = get_news_sources_from_config(conn)
|
||||||
|
|
||||||
# 如果detail为True,获取上一条新闻的详细内容
|
# 如果detail为True,获取上一条新闻的详细内容
|
||||||
detail = str(detail).lower() == "true"
|
detail = str(detail).lower() == "true"
|
||||||
if detail:
|
if detail:
|
||||||
@@ -132,7 +158,7 @@ def get_news_from_newsnow(
|
|||||||
url = conn.last_newsnow_link.get("url")
|
url = conn.last_newsnow_link.get("url")
|
||||||
title = conn.last_newsnow_link.get("title", "未知标题")
|
title = conn.last_newsnow_link.get("title", "未知标题")
|
||||||
source_id = conn.last_newsnow_link.get("source_id", "thepaper")
|
source_id = conn.last_newsnow_link.get("source_id", "thepaper")
|
||||||
source_name = NEWS_SOURCES.get(source_id, "未知来源")
|
source_name = news_sources.get(source_id, "未知来源")
|
||||||
|
|
||||||
if not url or url == "#":
|
if not url or url == "#":
|
||||||
return ActionResponse(
|
return ActionResponse(
|
||||||
@@ -167,11 +193,11 @@ def get_news_from_newsnow(
|
|||||||
|
|
||||||
# 否则,获取新闻列表并随机选择一条
|
# 否则,获取新闻列表并随机选择一条
|
||||||
# 验证新闻源是否有效,如果无效则使用默认源
|
# 验证新闻源是否有效,如果无效则使用默认源
|
||||||
if source not in NEWS_SOURCES:
|
if source not in news_sources:
|
||||||
logger.bind(tag=TAG).warning(f"无效的新闻源: {source},使用默认源thepaper")
|
logger.bind(tag=TAG).warning(f"无效的新闻源: {source},使用默认源thepaper")
|
||||||
source = "thepaper"
|
source = "thepaper"
|
||||||
|
|
||||||
source_name = NEWS_SOURCES.get(source, "澎湃新闻")
|
source_name = news_sources.get(source, "澎湃新闻")
|
||||||
logger.bind(tag=TAG).info(f"获取新闻: 新闻源={source}({source_name})")
|
logger.bind(tag=TAG).info(f"获取新闻: 新闻源={source}({source_name})")
|
||||||
|
|
||||||
# 获取新闻列表
|
# 获取新闻列表
|
||||||
|
|||||||
Reference in New Issue
Block a user