package text import ( "context" "fmt" "regexp" "strings" "unicode" "git.yeij.top/AskaEth/Cyrene-Plugins/sdk" ) type TextPlugin struct{ sdk.BasePlugin } func (p *TextPlugin) Metadata() sdk.PluginMetadata { return sdk.PluginMetadata{ Name: "text", DisplayName: "Text Processing", Version: "1.0.0", Description: "Text processing: count stats, summarize, regex extract", Category: "utility", Author: sdk.PluginAuthor{Name: "Cyrene Team"}, } } func (p *TextPlugin) Tools() []sdk.Tool { return []sdk.Tool{&TextTool{}} } type TextTool struct{ sdk.BaseTool } func (t *TextTool) Definition() sdk.ToolDefinition { return sdk.ToolDefinition{ ID: "text", Name: "text", DisplayName: "Text Processing", Description: "Text processing. Count stats, summarize, translate, regex extract.", Category: "utility", Complexity: sdk.ComplexitySimple, Parameters: map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "action": map[string]interface{}{"type": "string", "enum": []string{"count", "summarize", "translate", "extract"}}, "text": map[string]interface{}{"type": "string"}, "target_lang": map[string]interface{}{"type": "string", "enum": []string{"en", "zh", "ja", "ko", "fr", "de"}}, "pattern": map[string]interface{}{"type": "string"}, }, "required": []string{"action", "text"}, }, } } func (t *TextTool) Validate(args map[string]interface{}) error { for _, k := range []string{"action", "text"} { if _, ok := args[k]; !ok { return fmt.Errorf("missing required parameter: %s", k) } } return nil } func (t *TextTool) Execute(_ context.Context, args map[string]interface{}) (*sdk.ToolResult, error) { action, _ := args["action"].(string) txt, _ := args["text"].(string) switch action { case "count": charsNoSpace := 0 chineseChars := 0 for _, r := range txt { if !unicode.IsSpace(r) { charsNoSpace++ } if unicode.Is(unicode.Han, r) { chineseChars++ } } words := strings.Fields(txt) lines := strings.Split(txt, "\n") paragraphs := regexp.MustCompile(`\n\s*\n`).Split(txt, -1) return &sdk.ToolResult{ToolName: "text", Success: true, Output: fmt.Sprintf( "Characters: %d (no spaces: %d, Chinese: %d)\nBytes: %d\nWords: %d\nLines: %d\nParagraphs: %d", len([]rune(txt)), charsNoSpace, chineseChars, len(txt), len(words), len(lines), len(paragraphs))}, nil case "summarize": paragraphs := regexp.MustCompile(`\n\s*\n`).Split(txt, -1) firstPara := "" if len(paragraphs) > 0 { runes := []rune(paragraphs[0]) if len(runes) > 300 { runes = runes[:300] } firstPara = string(runes) } sentences := regexp.MustCompile(`[。!?.!?]+`).Split(txt, -1) keywords := []string{"重要", "关键", "因此", "总结", "important", "key", "conclusion", "therefore"} type scored struct { text string score int } var scoredSents []scored for _, s := range sentences { s = strings.TrimSpace(s) if len([]rune(s)) < 10 { continue } score := len([]rune(s)) for _, kw := range keywords { if strings.Contains(strings.ToLower(s), strings.ToLower(kw)) { score += 20 } } scoredSents = append(scoredSents, scored{s, score}) } var out strings.Builder out.WriteString(fmt.Sprintf("First paragraph: %s\n\nKey sentences:\n", firstPara)) count := 0 for i := 0; i < len(scoredSents) && count < 5; i++ { out.WriteString(fmt.Sprintf("- %s\n", scoredSents[i].text)) count++ } return &sdk.ToolResult{ToolName: "text", Success: true, Output: out.String()}, nil case "translate": targetLang, _ := args["target_lang"].(string) if targetLang == "" { targetLang = "en" } return &sdk.ToolResult{ToolName: "text", Success: true, Output: fmt.Sprintf( "[Translation request] Please translate the following text to %s.\n\nOriginal text:\n%s", targetLang, txt)}, nil case "extract": pattern, _ := args["pattern"].(string) var out strings.Builder extracted := false if pattern == "" || pattern == "email" { re := regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`) if matches := re.FindAllString(txt, -1); len(matches) > 0 { out.WriteString("Emails:\n") for _, m := range matches { out.WriteString(fmt.Sprintf("- %s\n", m)) } extracted = true } } if pattern == "" || pattern == "phone" { re := regexp.MustCompile(`1[3-9]\d{9}`) if matches := re.FindAllString(txt, -1); len(matches) > 0 { out.WriteString("Phone numbers:\n") for _, m := range matches { out.WriteString(fmt.Sprintf("- %s\n", m)) } extracted = true } } if pattern == "" || pattern == "url" { re := regexp.MustCompile(`https?://[^\s<>"{}|\\^` + "`" + `\[\]]+`) if matches := re.FindAllString(txt, -1); len(matches) > 0 { out.WriteString("URLs:\n") for _, m := range matches { out.WriteString(fmt.Sprintf("- %s\n", m)) } extracted = true } } if !extracted && pattern != "" && pattern != "email" && pattern != "phone" && pattern != "url" { re, err := regexp.Compile(pattern) if err != nil { return &sdk.ToolResult{ToolName: "text", Success: false, Error: "Invalid regex: " + err.Error()}, nil } if matches := re.FindAllString(txt, -1); len(matches) > 0 { out.WriteString(fmt.Sprintf("Pattern matches (%s):\n", pattern)) for _, m := range matches { out.WriteString(fmt.Sprintf("- %s\n", m)) } extracted = true } } if !extracted { return &sdk.ToolResult{ToolName: "text", Success: true, Output: "No matches found"}, nil } return &sdk.ToolResult{ToolName: "text", Success: true, Output: out.String()}, nil } return &sdk.ToolResult{ToolName: "text", Success: false, Error: "unknown action: " + action}, nil }