refactor: 收口技能与专员目录定义
统一 skill 与 specialist 清单,移除旧的 office 执行包与下线对象,并补入 text_to_speech、customer_followup 等当前目录定义与种子数据。
This commit is contained in:
@@ -199,7 +199,7 @@ func ExecuteOfficeSkillOCR(c *gin.Context) {
|
||||
TaskID: task.ID,
|
||||
SpecialistKey: task.SpecialistKey,
|
||||
ActionKey: "ocr-understanding",
|
||||
ActionTitle: "OCR / 图文理解",
|
||||
ActionTitle: "图片/扫描件智能识别",
|
||||
ActionType: "ocr",
|
||||
Status: "done",
|
||||
InputJSON: string(inputJSON),
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
package skillapi
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"eai_agentplatform/backend/internal/config"
|
||||
"eai_agentplatform/backend/internal/middleware"
|
||||
"eai_agentplatform/backend/internal/model"
|
||||
specialistruntime "eai_agentplatform/backend/internal/specialists/runtime"
|
||||
"eai_agentplatform/backend/internal/store"
|
||||
"eai_agentplatform/backend/internal/web"
|
||||
)
|
||||
|
||||
// ttsDefaultVoice 默认中文女声(edge-tts 自带音色)。
|
||||
const ttsDefaultVoice = "zh-CN-XiaoxiaoNeural"
|
||||
|
||||
// ttsAudioDir 存放合成 MP3 的目录,与公众号配图一致放在数据库同级的 tts_audio 下。
|
||||
func ttsAudioDir() string {
|
||||
cfg := config.Load()
|
||||
return filepath.Join(filepath.Dir(cfg.DBPath), "tts_audio")
|
||||
}
|
||||
|
||||
func defaultTTSText(text string) string {
|
||||
text = strings.TrimSpace(text)
|
||||
if text == "" {
|
||||
return "这是一个文字转语音的示例。"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// ExecuteOfficeSkillTTS POST /api/skills/office/tts —— 文字转语音。
|
||||
// body: { "task_id": <任务ID>, "text": "要朗读的文字", "voice": "音色(可空)", "rate": "语速(可空, 如 +0% / -10%)" }
|
||||
func ExecuteOfficeSkillTTS(c *gin.Context) {
|
||||
user := middleware.CurrentUser(c)
|
||||
if user == nil {
|
||||
web.Fail(c, web.NewAuthError("未登录"))
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
TaskID uint `json:"task_id"`
|
||||
Text string `json:"text"`
|
||||
Voice string `json:"voice"`
|
||||
Rate string `json:"rate"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("请求参数错误"))
|
||||
return
|
||||
}
|
||||
if req.TaskID == 0 {
|
||||
web.Fail(c, web.NewBadRequest("task_id 必填"))
|
||||
return
|
||||
}
|
||||
|
||||
text := defaultTTSText(req.Text)
|
||||
voice := strings.TrimSpace(req.Voice)
|
||||
if voice == "" {
|
||||
voice = ttsDefaultVoice
|
||||
}
|
||||
rate := strings.TrimSpace(req.Rate)
|
||||
|
||||
task, ok := loadMyOwnedTask(c, user, req.TaskID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
dir := ttsAudioDir()
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("无法创建音频目录"))
|
||||
return
|
||||
}
|
||||
sum := sha1.Sum([]byte(text + "|" + voice))
|
||||
filename := fmt.Sprintf("task_%d_%s_%x.mp3", task.ID, now.Format("20060102-150405"), sum[:6])
|
||||
audioPath := filepath.Join(dir, filename)
|
||||
|
||||
args := []string{"-m", "edge_tts", "--text", text, "--voice", voice, "--write-media", audioPath}
|
||||
if rate != "" {
|
||||
args = append(args, "--rate", rate)
|
||||
}
|
||||
cmd := exec.Command("python3", args...)
|
||||
var stderr strings.Builder
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("语音合成失败:"+firstNonEmpty(strings.TrimSpace(stderr.String()), err.Error())))
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(audioPath); err != nil {
|
||||
web.Fail(c, web.NewBadRequest("语音合成失败:未生成音频文件"))
|
||||
return
|
||||
}
|
||||
audioURL := "/api/tts/audio/" + filename
|
||||
|
||||
inputJSON, _ := json.Marshal(gin.H{"text": text, "voice": voice, "rate": rate})
|
||||
outputJSON, _ := json.Marshal(gin.H{
|
||||
"summary": "已将文本合成为语音,可在线播放或下载。",
|
||||
"text": text,
|
||||
"voice": voice,
|
||||
"audio_url": audioURL,
|
||||
})
|
||||
logsJSON, _ := json.Marshal([]string{
|
||||
"接收文字转语音请求",
|
||||
fmt.Sprintf("调用本地 TTS 引擎(voice=%s)", voice),
|
||||
"已生成 MP3 音频",
|
||||
})
|
||||
artifactPayloadJSON, _ := json.Marshal(gin.H{
|
||||
"text": text,
|
||||
"voice": voice,
|
||||
"audio_url": audioURL,
|
||||
"format": "mp3",
|
||||
})
|
||||
sourceRefsJSON, _ := json.Marshal([]string{"本地 edge-tts"})
|
||||
|
||||
var run model.TaskRun
|
||||
var artifact model.TaskArtifact
|
||||
err := store.DB.Transaction(func(tx *gorm.DB) error {
|
||||
run = model.TaskRun{
|
||||
TaskID: task.ID,
|
||||
SpecialistKey: task.SpecialistKey,
|
||||
ActionKey: "text-to-speech",
|
||||
ActionTitle: "文字转语音",
|
||||
ActionType: "audio",
|
||||
Status: "done",
|
||||
InputJSON: string(inputJSON),
|
||||
OutputJSON: string(outputJSON),
|
||||
LogsJSON: string(logsJSON),
|
||||
StartedAt: now,
|
||||
FinishedAt: &now,
|
||||
}
|
||||
if err := tx.Create(&run).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
artifact = model.TaskArtifact{
|
||||
TaskID: task.ID,
|
||||
SpecialistKey: task.SpecialistKey,
|
||||
Title: fmt.Sprintf("%s - 语音合成结果", task.Title),
|
||||
ArtifactType: "audio",
|
||||
Status: specialistruntime.ArtifactStatusDraft,
|
||||
ContentText: text,
|
||||
ContentJSON: string(artifactPayloadJSON),
|
||||
SourceRefsJSON: string(sourceRefsJSON),
|
||||
CreatedByRunID: &run.ID,
|
||||
}
|
||||
if err := tx.Create(&artifact).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
task.CurrentRunID = &run.ID
|
||||
task.CurrentResult = "已将文本合成为语音并生成 MP3。"
|
||||
task.Status = specialistruntime.TaskStatusDraft
|
||||
task.LastTriggeredAt = &now
|
||||
return tx.Save(&task).Error
|
||||
})
|
||||
if err != nil {
|
||||
web.Fail(c, web.NewBadRequest("保存结果失败:"+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
freshTask, _ := reloadTask(task.ID)
|
||||
web.OK(c, gin.H{
|
||||
"audio_url": audioURL,
|
||||
"text": text,
|
||||
"voice": voice,
|
||||
"rate": rate,
|
||||
"run": run,
|
||||
"artifact": artifact,
|
||||
"task": freshTask,
|
||||
})
|
||||
}
|
||||
|
||||
// ServeTTSAudio GET /api/tts/audio/:filename —— 提供生成的 MP3 音频文件。
|
||||
func ServeTTSAudio(c *gin.Context) {
|
||||
filename := filepath.Base(strings.TrimSpace(c.Param("filename")))
|
||||
if filename == "." || filename == "" {
|
||||
web.Fail(c, web.NewNotFoundError("音频不存在"))
|
||||
return
|
||||
}
|
||||
fullPath := filepath.Join(ttsAudioDir(), filename)
|
||||
if _, err := os.Stat(fullPath); err != nil {
|
||||
web.Fail(c, web.NewNotFoundError("音频不存在"))
|
||||
return
|
||||
}
|
||||
c.File(fullPath)
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
contractreview "eai_agentplatform/backend/internal/skills/packages/contract_review"
|
||||
copyproofreading "eai_agentplatform/backend/internal/skills/packages/copy_proofreading"
|
||||
documenttranslate "eai_agentplatform/backend/internal/skills/packages/document_translate"
|
||||
emaildrafting "eai_agentplatform/backend/internal/skills/packages/email_drafting"
|
||||
interviewsummary "eai_agentplatform/backend/internal/skills/packages/interview_summary"
|
||||
longformwriting "eai_agentplatform/backend/internal/skills/packages/longform_writing"
|
||||
meetingminutes "eai_agentplatform/backend/internal/skills/packages/meeting_minutes"
|
||||
@@ -16,13 +15,10 @@ import (
|
||||
policyrewrite "eai_agentplatform/backend/internal/skills/packages/policy_rewrite"
|
||||
pptgeneration "eai_agentplatform/backend/internal/skills/packages/ppt_generation"
|
||||
progressreport "eai_agentplatform/backend/internal/skills/packages/progress_report"
|
||||
projectplanning "eai_agentplatform/backend/internal/skills/packages/project_planning"
|
||||
proposalsummary "eai_agentplatform/backend/internal/skills/packages/proposal_summary"
|
||||
reportgeneration "eai_agentplatform/backend/internal/skills/packages/report_generation"
|
||||
smartassistant "eai_agentplatform/backend/internal/skills/packages/smart_assistant"
|
||||
surveysummary "eai_agentplatform/backend/internal/skills/packages/survey_summary"
|
||||
tablecleanup "eai_agentplatform/backend/internal/skills/packages/table_cleanup"
|
||||
texttoolkit "eai_agentplatform/backend/internal/skills/packages/text_toolkit"
|
||||
texttospeech "eai_agentplatform/backend/internal/skills/packages/text_to_speech"
|
||||
)
|
||||
|
||||
var builtinRegistry = NewRegistry(
|
||||
@@ -36,18 +32,14 @@ var builtinRegistry = NewRegistry(
|
||||
pptgeneration.Manifest,
|
||||
mindmap.Manifest,
|
||||
longformwriting.Manifest,
|
||||
texttoolkit.Manifest,
|
||||
ocrunderstanding.Manifest,
|
||||
meetingminutes.Manifest,
|
||||
projectplanning.Manifest,
|
||||
emaildrafting.Manifest,
|
||||
tablecleanup.Manifest,
|
||||
proposalsummary.Manifest,
|
||||
progressreport.Manifest,
|
||||
contractbrief.Manifest,
|
||||
interviewsummary.Manifest,
|
||||
policyrewrite.Manifest,
|
||||
surveysummary.Manifest,
|
||||
texttospeech.Manifest,
|
||||
)
|
||||
|
||||
func BuiltinRegistry() *Registry {
|
||||
|
||||
@@ -11,8 +11,10 @@ type SkillDefinition struct {
|
||||
EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
ObjectKind string `gorm:"column:object_kind;size:32;not null;default:skill;index" json:"object_kind"`
|
||||
Source string `gorm:"size:32;not null;default:eai;index" json:"source"`
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"`
|
||||
Source string `gorm:"size:32;not null;default:eai;index" json:"source"`
|
||||
ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"` // 业务对象进入入口(D26 口径)
|
||||
Color string `gorm:"size:16;default:''" json:"color"` // 展示主色(面向用户展示层,唯一的真值在后端)
|
||||
InteractionCardJSON string `gorm:"column:interaction_card_json;type:text" json:"interaction_card_json"` // 交互卡对象(JSON,snake_case 与专员一致)
|
||||
// 这里**有意不写** `default:true`。带上它,GORM 在 Create 时会跳过布尔零值字段
|
||||
// (false 被当成「没填」),改由库默认值 true 生效 —— 于是对象显式设的 false
|
||||
// 被持久层改写成 true,创建接口永远设不出「不暴露给用户」的技能。
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "audio-transcribe",
|
||||
Label: "语音转写",
|
||||
Label: "会议音频分析(转写)",
|
||||
OwnedDefinitionKeys: []string{"skill.audio-transcribe.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.audio-transcribe"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "batch-extract",
|
||||
Label: "批量提取",
|
||||
Label: "批量字段提取 → Excel",
|
||||
OwnedDefinitionKeys: []string{"skill.batch-extract.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.batch-extract"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "contract-brief",
|
||||
Label: "合同要点提炼",
|
||||
Label: "合同批量审查与提取(提取)",
|
||||
OwnedDefinitionKeys: []string{"skill.contract-brief.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.contract-brief"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "contract-brief",
|
||||
Label: "合同要点提炼",
|
||||
Label: "合同批量审查与提取(提取)",
|
||||
PlanTitle: "合同要点提炼流程",
|
||||
PlanSteps: []string{"识别合同结构", "提炼核心条款", "标记风险事项", "输出摘要版本"},
|
||||
ResultTitle: "合同要点摘要",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "contract-review",
|
||||
Label: "合同审查",
|
||||
Label: "合同批量审查与提取(审查)",
|
||||
OwnedDefinitionKeys: []string{"skill.contract-review.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.contract-review"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package emaildrafting
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "email-drafting",
|
||||
Label: "邮件起草",
|
||||
OwnedDefinitionKeys: []string{"skill.email-drafting.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.email-drafting"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package emaildrafting
|
||||
|
||||
import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "email-drafting",
|
||||
Label: "邮件起草",
|
||||
PlanTitle: "邮件起草流程",
|
||||
PlanSteps: []string{"识别沟通目的", "整理背景与重点", "生成正式邮件", "补充简短跟进版本"},
|
||||
ResultTitle: "邮件草稿",
|
||||
Summary: "已生成一版可直接发送的邮件正文,并补了简短跟进版本和要点摘要。",
|
||||
Highlights: []string{"适合汇报、催办、确认和通知", "兼顾正式语气与清晰表达", "默认沉淀长邮件和短消息版本"},
|
||||
ActionType: "communication",
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "interview-summary",
|
||||
Label: "访谈整理",
|
||||
Label: "招聘简历助手",
|
||||
OwnedDefinitionKeys: []string{"skill.interview-summary.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.interview-summary"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "interview-summary",
|
||||
Label: "访谈整理",
|
||||
Label: "招聘简历助手",
|
||||
PlanTitle: "访谈整理流程",
|
||||
PlanSteps: []string{"归并访谈内容", "提炼主题观点", "总结关键洞察", "输出整理版本"},
|
||||
ResultTitle: "访谈整理稿",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "longform-writing",
|
||||
Label: "长文创作",
|
||||
Label: "公文辅助写作(长文)",
|
||||
OwnedDefinitionKeys: []string{"skill.longform-writing.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.longform-writing"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "longform-writing",
|
||||
Label: "长文创作",
|
||||
Label: "公文辅助写作(长文)",
|
||||
PlanTitle: "长文创作流程",
|
||||
PlanSteps: []string{"明确文体与受众", "规划章节大纲", "生成正文骨架", "整理摘要与交付稿"},
|
||||
ResultTitle: "长文草稿",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "meeting-minutes",
|
||||
Label: "会议纪要",
|
||||
Label: "会议音频分析(纪要)",
|
||||
OwnedDefinitionKeys: []string{"skill.meeting-minutes.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.meeting-minutes"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "meeting-minutes",
|
||||
Label: "会议纪要",
|
||||
Label: "会议音频分析(纪要)",
|
||||
PlanTitle: "会议纪要整理流程",
|
||||
PlanSteps: []string{"识别会议主题", "提炼关键结论", "整理行动项", "输出同步版本"},
|
||||
ResultTitle: "会议纪要草稿",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "mind-map",
|
||||
Label: "思维导图",
|
||||
Label: "会议音频分析(思维导图)",
|
||||
OwnedDefinitionKeys: []string{"skill.mind-map.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.mind-map"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "mind-map",
|
||||
Label: "思维导图",
|
||||
Label: "会议音频分析(思维导图)",
|
||||
PlanTitle: "思维导图生成流程",
|
||||
PlanSteps: []string{"识别主题主线", "拆分一级分支", "补齐关键节点", "整理导图源结构"},
|
||||
ResultTitle: "导图结构草案",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "ocr-understanding",
|
||||
Label: "OCR / 图文理解",
|
||||
Label: "图片/扫描件智能识别",
|
||||
OwnedDefinitionKeys: []string{"skill.ocr-understanding.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.ocr-understanding"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "ocr-understanding",
|
||||
Label: "OCR / 图文理解",
|
||||
Label: "图片/扫描件智能识别",
|
||||
PlanTitle: "图文理解流程",
|
||||
PlanSteps: []string{"识别图像内容", "抽取文字与字段", "整理结构摘要", "输出可复用结果"},
|
||||
ResultTitle: "识别结果摘要",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "policy-rewrite",
|
||||
Label: "制度改写",
|
||||
Label: "公文辅助写作(制度)",
|
||||
OwnedDefinitionKeys: []string{"skill.policy-rewrite.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.policy-rewrite"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "policy-rewrite",
|
||||
Label: "制度改写",
|
||||
Label: "公文辅助写作(制度)",
|
||||
PlanTitle: "制度改写流程",
|
||||
PlanSteps: []string{"识别制度目标", "统一结构口径", "重写正式正文", "补充修订说明"},
|
||||
ResultTitle: "制度改写稿",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "ppt-generation",
|
||||
Label: "PPT 生成",
|
||||
Label: "一键生成 PPT",
|
||||
OwnedDefinitionKeys: []string{"skill.ppt-generation.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.ppt-generation"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "ppt-generation",
|
||||
Label: "PPT 生成",
|
||||
Label: "一键生成 PPT",
|
||||
PlanTitle: "PPT 生成流程",
|
||||
PlanSteps: []string{"确认汇报目标", "规划页面结构", "提炼每页要点", "整理讲稿备注"},
|
||||
ResultTitle: "演示文稿骨架",
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "progress-report",
|
||||
Label: "周报 / 日报",
|
||||
Label: "一键周报",
|
||||
OwnedDefinitionKeys: []string{"skill.progress-report.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.progress-report"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "progress-report",
|
||||
Label: "周报 / 日报",
|
||||
Label: "一键周报",
|
||||
PlanTitle: "进展汇报流程",
|
||||
PlanSteps: []string{"归并本期工作", "提炼关键进展", "整理风险事项", "输出汇报版本"},
|
||||
ResultTitle: "进展汇报草稿",
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package projectplanning
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "project-planning",
|
||||
Label: "项目规划",
|
||||
OwnedDefinitionKeys: []string{"skill.project-planning.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.project-planning"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package projectplanning
|
||||
|
||||
import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "project-planning",
|
||||
Label: "项目规划",
|
||||
PlanTitle: "项目规划流程",
|
||||
PlanSteps: []string{"明确目标边界", "拆解阶段路径", "整理里程碑", "补齐风险与依赖"},
|
||||
ResultTitle: "项目规划草案",
|
||||
Summary: "已把目标拆成阶段计划、里程碑和风险项,方便直接进入执行或评审。",
|
||||
Highlights: []string{"适合启动、排期和推进对齐", "默认沉淀阶段计划与风险清单", "结果适合继续流转到任务治理"},
|
||||
ActionType: "plan",
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package proposalsummary
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "proposal-summary",
|
||||
Label: "方案摘要",
|
||||
OwnedDefinitionKeys: []string{"skill.proposal-summary.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.proposal-summary"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package proposalsummary
|
||||
|
||||
import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "proposal-summary",
|
||||
Label: "方案摘要",
|
||||
PlanTitle: "方案摘要流程",
|
||||
PlanSteps: []string{"识别方案目标", "提炼核心亮点", "压缩实施路径", "输出摘要版本"},
|
||||
ResultTitle: "方案摘要稿",
|
||||
Summary: "已提炼出方案核心结论、价值亮点和实施建议,适合快速汇报或同步。",
|
||||
Highlights: []string{"适合方案汇报和管理层预读", "自动压缩价值点与实施路径", "默认沉淀摘要正文和亮点清单"},
|
||||
ActionType: "summary",
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "report-generation",
|
||||
Label: "报告生成",
|
||||
Label: "一键生成报告",
|
||||
OwnedDefinitionKeys: []string{"skill.report-generation.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.report-generation"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "smart-assistant",
|
||||
Label: "通用助手",
|
||||
Label: "智能助手",
|
||||
OwnedDefinitionKeys: []string{"skill.smart-assistant.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.smart-assistant"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package surveysummary
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "survey-summary",
|
||||
Label: "表单问卷汇总",
|
||||
OwnedDefinitionKeys: []string{"skill.survey-summary.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.survey-summary"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package surveysummary
|
||||
|
||||
import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "survey-summary",
|
||||
Label: "表单问卷汇总",
|
||||
PlanTitle: "问卷汇总流程",
|
||||
PlanSteps: []string{"归并表单结果", "提炼重点发现", "整理问题与建议", "输出汇总版本"},
|
||||
ResultTitle: "问卷汇总稿",
|
||||
Summary: "已整理出表单结果汇总、重点发现和改进建议,方便直接同步给负责人。",
|
||||
Highlights: []string{"适合反馈表、报名表、调查问卷", "自动压缩重点发现和改进建议", "默认沉淀汇总报告和行动建议"},
|
||||
ActionType: "report",
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "table-cleanup",
|
||||
Label: "表格整理",
|
||||
Label: "知识库表格视图",
|
||||
OwnedDefinitionKeys: []string{"skill.table-cleanup.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.table-cleanup"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
|
||||
@@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "table-cleanup",
|
||||
Label: "表格整理",
|
||||
Label: "知识库表格视图",
|
||||
PlanTitle: "表格整理流程",
|
||||
PlanSteps: []string{"识别字段结构", "清洗原始数据", "整理表格内容", "补充字段说明"},
|
||||
ResultTitle: "表格整理结果",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package texttospeech
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "text-to-speech",
|
||||
Label: "文字转语音",
|
||||
OwnedDefinitionKeys: []string{"skill.text-to-speech.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.text-to-speech"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package texttoolkit
|
||||
|
||||
import skillcontracts "eai_agentplatform/backend/internal/skills/contracts"
|
||||
|
||||
var Manifest = skillcontracts.Manifest{
|
||||
Key: "text-toolkit",
|
||||
Label: "文本处理",
|
||||
OwnedDefinitionKeys: []string{"skill.text-toolkit.definition"},
|
||||
OwnedCatalogEntries: []string{"catalog.skill.text-toolkit"},
|
||||
ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package texttoolkit
|
||||
|
||||
import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
|
||||
var OfficeRuntime = officecontracts.Runtime{
|
||||
Key: "text-toolkit",
|
||||
Label: "文本处理",
|
||||
PlanTitle: "文本处理流程",
|
||||
PlanSteps: []string{"识别清洗目标", "去除噪音符号", "统一格式与标点", "输出可复用文本"},
|
||||
ResultTitle: "清洗后文本",
|
||||
Summary: "已完成文本清洗、格式整理和统计,可直接复制或下载结果。",
|
||||
Highlights: []string{"去 Markdown 噪音", "输出文本统计", "适合高频复制到 Word 和 IM"},
|
||||
ActionType: "text",
|
||||
}
|
||||
-106
@@ -98,112 +98,6 @@ func BuildMeetingMinutesArtifacts(inputText string) []gin.H {
|
||||
}
|
||||
}
|
||||
|
||||
func BuildEmailDraftingArtifacts(inputText string) []gin.H {
|
||||
fields, bodyText := parseOfficeFields(inputText, map[string][]string{
|
||||
"recipient": {"收件人", "对象", "recipient", "to"},
|
||||
"cc": {"抄送", "抄送人", "cc"},
|
||||
"topic": {"主题", "标题", "topic", "subject"},
|
||||
"purpose": {"目的", "意图", "purpose"},
|
||||
"action": {"希望对方", "需要对方", "action"},
|
||||
"deadline": {"时间", "截止时间", "deadline"},
|
||||
"tone": {"语气", "风格", "tone", "style"},
|
||||
})
|
||||
topic := firstNonEmpty(fields["topic"], pickOfficeTopic(firstNonEmpty(bodyText, inputText), "邮件主题"))
|
||||
recipient := firstNonEmpty(fields["recipient"], "各位")
|
||||
ccList := splitSimpleList(fields["cc"])
|
||||
purpose := firstNonEmpty(fields["purpose"], "同步背景和当前进展")
|
||||
action := firstNonEmpty(fields["action"], "请协助确认并继续推进")
|
||||
deadline := firstNonEmpty(fields["deadline"], "请尽快反馈")
|
||||
tone := firstNonEmpty(fields["tone"], "正式、明确、礼貌")
|
||||
points := extractOfficePoints(firstNonEmpty(bodyText, inputText), []string{"交代背景和当前情况", "说明希望对方配合或确认的事项", "给出时间点和下一步动作", "保持礼貌但结论清楚"})
|
||||
subjectVariants := buildEmailSubjectVariants(topic, purpose)
|
||||
subject := subjectVariants[0]
|
||||
emailContent := strings.TrimSpace(strings.Join([]string{
|
||||
"主题:" + subject,
|
||||
"收件人:" + recipient,
|
||||
"抄送:" + firstNonEmpty(strings.Join(ccList, "、"), "无"),
|
||||
"",
|
||||
recipient + "好,",
|
||||
"",
|
||||
purpose + "。" + firstNonEmpty(pointAt(points, 0), "这边同步一下当前事项的背景和进展。"),
|
||||
action + "。" + firstNonEmpty(pointAt(points, 1), "目前需要大家协助确认相关事项。"),
|
||||
deadline + "。" + firstNonEmpty(pointAt(points, 2), "如无问题,请按约定时间继续推进。"),
|
||||
"",
|
||||
"语气建议:" + tone + "。如有问题,请直接回复沟通。",
|
||||
"",
|
||||
"谢谢。",
|
||||
}, "\n"))
|
||||
shortContent := strings.TrimSpace(strings.Join([]string{
|
||||
"【" + topic + "】",
|
||||
firstNonEmpty(pointAt(points, 1), "请协助确认相关事项。"),
|
||||
firstNonEmpty(pointAt(points, 2), "如无问题请按时推进。"),
|
||||
}, "\n"))
|
||||
briefContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 邮件要点",
|
||||
"",
|
||||
"- 主题:" + subject,
|
||||
"- " + firstNonEmpty(pointAt(points, 0), "交代背景和当前情况"),
|
||||
"- " + firstNonEmpty(pointAt(points, 1), "说明希望对方配合或确认的事项"),
|
||||
"- " + firstNonEmpty(pointAt(points, 2), "给出时间点和下一步动作"),
|
||||
"- " + firstNonEmpty(pointAt(points, 3), "保持礼貌但结论清楚"),
|
||||
}, "\n"))
|
||||
subjectLines := []string{
|
||||
"# 主题与抄送建议",
|
||||
"",
|
||||
"- 收件人:" + recipient,
|
||||
"- 抄送建议:" + firstNonEmpty(strings.Join(ccList, "、"), "建议抄送直属负责人 / 相关协同方"),
|
||||
"",
|
||||
"## 可选主题",
|
||||
}
|
||||
for index, item := range subjectVariants {
|
||||
subjectLines = append(subjectLines, fmt.Sprintf("%d. %s", index+1, item))
|
||||
}
|
||||
subjectContent := strings.TrimSpace(strings.Join(subjectLines, "\n"))
|
||||
slug := officeSlug(topic, "email-drafting")
|
||||
return []gin.H{
|
||||
{
|
||||
"key": "email",
|
||||
"title": "正式邮件",
|
||||
"description": "可直接复制到邮箱发送的完整版本。",
|
||||
"kind": "text",
|
||||
"fileFormat": "txt",
|
||||
"downloadName": slug + ".txt",
|
||||
"mimeType": "text/plain;charset=utf-8",
|
||||
"content": emailContent,
|
||||
},
|
||||
{
|
||||
"key": "short-followup",
|
||||
"title": "简短跟进版",
|
||||
"description": "适合发到 IM 或群里的短消息版本。",
|
||||
"kind": "text",
|
||||
"fileFormat": "txt",
|
||||
"downloadName": slug + "-short.txt",
|
||||
"mimeType": "text/plain;charset=utf-8",
|
||||
"content": shortContent,
|
||||
},
|
||||
{
|
||||
"key": "brief",
|
||||
"title": "邮件要点",
|
||||
"description": "方便审批或复核邮件口径的要点版。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-brief.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": briefContent,
|
||||
},
|
||||
{
|
||||
"key": "subject-variants",
|
||||
"title": "主题与抄送建议",
|
||||
"description": "提供多版主题候选和抄送建议。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-subject.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": subjectContent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BuildProgressReportArtifacts(inputText string) []gin.H {
|
||||
topic := pickOfficeTopic(inputText, "进展汇报")
|
||||
points := extractOfficePoints(inputText, []string{"本期完成的关键工作", "当前风险和阻塞项", "需要协同支持的事项", "下一步计划"})
|
||||
|
||||
@@ -114,109 +114,6 @@ func BuildMindMapArtifacts(inputText string) []gin.H {
|
||||
}
|
||||
}
|
||||
|
||||
func BuildProjectPlanningArtifacts(inputText string) []gin.H {
|
||||
fields, bodyText := parseOfficeFields(inputText, map[string][]string{
|
||||
"topic": {"项目", "项目名称", "主题", "topic"},
|
||||
"deadline": {"时间要求", "截止时间", "deadline"},
|
||||
"owner": {"负责人", "owner"},
|
||||
"goal": {"目标", "goal"},
|
||||
"start": {"开始时间", "启动时间", "start"},
|
||||
})
|
||||
topic := firstNonEmpty(fields["topic"], pickOfficeTopic(firstNonEmpty(bodyText, inputText), "项目规划"))
|
||||
deadline := firstNonEmpty(fields["deadline"], "待确认")
|
||||
owner := firstNonEmpty(fields["owner"], "待指定")
|
||||
goal := firstNonEmpty(fields["goal"], "先明确目标、阶段、依赖和协同方式")
|
||||
start := firstNonEmpty(fields["start"], "尽快启动")
|
||||
points := extractOfficePoints(firstNonEmpty(bodyText, inputText), []string{"明确目标、范围和成功标准", "梳理关键里程碑与交付节点", "安排执行分工与协同节奏", "识别风险与外部依赖"})
|
||||
stageRows := buildProjectStageRows(points, owner, deadline)
|
||||
planContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# " + topic,
|
||||
"",
|
||||
"## 项目目标",
|
||||
fmt.Sprintf("围绕“%s”整理一版可执行的项目规划,先确保目标、阶段和依赖都清楚。", topic),
|
||||
"- 负责人:" + owner,
|
||||
"- 启动时间:" + start,
|
||||
"- 时间要求:" + deadline,
|
||||
"- 总体目标:" + goal,
|
||||
"",
|
||||
"## 阶段安排",
|
||||
"### 阶段 1:启动与对齐",
|
||||
"- " + firstNonEmpty(pointAt(points, 0), "明确目标和边界"),
|
||||
"### 阶段 2:执行与推进",
|
||||
"- " + firstNonEmpty(pointAt(points, 1), "推进关键里程碑和核心交付"),
|
||||
"### 阶段 3:验收与收口",
|
||||
"- " + firstNonEmpty(pointAt(points, 2), "完成验收、复盘和沉淀"),
|
||||
}, "\n"))
|
||||
milestoneContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 里程碑清单",
|
||||
"",
|
||||
"1. M1:" + firstNonEmpty(pointAt(points, 0), "明确目标和边界"),
|
||||
"2. M2:" + firstNonEmpty(pointAt(points, 1), "推进关键里程碑和核心交付"),
|
||||
"3. M3:" + firstNonEmpty(pointAt(points, 2), "完成验收、复盘和沉淀"),
|
||||
"4. M4:" + firstNonEmpty(pointAt(points, 3), "确认依赖和外部配合事项"),
|
||||
}, "\n"))
|
||||
riskContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 风险与依赖",
|
||||
"",
|
||||
"- 风险 1:" + firstNonEmpty(pointAt(points, 3), "关键依赖尚未完全明确"),
|
||||
"- 风险 2:跨团队协同节奏可能影响排期",
|
||||
"- 建议:将关键依赖提前前置到周会或启动会确认",
|
||||
}, "\n"))
|
||||
scheduleLines := []string{
|
||||
"# 阶段排期表",
|
||||
"",
|
||||
"| 阶段 | 时间窗 | 负责人 | 目标 | 交付物 |",
|
||||
"| --- | --- | --- | --- | --- |",
|
||||
}
|
||||
for _, item := range stageRows {
|
||||
scheduleLines = append(scheduleLines, fmt.Sprintf("| %s | %s | %s | %s | %s |", asString(item["stage"]), asString(item["window"]), asString(item["owner"]), asString(item["goal"]), asString(item["output"])))
|
||||
}
|
||||
scheduleContent := strings.TrimSpace(strings.Join(scheduleLines, "\n"))
|
||||
slug := officeSlug(topic, "project-planning")
|
||||
return []gin.H{
|
||||
{
|
||||
"key": "project-plan",
|
||||
"title": "项目计划",
|
||||
"description": "适合直接评审和继续细化的主计划。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + ".md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": planContent,
|
||||
},
|
||||
{
|
||||
"key": "milestones",
|
||||
"title": "里程碑清单",
|
||||
"description": "关键节点和交付节奏的简洁版列表。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-milestones.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": milestoneContent,
|
||||
},
|
||||
{
|
||||
"key": "risks",
|
||||
"title": "风险清单",
|
||||
"description": "项目推进前需要确认的风险与依赖。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-risks.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": riskContent,
|
||||
},
|
||||
{
|
||||
"key": "schedule",
|
||||
"title": "阶段排期表",
|
||||
"description": "更接近甘特视角的阶段、时间窗和交付物表。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-schedule.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": scheduleContent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTableCleanupArtifacts(inputText string) []gin.H {
|
||||
fields, bodyText := parseOfficeFields(inputText, map[string][]string{
|
||||
"topic": {"主题", "标题", "topic", "title"},
|
||||
|
||||
@@ -58,115 +58,6 @@ func BuildLongformArtifacts(inputText string) []gin.H {
|
||||
}
|
||||
}
|
||||
|
||||
func BuildTextToolkitArtifacts(inputText string) []gin.H {
|
||||
cleaned := stripMarkdownText(inputText)
|
||||
stats := strings.Join([]string{
|
||||
"# 文本统计",
|
||||
"",
|
||||
fmt.Sprintf("- 字符数:%d", len([]rune(cleaned))),
|
||||
fmt.Sprintf("- 行数:%d", len(splitMeaningfulLines(cleaned))),
|
||||
fmt.Sprintf("- 原始长度:%d", len([]rune(strings.TrimSpace(inputText)))),
|
||||
"",
|
||||
"## 处理说明",
|
||||
"- 已移除常见 Markdown 标记",
|
||||
"- 已压缩多余空行",
|
||||
"- 已保留正文可读性",
|
||||
}, "\n")
|
||||
slug := officeSlug(pickOfficeTopic(inputText, "cleaned-text"), "text-toolkit")
|
||||
return []gin.H{
|
||||
{
|
||||
"key": "cleaned",
|
||||
"title": "清洗后文本",
|
||||
"description": "适合直接粘贴到文档或聊天工具。",
|
||||
"kind": "text",
|
||||
"fileFormat": "txt",
|
||||
"downloadName": slug + ".txt",
|
||||
"mimeType": "text/plain;charset=utf-8",
|
||||
"content": cleaned,
|
||||
},
|
||||
{
|
||||
"key": "stats",
|
||||
"title": "文本统计",
|
||||
"description": "记录本次清洗和统计结果。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-stats.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": stats,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BuildProposalSummaryArtifacts(inputText string) []gin.H {
|
||||
topic := pickOfficeTopic(inputText, "方案摘要")
|
||||
points := extractOfficePoints(inputText, []string{"明确方案目标和解决的问题", "提炼核心价值与收益", "压缩关键实施路径", "明确需要决策的事项"})
|
||||
summaryContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# " + topic,
|
||||
"",
|
||||
"## 核心结论",
|
||||
fmt.Sprintf("%s 已压缩为适合汇报和快速预读的摘要版本,重点保留目标、价值点和实施建议。", topic),
|
||||
"",
|
||||
"## 关键亮点",
|
||||
"- " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"),
|
||||
"- " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"),
|
||||
"- " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"),
|
||||
"- " + firstNonEmpty(pointAt(points, 3), "明确需要决策的事项"),
|
||||
"",
|
||||
"## 实施建议",
|
||||
"- 建议先确认资源与排期",
|
||||
"- 建议围绕高优先级场景先落一版 MVP",
|
||||
"- 建议同步关键负责人做进一步评审",
|
||||
}, "\n"))
|
||||
highlightsContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 亮点清单",
|
||||
"",
|
||||
"1. " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"),
|
||||
"2. " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"),
|
||||
"3. " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"),
|
||||
"4. " + firstNonEmpty(pointAt(points, 3), "明确需要决策的事项"),
|
||||
}, "\n"))
|
||||
briefingContent := strings.TrimSpace(strings.Join([]string{
|
||||
"【" + topic + " 摘要】",
|
||||
"1. " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"),
|
||||
"2. " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"),
|
||||
"3. " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"),
|
||||
"建议按上述结论进入下一步决策或评审。",
|
||||
}, "\n"))
|
||||
slug := officeSlug(topic, "proposal-summary")
|
||||
return []gin.H{
|
||||
{
|
||||
"key": "summary",
|
||||
"title": "方案摘要",
|
||||
"description": "适合直接汇报或继续细化的主摘要。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + ".md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": summaryContent,
|
||||
},
|
||||
{
|
||||
"key": "highlights",
|
||||
"title": "亮点清单",
|
||||
"description": "压缩提炼后的价值点列表。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-highlights.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": highlightsContent,
|
||||
},
|
||||
{
|
||||
"key": "briefing",
|
||||
"title": "汇报短版",
|
||||
"description": "适合发群或口头汇报前快速同步的短摘要。",
|
||||
"kind": "text",
|
||||
"fileFormat": "txt",
|
||||
"downloadName": slug + "-briefing.txt",
|
||||
"mimeType": "text/plain;charset=utf-8",
|
||||
"content": briefingContent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BuildContractBriefArtifacts(inputText string) []gin.H {
|
||||
fields, bodyText := parseOfficeFields(inputText, map[string][]string{
|
||||
"topic": {"合同名称", "主题", "topic"},
|
||||
@@ -422,67 +313,3 @@ func BuildPolicyRewriteArtifacts(inputText string) []gin.H {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BuildSurveySummaryArtifacts(inputText string) []gin.H {
|
||||
topic := pickOfficeTopic(inputText, "问卷汇总")
|
||||
points := extractOfficePoints(inputText, []string{"参与者的主要反馈方向", "高频问题或不满意点", "值得保留的积极反馈", "后续改进建议"})
|
||||
reportContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# " + topic,
|
||||
"",
|
||||
"## 汇总结论",
|
||||
"- " + firstNonEmpty(pointAt(points, 0), "参与者的主要反馈方向"),
|
||||
"- " + firstNonEmpty(pointAt(points, 1), "高频问题或不满意点"),
|
||||
"- " + firstNonEmpty(pointAt(points, 2), "值得保留的积极反馈"),
|
||||
"- " + firstNonEmpty(pointAt(points, 3), "后续改进建议"),
|
||||
"",
|
||||
"## 汇总说明",
|
||||
"已把表单和问卷结果压缩成便于阅读和决策的汇总结论。",
|
||||
}, "\n"))
|
||||
findingsContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 重点发现",
|
||||
"",
|
||||
"- 发现 1:" + firstNonEmpty(pointAt(points, 0), "参与者主要关注体验和执行效果"),
|
||||
"- 发现 2:" + firstNonEmpty(pointAt(points, 1), "部分问题集中在流程或内容安排上"),
|
||||
"- 发现 3:" + firstNonEmpty(pointAt(points, 2), "已有若干积极反馈值得继续保留"),
|
||||
}, "\n"))
|
||||
actionsContent := strings.TrimSpace(strings.Join([]string{
|
||||
"# 改进建议",
|
||||
"",
|
||||
"- [ ] " + firstNonEmpty(pointAt(points, 3), "根据汇总结果制定下一步改进动作"),
|
||||
"- [ ] 对高频问题安排专项优化",
|
||||
"- [ ] 向负责人同步汇总结论和优先级建议",
|
||||
}, "\n"))
|
||||
slug := officeSlug(topic, "survey-summary")
|
||||
return []gin.H{
|
||||
{
|
||||
"key": "report",
|
||||
"title": "汇总报告",
|
||||
"description": "适合直接汇报或继续细化的主报告。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + ".md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": reportContent,
|
||||
},
|
||||
{
|
||||
"key": "findings",
|
||||
"title": "重点发现",
|
||||
"description": "从表单结果中提炼出的关键发现。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-findings.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": findingsContent,
|
||||
},
|
||||
{
|
||||
"key": "actions",
|
||||
"title": "改进建议",
|
||||
"description": "建议后续继续推进的改进行动。",
|
||||
"kind": "text",
|
||||
"fileFormat": "md",
|
||||
"downloadName": slug + "-actions.md",
|
||||
"mimeType": "text/markdown;charset=utf-8",
|
||||
"content": actionsContent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package office
|
||||
|
||||
import (
|
||||
contractbrief "eai_agentplatform/backend/internal/skills/packages/contract_brief"
|
||||
emaildrafting "eai_agentplatform/backend/internal/skills/packages/email_drafting"
|
||||
interviewsummary "eai_agentplatform/backend/internal/skills/packages/interview_summary"
|
||||
longformwriting "eai_agentplatform/backend/internal/skills/packages/longform_writing"
|
||||
meetingminutes "eai_agentplatform/backend/internal/skills/packages/meeting_minutes"
|
||||
@@ -11,11 +10,7 @@ import (
|
||||
policyrewrite "eai_agentplatform/backend/internal/skills/packages/policy_rewrite"
|
||||
pptgeneration "eai_agentplatform/backend/internal/skills/packages/ppt_generation"
|
||||
progressreport "eai_agentplatform/backend/internal/skills/packages/progress_report"
|
||||
projectplanning "eai_agentplatform/backend/internal/skills/packages/project_planning"
|
||||
proposalsummary "eai_agentplatform/backend/internal/skills/packages/proposal_summary"
|
||||
surveysummary "eai_agentplatform/backend/internal/skills/packages/survey_summary"
|
||||
tablecleanup "eai_agentplatform/backend/internal/skills/packages/table_cleanup"
|
||||
texttoolkit "eai_agentplatform/backend/internal/skills/packages/text_toolkit"
|
||||
officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -29,18 +24,13 @@ var builtinRegistry = NewRegistry(
|
||||
withBuild(pptgeneration.OfficeRuntime, BuildPPTArtifacts),
|
||||
withBuild(mindmap.OfficeRuntime, BuildMindMapArtifacts),
|
||||
withBuild(longformwriting.OfficeRuntime, BuildLongformArtifacts),
|
||||
withBuild(texttoolkit.OfficeRuntime, BuildTextToolkitArtifacts),
|
||||
ocrunderstanding.OfficeRuntime,
|
||||
withBuild(meetingminutes.OfficeRuntime, BuildMeetingMinutesArtifacts),
|
||||
withBuild(projectplanning.OfficeRuntime, BuildProjectPlanningArtifacts),
|
||||
withBuild(emaildrafting.OfficeRuntime, BuildEmailDraftingArtifacts),
|
||||
withBuild(tablecleanup.OfficeRuntime, BuildTableCleanupArtifacts),
|
||||
withBuild(proposalsummary.OfficeRuntime, BuildProposalSummaryArtifacts),
|
||||
withBuild(progressreport.OfficeRuntime, BuildProgressReportArtifacts),
|
||||
withBuild(contractbrief.OfficeRuntime, BuildContractBriefArtifacts),
|
||||
withBuild(interviewsummary.OfficeRuntime, BuildInterviewSummaryArtifacts),
|
||||
withBuild(policyrewrite.OfficeRuntime, BuildPolicyRewriteArtifacts),
|
||||
withBuild(surveysummary.OfficeRuntime, BuildSurveySummaryArtifacts),
|
||||
)
|
||||
|
||||
func BuiltinRegistry() *Registry {
|
||||
|
||||
@@ -71,26 +71,6 @@ func parseMeetingActions(text string, fallback []string) []gin.H {
|
||||
return out
|
||||
}
|
||||
|
||||
func buildEmailSubjectVariants(topic, purpose string) []string {
|
||||
base := firstNonEmpty(topic, "事项")
|
||||
context := strings.TrimSpace(purpose)
|
||||
items := []string{
|
||||
base + " - 请协助确认",
|
||||
base + " - 需要回复",
|
||||
base + " - 进展同步",
|
||||
}
|
||||
if context != "" {
|
||||
runes := []rune(context)
|
||||
if len(runes) > 12 {
|
||||
context = string(runes[:12])
|
||||
}
|
||||
items = append(items, base+" - "+context)
|
||||
} else {
|
||||
items = append(items, base+" - 待处理提醒")
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func formatMeetingActionLine(actions []gin.H, index int) string {
|
||||
if index < 0 || index >= len(actions) {
|
||||
return fmt.Sprintf("%d. 待补充行动项", index+1)
|
||||
@@ -149,29 +129,3 @@ func buildContractRedlineItems(points, focusKeywords []string) []gin.H {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func stripMarkdownText(text string) string {
|
||||
text = strings.ReplaceAll(text, "\r", "\n")
|
||||
blockCode := regexp.MustCompile("```[\\s\\S]*?```")
|
||||
text = blockCode.ReplaceAllStringFunc(text, func(value string) string {
|
||||
return strings.TrimSpace(strings.ReplaceAll(value, "```", ""))
|
||||
})
|
||||
replacers := []struct {
|
||||
pattern string
|
||||
value string
|
||||
}{
|
||||
{"`([^`]+)`", "$1"},
|
||||
{"^#{1,6}\\s+", ""},
|
||||
{"^\\s*[-*+]\\s+", ""},
|
||||
{"^\\s*\\d+[.)]\\s+", ""},
|
||||
{"\\*\\*(.*?)\\*\\*", "$1"},
|
||||
{"\\*(.*?)\\*", "$1"},
|
||||
{"!\\[[^\\]]*\\]\\([^)]*\\)", ""},
|
||||
{"\\[([^\\]]+)\\]\\(([^)]*)\\)", "$1"},
|
||||
}
|
||||
for _, item := range replacers {
|
||||
text = regexp.MustCompile(item.pattern).ReplaceAllString(text, item.value)
|
||||
}
|
||||
text = regexp.MustCompile(`\n{3,}`).ReplaceAllString(text, "\n\n")
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
@@ -217,31 +217,6 @@ func splitSimpleList(value string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func buildProjectStageRows(points []string, owner, deadline string) []gin.H {
|
||||
labels := []string{"阶段 1", "阶段 2", "阶段 3", "阶段 4"}
|
||||
windows := []string{"第 1 周", "第 2 周", "第 3 周", firstNonEmpty(deadline, "收口前")}
|
||||
rows := make([]gin.H, 0, len(labels))
|
||||
for index, label := range labels {
|
||||
output := "收口结论"
|
||||
switch index {
|
||||
case 0:
|
||||
output = "目标确认"
|
||||
case 1:
|
||||
output = "阶段交付"
|
||||
case 2:
|
||||
output = "验收材料"
|
||||
}
|
||||
rows = append(rows, gin.H{
|
||||
"stage": label,
|
||||
"window": windows[index],
|
||||
"goal": firstNonEmpty(pointAt(points, index), "补充"+label+"目标"),
|
||||
"owner": firstNonEmpty(owner, "待指定"),
|
||||
"output": output,
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func repeatString(value string, count int) []string {
|
||||
items := make([]string, 0, count)
|
||||
for index := 0; index < count; index++ {
|
||||
|
||||
Reference in New Issue
Block a user