Skip to content

Commit fa63cc9

Browse files
Merge pull request #424 from watson-developer-cloud/codegen/natural-language-classifier
feat(NLC): Added classify_collection
2 parents dc88dd8 + b6602f3 commit fa63cc9

3 files changed

Lines changed: 214 additions & 22 deletions

File tree

examples/natural_language_classifier_v1.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from __future__ import print_function
22
import json
33
import os
4+
import time
45
# from os.path import join, dirname
56
from watson_developer_cloud import NaturalLanguageClassifierV1
6-
7+
FIVE_SECONDS = 5
78

89
natural_language_classifier = NaturalLanguageClassifierV1(
910
username='YOUR SERVICE USERNAME',
@@ -22,6 +23,7 @@
2223
classifier_id = classifier['classifier_id']
2324
print(json.dumps(classifier, indent=2))
2425

26+
time.sleep(FIVE_SECONDS)
2527
status = natural_language_classifier.get_classifier(classifier_id)
2628
print(json.dumps(status, indent=2))
2729

@@ -31,6 +33,12 @@
3133
'tomorrow?')
3234
print(json.dumps(classes, indent=2))
3335

36+
if status['status'] == 'Available':
37+
collection = ['{"text":"How hot will it be today?"}', '{"text":"Is it hot outside?"}']
38+
classes = natural_language_classifier.classify_collection(
39+
classifier_id, collection)
40+
print(json.dumps(classes, indent=2))
41+
3442
delete = natural_language_classifier.delete_classifier(classifier_id)
3543
print(json.dumps(delete, indent=2))
3644

test/unit/test_natural_language_classifier_v1.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,53 @@ def test_success():
8282
assert responses.calls[4].response.text == remove_response
8383

8484
assert len(responses.calls) == 5
85+
86+
@responses.activate
87+
def test_classify_collection():
88+
natural_language_classifier = watson_developer_cloud.NaturalLanguageClassifierV1(username="username",
89+
password="password")
90+
classify_collection_url = 'https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/497EF2-nlc-00/classify_collection'
91+
classify_collection_response = '{ \
92+
"classifier_id": "497EF2-nlc-00", \
93+
"url": "https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/10D41B-nlc-1", \
94+
"collection": [ \
95+
{ \
96+
"text": "How hot will it be today?", \
97+
"top_class": "temperature", \
98+
"classes": [ \
99+
{ \
100+
"class_name": "temperature", \
101+
"confidence": 0.9930558798985937 \
102+
}, \
103+
{ \
104+
"class_name": "conditions", \
105+
"confidence": 0.006944120101406304 \
106+
} \
107+
] \
108+
}, \
109+
{ \
110+
"text": "Is it hot outside?", \
111+
"top_class": "temperature", \
112+
"classes": [ \
113+
{ \
114+
"class_name": "temperature", \
115+
"confidence": 1 \
116+
}, \
117+
{ \
118+
"class_name": "conditions", \
119+
"confidence": 0 \
120+
} \
121+
] \
122+
} \
123+
] \
124+
}'
125+
responses.add(responses.POST, classify_collection_url,
126+
body=classify_collection_response, status=200,
127+
content_type='application/json')
128+
129+
classifier_id = '497EF2-nlc-00'
130+
collection = ['{"text":"How hot will it be today?"}', '{"text":"Is it hot outside?"}']
131+
natural_language_classifier.classify_collection(classifier_id, collection)
132+
133+
assert responses.calls[0].request.url == classify_collection_url
134+
assert responses.calls[0].response.text == classify_collection_response

watson_developer_cloud/natural_language_classifier_v1.py

Lines changed: 155 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,31 @@ def classify(self, classifier_id, text):
9191
method='POST', url=url, json=data, accept_json=True)
9292
return response
9393

