golang跨平台聊天机器人开发框架插件库go-sarah的使用

Golang跨平台聊天机器人开发框架插件库go-sarah的使用

介绍

Sarah是一个通用机器人框架,以作者第一个女儿的名字命名。它提供了"有状态命令"等独特功能,以及命令和定时任务等基本功能。此外,该项目还提供丰富的生命周期管理功能,包括实时配置更新、可定制的警报机制、自动命令/任务(重新)构建和防panic的并发命令/任务执行。

重要通知

v4版本发布

这是go-sarah的第四个主要版本,包含一些架构变更:

  • sarah.NewBot现在返回单个值:sarah.Bot
  • 包括logger、retry和worker在内的实用包现在由github.com/oklahomer/go-kasumi托管

支持的聊天服务/协议

虽然开发者可以实现sarah.Adapter来集成所需的聊天服务,但项目提供了一些适配器作为参考实现:

  • Slack
  • Gitter
  • XMPP
  • LINE

快速入门

一般命令执行

hello world

上图展示了go-sarah的一般用法。注册的命令会检查用户输入,匹配的命令会被执行;当用户输入".hello"时,hello命令执行并返回"Hello, 世界"消息。

有状态命令执行

下图展示了带有用户对话上下文的命令如何工作。"用户对话上下文"的想法和实现是go-sarah的标志性功能,使机器人命令具有"状态感知"能力。

todo示例

猜数字示例

示例代码

以下是实现上述一般命令和有状态命令的最小代码示例。这个例子展示了两种实现sarah.Command的方式:一种是直接实现sarah.Command接口;另一种使用sarah.CommandPropsBuilder进行延迟构造。

主程序

package main

import (
	"context"
	"fmt"
	"github.com/oklahomer/go-sarah/v4"
	"github.com/oklahomer/go-sarah/v4/slack"
	
	"os"
	"os/signal"
	"syscall"
	
	// 下面的包在init()中注册命令
	// 使用空白标识符导入即可实现
	_ "guess"
	_ "hello"
)

func main() {
	// 设置Slack适配器
	setupSlack()
	
	// 准备Sarah的核心上下文
	ctx, cancel := context.WithCancel(context.Background())

	// 运行
	config := sarah.NewConfig()
	err := sarah.Run(ctx, config)
	if err != nil {
		panic(fmt.Errorf("failed to run: %s", err.Error()))
	}
	
	// 当收到信号时停止
	c := make(chan os.Signal, 1)
   	signal.Notify(c, syscall.SIGTERM)
   	select {
   	case <-c:
   		cancel()
   	}
}

func setupSlack() {
	// 设置slack适配器
	slackConfig := slack.NewConfig()
	slackConfig.Token = "REPLACE THIS"
	adapter, err := slack.NewAdapter(slackConfig, slack.WithRTMPayloadHandler(slack.DefaultRTMPayloadHandler))
	if err != nil {
		panic(fmt.Errorf("faileld to setup Slack Adapter: %s", err.Error()))
	}

	// 设置可选存储,以便存储对话上下文
	cacheConfig := sarah.NewCacheConfig()
	storage := sarah.NewUserContextStorage(cacheConfig)

	// 使用Slack适配器和默认存储设置机器人
	bot := sarah.NewBot(adapter, sarah.BotWithStorage(storage))
	
	sarah.RegisterBot(bot)
}

猜数字命令实现

package guess

import (
	"context"
	"github.com/oklahomer/go-sarah/v4"
	"github.com/oklahomer/go-sarah/v4/slack"
	"math/rand"
	"strconv"
	"strings"
	"time"
)

func init() {
	sarah.RegisterCommandProps(props)
}

var props = sarah.NewCommandPropsBuilder().
	BotType(slack.SLACK).
	Identifier("guess").
	Instruction("Input .guess to start a game.").
	MatchFunc(func(input sarah.Input) bool {
		return strings.HasPrefix(strings.TrimSpace(input.Message()), ".guess")
	}).
	Func(func(ctx context.Context, input sarah.Input) (*sarah.CommandResponse, error) {
		// 在开始时生成答案值
		rand.Seed(time.Now().UnixNano())
		answer := rand.Intn(10)

		// 让用户猜测正确答案
		return slack.NewResponse(input, "Input number.", slack.RespWithNext(func(c context.Context, i sarah.Input) (*sarah.CommandResponse, error){
			return guessFunc(c, i, answer)
		}))
	}).
	MustBuild()

