Commit 896fcc0700b027acebed531bcf18efa7ec2a1c02

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

Integrated recommender and new web form; changed section about; changes frontpage layout;

src/web/server.py
... ... @@ -6,6 +6,7 @@ import tempfile
6 6 import sys
7 7 import simplejson as json
8 8 import apt
  9 +import re
9 10  
10 11 sys.path.insert(0,"../")
11 12  
... ... @@ -15,44 +16,24 @@ from user import *
15 16  
16 17 import urllib
17 18  
18   -class RequestForm(form.Form):
19   - def __init__(self):
20   - form.Form.__init__(self, \
21   - form.File("pkgs_file", size=35, description="Upload file"),
22   - form.Textarea("pkgs_list", description="Packages",
23   - rows="4", cols="52"),
24   - form.Dropdown('limit', [(5, '05'), (10, '10'), (20, '20')],
25   - description = "Limit"),
26   - form.Checkbox("strategy_cb", value=1, checked=False,
27   - description="Content-based"),
28   - form.Checkbox("strategy_col", value=1, checked=False,
29   - description="Collaborative"),
30   - form.Checkbox("strategy_hybrid", value="True", checked=False,
31   - description="Hybrid"),
32   - form.Checkbox("strategy_hybrid_plus", value="True", checked=False,
33   - description="Hybrid plus"),
34   - validators = [form.Validator("No packages list provided.",
35   - lambda f: f.has_key("pkgs_list") |
36   - f.has_key("pkgs_file") ),
37   - form.Validator("No strategy selected.",
38   - lambda f: f.has_key("strategy_cb") |
39   - f.has_key("startegy_col") |
40   - f.has_key("strategy_hybrid") |
41   - f.has_key("strategy_hybrid_plus")) ])
42   -
43 19 class FeedbackForm(form.Form):
44   - def __init__(self,strategies):
45   - desc_dict = {"cta": "Content-based", "col": "Collaborative",
46   - "hybrid": "Hybrib", "hybrid_plus": "Hybrid Plus"}
  20 + def __init__(self,selected_strategies):
  21 + desc_dict = {"cb": "Content-based", "cbt": "Content-based",
  22 + "cbd": "Content-based", "col": "Collaborative",
  23 + "hybrid": "Hybrib"}
47 24 fields = []
48   - for strategy in strategies:
  25 + for strategy in selected_strategies:
49 26 fields.append(form.Radio(desc_dict[strategy],
50 27 [('1','1 '),('2','2 '),('3','3'),('4','4 '),('5','5')]))
51 28 form.Form.__init__(self, *fields, validators = [])
52 29  
53 30 class Index:
54 31 def GET(self):
55   - return render.index("/apprec", "post", RequestForm())
  32 + return render.index()
  33 +
  34 +class About:
  35 + def GET(self):
  36 + return render.about()
