diff --git a/Clarifai.podspec b/Clarifai.podspec index a904b98..4d2e4f0 100644 --- a/Clarifai.podspec +++ b/Clarifai.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Clarifai' - s.version = '2.0.3' + s.version = '2.1.0' s.summary = 'Clarifai API client for Objective-C.' s.homepage = 'https://github.com/Clarifai' diff --git a/Clarifai/Classes/ClarifaiApp.h b/Clarifai/Classes/ClarifaiApp.h index 98d70f7..3281540 100644 --- a/Clarifai/Classes/ClarifaiApp.h +++ b/Clarifai/Classes/ClarifaiApp.h @@ -41,33 +41,61 @@ - (void)addInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion; /** - * Add tags to an existing input. + * Merge tags to an existing input. * - * @param concepts Array of new ClarifaiConcepts. - * @param inputID String containing the id of the input you'd like to update - * concepts for. + * @warning Merging will overwrite values for tags with matching id's, or append to the + * input's existing list of tags in the app. + * + * @param concepts Array of new or updated ClarifaiConcepts to merge. + * @param inputID String containing the id of the input you'd like to merge concepts to. * @param completion Invoked when the update completes. */ -- (void)addConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion; +- (void)mergeConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion; /** - * Add tags to one or more existing inputs. + * Merge tags to one or more existing inputs. + * + * @warning Merging will overwrite values for tags with matching id's, or append to an + * input's existing list of tags in the app. * - * @param inputs Array of ClarifaiInputs to add tags to. Each input should contain - * the tags to be added in it's concepts array property. These new - * concepts will be merged with the existing tags of the input. - * Each input must also have an inputID. + * @param inputs Array of ClarifaiInputs to merge tags to. Each input should contain the + * list of tags to be merged in it's concepts array property. Each input + * must also have an inputID. * @param completion Invoked when the update completes. */ -- (void)updateConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion; +- (void)mergeConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion; + +/** + * Overwrites tags of existing input with given ID. + * + * @warning This method will overwrite values for tags with matching id's, or overwrite the + * input's list of tags with the new list of tags. + * + * @param inputID String containing the id of the input you'd like to overwrite concepts for. + * @param completion Invoked when the update completes. + */ +- (void)setConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion; + +/** + * Overwrites tags of one or more existing inputs. + * + * @warning This method will overwrite values for tags with matching id's, or overwrite each + * input's list of tags with the new list of tags. + * + * @param inputs Array of ClarifaiInputs to add tags to. Each input should contain + * the tags to be added in it's concepts array property. Each input must also + * have an inputID. + * @param completion Invoked when the update completes. + */ +- (void)setConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion; /** * Delete tags from an existing input. * * @param concepts Array of ClarifaiConcepts to delete. These must have matching conceptID's * to whichever ones are being deleted. - * @param inputID String containing the id of the input you'd like to update - * concepts for. + * @param inputID String containing the id of the input you'd like to delete + * concepts from. * @param completion Invoked when the update completes. */ - (void)deleteConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion; @@ -76,7 +104,7 @@ * Delete tags from one or more existing inputs. * * @param inputs Array of ClarifaiInputs to delete tags from. Each input should contain - * the tags to be delete in it's concepts array property. Each input must + * a list of tags to be deleted as it's concepts array property. Each input must * also have an inputID. * @param completion Invoked when the update completes. */ @@ -168,21 +196,33 @@ */ - (void)addConcepts:(NSArray *)concepts completion:(ClarifaiSearchConceptCompletion)completion; +/** + * Merge a list of tags to an existing model. + * + * @warning Merging will overwrite values for tags with matching id's, or append to the + * model's existing list of tags in the app. + * + * @param concepts Array of new ClarifaiConcepts. + * @param modelID String containing the id of the model you'd like to update + * concepts for. + * @param completion Invoked when the update completes. + */ +- (void)mergeConcepts:(NSArray *)concepts forModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion; /** - * This can be used to add tags to an existing model. + * Overwrite the list of tags of an existing model with a new list of tags. * * @param concepts Array of new ClarifaiConcepts. * @param modelID String containing the id of the model you'd like to update * concepts for. * @param completion Invoked when the update completes. */ -- (void)addConcepts:(NSArray *)concepts toModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion; +- (void)setConcepts:(NSArray *)concepts forModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion; /** - * This can be used to remove tags from an existing model. + * Remove tags from an existing model. * - * @param concepts Array of ClarifaiConcepts. + * @param concepts Array of ClarifaiConcepts with id's matching the tags to be removed. * @param modelID String containing the id of the model you'd like to update * concepts for. * @param completion Invoked when the update completes. diff --git a/Clarifai/Classes/ClarifaiApp.m b/Clarifai/Classes/ClarifaiApp.m index 279a580..ed91f60 100644 --- a/Clarifai/Classes/ClarifaiApp.m +++ b/Clarifai/Classes/ClarifaiApp.m @@ -157,97 +157,7 @@ - (void)addInputs:(NSArray *)inputs completion:(ClarifaiInputs }]; } -- (void)addConcepts:(NSArray *)concepts toModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion { - [self ensureValidAccessToken:^(NSError *error) { - if (error) { - SafeRunBlock(completion, nil, error); - return; - } - - NSMutableDictionary *params = [NSMutableDictionary dictionary]; - NSMutableArray *conceptsArray = [NSMutableArray array]; - for (ClarifaiConcept *concept in concepts) { - NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; - conceptDict[@"id"] = concept.conceptID; - [conceptsArray addObject:conceptDict]; - } - - params[@"concepts"] = conceptsArray; - params[@"action"] = @"merge_concepts"; - - NSString *inputURLSuffix = [NSString stringWithFormat:@"/models/%@/output_info/data/concepts", modelID]; - NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; - [self.manager PATCH:apiURL - parameters:params - success:^(AFHTTPRequestOperation *op, id response) { - NSDictionary *status = response[@"status"]; - long code = [status[@"code"] longValue]; - if (code == 10000) { - ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:response[@"model"]]; - completion(model, nil); - } else if (code == 21202) { - NSError *error = [[NSError alloc] initWithDomain:kErrorDomain - code:400 - userInfo:@{@"description": status[@"description"], - @"details": status[@"details"]}]; - completion(nil, error); - } - } failure:^(AFHTTPRequestOperation *op, NSError *error) { - if (op.response.statusCode >= 400) { - error = [self errorFromHttpResponse:op]; - } - completion(nil, error); - }]; - - }]; -}; - -- (void)deleteConcepts:(NSArray *)concepts fromModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion { - [self ensureValidAccessToken:^(NSError *error) { - if (error) { - SafeRunBlock(completion, nil, error); - return; - } - - NSMutableDictionary *params = [NSMutableDictionary dictionary]; - NSMutableArray *conceptsArray = [NSMutableArray array]; - for (ClarifaiConcept *concept in concepts) { - NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; - conceptDict[@"id"] = concept.conceptID; - [conceptsArray addObject:conceptDict]; - } - - params[@"concepts"] = conceptsArray; - params[@"action"] = @"delete_concepts"; - - NSString *inputURLSuffix = [NSString stringWithFormat:@"/models/%@/output_info/data/concepts", modelID]; - NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; - [self.manager PATCH:apiURL - parameters:params - success:^(AFHTTPRequestOperation *op, id response) { - NSDictionary *status = response[@"status"]; - long code = [status[@"code"] longValue]; - if (code == 10000) { - ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:response[@"model"]]; - completion(model, nil); - } else if (code == 21202) { - NSError *error = [[NSError alloc] initWithDomain:kErrorDomain - code:400 - userInfo:@{@"description": status[@"description"], - @"details": status[@"details"]}]; - completion(nil, error); - } - } failure:^(AFHTTPRequestOperation *op, NSError *error) { - if (op.response.statusCode >= 400) { - error = [self errorFromHttpResponse:op]; - } - completion(nil, error); - }]; - - }]; -}; - -- (void)addConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion { +- (void)mergeConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion { [self ensureValidAccessToken:^(NSError *error) { if (error) { SafeRunBlock(completion, nil, error); @@ -272,7 +182,7 @@ - (void)addConcepts:(NSArray *)concepts forInputWithID:(NSSt NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"inputs"] = @[inputDict]; - params[@"action"] = @"merge_concepts"; + params[@"action"] = @"merge"; NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; @@ -290,7 +200,7 @@ - (void)addConcepts:(NSArray *)concepts forInputWithID:(NSSt }]; } -- (void)updateConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion { +- (void)mergeConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion { [self ensureValidAccessToken:^(NSError *error) { if (error) { SafeRunBlock(completion, nil, error); @@ -318,7 +228,7 @@ - (void)updateConceptsForInputs:(NSArray *)inputs completion:(C NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"inputs"] = inputsArray; - params[@"action"] = @"merge_concepts"; + params[@"action"] = @"merge"; NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; @@ -340,6 +250,99 @@ - (void)updateConceptsForInputs:(NSArray *)inputs completion:(C }]; } +- (void)setConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion { + [self ensureValidAccessToken:^(NSError *error) { + if (error) { + SafeRunBlock(completion, nil, error); + return; + } + + NSMutableDictionary *inputDict = [NSMutableDictionary dictionary]; + inputDict[@"id"] = inputID; + + // create concepts array + NSMutableDictionary *data = [NSMutableDictionary dictionary]; + NSMutableArray *conceptsArray = [NSMutableArray array]; + for (ClarifaiConcept *concept in concepts) { + NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; + conceptDict[@"id"] = concept.conceptID; + conceptDict[@"value"] = [NSNumber numberWithFloat:concept.score]; + [conceptsArray addObject:conceptDict]; + } + + data[@"concepts"] = conceptsArray; + inputDict[@"data"] = data; + + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + params[@"inputs"] = @[inputDict]; + params[@"action"] = @"overwrite"; + + NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; + NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; + [self.manager PATCH:apiURL + parameters:params + success:^(AFHTTPRequestOperation *op, id response) { + ClarifaiInput *input = [[ClarifaiInput alloc] initWithDictionary:response[@"inputs"][0]]; + completion(input, nil); + } failure:^(AFHTTPRequestOperation *op, NSError *error) { + if (op.response.statusCode >= 400) { + error = [self errorFromHttpResponse:op]; + } + completion(nil, error); + }]; + }]; +} + +- (void)setConceptsForInputs:(NSArray *)inputs completion:(ClarifaiInputsCompletion)completion { + [self ensureValidAccessToken:^(NSError *error) { + if (error) { + SafeRunBlock(completion, nil, error); + return; + } + NSMutableArray *inputsArray = [[NSMutableArray alloc] init]; + for (ClarifaiInput *input in inputs) { + NSMutableDictionary *inputDict = [NSMutableDictionary dictionary]; + inputDict[@"id"] = input.inputID; + + // create concepts array + NSMutableDictionary *data = [NSMutableDictionary dictionary]; + NSMutableArray *conceptsArray = [NSMutableArray array]; + for (ClarifaiConcept *concept in input.concepts) { + NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; + conceptDict[@"id"] = concept.conceptID; + conceptDict[@"value"] = [NSNumber numberWithFloat:concept.score]; + [conceptsArray addObject:conceptDict]; + } + + data[@"concepts"] = conceptsArray; + inputDict[@"data"] = data; + [inputsArray addObject:inputDict]; + } + + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + params[@"inputs"] = inputsArray; + params[@"action"] = @"overwrite"; + + NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; + NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; + [self.manager PATCH:apiURL + parameters:params + success:^(AFHTTPRequestOperation *op, id response) { + NSMutableArray *inputs = [[NSMutableArray alloc] init]; + for (NSDictionary *inputDict in response[@"inputs"]) { + ClarifaiInput *input = [[ClarifaiInput alloc] initWithDictionary:inputDict]; + [inputs addObject:input]; + } + completion(inputs, nil); + } failure:^(AFHTTPRequestOperation *op, NSError *error) { + if (op.response.statusCode >= 400) { + error = [self errorFromHttpResponse:op]; + } + completion(nil, error); + }]; + }]; +} + - (void)deleteConcepts:(NSArray *)concepts forInputWithID:(NSString *)inputID completion:(ClarifaiStoreInputCompletion)completion { [self ensureValidAccessToken:^(NSError *error) { if (error) { @@ -364,7 +367,7 @@ - (void)deleteConcepts:(NSArray *)concepts forInputWithID:(N NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"inputs"] = @[inputDict]; - params[@"action"] = @"delete_concepts"; + params[@"action"] = @"remove"; NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; @@ -409,7 +412,7 @@ - (void)deleteConceptsForInputs:(NSArray *)inputs completion:(C NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"inputs"] = inputsArray; - params[@"action"] = @"delete_concepts"; + params[@"action"] = @"remove"; NSString *inputURLSuffix = [NSString stringWithFormat:@"/inputs/"]; NSString *apiURL = [kApiBaseUrl stringByAppendingString:inputURLSuffix]; @@ -707,17 +710,17 @@ - (NSDictionary *)formatItemForSearch:(ClarifaiSearchTerm *)searchTerm { } } else if ([searchTerm.searchItem isKindOfClass:[ClarifaiConcept class]]) { ClarifaiConcept *concept = (ClarifaiConcept *)searchTerm.searchItem; - if (concept.conceptID) { + if (concept.conceptName) { if (searchTerm.isInput) { - return @{@"input": @{@"data": @{@"concepts": @[ @{@"id": concept.conceptID, @"value": @(YES)}]}}}; + return @{@"input": @{@"data": @{@"concepts": @[ @{@"name": concept.conceptName}]}}}; } else { - return @{@"output": @{@"data": @{@"concepts": @[ @{@"id": concept.conceptID, @"value": @(YES)}]}}}; + return @{@"output": @{@"data": @{@"concepts": @[ @{@"name": concept.conceptName}]}}}; } - } else { + } else if (concept.conceptID) { if (searchTerm.isInput) { - return @{@"input": @{@"data": @{@"concepts": @[ @{@"name": concept.conceptName, @"value": @(YES)}]}}}; + return @{@"input": @{@"data": @{@"concepts": @[ @{@"id": concept.conceptID}]}}}; } else { - return @{@"output": @{@"data": @{@"concepts": @[ @{@"name": concept.conceptName, @"value": @(YES)}]}}}; + return @{@"output": @{@"data": @{@"concepts": @[ @{@"id": concept.conceptID}]}}}; } } @@ -746,8 +749,10 @@ - (void)search:(NSArray *)searchTerms query[@"ands"] = ands; NSDictionary *pagination = @{@"page": page, @"per_page": perPage}; - - [self.manager POST:apiURL parameters:@{@"query": query, @"pagination":pagination} success:^(AFHTTPRequestOperation *operation, NSDictionary *response) { + NSDictionary *params = @{@"query": query, @"pagination":pagination}; + [self.manager POST:apiURL + parameters:params + success:^(AFHTTPRequestOperation *operation, NSDictionary *response) { NSArray *hits = response[@"hits"]; NSArray *searchResults = [hits map:^(NSDictionary *hit) { return [[ClarifaiSearchResult alloc] initWithDictionary:hit]; @@ -858,6 +863,155 @@ - (void)getModelByName:(NSString *)modelName completion:(ClarifaiModelCompletion }]; } +- (void)mergeConcepts:(NSArray *)concepts forModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion { + [self ensureValidAccessToken:^(NSError *error) { + if (error) { + SafeRunBlock(completion, nil, error); + return; + } + // Create concepts array. + NSMutableArray *conceptsArray = [NSMutableArray array]; + for (ClarifaiConcept *concept in concepts) { + NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; + conceptDict[@"id"] = concept.conceptID; + [conceptsArray addObject:conceptDict]; + } + + // Create model array of one model with given ID. + NSMutableDictionary *modelDict = @{@"id":modelID, + @"output_info":@{@"data":@{@"concepts":conceptsArray}}}; + NSArray *modelArray = @[modelDict]; + + // Add all to params. + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + params[@"models"] = modelArray; + params[@"action"] = @"merge"; + + NSString *apiURL = [kApiBaseUrl stringByAppendingString:@"/models/"]; + [self.manager PATCH:apiURL + parameters:params + success:^(AFHTTPRequestOperation *op, id response) { + NSDictionary *status = response[@"status"]; + long code = [status[@"code"] longValue]; + if (code == 10000) { + ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:response[@"model"]]; + completion(model, nil); + } else if (code == 21202) { + NSError *error = [[NSError alloc] initWithDomain:kErrorDomain + code:400 + userInfo:@{@"description": status[@"description"], + @"details": status[@"details"]}]; + completion(nil, error); + } + } failure:^(AFHTTPRequestOperation *op, NSError *error) { + if (op.response.statusCode >= 400) { + error = [self errorFromHttpResponse:op]; + } + completion(nil, error); + }]; + + }]; +} + +- (void)setConcepts:(NSArray *)concepts forModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion { + [self ensureValidAccessToken:^(NSError *error) { + if (error) { + SafeRunBlock(completion, nil, error); + return; + } + // Create concepts array. + NSMutableArray *conceptsArray = [NSMutableArray array]; + for (ClarifaiConcept *concept in concepts) { + NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; + conceptDict[@"id"] = concept.conceptID; + [conceptsArray addObject:conceptDict]; + } + + // Create model array of one model with given ID. + NSMutableDictionary *modelDict = @{@"id":modelID, + @"output_info":@{@"data":@{@"concepts":conceptsArray}}}; + NSArray *modelArray = @[modelDict]; + + // Add all to params. + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + params[@"models"] = modelArray; + params[@"action"] = @"overwrite"; + + NSString *apiURL = [kApiBaseUrl stringByAppendingString:@"/models/"]; + [self.manager PATCH:apiURL + parameters:params + success:^(AFHTTPRequestOperation *op, id response) { + NSDictionary *status = response[@"status"]; + long code = [status[@"code"] longValue]; + if (code == 10000) { + ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:response[@"model"]]; + completion(model, nil); + } else if (code == 21202) { + NSError *error = [[NSError alloc] initWithDomain:kErrorDomain + code:400 + userInfo:@{@"description": status[@"description"], + @"details": status[@"details"]}]; + completion(nil, error); + } + } failure:^(AFHTTPRequestOperation *op, NSError *error) { + if (op.response.statusCode >= 400) { + error = [self errorFromHttpResponse:op]; + } + completion(nil, error); + }]; + + }]; +} + +- (void)deleteConcepts:(NSArray *)concepts fromModelWithID:(NSString *)modelID completion:(ClarifaiModelCompletion)completion { + [self ensureValidAccessToken:^(NSError *error) { + if (error) { + SafeRunBlock(completion, nil, error); + return; + } + // Create concepts array. + NSMutableArray *conceptsArray = [NSMutableArray array]; + for (ClarifaiConcept *concept in concepts) { + NSMutableDictionary *conceptDict = [NSMutableDictionary dictionary]; + conceptDict[@"id"] = concept.conceptID; + [conceptsArray addObject:conceptDict]; + } + + // Create model array of one model with given ID. + NSMutableDictionary *modelDict = @{@"id":modelID, + @"output_info":@{@"data":@{@"concepts":conceptsArray}}}; + NSArray *modelArray = @[modelDict]; + + // Add all to params. + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + params[@"models"] = modelArray; + params[@"action"] = @"remove"; + + NSString *apiURL = [kApiBaseUrl stringByAppendingString:@"/models/"]; + [self.manager PATCH:apiURL + parameters:params + success:^(AFHTTPRequestOperation *op, id response) { + NSDictionary *status = response[@"status"]; + long code = [status[@"code"] longValue]; + if (code == 10000) { + ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:response[@"model"]]; + completion(model, nil); + } else if (code == 21202) { + NSError *error = [[NSError alloc] initWithDomain:kErrorDomain + code:400 + userInfo:@{@"description": status[@"description"], + @"details": status[@"details"]}]; + completion(nil, error); + } + } failure:^(AFHTTPRequestOperation *op, NSError *error) { + if (op.response.statusCode >= 400) { + error = [self errorFromHttpResponse:op]; + } + completion(nil, error); + }]; + + }]; +} - (void)listVersionsForModel:(NSString *)modelID page:(int)page @@ -1052,9 +1206,19 @@ - (void)createModel:(NSArray *)concepts NSString *apiURL = [kApiBaseUrl stringByAppendingString:@"/models"]; [self.manager POST:apiURL parameters:model success:^(AFHTTPRequestOperation *operation, id responseObject) { - ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:responseObject[@"model"]]; - model.app = self; - completion(model, nil); + NSDictionary *status = responseObject[@"status"]; + long code = [status[@"code"] longValue]; + if (code == 10000) { + ClarifaiModel *model = [[ClarifaiModel alloc] initWithDictionary:responseObject[@"model"]]; + model.app = self; + completion(model, nil); + } else if (code == 21202) { + NSError *error = [[NSError alloc] initWithDomain:kErrorDomain + code:400 + userInfo:@{@"description": status[@"description"], + @"details": status[@"details"]}]; + completion(nil, error); + } } failure:^(AFHTTPRequestOperation * operation, NSError *error) { completion(nil, error); }]; @@ -1162,7 +1326,7 @@ - (void)setAccessToken:(NSString *)accessToken { NSString *value = [NSString stringWithFormat:@"Bearer %@", self.accessToken]; [self.manager.requestSerializer setValue:value forHTTPHeaderField:@"Authorization"]; [self.manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - [self.manager.requestSerializer setValue:@"objc:2.0.3" forHTTPHeaderField:@"X-Clarifai-Client"]; + [self.manager.requestSerializer setValue:@"objc:2.1.0" forHTTPHeaderField:@"X-Clarifai-Client"]; } - (void)ensureValidAccessToken:(void (^)(NSError *error))handler { diff --git a/Example/ClarifaiTests/ClarifaiTests.m b/Example/ClarifaiTests/ClarifaiTests.m index 43cbbb1..6fa7362 100644 --- a/Example/ClarifaiTests/ClarifaiTests.m +++ b/Example/ClarifaiTests/ClarifaiTests.m @@ -27,6 +27,7 @@ - (void)setUp { _conCount = 0; } +// TEST INPUTS - (void)testAddInputs { CAIFuture *future = [[CAIFuture alloc] init]; @@ -34,7 +35,7 @@ - (void)testAddInputs { ClarifaiConcept *concept1 = [[ClarifaiConcept alloc] initWithConceptName:@"dogg"]; concept1.score = 0; ClarifaiCrop *crop = [[ClarifaiCrop alloc] initWithTop:0.2 left:0.3 bottom:0.7 right:0.8]; - ClarifaiImage *img1 = [[ClarifaiImage alloc] initWithURL:@"https://samples.clarifai.com/metro-north.jpg" crop:crop andConcepts:@[concept1]]; + ClarifaiImage *img1 = [[ClarifaiImage alloc] initWithURL:@"https://samples.clarifai.com/metro-north.jpg" andConcepts:@[concept1]]; img1.allowDuplicateURLs = YES; //create second image and concept. @@ -59,6 +60,124 @@ - (void)testAddInputs { [future getResult]; } +- (void)testGetInputs { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + [_app getInputsOnPage:1 pageSize:30 completion:^(NSArray *inputs, NSError *error) { + assert(error == nil); + XCTAssert([inputs count] > 0); + [future setResult:@(YES)]; + }]; + [future getResult]; +} + +- (void)testGetInputByID { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { + assert(error == nil); + XCTAssert([_runningImageID isEqualToString:input.inputID]); + [future setResult:@(YES)]; + }]; + + [future getResult]; +} + +- (void)testGetInputStatus { + CAIFuture *future = [[CAIFuture alloc] init]; + [_app getInputsStatus:^(int numProcessed, int numToProcess, int errors, NSError *error) { + assert(error == nil); + [future setResult:@(YES)]; + }]; + + [future getResult]; +} + +- (void)testDeleteInputByID { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + [_app deleteInput:_runningImageID completion:^(NSError *error) { + assert(error == nil); + [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { + //should be error if input was properly deleted. + XCTAssert(error != nil); + [future setResult:@(YES)]; + }]; + }]; + + [future getResult]; +} + +- (void)testDeleteInputByIDListInputs { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + ClarifaiInput *input = [[ClarifaiInput alloc] init]; + input.inputID = _runningImageID; + [_app deleteInputsByIDList:@[input] completion:^(NSError *error) { + assert(error == nil); + //poll to check for input until deletion completes. + [self pollForInputWithTimeout:20 completion:^(NSError *error) { + XCTAssert(error == nil); + [future setResult:@(YES)]; + }]; + }]; + + [future getResult]; +} + +- (void)testDeleteInputByIDListStrings { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + [_app deleteInputsByIDList:@[_runningImageID] completion:^(NSError *error) { + assert(error == nil); + //poll to check for input until deletion completes. + [self pollForInputWithTimeout:20 completion:^(NSError *error) { + XCTAssert(error == nil); + [future setResult:@(YES)]; + }]; + }]; + + [future getResult]; +} + +- (void)testDeleteAllInputs { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; + [_app deleteAllInputs:^(NSError *error) { + assert(error == nil); + //poll until deletion completes, getinput returns 404 error. + [self pollForInputWithTimeout:20 completion:^(NSError *error) { + XCTAssert(error == nil); + [future setResult:@(YES)]; + }]; + }]; + [future getResult]; +} + +- (void) pollForInputWithTimeout:(NSInteger)attempts completion:(ClarifaiRequestCompletion)completion { + if (attempts > 0) { + [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { + if (input == nil && error != nil) { + if ([error code] == (NSInteger)404) { + // error code was 404, resource does not exist. input was deleted. + completion(nil); + } else { + // some other error, pass on to completion. + completion(error); + } + } else if (input != nil && error == nil) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ + [self pollForInputWithTimeout:attempts-1 completion:completion]; + }); + } + }]; + } else { + // timed out, all attempts completed. + NSError *error = [[NSError alloc] initWithDomain:@"com.clarifai.ClarifaiClient" code:(NSInteger)408 userInfo:@{@"description":@"Request timed out. Input still existed after all attempts."}]; + completion(error); + } +} + - (void)testSearchWithMetadata { CAIFuture *future = [[CAIFuture alloc] init]; [self testAddInputs]; @@ -72,11 +191,11 @@ - (void)testSearchWithMetadata { - (void)testSearchWithImageData { CAIFuture *future = [[CAIFuture alloc] init]; + [self testAddInputs]; ClarifaiImage *image = [[ClarifaiImage alloc] initWithImage:[UIImage imageNamed:@"geth.jpg"]]; ClarifaiSearchTerm *searchTerm = [[ClarifaiSearchTerm alloc] initWithSearchItem:image isInput:NO]; [_app search:@[searchTerm] page:@1 perPage:@20 completion:^(NSArray *results, NSError *error) { - - NSLog(@"results: %@", results); + XCTAssert([results count] > 0); [future setResult:@(YES)]; }]; [future getResult]; @@ -128,25 +247,30 @@ - (void)testPredictCandelabraCustomModel { [future getResult]; } -- (void)testAddConceptsToInput { +- (void)testMergeConceptsToInput { CAIFuture *future = [[CAIFuture alloc] init]; [self testAddInputs]; ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; - [_app addConcepts:@[concept] forInputWithID:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { + concept.score = 0; + [_app mergeConcepts:@[concept] forInputWithID:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { assert(error == nil); bool cat = NO; + bool dogg = NO; for (ClarifaiConcept *concept in input.concepts) { if ([concept.conceptID isEqualToString: @"cat"]) { cat = YES; + } else if ([concept.conceptID isEqualToString: @"dogg"]) { + dogg = YES; } } XCTAssert(cat); + XCTAssert(dogg); [future setResult:@(YES)]; }]; [future getResult]; } -- (void)testUpdateConceptsForInputs { +- (void)testMergeConceptsForInputs { CAIFuture *future = [[CAIFuture alloc] init]; [self testAddInputs]; [_app getInputsOnPage:1 pageSize:30 completion:^(NSArray *inputs, NSError *error) { @@ -156,7 +280,7 @@ - (void)testUpdateConceptsForInputs { ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; input1.concepts = @[concept]; input2.concepts = @[concept]; - [_app updateConceptsForInputs:@[input1,input2] completion:^(NSArray *inputs, NSError *error) { + [_app mergeConceptsForInputs:@[input1,input2] completion:^(NSArray *inputs, NSError *error) { assert(error == nil); bool catInput1 = NO; bool catInput2 = NO; @@ -179,27 +303,32 @@ - (void)testUpdateConceptsForInputs { [future getResult]; } -- (void)testDeleteConceptsFromInput { +- (void)testSetConceptsForInput { CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddConceptsToInput]; + [self testAddInputs]; ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; - [_app deleteConcepts:@[concept] forInputWithID:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { + concept.score = 0; + [_app setConcepts:@[concept] forInputWithID:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { assert(error == nil); bool cat = NO; + bool otherConcepts = NO; // should be no others after overwrite for (ClarifaiConcept *concept in input.concepts) { if ([concept.conceptID isEqualToString: @"cat"]) { cat = YES; + } else { + otherConcepts = YES; } } - XCTAssert(!cat); + XCTAssert(cat); + XCTAssert(!otherConcepts); [future setResult:@(YES)]; }]; [future getResult]; } -- (void)testDeleteConceptsForInputs { +- (void)testSetConceptsForInputs { CAIFuture *future = [[CAIFuture alloc] init]; - [self testUpdateConceptsForInputs]; + [self testAddInputs]; [_app getInputsOnPage:1 pageSize:30 completion:^(NSArray *inputs, NSError *error) { if (inputs.count >= 2) { ClarifaiInput *input1 = inputs[0]; @@ -207,22 +336,28 @@ - (void)testDeleteConceptsForInputs { ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; input1.concepts = @[concept]; input2.concepts = @[concept]; - [_app deleteConceptsForInputs:@[input1,input2] completion:^(NSArray *inputs, NSError *error) { + [_app setConceptsForInputs:@[input1,input2] completion:^(NSArray *inputs, NSError *error) { assert(error == nil); bool catInput1 = NO; bool catInput2 = NO; + bool otherConcepts = NO; // should be no others after overwrite for (ClarifaiConcept *concept in inputs[0].concepts) { if ([concept.conceptID isEqualToString: @"cat"]) { catInput1 = YES; + } else { + otherConcepts = YES; } } for (ClarifaiConcept *concept in inputs[1].concepts) { if ([concept.conceptID isEqualToString: @"cat"]) { catInput2 = YES; + } else { + otherConcepts = YES; } } - XCTAssert(!catInput1); - XCTAssert(!catInput2); + XCTAssert(catInput1); + XCTAssert(catInput2); + XCTAssert(!otherConcepts); [future setResult:@(YES)]; }]; } @@ -230,54 +365,93 @@ - (void)testDeleteConceptsForInputs { [future getResult]; } -- (void)testGetInputs { +- (void)testDeleteConceptsFromInput { CAIFuture *future = [[CAIFuture alloc] init]; - [_app getInputsOnPage:1 pageSize:30 completion:^(NSArray *inputs, NSError *error) { + [self testSetConceptsForInput]; + ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; + [_app deleteConcepts:@[concept] forInputWithID:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { assert(error == nil); + bool cat = NO; + for (ClarifaiConcept *concept in input.concepts) { + if ([concept.conceptID isEqualToString: @"cat"]) { + cat = YES; + } + } + XCTAssert(!cat); [future setResult:@(YES)]; }]; [future getResult]; } -- (void)testGetInputByID { +- (void)testDeleteConceptsForInputs { CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddInputs]; - [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { - assert(error == nil); - XCTAssert([_runningImageID isEqualToString:input.inputID]); - [future setResult:@(YES)]; + [self testSetConceptsForInputs]; + [_app getInputsOnPage:1 pageSize:30 completion:^(NSArray *inputs, NSError *error) { + if (inputs.count >= 2) { + ClarifaiInput *input1 = inputs[0]; + ClarifaiInput *input2 = inputs[1]; + ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"cat"]; + input1.concepts = @[concept]; + input2.concepts = @[concept]; + [_app deleteConceptsForInputs:@[input1,input2] completion:^(NSArray *inputs, NSError *error) { + assert(error == nil); + bool catInput1 = NO; + bool catInput2 = NO; + for (ClarifaiConcept *concept in inputs[0].concepts) { + if ([concept.conceptID isEqualToString: @"cat"]) { + catInput1 = YES; + } + } + for (ClarifaiConcept *concept in inputs[1].concepts) { + if ([concept.conceptID isEqualToString: @"cat"]) { + catInput2 = YES; + } + } + XCTAssert(!catInput1); + XCTAssert(!catInput2); + [future setResult:@(YES)]; + }]; + } }]; - [future getResult]; } -- (void)testGetInputStatus { +- (void)testSearchByImageURL { CAIFuture *future = [[CAIFuture alloc] init]; - [_app getInputsStatus:^(int numProcessed, int numToProcess, int errors, NSError *error) { + ClarifaiImage *image = [[ClarifaiImage alloc] initWithURL:@"http://thedigitalstory.com/2012/07/27/Train%20Tracks%20P7242542%20Retina.jpg"]; + ClarifaiSearchTerm *searchTerm = [[ClarifaiSearchTerm alloc] initWithSearchItem:image isInput:NO]; + [_app search:@[searchTerm] page:@1 perPage:@20 completion:^(NSArray *outputs, NSError *error) { assert(error == nil); [future setResult:@(YES)]; }]; - [future getResult]; } -- (void)testSearchByImageURL { +- (void)testSearchByConceptNameOutputs { CAIFuture *future = [[CAIFuture alloc] init]; - ClarifaiImage *image = [[ClarifaiImage alloc] initWithURL:@"http://thedigitalstory.com/2012/07/27/Train%20Tracks%20P7242542%20Retina.jpg"]; - ClarifaiSearchTerm *searchTerm = [[ClarifaiSearchTerm alloc] initWithSearchItem:image isInput:NO]; + [self testAddInputs]; + ClarifaiConcept *concept1 = [[ClarifaiConcept alloc] initWithConceptName:@"train"]; + ClarifaiSearchTerm *searchTerm = [[ClarifaiSearchTerm alloc] initWithSearchItem:concept1 isInput:NO]; [_app search:@[searchTerm] page:@1 perPage:@20 completion:^(NSArray *outputs, NSError *error) { assert(error == nil); + XCTAssert([outputs count] > 0); + XCTAssert([outputs[0].mediaURL isEqualToString:@"https://samples.clarifai.com/metro-north.jpg"]); + XCTAssert(outputs[0].score.doubleValue > 0.5); [future setResult:@(YES)]; }]; [future getResult]; } -- (void)testSearchByConcept { +- (void)testSearchByConceptIDInputs { CAIFuture *future = [[CAIFuture alloc] init]; - ClarifaiConcept *concept1 = [[ClarifaiConcept alloc] initWithConceptName:@"ai_2nvg6rJ6"]; + [self testAddInputs]; + ClarifaiConcept *concept1 = [[ClarifaiConcept alloc] initWithConceptID:@"ggod"]; ClarifaiSearchTerm *searchTerm = [[ClarifaiSearchTerm alloc] initWithSearchItem:concept1 isInput:YES]; - [_app search:@[searchTerm] page:@1 perPage:@20 completion:^(NSArray *outputs, NSError *error) { + [_app search:@[searchTerm] page:@1 perPage:@20 completion:^(NSArray *inputs, NSError *error) { assert(error == nil); + XCTAssert([inputs count] > 0); + XCTAssert([inputs[0].mediaURL isEqualToString:@"http://www.pumapedia.com/wp-content/uploads/2012/10/puma-roca.jpg"]); + XCTAssert(inputs[0].score.doubleValue > 0.5); [future setResult:@(YES)]; }]; [future getResult]; @@ -320,73 +494,6 @@ - (void)testSearchInputsAndOutputsByConcept { [future getResult]; } -- (void)testDeleteInputByID { - CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddInputs]; - [_app deleteInput:_runningImageID completion:^(NSError *error) { - assert(error == nil); - [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { - //should be error if input was properly deleted. - XCTAssert(error != nil); - [future setResult:@(YES)]; - }]; - }]; - - [future getResult]; -} - -- (void)testDeleteInputByIDListInputs { - CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddInputs]; - ClarifaiInput *input = [[ClarifaiInput alloc] init]; - input.inputID = _runningImageID; - [_app deleteInputsByIDList:@[input] completion:^(NSError *error) { - assert(error == nil); - [NSThread sleepForTimeInterval:2.0]; //Delete batch is async - [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { - //should be error if input was properly deleted. - XCTAssert(error != nil); - [future setResult:@(YES)]; - }]; - }]; - - [future getResult]; -} - -- (void)testDeleteInputByIDListStrings { - CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddInputs]; - [_app deleteInputsByIDList:@[_runningImageID] completion:^(NSError *error) { - assert(error == nil); - [NSThread sleepForTimeInterval:2.0]; //Delete batch is async - [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { - //should be error if input was properly deleted. - XCTAssert(error != nil); - [future setResult:@(YES)]; - }]; - }]; - - [future getResult]; -} - -- (void)testDeleteAllInputs { - CAIFuture *future = [[CAIFuture alloc] init]; - [self testAddInputs]; - ClarifaiInput *input = [[ClarifaiInput alloc] init]; - input.inputID = _runningImageID; - [_app deleteAllInputs:^(NSError *error) { - assert(error == nil); - [NSThread sleepForTimeInterval:2.0]; //Delete all is async - [_app getInput:_runningImageID completion:^(ClarifaiInput *input, NSError *error) { - //should be error if input was properly deleted. - XCTAssert(error != nil); - [future setResult:@(YES)]; - }]; - }]; - - [future getResult]; -} - - (void)testGetConcepts { CAIFuture *future = [[CAIFuture alloc] init]; [_app getConceptsOnPage:1 pageSize:30 completion:^(NSArray *concepts, NSError *error) { @@ -429,36 +536,79 @@ - (void)testGetConceptByID { [future getResult]; } -- (void)testAddConceptsToModel { +- (void)testMergeConceptsToModel { CAIFuture *future = [[CAIFuture alloc] init]; + [self testCreateModel]; ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"burf"]; - ClarifaiImage *image = [[ClarifaiImage alloc] initWithURL:@"https://samples.clarifai.com/metro-north.jpg" andConcepts:@[@"burf"]]; - NSString *modelID = @"b06ced930c784b2fa59b8e1d90551201"; - __weak ClarifaiApp *app = _app; - [app addInputs:@[image] completion:^(NSArray *inputs, NSError *error) { + NSString *modelID = @"burfgerz"; + [_app mergeConcepts:@[concept] forModelWithID:modelID completion:^(ClarifaiModel *model, NSError *error) { assert(error == nil); - [app addConcepts:@[concept] toModelWithID:modelID completion:^(ClarifaiModel *model, NSError *error) { + [_app getModelByID:modelID completion:^(ClarifaiModel *model, NSError *error) { assert(error == nil); - [app getModelByID:modelID completion:^(ClarifaiModel *model, NSError *error) { - assert(error == nil); - [future setResult:@(YES)]; - }]; + bool burf = NO; + bool dogg = NO; + for (ClarifaiConcept *concept in model.concepts) { + if ([concept.conceptID isEqualToString:@"burf"]) { + burf = YES; + } else if ([concept.conceptID isEqualToString:@"dogg"]) { + dogg = YES; + } + } + XCTAssert(burf); + XCTAssert(dogg); + [future setResult:@(YES)]; }]; }]; [future getResult]; - } -- (void)testAddAndRemoveConceptFromModel { +- (void)testSetConceptsToModel { CAIFuture *future = [[CAIFuture alloc] init]; + [self testCreateModel]; ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"burf"]; - __weak ClarifaiApp *app = _app; - - [_app addConcepts:@[concept] toModelWithID:@"b06ced930c784b2fa59b8e1d90551201" completion:^(ClarifaiModel *model, NSError *error) { + NSString *modelID = @"burfgerz"; + [_app setConcepts:@[concept] forModelWithID:modelID completion:^(ClarifaiModel *model, NSError *error) { assert(error == nil); - [app deleteConcepts:@[concept] fromModelWithID:@"b06ced930c784b2fa59b8e1d90551201" completion:^(ClarifaiModel *model, NSError *error) { + [_app getModelByID:modelID completion:^(ClarifaiModel *model, NSError *error) { assert(error == nil); - [future setResult:@YES]; + bool burf = NO; + bool otherConcepts = NO; // should have no others after overwrite. + for (ClarifaiConcept *concept in model.concepts) { + if ([concept.conceptID isEqualToString:@"burf"]) { + burf = YES; + } else { + otherConcepts = YES; + } + } + XCTAssert(burf); + XCTAssert(!otherConcepts); + [future setResult:@(YES)]; + }]; + }]; + [future getResult]; +} + +- (void)testDeleteConceptsToModel { + CAIFuture *future = [[CAIFuture alloc] init]; + [self testCreateModel]; + ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"dogg"]; + NSString *modelID = @"burfgerz"; + [_app deleteConcepts:@[concept] fromModelWithID:modelID completion:^(ClarifaiModel *model, NSError *error) { + assert(error == nil); + [_app getModelByID:modelID completion:^(ClarifaiModel *model, NSError *error) { + assert(error == nil); + bool dogg = NO; + bool otherConcepts = NO; // should have no others after delete. + for (ClarifaiConcept *concept in model.concepts) { + if ([concept.conceptID isEqualToString:@"dogg"]) { + dogg = YES; + } else { + otherConcepts = YES; + } + } + XCTAssert(!dogg); + XCTAssert(!otherConcepts); + [future setResult:@(YES)]; }]; }]; [future getResult]; @@ -467,16 +617,14 @@ - (void)testAddAndRemoveConceptFromModel { - (void)testCreateModel { CAIFuture *future = [[CAIFuture alloc] init]; NSString *modelName = @"burfgerz"; - ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"bunz"]; -// [_app addConcepts:@[concept] completion:^(NSArray *concepts, NSError *error) { //UNCOMMENT ON FIRST RUN TO CREATE BUNZ CONCEPT, after that it'll be fine. -// assert(error == nil); + [_app deleteModel:modelName completion:^(NSError *error) { + ClarifaiConcept *concept = [[ClarifaiConcept alloc] initWithConceptName:@"dogg"]; [_app createModel:@[concept] name:modelName conceptsMutuallyExclusive:NO closedEnvironment:NO completion:^(ClarifaiModel *model, NSError *error) { XCTAssert(error == nil); XCTAssert([modelName isEqualToString:model.name]); [future setResult:@(YES)]; }]; - // }]; - + }]; [future getResult]; } @@ -533,13 +681,11 @@ - (void)testDeleteModelByID { - (void)testDeleteAllModels { CAIFuture *future = [[CAIFuture alloc] init]; - [self testGetModelsOnPage]; [_app deleteAllModels:^(NSError *error) { assert(error == nil); [NSThread sleepForTimeInterval:2.0]; //Delete batch is async - [_app getModelByID:_runningModelID completion:^(ClarifaiModel *model, NSError *error) { - //should be error if model was properly deleted. - XCTAssert(error != nil); + [_app getModels:1 resultsPerPage:20 completion:^(NSArray *models, NSError *error) { + XCTAssert([models count] <= 8); // general models, etc remain. [future setResult:@(YES)]; }]; }]; @@ -615,7 +761,7 @@ - (void)testTrainModel { assert(error == nil); // add concept to model - [_app addConcepts:@[concept] toModelWithID:modelToTrain.modelID completion:^(ClarifaiModel *model, NSError *error) { + [_app mergeConcepts:@[concept] forModelWithID:modelToTrain.modelID completion:^(ClarifaiModel *model, NSError *error) { assert(error == nil); [NSThread sleepForTimeInterval:1.0]; // train model diff --git a/README.md b/README.md index 672015f..6c388f1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A client for iOS apps using the Clarifai V2 API. * Sign up for a free developer account at: https://developer.clarifai.com/signup/ * Read the developer guide at: https://developer.clarifai.com/guide-v2/ -* Read the full Objective-C docs at: https://sdk.clarifai.com/iOS/docs-{{version-number}}/masterTOC.html +* Read the full Objective-C docs at: http://cocoadocs.org/docsets/Clarifai/ ## Installation ### CocoaPods @@ -40,9 +40,14 @@ have an account or application, you'll need to sign up first). ``` 6. That's it! Explore the [API docs and guide](https://developer.clarifai.com). +NOTE- to use Clarifai in Swift, make sure to add use_frameworks! to your podfile and import into any swift file using: + ``` + import Clarifai + ``` + ## Documentation -The most recent docs can currently be found [here](https://sdk.clarifai.com/iOS/docs-2.0.0/masterTOC.html). +The most recent docs can be found [here](http://cocoadocs.org/docsets/Clarifai/) on Cocoadocs. ## Example Project