Advertisement
CitraDeus

Cleverbot

Jul 3rd, 2013
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.82 KB | None | 0 0
  1. --[[
  2. Cleverbot client for ComputerCraft v1.0
  3. Based on https://code.google.com/p/chatter-bot-api/
  4.  
  5. This code uses a pure lua implementation of the MD5 hash algortihm by Adam Baldwin as presented
  6. in this Stack Overflow answer: http://stackoverflow.com/a/12292659
  7.  
  8. Usage:
  9. pastebin get Dv9x1ppc cleverbot
  10. cleverbot start
  11.  
  12. If a Chat Box (from Misc Peripherals) is connected to the computer the client uses it. Voice commands are activated by prepending the message with "Jarvis:" or "Jarvis," or just "Jarvis ". The name and delimiters can be customized by changing the relevant variables. Without a Chat Box the code responds to typed messages on the computer (no need to use the name, just type the message).
  13.  
  14. See the code in action: http://imgur.com/a/MNN4J
  15.  
  16. This same file can also be used as an API.
  17.  
  18. Example code:
  19. os.load("cleverbot")
  20.  
  21. bot = cleverbot.Cleverbot.new()
  22.  
  23. message = "Hi there!"
  24. response = bot:send(message) -- use of : is important here because of self reference
  25. print(response)
  26.  
  27. Notes:
  28. * Sending the message is pretty slow as the hashing takes time and cleverbot.com can sometimes take a while to respond. On slower computers this can sometimes lead to "too long without yielding" error.
  29.  
  30. Matti Vapa (2013)
  31. ]]--
  32.  
  33.  
  34. -- Here are the (slightly modified) LuaBit and MD5 implementations with original comments
  35.  
  36. --[[---------------
  37. LuaBit v0.4
  38. -------------------
  39. a bitwise operation lib for lua.
  40.  
  41. http://luaforge.net/projects/bit/
  42.  
  43. How to use:
  44. -------------------
  45. bit.bnot(n) -- bitwise not (~n)
  46. bit.band(m, n) -- bitwise and (m & n)
  47. bit.bor(m, n) -- bitwise or (m | n)
  48. bit.bxor(m, n) -- bitwise xor (m ^ n)
  49. bit.brshift(n, bits) -- right shift (n >> bits)
  50. bit.blshift(n, bits) -- left shift (n << bits)
  51. bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)
  52.  
  53. Please note that bit.brshift and bit.blshift only support number within
  54. 32 bits.
  55.  
  56. 2 utility functions are provided too:
  57. bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
  58. -- high bits first
  59. bit.tonumb(bit_tbl) -- convert a bit table into a number
  60. -------------------
  61.  
  62. Under the MIT license.
  63.  
  64. copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
  65. --]]---------------
  66.  
  67. --do
  68.  
  69. ------------------------
  70. -- bit lib implementions
  71.  
  72. local function check_int(n)
  73. -- checking not float
  74. if(n - math.floor(n) > 0) then
  75. error("trying to use bitwise operation on non-integer!")
  76. end
  77. end
  78.  
  79. local function tbl_to_number(tbl)
  80. local n = #tbl
  81.  
  82. local rslt = 0
  83. local power = 1
  84. for i = 1, n do
  85. rslt = rslt + tbl[i]*power
  86. power = power*2
  87. end
  88.  
  89. return rslt
  90. end
  91.  
  92. local function expand(tbl_m, tbl_n)
  93. local big = {}
  94. local small = {}
  95. if(#tbl_m > #tbl_n) then
  96. big = tbl_m
  97. small = tbl_n
  98. else
  99. big = tbl_n
  100. small = tbl_m
  101. end
  102. -- expand small
  103. for i = #small + 1, #big do
  104. small[i] = 0
  105. end
  106.  
  107. end
  108.  
  109. local to_bits = function () end
  110.  
  111. local function bit_not(n)
  112. local tbl = to_bits(n)
  113. local size = math.max(#tbl, 32)
  114. for i = 1, size do
  115. if(tbl[i] == 1) then
  116. tbl[i] = 0
  117. else
  118. tbl[i] = 1
  119. end
  120. end
  121. return tbl_to_number(tbl)
  122. end
  123.  
  124.  
  125. to_bits = function (n)
  126. check_int(n)
  127. if(n < 0) then
  128. -- negative
  129. return to_bits(bit_not(math.abs(n)) + 1)
  130. end
  131. -- to bits table
  132. local tbl = {}
  133. local cnt = 1
  134. while (n > 0) do
  135. local last = math.fmod(n,2)
  136. if(last == 1) then
  137. tbl[cnt] = 1
  138. else
  139. tbl[cnt] = 0
  140. end
  141. n = (n-last)/2
  142. cnt = cnt + 1
  143. end
  144.  
  145. return tbl
  146. end
  147.  
  148.  
  149. local function bit_or(m, n)
  150. local tbl_m = to_bits(m)
  151. local tbl_n = to_bits(n)
  152. expand(tbl_m, tbl_n)
  153.  
  154. local tbl = {}
  155. local rslt = math.max(#tbl_m, #tbl_n)
  156. for i = 1, rslt do
  157. if(tbl_m[i]== 0 and tbl_n[i] == 0) then
  158. tbl[i] = 0
  159. else
  160. tbl[i] = 1
  161. end
  162. end
  163.  
  164. return tbl_to_number(tbl)
  165. end
  166.  
  167. local function bit_and(m, n)
  168. local tbl_m = to_bits(m)
  169. local tbl_n = to_bits(n)
  170. expand(tbl_m, tbl_n)
  171.  
  172. local tbl = {}
  173. local rslt = math.max(#tbl_m, #tbl_n)
  174. for i = 1, rslt do
  175. if(tbl_m[i]== 0 or tbl_n[i] == 0) then
  176. tbl[i] = 0
  177. else
  178. tbl[i] = 1
  179. end
  180. end
  181.  
  182. return tbl_to_number(tbl)
  183. end
  184.  
  185. local function bit_xor(m, n)
  186. local tbl_m = to_bits(m)
  187. local tbl_n = to_bits(n)
  188. expand(tbl_m, tbl_n)
  189.  
  190. local tbl = {}
  191. local rslt = math.max(#tbl_m, #tbl_n)
  192. for i = 1, rslt do
  193. if(tbl_m[i] ~= tbl_n[i]) then
  194. tbl[i] = 1
  195. else
  196. tbl[i] = 0
  197. end
  198. end
  199.  
  200. --table.foreach(tbl, print)
  201.  
  202. return tbl_to_number(tbl)
  203. end
  204.  
  205. local function bit_rshift(n, bits)
  206. check_int(n)
  207.  
  208. local high_bit = 0
  209. if(n < 0) then
  210. -- negative
  211. n = bit_not(math.abs(n)) + 1
  212. high_bit = 2147483648 -- 0x80000000
  213. end
  214.  
  215. for i=1, bits do
  216. n = n/2
  217. n = bit_or(math.floor(n), high_bit)
  218. end
  219. return math.floor(n)
  220. end
  221.  
  222. -- logic rightshift assures zero filling shift
  223. local function bit_logic_rshift(n, bits)
  224. check_int(n)
  225. if(n < 0) then
  226. -- negative
  227. n = bit_not(math.abs(n)) + 1
  228. end
  229. for i=1, bits do
  230. n = n/2
  231. end
  232. return math.floor(n)
  233. end
  234.  
  235. local function bit_lshift(n, bits)
  236. check_int(n)
  237.  
  238. if(n < 0) then
  239. -- negative
  240. n = bit_not(math.abs(n)) + 1
  241. end
  242.  
  243. for i=1, bits do
  244. n = n*2
  245. end
  246. return bit_and(n, 4294967295) -- 0xFFFFFFFF
  247. end
  248.  
  249. local function bit_xor2(m, n)
  250. local rhs = bit_or(bit_not(m), bit_not(n))
  251. local lhs = bit_or(m, n)
  252. local rslt = bit_and(lhs, rhs)
  253. return rslt
  254. end
  255.  
  256. -- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh)
  257. -- 10/02/2001 jcw@equi4.com
  258.  
  259. local md5={ff=tonumber('ffffffff',16),consts={}}
  260.  
  261. string.gsub([[ d76aa478 e8c7b756 242070db c1bdceee
  262. f57c0faf 4787c62a a8304613 fd469501
  263. 698098d8 8b44f7af ffff5bb1 895cd7be
  264. 6b901122 fd987193 a679438e 49b40821
  265. f61e2562 c040b340 265e5a51 e9b6c7aa
  266. d62f105d 02441453 d8a1e681 e7d3fbc8
  267. 21e1cde6 c33707d6 f4d50d87 455a14ed
  268. a9e3e905 fcefa3f8 676f02d9 8d2a4c8a
  269. fffa3942 8771f681 6d9d6122 fde5380c
  270. a4beea44 4bdecfa9 f6bb4b60 bebfbc70
  271. 289b7ec6 eaa127fa d4ef3085 04881d05
  272. d9d4d039 e6db99e5 1fa27cf8 c4ac5665
  273. f4292244 432aff97 ab9423a7 fc93a039
  274. 655b59c3 8f0ccc92 ffeff47d 85845dd1
  275. 6fa87e4f fe2ce6e0 a3014314 4e0811a1
  276. f7537e82 bd3af235 2ad7d2bb eb86d391
  277. 67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) table.insert(md5.consts, tonumber(s,16)) end)
  278. --67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) tinsert(md5.consts,tonumber(s,16)) end)
  279.  
  280. function transform(A,B,C,D,X)
  281. local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end
  282. local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end
  283. local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end
  284. local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end
  285. local z=function (f,a,b,c,d,x,s,ac)
  286. a=bit_and(a+f(b,c,d)+x+ac,md5.ff)
  287. -- be *very* careful that left shift does not cause rounding!
  288. return bit_or(bit_lshift(bit_and(a,bit_rshift(md5.ff,s)),s),bit_rshift(a,32-s))+b
  289. end
  290. local a,b,c,d=A,B,C,D
  291. local t=md5.consts
  292.  
  293. a=z(f,a,b,c,d,X[ 0], 7,t[ 1])
  294. d=z(f,d,a,b,c,X[ 1],12,t[ 2])
  295. c=z(f,c,d,a,b,X[ 2],17,t[ 3])
  296. b=z(f,b,c,d,a,X[ 3],22,t[ 4])
  297. a=z(f,a,b,c,d,X[ 4], 7,t[ 5])
  298. d=z(f,d,a,b,c,X[ 5],12,t[ 6])
  299. c=z(f,c,d,a,b,X[ 6],17,t[ 7])
  300. b=z(f,b,c,d,a,X[ 7],22,t[ 8])
  301. a=z(f,a,b,c,d,X[ 8], 7,t[ 9])
  302. d=z(f,d,a,b,c,X[ 9],12,t[10])
  303. c=z(f,c,d,a,b,X[10],17,t[11])
  304. b=z(f,b,c,d,a,X[11],22,t[12])
  305. a=z(f,a,b,c,d,X[12], 7,t[13])
  306. d=z(f,d,a,b,c,X[13],12,t[14])
  307. c=z(f,c,d,a,b,X[14],17,t[15])
  308. b=z(f,b,c,d,a,X[15],22,t[16])
  309.  
  310. a=z(g,a,b,c,d,X[ 1], 5,t[17])
  311. d=z(g,d,a,b,c,X[ 6], 9,t[18])
  312. c=z(g,c,d,a,b,X[11],14,t[19])
  313. b=z(g,b,c,d,a,X[ 0],20,t[20])
  314. a=z(g,a,b,c,d,X[ 5], 5,t[21])
  315. d=z(g,d,a,b,c,X[10], 9,t[22])
  316. c=z(g,c,d,a,b,X[15],14,t[23])
  317. b=z(g,b,c,d,a,X[ 4],20,t[24])
  318. a=z(g,a,b,c,d,X[ 9], 5,t[25])
  319. d=z(g,d,a,b,c,X[14], 9,t[26])
  320. c=z(g,c,d,a,b,X[ 3],14,t[27])
  321. b=z(g,b,c,d,a,X[ 8],20,t[28])
  322. a=z(g,a,b,c,d,X[13], 5,t[29])
  323. d=z(g,d,a,b,c,X[ 2], 9,t[30])
  324. c=z(g,c,d,a,b,X[ 7],14,t[31])
  325. b=z(g,b,c,d,a,X[12],20,t[32])
  326.  
  327. a=z(h,a,b,c,d,X[ 5], 4,t[33])
  328. d=z(h,d,a,b,c,X[ 8],11,t[34])
  329. c=z(h,c,d,a,b,X[11],16,t[35])
  330. b=z(h,b,c,d,a,X[14],23,t[36])
  331. a=z(h,a,b,c,d,X[ 1], 4,t[37])
  332. d=z(h,d,a,b,c,X[ 4],11,t[38])
  333. c=z(h,c,d,a,b,X[ 7],16,t[39])
  334. b=z(h,b,c,d,a,X[10],23,t[40])
  335. a=z(h,a,b,c,d,X[13], 4,t[41])
  336. d=z(h,d,a,b,c,X[ 0],11,t[42])
  337. c=z(h,c,d,a,b,X[ 3],16,t[43])
  338. b=z(h,b,c,d,a,X[ 6],23,t[44])
  339. a=z(h,a,b,c,d,X[ 9], 4,t[45])
  340. d=z(h,d,a,b,c,X[12],11,t[46])
  341. c=z(h,c,d,a,b,X[15],16,t[47])
  342. b=z(h,b,c,d,a,X[ 2],23,t[48])
  343.  
  344. a=z(i,a,b,c,d,X[ 0], 6,t[49])
  345. d=z(i,d,a,b,c,X[ 7],10,t[50])
  346. c=z(i,c,d,a,b,X[14],15,t[51])
  347. b=z(i,b,c,d,a,X[ 5],21,t[52])
  348. a=z(i,a,b,c,d,X[12], 6,t[53])
  349. d=z(i,d,a,b,c,X[ 3],10,t[54])
  350. c=z(i,c,d,a,b,X[10],15,t[55])
  351. b=z(i,b,c,d,a,X[ 1],21,t[56])
  352. a=z(i,a,b,c,d,X[ 8], 6,t[57])
  353. d=z(i,d,a,b,c,X[15],10,t[58])
  354. c=z(i,c,d,a,b,X[ 6],15,t[59])
  355. b=z(i,b,c,d,a,X[13],21,t[60])
  356. a=z(i,a,b,c,d,X[ 4], 6,t[61])
  357. d=z(i,d,a,b,c,X[11],10,t[62])
  358. c=z(i,c,d,a,b,X[ 2],15,t[63])
  359. b=z(i,b,c,d,a,X[ 9],21,t[64])
  360.  
  361. return A+a,B+b,C+c,D+d
  362. end
  363.  
  364. -- convert little-endian 32-bit int to a 4-char string
  365. local function leIstr(i)
  366. local f=function (s) return string.char(bit_and(bit_rshift(i,s),255)) end
  367. return f(0)..f(8)..f(16)..f(24)
  368. end
  369.  
  370. -- convert raw string to big-endian int
  371. local function beInt(s)
  372. local v=0
  373. for i=1,string.len(s) do v=v*256+string.byte(s,i) end
  374. return v
  375. end
  376. -- convert raw string to little-endian int
  377. local function leInt(s)
  378. local v=0
  379. for i=string.len(s),1,-1 do v=v*256+string.byte(s,i) end
  380. return v
  381. end
  382. -- cut up a string in little-endian ints of given size
  383. local function leStrCuts(s,...)
  384. local o,r=1,{}
  385. for i=1,#arg do
  386. table.insert(r,leInt(string.sub(s,o,o+arg[i]-1)))
  387. o=o+arg[i]
  388. end
  389. return r
  390. end
  391.  
  392. function Calc(s)
  393. local msgLen=string.len(s)
  394. local padLen=56- msgLen % 64
  395. if msgLen % 64 > 56 then padLen=padLen+64 end
  396. if padLen==0 then padLen=64 end
  397. s=s..string.char(128)..string.rep(string.char(0),padLen-1)
  398. s=s..leIstr(8*msgLen)..leIstr(0)
  399. assert(string.len(s) % 64 ==0)
  400. local t=md5.consts
  401. local a,b,c,d=t[65],t[66],t[67],t[68]
  402. for i=1,string.len(s),64 do
  403. local X=leStrCuts(string.sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4)
  404. assert(#X==16)
  405. X[0]=table.remove(X,1) -- zero based!
  406. a,b,c,d=transform(a,b,c,d,X)
  407. end
  408. local swap=function (w) return beInt(leIstr(w)) end
  409. return string.format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d))
  410. end
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420. -- Here begins the Cleverbot client section
  421.  
  422.  
  423. -- Utility functions
  424.  
  425. -- parse the response lines to a table
  426. split2lines = function(input)
  427. output = {}
  428. local i = 0
  429. local line = input.readLine()
  430. while line ~= nil do
  431. output[i] = line
  432. i = i + 1
  433. line = input.readLine()
  434. end
  435. return output
  436. end
  437.  
  438. -- encode the variables to a string so that
  439. -- vars["key"] = "value" becomes "key=value&"
  440. encodeVars = function(vars)
  441. local s = ""
  442. for k,v in pairs(vars) do
  443. if #v > 0 then
  444. s = s..k.."="..v.."&"
  445. end
  446. end
  447. return s
  448. end
  449.  
  450. -- a helper for iterating over the lines in a response
  451. stringAtIndex = function(strings, index)
  452. if #strings > index then
  453. return strings[index]
  454. else
  455. return ""
  456. end
  457. end
  458.  
  459. -- this function parses the response, saves some important pieces of data
  460. -- to vars and returns the actual response message
  461. handleResponse = function(resp,vars)
  462. response = split2lines(resp)
  463. vars["sessionid"] = stringAtIndex(response,1)
  464. vars["logurl"] = stringAtIndex(response,2)
  465. vars["vText8"] = stringAtIndex(response,3)
  466. vars["vText7"] = stringAtIndex(response,4)
  467. vars["vText6"] = stringAtIndex(response,5)
  468. vars["vText5"] = stringAtIndex(response,6)
  469. vars["vText4"] = stringAtIndex(response,7)
  470. vars["vText3"] = stringAtIndex(response,8)
  471. vars["vText2"] = stringAtIndex(response,9)
  472. vars["prevref"] = stringAtIndex(response,10)
  473. vars["emotionalhistory"] = stringAtIndex(response,12)
  474. vars["ttsLocMP3"] = stringAtIndex(response,13)
  475. vars["ttsLocTXT"] = stringAtIndex(response,14)
  476. vars["ttsLocTXT3"] = stringAtIndex(response,15)
  477. vars["ttsText"] = stringAtIndex(response,16)
  478. vars["lineRef"] = stringAtIndex(response,17)
  479. vars["lineURL"] = stringAtIndex(response,18)
  480. vars["linePOST"] = stringAtIndex(response,19)
  481. vars["lineChoices"] = stringAtIndex(response,20)
  482. vars["lineChoicesAbbrev"] = stringAtIndex(response,21)
  483. vars["typingData"] = stringAtIndex(response,22)
  484. vars["divert"] = stringAtIndex(response,23)
  485. end
  486.  
  487. -- this function takes the vars and makes a valid POST to cleverbot.com
  488. sendMsg = function(vars)
  489. -- encode the vars to a string
  490. data = encodeVars(vars)
  491. -- take a piece and hash it (important to validate the query)
  492. hash = data:sub(10,29)
  493. hash = Calc(hash)
  494. -- append the has to data
  495. data = data.."icognocheck="..hash
  496. -- send POST
  497. resp = http.post(url,data)
  498. handleResponse(resp,vars)
  499. return vars["ttsText"]
  500. end
  501.  
  502. url = "http://www.cleverbot.com/webservicemin"
  503. -- initial variables
  504. vars = {}
  505. vars["start"] = "y"
  506. vars["icognoid"] = "wsf"
  507. vars["fno"] = "0"
  508. vars["sub"] = "Say"
  509. vars["islearning"] = "1"
  510. vars["cleanslate"] = "false"
  511.  
  512.  
  513. -- Here is the Cleverbot "class" that can be used by an external program
  514. -- or by the client at the end of the file
  515.  
  516. Cleverbot = {}
  517.  
  518. Cleverbot.new = function()
  519. local bot = {}
  520. local tvars = {}
  521. for k,v in pairs(vars) do
  522. tvars[k] = v
  523. end
  524. bot.vars = tvars
  525. setmetatable(bot,{__index = Cleverbot})
  526. return bot
  527. end
  528.  
  529. Cleverbot.send = function(self,message)
  530. self.vars["stimulus"] = textutils.urlEncode(message)
  531. local response = sendMsg(self.vars)
  532. if #response > 0 then
  533. return response
  534. else
  535. return "-!- ERROR - NO RESPONSE -!-"
  536. end
  537. end
  538.  
  539. -- args are used to check if this file was loaded as an API or used as a stand-alone client
  540.  
  541. args = {...}
  542.  
  543. if #args > 0 then
  544. -- Here you can customize the name and valid delimiters
  545. local myname = "Computer"
  546. local delimiters = {",", ":", " "}
  547.  
  548. -- Chat Box radius
  549. local radius = 999999
  550.  
  551. -- get message from chat
  552. local getFromChat = function()
  553. while true do
  554. local event, player, message = os.pullEvent("chat")
  555. if player == "Undefinedmaster" then
  556. if message:sub(1,6):lower():find(myname:lower()) then
  557. local min_index = #message
  558. for a,del in ipairs(delimiters) do
  559. local i = message:find(del)
  560. if i and i < min_index then min_index = i end
  561. end
  562. if min_index < #message then
  563. return message:sub(min_index+1)
  564. end
  565. end
  566. end
  567. end
  568. end
  569.  
  570. -- or from command line
  571. local getFromCLI = function()
  572. return read()
  573. end
  574.  
  575. local bot = Cleverbot.new()
  576. local sides = {"top","bottom","front","back","left","right"}
  577. local side = nil
  578. local get = nil -- function for getting a message from player
  579. local say = nil -- function for broadcasting the response
  580.  
  581. -- check for Chat Box
  582. for i,s in ipairs(sides) do
  583. if peripheral.getType(s) == "chat" then
  584. side = s
  585. break
  586. end
  587. end
  588.  
  589. if side then
  590. -- found a Chat Box
  591. print("Found a Chat Box. Switching to voice commands. Address me as "..myname..".")
  592. local chat = peripheral.wrap(side)
  593. get = getFromChat
  594. say = function(message)
  595. chat.say(myname.."> "..message, radius, true)
  596. end
  597. else
  598. -- default to command line
  599. print("No Chat Box detected. Using command line.")
  600. get = getFromCLI
  601. say = function(message)
  602. print(myname.."> "..message)
  603. end
  604. end
  605.  
  606. -- main loop
  607. local m = ""
  608. while true do
  609. m = get()
  610. m = bot:send(m)
  611. say(m)
  612. sleep(0.1)
  613. end
  614.  
  615. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement