Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2017/07/25

Sentimentalizing Twitter: First Pass

It started here.

I couldn't leave it there.

I can write a tool that goes through all old tweets and deletes ones that don't pass criteria, but I prefer to get out ahead of the issue and leave the record as it is.

And, as a later pass, one can pull a corpus, use a module like Algorithm::NaiveBayes and make your own classifier, rather than using Microsoft Research's Text Analytics API or another service. I was somewhere along that process when the hosting died, so I'm not bringing it here.

I was kinda under the thrall of Building Maintainable Software, or at least the first few chapters of it, so I did a few things differently in order to get their functions less than 15 lines, but the send_tweet function didn't get the passes it'd need, and I could probably give check_status some love, or perhaps even roll it into something like WebService::Microsoft::TextAnalytics. In the mean time, this should allow you to always tweet on the bright side of life.

  1. #!/usr/bin/env perl  
  2.   
  3. use feature qw{ postderef say signatures } ;  
  4. use strict ;  
  5. use warnings ;  
  6. use utf8 ;  
  7.   
  8. no warnings qw{ experimental::postderef experimental::signatures } ;  
  9.   
  10. use Carp ;  
  11. use Getopt::Long ;  
  12. use IO::Interactive qw{ interactive } ;  
  13. use JSON ;  
  14. use LWP::UserAgent ;  
  15. use Net::Twitter ;  
  16. use YAML qw{ LoadFile } ;  
  17.   
  18. my $options = options() ;  
  19. my $config  = config() ;  
  20.   
  21. if ( check_status( $options->{ status }, $config ) >= 0.5 ) {  
  22.     send_tweet( $options$config ) ;  
  23.     }  
  24. else { say qq{Blocked due to negative vibes, man.} }  
  25. exit ;  
  26.   
  27. sub send_tweet ( $options$config ) {  
  28.     my $twit = Net::Twitter->new(  
  29.         traits          => [ qw/API::RESTv1_1/ ],  
  30.         consumer_key    => $config->{ twitter }{ consumer_key },  
  31.         consumer_secret => $config->{ twitter }{ consumer_secret },  
  32.         ssl             => 1,  
  33.         ) ;  
  34.     my $tokens = $config->{ twitter }{ tokens }{ $options->{ username } } ;  
  35.     if (   $tokens->{ access_token }  
  36.         && $tokens->{ access_token_secret } ) {  
  37.         $twit->access_token( $tokens->{ access_token } ) ;  
  38.         $twit->access_token_secret( $tokens->{ access_token_secret } ) ;  
  39.         }  
  40.     if ( $twit->authorized ) {  
  41.         if ( $twit->update( $options->{ status } ) ) {  
  42.             say { interactive } $options->{ status } ;  
  43.             }  
  44.         else {  
  45.             say { interactive } 'FAILED TO TWEET' ;  
  46.             }  
  47.         }  
  48.     else {  
  49.         croak( "Not Authorized" ) ;  
  50.         }  
  51.     }  
  52.   
  53. sub check_status ( $status$config ) {  
  54.     my $j   = JSON->new->canonical->pretty ;  
  55.     my $key = $config->{ microsoft }{ text_analytics }{ key } ;  
  56.     my $id  = 'tweet_' . time ;  
  57.     my $object ;  
  58.     push @{ $object->{ documents } },  
  59.         {  
  60.         language => 'EN',  
  61.         text     => $status,  
  62.         id       => $id,  
  63.         } ;  
  64.     my $json    = $j->encode( $object ) ;  
  65.     my $api     = 'https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment' ;  
  66.     my $agent   = LWP::UserAgent->new ;  
  67.     my $request = HTTP::Request->new( POST => $api ) ;  
  68.     $request->header( 'Ocp-Apim-Subscription-Key' => $key ) ;  
  69.     $request->content( $json ) ;  
  70.     my $response = $agent->request( $request ) ;  
  71.   
  72.     if ( $response->is_success ) {  
  73.         my $out = decode_json $response->content ;  
  74.         my $doc = $out->{ documents }[ 0 ] ;  
  75.         return $doc->{ score } ;  
  76.         }  
  77.     else {  
  78.         croak( $response->status_line ) ;  
  79.         }  
  80.     return 1 ;  
  81.     }  
  82.   
  83. sub config () {  
  84.     my $config ;  
  85.     $config->{ twitter }   = LoadFile( join '/'$ENV{ HOME }, '.twitter.cnf' ) ;  
  86.     $config->{ microsoft } = LoadFile( join '/'$ENV{ HOME }, '.microsoft.yml' ) ;  
  87.     return $config ;  
  88.     }  
  89.   
  90. sub options () {  
  91.     my $options ;  
  92.     GetOptions(  
  93.         'help'       => \$options->{ help },  
  94.         'username=s' => \$options->{ username },  
  95.         'status=s'   => \$options->{ status },  
  96.         ) ;  
  97.     show_usage( $options ) ;  
  98.     return $options ;  
  99.     }  
  100.   
  101. sub show_usage ($options) {  
  102.     if (   $options->{ help }  
  103.         || !$options->{ username }  
  104.         || !$options->{ status } ) {  
  105.         say { interactive } <<'HELP';  
  106. Only Positive Tweets -- Does text analysis of content before tweeting  
  107.   
  108.     -u  user        Twitter screen name (required)  
  109.     -s  status      Status to be tweeted (required)  
  110.     -h  help        This screen  
  111. HELP  
  112.         exit ;  
  113.         }  
  114.     }  
  115. __DATA__  
  116.   
  117. .microsoft.yml looks like this  
  118. ---  
  119. text_analytics:  
  120.     key: GENERATED_BY_MICROSOFT  
  121.   
  122. .twitter.cnf looks like this  
  123.   
  124. ---  
  125. consumer_key: GO_TO_DEV.TWITTER.COM  
  126. consumer_secret: GO_TO_DEV.TWITTER.COM  
  127. tokens:  
  128.     your_username:  
  129.         access_token: TIED_TO_YOU_AS_USER_NOT_DEV  
  130.         access_token_secret:TIED_TO_YOU_AS_USER_NOT_DEV  
  131.   
  132. I cover access_tokens in https://varlogrant.blogspot.com/2016/07/nettwitter-cookbook-how-to-tweet.html  

No comments:

Post a Comment