func guessFunc(_ context.Context, input sarah.Input, answer int) (*sarah.CommandResponse, error) {
	// 为了方便,创建一个递归调用guessFunc的函数,直到用户输入正确答案
	retry := func(c context.Context, i sarah.Input) (*sarah.CommandResponse, error) {
		return guessFunc(c, i, answer)
	}

	// 检查用户是否输入了有效数字
	guess, err := strconv.Atoi(strings.TrimSpace(input.Message()))
	if err != nil {
		return slack.NewResponse(input, "Invalid input format.", slack.RespWithNext(retry))
	}

	// 如果猜对了,告诉用户并结束当前用户上下文
	// 否则,让用户输入下一个猜测并给出提示
	if guess == answer {
		return slack.NewResponse(input, "Correct!")
	} else if guess > answer {
		return slack.NewResponse(input, "Smaller!", slack.RespWithNext(retry))
	} else {
		return slack.NewResponse(input, "Bigger!", slack.RespWithNext(retry))
	}
}

Hello命令实现

package hello

import (
	"context"
	"github.com/oklahomer/go-sarah/v4"
	"github.com/oklahomer/go-sarah/v4/slack"
	"strings"
)

func init() {
    sarah.RegisterCommand(slack.SLACK, &command{})	
}

type command struct {
}

var _ sarah.Command = (*command)(nil)

func (hello *command) Identifier() string {
	return "hello"
}

func (hello *command) Execute(_ context.Context, i sarah.Input) (*sarah.CommandResponse, error) {
	return slack.NewResponse(i, "Hello!")
}

func (hello *command) Instruction(input *sarah.HelpInput) string {
	if 12 < input.SentAt().Hour() {
		// 此命令仅在上午活动
		// 下午不显示指令
		return ""
	}
	return "Input .hello to greet"
}

func (hello *command) Match(input sarah.Input) bool {
	return strings.TrimSpace(input.Message()) == ".hello"
}

支持的Golang版本

官方发布策略规定"每个主要的Go版本支持到有两个更新的主要版本发布为止"。遵循这一策略有助于本项目享受后续版本中的改进。然而,并非所有项目都能立即切换到新环境。特别是当本项目在新的主要Go版本发布后立即切断对旧版本的支持时,迁移可能会特别困难。

作为过渡期,本项目比Go项目多支持一个旧版本。这样的版本保证会列在.travis.ci中。换句话说,1.10中引入的新功能/接口只有等到1.12发布后才能在本项目中使用。


更多关于golang跨平台聊天机器人开发框架插件库go-sarah的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨平台聊天机器人开发框架插件库go-sarah的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-sarah: Golang跨平台聊天机器人开发框架

go-sarah是一个轻量级的Golang聊天机器人框架,支持多平台集成,包括Slack、LINE、Gitter等。它提供了插件化架构,使得开发者可以轻松扩展功能。

核心特性

  1. 多平台支持:统一接口对接不同聊天平台
  2. 插件系统:模块化开发,易于扩展
  3. 定时任务:支持定时消息推送
  4. 上下文管理:维护用户会话状态
  5. 配置热加载:无需重启即可更新配置

基本使用示例

安装

go get github.com/oklahomer/go-sarah/v4

简单机器人示例

package main

import (
	"context"
	"github.com/oklahomer/go-sarah/v4"
	"github.com/oklahomer/go-sarah/v4/slack"
	"os"
	"os/signal"
)

