summaryrefslogtreecommitdiff
path: root/lib/model.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/model.rb')
-rw-r--r--lib/model.rb152
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/model.rb b/lib/model.rb
new file mode 100644
index 0000000..dfc779c
--- /dev/null
+++ b/lib/model.rb
@@ -0,0 +1,152 @@
+# Get a list of all prediction models
+# @param [Header] Accept one of text/uri-list,
+# @return [text/uri-list] list of all prediction models
+get "/api/model/?" do
+ models = Model::Validation.all
+ case @accept
+ when "text/uri-list"
+ uri_list = models.collect{|model| uri("/api/model/#{model.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ models = JSON.parse models.to_json
+ list = []
+ models.each{|m| list << uri("/api/model/#{m["_id"]["$oid"]}")}
+ return list.to_json
+ else
+ halt 400, "Mime type #{@accept} is not supported."
+ end
+end
+
+get "/api/model/:id/?" do
+ model = Model::Validation.find params[:id]
+ halt 400, "Model with id: #{params[:id]} not found." unless model
+ model["training_dataset"] = model.model.training_dataset.id.to_s
+ return model.to_json
+end
+
+post "/api/model/:id/?" do
+ if request.content_type == "application/x-www-form-urlencoded"
+ identifier = params[:identifier].strip.gsub(/\A"|"\Z/,'')
+ compound = Compound.from_smiles identifier
+ model = Model::Validation.find params[:id]
+ prediction = model.predict(compound)
+ output = {:compound => {:id => compound.id, :inchi => compound.inchi, :smiles => compound.smiles},
+ :model => model,
+ :prediction => prediction
+ }
+ return 200, output.to_json
+ elsif request.content_type =~ /^multipart\/form-data/ && request.content_length.to_i > 0
+ @task = Task.new
+ @task.save
+ task = Task.run do
+ m = Model::Validation.find params[:id]
+ @task.update_percent(0.1)
+ dataset = Batch.from_csv_file params[:fileName][:tempfile]
+ compounds = dataset.compounds
+ $logger.debug compounds.size
+ identifiers = dataset.identifiers
+ ids = dataset.ids
+ type = (m.regression? ? "Regression" : "Classification")
+ # add header for regression
+ if type == "Regression"
+ unit = (type == "Regression") ? "(#{m.unit})" : ""
+ converted_unit = (type == "Regression") ? "#{m.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : ""
+ if ids.blank?
+ header = "ID,Input,Endpoint,Unique SMILES,inTrainingSet,Measurements #{unit},Prediction #{unit},Prediction #{converted_unit},"\
+ "Prediction Interval Low #{unit},Prediction Interval High #{unit},"\
+ "Prediction Interval Low #{converted_unit},Prediction Interval High #{converted_unit},"\
+ "inApplicabilityDomain,Note\n"
+ else
+ header = "ID,Original ID,Input,Endpoint,Unique SMILES,inTrainingSet,Measurements #{unit},Prediction #{unit},Prediction #{converted_unit},"\
+ "Prediction Interval Low #{unit},Prediction Interval High #{unit},"\
+ "Prediction Interval Low #{converted_unit},Prediction Interval High #{converted_unit},"\
+ "inApplicabilityDomain,Note\n"
+ end
+ end
+ # add header for classification
+ if type == "Classification"
+ av = m.prediction_feature.accept_values
+ if ids.blank?
+ header = "ID,Input,Endpoint,Unique SMILES,inTrainingSet,Measurements,Prediction,"\
+ "predProbability #{av[0]},predProbability #{av[1]},inApplicabilityDomain,Note\n"
+ else
+ header = "ID,Original ID,Input,Endpoint,Unique SMILES,inTrainingSet,Measurements,Prediction,"\
+ "predProbability #{av[0]},predProbability #{av[1]},inApplicabilityDomain,Note\n"
+ end
+ end
+ # predict compounds
+ p = 100.0/compounds.size
+ counter = 1
+ predictions = []
+ compounds.each_with_index do |cid,idx|
+ compound = Compound.find cid
+ #$logger.debug compound.inspect
+ if Prediction.where(compound: compound.id, model: m.id).exists?
+ prediction_object = Prediction.find_by(compound: compound.id, model: m.id)
+ prediction = prediction_object.prediction
+ prediction_id = prediction_object.id
+ # in case prediction object was created by single prediction
+ if prediction_object.csv.blank?
+ prediction_object[:csv] = prediction_to_csv(m,compound,prediction)
+ prediction_object.save
+ end
+ # identifier
+ identifier = identifiers[idx]
+ else
+ prediction = m.predict(compound)
+ # save prediction object
+ prediction_object = Prediction.new
+ prediction_id = prediction_object.id
+ prediction_object[:compound] = compound.id
+ prediction_object[:model] = m.id
+ # add additionally fields for html representation
+ unless prediction[:value].blank? || type == "Classification"
+ prediction[:prediction_value] = "#{prediction[:value].delog10.signif(3)} #{unit}"
+ prediction["converted_prediction_value"] = "#{compound.mmol_to_mg(prediction[:value].delog10).signif(3)} #{converted_unit}"
+ end
+ unless prediction[:prediction_interval].blank?
+ interval = prediction[:prediction_interval]
+ prediction[:interval] = "#{interval[1].delog10.signif(3)} - #{interval[0].delog10.signif(3)} #{unit}"
+ prediction[:converted_interval] = "#{compound.mmol_to_mg(interval[1].delog10).signif(3)} - #{compound.mmol_to_mg(interval[0].delog10).signif(3)} #{converted_unit}"
+ end
+ prediction["unit"] = unit
+ prediction["converted_unit"] = converted_unit
+ if prediction[:measurements].is_a?(Array)
+ prediction["measurements_string"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10.signif(3)} #{unit}"} : prediction[:measurements].join("</br>")
+ prediction["converted_measurements"] = prediction[:measurements].collect{|value| "#{compound.mmol_to_mg(value.delog10).signif(3)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"} if type == "Regression"
+ else
+ output["measurements_string"] = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} #{unit}}" : prediction[:measurements]
+ output["converted_measurements"] = "#{compound.mmol_to_mg(prediction[:measurements].delog10).signif(3)} #{(unit =~ /\b(mmol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if type == "Regression"
+ end
+
+ # store in prediction_object
+ prediction_object[:prediction] = prediction
+ prediction_object[:csv] = prediction_to_csv(m,compound,prediction)
+ prediction_object.save
+
+ # identifier
+ identifier = identifiers[idx]
+ end
+ # collect prediction_object ids with identifier
+ predictions << {"#{identifier}" => prediction_id}
+ $logger.debug predictions.inspect
+ @task.update_percent((counter*p).ceil > 100 ? 100 : (counter*p).ceil)
+ counter += 1
+ end
+ # write csv
+ @task[:csv] = header
+ # write predictions
+ # save task
+ # append predictions as last action otherwise they won't save
+ # mongoid works with shallow copy via #dup
+ @task[:predictions] = {m.id.to_s => predictions}
+ @task[:dataset_id] = dataset.id
+ @task[:model_id] = m.id
+ @task.save
+ end#main task
+ tid = @task.id.to_s
+ return 202, "//#{$host_with_port}/task/#{tid}".to_json
+ else
+ halt 400, "No accepted content type"
+ end
+end