关于机器人【小香蕉】

代码分享

http://git.oschina.net/for-1988/osc-robot

说明

关于这两天osc上出现的自动回复机器人【小香蕉】是我提供给大家娱乐的一个东西,这就和Simsimi差不多的东西,有的人觉得比较好玩,但肯定也打扰到了一些人,这个在这里跟大家说不好意思。【小香蕉】的服务我还会开着,如果红薯,虫虫那边觉得不好的话,那我就给停掉。刚看到了红薯发了一个说明文章,这里感谢osc的理解,一切听从 @红薯 安排。。

关于【小香蕉】

小香蕉其实就是和小黄鸡 Simsimi ,小i机器人差不多的东西。因为Simsimi,小i收费了,31号晚上正好发现了国外的一个提供api的机器人 CleverBot ,小香蕉的英文聊天就是用的它,应该是不支持中文的。然后不少人在问能不能支持中文,后来有人推荐了国内的小九机器人。昨天就加了小九,可以通过@ 小香蕉,然后 #中文  开始中文聊天。如果是中文前面没有加# ,那么很容易出现不回复的情况,我这样没有做恢复机制的处理。

【小香蕉】的代码

考虑了一下,还是不完全把代码分享出来了。其实我写的代码很简单的,大概300行,明白的朋友就知道是怎么回事。大概来说就是一个多线程的来调用osc的api获取@ 的信息,然后把内容传给机器人的接口获取回答,最后在通过osc的接口完成回复。

这里我用的编程语言和框架是  scala+akka。 Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用。用来编写多线程异步的并发程序很是方便简单。

小香蕉目前跑在一个阿里云的服务器上,最便宜的那种,高并发处理的时候大概内存占用在70m左右。

下面是部分的代码

1. Runable Jar 的入口方法,这里初始化了Akka 的actor system。这个方法用java编写是因为开始通过maven打包失败,就直接用eclipse 的expend打包了,那就必须是一个java来写的main方法了。

public class Main {
	public static void main(String[] args) {
		ActorSystem system = ActorSystem.create("system");
		ActorRef actor = system.actorOf(Props.create(OscActor.class),
				"listener");
		actor.tell("login", actor);
		actor.tell("check", actor);
	}
}
2. 处理调用osc相关接口的actor


class OscActor extends Actor {

  val client = new HttpClient

  val username = "xxxxx@126.com"
  val password = "****"

  var u: User = _

  var last_count = 0

  def receive = {
    // 处理登陆
    case "login" => {
      val login_url = OscUrl.LOGIN_VALIDATE_HTTP
      val login = _get(login_url + "?username=" + username + "&pwd=" + password + "&keep_login=1")
      val head = new Header
      client.executeMethod(login)
      println(login.getResponseBodyAsString())
      u = User.parse(login.getResponseBodyAsString())
      login.releaseConnection()
    }
    // 这里递归想当前actor发送check消息,来检查是否有新的 @ 消息
    case "check" => {
      last_count = checkatmeCount()
      if (last_count > 0)
        self ! last_count
      else {
        Thread.sleep(3000)
        self ! "check"
      }
    }
    // 查询前count条active
    case count: Int => {
      val active_url = OscUrl.ACTIVE_LIST
      val active = _get(active_url + "?uid=" + u.uid + "&catalog=2&pageIndex=0&pageSize=" + count)
      client.executeMethod(active)
      if (active.getStatusCode() == 200) {
        val list = Active.parseList(active.getResponseBodyAsString())
        list.foreach(active => {
          // 判断是否#开头的消息,如果是 创建一个新的 小九的actor 来处理这个active。否则创建CeleverBot的actor来处理
          if (active.getMessage.startsWith("#")) {
            val chatter = context.actorOf(Props[XiaojiuActor])
            chatter ! active
          } else {
            val chatter = context.actorOf(Props[ChatterActor])
            chatter ! active
          }
        })
        // 这里是为了处理出现 漏回复的情况,由于是我主动去拉osc的信息,在这个checkatmeCount 的损耗时间内,如果有新的@消息
        // 那么就很可能出现漏回复,这是无法避免的了
        val count = checkatmeCount()
        if (count <= last_count) {
          clearNotice()
          self ! "check"
        } else {
          last_count = count
          self ! (count - last_count)
        }
      } else {
        self ! "check"
      }
      active.releaseConnection()
    }
    // 回复消息
    case active: Active => {
      if (active != null) {
        val reply_url = OscUrl.COMMENT_REPLY
        val url = reply_url + "?catalog=" + active.getCatalog + "&id=" + active.getId + "&uid=" + u.getUid + "&content=" + URLEncoder.encode(active.getReplymsg) + "&replyid=" + active.getReplyid + "&authorid=" + active.getAuthorid
        val reply = _get(url)
        client.executeMethod(reply)
        reply.releaseConnection()
      }
      sender ! PoisonPill
    }
  }

  def _get(url: String): GetMethod = {
    val method = new GetMethod(url)
    method.setRequestHeader("Host", "www.oschina.net")
    method.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
    method.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8")
    method.setRequestHeader("Connection", "keep-alive")
    method.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36")
    method
  }

  def checkatmeCount(): Int = {
    val notice_url = OscUrl.USER_NOTICE
    val notice = _get(notice_url + "?uid=" + u.getUid)
    client.executeMethod(notice)
    val xml = notice.getResponseBodyAsString()
    val atme = Jsoup.parse(xml)
    var count = 0
    try {
      count = atme.select("atmeCount").first().html().toInt
    } catch {
      case e: Exception => count = 0
    }
    notice.releaseConnection()
    count
  }

  def clearNotice(): Boolean = {
    val clear_notice_url = OscUrl.NOTICE_CLEAR
    val clear = _get(clear_notice_url + "?uid=" + u.getUid + "&type=" + 1)
    client.executeMethod(clear)
    val flag = clear.getStatusCode() == 200
    clear.releaseConnection()
    flag
  }
}

3. 处理机器人回复接口的actor,这里创建了3种bot来平衡处理回复

class ChatterActor extends Actor {

  val factory = new ChatterBotFactory();
  val bot1 = factory.create(ChatterBotType.CLEVERBOT);
  val bot1session = bot1.createSession();

  val bot2 = factory.create(ChatterBotType.PANDORABOTS,
    "b0dafd24ee35a477");
  val bot2session = bot2.createSession();

  val bot3 = factory.create(ChatterBotType.JABBERWACKY);
  val bot3session = bot3.createSession();

  def receive = {
    case active: Active => {
      val s = think(active)
      active.setReplymsg(s)
      val actor = context.actorOf(Props[OscActor])
      actor ! active
      actor ! PoisonPill
    }
  }

  def think(active: Active): String = {
    (active.getId.toInt % 3) match {
      case 0 => {
        bot1session.think(active.getMessage)
      }
      case 1 => {
        bot2session.think(active.getMessage)
      }
      case 2 => {
        bot3session.think(active.getMessage)
      }
    }
  }
}

这些就是我写的主要代码了,具体关于机器人的实现等等,可以去查一查有关 AIML 的资料。




转载于:https://my.oschina.net/FengJ/blog/149367

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值