Commit e3e4041f7862400ca7c66b3e1b943de944b869de

Authored by Tássia Camões Araújo
1 parent dabda648
Exists in master and in 1 other branch add_vagrant

Last modifications before releasing survey.

src/web/static/css/survey.css
... ... @@ -97,6 +97,7 @@ margin-bottom: 10px;
97 97 }
98 98  
99 99 .radioButton,
  100 +#start-button,
100 101 #next-button,
101 102 #restart-button,
102 103 #continue-button,
... ... @@ -148,7 +149,7 @@ cursor: pointer;
148 149 #panel-controls {
149 150 position: relative;
150 151 width: 200px;
151   -height: 60px;
  152 +height: 80px;
152 153 padding: 5px;
153 154 margin: 5px;
154 155 border-radius: 5px;
... ...
src/web/survey.py
... ... @@ -12,6 +12,7 @@ import urllib
12 12 import socket
13 13 import csv
14 14 import datetime
  15 +import stat
15 16  
16 17 sys.path.insert(0,"/var/www/AppRecommender/src/")
17 18  
... ... @@ -38,15 +39,16 @@ class Thanks:
38 39 user_id = web_input['user_id'].encode('utf8')
39 40 personal_file = open("/var/www/AppRecommender/src/web/submissions/%s/personal" % user_id,'w')
40 41 personal = {}
41   - for key in ["name","email","comments"]:
  42 + for key in ["name","email","user_habits","comments"]:
42 43 if web_input.has_key(key):
43 44 personal[key] = web_input[key].encode("utf-8")
44 45 else:
45 46 personal[key] = ""
46 47 try:
47 48 writer = csv.writer(personal_file)
48   - writer.writerow(("user","name","email","comments"))
49   - writer.writerow((user_id,personal["name"],personal["email"],personal["comments"]))
  49 + writer.writerow(("user","name","email","habits_id","comments"))
  50 + writer.writerow((user_id,personal["name"],personal["email"],
  51 + personal["user_habits"],personal["comments"]))
50 52 except:
51 53 error_msg = "Could not save optional information."
52 54 logging.critical("Could not save optional information.")
... ... @@ -72,7 +74,8 @@ class Save:
72 74 % (user_id,strategy))
73 75 summary = {}
74 76 summary["poor"] = 0
75   - summary["good"] = 0
  77 + summary["redundant"] = 0
  78 + summary["useful"] = 0
76 79 summary["surprising"] = 0
77 80  
78 81 # Save evaluation
... ... @@ -94,44 +97,42 @@ class Save:
94 97 summary[evaluation] += 1
95 98 break
96 99 prediction_file.seek(0)
  100 + prediction_file.close()
  101 + evaluation_file.close()
97 102 except:
98 103 error_msg = "Could not write evaluation to file."
99 104 logging.critical(error_msg)
100 105 return render.error([error_msg], "/survey/","START")
101 106 finally:
102   - prediction_file.close()
103   - evaluation_file.close()
104 107 os.remove(os.path.join(strategy_dir,"prediction"))
105 108 with open(os.path.join(strategy_dir,"end"),'w') as end:
106 109 end_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
107 110 end.write(end_time)
108 111  
109 112 # Save report
110   - try:
111   - report = os.path.join(user_dir,"report")
112   - report_file = open(os.path.join(user_dir,"report"),'a')
113   - writer = csv.writer(report_file)
114   - if os.path.getsize(report) == 0:
115   - fieldnames = ('user','strategy',"start","end",'truepositive',
116   - 'falsepositive','surprise','comments')
117   - writer.writerow(fieldnames)
118   - with open(os.path.join(strategy_dir,"start"),'r') as start:
119   - start_time = start.readline().strip()
120   - if web_input.has_key("comments"):
121   - comments = web_input['comments'].encode("utf-8")
122   - else:
123   - comments = ""
124   - writer.writerow((user_id,strategy,start_time,end_time,
125   - summary["good"]+summary["surprising"],
126   - summary["poor"],summary["surprising"],comments))
127   - except:
128   - if comments:
129   - error_msg = "Could not save comments."
130   - logging.critical(error_msg)
131   - return render.error([error_msg], "/survey/","START")
132   - logging.critical("Could not save evaluation report.")
133   - finally:
134   - report_file.close()
  113 + #try:
  114 + report = os.path.join(user_dir,"report")
  115 + report_file = open(os.path.join(user_dir,"report"),'a')
  116 + writer = csv.writer(report_file)
  117 + if os.path.getsize(report) == 0:
  118 + fieldnames = ('user','strategy','start','end','poor',
  119 + 'redundant','useful','surprising','comments')
  120 + writer.writerow(fieldnames)
  121 + with open(os.path.join(strategy_dir,"start"),'r') as start:
  122 + start_time = start.readline().strip()
  123 + if web_input.has_key("comments"):
  124 + comments = web_input['comments'].encode("utf-8")
  125 + else:
  126 + comments = ""
  127 + writer.writerow((user_id,strategy,start_time,end_time,summary["poor"],
  128 + summary["redundant"],summary["useful"],
  129 + summary["surprising"],comments))
  130 + #except:
  131 + # error_msg = "Could not save evaluation report."
  132 + # logging.critical(error_msg)
  133 + # return render.error([error_msg], "/survey/","START")
  134 + #finally:
  135 + # report_file.close()
