-
Notifications
You must be signed in to change notification settings - Fork 0
/
manager.py
312 lines (287 loc) · 15.2 KB
/
manager.py
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#!/usr/bin/python
# coding: utf-8
import json
import locale
from dbapi import formatDate, createUserRegisterDB, dateTime2EpochString, createAppointmentDB, getActivitiesNames
import time
# This should be tied to a configuration file:
locale.setlocale(locale.LC_ALL,'es_AR.utf8')
#####################################################################
# #
# dbapi module where all the data access methods are provided #
# #
from dbapi import ActivityRegister, getUserRegister, humanActivityCreditsExpire
#####################################################################
#####################################################################
# This code could be in a separate file and import the dictionary #
# from that "module". #
# Get a list of phones and activities for staff priviledges #
with open("/home/lean/arena/10cur4/hongaPors.txt", "r") as file: #
hongaPors = file.readlines() #
#
hongaPors = map(lambda pl: pl.rstrip('\n').split(','),hongaPors) #
#
databaseAccess = dict() #
for i in hongaPors: #
databaseAccess[i[0]] = i[1:] #
#####################################################################
# Now whenever I want to access a database, I use the following #
# dictionary: #
# defaultActivity = databaseAccess[telephoneNumber] #
# #
#####################################################################
# DATABASE NAME
with open('databaseName.txt','r') as f:
databaseName = f.read()
# TODO: Crear método que reserve turno y descuente crédito (sólo puede tener crédito negativo de -1?, creo
# que no tiene que tener límites ó al menos diferenciar actividades con créditos o sin créditos). Y que envíe un pedido de confirmación al/la responsable de la actividad para aceptarla o no.
# TODO: Crear un método que cancele un turno, entre los reservados por la persona.
# TODO: Crear un método que cree nuevas actividades a partir de una lista con el siguiente formato:
# lunes 10:00 12:00 14:30 18:00 21:15 23:00
# TODO: #1 Método que inicializa una cuenta, cuyo primer usuario (en adelante hongaPor) brinda un
# email al cuál se le envia un código de confirmacion. Para qué sirve??Porque si perdés el celu,
# te queda una oportunidadpara suspender los permisos administrativos de ese celu. En ese método,
# se pregunta si el servicio para los/las clientes será prepago (basado en créditos) o no.
#
# TODO: #2: Método que permita agregar un administrador con acceso a una base de datos. Lo puede
# hacer el/la usuario/a creada por el #1
# TODO: Método donde hongaPor puede pedir cualquier tipo de registro, para control de las tareas administrativas. Se recibe por un archivo de texto, por email, directamente por chat, según se elija
class ManageAppointments(ActivityRegister):
"""This class will give access to all method defined in the dbapi, and extend its functionality
with lots of verifications before actually calling those methods... """
def __init__(self, phoneNumber,activity=None,initHour=None):
#initHour is a datetime object
self.phoneNumber = phoneNumber
self.activity = activity
if initHour is None:
self.initHour = "0"
else:
self.initHour = dateTime2EpochString(initHour)
self.accountType = 'unknown'
try:
# Defaulta DATABASE NAME
with open('databaseName.txt','r') as f:
self.database = f.read()
if self.phoneNumber in databaseAccess.keys():
self.accountType = "staff"
if activity is None:
self.activity = databaseAccess[self.phoneNumber][1] #default activity
else:
self.activity = activity
except KeyError as e:
print("Error: Your telephone's number has no admin access to this system")
print("or there is no activity named as {}".format(activity))
except:
print("Error: No database yet created!")
def addStaff(self,phoneNumber,defaultActivity):
pass
def createAppointment(self):
if self.accountType == "staff":
super(ManageAppointments, self).__init__(self.database,self.activity,self.initHour)
def makeAppointment(self,phoneNumber): #Should I remove the parameter here?
""" Add one phoneNumber to a given activity's initHour, if it exists and if the phone is
in the database. The initHour is a datetime object and should be already
in the instance object
"""
# Check if telephone exists in database (and also if at least has any
# register in activities credits):
from datetime import datetime
magic = datetime.fromtimestamp
try:
phone, name, activityCreditsExpire, vCard = getUserRegister(self.database, phoneNumber)
print("1")
if activityCreditsExpire is not None:
actCreditsDict = humanActivityCreditsExpire(activityCreditsExpire)
print("1.1: {}".format(actCreditsDict))
print("2: {} is type {} ".format(self.initHour,type(self.initHour)))
initHour = magic(float(self.initHour))
print("2.1")
print("{}, {}, {}, {}".format(phone, name, activityCreditsExpire, vCard))
except TypeError as e:
return "Error: That phone number does not belong to any registered user."
#raise e
# Done with checking if phone is in user's database.
# Check if the activity initHour exists:
# initHourEpoch= formatDate(initHour.timetuple()[0:5])[2]
initHourEpoch = float(self.initHour)
print("initHourEpoch: {}".format(initHourEpoch))
aaps = map(float,
self.reportAvailableAppointments(onDay=initHour.replace(hour = 0,
minute = 0)))
print("Appointments: {}".format(aaps))
print(initHour,map(lambda x: time.localtime(x),aaps))
if initHourEpoch in aaps:
print("available appointment at {}".format(initHour))
# Now make the friggin' appointment:
return self.mkAppointment(phoneNumber)
# return "Bingoooo!"
else:
return "Message: No available appointment at {}".format(initHour)
def getUserRegister(self):
return getUserRegister(self.database,self.phoneNumber)
def createUserRegisterDB(self,
phoneNumber,
name,
activity=None,
credit=None,
vCard=None,
expDate=None):
return createUserRegisterDB(self.database,phoneNumber,name,activity,credit,vCard,expDate)
def getActivitiesNames(self):
"""
Return all activities names.
"""
return getActivitiesNames(self.database)
def createUserRegisterFromVCard(self,vCard,activity=None,credit=None,expDate=None):
import vobject
# if (activity or credit) is not None: return "You must give both values: activity and credits. Or you can give nither of them"
vcObj = vobject.readOne(vCard)
name = vcObj.contents['fn'][0].value
phonedata = vcObj.contents['tel'][0].value
phone = phonedata.lstrip('+').replace(' ','').replace('-','') #Not very elegant, but ...
createUserRegisterDB(self.database,
phone,
name,
activity,
credit,
vCard,
expDate)
texto = "El teléfono {} se agendó a nombre de {}".format(phonedata,name)
print(texto)
return(phonedata,name)
def setup(self,databaseName):
"""
Create a new database, staff permitions are not lost 'cause it is
stored in a different file.
"""
try:
with open("databaseName.txt", "w") as file:
file.write(databaseName)
createAppointmentDB(databaseName)
return "DB Succesfully created"
except:
return "DEBUG: UUUps... creation of new database file failed"
class VistaMinable(ActivityRegister):
"""Esta clase será utilizada para crear una vista minable con
los datos que se generan con el uso del sistema"""
#####################
# import sklearn as sk
# import numpy as np
#####################
target_class_name = 'participants' #Default class
feature_names = ['apparentTemperature', 'precipIntensity','humidity',
'summary','pressure'] #Default features
def __init__(self, phoneNumber,activity):
"""In order to create the vista minable, a phone number with proper
access to the database must be given, as well as the activity under
study."""
self.phoneNumber = phoneNumber
self.activity = activity
self.initHour = "0" # This initHour is a dummy value, just to start the object. Could I use it to store any useful data on it, like participants are the admins of that activity.
self.database = databaseAccess[self.phoneNumber] #this is broken
self.timeTuple = None # (year,month,day,hour,minute)
try:
super(VistaMinable, self).__init__(self.database,self.activity,self.initHour)
except KeyError as e:
print("Error: Your telephone's number has no access to this system")
def getData(self):
""" Returns a dictionary with all weather variables for each initHour
that is the database for the current week"""
print("a ver che...")
from forecastiopy import ForecastIO
# TODO: A method that will get the weather variables for the activity
# initHour when the time comes. DONE
Cordoba = [-31.4173,-64.1833] # TODO: Avoid this hardcoded data
language= 'es'
with open("forecast.txt", "r") as file:
forecastAPI= file.readlines().pop().rstrip('\n')
_,timeRange = ActivityRegister(
self.database,self.activity,self.initHour).periodReport('semanal')
weatherData = dict()
timeRange.sort()
for time in timeRange:
weatherData[time] = dict()
weatherData[time]['participants'] = ActivityRegister(
self.database,self.activity,unicode(time)).howMuch()
fio = ForecastIO.ForecastIO(forecastAPI, latitude=Cordoba[0], longitude=Cordoba[1],lang=language)
fio.time_url=time.rstrip('0').rstrip('.') #needs to be done couse
#the api doesn't support floating point time
forecast = json.loads(fio.http_get(fio.get_url()))
for key in forecast['currently'].keys():
weatherData[time][key]=forecast['currently'][key]
# print(time,key,datos,weatherData[time][key])
#'summary','apparentTemperature','precipIntensity',
#'humidity','pressure','precipProbability','windSpeed',
#'Among others variables'
setattr(self, 'data',weatherData)
def createFeatures(self):
"""This method will create two list: the feature list and the target
class values for that examples. This method can only be called after
using the getData method, which will retrieve al info from weather cast
api for the initHour and the number of participants."""
features = list()
target_class = list()
for time in self.data.keys():
instance = list()
for f in self.feature_names: #Get only the features which we chose
try: instance.append(self.data[time][f])
except: pass
target_class.append(self.data[time][self.target_class_name])
if len(instance) > 0: features.append(instance)
setattr(self,'features_values',self.np.array(features))
setattr(self,'target_class_value',self.np.array(target_class))
def binaryTree(self):
"""This will preprocess all categorical features to numerical values"""
from sklearn.preprocessing import LabelEncoder
enc = LabelEncoder()
#Due to numpy < 1.7 I must convert unicode -> str
temporary = vm.np.array(map(str,self.features_values[:,3]))
label_encoder = enc.fit(temporary)
integer_classes = label_encoder.transform(label_encoder.classes_).reshape(2, 1)
#El dos es la cantidad de estados (TODO: evitar este valor hardcodeado)
enc = OneHotEncoder()
one_hot_encoder = enc.fit(integer_classes)
num_of_rows = temporary.shape[0]
t = label_encoder.transform(temporary).reshape(num_of_rows, 1)
# Second, create a sparse matrix with two columns, each one indicating if the
# instance belongs to the class
new_features = one_hot_encoder.transform(t)
# Add the new features to features_values
self.features_values = vm.np.concatenate([self.features_values,
new_features.toarray()], axis = 1)
#Eliminate converted columns
self.features_values = vm.np.delete(self.features_values, [3], 1)
# Update feature names
# (TODO: evitar estos valores hardcodeados):
feature_names = ['apparentTemperature', 'precipIntensity','humidity',
'pressure','Despejado','Parcialmente Nublado']
# Now preprocess the target class:
temporary = vm.np.array(map(str,self.target_class_value))
self.sk.preprocessing.Binarizer(threshold=5).fit(temporary.reshape(-1,1))
self.target_class_value = binarizer.transform(temporary)
# Now do the same for the 'summary' feature, which is a categoric value
# transformed to a binary vector :
# First, convert clases to 0-(N-1) integers using label_encoder
# Convert to numerical values
self.features_values = self.features_values.astype(float)
self.target_class_value = self.target_class_value.astype(float)
# Hacemos cross validation, con el 75\% y 25\% de los datos
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(self.features_values,
self.target_class_value,
test_size=0.25,
random_state=33)
# Creamos el árbol de desición
from sklearn import tree
clf = tree.DecisionTreeClassifier(criterion='entropy',
max_depth=3,min_samples_leaf=5)
clf = clf.fit(X_train,y_train)
# Visualización
import StringIO
dot_data = StringIO.StringIO()
tree.export_graphviz(clf, out_file=dot_data, feature_names=self.feature_names)
graph = pydot.graph_from_dot_data(dot_data.getvalue())
graph.write_png('asistencia.png')
from IPython.core.display import Image
Image(filename='asistencia.png')
###