56 37  
57 38 class Thanks:
58 39 def POST(self):
... ... @@ -95,52 +76,108 @@ class Package:
95 76 subtags = []
96 77 return debtags
97 78  
  79 +class Request:
  80 + def __init__(self,web_input,user_id):
  81 + self.user_id = user_id
  82 + self.storage = web_input
  83 +
  84 + self.pkgs_list = []
  85 + if web_input.has_key('pkgs_list'):
  86 + self.pkgs_list = web_input['pkgs_list'].encode('utf8').split()
  87 + print self.pkgs_list
  88 + print web_input['pkgs_file']
  89 + if web_input['pkgs_file']:
  90 + f = open(outputdir + "/packages_list", "wb")
  91 + lines = web_input['pkgs_file'].file.readlines()
  92 + print lines
  93 + if lines[0].startswith('POPULARITY-CONTEST'):
  94 + del lines[0]
  95 + del lines[-1]
  96 + package_name_field = 2
  97 + else:
  98 + package_name_field = 0
  99 + for line in lines:
  100 + self.pkgs_list.append(line.split()[package_name_field])
  101 + f.write(line)
  102 + f.close()
  103 +
  104 + if web_input.has_key('limit'):
  105 + self.limit = int(web_input['limit'])
  106 + if web_input.has_key('profile_size'):
  107 + self.profile_size = int(web_input['profile_size'])
  108 + if web_input.has_key('weight'):
  109 + self.weight = web_input['weight'].encode('utf8')
  110 +
  111 + self.selected_strategies = []
  112 + if web_input.has_key('strategy'):
  113 + if web_input['strategy'].encode('utf8') == "content":
  114 + if (web_input.has_key('tag') and web_input.has_key('desc')):
  115 + self.selected_strategies.append("cb")
  116 + elif web_input.has_key('desc'):
  117 + self.selected_strategies.append("cbd")
  118 + else:
  119 + self.selected_strategies.append("cbt")
  120 + if web_input['strategy'].encode('utf8') == "collab":
  121 + self.selected_strategies.append("col")
  122 + if web_input['strategy'].encode('utf8') == "hybrid":
  123 + self.selected_strategies.append("hybrid")
  124 +
  125 + if web_input.has_key('cluster'):
  126 + self.cluster = bool(web_input.has_key['cluster'].encode('utf8'))
  127 +
  128 + if web_input.has_key('neighbours'):
  129 + self.neighbours = int(web_input['neighbours'])
  130 +
  131 + self.profiles_set = set()
  132 + if web_input.has_key('profile_desktop'):
  133 + self.profiles = self.profiles.add("desktop")
  134 + if web_input.has_key('profile_admin'):
  135 + self.profiles = self.profiles.add("admin")
  136 + if web_input.has_key('profile_devel'):
  137 + self.profiles = self.profiles.add("devel")
  138 + if web_input.has_key('profile_science'):
  139 + self.profiles = self.profiles.add("science")
  140 + if web_input.has_key('profile_arts'):
  141 + self.profiles = self.profiles.add("arts")
  142 +
  143 + def __str__(self):
  144 + return self.storage
  145 +
  146 + def validates(self):
  147 + self.errors = []
  148 + if (not self.pkgs_list or not self.selected_strategies):
  149 + self.errors.append("No upload file or packages list was provided.")
  150 + return False
  151 + if not self.selected_strategies:
  152 + self.errors.append("No strategy was selected.")
  153 + return False
  154 + return True
  155 +
  156 + def get_strategy_details(self):
  157 + return self.selected_strategies[0]
98 158  
99 159 class AppRecommender:
100 160 def POST(self):
  161 + print "post",web.input()
101 162 outputdir = tempfile.mkdtemp(prefix='',dir='./submissions/')
102 163 user_id = outputdir.lstrip('./submissions/')
103   - request = RequestForm()
104   - request_info = web.input(pkgs_file={})
105   - if not request.validates(request_info):
106   - return render.error(request)
  164 + print web.input(pkgs_file={})
  165 + request = Request(web.input(pkgs_file={}),user_id)
  166 + if not request.validates():
  167 + return render.error(request.errors)
107 168 else:
108   - user_pkgs_list = []
109   - if request_info.has_key('pkgs_list'):
110   - user_pkgs_list = request_info['pkgs_list'].encode('utf8').split()
111   - print user_pkgs_list
112   -
113   - if request_info['pkgs_file'].value:
114   - f = open(outputdir + "/packages_list", "wb")
115   - lines = request_info['pkgs_file'].file.readlines()
116   - print lines
117   - if lines[0].startswith('POPULARITY-CONTEST'):
118   - del lines[0]
119   - del lines[-1]
120   - package_name_field = 2
121   - else:
122   - package_name_field = 0
123   - for line in lines:
124   - user_pkgs_list.append(line.split()[package_name_field])
125   - f.write(line)
126   - f.close()
127   -
128   - strategies = []
129   - if request_info.has_key('strategy_cb'): strategies.append("cta")
130   - ### Colaborative strategies can not go online yet
131   - if request_info.has_key('strategy_col'): strategies.append("col")
132   - if request_info.has_key('strategy_hybrid'):
133   - strategies.append("hybrid")
134   - if request_info.has_key('strategy_hybrid_plus'):
135   - strategies.append("hybrid_plus")
136   - recommends = self._recommends(user_id,user_pkgs_list,strategies, int(request_info['limit']))
  169 + recommendation = self._recommends(request)