135 136  
136 137 if web_input.has_key('continue_button'):
137 138 return Survey().POST()
... ... @@ -140,42 +141,26 @@ class Save:
140 141 else:
141 142 return render.index_survey()
142 143  
143   -class Request:
144   - def __init__(self,web_input,submissions_dir):
145   - self.strategy = ""
146   - # Check if it is first round
147   - if web_input.has_key('user_id'):
148   - self.user_id = web_input['user_id'].encode('utf8')
149   - self.user_dir = os.path.join(submissions_dir, self.user_id)
150   - logging.info("New round for user %s" % self.user_id)
151   - else:
152   - self.user_dir = tempfile.mkdtemp(prefix='',dir=submissions_dir)
153   - self.user_id = self.user_dir.split("/")[-1]
154   - logging.info("Request from user %s" % self.user_id)
155   - logging.debug("Created dir %s" % self.user_dir)
156   - uploaded_file = os.path.join(self.user_dir,"uploaded_file")
  144 +class Instruction:
  145 + def POST(self):
  146 + web_input = web.input(pkgs_file={})
  147 + submissions_dir = "/var/www/AppRecommender/src/web/submissions/"
  148 + user_dir = tempfile.mkdtemp(prefix='',dir=submissions_dir)
  149 + os.chmod(user_dir,stat.S_IRWXU|stat.S_IXOTH|stat.S_IROTH)
  150 + user_id = user_dir.split("/")[-1]
  151 + logging.info("Request from user %s" % user_id)
  152 + logging.debug("Created dir %s" % user_dir)
  153 + uploaded_file = os.path.join(user_dir,"uploaded_file")
157 154 if not os.path.exists(uploaded_file):
158 155 if web_input['pkgs_file'].value:
159 156 lines = web_input['pkgs_file'].file.readlines()
160 157 with open(uploaded_file, "w") as uploaded:
161 158 uploaded.writelines(lines)
162   - with open(uploaded_file) as uploaded:
163   - if uploaded.readline().startswith('POPULARITY-CONTEST'):
164   - self.user = PopconSystem(uploaded_file,self.user_id)
165 159 else:
166   - self.user = PkgsListSystem(uploaded_file,self.user_id)
167   -
168   - def __str__(self):
169   - return "Request %s:\n %s" % (self.user.user_id,
170   - str(self.user.pkg_profile))
171   -
172   - def validates(self):
173   - self.errors = []
174   - if not self.user.pkg_profile:
175   - self.errors.append("No packages list provided.")
176   - if self.errors:
177   - return False
178   - return True
  160 + # saving empty files
  161 + with open(uploaded_file, "w") as uploaded:
  162 + pass
  163 + return render.intro(user_id)
