~aleteoryx/ntalk

ref: 32c9d4becb3c6f119aad7e048b8c002a49bd464a ntalk/botlib.py -rwxr-xr-x 2.9 KiB
32c9d4beAleteoryx better errors a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/bin/env python

import socket
from sys import argv, stderr, exit
import os
from time import sleep

lastmsg = 0

sok = None
isok = None
osok = None

argv0 = "bot.py"
def usage():
	global argv0
	print(f"usage: {argv0} HOST PORT", file=stderr)
	print(file=stderr)
	print("'advanced' 'AI' for nanochat", file=stderr)
	exit(-1)


### "AI" ###

def split_list(words, pwords):
	terms = []
	acc = []
	for i in range(len(words)):
		if len(acc) == 0 and pwords[i] in ('and', 'or'):
			continue
		if words[i][-1] == ',':
			acc.append(words[i].rstrip(','))
			terms.append(acc)
			acc = []
		else:
			acc.append(words[i])
	
	if len(acc) != 0:
		terms.append(acc)
	
	return terms

def strip_direct_address(name, special, words, pwords):
	if name not in pwords:
		return False

	# ignore an initial greeting
	if pwords[0] in ['hey', 'oh', 'yo', 'ok', 'okay']:
		idx = 1
	else:
		idx = 0
	
	# "bot, hi"
	if pwords[idx] == name and words[idx][-1] in ',:':
		# strip direct address and greeting
		for _ in range(idx+1):
			words.pop(0)
			pwords.pop(0)
		return True
	
	# lol
	if len(words) < 2:
		words.pop()
		pwords.pop()
		return True
	if len(words) == True and words[-2] in special:
		words.pop()
		pwords.pop()
		return True
	
	# trailing address
	if pwords[-1] == name and words[-2][-1] == ',':
		words.pop()
		pwords.pop()
		words[-1] = words[-1].lstrip(',') # strip comma
		return True
	
	return False
	

def handle_line(line, name, msgfn, actfn):
	# we assume nobody's nick is longer than 20 chars, to
	# hopefully avoid picking up actions that include colons.
	# this may need tweaking!
	try:
		colon_pos = line.index(':', 0, 20)
	except:
		colon_pos = len(line)
	
	if colon_pos+1 >= len(line):
		words, pwords = parse_words(line)
		if len(words) > 0:
			actfn(line, words, pwords)
	else:
		nick, line = line.split(':', 1)
		if line.startswith('/') or nick.endswith('http') or nick.endswith('https'):
			return # picked up a URL by accident

		if nick == name:
			return

		words, pwords = parse_words(line)
		if len(words) >= 2:
			msgfn(nick, line, words, pwords)

def parse_words(line):
	words = [*filter(lambda x: x, line.split(' '))]
	pwords = [word.rstrip(',!.:~?') for word in words] # [n]ormalized words
	return words, pwords

### NETCODE ###

def readln():
	global isok
	return isok.readline().decode('latin-1', errors='replace').strip()

def readk():
	return int(readln())

def writeln(line):
	global osok
	osok.write(f"{line}\n")
	osok.flush()

def send(msg):
	writeln(f"SEND {msg}")
	return readk()

def readmany():
	global lastmsg
	ret = []
	k = readk()
	for i in range(k):
		ret.append(readln())
	lastmsg = readk()

	return ret

### BOOT ###

def parse_args():
	global sok, isok, osok, argv, argv0, lastmsg
	if len(argv) < 1:
		usage()
	argv0 = argv[0]
	argv = argv[1:]
	if len(argv) != 2:
		usage()

	sok = socket.create_connection((argv[0], int(argv[1])))
	isok = sok.makefile('rb')
	osok = sok.makefile('w')

	writeln("LAST 0")
	readln()
	lastmsg = readk()