137 170 ### Getting package summary (short description) ###
138 171 pkg_summaries = {}
139 172 cache = apt.Cache()
140   - for strategy, result in recommends.items():
  173 + for strategy, result in recommendation.items():
141 174 for pkg in result:
142   - pkg_summaries[pkg] = cache[pkg].candidate.summary
143   - return render.apprec(recommends, pkg_summaries, FeedbackForm(strategies))
  175 + try:
  176 + pkg_summaries[pkg] = cache[pkg].candidate.summary
  177 + except:
  178 + pkg_summaries[pkg] = ""
  179 + return render.apprec(recommendation, pkg_summaries,
  180 + FeedbackForm(request.selected_strategies),request)
144 181  
145 182 # parsing json from screenshots - can be usefull in the future...
146 183 # def _packages_attrs(self, recommends): #recommends is result of _recommends()
... ... @@ -156,18 +193,16 @@ class AppRecommender:
156 193 # recommended_pkgs_attrs[pkg_attrs_dict['name']] = pkg_attrs_dict
157 194 # return recommended_pkgs_attrs
158 195  
159   - def _recommends(self,user_id,user_pkgs_list,strategies,limit):
160   - user = User(dict.fromkeys(user_pkgs_list,1),user_id)
  196 + def _recommends(self,request):
  197 + user = User(dict.fromkeys(request.pkgs_list,1),request.user_id)
161 198 user.maximal_pkg_profile()
162 199 cfg = Config()
163 200 rec = Recommender(cfg)
164 201 results = dict()
165   - for strategy in strategies:
166   - ### Colaborative strategies can not go online yet
167   - #eval("rec."+strategy+"(cfg)")
168   - rec.cta(cfg)
169   - prediction = rec.get_recommendation(user).get_prediction(limit)
170   - results[rec.strategy.description] = \
  202 + for strategy_str in request.selected_strategies:
  203 + rec.set_strategy(strategy_str)
  204 + prediction = rec.get_recommendation(user).get_prediction(request.limit)
  205 + results[strategy_str] = \