179 164  
180 165 class Survey:
181 166 def __init__(self):
... ... @@ -185,24 +170,46 @@ class Survey:
185 170 self.submissions_dir = "/var/www/AppRecommender/src/web/submissions/"
186 171 if not os.path.exists(self.submissions_dir):
187 172 os.makedirs(self.submissions_dir)
188   -
  173 + self.strategies = ["cbh","cbh_eset",
  174 + "knn","knn_eset","knn_plus",
  175 + "knnco"]
189 176 def POST(self):
190 177 web_input = web.input(pkgs_file={})
191   - logging.debug("Survey web_input %s" % str(web_input))
192   - self.strategies = ["cb","cbh","cb_eset","cbh_eset",
193   - "knn","knn_eset","knn_plus",
194   - "knnco","knnco_eset"]
195   - request = Request(web_input,self.submissions_dir)
196   - if len(request.user.pkg_profile)<10:
  178 + if web_input.has_key('user_id'):
  179 + user_id = web_input['user_id'].encode('utf8')
  180 + user_dir = os.path.join(self.submissions_dir, user_id)
  181 + logging.info("New recommendation for user %s" % user_id)
  182 +
  183 + uploaded_file = os.path.join(user_dir,"uploaded_file")
  184 + with open(uploaded_file) as uploaded:
  185 + if uploaded.readline().startswith('POPULARITY-CONTEST'):
  186 + user = PopconSystem(uploaded_file,user_id)
  187 + else:
  188 + user = PkgsListSystem(uploaded_file,user_id)
  189 + user.maximal_pkg_profile()
  190 + if len(user.pkg_profile)<10:
197 191 error_msg = "Could not extract profile from uploaded file. It must have at least 10 applications."
198 192 logging.critical(error_msg)
199 193 return render.error([error_msg], "/survey/","START")
200 194 else:
201   - request.strategy = self.set_rec_strategy(request.user_id)
202   - prediction = self.rec.get_recommendation(request.user,10).get_prediction()
203   - logging.info("Prediction for user %s" % request.user_id)
  195 + # Check the remaining strategies and select a new one
  196 + old_strategies = [dirs for root, dirs, files in
  197 + os.walk(os.path.join(self.submissions_dir,
  198 + user_id))]
  199 + if old_strategies:
  200 + strategies = [s for s in self.strategies if s not in old_strategies[0]]
  201 + logging.info("Already used strategies %s" % old_strategies[0])
  202 + else:
  203 + strategies = self.strategies
  204 + if not strategies:
  205 + return render.thanks(user_id)
  206 + selected_strategy = random.choice(strategies)
  207 + logging.info("Selected \'%s\' from %s" % (selected_strategy,strategies))
  208 + self.set_rec_strategy(selected_strategy)
  209 + prediction = self.rec.get_recommendation(user,10).get_prediction()
  210 + logging.info("Prediction for user %s" % user_id)
204 211 logging.info(str(prediction))
205   - self.save_prediction(request,prediction)
  212 + self.save_prediction(user_id,selected_strategy,prediction)
206 213  
207 214 # Load packages details
208 215 recommendation = [result[0] for result in prediction]
... ... @@ -215,32 +222,15 @@ class Survey:
215 222  
216 223 if pkgs_details:
217 224 logging.info("Rendering survey slide...")
218   - return render.survey(pkgs_details, request)
  225 + return render.survey(pkgs_details, user_id, selected_strategy, len(strategies))
219 226 else:
220 227 return render.error(["No recommendation produced for the uploaded file."],"/survey/","START")
221 228  
222   - def set_rec_strategy(self,user_id):
223   - # Check the remaining strategies and select a new one
224   - old_strategies = [dirs for root, dirs, files in
225   - os.walk(os.path.join(self.submissions_dir,
226   - user_id))]
227   - if old_strategies:
228   - strategies = [s for s in self.strategies if s not in old_strategies[0]]
229   - logging.info("Already used strategies %s" % old_strategies[0])
230   - else:
231   - strategies = self.strategies
232   - if not strategies:
233   - return render.thanks(request.user_id)
234   - selected_strategy = random.choice(strategies)
235   - logging.info("Selected \'%s\' from %s" % (selected_strategy,strategies))
236   - k=50
237   - n=50
238   - if selected_strategy == "cb":
239   - pass
  229 + def set_rec_strategy(self,selected_strategy):
  230 + k=10
  231 + n=20