func main() {
	// 创建上下文
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// 配置Slack适配器
	slackConfig := slack.NewConfig()
	slackConfig.Token = "xoxb-your-slack-token" // 替换为你的Slack token

	// 创建Slack适配器
	adapter, err := slack.NewAdapter(slackConfig)
	if err != nil {
		panic(err)
	}

	// 创建机器人核心
	bot := sarah.NewBot(adapter)

	// 注册一个简单的"ping"命令
	pingCommand := &sarah.Command{
		Match: func(input sarah.Input) bool {
			return input.Message() == "ping"
		},
		Func: func(ctx context.Context, input sarah.Input) (*sarah.CommandResponse, error) {
			return &sarah.CommandResponse{
				Content: "pong",
			}, nil
		},
	}

	// 将命令添加到机器人
	bot.AppendCommand(pingCommand)

	// 启动机器人
	go func() {
		if err := sarah.Run(ctx, bot); err != nil {
			panic(err)
		}
	}()

	// 等待中断信号
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt)
	<-sigChan
}

插件开发

go-sarah的强大之处在于其插件系统。下面是一个更复杂的插件示例:

package main

import (
	"context"
	"github.com/oklahomer/go-sarah/v4"
	"github.com/oklahomer/go-sarah/v4/slack"
	"os"
	"os/signal"
	"time"
)

// 定义一个天气插件
type WeatherPlugin struct{}

func (p *WeatherPlugin) Name() string {
	return "weather"
}

func (p *WeatherPlugin) Match(input sarah.Input) bool {
	return input.Message() == "weather"
}

func (p *WeatherPlugin) Execute(ctx context.Context, input sarah.Input) (*sarah.CommandResponse, error) {
	// 这里可以调用天气API获取实时天气
	return &sarah.CommandResponse{
		Content: "当前天气: 晴朗, 25°C",
	}, nil
}

func (p *WeatherPlugin) DefaultResponse(input sarah.Input) string {
	return "输入'weather'获取天气信息"
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// 配置Slack
	slackConfig := slack.NewConfig()
	slackConfig.Token = "xoxb-your-slack-token"

	adapter, err := slack.NewAdapter(slackConfig)
	if err != nil {
		panic(err)
	}

	bot := sarah.NewBot(adapter)
	
	// 注册天气插件
	bot.AppendCommand(&WeatherPlugin{})

	// 添加定时任务
	bot.Schedule(sarah.NewScheduleTask(
		"morning_greeting",
		"0 9 * * *", // 每天上午9点
		func(_ context.Context) ([]*sarah.ScheduledTaskResult, error) {
			return []*sarah.ScheduledTaskResult{
				{
					Content:     "早上好!今天是" + time.Now().Format("2006-01-02"),
					Destination: sarah.Broadcast, // 广播到所有频道
				},
			}, nil
		},
	))

	go func() {
		if err := sarah.Run(ctx, bot); err != nil {
			panic(err)
		}
	}()

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt)
	<-sigChan
}

配置热加载

go-sarah支持配置热加载,可以在运行时更新配置:

// 创建配置存储
storage := sarah.NewUserContextStorage(sarah.NewCacheConfig())

// 创建配置监视器
watcher, err := sarah.NewConfigWatcher(".", "*.yml", time.Minute)
if err != nil {
    panic(err)
}

// 启动机器人时传入配置监视器
sarah.RunWithOptions(ctx, []sarah.Bot{bot}, sarah.WithConfigWatcher(watcher))

多平台支持

go-sarah支持多种聊天平台,只需更换适配器:

// LINE适配器示例
lineConfig := line.NewConfig()
lineConfig.ChannelSecret = "your-channel-secret"
lineConfig.ChannelToken = "your-channel-token"
adapter, err := line.NewAdapter(lineConfig)

// Gitter适配器示例
gitterConfig := gitter.NewConfig()
gitterConfig.Token = "your-gitter-token"
adapter, err := gitter.NewAdapter(gitterConfig)

最佳实践

  1. 错误处理:为每个插件实现健壮的错误处理
  2. 日志记录:使用go-sarah内置的日志接口
  3. 状态管理:合理使用UserContext管理会话状态
  4. 测试:为每个插件编写单元测试
  5. 性能监控:集成Prometheus等监控工具

go-sarah是一个灵活且功能丰富的框架,适合构建从简单到复杂的企业级聊天机器人应用。通过其插件系统,开发者可以轻松扩展功能,而无需修改核心代码。

回到顶部