94+
def classify_collection(self, classifier_id, collection):
95+
"""
96+
Returns label information for multiple phrases. The status must be `Available`
97+
before you can use the classifier to classify text. Note that classifying
98+
Japanese texts is a beta feature.
99+
100+
:param str classifier_id: Classifier ID to use.
101+
:param list[ClassifyInput] collection: The submitted phrases.
102+
:return: A `dict` containing the `ClassificationCollection` response.
103+
:rtype: dict
104+
"""
105+
if classifier_id is None:
106+
raise ValueError('classifier_id must be provided')
107+
if collection is None:
108+
raise ValueError('collection must be provided')
109+
collection = [
110+
self._convert_model(x, ClassifyInput) for x in collection
111+
]
112+
data = {'collection': collection}
113+
url = '/v1/classifiers/{0}/classify_collection'.format(
114+
*self._encode_path_vars(classifier_id))
115+
response = self.request(
116+
method='POST', url=url, json=data, accept_json=True)
117+
return response
118+
94119
#########################
95120
# Manage classifiers
96121
#########################
@@ -106,8 +131,8 @@ def create_classifier(self,
106131
Sends data to create and train a classifier and returns information about the new
107132
classifier.
108133
109-
:param file metadata: Metadata in JSON format. The metadata identifies the language of the data, and an optional name to identify the classifier.
110-
:param file training_data: Training data in CSV format. Each text value must have at least one class. The data can include up to 15,000 records. For details, see [Using your own data](https://console.bluemix.net/docs/services/natural-language-classifier/using-your-data.html).
134+
:param file metadata: Metadata in JSON format. The metadata identifies the language of the data, and an optional name to identify the classifier. Specify the language with the 2-letter primary language code as assigned in ISO standard 639. Supported languages are English (`en`), Arabic (`ar`), French (`fr`), German, (`de`), Italian (`it`), Japanese (`ja`), Korean (`ko`), Brazilian Portuguese (`pt`), and Spanish (`es`).
135+
:param file training_data: Training data in CSV format. Each text value must have at least one class. The data can include up to 20,000 records. For details, see [Data preparation](https://console.bluemix.net/docs/services/natural-language-classifier/using-your-data.html).
111136
:param str metadata_filename: The filename for training_metadata.
112137
:param str training_data_filename: The filename for training_data.
113138
:return: A `dict` containing the `Classifier` response.
@@ -190,8 +215,8 @@ class Classification(object):
190215
"""
191216
Response from the classifier for a phrase.
192217
193-
:attr str classifier_id: (optional) Unique identifier for this classifier.
194-
:attr str url: (optional) Link to the classifier.
218+
:attr str classifier_id: (optional) Unique identifier for this classifier. Not returned by the request to classify multiple phrases.
219+
:attr str url: (optional) Link to the classifier. Not returned by the request to classify multiple phrases.
195220
:attr str text: (optional) The submitted phrase.
196221
:attr str top_class: (optional) The class with the highest confidence.
197222
:attr list[ClassifiedClass] classes: (optional) An array of up to ten class-confidence pairs sorted in descending order of confidence.
@@ -206,8 +231,8 @@ def __init__(self,
206231
"""
207232
Initialize a Classification object.
208233
209-
:param str classifier_id: (optional) Unique identifier for this classifier.
210-
:param str url: (optional) Link to the classifier.
234+
:param str classifier_id: (optional) Unique identifier for this classifier. Not returned by the request to classify multiple phrases.
235+
:param str url: (optional) Link to the classifier. Not returned by the request to classify multiple phrases.
211236
:param str text: (optional) The submitted phrase.
212237
:param str top_class: (optional) The class with the highest confidence.
213238
:param list[ClassifiedClass] classes: (optional) An array of up to ten class-confidence pairs sorted in descending order of confidence.
@@ -223,16 +248,16 @@ def _from_dict(cls, _dict):
223248
"""Initialize a Classification object from a json dictionary."""
224249
args = {}
225250
if 'classifier_id' in _dict:
226-
args['classifier_id'] = _dict['classifier_id']
251+
args['classifier_id'] = _dict.get('classifier_id')
227252
if 'url' in _dict:
228-
args['url'] = _dict['url']
253+
args['url'] = _dict.get('url')
229254
if 'text' in _dict:
230-
args['text'] = _dict['text']
255+
args['text'] = _dict.get('text')
231256
if 'top_class' in _dict:
232-
args['top_class'] = _dict['top_class']
257+
args['top_class'] = _dict.get('top_class')
233258
if 'classes' in _dict:
234259
args['classes'] = [
235-
ClassifiedClass._from_dict(x) for x in _dict['classes']
260+
ClassifiedClass._from_dict(x) for x in (_dict.get('classes'))
236261
]
237262
return cls(**args)
238263

@@ -266,6 +291,67 @@ def __ne__(self, other):
266291
return not self == other
267292

268293

294+
class ClassificationCollection(object):
295+
"""
296+
Response from the classifier for a phrase.
297+
298+
:attr str text: (optional) The submitted phrase.
299+
:attr str top_class: (optional) The class with the highest confidence.
300+
:attr list[Classification] classes: (optional) An array of up to ten class-confidence pairs sorted in descending order of confidence.
301+
"""
302+
303+
def __init__(self, text=None, top_class=None, classes=None):
304+
"""
305+
Initialize a ClassificationCollection object.
306+
307+
:param str text: (optional) The submitted phrase.
308+
:param str top_class: (optional) The class with the highest confidence.
309+
:param list[Classification] classes: (optional) An array of up to ten class-confidence pairs sorted in descending order of confidence.
310+
"""
311+
self.text = text
312+
self.top_class = top_class
313+
self.classes = classes
314+
315+
@classmethod
316+
def _from_dict(cls, _dict):
317+
"""Initialize a ClassificationCollection object from a json dictionary."""
318+
args = {}
319+
if 'text' in _dict:
320+
args['text'] = _dict.get('text')
321+
if 'top_class' in _dict:
322+
args['top_class'] = _dict.get('top_class')
323+
if 'classes' in _dict:
324+
args['classes'] = [
325+
Classification._from_dict(x) for x in (_dict.get('classes'))
326+
]
327+
return cls(**args)
328+
329+
def _to_dict(self):
330+
"""Return a json dictionary representing this model."""
331+
_dict = {}
332+
if hasattr(self, 'text') and self.text is not None:
333+
_dict['text'] = self.text
334+
if hasattr(self, 'top_class') and self.top_class is not None:
335+
_dict['top_class'] = self.top_class
336+
if hasattr(self, 'classes') and self.classes is not None:
337+
_dict['classes'] = [x._to_dict() for x in self.classes]
338+
return _dict
339+
340+
def __str__(self):
341+
"""Return a `str` version of this ClassificationCollection object."""
342+
return json.dumps(self._to_dict(), indent=2)
343+
344+
def __eq__(self, other):
345+
"""Return `true` when self and other are equal, false otherwise."""
346+
if not isinstance(other, self.__class__):
347+
return False
348+
return self.__dict__ == other.__dict__
349+
350+
def __ne__(self, other):
351+
"""Return `true` when self and other are not equal, false otherwise."""
352+
return not self == other
353+
354+
269355
class ClassifiedClass(object):
270356
"""
271357
Class and confidence.
@@ -289,9 +375,9 @@ def _from_dict(cls, _dict):
289375
"""Initialize a ClassifiedClass object from a json dictionary."""
290376
args = {}
291377
if 'confidence' in _dict:
292-
args['confidence'] = _dict['confidence']
378+
args['confidence'] = _dict.get('confidence')
293379
if 'class_name' in _dict:
294-
args['class_name'] = _dict['class_name']
380+
args['class_name'] = _dict.get('class_name')
295381
return cls(**args)
296382

297383
def _to_dict(self):
@@ -363,26 +449,26 @@ def _from_dict(cls, _dict):
363449
"""Initialize a Classifier object from a json dictionary."""
364450
args = {}
365451
if 'name' in _dict:
366-
args['name'] = _dict['name']
452+
args['name'] = _dict.get('name')
367453
if 'url' in _dict:
368-
args['url'] = _dict['url']
454+
args['url'] = _dict.get('url')
369455
else:
370456
raise ValueError(
371457
'Required property \'url\' not present in Classifier JSON')
372458
if 'status' in _dict:
373-
args['status'] = _dict['status']
459+
args['status'] = _dict.get('status')
374460
if 'classifier_id' in _dict:
375-
args['classifier_id'] = _dict['classifier_id']
461+
args['classifier_id'] = _dict.get('classifier_id')
376462
else:
377463
raise ValueError(
378464
'Required property \'classifier_id\' not present in Classifier JSON'
379465
)
380466
if 'created' in _dict:
381-
args['created'] = string_to_datetime(_dict['created'])
467+
args['created'] = string_to_datetime(_dict.get('created'))
382468
if 'status_description' in _dict:
383-
args['status_description'] = _dict['status_description']
469+
args['status_description'] = _dict.get('status_description')
384470
if 'language' in _dict:
385-
args['language'] = _dict['language']
471+
args['language'] = _dict.get('language')
386472
return cls(**args)
387473

388474
def _to_dict(self):
@@ -442,7 +528,7 @@ def _from_dict(cls, _dict):
442528
args = {}
443529
if 'classifiers' in _dict:
444530
args['classifiers'] = [
445-
Classifier._from_dict(x) for x in _dict['classifiers']
531+
Classifier._from_dict(x) for x in (_dict.get('classifiers'))
446532
]
447533
else:
448534
raise ValueError(
@@ -470,3 +556,51 @@ def __eq__(self, other):
470556
def __ne__(self, other):
471557
"""Return `true` when self and other are not equal, false otherwise."""
472558
return not self == other
559+
560+
561+
class ClassifyInput(object):
562+
"""
563+
Request payload to classify.
564+
565+
:attr str text: The submitted phrase.
566+
"""
567+
568+
def __init__(self, text):
569+
"""
570+
Initialize a ClassifyInput object.
571+
572+
:param str text: The submitted phrase.
573+
"""
574+
self.text = text
575+
576+
@classmethod
577+
def _from_dict(cls, _dict):
578+
"""Initialize a ClassifyInput object from a json dictionary."""
579+
args = {}
580+
if 'text' in _dict:
581+
args['text'] = _dict.get('text')
582+
else:
583+
raise ValueError(
584+
'Required property \'text\' not present in ClassifyInput JSON')
585+
return cls(**args)
586+
587+
def _to_dict(self):
588+
"""Return a json dictionary representing this model."""
589+
_dict = {}
590+
if hasattr(self, 'text') and self.text is not None:
591+
_dict['text'] = self.text
592+
return _dict
593+
594+
def __str__(self):
595+
"""Return a `str` version of this ClassifyInput object."""
596+
return json.dumps(self._to_dict(), indent=2)
597+
598+
def __eq__(self, other):
599+
"""Return `true` when self and other are equal, false otherwise."""
600+
if not isinstance(other, self.__class__):
601+
return False
602+
return self.__dict__ == other.__dict__
603+
604+
def __ne__(self, other):
605+
"""Return `true` when self and other are not equal, false otherwise."""
606+
return not self == other

0 commit comments

Comments
 (0)