| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- package com.agent.management.controller;
- import com.agent.management.common.Result;
- import com.agent.management.model.dto.FileCreateDTO;
- import com.agent.management.model.dto.FileNodeDTO;
- import com.agent.management.model.dto.IOField;
- import com.agent.management.model.dto.SkillDTO;
- import com.agent.management.model.dto.SkillUpdateDTO;
- import com.agent.management.model.vo.SkillDetailVO;
- import com.agent.management.model.vo.SkillVO;
- import com.agent.management.service.SkillService;
- import com.agent.management.service.TranslationService;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.web.multipart.MultipartFile;
- import java.util.List;
- import java.util.Map;
- import java.util.stream.Collectors;
- @Slf4j
- @RestController
- @RequestMapping("/api/skills")
- @RequiredArgsConstructor
- public class SkillController {
- private final SkillService skillService;
- private final TranslationService translationService;
- /**
- * 获取所有 Skill 列表
- * 立即返回数据(优先带缓存翻译),未缓存的通过 SSE 异步推送
- */
- @GetMapping
- public Result<List<SkillVO>> listSkills() {
- List<SkillDTO> skills = skillService.listSkills();
- // 构建 VO:优先从缓存读取翻译(不触发 LLM)
- List<SkillVO> voList = skills.stream()
- .map(this::toVOWithCache)
- .collect(Collectors.toList());
- // 对需要翻译的 Skill 异步翻译 + SSE 推送
- for (SkillDTO dto : skills) {
- // 只有缓存未命中时才需要异步翻译
- String cachedName = translationService.getCachedTranslation(dto.getName());
- String cachedDesc = translationService.getCachedTranslation(dto.getDescription());
- if (cachedName == null || cachedDesc == null) {
- translationService.asyncTranslateAndPush(
- dto.getFolderName(), dto.getName(), dto.getDescription());
- }
- }
- return Result.success(voList);
- }
- @PostMapping("/upload")
- public Result<Void> uploadSkill(@RequestParam("file") MultipartFile file) {
- skillService.createSkill(file);
- return Result.success("上传成功", null);
- }
- @PostMapping("/{folderName}/edit")
- public Result<Void> editSkill(@PathVariable String folderName,
- @RequestBody SkillUpdateDTO dto) {
- skillService.updateSkill(folderName, dto);
- return Result.success("更新成功", null);
- }
- @PostMapping("/{folderName}/delete")
- public Result<Void> deleteSkill(@PathVariable String folderName) {
- skillService.deleteSkill(folderName);
- return Result.success("删除成功", null);
- }
- // ==================== 技能编辑相关 API ====================
- /**
- * 获取技能详情(含 SKILL.md 正文内容)
- */
- @GetMapping("/{folderName}/detail")
- public Result<SkillDetailVO> getSkillDetail(@PathVariable String folderName) {
- return Result.success(skillService.getSkillDetail(folderName));
- }
- /**
- * 保存 SKILL.md(智能合并元数据)
- */
- @PutMapping("/{folderName}/skill-md")
- public Result<Void> saveSkillMd(@PathVariable String folderName,
- @RequestBody Map<String, Object> body) {
- String name = (String) body.getOrDefault("name", "");
- String description = (String) body.getOrDefault("description", "");
- String bodyText = (String) body.getOrDefault("body", "");
- // 解析 inputs / outputs
- List<IOField> inputs = parseIOFields(body.get("inputs"));
- List<IOField> outputs = parseIOFields(body.get("outputs"));
- skillService.saveSkillMd(folderName, name, description, inputs, outputs, bodyText);
- return Result.success("保存成功", null);
- }
- @SuppressWarnings("unchecked")
- private List<IOField> parseIOFields(Object obj) {
- if (obj == null) return null;
- if (obj instanceof List) {
- return ((List<?>) obj).stream()
- .map(item -> {
- if (item instanceof java.util.Map) {
- java.util.Map<String, Object> m = (java.util.Map<String, Object>) item;
- IOField field = new IOField();
- field.setName((String) m.getOrDefault("name", ""));
- field.setType((String) m.getOrDefault("type", "string"));
- field.setDescription((String) m.getOrDefault("description", ""));
- field.setRequired(Boolean.TRUE.equals(m.get("required")));
- return field;
- }
- return null;
- })
- .filter(java.util.Objects::nonNull)
- .collect(Collectors.toList());
- }
- return null;
- }
- /**
- * 列出技能目录下的所有文件(树形结构)
- */
- @GetMapping("/{folderName}/files")
- public Result<List<FileNodeDTO>> listFiles(@PathVariable String folderName) {
- return Result.success(skillService.listSkillFiles(folderName));
- }
- /**
- * 读取文件内容
- */
- @GetMapping("/{folderName}/files/content")
- public Result<String> readFile(@PathVariable String folderName,
- @RequestParam String path) {
- return Result.success(skillService.readFile(folderName, path));
- }
- /**
- * 保存文件内容
- */
- @PutMapping("/{folderName}/files/content")
- public Result<Void> saveFile(@PathVariable String folderName,
- @RequestBody Map<String, String> body) {
- skillService.saveFile(folderName, body.get("path"), body.get("content"));
- return Result.success("保存成功", null);
- }
- /**
- * 创建文件或目录
- */
- @PostMapping("/{folderName}/files")
- public Result<Void> createFile(@PathVariable String folderName,
- @RequestBody FileCreateDTO dto) {
- skillService.createFileOrDir(folderName, dto);
- return Result.success("创建成功", null);
- }
- /**
- * 删除文件或目录
- */
- @DeleteMapping("/{folderName}/files")
- public Result<Void> deleteFile(@PathVariable String folderName,
- @RequestParam String path) {
- skillService.deleteFile(folderName, path);
- return Result.success("删除成功", null);
- }
- // ==================== 私有方法 ====================
- /**
- * 构建 VO:优先从缓存读取翻译(纯内存操作,不触发 LLM)
- */
- private SkillVO toVOWithCache(SkillDTO dto) {
- SkillVO vo = new SkillVO();
- vo.setFolderName(dto.getFolderName());
- vo.setName(dto.getName());
- vo.setDescription(dto.getDescription());
- vo.setTranslatedName(translationService.getCachedTranslation(dto.getName()));
- vo.setTranslatedDescription(translationService.getCachedTranslation(dto.getDescription()));
- vo.setInputs(dto.getInputs());
- vo.setOutputs(dto.getOutputs());
- return vo;
- }
- }
|