├── LICENSE ├── README.md ├── composer.json ├── config └── personality-insights.php └── src ├── AbstractPersonalityInsights.php ├── Auth └── AccessManager.php ├── Contracts └── InsightsInterface.php ├── Exceptions ├── InvalidCredentialsName.php └── MissingParameterContentItemException.php ├── Facades └── PersonalityInsightsFacade.php ├── InsightsServiceProvider.php ├── Models ├── BaseModel.php ├── BehaviorNode.php ├── ConsumptionPreferencesCategoryNode.php ├── ConsumptionPreferencesNode.php ├── Contracts │ └── Childrenable.php ├── Profile.php ├── TraitTreeNode.php └── Warning.php ├── PersonalityInsights.php └── Support ├── DataCollector ├── ContentItem.php └── ContentListContainer.php ├── Util └── ResultsProcessor.php └── helpers.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 FindBrok 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | Laravel Personality Insights 6 |

7 | 8 |

9 | Latest Stable Version 10 | Latest Unstable Version 11 | Build Status 12 | StyleCI 13 | License 14 | Total Downloads 15 | 16 |

17 | 18 | ## Introduction 19 | Laravel Personality Insights, provides a simple and easy to use wrapper 20 | around [IBM Watson Personality Insights API](http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/personality-insights.html) 21 | 22 | ## License 23 | Laravel Personality Insights is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) 24 | 25 | ### How it works 26 | Personality Insights extracts and analyzes a spectrum of personality attributes to help discover actionable insights about 27 | people and entities, and in turn guides end users to highly personalized interactions. The service outputs personality 28 | characteristics that are divided into three dimensions: the Big 5, Values, and Needs. While some services are 29 | contextually specific depending on the domain model and content, Personality Insights only requires a 30 | minimum of 3500+ words of any text. 31 | 32 | ### Intended Use 33 | The Personality Insights service lends itself to an almost limitless number of potential applications. Businesses 34 | can use the detailed personality portraits of individual customers for finer-grained customer segmentation and 35 | better-quality lead generation. This data enables them to design marketing, provide product recommendations, 36 | and deliver customer care that is more personal and relevant. Personality Insights can also be used to 37 | help recruiters or university admissions match candidates to companies or universities. 38 | 39 | ### Installation 40 | Install the package through composer: 41 | 42 | ```bash 43 | $ composer require findbrok/laravel-personality-insights 44 | ``` 45 | > If you are using Laravel >= 5.5, you can skip service registration 46 | > and aliases registration thanks to Laravel auto package discovery 47 | > feature. 48 | 49 | Add the Service Provider to your providers array in ```config/app.php```, 50 | see [Registering Providers](https://laravel.com/docs/master/providers#registering-providers) 51 | 52 | ```php 53 | 'providers' => [ 54 | // Other Service Providers 55 | 56 | FindBrok\PersonalityInsights\InsightsServiceProvider::class, 57 | ], 58 | ``` 59 | 60 | ### Configuration 61 | Once installed you can now publish your config file and set your correct configuration for using the package. 62 | 63 | ```bash 64 | $ php artisan vendor:publish --provider="FindBrok\PersonalityInsights\InsightsServiceProvider" --tag="config" 65 | ``` 66 | 67 | This will create a file ```config/personality-insights.php``` , for information on how to set values present in this file see [Configuration Before Usage](https://github.com/findbrok/laravel-personality-insights/wiki/Configuration-Before-Usage-(1.1)) 68 | 69 | ### Credits 70 | Big Thanks to all developers who worked hard to create something amazing! 71 | 72 | ### Creator 73 | [![Percy Mamedy](https://img.shields.io/badge/Author-Percy%20Mamedy-orange.svg)](https://twitter.com/PercyMamedy) 74 | 75 | Twitter: [@PercyMamedy](https://twitter.com/PercyMamedy) 76 |
77 | GitHub: [percymamedy](https://github.com/percymamedy) 78 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "findbrok/laravel-personality-insights", 3 | "description": "Using IBM Watson Personality Insights Service with Laravel 5", 4 | "keywords": ["laravel", "ibm", "watson", "personality", "insights"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Percy Mamedy", 9 | "email": "percymamedy@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.6.0", 14 | "findbrok/php-watson-api-bridge": "^1.0", 15 | "illuminate/support": "~5.0", 16 | "netresearch/jsonmapper": "^1.1", 17 | "ramsey/uuid": "^3.4" 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "~4.0|~5.0", 21 | "mockery/mockery": "0.9.*", 22 | "orchestra/testbench": "~3.0" 23 | }, 24 | "autoload": { 25 | "files": [ 26 | "src/Support/helpers.php" 27 | ], 28 | "psr-4": { 29 | "FindBrok\\PersonalityInsights\\": "src/" 30 | } 31 | }, 32 | "extra": { 33 | "branch-alias": { 34 | "dev-master": "1.2.x-dev" 35 | }, 36 | "laravel": { 37 | "providers": [ 38 | "FindBrok\\PersonalityInsights\\InsightsServiceProvider" 39 | ] 40 | } 41 | }, 42 | "minimum-stability": "dev", 43 | "prefer-stable": true 44 | } 45 | -------------------------------------------------------------------------------- /config/personality-insights.php: -------------------------------------------------------------------------------- 1 | env('PERSONALITY_INSIGHTS_DEFAULT_CREDENTIALS', 'default'), 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | Credentials 20 | |-------------------------------------------------------------------------- 21 | | 22 | | Here you may define credentials for your Personality Insights Service 23 | | you should find them in your Bluemix console. You can define as 24 | | many credentials as you want 25 | | 26 | */ 27 | 28 | 'credentials' => [ 29 | 30 | 'default' => [ 31 | 'url' => env('PERSONALITY_INSIGHTS_URL', 'https://gateway.watsonplatform.net/personality-insights/api/'), 32 | 'password' => env('PERSONALITY_INSIGHTS_PASSWORD', 'SomePassword'), 33 | 'username' => env('PERSONALITY_INSIGHTS_USERNAME', 'SomeUsername'), 34 | ], 35 | 36 | ], 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | API version 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Here you may specify the Personality Insights API version to use. 44 | | 45 | */ 46 | 47 | 'api_version' => env('PERSONALITY_INSIGHTS_API_VERSION', 'v3'), 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | X-Watson-Learning-Opt-Out 52 | |-------------------------------------------------------------------------- 53 | | 54 | | By default, Watson collects data from all requests and uses the data 55 | | to improve the service. If you do not want to share your data, 56 | | set this value to true. 57 | | 58 | */ 59 | 60 | 'x_watson_learning_opt_out' => false, 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Cache On 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Specify if we should cache results from Watson 68 | | 69 | */ 70 | 71 | 'cache_on' => env('PERSONALITY_INSIGHTS_CACHE', false), 72 | 73 | /* 74 | |-------------------------------------------------------------------------- 75 | | Cache Expiration (in minutes) 76 | |-------------------------------------------------------------------------- 77 | | 78 | | How long should the results stay in cache 79 | | 80 | */ 81 | 82 | 'cache_expiration' => 60, 83 | ]; 84 | -------------------------------------------------------------------------------- /src/AbstractPersonalityInsights.php: -------------------------------------------------------------------------------- 1 | 'application/json']; 39 | 40 | /** 41 | * Request Query. 42 | * 43 | * @var array 44 | */ 45 | protected $query = []; 46 | 47 | /** 48 | * Create the ContentListContainer and push in items. 49 | * 50 | * @param array $contentItems 51 | * 52 | * @return void 53 | */ 54 | public function newUpContainer($contentItems = []) 55 | { 56 | // New Up Container. 57 | $this->contentListContainer = app(ContentListContainer::SERVICE_ID)->setContentsItems($contentItems); 58 | } 59 | 60 | /** 61 | * Get the current Container. 62 | * 63 | * @return ContentListContainer 64 | */ 65 | public function getContainer() 66 | { 67 | // Return container. 68 | return $this->contentListContainer; 69 | } 70 | 71 | /** 72 | * Specify the credentials name to use. 73 | * 74 | * @param string $name 75 | * 76 | * @return $this 77 | */ 78 | public function usingCredentials($name = null) 79 | { 80 | // Set credentials name. 81 | $this->getAccessManager()->setCredentialsName($name)->setCredentials($name); 82 | 83 | // Return this. 84 | return $this; 85 | } 86 | 87 | /** 88 | * Sets the API version to use for the requests. 89 | * 90 | * @param string $apiVersion 91 | * 92 | * @return $this 93 | */ 94 | public function usingApiVersion($apiVersion = null) 95 | { 96 | // Set credentials name. 97 | $this->getAccessManager()->setApiVersion($apiVersion); 98 | 99 | // Return this. 100 | return $this; 101 | } 102 | 103 | /** 104 | * Return the Credential Name to use. 105 | * 106 | * @return string 107 | */ 108 | public function getCredentialsName() 109 | { 110 | return $this->getAccessManager()->getCredentialsName(); 111 | } 112 | 113 | /** 114 | * Return the Api Version to use. 115 | * 116 | * @return string 117 | */ 118 | public function getApiVersion() 119 | { 120 | return $this->getAccessManager() 121 | ->getApiVersion(); 122 | } 123 | 124 | /** 125 | * Return the headers used for making request. 126 | * 127 | * @return array 128 | */ 129 | protected function getHeaders() 130 | { 131 | // Return headers. 132 | return collect($this->headers)->merge([ 133 | 'X-Watson-Learning-Opt-Out' => config('personality-insights.x_watson_learning_opt_out'), 134 | ])->all(); 135 | } 136 | 137 | /** 138 | * Get Query to pass additionally to the request,. 139 | * 140 | * @return string 141 | */ 142 | protected function getQuery() 143 | { 144 | // Our final results. 145 | $finalQueryString = ''; 146 | 147 | // Construct query string. 148 | foreach ($this->query as $key => $value) { 149 | $finalQueryString .= $key.'='.$value.'&'; 150 | } 151 | 152 | // We have something in the result. 153 | if (! empty($finalQueryString)) { 154 | $finalQueryString = rtrim($finalQueryString, '&'); 155 | } 156 | 157 | // We return our results. 158 | return $finalQueryString; 159 | } 160 | 161 | /** 162 | * Send API Request to Watson and get Response. 163 | * 164 | * @return \GuzzleHttp\Psr7\Response 165 | */ 166 | protected function sendRequest() 167 | { 168 | // Get AccessManager. 169 | $accessManager = $this->getAccessManager(); 170 | 171 | // Make a Watson Bridge. 172 | $watsonBridge = $this->makeBridge(); 173 | 174 | // Get Url We post to Watson to Get Profile. 175 | $postUrl = $accessManager->getProfileResourcePath(); 176 | 177 | // Append query string if needed 178 | if (! empty($this->getQuery())) { 179 | $postUrl .= '?'.$this->getQuery(); 180 | } 181 | 182 | // Cross the Bridge and return the Response. 183 | return $watsonBridge->post($postUrl, $this->getContainer()->getContentsForRequest()); 184 | } 185 | 186 | /** 187 | * Make headers as they were. 188 | * 189 | * @return void 190 | */ 191 | protected function cleanHeaders() 192 | { 193 | // Clean up header. 194 | $this->headers = ['Accept' => 'application/json']; 195 | } 196 | 197 | /** 198 | * Reset Query data in the Class. 199 | * 200 | * @return void 201 | */ 202 | protected function cleanQuery() 203 | { 204 | $this->query = []; 205 | } 206 | 207 | /** 208 | * Append Headers to request. 209 | * 210 | * @param array $headers 211 | * 212 | * @return self 213 | */ 214 | public function appendHeaders(array $headers = []) 215 | { 216 | // Append headers. 217 | $this->headers = collect($this->headers)->merge($headers)->all(); 218 | 219 | // Return calling object. 220 | return $this; 221 | } 222 | 223 | /** 224 | * Add Query to the Request. 225 | * 226 | * @param array $query 227 | * 228 | * @return self 229 | */ 230 | public function withQuery(array $query = []) 231 | { 232 | // Set Query in class. 233 | $this->query = collect($this->query)->merge($query)->all(); 234 | 235 | return $this; 236 | } 237 | 238 | /** 239 | * Returns the AccessManager. 240 | * 241 | * @return AccessManager 242 | */ 243 | public function getAccessManager() 244 | { 245 | return app(AccessManager::SERVICE_ID); 246 | } 247 | 248 | /** 249 | * Create a new WatsonBridge to handle Requests. 250 | * 251 | * @return \FindBrok\WatsonBridge\Bridge; 252 | */ 253 | public function makeBridge() 254 | { 255 | // Create and Return Bridge. 256 | return app('PIBridge')->appendHeaders($this->getHeaders()); 257 | } 258 | 259 | /** 260 | * Add a ContentItem to ContentListContainer. 261 | * 262 | * @param array|ContentItem $items 263 | * 264 | * @return self 265 | */ 266 | public function addSingleContentItem($items = []) 267 | { 268 | // Push ContentItem in ContentListContainer. 269 | $this->contentListContainer->push($items instanceof ContentItem ? $items : personality_insights_content_item($items)); 270 | 271 | // Return object. 272 | return $this; 273 | } 274 | 275 | /** 276 | * Add ContentItems to the Container. 277 | * 278 | * @param array $items 279 | * 280 | * @return self 281 | */ 282 | public function addContentItems($items = []) 283 | { 284 | // Loop on each item. 285 | collect($items)->each(function ($item) { 286 | // Add each content to the Container. 287 | $this->addSingleContentItem($item); 288 | }); 289 | 290 | // Return object. 291 | return $this; 292 | } 293 | 294 | /** 295 | * Checks if cache is on. 296 | * 297 | * @return bool 298 | */ 299 | public function cacheIsOn() 300 | { 301 | return config('personality-insights.cache_on'); 302 | } 303 | 304 | /** 305 | * Get The cache lifetime in minutes. 306 | * 307 | * @return int 308 | */ 309 | public function cacheLifetime() 310 | { 311 | return config('personality-insights.cache_expiration'); 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/Auth/AccessManager.php: -------------------------------------------------------------------------------- 1 | setCredentialsName($credentialsName); 44 | $this->setCredentials($credentialsName); 45 | $this->setApiVersion($apiVersion); 46 | } 47 | 48 | /** 49 | * Sets the Credentials name. 50 | * 51 | * @param string $credentialsName 52 | * 53 | * @return $this 54 | */ 55 | public function setCredentialsName($credentialsName = null) 56 | { 57 | // No credentials name. 58 | if (is_null($credentialsName)) { 59 | $credentialsName = config('personality-insights.default_credentials'); 60 | } 61 | 62 | // Credentials does not exist. 63 | if (! config()->has('personality-insights.credentials.'.$credentialsName)) { 64 | throw new InvalidCredentialsName; 65 | } 66 | 67 | $this->credentialsName = $credentialsName; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Gets the Credentials name to use. 74 | * 75 | * @return null|string 76 | */ 77 | public function getCredentialsName() 78 | { 79 | return $this->credentialsName; 80 | } 81 | 82 | /** 83 | * Returns the Credentials to use for requests. 84 | * 85 | * @return array 86 | */ 87 | public function getCredentials() 88 | { 89 | return $this->credentials; 90 | } 91 | 92 | /** 93 | * Sets the Credentials we will use to perform requests. 94 | * 95 | * @param string $name 96 | * 97 | * @throws InvalidCredentialsName 98 | * 99 | * @return $this 100 | */ 101 | public function setCredentials($name = null) 102 | { 103 | // No name given. 104 | if (is_null($name)) { 105 | $name = config('personality-insights.default_credentials'); 106 | } 107 | 108 | // Credentials does not exist. 109 | if (! config()->has('personality-insights.credentials.'.$name)) { 110 | throw new InvalidCredentialsName; 111 | } 112 | 113 | $this->credentials = config('personality-insights.credentials.'.$name); 114 | 115 | return $this; 116 | } 117 | 118 | /** 119 | * Returns the API version to use for 120 | * making requests. 121 | * 122 | * @return string 123 | */ 124 | public function getApiVersion() 125 | { 126 | return $this->apiVersion; 127 | } 128 | 129 | /** 130 | * Sets ths API version we are using. 131 | * 132 | * @param string $apiVersion 133 | * 134 | * @return $this 135 | */ 136 | public function setApiVersion($apiVersion = null) 137 | { 138 | // No version specified. 139 | if (is_null($apiVersion)) { 140 | $apiVersion = config('personality-insights.api_version') ?: 'v3'; 141 | } 142 | 143 | $this->apiVersion = $apiVersion; 144 | 145 | return $this; 146 | } 147 | 148 | /** 149 | * Get the API path used for getting Profile. 150 | * 151 | * @return string 152 | */ 153 | public function getProfileResourcePath() 154 | { 155 | return $this->getApiVersion().'/profile'; 156 | } 157 | 158 | /** 159 | * Gets the Default Credentials. 160 | * 161 | * @return array 162 | */ 163 | public function getDefaultCredentials() 164 | { 165 | return config('personality-insights.credentials.'.config('personality-insights.default_credentials')); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/Contracts/InsightsInterface.php: -------------------------------------------------------------------------------- 1 | message); 28 | // Call parent exception 29 | parent::__construct($message, $code, $previous); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Exceptions/MissingParameterContentItemException.php: -------------------------------------------------------------------------------- 1 | message); 28 | // Call parent exception 29 | parent::__construct($message, $code, $previous); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Facades/PersonalityInsightsFacade.php: -------------------------------------------------------------------------------- 1 | publishes([ 26 | __DIR__.'/../config/personality-insights.php' => config_path('personality-insights.php'), 27 | ], 'config'); 28 | } 29 | 30 | /** 31 | * Register the service provider. 32 | * 33 | * @return void 34 | */ 35 | public function register() 36 | { 37 | // Merge Config File. 38 | $this->mergeConfigFrom(__DIR__.'/../config/personality-insights.php', 'personality-insights'); 39 | 40 | // Register Bindings. 41 | $this->registerBindings(); 42 | 43 | // Register Facades. 44 | $this->registerFacades(); 45 | } 46 | 47 | /** 48 | * Registers all Interface to Class bindings. 49 | * 50 | * @return void 51 | */ 52 | protected function registerBindings() 53 | { 54 | // Bind Personality Insights interface. 55 | $this->app->bind(InsightsContract::class, PersonalityInsights::class); 56 | 57 | // Bind Personality Insights Service. 58 | $this->app->bind(PersonalityInsights::SERVICE_ID, PersonalityInsights::class); 59 | 60 | // Registers the Access Manager. 61 | $this->registerAccessManager(); 62 | 63 | // Registers the Bridge. 64 | $this->registerBridge(); 65 | 66 | // Bind PersonalityInsights ContentListContainer in App. 67 | $this->app->bind(ContentListContainer::SERVICE_ID, function () { 68 | return (new ContentListContainer)->cleanContainer(); 69 | }); 70 | } 71 | 72 | /** 73 | * Registers the Access Manager in 74 | * the Container. 75 | * 76 | * @return void 77 | */ 78 | protected function registerAccessManager() 79 | { 80 | // Bind AccessManager. 81 | $this->app->singleton(AccessManager::SERVICE_ID, function (Application $app) { 82 | /** @var Repository $configRepo */ 83 | $configRepo = $app->make('config'); 84 | 85 | return new AccessManager( 86 | $configRepo->get('personality-insights.default_credentials'), 87 | $configRepo->get('personality-insights.api_version') 88 | ); 89 | }); 90 | } 91 | 92 | /** 93 | * Registers the Bridge. 94 | * 95 | * @return void 96 | */ 97 | protected function registerBridge() 98 | { 99 | // Bind WatsonBridge for Personality insights that we depend on. 100 | $this->app->bind('PIBridge', function (Application $app) { 101 | // Get Default Credentials. 102 | $credentials = $app->make(AccessManager::SERVICE_ID)->getCredentials(); 103 | 104 | // Return an Instance of Bridge. 105 | return new Bridge($credentials['username'], $credentials['password'], $credentials['url']); 106 | }); 107 | } 108 | 109 | /** 110 | * Registers all facades. 111 | * 112 | * @return void 113 | */ 114 | protected function registerFacades() 115 | { 116 | // Since Laravel 5.4 allows for automatic Facade 117 | // we do not need to register Facades here. 118 | if ($this->app->version() >= 5.0 && $this->app->version() < 5.4) { 119 | // Add Facade. 120 | $this->app->booting(function () { 121 | AliasLoader::getInstance()->alias(PersonalityInsights::SERVICE_ID, PersonalityInsightsFacade::class); 122 | }); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Models/BaseModel.php: -------------------------------------------------------------------------------- 1 | {$name}; 27 | } 28 | 29 | // Nothing to return. 30 | return null; 31 | } 32 | 33 | /** 34 | * Traverse Collection of Nodes and return specific Node if 35 | * criteria matches. 36 | * 37 | * @param string $propName 38 | * @param string $propValue 39 | * @param Collection $nodes 40 | * 41 | * @return TraitTreeNode|ConsumptionPreferencesCategoryNode|ConsumptionPreferencesNode|null 42 | */ 43 | public function traverseNodesAndFindBy($propName, $propValue, Collection $nodes = null) 44 | { 45 | // Nodes are null so nothing to Traverse. 46 | if (is_null($nodes)) { 47 | return null; 48 | } 49 | 50 | foreach ($nodes as $node) { 51 | if ($node->{$propName} == $propValue) { 52 | return $node; 53 | } 54 | 55 | if ($node->hasChildren()) { 56 | $node = $this->traverseNodesAndFindBy($propName, $propValue, $node->getChildren()); 57 | 58 | if (! is_null($node) && $node instanceof self) { 59 | return $node; 60 | } 61 | } 62 | } 63 | 64 | // Nothing Found. 65 | return null; 66 | } 67 | 68 | /** 69 | * Convert the object into something JSON serializable. 70 | * 71 | * @return array 72 | */ 73 | public function jsonSerialize() 74 | { 75 | return array_map(function ($value) { 76 | if ($value instanceof JsonSerializable) { 77 | return $value->jsonSerialize(); 78 | } elseif ($value instanceof Jsonable) { 79 | return json_decode($value->toJson(), true); 80 | } elseif ($value instanceof Arrayable) { 81 | return $value->toArray(); 82 | } else { 83 | return $value; 84 | } 85 | }, get_object_vars($this)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Models/BehaviorNode.php: -------------------------------------------------------------------------------- 1 | consumption_preferences = collect($consumption_preferences); 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * Checks if ConsumptionPreferencesCategoryNode has Children. 49 | * 50 | * @return bool 51 | */ 52 | public function hasChildren() 53 | { 54 | return $this->consumption_preferences instanceof Collection && ! $this->consumption_preferences->isEmpty(); 55 | } 56 | 57 | /** 58 | * Gets Children nodes. 59 | * 60 | * @return Collection 61 | */ 62 | public function getChildren() 63 | { 64 | return $this->consumption_preferences; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Models/ConsumptionPreferencesNode.php: -------------------------------------------------------------------------------- 1 | score == 1.0; 63 | } 64 | 65 | /** 66 | * Checks if Profile is Unlikely to this preference. 67 | * 68 | * @return bool 69 | */ 70 | public function isUnlikely() 71 | { 72 | return $this->score == 0.0; 73 | } 74 | 75 | /** 76 | * Checks if Profile is Neutral to this preference. 77 | * 78 | * @return bool 79 | */ 80 | public function isNeutral() 81 | { 82 | return $this->score == 0.5; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Models/Contracts/Childrenable.php: -------------------------------------------------------------------------------- 1 | personality = collect($personality); 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * Sets Needs. 98 | * 99 | * @param TraitTreeNode[] $needs 100 | * 101 | * @return $this 102 | */ 103 | public function setNeeds($needs) 104 | { 105 | $this->needs = collect($needs); 106 | 107 | return $this; 108 | } 109 | 110 | /** 111 | * Sets Values. 112 | * 113 | * @param TraitTreeNode[] $values 114 | * 115 | * @return $this 116 | */ 117 | public function setValues($values) 118 | { 119 | $this->values = collect($values); 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Sets Behavior. 126 | * 127 | * @param BehaviorNode[] $behavior 128 | * 129 | * @return $this 130 | */ 131 | public function setBehavior($behavior) 132 | { 133 | $this->behavior = collect($behavior); 134 | 135 | return $this; 136 | } 137 | 138 | /** 139 | * Sets consumption_preferences. 140 | * 141 | * @param ConsumptionPreferencesCategoryNode[] $consumption_preferences 142 | * 143 | * @return $this 144 | */ 145 | public function setConsumptionPreferences($consumption_preferences) 146 | { 147 | $this->consumption_preferences = collect($consumption_preferences); 148 | 149 | return $this; 150 | } 151 | 152 | /** 153 | * Sets warnings. 154 | * 155 | * @param Warning[] $warnings 156 | * 157 | * @return $this 158 | */ 159 | public function setWarnings($warnings) 160 | { 161 | $this->warnings = collect($warnings); 162 | 163 | return $this; 164 | } 165 | 166 | /** 167 | * Convert Profile to json. 168 | * 169 | * @param int $options 170 | * 171 | * @return string 172 | */ 173 | public function toJson($options = 0) 174 | { 175 | return json_encode($this->jsonSerialize(), $options); 176 | } 177 | 178 | /** 179 | * Get a Facet using Id. 180 | * 181 | * @param string $id 182 | * 183 | * @return TraitTreeNode|null 184 | */ 185 | public function findFacetById($id) 186 | { 187 | // No personality defined yet. 188 | if (is_null($this->personality)) { 189 | return null; 190 | } 191 | 192 | // Traverse and Return. 193 | return $this->traverseNodesAndFindBy('trait_id', $id, $this->personality); 194 | } 195 | 196 | /** 197 | * Get a Facet using Name. 198 | * 199 | * @param string $name 200 | * 201 | * @return TraitTreeNode|null 202 | */ 203 | public function findFacetByName($name) 204 | { 205 | // No personality defined yet. 206 | if (is_null($this->personality)) { 207 | return null; 208 | } 209 | 210 | // Traverse and Return. 211 | return $this->traverseNodesAndFindBy('name', $name, $this->personality); 212 | } 213 | 214 | /** 215 | * Checks if the Profile has the Facet given. 216 | * 217 | * @param string $facet 218 | * 219 | * @return bool 220 | */ 221 | public function hasFacet($facet) 222 | { 223 | return ! is_null($this->findFacetByName($facet)) || ! is_null($this->findFacetById($facet)); 224 | } 225 | 226 | /** 227 | * Get a Need using Id. 228 | * 229 | * @param string $id 230 | * 231 | * @return TraitTreeNode|null 232 | */ 233 | public function findNeedById($id) 234 | { 235 | // No needs defined yet. 236 | if (is_null($this->needs)) { 237 | return null; 238 | } 239 | 240 | // Traverse and Return. 241 | return $this->traverseNodesAndFindBy('trait_id', $id, $this->needs); 242 | } 243 | 244 | /** 245 | * Get a Need using its name. 246 | * 247 | * @param string $name 248 | * 249 | * @return TraitTreeNode|null 250 | */ 251 | public function findNeedByName($name) 252 | { 253 | // No needs defined yet. 254 | if (is_null($this->needs)) { 255 | return null; 256 | } 257 | 258 | // Traverse and Return. 259 | return $this->traverseNodesAndFindBy('name', $name, $this->needs); 260 | } 261 | 262 | /** 263 | * Checks if Profile has given need. 264 | * 265 | * @param string $need 266 | * 267 | * @return bool 268 | */ 269 | public function hasNeed($need) 270 | { 271 | return ! is_null($this->findNeedByName($need)) || ! is_null($this->findNeedById($need)); 272 | } 273 | 274 | /** 275 | * Get a Value using Id. 276 | * 277 | * @param string $id 278 | * 279 | * @return TraitTreeNode|null 280 | */ 281 | public function findValueById($id) 282 | { 283 | // No values defined yet. 284 | if (is_null($this->values)) { 285 | return null; 286 | } 287 | 288 | // Traverse and Return. 289 | return $this->traverseNodesAndFindBy('trait_id', $id, $this->values); 290 | } 291 | 292 | /** 293 | * Get a Value using its name. 294 | * 295 | * @param string $name 296 | * 297 | * @return TraitTreeNode|null 298 | */ 299 | public function findValueByName($name) 300 | { 301 | // No values defined yet. 302 | if (is_null($this->values)) { 303 | return null; 304 | } 305 | 306 | // Traverse and Return. 307 | return $this->traverseNodesAndFindBy('name', $name, $this->values); 308 | } 309 | 310 | /** 311 | * Checks if Profile has given value. 312 | * 313 | * @param string $value 314 | * 315 | * @return bool 316 | */ 317 | public function hasValue($value) 318 | { 319 | return ! is_null($this->findValueByName($value)) || ! is_null($this->findValueById($value)); 320 | } 321 | 322 | /** 323 | * Find Behaviors a give times or Days. 324 | * 325 | * @param array|string $times 326 | * 327 | * @return Collection|BehaviorNode|null 328 | */ 329 | public function findBehaviorsFor($times) 330 | { 331 | // No behaviors set yet. 332 | if (is_null($this->behavior)) { 333 | return null; 334 | } 335 | 336 | // Specifically convert times to array. 337 | $times = ! is_array($times) ? [$times] : $times; 338 | 339 | // Return Behavior at specific times 340 | $behaviors = $this->behavior->reject(function (BehaviorNode $behavior) use ($times) { 341 | return ! in_array($behavior->name, $times); 342 | }); 343 | 344 | // Only one item. 345 | if ($behaviors->count() == 1) { 346 | return $behaviors->first(); 347 | } 348 | 349 | return $behaviors; 350 | } 351 | 352 | /** 353 | * Get a ConsumptionPreferencesCategory using Id. 354 | * 355 | * @param string $preference 356 | * 357 | * @return ConsumptionPreferencesCategoryNode|null 358 | */ 359 | public function findConsumptionPreferenceCategoryById($preference) 360 | { 361 | // No Preferences defined yet. 362 | if (is_null($this->consumption_preferences)) { 363 | return null; 364 | } 365 | 366 | // Traverse and Return. 367 | return $this->traverseNodesAndFindBy('consumption_preference_category_id', $preference, $this->consumption_preferences); 368 | } 369 | 370 | /** 371 | * Get a ConsumptionPreferencesCategory using its name. 372 | * 373 | * @param string $preference 374 | * 375 | * @return ConsumptionPreferencesCategoryNode|null 376 | */ 377 | public function findConsumptionPreferenceCategoryName($preference) 378 | { 379 | // No Preferences defined yet. 380 | if (is_null($this->consumption_preferences)) { 381 | return null; 382 | } 383 | 384 | // Traverse and Return. 385 | return $this->traverseNodesAndFindBy('name', $preference, $this->consumption_preferences); 386 | } 387 | 388 | /** 389 | * Checks if ConsumptionPreferencesCategory exists on profile. 390 | * 391 | * @param string $preference 392 | * 393 | * @return bool 394 | */ 395 | public function hasConsumptionPreferenceCategory($preference) 396 | { 397 | return ! is_null($this->findConsumptionPreferenceCategoryName($preference)) || ! is_null($this->findConsumptionPreferenceCategoryById($preference)); 398 | } 399 | 400 | /** 401 | * Find ConsumptionPreferencesNode by Id. 402 | * 403 | * @param string $preferenceId 404 | * 405 | * @return ConsumptionPreferencesNode|null 406 | */ 407 | public function findConsumptionPreference($preferenceId) 408 | { 409 | // No Preferences defined yet. 410 | if (is_null($this->consumption_preferences)) { 411 | return null; 412 | } 413 | 414 | // Traverse and Return. 415 | return $this->traverseNodesAndFindBy('consumption_preference_id', $preferenceId, $this->consumption_preferences); 416 | } 417 | 418 | /** 419 | * Checks if Consumption Preference exists. 420 | * 421 | * @param string $preferenceId 422 | * 423 | * @return bool 424 | */ 425 | public function hasConsumptionPreference($preferenceId) 426 | { 427 | return ! is_null($this->findConsumptionPreference($preferenceId)); 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /src/Models/TraitTreeNode.php: -------------------------------------------------------------------------------- 1 | children = collect($children); 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Gets Children nodes. 75 | * 76 | * @return Collection 77 | */ 78 | public function getChildren() 79 | { 80 | return $this->children; 81 | } 82 | 83 | /** 84 | * Checks if TraitTreeNode has Children. 85 | * 86 | * @return bool 87 | */ 88 | public function hasChildren() 89 | { 90 | return $this->children instanceof Collection && ! $this->children->isEmpty(); 91 | } 92 | 93 | /** 94 | * Calculate the percentage for this node. 95 | * 96 | * @param int $decimal 97 | * 98 | * @return float|null 99 | */ 100 | public function calculatePercentage($decimal = 1) 101 | { 102 | // Profile not loaded yet. 103 | if (is_null($this->percentile)) { 104 | return null; 105 | } 106 | 107 | // Calculate percentage and return value 108 | return (float) number_format($this->percentile * 100, $decimal, '.', ''); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Models/Warning.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 50 | $this->jsonMapper = $jsonMapper; 51 | 52 | // New Up a container. 53 | $this->newUpContainer($contentItems); 54 | } 55 | 56 | /** 57 | * Pre-load a profile. 58 | * 59 | * @param $profile 60 | * 61 | * @return $this 62 | */ 63 | public function loadProfile($profile) 64 | { 65 | // Override profile 66 | $this->profile = $profile; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Get Full Insights From Watson API. 73 | * 74 | * @throws \FindBrok\WatsonBridge\Exceptions\WatsonBridgeException 75 | * 76 | * @return Profile 77 | */ 78 | public function getProfileFromWatson() 79 | { 80 | // We have the request in cache and cache is on. 81 | if ($this->cacheIsOn() && $this->cache->has($this->getContainer()->getCacheKey())) { 82 | // Return results from cache. 83 | return $this->cache->get($this->getContainer()->getCacheKey()); 84 | } 85 | 86 | // Send Request to Watson. 87 | $response = $this->sendRequest(); 88 | 89 | // Decode and map onto Object. 90 | /** @var Profile $profile */ 91 | $profile = $this->jsonMapper->map(json_decode($response->getBody()->getContents()), new Profile); 92 | 93 | // Cache results if cache is on. 94 | if ($this->cacheIsOn()) { 95 | $this->cache->put($this->getContainer()->getCacheKey(), $profile, $this->cacheLifetime()); 96 | } 97 | 98 | // Return profile. 99 | return $profile; 100 | } 101 | 102 | /** 103 | * Get Full Insights. 104 | * 105 | * @return Profile 106 | */ 107 | public function getFullProfile() 108 | { 109 | // Profile not already loaded. 110 | if (! $this->hasProfilePreLoaded()) { 111 | // Fetch Profile From Watson API. 112 | $this->profile = $this->getProfileFromWatson(); 113 | } 114 | 115 | // Return Results. 116 | return $this->profile; 117 | } 118 | 119 | /** 120 | * Cleans the object by erasing all profile and content info. 121 | * 122 | * @return $this 123 | */ 124 | public function clean() 125 | { 126 | // Empty Profile. 127 | $this->profile = null; 128 | // Empty credentials. 129 | $this->credentialsName = null; 130 | 131 | // Recreate a new container. 132 | $this->newUpContainer(); 133 | // Clean headers. 134 | $this->cleanHeaders(); 135 | // Clean Query 136 | $this->cleanQuery(); 137 | 138 | // Return calling object. 139 | return $this; 140 | } 141 | 142 | /** 143 | * Checks if profile data is already loaded in profile prop. 144 | * 145 | * @return bool 146 | */ 147 | public function hasProfilePreLoaded() 148 | { 149 | return property_exists($this, 'profile') && ! is_null($this->profile) && $this->profile instanceof Profile; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Support/DataCollector/ContentItem.php: -------------------------------------------------------------------------------- 1 | '', 27 | 28 | /* 29 | |-------------------------------------------------------------------------- 30 | | content [string] | (Required) 31 | |-------------------------------------------------------------------------- 32 | | 33 | | A maximum of 20 MB of content to be analyzed 34 | | 35 | */ 36 | 37 | 'content' => '', 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | created [integer] | (Optional) 42 | |-------------------------------------------------------------------------- 43 | | 44 | | When was the content created, UNIX Timestamp 45 | | 46 | */ 47 | 48 | 'created' => '', 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | updated [integer] | (Optional) 53 | |-------------------------------------------------------------------------- 54 | | 55 | | When was the content updated, UNIX Timestamp 56 | | 57 | */ 58 | 59 | 'updated' => '', 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | contenttype [string] | (Optional) 64 | |-------------------------------------------------------------------------- 65 | | 66 | | The MIME type of the content: Defaults to text/plain 67 | | - text/plain 68 | | - text/html 69 | | 70 | */ 71 | 72 | 'contenttype' => '', 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | language [string] | (Optional) 77 | |-------------------------------------------------------------------------- 78 | | 79 | | The language of the content as a two-letter ISO 639-1 80 | | identifier: Defaults to en 81 | | - ar (Arabic) 82 | | - en (English, the default) 83 | | - es (Spanish) 84 | | - ja (Japanese) 85 | | Regional variants are treated as their parent 86 | | language; for example, en-US is interpreted 87 | | as en. 88 | | 89 | */ 90 | 91 | 'language' => '', 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | parentid [string] | (Optional) 96 | |-------------------------------------------------------------------------- 97 | | 98 | | The unique ID of the parent content item for this item. Used to 99 | | identify hierarchical relationships between posts/replies, 100 | | messages/replies, and so on. 101 | | 102 | */ 103 | 104 | 'parentid' => '', 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | reply [boolean] | (Optional) 109 | |-------------------------------------------------------------------------- 110 | | 111 | | Indicates whether this content item is a reply to another content item. 112 | | 113 | */ 114 | 115 | 'reply' => '', 116 | 117 | /* 118 | |-------------------------------------------------------------------------- 119 | | forward [boolean] | (Optional) 120 | |-------------------------------------------------------------------------- 121 | | 122 | | Indicates whether this content item is a forwarded/copied version of 123 | | another content item. 124 | | 125 | */ 126 | 127 | 'forward' => '', 128 | ]; 129 | 130 | /** 131 | * Create a new ContentItem. 132 | * 133 | * @param array $items 134 | */ 135 | public function __construct($items = []) 136 | { 137 | // New Up parent. 138 | parent::__construct($items); 139 | 140 | // Validates the ContentItem. 141 | $this->validates(); 142 | } 143 | 144 | /** 145 | * Validates the ContentItem. 146 | * 147 | * @throws MissingParameterContentItemException 148 | */ 149 | protected function validates() 150 | { 151 | // If we do not have content then throw an Exception. 152 | if (! $this->has('content')) { 153 | throw new MissingParameterContentItemException('Personality Insights requires a content', 422); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/Support/DataCollector/ContentListContainer.php: -------------------------------------------------------------------------------- 1 | items = $this->getArrayableItems($items); 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Remove all invalid contents in the ContentListContainer. 41 | * 42 | * @return $this 43 | */ 44 | public function cleanContainer() 45 | { 46 | $this->reject(function ($item) { 47 | // Remove all which are not content item. 48 | return ! ($item instanceof ContentItem); 49 | }); 50 | 51 | // Return Container. 52 | return $this; 53 | } 54 | 55 | /** 56 | * Unique cache key for this Container. 57 | * 58 | * @return string 59 | */ 60 | public function getCacheKey() 61 | { 62 | // Return Key. 63 | return 'PersonalityInsights-'.Uuid::uuid5(Uuid::NAMESPACE_DNS, 64 | collect(['contentItems' => $this->toArray()])->toJson())->toString(); 65 | } 66 | 67 | /** 68 | * Get the content of the Container for passing to a request. 69 | * 70 | * @return string 71 | */ 72 | public function getContentsForRequest() 73 | { 74 | // Return correct format for request. 75 | return collect(['contentItems' => $this->toArray()])->all(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Support/Util/ResultsProcessor.php: -------------------------------------------------------------------------------- 1 | getFullProfile()->word_count; 15 | } 16 | 17 | /** 18 | * Get the language analysed. 19 | * 20 | * @return mixed 21 | */ 22 | public function getLanguage() 23 | { 24 | return $this->getFullProfile()->processed_language; 25 | } 26 | 27 | /** 28 | * Get the analysis level. 29 | * 30 | * @return string 31 | */ 32 | public function analysisLevel() 33 | { 34 | // Get Word count. 35 | $wordCount = $this->getWordCount(); 36 | 37 | // Very Strong. 38 | if ($wordCount >= 6000) { 39 | return 'Very Strong'; 40 | } 41 | 42 | // Strong analysis. 43 | if ($wordCount < 6000 && $wordCount >= 3500) { 44 | return 'Strong'; 45 | } 46 | 47 | // Weak analysis. 48 | if ($wordCount < 3500 && $wordCount >= 100) { 49 | return 'Weak'; 50 | } 51 | 52 | // Very weak. 53 | return 'Very Weak'; 54 | } 55 | 56 | /** 57 | * Check if analysis is very strong. 58 | * 59 | * @return bool 60 | */ 61 | public function isAnalysisVeryStrong() 62 | { 63 | return $this->analysisLevel() == 'Very Strong'; 64 | } 65 | 66 | /** 67 | * Check if analysis is strong. 68 | * 69 | * @return bool 70 | */ 71 | public function isAnalysisStrong() 72 | { 73 | return $this->isAnalysisVeryStrong() || $this->analysisLevel() == 'Strong'; 74 | } 75 | 76 | /** 77 | * Check if analysis is weak. 78 | * 79 | * @return bool 80 | */ 81 | public function isAnalysisWeak() 82 | { 83 | return $this->isAnalysisVeryWeak() || $this->analysisLevel() == 'Weak'; 84 | } 85 | 86 | /** 87 | * Check if analysis is very weak. 88 | * 89 | * @return bool 90 | */ 91 | public function isAnalysisVeryWeak() 92 | { 93 | return $this->analysisLevel() == 'Very Weak'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Support/helpers.php: -------------------------------------------------------------------------------- 1 |