Class: Levdon::LevdonImpl

Inherits:
Object
  • Object
show all
Defined in:
lib/levdon.rb

Instance Method Summary collapse

Constructor Details

#initializeLevdonImpl

def LevdonImpl.dealloc(workers)

proc {|id|
  begin
    workers.each(&:stop)
    workers = nil
  rescue => e
    # nothing to do
  end
}

end



553
554
555
556
557
558
559
560
561
# File 'lib/levdon.rb', line 553

def initialize()
  @access_token = "DUMMY"
  @blocks       = {}
  @timeout      = 10.0 # default 10sec
  @request_cluster_num = 1
  
  # prediction parameters 
  @ontologies = [:CLASS_ADULT]
end

Instance Method Details

#_predict_impl(parameter) ⇒ Object



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# File 'lib/levdon.rb', line 563

def _predict_impl(parameter)
  ret   = nil
  error = nil
  
  f             = parameter[:target]
  request_id    = parameter[:request_id]
  ontologies    = parameter[:ontologies]
  access_token  = parameter[:access_token]
  url           = URI.parse(API_URL)
  
  options       = {}
  options['ontologies'] = []
  error = "Class is not specified." if ontologies.length == 0
  ontologies.each{|key|
    obj = ONTOLOGY_LIST[key]
    unless obj
      error = "Invalid key => " + key.to_s 
      break
    end
    unless obj[:available]
      error = key.to_s + " class is not available.\n Reason => #{obj[:desc]}" 
      break
    end
    options['ontologies'] += [obj[:key]]
  }
  if(!error)
    stream = load(f)
    if(stream)
      io = nil
      begin
        io = StringIO.new(Levdon.prob_resize(stream))
        req = Net::HTTP::Post::Multipart.new url.path,
          "api_version"   => API_VERSION,
          "upload"        => UploadIO.new(io, "image/jpeg", "image.jpg"),
          "request_id"    => request_id,
          "access_token"  => access_token,
          "constant_id"   => APPLICATION_ID,
          "options"       => JSON.generate(options)
  
        n = Net::HTTP.new(url.host, url.port) 
        n.use_ssl = ENABLE_SSL
  
        res = n.start {|http| http.request(req) }
      
        j = JSON.parse(res.body)
        if(res.code == '200' and j['results'])
          # TODO: data struct problem
          ret = {}
          j['results'].each{|k,v|
            ret[ONTOLOGY_REV_LIST[k]] = v
          }
        else
          ret = nil
          error = j['desc']
        end
      rescue => e
        error = ""
        error += e.class.to_s + "\n"
        error += e.message.to_s + "\n"
        error += e.backtrace.to_s + "\n"
      ensure
        if(io)
          begin
            io.close()
          rescue IOError
            # nothing to do
          rescue => e
            error = ""
            error += e.class.to_s + "\n"
            error += e.message.to_s + "\n"
            error += e.backtrace.to_s + "\n"
          end
        end
      end
    else
      error = "Could not read a '#{f.to_s}'."
    end
  end
  return {:error=>error,:result=>ret}
end

#async_predict(parameter, &block) ⇒ Object



822
823
824
825
826
827
828
829
830
# File 'lib/levdon.rb', line 822

def async_predict(parameter,&block)
  raise "expected key: request_id" if(parameter[:request_id])
  raise "expected key: ontologies" if(parameter[:ontologies])
  raise "required key: target. Specify a file path or URL or data." unless(parameter[:target])
  parameter[:request_id] = SecureRandom.uuid.gsub("-","")
  parameter[:ontologies] = @ontologies
  enqueue(parameter)
  @blocks[VUUID+parameter[:request_id]] = block
end

#async_start(access_token, &block) ⇒ Object



644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/levdon.rb', line 644

def async_start(access_token,&block)
  @access_token = access_token
  @workers = @request_cluster_num.times.map{
    Worker.new{|*args|
      ret   = nil
      error = nil
      begin
        parameter   = args[0]
        parameter[:access_token] = access_token
        obj = _predict_impl(parameter)
        ret = obj[:result]
        error = obj[:error]
      rescue => e
        error = ""
        error += e.class.to_s + "\n"
        error += e.message.to_s + "\n"
        error += e.backtrace.to_s + "\n"
      end
      
      {:results => ret, :error => error}
    }
  }
  
  @workers.map(&:run).each(&:join)
  @roundrobin_counter       = 0
  @task_stacking_counter    = []
  @workers.length.times{|i| @task_stacking_counter.push([i,0]) }
  #ObjectSpace.define_finalizer(self,LevdonImpl.dealloc(@workers))
  
  # CTRL + C
  Signal.trap(:INT) {
    puts "Stop " + APPLICATION_ID + " clients "
    close()
    exit(0)
  }
  
  block.call({:error => nil})
end

#closeObject



835
836
837
838
839
840
841
# File 'lib/levdon.rb', line 835

def close
  begin
    @workers.each(&:stop)
  rescue => e
    # nothing to do
  end
end

#detect_content_type(ouri) ⇒ Object



700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
# File 'lib/levdon.rb', line 700

def detect_content_type(ouri)
  if(ouri)
    if(ouri.respond_to?(:content_type))
      ct = ouri.content_type
      if(ct)
        if(ct.index('image'))
          return 'image'
        elsif(ct.index('video'))
          return 'video'
        end
      end
    else
      return 'file'
    end
  end
  return nil