240 232 if selected_strategy == "cbh":
241 233 pass
242   - if selected_strategy == "cb_eset":
243   - pass
244 234 if selected_strategy == "cbh_eset":
245 235 pass
246 236 if selected_strategy == "knn":
... ... @@ -251,13 +241,11 @@ class Survey:
251 241 pass
252 242 if selected_strategy == "knnco":
253 243 pass
254   - if selected_strategy == "knnco_eset":
255   - pass
256 244 self.rec.set_strategy(selected_strategy,k,n)
257 245 return selected_strategy
258 246  
259   - def save_prediction(self,request,prediction):
260   - strategy_dir = os.path.join(request.user_dir,request.strategy)
  247 + def save_prediction(self,user_id,strategy,prediction):
  248 + strategy_dir = os.path.join(self.submissions_dir,user_id,strategy)
261 249 if not os.path.exists(strategy_dir):
262 250 os.makedirs(strategy_dir)
263 251 ranking = 0
... ... @@ -279,7 +267,7 @@ class Survey:
279 267 now = datetime.datetime.now()
280 268 start.write(now.strftime("%Y%m%d%H%M%S"))
281 269 logging.debug("Saved prediction to file at %s/%s" %
282   - (request.user_id,request.strategy))
  270 + (user_id,strategy))