171 206 [result[0] for result in prediction]
172 207 return results
173 208  
... ... @@ -181,9 +216,10 @@ def add_global_hook():
181 216 render = web.template.render('templates/', base='layout')
182 217 render_plain = web.template.render('templates/')
183 218  
184   -urls = ('/', 'Index',
185   - '/apprec', 'AppRecommender',
  219 +urls = ('/', 'Index',
  220 + '/apprec', 'AppRecommender',
186 221 '/thanks', 'Thanks',
  222 + '/about', 'About',
187 223 '/package/(.*)', 'Package'
188 224 )
189 225  
... ...
src/web/templates/about.html 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +$var title: About
  2 +$var mod = 'about';
  3 +
  4 +<div class="graybox">
  5 + <h1>What is this?</h1>
  6 +<p>AppRecommender is a project in development that aims to provide solutions
  7 +for application recommendation at the GNU/Linux world. It was initially thought
  8 +as a Debian package recommender, but considering the multi-distro effort in
  9 +providing platform independent solutions, it should also follow this
  10 +principle.</p>
  11 +</div>
  12 +
  13 +<div class="align-right"><img alt="AppRecommender logo" src="/static/images/AppRecommender-logo.jpg" width="320" /></div>
  14 +
... ...
src/web/templates/apprec.html
1   -$def with (recommends, pkg_summaries, form)
  1 +$def with (recommends, pkg_summaries, form, request)
2 2 $var title: Feedback
3 3 $var mod = 'feedback';
4 4  
5   -
6 5 <script type="application/x-javascript">
7 6 $$(document).ready(function() {
8 7 inithandlers();
... ... @@ -12,18 +11,19 @@ $$(document).ready(function() {
12 11 </script>
13 12  
14 13 <div class="graybox">
15   - <h1>Results per strategy</h1>
16   -<ul class="toc">
  14 + <h1>Details of recommendation strategy</h1>
  15 + $request.get_strategy_details()
  16 +<!--<ul class="toc">
17 17 $for strategy, result in recommends.items():
18 18 <li><a href="#$strategy">$strategy</a></li>
19 19 </ul>
20   -</div>
  20 +</div>-->
21 21  
22   -<form action="/thanks" method="post">
  22 +<form action="/thanks" method="post" enctype="multipart/form-data">
23 23 <table>
24 24 <tbody>
25 25 $for strategy, result in recommends.items():
26   - <h2><a name="$strategy" id="$strategy">$strategy</a></h2>
  26 + <!--<h2><a name="$strategy" id="$strategy">$strategy</a></h2>-->
27 27 <tr>
28 28 $ count = 0
29 29 $for pkg in result:
... ...
src/web/templates/error.html
1   -$def with (form)
  1 +$def with (error_msgs)
2 2 $var title: Error
3 3 $var mod = 'error';
4 4  
... ... @@ -11,10 +11,10 @@ $var mod = &#39;error&#39;;
11 11  
12 12 Your request could not be proccessed due to the following error(s):
13 13  
14   -<ul>
15   -$for v in form.validators:
16   - <b><li>$v.msg</li></b>
17   -</ul>
  14 +<p><ul>
  15 +$for e in error_msgs:
  16 + <b><li>$e</li></b>
  17 +</ul></p>
18 18  
19 19 <p><a href="/">Go back</a> and try again. </p>
20 20 <p>If you believe it is a bug, please report to <a
... ...
src/web/templates/index.html
1   -$def with (action, method, form)
2 1 $var title: Home
3 2 $var mod = 'index';
4 3  
5 4 <div class="graybox">
6   - <h1>What is this?</h1>
7   -<p>AppRecommender is a project in development that aims to provide solutions
8   -for application recommendation at the GNU/Linux world. It was initially thought
9   -as a Debian package recommender, but considering the multi-distro effort in
10   -providing platform independent solutions, it should also follow this
11   -principle.</p>
12   -</div>
  5 +<h1>You might also like these packages...</h1>
13 6  
14   -<div class="align-right"><img alt="AppRecommender logo" src="/static/images/AppRecommender-logo.jpg" width="320" /></div>
  7 +<p>Provide a list of packages or upload a popcon submission file and you'll get
  8 +a list of suggested packages automatically computed by AppRecommender. You can
  9 +customize the recommender setup or let it randomly choose a setup for you.</p>
15 10  
  11 +<p>Please fill in the form that follows the recommendation results. Your
  12 +feedback is very much appreciated!</p>
16 13  
  14 +<p>Enjoy it :)</p>
  15 +</div>
17 16  
  17 +<!--<div class="align-right"><img alt="AppRecommender logo"
  18 +src="/static/images/AppRecommender-logo.jpg" width="320" /></div>-->
18 19  
19   -<form action="" name="weboptions">
  20 +<form action="apprec" enctype="multipart/form-data" method="post" name="weboptions">
20 21 <p>
  22 + <label>Upload file:<input type="file" id="pkgs_file" name="pkgs_file" size="35"/></label><br />
  23 + <label>Packages list:<textarea rows="2" cols="40" name="pkgs_list" id="pkgs_list"></textarea><label><br />
21 24 <label>Profile size: <input type="text" name="profile_size" value="10"></label><br />
22   - <label>Recommendations: <input type="text" name="recommendation_size" value="10"></label><br />
23   - <label>Weighting scheme:<br /><input type="radio" name="scheme" value="BM25">BM25</label><br />
24   - <label><input type="radio" name="scheme" value="trad"></label>Traditional<br />
25   - <label>Strategy: <br /><input type="radio" name="strategy" value="content"> Content-based</label><br />
26   - <label><input type="radio" name="strategy" value="collab"> Collaborative</label><br />
27   - <label><input type="radio" name="strategy" value="hybrid"> Hybrid</label><br />
  25 + <label>Recommendation size: <input type="text" name="limit" value="10"></label><br />
  26 + <label>Weighting scheme:<br />
  27 + <input type="radio" name="weight" value="BM25" checked >BM25<br />
  28 + <input type="radio" name="weight" value="trad">Traditional<br />
  29 + </label>
  30 + <label>Strategy: <br />
  31 + <input type="radio" name="strategy" value="content" checked> Content-based<br />
  32 + <input type="radio" name="strategy" value="collab"> Collaborative<br />
  33 + <input type="radio" name="strategy" value="hybrid"> Hybrid<br />
  34 + </label>
28 35 <!-- <label>Password:<input type="password" name="pass"></label> -->
29   - <label style="margin-bottom: 1em; padding-bottom: 1em; border-bottom: 3px silver groove;"><input type="hidden" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"></label>
30   - <label><input type="checkbox" name="ssh" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"> Tag</label>
31   - <label><input type="checkbox" name="iis" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"> Description</label>
32   - <br /><label><input type="checkbox" name="asp" class="DEPENDS ON strategy BEING collab OR strategy BEING hybrid"> Clustering</label><br />
33   - <label>Neighbours: <input type="text" name="neighbours" class="DEPENDS ON strategy BEING collab OR strategy BEING hybrid" value="50"></label><br />
34   -
35   - <label>Personal profile: <br /><input type="checkbox" name="user_desktop" checked class="DEPENDS ON strategy BEING hybrid">Desktop</label>
36   - <label><input type="checkbox" name="neighbours" class="DEPENDS ON strategy BEING hybrid">Admin</label>
37   - <label><input type="checkbox" name="neighbours" class="DEPENDS ON strategy BEING hybrid">Devel</label>
38   - <label><input type="checkbox" name="neighbours" class="DEPENDS ON strategy BEING hybrid">Science</label>
39   - <label><input type="checkbox" name="neighbours" class="DEPENDS ON strategy BEING hybrid">Arts</label>
  36 + <!-- <label style="margin-bottom: 1em; padding-bottom: 1em; border-bottom: 3px silver groove;"><input type="hidden" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"></label> -->
  37 + </p><p>
  38 + <label>Content attributes:
  39 + <input type="radio" name="content" value="tag" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid" checked> tag
  40 + <input type="radio" name="content" value="desc" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"> description
  41 + <input type="radio" name="content" value="full" class="DEPENDS ON strategy BEING content OR strategy BEING hybrid"> both
  42 + </label><br />
  43 + <label>Clustering
  44 + <input type="radio" name="cluster" value="True" class="DEPENDS ON strategy BEING collab OR strategy BEING hybrid" checked> Yes
  45 + <input type="radio" name="cluster" value="False" class="DEPENDS ON strategy BEING collab OR strategy BEING hybrid"> No
  46 + </label><br />
  47 + <label>Neighbours:
  48 + <input type="text" name="neighbours" class="DEPENDS ON strategy BEING collab OR strategy BEING hybrid" value="50">
  49 + </label><br />
  50 + <label>Personal profile:
  51 + <input type="checkbox" name="profile_desktop" class="DEPENDS ON strategy BEING hybrid" checked>Desktop
  52 + <input type="checkbox" name="profile_admin" class="DEPENDS ON strategy BEING hybrid">Admin
  53 + <input type="checkbox" name="profile_devel" class="DEPENDS ON strategy BEING hybrid">Devel
  54 + <input type="checkbox" name="profile_science" class="DEPENDS ON strategy BEING hybrid">Science
  55 + <input type="checkbox" name="profile_arts" class="DEPENDS ON strategy BEING hybrid">Arts
  56 + </label>
40 57 </p>
41 58 <input type="submit" />
42 59 </form>
43 60  
44   -<!--
45   -<form action="$action" enctype="multipart/form-data" method="$method">
46   -$:form.render()
47   -<br />
48   -<input type="submit" />
49   -</form>
50   --->
... ...
src/web/templates/layout.html
1 1 $def with (content)
2   -$ url_base = "http://localhost:8080/"
  2 +$ url_base = "http://localhost:8080"
3 3  
4 4 <!DOCTYPE html>
5 5 <html lang="en"><head>
... ... @@ -133,7 +133,7 @@ function hideMesg(){
133 133 <div id="nav">
134 134 <a href="$url_base">Home</a>
135 135 |
136   - <a href="http://www.ime.usp.br/~tassia/apprec.html">About</a>
  136 + <a href="$url_base/about">About</a>
137 137 |
138 138 <a href="http://github.com/tassia/AppRecommender">Devel</a>
139 139 </div>
... ...