end

#detect_image_or_video_from_path(path) ⇒ Object



718
719
720
721
722
723
724
725
726
# File 'lib/levdon.rb', line 718

def detect_image_or_video_from_path(path)
  ext = File.extname(path).downcase
  if(ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".jpg" || ext == ".tiff" || ext == ".tif" || ext == ".psd" || ext == ".pdf")
    return "image"
  elsif(ext == ".mp4" || ext == ".avi" || ext == ".mov" || ext == ".3gp" || ext == ".flv" || ext == ".wmv")
    return "video"
  end
  return nil
end

#enqueue(*args) ⇒ Object



812
813
814
815
816
817
818
819
820
# File 'lib/levdon.rb', line 812

def enqueue(*args)
  target = @task_stacking_counter.sort{|a,b| a[1]-b[1]}[0][0]
  @task_stacking_counter[target][1] += 1
  #target = @roundrobin_counter % @workers.length
  #@roundrobin_counter += 1
  
  worker = @workers[target]
  worker.async_execute(*args)
end

#generate_thumb_from_video(f) ⇒ Object



728
729
730
731
732
733
734
735
736
737
# File 'lib/levdon.rb', line 728

def generate_thumb_from_video(f)
  thumb_url = "tmp"+Process.pid.to_s
  movie = FFMPEG::Movie.new(f)
  duration = (movie.duration / 2).floor
  path = "#{thumb_url}.jpg"
  movie.screenshot(path,  seek_time: duration)
  data = File.open(path).read()
  File.delete(path)
  return data
end

#load(any) ⇒ Object



749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
# File 'lib/levdon.rb', line 749

def load(any)
  if(any.class.name == "String")
    if(any.index("http://") == 0 or any.index("https://") == 0)
      # from network
      ouri = open(any)
      ct = detect_content_type(ouri)
      new_data = nil
      if(ct == "video")
        new_data = generate_thumb_from_video(ouri.path)
      elsif(ct == "image")
        new_data = ouri.read
      end
      return new_data
    else
      if File::ftype(any) == "file"
        ct = detect_image_or_video_from_path(any)
        if(ct == "video")
          return generate_thumb_from_video(any)
        elsif(ct ==  "image")
          return File.open(any).read
        end
        puts "Invalid media file."
        return nil
      elsif(File::ftype(any) == "directory")
        puts "Can't load a directory. Target should be a file or URL."
        return nil
      else
        # from memory
        return any
      end
    end
  else
    # from memory
    return any
  end
  return nil
end

#option(obj) ⇒ Object



688
689
690
691
692
693
694
695
696
697
698
# File 'lib/levdon.rb', line 688

def option(obj)
  obj.each{|k,v|
    if(k == :CLASS)
      @ontologies = v
    elsif(k == :PARALLEL)
      @request_cluster_num = v
    else
      puts "Invalid option : " + k.to_s
    end
  }
end

#pollObject



787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
# File 'lib/levdon.rb', line 787

def poll
  @workers.each(&:poll)
  @workers.map(&:nonblock_read_from_child).each_with_index{|ret,i|
    begin
      if(ret)
        request_id = ret[:parameter][:request_id]
        key = VUUID + request_id
        if(@blocks.has_key?(key))
          @task_stacking_counter[i][1] -= 1
          @blocks[key].call(ret)
          @blocks.delete(key)
        else
          puts "Error"
          puts "Invalid response from server."
        end
      end
    rescue => e
      puts "Response error"
      puts e.class
      puts e.message
      puts e.backtrace
    end
  }
end

#predict(parameter) ⇒ Object



843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
# File 'lib/levdon.rb', line 843

def predict(parameter)
  if(parameter.class.name == "String")
    parameter = {:target => parameter }
  elsif(parameter.class.name == "Hash")
    raise "expected key: request_id" if(parameter[:request_id])
    raise "expected key: ontologies" if(parameter[:ontologies])
    raise "required key: target. Specify a file path or URL or data." unless(parameter[:target])
  else
    raise "Invalid parameter type"
  end
  parameter[:request_id]    = SecureRandom.uuid.gsub("-","")
  parameter[:ontologies]    = @ontologies
  parameter[:access_token]  = @access_token
  
  ret   = nil
  error = nil
  begin
    obj         = _predict_impl(parameter)
    ret         = obj[:result]
    error       = obj[:error]
  rescue => e
    error = ""
    error += e.class.to_s + "\n"
    error += e.message.to_s + "\n"
    error += e.backtrace.to_s + "\n"
  end
  return {:results => ret, :error => error}
end

#queue_sizeObject



831
832
833
# File 'lib/levdon.rb', line 831

def queue_size
  @blocks.length
end

#start(access_token) ⇒ Object



683
684
685
686
# File 'lib/levdon.rb', line 683

def start(access_token)
  @access_token = access_token
  return {:erorr => nil}
end

#to_image(fname, ct) ⇒ Object



739
740
741
742
743
744
745
746
747
# File 'lib/levdon.rb', line 739

def to_image(fname,ct)
  if(ct == "video")
    return generate_thumb_from_video(fname)
  elsif(ct == "image")
    return File.open(fname).read
  end
  puts "Invalid media stream."
  return nil
end