Skip to content

Commit 288d4f5

Browse files
committed
Initial commit
0 parents  commit 288d4f5

9 files changed

+437
-0
lines changed

.editorconfig

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
root = true;
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 4
7+
charset = "utf-8"
8+
end_of_line = lf
9+
insert_final_newline = true
10+
trim_trailing_whitespace = true

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
composer.lock
2+
vendor/*

.semver

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
:major: 1
3+
:minor: 0
4+
:patch: 0
5+
:special: ''
6+
:metadata: ''

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Jad Bitar
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.

README.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# AlchemyAPI
2+
3+
## Installation
4+
5+
```
6+
{
7+
"require": {
8+
"jadb/alchemyapi": "1.*"
9+
}
10+
}
11+
```
12+
13+
## Credits
14+
15+
Initially inspired by the [official SDK](https://github.com/AlchemyAPI/alchemyapi_php)
16+
and an [abandoned composer package](https://github.com/alanchavez88/alchemy-api).
17+
18+
*I like to believe this one is better :)*

composer.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "jadb/alchemyapi"
3+
, "description": "Natural Language Processing using AlchemyAPI"
4+
, "type": "library"
5+
, "keywords": ["alchemy", "nlp", "natural language process", "alchemyapi"]
6+
, "license": "MIT"
7+
, "homepage": "https://github.com/jadb/php-alchemyapi"
8+
, "authors": [
9+
{
10+
"name": "Jad Bitar"
11+
, "homepage": "http://jadb.io"
12+
, "role": "Author"
13+
}
14+
]
15+
, "require": {
16+
"php": ">=5.5"
17+
, "guzzlehttp/guzzle": "4.*"
18+
}
19+
, "require-dev": {
20+
"phpunit/phpunit": "4.0"
21+
}
22+
, "autoload": {
23+
"psr-4": {
24+
"AlchemyAPI\\": "src"
25+
}
26+
}
27+
, "autoload-dev": {
28+
"psr-4": {
29+
"AlchemyAPI\\Test\\": "tests"
30+
}
31+
}
32+
}

phpunit.xml.dist

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="./vendor/autoload.php" colors="true">
3+
<testsuites>
4+
<testsuite>
5+
<directory>tests</directory>
6+
</testsuite>
7+
</testsuites>
8+
<filter>
9+
<whitelist>
10+
<directory suffix=".php">src</directory>
11+
</whitelist>
12+
</filter>
13+
</phpunit>

src/AlchemyAPI.php

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
<?php
2+
3+
namespace AlchemyAPI;
4+
5+
class AlchemyAPI
6+
{
7+
8+
const URI = 'access.alchemyapi.com/calls';
9+
10+
public $client;
11+
12+
public $endpoint;
13+
14+
public $params;
15+
16+
protected $key = '';
17+
18+
protected $ssl = false;
19+
20+
protected $defaults = [
21+
'category' => ['showSourceText' => false],
22+
'combined' => [
23+
'baseUrl' => null,
24+
'coreference' => true,
25+
'disambiguate' => true,
26+
'extract' => 'entity, keyword, taxonomy, concept',
27+
'linkedData' => true,
28+
'maxRetrieve' => 50,
29+
'quotations' => false,
30+
'sentiment' => false,
31+
'showSourceText' => false,
32+
],
33+
'concepts' => [
34+
'linkedData' => true,
35+
'maxRetrieve' => 8,
36+
'showSourceText' => false,
37+
],
38+
'entities' => [
39+
'coreference' => true,
40+
'disambiguate' => false,
41+
'linkedData' => true,
42+
'maxRetrieve' => 50,
43+
'quotations' => false,
44+
'sentiment' => false,
45+
'showSourceText' => false,
46+
],
47+
'image_keywords' => [
48+
'extractMode' => 'trust-metadata',
49+
'imagePostMode' => null,
50+
],
51+
'keywords' => [
52+
'keywordExtractMode' => 'normal',
53+
'maxRetrieve' => 50,
54+
'sentiment' => false,
55+
'showSourceText' => false,
56+
],
57+
'relations' => [
58+
'coreference' => true,
59+
'disambiguate' => true,
60+
'entities' => false,
61+
'keywords' => false,
62+
'linkedData' => true,
63+
'maxRetrieve' => 50,
64+
'requireEntities' => false,
65+
'sentiment' => false,
66+
'sentimentExcludeEntities' => true,
67+
'showSourceText' => false,
68+
],
69+
'sentiment' => ['showSourceText' => false],
70+
'sentiment_targeted' => ['showSourceText' => false],
71+
'taxonomy' => [
72+
'baseUrl' => null,
73+
'cquery' => null,
74+
'showSourceText' => false,
75+
'sourceText' => 'cleaned_or_raw',
76+
'xpath' => null,
77+
],
78+
'text' => [
79+
'extractLinks' => false,
80+
'useMetaData' => true,
81+
],
82+
'title' => ['useMetaData' => true],
83+
];
84+
85+
private $services = [
86+
'author',
87+
'category',
88+
'combined',
89+
'concepts',
90+
'entities',
91+
'feeds',
92+
'image',
93+
'image_keywords',
94+
'keywords',
95+
'language',
96+
'microformats',
97+
'relations',
98+
'sentiment',
99+
'sentiment_targeted',
100+
'taxonomy',
101+
'text',
102+
'text_raw',
103+
'title'
104+
];
105+
106+
private $mapServices = [
107+
'combined' => 'CombinedData',
108+
'concepts' => 'RankedConcepts',
109+
'entities' => 'RankedNamedEntit',
110+
'feeds' => 'FeedLinks',
111+
'image_keywords' => 'RankedImageKeywords',
112+
'keywords' => 'RankedKeywords',
113+
'microformats' => 'MicroformatData',
114+
'sentiment' => 'TextSentiment',
115+
'sentiment_targeted' => 'TargetedSentiment',
116+
'taxonomy' => 'RankedTaxonomy',
117+
'text_raw' => 'RawText',
118+
];
119+
120+
private $acceptedFlavors = [
121+
'author' => ['url', 'html'],
122+
'combined' => ['url', 'text'],
123+
'feeds' => ['url', 'html'],
124+
'image' => ['url'],
125+
'image_keywords' => ['url', 'image'],
126+
'microformats' => ['url', 'html'],
127+
'text' => ['url', 'html'],
128+
'text_raw' => ['url', 'html'],
129+
'title' => ['url', 'html'],
130+
];
131+
132+
public function __construct($key, $ssl = true)
133+
{
134+
$this->key = $key;
135+
$this->ssl = $ssl;
136+
}
137+
138+
public function __call($method, $args)
139+
{
140+
if (count($args) < 3) {
141+
$args[] = [];
142+
}
143+
144+
list($flavor, $data, $params) = $args;
145+
146+
if (!in_array($method, $this->services)) {
147+
throw new \Exception(sprintf('Invalid service (%s)', $method));
148+
}
149+
150+
if (!$this->accepts($method, $flavor)) {
151+
throw new \Exception(sprintf('Invalid flavor (%s) for service (%s)', $flavor, $method));
152+
}
153+
154+
$endpoint = $this->getServiceEndpoint($method, $flavor);
155+
$params = $params + ['apikey' => $this->key, 'outputMode' => 'json'];
156+
157+
if (!empty($this->defaults[$method])) {
158+
$params += $this->defaults[$method];
159+
}
160+
161+
if ('image' != $flavor) {
162+
$params[$flavor] = $data;
163+
} else {
164+
$endpoint .= '?' . http_build_query($params);
165+
$params = $data;
166+
}
167+
168+
$this->rawResponse = $this->query($endpoint, $params);
169+
$response = $this->rawResponse->json();
170+
171+
if ('ERROR' == $response['status']) {
172+
throw new \Exception($response['statusInfo']);
173+
}
174+
175+
return $response;
176+
}
177+
178+
public function accepts($service, $flavor) {
179+
if (empty($this->acceptedFlavors[$service])) {
180+
$this->acceptedFlavors[$service] = ['url', 'text', 'html'];
181+
}
182+
183+
return in_array($flavor, $this->acceptedFlavors[$service]);
184+
}
185+
186+
public function disableSsl()
187+
{
188+
$this->ssl = false;
189+
return $this;
190+
}
191+
192+
public function enableSsl()
193+
{
194+
$this->ssl = true;
195+
return $this;
196+
}
197+
198+
public function getServiceEndpoint($service, $flavor)
199+
{
200+
if (!empty($this->mapServices[$service])) {
201+
$service = $this->mapServices[$service];
202+
}
203+
204+
if (in_array($flavor, ['html', 'url'])) {
205+
$flavor = strtoupper($flavor);
206+
}
207+
208+
return sprintf(
209+
'http%s://%s/%s/%sGet%s',
210+
$this->ssl ? 's' : null,
211+
self::URI,
212+
strtolower($flavor),
213+
ucfirst($flavor),
214+
$service
215+
);
216+
}
217+
218+
protected function query($endpoint, $body)
219+
{
220+
return \GuzzleHttp\post($endpoint, compact('body'));
221+
}
222+
223+
}

0 commit comments

Comments
 (0)