283 271 #def add_global_hook():
284 272 # g = web.storage({"counter": "1"})
285 273 # def _wrapper(handler):
... ... @@ -290,7 +278,8 @@ class Survey:
290 278 render = web.template.render('/var/www/AppRecommender/src/web/templates/', base='layout', globals={'hasattr':hasattr})
291 279 render_plain = web.template.render('/var/www/AppRecommender/src/web/templates/', globals={'hasattr':hasattr})
292 280  
293   -urls = ('/apprec', 'Survey',
  281 +urls = ('/apprec', 'Instruction',
  282 + '/evaluation', 'Survey',
294 283 '/thanks', 'Thanks',
295 284 '/save', 'Save',
296 285 '/about', 'About',
... ...
src/web/templates/index_survey.html
... ... @@ -23,7 +23,7 @@ window.onload = function() {
23 23 <a href="http://github.com/tassia/AppRecommender">AppRecommender</a>,
24 24 a recommender system for GNU/Linux applications.</p><br />
25 25 <p align="justify"> Given a list of packages installed in a real
26   - running system and a set of applications will be suggested for it.
  26 + running system, a set of applications will be suggested for it.
27 27 Upload a popularity-contest submission file (usually located at
28 28 '/var/log/popularity-contest') or run the following command and
29 29 upload the generated 'packages.list' file.</p><br />
... ...
src/web/templates/layout.html
... ... @@ -80,7 +80,7 @@ function validateForm()
80 80 <div id="upload-slide">
81 81 <fieldset>
82 82 <p>
83   - <label title="Upload file">Installed packages file: <input type="file" name="pkgs_file" size="20" /></label>
  83 + <label title="Upload file">Installed packages: <input type="file" name="pkgs_file" size="20" /></label>
84 84 </p>
85 85 <div id="tip-upload" class="tip important">
86 86 <p>
... ...
src/web/templates/survey.html
1   -$def with (pkgs_details, request)
  1 +$def with (pkgs_details, user_id, strategy, remaining)
2 2 $var title: Survey
3 3 $var url_base: /survey/
4 4 $var action: START
... ... @@ -28,16 +28,20 @@ $var jsfiles: /static/coda-slider-2.0/javascripts/jquery-1.3.2.min.js /static/co
28 28  
29 29 <div class="show-end" style="display: none;">
30 30  
31   -<p>
32   -If you have any comment regarding this set of suggestions, please write in the form below. Choose <i>Continue</i> if you can perform another round of evaluations, or <i>Finish</i> to conclude your participation.
  31 +<p align="justify">
  32 +If you have any comments regarding this set of suggestions, please write in the
  33 +form below. There are <b>$(remaining-1) remaining</b> recommendation strategies to be evaluated.
  34 +Choose <i>Continue</i> if you can perform one more round of evaluations, or
  35 +<i>Finish</i> to conclude your participation.
33 36 </p>
34 37  
35 38 </div>
36 39  
37 40 <form action="save" method="post" enctype="multipart/form-data" name="surveyform">
38 41  
39   -<input type="hidden" name="user_id" value=$request.user.user_id>
40   -<input type="hidden" name="strategy" value=$request.strategy>
  42 +<input type="hidden" name="user_id" value=$user_id>
  43 +<input type="hidden" name="strategy" value=$strategy>
  44 +<input type="hidden" name="remaining" value=$remaining>
41 45  
42 46 <div style="display: none; width: 400px; margin-left: 150px; margin-top: 10px;" class="show-end"><!-- display show in the end form -->
43 47 <p align="center">
... ... @@ -62,16 +66,20 @@ $for pkg in pkgs_details:
62 66 <div id="panel-controls" class="glass">
63 67 <fieldset>
64 68 <label class="radioButton">
65   - <input class="radio" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="surprising" />
66   - Pleasantly surprising
  69 + <input class="radio" type="radio" name="evaluation-$(pkgs_details.index(pkg))" value="poor" />
  70 + Poor
  71 + </label><br />
  72 + <label class="radioButton">
  73 + <input class="radio" type="radio" name="evaluation-$(pkgs_details.index(pkg))" value="redundant" />
  74 + Redundant
67 75 </label><br />
68 76 <label class="radioButton">
69   - <input class="radio yesb" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="good" />
  77 + <input class="radio" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="useful" />
70 78 Useful
71 79 </label><br />
72 80 <label class="radioButton">
73   - <input class="radio" type="radio" name="evaluation-$(pkgs_details.index(pkg))" value="poor" />
74   - Poor
  81 + <input class="radio" type="radio" name="evaluation-$pkgs_details.index(pkg)" value="surprising" />
  82 + Pleasantly surprising
75 83 </label>
76 84 </fieldset>
77 85 <br style="clear: both;" />
... ...
src/web/templates/thanks.html
... ... @@ -14,14 +14,25 @@ $var cssfiles: static/css/survey.css
14 14 <div class="innertube">
15 15  
16 16 <h1>AppRecommender Survey</h1>
17   -<p>Thank you very much for participating in this survey, you help is very much
18   -appreciated! Identify yourself if you want to be mentioned in our thanks page
19   -and final report.
20   -</p><br />
  17 +<p>Thank you very much for participating in this survey!</p>
  18 +<p>Last but not least, we'd like to have your personal identification to mention
  19 +your name in our thanks page. The awareness of your installation habits would
  20 +make our report more informative and, finally, we appreciate general comments
  21 +regarding this survey and/or the recommendations you got.</p>
21 22  
22 23 <div style="margin-left:150px;" id="optionalform">
23 24 <center>
24 25 <form action="thanks" method="post" enctype="multipart/form-data" name="identification_form">
  26 +<div style="text-align: left;">
  27 + <p><label style="margin-left: 7px">Admin's habit</label>
  28 + <fieldset style="margin-left: 20px">
  29 + <input type=radio class=radio name="user_habits" value="1">I rarely install new applications.<br />
  30 + <input type=radio class=radio name="user_habits" value="2">I only install when I get a trusted recommendation.<br />
  31 + <input type=radio class=radio name="user_habits" value="3">I actively seek for new applications.<br />
  32 + <input type=radio class=radio name="user_habits" value="0">I would rather not comment on that.<br />
  33 + </fieldset>
  34 + </p>
  35 +</div>
25 36 <p>
26 37 <label>
27 38 <input type="hidden" name="user_id" value=$user_id>
... ...
src/web/templates/thanks_id.html
... ... @@ -10,7 +10,7 @@ $var cssfiles: static/css/survey.css
10 10  
11 11 <center>
12 12 <h1>Thanks!</h1>
13   -<p>Thank you once again and stay tuned for the survey report.</p><br />
  13 +<p>Thank you once again, your help is very much appreciated!</p><br />
14 14 </center>
15 15  
16 16 </div><!-- class="innertube" -->
... ...