diff --git a/examples/AddressSimilarity.cs b/examples/AddressSimilarity.cs new file mode 100644 index 0000000..6c2683e --- /dev/null +++ b/examples/AddressSimilarity.cs @@ -0,0 +1,60 @@ +using Rosette.Api; +using Rosette.Api.Models; + +namespace examples +{ + class AddressSimilarity + { + /// + /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. + /// An optional alternate URL may be provided, i.e. for an on-premise solution. + /// + /// Required api key (obtained from Basis Technology) + /// Optional alternate URL + private void RunEndpoint(string apiKey, string? altUrl = null) + { + try + { + ApiClient api = new ApiClient(apiKey); + if (!string.IsNullOrEmpty(altUrl)) + { + api.UseAlternateURL(altUrl); + } + + var add1 = new UnfieldedAddressRecord { Address = "160 Pennsylvana Avenue, Washington, D.C., 20500" }; + var add2 = new FieldedAddressRecord(houseNumber: "1600", road: "Pennsylvania Ave N.W.", city: "Washington", state: "DC", postcode: "20500"); + + + Rosette.Api.Endpoints.AddressSimilarity endpoint = new Rosette.Api.Endpoints.AddressSimilarity(add1, add2); + + Response response = endpoint.Call(api); + + //The results of the API call will come back in the form of a Dictionary + foreach (KeyValuePair h in response.Headers) + { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } + Console.WriteLine(response.ContentAsJson(pretty: true)); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + /// + /// Main is a simple entrypoint for command line calling of the endpoint examples + /// + /// Command line args, expects API Key, (optional) alt URL + static void Main(string[] args) + { + if (args.Length != 0) + { + new AddressSimilarity().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + } + else + { + Console.WriteLine("An API Key is required"); + } + } + } +} diff --git a/examples/Categories.cs b/examples/Categories.cs index 4eaa3f7..560cad3 100644 --- a/examples/Categories.cs +++ b/examples/Categories.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Categories @@ -11,16 +12,20 @@ class Categories /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string categories_text_data = @"Sony Pictures is planning to shoot a good portion of the new ""Ghostbusters"" in Boston as well."; - CategoriesEndpoint endpoint = new CategoriesEndpoint(categories_text_data); + Rosette.Api.Endpoints.Categories endpoint = new Rosette.Api.Endpoints.Categories(categories_text_data); - RosetteResponse response = endpoint.Call(api); + Response response = endpoint.Call(api); //The results of the API call will come back in the form of a Dictionary + foreach (KeyValuePair h in response.Headers) + { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } Console.WriteLine(response.ContentAsJson(pretty: true)); } catch (Exception e) { diff --git a/examples/ConcurrencyTest.cs b/examples/ConcurrencyTest.cs index 37eedca..c3520aa 100644 --- a/examples/ConcurrencyTest.cs +++ b/examples/ConcurrencyTest.cs @@ -1,4 +1,4 @@ -using rosette_api; +using Rosette.Api; namespace examples { public class ConcurrencyTest { @@ -15,7 +15,7 @@ public class ConcurrencyTest { /// Optional alternate URL private static async Task TestConcurrency(string apiKey, string altUrl) { var tasks = new List(); - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } @@ -29,9 +29,9 @@ private static async Task TestConcurrency(string apiKey, string altUrl) { Console.WriteLine("Test complete"); } - private static Task runLookup(int taskId, RosetteAPI api) { + private static Task runLookup(int taskId, ApiClient api) { string entities_text_data = @"The Securities and Exchange Commission today announced the leadership of the agency’s trial unit. Bridget Fitzpatrick has been named Chief Litigation Counsel of the SEC and David Gottesman will continue to serve as the agency’s Deputy Chief Litigation Counsel. Since December 2016, Ms. Fitzpatrick and Mr. Gottesman have served as Co-Acting Chief Litigation Counsel. In that role, they were jointly responsible for supervising the trial unit at the agency’s Washington D.C. headquarters as well as coordinating with litigators in the SEC’s 11 regional offices around the country."; - EntitiesEndpoint endpoint = new EntitiesEndpoint(entities_text_data); + Rosette.Api.Endpoints.Entities endpoint = new Rosette.Api.Endpoints.Entities(entities_text_data); foreach (int call in Enumerable.Range(0, calls)) { Console.WriteLine("Task ID: {0} call {1}", taskId, call); try { diff --git a/examples/Entities.cs b/examples/Entities.cs index 4b2d85d..7237266 100755 --- a/examples/Entities.cs +++ b/examples/Entities.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Entities @@ -11,14 +12,14 @@ class Entities /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string entities_text_data = @"The Securities and Exchange Commission today announced the leadership of the agency’s trial unit. Bridget Fitzpatrick has been named Chief Litigation Counsel of the SEC and David Gottesman will continue to serve as the agency’s Deputy Chief Litigation Counsel. Since December 2016, Ms. Fitzpatrick and Mr. Gottesman have served as Co-Acting Chief Litigation Counsel. In that role, they were jointly responsible for supervising the trial unit at the agency’s Washington D.C. headquarters as well as coordinating with litigators in the SEC’s 11 regional offices around the country."; - EntitiesEndpoint endpoint = new EntitiesEndpoint(entities_text_data).SetGenre("social-media"); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Entities endpoint = new Rosette.Api.Endpoints.Entities(entities_text_data).SetGenre("social-media"); + Response response = endpoint.Call(api); // Print out the response headers foreach (KeyValuePair h in response.Headers) { diff --git a/examples/Events.cs b/examples/Events.cs new file mode 100644 index 0000000..1698578 --- /dev/null +++ b/examples/Events.cs @@ -0,0 +1,52 @@ +using Rosette.Api; +using Rosette.Api.Models; + +namespace examples { + class Events + { + /// + /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. + /// An optional alternate URL may be provided, i.e. for an on-premise solution. + /// + /// Required api key (obtained from Basis Technology) + /// Optional alternate URL + private void RunEndpoint(string apiKey, string? altUrl = null) { + try { + ApiClient api = new ApiClient(apiKey); + if (!string.IsNullOrEmpty(altUrl)) { + api.UseAlternateURL(altUrl); + } + string events_text_data = @"I am looking for flights to Super Bowl 2022 in Inglewood, LA."; + + Rosette.Api.Endpoints.Events endpoint = new Rosette.Api.Endpoints.Events(events_text_data); + Response response = endpoint.Call(api); + + // Print out the response headers + foreach (KeyValuePair h in response.Headers) { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } + // Print out the content in JSON format. The Content property returns an IDictionary. + Console.WriteLine(response.ContentAsJson(pretty: true)); + + // Retrieve the Events with full ADM + response = endpoint.SetUrlParameter("output", "rosette").Call(api); + Console.WriteLine(response.ContentAsJson(pretty: true)); + } + catch (Exception e) { + Console.WriteLine("Exception: " + e.Message); + } + } + /// + /// Main is a simple entrypoint for command line calling of the endpoint examples + /// + /// Command line args, expects API Key, (optional) alt URL + static void Main(string[] args) { + if (args.Length != 0) { + new Events().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + } + else { + Console.WriteLine("An API Key is required"); + } + } + } +} \ No newline at end of file diff --git a/examples/Info.cs b/examples/Info.cs index 97dc514..3f80fd0 100644 --- a/examples/Info.cs +++ b/examples/Info.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Info @@ -11,12 +12,12 @@ class Info /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } - InfoEndpoint endpoint = new InfoEndpoint(); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Info endpoint = new Rosette.Api.Endpoints.Info(); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); diff --git a/examples/Language.cs b/examples/Language.cs index 000c16a..dc6a0bf 100644 --- a/examples/Language.cs +++ b/examples/Language.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Language @@ -11,7 +12,7 @@ class Language /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } @@ -20,9 +21,9 @@ private void RunEndpoint(string apiKey, string? altUrl =null) { string language_data = @"Por favor Señorita, says the man."; - LanguageEndpoint endpoint = new LanguageEndpoint(language_data); + Rosette.Api.Endpoints.Language endpoint = new Rosette.Api.Endpoints.Language(language_data); //The results of the API call will come back in the form of a Dictionary - RosetteResponse response = endpoint.Call(api); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/LanguageMultilingual.cs b/examples/LanguageMultilingual.cs index 1a0c378..aa0500c 100644 --- a/examples/LanguageMultilingual.cs +++ b/examples/LanguageMultilingual.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class LanguageMultilingual @@ -11,16 +12,16 @@ class LanguageMultilingual /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string language_multilingual_data = @"On Thursday, as protesters gathered in Washington D.C., the United States Federal Communications Commission under Chairman Ajit Pai voted 3-2 to overturn a 2015 decision, commonly called Net Neutrality, that forbade Internet service providers (ISPs) such as Verizon, Comcast, and AT&T from blocking individual websites or charging websites or customers more for faster load times. Quatre femmes ont été nommées au Conseil de rédaction de la loi du Qatar. Jeudi, le décret royal du Qatar a annoncé que 28 nouveaux membres ont été nommés pour le Conseil de la Choura du pays. ذكرت مصادر أمنية يونانية، أن 9 موقوفين من منظمة ""د هـ ك ب ج"" الذين كانت قد أوقفتهم الشرطة اليونانية في وقت سابق كانوا يخططون لاغتيال الرئيس التركي رجب طيب أردوغان."; - LanguageEndpoint endpoint = new LanguageEndpoint(language_multilingual_data).SetOption("multilingual", true); + Rosette.Api.Endpoints.Language endpoint = new Rosette.Api.Endpoints.Language(language_multilingual_data).SetOption("multilingual", true); //The results of the API call will come back in the form of a Dictionary - RosetteResponse response = endpoint.Call(api); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/MorphologyComplete.cs b/examples/MorphologyComplete.cs index 03dce4e..ff3b870 100644 --- a/examples/MorphologyComplete.cs +++ b/examples/MorphologyComplete.cs @@ -1,4 +1,6 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; namespace examples { class MorphologyComplete @@ -11,15 +13,15 @@ class MorphologyComplete /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string morphology_complete_data = @"The quick brown fox jumped over the lazy dog. 👍🏾 Yes he did. B)"; //The results of the API call will come back in the form of a Dictionary - MorphologyEndpoint endpoint = new MorphologyEndpoint(morphology_complete_data, MorphologyFeature.complete); + Morphology endpoint = new Morphology(morphology_complete_data, MorphologyFeature.complete); - RosetteResponse response = endpoint.Call(api); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/MorphologyCompoundComponents.cs b/examples/MorphologyCompoundComponents.cs index b553e8f..8693799 100644 --- a/examples/MorphologyCompoundComponents.cs +++ b/examples/MorphologyCompoundComponents.cs @@ -1,6 +1,8 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; -namespace rosette_apiExamples { +namespace Rosette.ApiExamples { class MorphologyCompoundComponents { /// @@ -11,14 +13,14 @@ class MorphologyCompoundComponents /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string morphology_compound_components_data = @"Rechtsschutzversicherungsgesellschaften"; //The results of the API call will come back in the form of a Dictionary - MorphologyEndpoint endpoint = new MorphologyEndpoint(morphology_compound_components_data, MorphologyFeature.compoundComponents); - RosetteResponse response = endpoint.Call(api); + Morphology endpoint = new Morphology(morphology_compound_components_data, MorphologyFeature.compoundComponents); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/MorphologyHanReadings.cs b/examples/MorphologyHanReadings.cs index 575b56a..d4da2c3 100644 --- a/examples/MorphologyHanReadings.cs +++ b/examples/MorphologyHanReadings.cs @@ -1,4 +1,6 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; namespace examples { class MorphologyHanReadings @@ -12,13 +14,13 @@ class MorphologyHanReadings private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string morphology_han_readings_data = @"北京大学生物系主任办公室内部会议"; - MorphologyEndpoint endpoint = new MorphologyEndpoint(morphology_han_readings_data, MorphologyFeature.hanReadings); - RosetteResponse response = endpoint.Call(api); + Morphology endpoint = new Morphology(morphology_han_readings_data, MorphologyFeature.hanReadings); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/MorphologyLemmas.cs b/examples/MorphologyLemmas.cs index 7dd53af..fb1c55f 100644 --- a/examples/MorphologyLemmas.cs +++ b/examples/MorphologyLemmas.cs @@ -1,4 +1,6 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; namespace examples { class MorphologyLemmas @@ -11,14 +13,15 @@ class MorphologyLemmas /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string morphology_lemmas_data = @"The fact is that the geese just went back to get a rest and I'm not banking on their return soon"; //The results of the API call will come back in the form of a Dictionary - MorphologyEndpoint endpoint = new MorphologyEndpoint(morphology_lemmas_data, MorphologyFeature.lemmas); - RosetteResponse response = endpoint.Call(api); + Morphology endpoint = new Morphology(morphology_lemmas_data, MorphologyFeature.lemmas); + Response response = endpoint.Call(api); + foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/MorphologyPartsOfSpeech.cs b/examples/MorphologyPartsOfSpeech.cs index d0c3f30..107b22a 100644 --- a/examples/MorphologyPartsOfSpeech.cs +++ b/examples/MorphologyPartsOfSpeech.cs @@ -1,4 +1,6 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; namespace examples { class MorphologyPartsOfSpeech @@ -11,13 +13,13 @@ class MorphologyPartsOfSpeech /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string morphology_parts_of_speech_data = @"The fact is that the geese just went back to get a rest and I'm not banking on their return soon"; - MorphologyEndpoint endpoint = new MorphologyEndpoint(morphology_parts_of_speech_data, MorphologyFeature.partsOfSpeech); - RosetteResponse response = endpoint.Call(api); + Morphology endpoint = new Morphology(morphology_parts_of_speech_data, MorphologyFeature.partsOfSpeech); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/NameDeduplication.cs b/examples/NameDeduplication.cs index 56ede2b..c950c0e 100644 --- a/examples/NameDeduplication.cs +++ b/examples/NameDeduplication.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class NameDeduplication @@ -11,17 +12,17 @@ class NameDeduplication /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string name_dedupe_data = @"Alice Terry,Alice Thierry,Betty Grable,Betty Gable,Norma Shearer,Norm Shearer,Brigitte Helm,Bridget Helem,Judy Holliday,Julie Halliday"; List dedupe_names = name_dedupe_data.Split(',').ToList(); - List names = dedupe_names.Select(name => new RosetteName(name)).ToList(); + List names = dedupe_names.Select(name => new Name(name)).ToList(); - NameDeduplicationEndpoint endpoint = new NameDeduplicationEndpoint(names).SetThreshold(0.75f); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.NameDeduplication endpoint = new Rosette.Api.Endpoints.NameDeduplication(names).SetThreshold(0.75f); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/NameMatch.cs b/examples/NameSimilarity.cs similarity index 69% rename from examples/NameMatch.cs rename to examples/NameSimilarity.cs index 0dc8570..38f6eb1 100644 --- a/examples/NameMatch.cs +++ b/examples/NameSimilarity.cs @@ -1,7 +1,9 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Endpoints; +using Rosette.Api.Models; namespace examples { - class NameMatch + class NameSimilarity { /// /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. @@ -11,14 +13,16 @@ class NameMatch /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } - string matched_name_data1 = @"Michael Jackson"; - string matched_name_data2 = @"迈克尔·杰克逊"; - NameSimilarityEndpoint endpoint = new NameSimilarityEndpoint(new RosetteName(matched_name_data1), new RosetteName(matched_name_data2)); - RosetteResponse response = endpoint.Call(api); + + var name1 = new Name("Michael Jackson").SetLanguage("eng").SetEntityType(EntityType.Person); + var name2 = new Name("迈克尔·杰克逊").SetEntityType(EntityType.Person); + + Rosette.Api.Endpoints.NameSimilarity endpoint = new Rosette.Api.Endpoints.NameSimilarity(name1, name2); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } @@ -34,7 +38,7 @@ private void RunEndpoint(string apiKey, string? altUrl =null) { /// Command line args, expects API Key, (optional) alt URL static void Main(string[] args) { if (args.Length != 0) { - new NameMatch().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + new NameSimilarity().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); } else { Console.WriteLine("An API Key is required"); diff --git a/examples/NameTranslation.cs b/examples/NameTranslation.cs index 1f4cef7..76d7b60 100644 --- a/examples/NameTranslation.cs +++ b/examples/NameTranslation.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class NameTranslation @@ -11,13 +12,13 @@ class NameTranslation /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string translated_name_data = @"معمر محمد أبو منيار القذاف"; - NameTranslationEndpoint endpoint = new NameTranslationEndpoint(translated_name_data, "eng"); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.NameTranslation endpoint = new Rosette.Api.Endpoints.NameTranslation(translated_name_data, "eng"); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/Ping.cs b/examples/Ping.cs index b57e2ca..87c528c 100644 --- a/examples/Ping.cs +++ b/examples/Ping.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Ping @@ -11,11 +12,11 @@ class Ping /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } - RosetteResponse response = new PingEndpoint().Call(api); + Response response = new Rosette.Api.Endpoints.Ping().Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/README.md b/examples/README.md index 3e1b78d..530f591 100644 --- a/examples/README.md +++ b/examples/README.md @@ -21,18 +21,16 @@ Here is one way to run the examples. - Set up the environment. ``` - apt update - apt install -y wget - - wget https://packages.microsoft.com/config/debian/13/packages-microsoft-prod.deb -O packages-microsoft-prod.deb - dpkg -i packages-microsoft-prod.deb - - apt update - apt install -y dotnet-sdk-10.0 - - dotnet --version - dotnet --list-sdks - dotnet --list-runtimes + apt-get update -y + apt-get install -y wget + apt-get install -y curl + apt-get install -y libicu76 + apt-get install -y libgssapi-krb5-2 + + wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh + chmod +x ./dotnet-install.sh + ./dotnet-install.sh --version latest + export PATH="$PATH:/root/.dotnet" ``` diff --git a/examples/RecordSimilarity.cs b/examples/RecordSimilarity.cs new file mode 100644 index 0000000..a17a3bd --- /dev/null +++ b/examples/RecordSimilarity.cs @@ -0,0 +1,125 @@ +using Rosette.Api; +using Rosette.Api.Models; + +namespace examples +{ + class RecordSimilarity + { + /// + /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. + /// An optional alternate URL may be provided, i.e. for an on-premise solution. + /// + /// Required api key (obtained from Basis Technology) + /// Optional alternate URL + private void RunEndpoint(string apiKey, string? altUrl = null) + { + try + { + ApiClient api = new ApiClient(apiKey); + if (!string.IsNullOrEmpty(altUrl)) + { + api.UseAlternateURL(altUrl); + } + + // record field names + string primaryNameField = "primaryName"; + string dobField = "dob"; + string dob2Field = "dob2"; + string addrField = "addr"; + string jobField = "jobTitle"; + string ageField = "age"; + string retiredField = "isRetired"; + string dobHyphen = "1993-04-16"; + + // Creating the request object + Dictionary fields = new Dictionary + { + { primaryNameField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniName, Weight = 0.5 } }, + { dobField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniDate, Weight = 0.2 } }, + { dob2Field, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniDate, Weight = 0.1 } }, + { addrField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniAddress, Weight = 0.5 } }, + { jobField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniString, Weight = 0.2 } }, + { ageField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniNumber, Weight = 0.4 } }, + { retiredField, new RecordSimilarityFieldInfo { Type = RecordFieldType.RniBoolean, Weight = 0.05 } } + }; + + RecordSimilarityProperties properties = new RecordSimilarityProperties { Threshold = 0.7, IncludeExplainInfo = true }; + + RecordSimilarityRecords records = new RecordSimilarityRecords + { + Left = new List> + { + new Dictionary + { + { primaryNameField, new FieldedNameRecord { Text = "Ethan R", Language = "eng", LanguageOfOrigin = "eng", Script = "Latn", EntityType = "PERSON"} }, + { dobField, new UnfieldedDateRecord { Date = dobHyphen} }, + { dob2Field, new FieldedDateRecord { Date = "04161993", Format = "MMddyyyy"} }, + { addrField, new UnfieldedAddressRecord { Address = "123 Roadlane Ave"} }, + { jobField, new StringRecord { Text = "software engineer"} } + }, + new Dictionary + { + { primaryNameField, new FieldedNameRecord { Text = "Evan R"} }, + { dobField, new FieldedDateRecord { Date = dobHyphen} }, + { ageField, new NumberRecord { Number = 47.344 } }, + { retiredField, new BooleanRecord { Boolean = false } } + } + }, + Right = new List> + { + new Dictionary + { + { primaryNameField, new FieldedNameRecord { Text = "Seth R", Language = "eng"} }, + { dobField, new FieldedDateRecord { Date = dobHyphen} }, + { jobField, new StringRecord { Text = "manager"} }, + { retiredField, new BooleanRecord { Boolean = true } } + }, + new Dictionary + { + { primaryNameField, new UnfieldedNameRecord { Text = "Ivan R"} }, + { dobField, new FieldedDateRecord { Date = dobHyphen} }, + { dob2Field, new FieldedDateRecord { Date = "1993/04/16"} }, + { addrField, new FieldedAddressRecord { HouseNumber = "123", Road = "Roadlane Ave"} }, + { ageField, new NumberRecord { Number = 72 } }, + { retiredField, new BooleanRecord { Boolean = true } } + } + } + }; + + Rosette.Api.Endpoints.RecordSimilarity endpoint = new Rosette.Api.Endpoints.RecordSimilarity(fields, properties, records); + Response response = endpoint.Call(api); + + // Print out the response headers + foreach (KeyValuePair h in response.Headers) + { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } + // Print out the content in JSON format. The Content property returns an IDictionary. + Console.WriteLine(response.ContentAsJson(pretty: true)); + + // Retrieve the Events with full ADM + response = endpoint.SetUrlParameter("output", "rosette").Call(api); + Console.WriteLine(response.ContentAsJson(pretty: true)); + } + catch (Exception e) + { + Console.WriteLine("Exception: " + e.Message); + } + } + /// + /// Main is a simple entrypoint for command line calling of the endpoint examples + /// + /// Command line args, expects API Key, (optional) alt URL + static void Main(string[] args) + { + if (args.Length != 0) + { + new RecordSimilarity().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + } + else + { + Console.WriteLine("An API Key is required"); + } + } + } +} \ No newline at end of file diff --git a/examples/Relationships.cs b/examples/Relationships.cs index 8ec12de..9717b43 100644 --- a/examples/Relationships.cs +++ b/examples/Relationships.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Relationships @@ -11,13 +12,13 @@ class Relationships /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string relationships_text_data = @"FLIR Systems is headquartered in Oregon and produces thermal imaging, night vision, and infrared cameras and sensor systems. According to the SEC’s order instituting a settled administrative proceeding, FLIR entered into a multi-million dollar contract to provide thermal binoculars to the Saudi government in November 2008. Timms and Ramahi were the primary sales employees responsible for the contract, and also were involved in negotiations to sell FLIR’s security cameras to the same government officials. At the time, Timms was the head of FLIR’s Middle East office in Dubai."; - RelationshipsEndpoint endpoint = new RelationshipsEndpoint(relationships_text_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Relationships endpoint = new Rosette.Api.Endpoints.Relationships(relationships_text_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/SemanticsVector.cs b/examples/SemanticsVector.cs new file mode 100644 index 0000000..e331885 --- /dev/null +++ b/examples/SemanticsVector.cs @@ -0,0 +1,53 @@ +using Rosette.Api; +using Rosette.Api.Models; + +namespace examples +{ + class SemanticsVector + { + /// + /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. + /// An optional alternate URL may be provided, i.e. for an on-premise solution. + /// + /// Required api key (obtained from Basis Technology) + /// Optional alternate URL + private void RunEndpoint(string apiKey, string? altUrl = null) + { + try + { + ApiClient api = new ApiClient(apiKey); + if (!string.IsNullOrEmpty(altUrl)) + { + api.UseAlternateURL(altUrl); + } + string semantic_vectors_data = @"Cambridge, Massachusetts"; + Rosette.Api.Endpoints.SemanticsVector endpoint = new Rosette.Api.Endpoints.SemanticsVector(semantic_vectors_data); + Response response = endpoint.Call(api); + foreach (KeyValuePair h in response.Headers) + { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } + Console.WriteLine(response.ContentAsJson(pretty: true)); + } + catch (Exception e) + { + Console.WriteLine("Exception: " + e.Message); + } + } + /// + /// Main is a simple entrypoint for command line calling of the endpoint examples + /// + /// Command line args, expects API Key, (optional) alt URL + static void Main(string[] args) + { + if (args.Length != 0) + { + new SemanticsVector().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + } + else + { + Console.WriteLine("An API Key is required"); + } + } + } +} diff --git a/examples/Sentences.cs b/examples/Sentences.cs index 17d3dce..9fa41d0 100644 --- a/examples/Sentences.cs +++ b/examples/Sentences.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Sentences @@ -11,13 +12,13 @@ class Sentences /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string sentences_data = @"This land is your land. This land is my land, from California to the New York island; from the red wood forest to the Gulf Stream waters. This land was made for you and Me. As I was walking that ribbon of highway, I saw above me that endless skyway: I saw below me that golden valley: This land was made for you and me."; - SentencesEndpoint endpoint = new SentencesEndpoint(sentences_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Sentences endpoint = new Rosette.Api.Endpoints.Sentences(sentences_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/Sentiment.cs b/examples/Sentiment.cs index 01f80cc..67a4293 100644 --- a/examples/Sentiment.cs +++ b/examples/Sentiment.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Sentiment @@ -11,7 +12,7 @@ class Sentiment /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } @@ -24,10 +25,10 @@ private void RunEndpoint(string apiKey, string? altUrl =null) { sw.Close(); using (FileStream fs = File.OpenRead(newFile)) { - SentimentEndpoint endpoint = new SentimentEndpoint(fs) + Rosette.Api.Endpoints.Sentiment endpoint = new Rosette.Api.Endpoints.Sentiment(fs) .SetFileContentType(@"application/octet-stream") .SetLanguage("eng"); - RosetteResponse response = endpoint.Call(api); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/SimilarTerms.cs b/examples/SimilarTerms.cs new file mode 100644 index 0000000..3a3ae6d --- /dev/null +++ b/examples/SimilarTerms.cs @@ -0,0 +1,64 @@ +using Rosette.Api; +using Rosette.Api.Models; + +namespace examples +{ + class SimilarTerms + { + /// + /// RunEndpoint runs the example. By default the endpoint will be run against the Rosette Cloud Service. + /// An optional alternate URL may be provided, i.e. for an on-premise solution. + /// + /// Required api key (obtained from Basis Technology) + /// Optional alternate URL + private void RunEndpoint(string apiKey, string? altUrl = null) + { + try + { + ApiClient api = new ApiClient(apiKey); + if (!string.IsNullOrEmpty(altUrl)) + { + api.UseAlternateURL(altUrl); + } + + var similar_terms_data = "spy"; + var resultLanguages = new List() { "spa", "deu", "jpn" }; + + Rosette.Api.Endpoints.SimilarTerms endpoint = new Rosette.Api.Endpoints.SimilarTerms(similar_terms_data); + endpoint.SetOption("resultLanguages", resultLanguages); + Response response = endpoint.Call(api); + + // Print out the response headers + foreach (KeyValuePair h in response.Headers) + { + Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); + } + // Print out the content in JSON format. The Content property returns an IDictionary. + Console.WriteLine(response.ContentAsJson(pretty: true)); + + // Retrieve the Events with full ADM + response = endpoint.SetUrlParameter("output", "rosette").Call(api); + Console.WriteLine(response.ContentAsJson(pretty: true)); + } + catch (Exception e) + { + Console.WriteLine("Exception: " + e.Message); + } + } + /// + /// Main is a simple entrypoint for command line calling of the endpoint examples + /// + /// Command line args, expects API Key, (optional) alt URL + static void Main(string[] args) + { + if (args.Length != 0) + { + new SimilarTerms().RunEndpoint(args[0], args.Length > 1 ? args[1] : null); + } + else + { + Console.WriteLine("An API Key is required"); + } + } + } +} \ No newline at end of file diff --git a/examples/SyntaxDependencies.cs b/examples/SyntaxDependencies.cs index 0c01c17..2c1c024 100644 --- a/examples/SyntaxDependencies.cs +++ b/examples/SyntaxDependencies.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class SyntaxDependencies @@ -11,13 +12,13 @@ class SyntaxDependencies /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string syntax_dependencies_data = "Yoshinori Ohsumi, a Japanese cell biologist, was awarded the Nobel Prize in Physiology or Medicine on Monday."; - SyntaxDependenciesEndpoint endpoint = new SyntaxDependenciesEndpoint(syntax_dependencies_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.SyntaxDependencies endpoint = new Rosette.Api.Endpoints.SyntaxDependencies(syntax_dependencies_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/TextEmbedding.cs b/examples/TextEmbedding.cs index d96f5fa..a44b2b7 100644 --- a/examples/TextEmbedding.cs +++ b/examples/TextEmbedding.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class TextEmbedding @@ -11,13 +12,13 @@ class TextEmbedding /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string embedding_data = @"Cambridge, Massachusetts"; - TextEmbeddingEndpoint endpoint = new TextEmbeddingEndpoint(embedding_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.TextEmbedding endpoint = new Rosette.Api.Endpoints.TextEmbedding(embedding_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); diff --git a/examples/Tokens.cs b/examples/Tokens.cs index 8adac22..d4c9336 100644 --- a/examples/Tokens.cs +++ b/examples/Tokens.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Tokens @@ -11,13 +12,13 @@ class Tokens /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string tokens_data = @"北京大学生物系主任办公室内部会议"; - TokensEndpoint endpoint = new TokensEndpoint(tokens_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Tokens endpoint = new Rosette.Api.Endpoints.Tokens(tokens_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/Topics.cs b/examples/Topics.cs index 75d8431..bc0e003 100644 --- a/examples/Topics.cs +++ b/examples/Topics.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Topics @@ -11,13 +12,13 @@ class Topics /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string topics_data = @"Lily Collins is in talks to join Nicholas Hoult in Chernin Entertainment and Fox Searchlight's J.R.R. Tolkien biopic Tolkien. Anthony Boyle, known for playing Scorpius Malfoy in the British play Harry Potter and the Cursed Child, also has signed on for the film centered on the famed author. In Tolkien, Hoult will play the author of the Hobbit and Lord of the Rings book series that were later adapted into two Hollywood trilogies from Peter Jackson. Dome Karukoski is directing the project."; - TopicsEndpoint endpoint = new TopicsEndpoint(topics_data); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Topics endpoint = new Rosette.Api.Endpoints.Topics(topics_data); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); } diff --git a/examples/Transliteration.cs b/examples/Transliteration.cs index 3b8e631..dc484c1 100644 --- a/examples/Transliteration.cs +++ b/examples/Transliteration.cs @@ -1,4 +1,5 @@ -using rosette_api; +using Rosette.Api; +using Rosette.Api.Models; namespace examples { class Transliteration @@ -11,14 +12,14 @@ class Transliteration /// Optional alternate URL private void RunEndpoint(string apiKey, string? altUrl =null) { try { - RosetteAPI api = new RosetteAPI(apiKey); + ApiClient api = new ApiClient(apiKey); if (!string.IsNullOrEmpty(altUrl)) { api.UseAlternateURL(altUrl); } string transliteration_data = "ana r2ye7 el gam3a el sa3a 3 el 3asr"; - TransliterationEndpoint endpoint = new TransliterationEndpoint(transliteration_data).SetLanguage("ara"); - RosetteResponse response = endpoint.Call(api); + Rosette.Api.Endpoints.Transliteration endpoint = new Rosette.Api.Endpoints.Transliteration(transliteration_data).SetLanguage("ara"); + Response response = endpoint.Call(api); foreach (KeyValuePair h in response.Headers) { Console.WriteLine(string.Format("{0}:{1}", h.Key, h.Value)); diff --git a/rosette_api/RosetteAPI.cs b/rosette_api/ApiClient.cs old mode 100755 new mode 100644 similarity index 89% rename from rosette_api/RosetteAPI.cs rename to rosette_api/ApiClient.cs index 7e25f0b..20562fe --- a/rosette_api/RosetteAPI.cs +++ b/rosette_api/ApiClient.cs @@ -1,231 +1,231 @@ -using System.Net; - -namespace rosette_api; - -public class RosetteAPI : IDisposable -{ - private readonly Dictionary _customHeaders; - private bool _disposeClient = false; - - /// - /// APIKey is the Rosette API key provided by Basis Technology - /// - public string APIKey { get; private set; } - - /// - /// Client is the HttpClient to be used for communication with the server. - /// - public HttpClient? Client { get; private set; } - - /// - /// URI is the uri of the Rosette API server. - /// Default: https://api.rosette.com/rest/v1/ - /// - public string URI { get; private set; } - - /// - /// ConcurrentConnections is the maximum number of connections allowed by the Rosette API Server. - /// Default: 2 - /// - public int ConcurrentConnections { get; private set; } - - /// - /// Timeout is the receive data timeout for the http client. - /// Default: 30 seconds - /// - public int Timeout { get; private set; } - - /// - /// Version returns the version of the assembly - /// - public static string Version => - typeof(RosetteAPI).Assembly.GetName().Version?.ToString() ?? "0.0.0.0"; - - /// - /// Debug turns on extended debug information - /// Default: false - /// - public bool Debug { get; private set; } - - /// - /// RosetteAPI provides the connection to be used for all of the endpoints. - /// - /// Required Rosette API key - public RosetteAPI(string apiKey) { - ArgumentNullException.ThrowIfNull(apiKey); - APIKey = apiKey; - URI = "https://api.rosette.com/rest/v1/"; - Client = null; - ConcurrentConnections = 2; - Timeout = 300; - Debug = false; - _customHeaders = new Dictionary(); - - Prepare(); - } - - /// - /// UseAlternateURL allows the user to specify a different URL for connection to the Rosette API server - /// - /// Destination URL string - /// RosetteAPI object - public RosetteAPI UseAlternateURL(string urlString) { - URI = urlString.EndsWith("/") ? urlString : urlString + "/"; - - return Prepare(); - } - - /// - /// AssignClient allows the user to assign a Client object of their choosing. Additional Rosette API headers - /// will be added to this prior to operation. - /// - /// A valid HttpClient - /// RosetteAPI object - public RosetteAPI AssignClient(HttpClient client) { - Client = client; - - return Prepare(); - } - - /// - /// AssignConcurrentConnections allows the user to specify the number of connections to use. This number, default 2, - /// is based on the user's plan with Basis Technology. - /// - /// Maximum number of connections to allow - /// RosetteAPI object - public RosetteAPI AssignConcurrentConnections(int connections) { - ConcurrentConnections = connections < 2 ? 2 : connections; - - return Prepare(true); - } - - /// - /// AssignTimeoutInMS sets the Client receive data timeout in seconds - /// Default: 30 seconds - /// - /// Timeout in seconds - /// RosetteAPI object - public RosetteAPI AssignTimeout(int timeout) { - Timeout = timeout < 0 ? 0 : timeout; - - return Prepare(); - } - - /// - /// SetDebug sets the debug state of the server response. - /// Default: false - /// - /// Debug state - /// RosetteAPI object - public RosetteAPI SetDebug(bool state=true) { - Debug = state; - - return Prepare(); - } - - /// - /// AddCustomHeader allows the user to add custom headers to the Client. Header names must be prefixed with - /// 'X-RosetteAPI-' - /// - /// Name of header, prefixed with 'X-RosetteAPI-' - /// Value of header - /// RosetteAPI object - public RosetteAPI AddCustomHeader(string headerName, string headerValue) { - if (!headerName.StartsWith("X-RosetteAPI-", StringComparison.OrdinalIgnoreCase)) - { - throw new ArgumentException( - $"Custom header name must begin with 'X-RosetteAPI-'. Provided: {headerName}", - nameof(headerName)); - } - if (_customHeaders.ContainsKey(headerName) && headerValue == null) - { - _customHeaders.Remove(headerName); - } - else - { - _customHeaders[headerName] = headerValue; - } - - return Prepare(); - } - - /// - /// Prepare constructs the Client, with Rosette specific headers, Timeout, ConcurrentConnections, etc. - /// If an outside client is provided, timeout, header and custom header values will still be applied. - /// Warning: Changing the concurrent connections requires a new client, which will replace the user provided one with an - /// internal one. It is advisable that if a user wants to control their own Http Client, they should set the concurrent - /// connections on that object prior to assigning it to the RosetteAPI. - /// - /// Forces the client to refresh. This is necessary if the concurrent connections are changed. - /// RosetteAPI object - private RosetteAPI Prepare(bool forceUpdate=false) { - if (Client == null || forceUpdate) { - Client = new HttpClient( - new SocketsHttpHandler { - AutomaticDecompression = DecompressionMethods.All, - MaxConnectionsPerServer = ConcurrentConnections, - PooledConnectionLifetime = TimeSpan.FromMinutes(2), - PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1) - }); - _disposeClient = true; - } - Client.Timeout = TimeSpan.FromSeconds(Timeout); - - if (Client.BaseAddress == null) { - Client.BaseAddress = new Uri(URI); // base address must be the rosette URI regardless of whether the client is external or internal - } - - // Standard headers, which are required for Rosette API - AddRequestHeader("X-RosetteAPI-Key", APIKey); - AddRequestHeader("User-Agent", string.Format("RosetteAPICsharp/{0}-{1}", Version, Environment.Version.ToString())); - AddRequestHeader("X-RosetteAPI-Binding", "csharp"); - AddRequestHeader("X-RosetteAPI-Binding-Version", Version); - if (Debug) { - AddRequestHeader("X-RosetteAPI-Devel", Debug.ToString()); - } - - var acceptHeader = new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"); - if (!Client.DefaultRequestHeaders.Accept.Contains(acceptHeader)) { - Client.DefaultRequestHeaders.Accept.Add(acceptHeader); - } - - foreach (string encodingType in new List() { "gzip", "deflate" }) { - var encodingHeader = new System.Net.Http.Headers.StringWithQualityHeaderValue(encodingType); - if (!Client.DefaultRequestHeaders.AcceptEncoding.Contains(encodingHeader)) { - Client.DefaultRequestHeaders.AcceptEncoding.Add(encodingHeader); - } - } - - // Custom headers provided by the user - if (_customHeaders.Count > 0) { - foreach (KeyValuePair entry in _customHeaders) { - AddRequestHeader(entry.Key, entry.Value); - } - } - - return this; - } - - /// - /// AddRequestHeader is a helper method to add a header value to the client - /// - /// header name - /// header value - private void AddRequestHeader(string name, string value) - { - ArgumentNullException.ThrowIfNull(Client); - - if (!Client.DefaultRequestHeaders.Contains(name)) - { - Client.DefaultRequestHeaders.Add(name, value); - } - } - - public void Dispose() - { - if (_disposeClient && Client != null) - { - Client.Dispose(); - } - } -} +using System.Net; + +namespace Rosette.Api; + +public class ApiClient : IDisposable +{ + private readonly Dictionary _customHeaders; + private bool _disposeClient = false; + + /// + /// APIKey is the Rosette API key provided by Basis Technology + /// + public string APIKey { get; private set; } + + /// + /// Client is the HttpClient to be used for communication with the server. + /// + public HttpClient? Client { get; private set; } + + /// + /// URI is the uri of the Rosette API server. + /// Default: https://api.rosette.com/rest/v1/ + /// + public string URI { get; private set; } + + /// + /// ConcurrentConnections is the maximum number of connections allowed by the Rosette API Server. + /// Default: 2 + /// + public int ConcurrentConnections { get; private set; } + + /// + /// Timeout is the receive data timeout for the http client. + /// Default: 30 seconds + /// + public int Timeout { get; private set; } + + /// + /// Version returns the version of the assembly + /// + public static string Version => + typeof(ApiClient).Assembly.GetName().Version?.ToString() ?? "0.0.0.0"; + + /// + /// Debug turns on extended debug information + /// Default: false + /// + public bool Debug { get; private set; } + + /// + /// RosetteAPI provides the connection to be used for all of the endpoints. + /// + /// Required Rosette API key + public ApiClient(string apiKey) { + ArgumentNullException.ThrowIfNull(apiKey); + APIKey = apiKey; + URI = "https://api.rosette.com/rest/v1/"; + Client = null; + ConcurrentConnections = 2; + Timeout = 300; + Debug = false; + _customHeaders = new Dictionary(); + + Prepare(); + } + + /// + /// UseAlternateURL allows the user to specify a different URL for connection to the Rosette API server + /// + /// Destination URL string + /// RosetteAPI object + public ApiClient UseAlternateURL(string urlString) { + URI = urlString.EndsWith("/") ? urlString : urlString + "/"; + + return Prepare(); + } + + /// + /// AssignClient allows the user to assign a Client object of their choosing. Additional Rosette API headers + /// will be added to this prior to operation. + /// + /// A valid HttpClient + /// RosetteAPI object + public ApiClient AssignClient(HttpClient client) { + Client = client; + + return Prepare(); + } + + /// + /// AssignConcurrentConnections allows the user to specify the number of connections to use. This number, default 2, + /// is based on the user's plan with Basis Technology. + /// + /// Maximum number of connections to allow + /// RosetteAPI object + public ApiClient AssignConcurrentConnections(int connections) { + ConcurrentConnections = connections < 2 ? 2 : connections; + + return Prepare(true); + } + + /// + /// AssignTimeoutInMS sets the Client receive data timeout in seconds + /// Default: 30 seconds + /// + /// Timeout in seconds + /// RosetteAPI object + public ApiClient AssignTimeout(int timeout) { + Timeout = timeout < 0 ? 0 : timeout; + + return Prepare(); + } + + /// + /// SetDebug sets the debug state of the server response. + /// Default: false + /// + /// Debug state + /// RosetteAPI object + public ApiClient SetDebug(bool state=true) { + Debug = state; + + return Prepare(); + } + + /// + /// AddCustomHeader allows the user to add custom headers to the Client. Header names must be prefixed with + /// 'X-RosetteAPI-' + /// + /// Name of header, prefixed with 'X-RosetteAPI-' + /// Value of header + /// RosetteAPI object + public ApiClient AddCustomHeader(string headerName, string headerValue) { + if (!headerName.StartsWith("X-RosetteAPI-", StringComparison.OrdinalIgnoreCase)) + { + throw new ArgumentException( + $"Custom header name must begin with 'X-RosetteAPI-'. Provided: {headerName}", + nameof(headerName)); + } + if (_customHeaders.ContainsKey(headerName) && headerValue == null) + { + _customHeaders.Remove(headerName); + } + else + { + _customHeaders[headerName] = headerValue; + } + + return Prepare(); + } + + /// + /// Prepare constructs the Client, with Rosette specific headers, Timeout, ConcurrentConnections, etc. + /// If an outside client is provided, timeout, header and custom header values will still be applied. + /// Warning: Changing the concurrent connections requires a new client, which will replace the user provided one with an + /// internal one. It is advisable that if a user wants to control their own Http Client, they should set the concurrent + /// connections on that object prior to assigning it to the RosetteAPI. + /// + /// Forces the client to refresh. This is necessary if the concurrent connections are changed. + /// RosetteAPI object + private ApiClient Prepare(bool forceUpdate=false) { + if (Client == null || forceUpdate) { + Client = new HttpClient( + new SocketsHttpHandler { + AutomaticDecompression = DecompressionMethods.All, + MaxConnectionsPerServer = ConcurrentConnections, + PooledConnectionLifetime = TimeSpan.FromMinutes(2), + PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1) + }); + _disposeClient = true; + } + Client.Timeout = TimeSpan.FromSeconds(Timeout); + + if (Client.BaseAddress == null) { + Client.BaseAddress = new Uri(URI); // base address must be the rosette URI regardless of whether the client is external or internal + } + + // Standard headers, which are required for Rosette API + AddRequestHeader("X-BabelStreetAPI-Key", APIKey); + AddRequestHeader("User-Agent", string.Format("RosetteAPICsharp/{0}-{1}", Version, Environment.Version.ToString())); + AddRequestHeader("X-RosetteAPI-Binding", "csharp"); + AddRequestHeader("X-RosetteAPI-Binding-Version", Version); + if (Debug) { + AddRequestHeader("X-RosetteAPI-Devel", Debug.ToString()); + } + + var acceptHeader = new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"); + if (!Client.DefaultRequestHeaders.Accept.Contains(acceptHeader)) { + Client.DefaultRequestHeaders.Accept.Add(acceptHeader); + } + + foreach (string encodingType in new List() { "gzip", "deflate" }) { + var encodingHeader = new System.Net.Http.Headers.StringWithQualityHeaderValue(encodingType); + if (!Client.DefaultRequestHeaders.AcceptEncoding.Contains(encodingHeader)) { + Client.DefaultRequestHeaders.AcceptEncoding.Add(encodingHeader); + } + } + + // Custom headers provided by the user + if (_customHeaders.Count > 0) { + foreach (KeyValuePair entry in _customHeaders) { + AddRequestHeader(entry.Key, entry.Value); + } + } + + return this; + } + + /// + /// AddRequestHeader is a helper method to add a header value to the client + /// + /// header name + /// header value + private void AddRequestHeader(string name, string value) + { + ArgumentNullException.ThrowIfNull(Client); + + if (!Client.DefaultRequestHeaders.Contains(name)) + { + Client.DefaultRequestHeaders.Add(name, value); + } + } + + public void Dispose() + { + if (_disposeClient && Client != null) + { + Client.Dispose(); + } + } +} diff --git a/rosette_api/Endpoints/AddressSimilarity.cs b/rosette_api/Endpoints/AddressSimilarity.cs new file mode 100644 index 0000000..69a29e6 --- /dev/null +++ b/rosette_api/Endpoints/AddressSimilarity.cs @@ -0,0 +1,26 @@ +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class AddressSimilarity : EndpointBase + { + /// + /// AddressSimilarityEndpoint checks the similarity between two RosetteAddress objects + /// + /// RosetteAddress object + /// RosetteAddress object + public AddressSimilarity(AddressField? address1, AddressField? address2) : base("address-similarity") + { + ArgumentNullException.ThrowIfNull(address1); + Params["address1"] = address1; + ArgumentNullException.ThrowIfNull(address2); + Params["address2"] = address2; + } + + public Response Call(ApiClient api) + { + return Funcs.PostCall(api); + } + } +} \ No newline at end of file diff --git a/rosette_api/CategoriesEndpoint.cs b/rosette_api/Endpoints/Categories.cs old mode 100755 new mode 100644 similarity index 50% rename from rosette_api/CategoriesEndpoint.cs rename to rosette_api/Endpoints/Categories.cs index 45b9373..25768db --- a/rosette_api/CategoriesEndpoint.cs +++ b/rosette_api/Endpoints/Categories.cs @@ -1,12 +1,14 @@ -namespace rosette_api; - -public class CategoriesEndpoint : ContentBasedEndpoint -{ - /// - /// CategoriesEndpoint returns the categories extracted from the endpoint - /// - /// text, Uri object or FileStream - public CategoriesEndpoint(object content) : base("categories", content) - { - } -} +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Categories : ContentEndpointBase +{ + /// + /// CategoriesEndpoint returns the categories extracted from the endpoint + /// + /// text, Uri object or FileStream + public Categories(object content) : base("categories", content) + { + } +} diff --git a/rosette_api/ContentBasedEndpoint.cs b/rosette_api/Endpoints/Core/ContentEndpointBase.cs similarity index 91% rename from rosette_api/ContentBasedEndpoint.cs rename to rosette_api/Endpoints/Core/ContentEndpointBase.cs index be404fb..16c53ab 100644 --- a/rosette_api/ContentBasedEndpoint.cs +++ b/rosette_api/Endpoints/Core/ContentEndpointBase.cs @@ -1,17 +1,19 @@ -namespace rosette_api; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints.Core; /// /// Abstract base class for Rosette API endpoints that accept content and common parameters /// /// The concrete endpoint type for fluent API support -public abstract class ContentBasedEndpoint : EndpointCommon where T : ContentBasedEndpoint +public abstract class ContentEndpointBase : EndpointBase where T : ContentEndpointBase { /// /// Constructor for content-based endpoints /// /// The API endpoint name (e.g., "language", "categories", "entities") /// text, Uri object or FileStream - protected ContentBasedEndpoint(string endpointName, object content) : base(endpointName) { + protected ContentEndpointBase(string endpointName, object content) : base(endpointName) { ArgumentNullException.ThrowIfNull(content); SetContent(content); } @@ -91,7 +93,7 @@ public T SetFileContentType(string contentType) { /// /// RosetteAPI object /// RosetteResponse - public RosetteResponse Call(RosetteAPI api) { + public Response Call(ApiClient api) { return Funcs.PostCall(api); } } \ No newline at end of file diff --git a/rosette_api/EndpointCommon.cs b/rosette_api/Endpoints/Core/EndpointBase.cs old mode 100755 new mode 100644 similarity index 86% rename from rosette_api/EndpointCommon.cs rename to rosette_api/Endpoints/Core/EndpointBase.cs index 7c5f4e1..49b6b4a --- a/rosette_api/EndpointCommon.cs +++ b/rosette_api/Endpoints/Core/EndpointBase.cs @@ -1,91 +1,91 @@ -using System.Collections.Specialized; - -namespace rosette_api; - -public class EndpointCommon where T : EndpointCommon -{ - private EndpointFunctions _funcs = null; - public Dictionary Options { get; private set; } - public Dictionary Params { get; set; } - public NameValueCollection UrlParameters { get; private set; } - public string Endpoint { get; protected set; } - public EndpointFunctions Funcs { - get { - if (_funcs == null) { - _funcs = new EndpointFunctions(Params, Options, UrlParameters, Endpoint); - } - return _funcs; - } - } - - public EndpointCommon(string endpoint) { - Options = []; - Params = []; - UrlParameters = []; - Endpoint = endpoint; - } - - /// - /// SetOption sets an option and value - /// - /// Name of option - /// Value of option - /// Update object - public T SetOption(string optionName, object optionValue) - { - ArgumentException.ThrowIfNullOrWhiteSpace(optionName); - ArgumentNullException.ThrowIfNull(optionValue); - - Options[optionName] = optionValue; - return (T)this; - } - - /// - /// RemoveOption removes an option - /// - /// Name of option - /// Update object - public T RemoveOption(string optionName) - { - ArgumentException.ThrowIfNullOrWhiteSpace(optionName); - Options.Remove(optionName); - return (T)this; - } - - /// - /// ClearOptions removes all options - /// - /// Updated object - public T ClearOptions() { - Options.Clear(); - return (T)this; - } - - /// - /// SetUrlParameter sets a key/value for a query string, e.g. ?output=rosette - /// - /// parameter key - /// parameter value - /// Updated object - public T SetUrlParameter(string parameterKey, string parameterValue) - { - ArgumentException.ThrowIfNullOrWhiteSpace(parameterKey); - ArgumentException.ThrowIfNullOrWhiteSpace(parameterValue); - - UrlParameters.Add(parameterKey, parameterValue); - return (T)this; - } - - /// - /// RemoveUrlParameter removes all values associated with a specified key - /// - /// parameter key - /// Update object - public T RemoveUrlParameter(string parameterKey) - { - ArgumentException.ThrowIfNullOrWhiteSpace(parameterKey); - UrlParameters.Remove(parameterKey); - return (T)this; - } - -} +using System.Collections.Specialized; + +namespace Rosette.Api.Endpoints.Core; + +public class EndpointBase where T : EndpointBase +{ + private EndpointExecutor _funcs = null; + public Dictionary Options { get; private set; } + public Dictionary Params { get; set; } + public NameValueCollection UrlParameters { get; private set; } + public string Endpoint { get; protected set; } + public EndpointExecutor Funcs { + get { + if (_funcs == null) { + _funcs = new EndpointExecutor(Params, Options, UrlParameters, Endpoint); + } + return _funcs; + } + } + + public EndpointBase(string endpoint) { + Options = []; + Params = []; + UrlParameters = []; + Endpoint = endpoint; + } + + /// + /// SetOption sets an option and value + /// + /// Name of option + /// Value of option + /// Update object + public T SetOption(string optionName, object optionValue) + { + ArgumentException.ThrowIfNullOrWhiteSpace(optionName); + ArgumentNullException.ThrowIfNull(optionValue); + + Options[optionName] = optionValue; + return (T)this; + } + + /// + /// RemoveOption removes an option + /// + /// Name of option + /// Update object + public T RemoveOption(string optionName) + { + ArgumentException.ThrowIfNullOrWhiteSpace(optionName); + Options.Remove(optionName); + return (T)this; + } + + /// + /// ClearOptions removes all options + /// + /// Updated object + public T ClearOptions() { + Options.Clear(); + return (T)this; + } + + /// + /// SetUrlParameter sets a key/value for a query string, e.g. ?output=rosette + /// + /// parameter key + /// parameter value + /// Updated object + public T SetUrlParameter(string parameterKey, string parameterValue) + { + ArgumentException.ThrowIfNullOrWhiteSpace(parameterKey); + ArgumentException.ThrowIfNullOrWhiteSpace(parameterValue); + + UrlParameters.Add(parameterKey, parameterValue); + return (T)this; + } + + /// + /// RemoveUrlParameter removes all values associated with a specified key + /// + /// parameter key + /// Update object + public T RemoveUrlParameter(string parameterKey) + { + ArgumentException.ThrowIfNullOrWhiteSpace(parameterKey); + UrlParameters.Remove(parameterKey); + return (T)this; + } + +} diff --git a/rosette_api/EndpointFunctions.cs b/rosette_api/Endpoints/Core/EndpointExecutor.cs old mode 100755 new mode 100644 similarity index 91% rename from rosette_api/EndpointFunctions.cs rename to rosette_api/Endpoints/Core/EndpointExecutor.cs index 0b1aa6c..aa18f67 --- a/rosette_api/EndpointFunctions.cs +++ b/rosette_api/Endpoints/Core/EndpointExecutor.cs @@ -1,243 +1,245 @@ -using System.Collections.Specialized; -using System.Text; -using System.Text.Json; - -namespace rosette_api; - -/// -/// EndpointProcessor provices the compilation and processing of the endpoint -/// through the server. It includes functions that may be used by the different endpoints -/// as needed. -/// -public class EndpointFunctions { - private const string CONTENT = "content"; - private const string CONTENTURI = "contenturi"; - private const string LANGUAGE = "language"; - private const string GENRE = "genre"; - private const string OPTIONS = "options"; - - /// - /// _params contains the parameters to be sent to the server - /// - private readonly Dictionary _params; - - /// - /// _options contains user provided options - /// - private readonly Dictionary _options; - - /// - /// _urlParameters is a NameValueCollection to provide URL query string parameters to the call - /// - private readonly NameValueCollection _urlParameters; - - /// - /// BaseEndpoint is the constructor - /// - public EndpointFunctions( - Dictionary parameters, - Dictionary options, - NameValueCollection urlParameters, - string endpoint) -{ - ArgumentNullException.ThrowIfNull(parameters); - ArgumentNullException.ThrowIfNull(options); - ArgumentNullException.ThrowIfNull(urlParameters); - ArgumentException.ThrowIfNullOrWhiteSpace(endpoint); - - _params = parameters; - _options = options; - _urlParameters = urlParameters; - Endpoint = endpoint; - FileContentType = "text/plain"; -} - /// - /// Endpoint returns the assigned endpoint - /// - public string Endpoint { get; private set; } - - /// - /// Filename returns the provided FileStream's filename - /// - public string Filename { get => Filestream == null ? string.Empty : Filestream.Name; } - - /// - /// Filestream contains the user provided FileStream or null - /// - /// - public FileStream Filestream {get; private set; } - - /// - /// FileContentType returns the assigned Content-Type for a multipart file upload - /// - public string FileContentType { get; set; } - - /// - /// Parameters return the paramters dictionary - /// - /// - public Dictionary Parameters { get => _params; } - - /// - /// Options returns the option dictionary - /// - public Dictionary Options { get=> _options; } - - /// - /// UrlParameters returns any parameters to be used for query string - /// - public NameValueCollection UrlParameters { get => _urlParameters; } - - /// - /// Content returns the textual content, the URI (as a string) or an empty string - /// - public object Content { - get => _params.ContainsKey(CONTENT) ? _params[CONTENT] - : _params.ContainsKey(CONTENTURI) ? _params[CONTENTURI] - : string.Empty; - set { - if (value.GetType() == typeof(FileStream)) { - Filestream = (FileStream)value; - ClearKey(CONTENT); - ClearKey(CONTENTURI); - } - else if (value.GetType() == typeof(Uri)) { - _params[CONTENTURI] = ((Uri)value).AbsoluteUri; - ClearKey(CONTENT); - Filestream = null; - } - else { - _params[CONTENT] = value; - ClearKey(CONTENTURI); - Filestream = null; - } - } - } - /// - /// Language returns the provided 3-letter language code or an empty string - /// - public string? Language { - get => _params.ContainsKey(LANGUAGE) ? _params[LANGUAGE].ToString() : string.Empty; - set => _params[LANGUAGE] = value; - } - - /// - /// Genre returns the provided genre or an empty string - /// - public string? Genre { - get => _params.ContainsKey(GENRE) ? _params[GENRE].ToString() : string.Empty; - set => _params[GENRE] = value; - } - - /// - /// GetCall executes the endpoint against the server using GetAsync - /// - /// RosetteAPI object - /// RosetteResponse - public RosetteResponse GetCall(RosetteAPI api) { - string url = api.URI + Endpoint; - Task task = Task.Run(async () => await api.Client.GetAsync(url)); - var response = task.Result; - - return new RosetteResponse(response); - } - - /// - /// Call calls the server with the provided data using PostAsync - /// - /// RosetteAPI object - /// Rosette Response - public virtual RosetteResponse PostCall(RosetteAPI api) { - string url = api.URI + Endpoint + ToQueryString(); - if (Filestream == null) { - HttpContent content = new StringContent(JsonSerializer.Serialize(AppendOptions(_params))); - content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); - Task task = Task.Run(async () => await api.Client.PostAsync(url, content)); - var response = task.Result; - - return new RosetteResponse(response); - } - else { - return PostAsMultipart(api, url); - } - } - - /// - /// AppendOptions appends any provided options to the parameter dictionary - /// - /// Dictionary of options - /// Dictionary of string, object - private Dictionary AppendOptions(Dictionary dict) { - if (_options.Count > 0) { - dict[OPTIONS] = _options; - } - else { - dict.Remove(OPTIONS); // Remove returns false if key doesn't exist, no need to check - } - return dict; - } - - /// - /// PostAsMultipart handles processing of files as a multipart upload - /// - /// RosetteAPI object - /// Endpoint URL - /// RosetteResponse object - private RosetteResponse PostAsMultipart(RosetteAPI api, string url) { - - using (var _multiPartContent = new MultipartFormDataContent()) { - var streamContent = new StreamContent(Filestream); - streamContent.Headers.Add("Content-Type", FileContentType); - streamContent.Headers.Add("Content-Disposition", "mixed; name=\"content\"; filename=\"" + Path.GetFileName(Filestream.Name) + "\""); - _multiPartContent.Add(streamContent, "content", Path.GetFileName(Filestream.Name)); - - if (_options.Count > 0 || _params.Count > 0) { - var stringContent = new StringContent(JsonSerializer.Serialize(AppendOptions(_params)), Encoding.UTF8, "application/json"); - stringContent.Headers.Add("Content-Disposition", "mixed; name=\"request\""); - _multiPartContent.Add(stringContent, "request"); - } - Task task = Task.Run(async () => await api.Client.PostAsync(url, _multiPartContent)); - - var response = task.Result; - return new RosetteResponse(response); - } - } - - /// - /// clearKey removes the specified key from the _params dictionary - /// - /// key name - private void ClearKey(string key) => _params.Remove(key); - - /// - /// ToQueryString is a helper to generate the query string to append to the URL - /// - /// query string - private string ToQueryString() { - if (UrlParameters.Count == 0) { - return String.Empty; - } - StringBuilder sb = new StringBuilder("?"); - - bool first = true; - foreach (string key in UrlParameters.AllKeys) { - foreach (string value in UrlParameters.GetValues(key)) { - if (!first) { - sb.Append("&"); - } - sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value)); - first = false; - } - } - - return sb.ToString(); - } - - /// - /// HasContent checks for content to send - /// - /// bool if content, contenturi or filename - private bool HasContent() { - return _params.ContainsKey(CONTENT) || _params.ContainsKey(CONTENTURI) || !string.IsNullOrEmpty(Filename); - } -} +using Rosette.Api.Models; +using System.Collections.Specialized; +using System.Text; +using System.Text.Json; + +namespace Rosette.Api.Endpoints.Core; + +/// +/// EndpointProcessor provices the compilation and processing of the endpoint +/// through the server. It includes functions that may be used by the different endpoints +/// as needed. +/// +public class EndpointExecutor { + private const string CONTENT = "content"; + private const string CONTENTURI = "contenturi"; + private const string LANGUAGE = "language"; + private const string GENRE = "genre"; + private const string OPTIONS = "options"; + + /// + /// _params contains the parameters to be sent to the server + /// + private readonly Dictionary _params; + + /// + /// _options contains user provided options + /// + private readonly Dictionary _options; + + /// + /// _urlParameters is a NameValueCollection to provide URL query string parameters to the call + /// + private readonly NameValueCollection _urlParameters; + + /// + /// BaseEndpoint is the constructor + /// + public EndpointExecutor( + Dictionary parameters, + Dictionary options, + NameValueCollection urlParameters, + string endpoint) +{ + ArgumentNullException.ThrowIfNull(parameters); + ArgumentNullException.ThrowIfNull(options); + ArgumentNullException.ThrowIfNull(urlParameters); + ArgumentException.ThrowIfNullOrWhiteSpace(endpoint); + + _params = parameters; + _options = options; + _urlParameters = urlParameters; + Endpoint = endpoint; + FileContentType = "text/plain"; +} + /// + /// Endpoint returns the assigned endpoint + /// + public string Endpoint { get; private set; } + + /// + /// Filename returns the provided FileStream's filename + /// + public string Filename { get => Filestream == null ? string.Empty : Filestream.Name; } + + /// + /// Filestream contains the user provided FileStream or null + /// + /// + public FileStream Filestream {get; private set; } + + /// + /// FileContentType returns the assigned Content-Type for a multipart file upload + /// + public string FileContentType { get; set; } + + /// + /// Parameters return the paramters dictionary + /// + /// + public Dictionary Parameters { get => _params; } + + /// + /// Options returns the option dictionary + /// + public Dictionary Options { get=> _options; } + + /// + /// UrlParameters returns any parameters to be used for query string + /// + public NameValueCollection UrlParameters { get => _urlParameters; } + + /// + /// Content returns the textual content, the URI (as a string) or an empty string + /// + public object Content { + get => _params.ContainsKey(CONTENT) ? _params[CONTENT] + : _params.ContainsKey(CONTENTURI) ? _params[CONTENTURI] + : string.Empty; + set { + if (value.GetType() == typeof(FileStream)) { + Filestream = (FileStream)value; + ClearKey(CONTENT); + ClearKey(CONTENTURI); + } + else if (value.GetType() == typeof(Uri)) { + _params[CONTENTURI] = ((Uri)value).AbsoluteUri; + ClearKey(CONTENT); + Filestream = null; + } + else { + _params[CONTENT] = value; + ClearKey(CONTENTURI); + Filestream = null; + } + } + } + /// + /// Language returns the provided 3-letter language code or an empty string + /// + public string? Language { + get => _params.ContainsKey(LANGUAGE) ? _params[LANGUAGE].ToString() : string.Empty; + set => _params[LANGUAGE] = value; + } + + /// + /// Genre returns the provided genre or an empty string + /// + public string? Genre { + get => _params.ContainsKey(GENRE) ? _params[GENRE].ToString() : string.Empty; + set => _params[GENRE] = value; + } + + /// + /// GetCall executes the endpoint against the server using GetAsync + /// + /// RosetteAPI object + /// RosetteResponse + public Response GetCall(ApiClient api) { + string url = api.URI + Endpoint; + Task task = Task.Run(async () => await api.Client.GetAsync(url)); + var response = task.Result; + + return new Response(response); + } + + /// + /// Call calls the server with the provided data using PostAsync + /// + /// RosetteAPI object + /// Rosette Response + public virtual Response PostCall(ApiClient api) { + string url = api.URI + Endpoint + ToQueryString(); + if (Filestream == null) { + var requestBody = JsonSerializer.Serialize(AppendOptions(_params)); + HttpContent content = new StringContent(requestBody); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + Task task = Task.Run(async () => await api.Client.PostAsync(url, content)); + var response = task.Result; + + return new Response(response); + } + else { + return PostAsMultipart(api, url); + } + } + + /// + /// AppendOptions appends any provided options to the parameter dictionary + /// + /// Dictionary of options + /// Dictionary of string, object + private Dictionary AppendOptions(Dictionary dict) { + if (_options.Count > 0) { + dict[OPTIONS] = _options; + } + else { + dict.Remove(OPTIONS); // Remove returns false if key doesn't exist, no need to check + } + return dict; + } + + /// + /// PostAsMultipart handles processing of files as a multipart upload + /// + /// RosetteAPI object + /// Endpoint URL + /// RosetteResponse object + private Response PostAsMultipart(ApiClient api, string url) { + + using (var _multiPartContent = new MultipartFormDataContent()) { + var streamContent = new StreamContent(Filestream); + streamContent.Headers.Add("Content-Type", FileContentType); + streamContent.Headers.Add("Content-Disposition", "mixed; name=\"content\"; filename=\"" + Path.GetFileName(Filestream.Name) + "\""); + _multiPartContent.Add(streamContent, "content", Path.GetFileName(Filestream.Name)); + + if (_options.Count > 0 || _params.Count > 0) { + var stringContent = new StringContent(JsonSerializer.Serialize(AppendOptions(_params)), Encoding.UTF8, "application/json"); + stringContent.Headers.Add("Content-Disposition", "mixed; name=\"request\""); + _multiPartContent.Add(stringContent, "request"); + } + Task task = Task.Run(async () => await api.Client.PostAsync(url, _multiPartContent)); + + var response = task.Result; + return new Response(response); + } + } + + /// + /// clearKey removes the specified key from the _params dictionary + /// + /// key name + private void ClearKey(string key) => _params.Remove(key); + + /// + /// ToQueryString is a helper to generate the query string to append to the URL + /// + /// query string + private string ToQueryString() { + if (UrlParameters.Count == 0) { + return String.Empty; + } + StringBuilder sb = new StringBuilder("?"); + + bool first = true; + foreach (string key in UrlParameters.AllKeys) { + foreach (string value in UrlParameters.GetValues(key)) { + if (!first) { + sb.Append("&"); + } + sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value)); + first = false; + } + } + + return sb.ToString(); + } + + /// + /// HasContent checks for content to send + /// + /// bool if content, contenturi or filename + private bool HasContent() { + return _params.ContainsKey(CONTENT) || _params.ContainsKey(CONTENTURI) || !string.IsNullOrEmpty(Filename); + } +} diff --git a/rosette_api/Endpoints/Entities.cs b/rosette_api/Endpoints/Entities.cs new file mode 100644 index 0000000..ccfb875 --- /dev/null +++ b/rosette_api/Endpoints/Entities.cs @@ -0,0 +1,26 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Entities : ContentEndpointBase +{ + /// + /// EntitiesEndpoint returns the entities extracted from the endpoint + /// + /// text, Uri object or FileStream + public Entities(object content) : base("entities", content) + { + } + + /// + /// SetGenre is not supported for the Entities endpoint and will be ignored. + /// This override prevents the genre from being set. + /// + /// document genre (ignored) + /// Updated endpoint instance + public new Entities SetGenre(string genre) + { + // Genre is not supported for Entities endpoint - ignore the value + return this; + } +} diff --git a/rosette_api/Endpoints/Events.cs b/rosette_api/Endpoints/Events.cs new file mode 100644 index 0000000..9d9c19f --- /dev/null +++ b/rosette_api/Endpoints/Events.cs @@ -0,0 +1,14 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Events : ContentEndpointBase +{ + /// + /// EventsEndpoint returns the events extracted from the endpoint + /// + /// text, Uri object or FileStream + public Events(object content) : base("events", content) + { + } +} \ No newline at end of file diff --git a/rosette_api/Endpoints/Info.cs b/rosette_api/Endpoints/Info.cs new file mode 100644 index 0000000..eec493e --- /dev/null +++ b/rosette_api/Endpoints/Info.cs @@ -0,0 +1,12 @@ +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class Info : EndpointBase + { + public Info() : base("info") { } + + public Response Call(ApiClient api) => Funcs.GetCall(api); + } +} diff --git a/rosette_api/LanguageEndpoint.cs b/rosette_api/Endpoints/Language.cs old mode 100755 new mode 100644 similarity index 51% rename from rosette_api/LanguageEndpoint.cs rename to rosette_api/Endpoints/Language.cs index abbe6d3..ec07ee9 --- a/rosette_api/LanguageEndpoint.cs +++ b/rosette_api/Endpoints/Language.cs @@ -1,12 +1,14 @@ -namespace rosette_api; - -public class LanguageEndpoint : ContentBasedEndpoint -{ - /// - /// LanguageEndpoint returns the language extracted from the endpoint - /// - /// text, Uri object or FileStream - public LanguageEndpoint(object content) : base("language", content) - { - } -} +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Language : ContentEndpointBase +{ + /// + /// LanguageEndpoint returns the language extracted from the endpoint + /// + /// text, Uri object or FileStream + public Language(object content) : base("language", content) + { + } +} diff --git a/rosette_api/MorphologyEndpoint.cs b/rosette_api/Endpoints/Morphology.cs old mode 100755 new mode 100644 similarity index 84% rename from rosette_api/MorphologyEndpoint.cs rename to rosette_api/Endpoints/Morphology.cs index e7f50e9..ba98f80 --- a/rosette_api/MorphologyEndpoint.cs +++ b/rosette_api/Endpoints/Morphology.cs @@ -1,103 +1,106 @@ -namespace rosette_api -{ - public enum MorphologyFeature { - /// provide complete morphology - complete, - /// provide lemmas - lemmas, - /// provide parts of speech - partsOfSpeech, - /// provide compound components - compoundComponents, - /// provide han readings - hanReadings - }; - public class MorphologyEndpoint : EndpointCommon { - - - private Dictionary _featureEndpoint; - /// - /// MorphologyEndpoint returns morphological analysis of input - /// - /// text, Uri object or FileStream - /// feature to use - public MorphologyEndpoint(object content, MorphologyFeature feature = MorphologyFeature.complete) : base("morphology") { - Endpoint = "morphology/" + FeatureAsString(feature); - SetContent(content); - } - /// - /// SetContent sets the content to be reviewed - /// - /// text, Uri object or FileStream - /// update Morphology endpoint - public MorphologyEndpoint SetContent(object content) { - Funcs.Content = content; - - return this; - } - - public object Content => Funcs.Content; - /// - /// SetLanguage sets the optional ISO 639-3 language code - /// - /// ISO 639-3 language code - /// updated Morphology endpoint - public MorphologyEndpoint SetLanguage(string language) { - Funcs.Language = language; - - return this; - } - - public string? Language => Funcs.Language; - /// - /// SetGenre sets the optional document genre, e.g. social-media - /// - /// document genre - /// updated Morphology endpoint - public MorphologyEndpoint SetGenre(string genre) { - Funcs.Genre = genre; - - return this; - } - - public string? Genre => Funcs.Genre; - /// - /// SetFileContentType sets the content type of the file contents. Note that - /// it only applies when the content is a filename - /// - /// Content-Type - /// updated Morphology endpoint - public MorphologyEndpoint SetFileContentType(string contentType) { - Funcs.FileContentType = contentType; - - return this; - } - public string FileContentType => Funcs.FileContentType; - public string Filename => Funcs.Filename; - /// - /// Call passes the data to the server and returns the response - /// - /// RosetteAPI object - /// RosetteResponse - public RosetteResponse Call(RosetteAPI api) { - return Funcs.PostCall(api); - } - /// - /// FeatureAsString returns the feature enum in its endpoint string form - /// - /// feature - /// endpoint equivalent - public string FeatureAsString(MorphologyFeature feature) { - _featureEndpoint = new Dictionary() { - { MorphologyFeature.complete, "complete" }, - { MorphologyFeature.lemmas, "lemmas" }, - { MorphologyFeature.partsOfSpeech, "parts-of-speech" }, - { MorphologyFeature.compoundComponents, "compound-components" }, - { MorphologyFeature.hanReadings, "han-readings" } - }; - - return _featureEndpoint[feature]; - } - - } -} +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public enum MorphologyFeature { + /// provide complete morphology + complete, + /// provide lemmas + lemmas, + /// provide parts of speech + partsOfSpeech, + /// provide compound components + compoundComponents, + /// provide han readings + hanReadings + }; + public class Morphology : EndpointBase { + + + private Dictionary _featureEndpoint; + /// + /// MorphologyEndpoint returns morphological analysis of input + /// + /// text, Uri object or FileStream + /// feature to use + public Morphology(object content, MorphologyFeature feature = MorphologyFeature.complete) : base("morphology") { + Endpoint = "morphology/" + FeatureAsString(feature); + SetContent(content); + } + /// + /// SetContent sets the content to be reviewed + /// + /// text, Uri object or FileStream + /// update Morphology endpoint + public Morphology SetContent(object content) { + Funcs.Content = content; + + return this; + } + + public object Content => Funcs.Content; + /// + /// SetLanguage sets the optional ISO 639-3 language code + /// + /// ISO 639-3 language code + /// updated Morphology endpoint + public Morphology SetLanguage(string language) { + Funcs.Language = language; + + return this; + } + + public string? Language => Funcs.Language; + /// + /// SetGenre sets the optional document genre, e.g. social-media + /// + /// document genre + /// updated Morphology endpoint + public Morphology SetGenre(string genre) { + Funcs.Genre = genre; + + return this; + } + + public string? Genre => Funcs.Genre; + /// + /// SetFileContentType sets the content type of the file contents. Note that + /// it only applies when the content is a filename + /// + /// Content-Type + /// updated Morphology endpoint + public Morphology SetFileContentType(string contentType) { + Funcs.FileContentType = contentType; + + return this; + } + public string FileContentType => Funcs.FileContentType; + public string Filename => Funcs.Filename; + /// + /// Call passes the data to the server and returns the response + /// + /// RosetteAPI object + /// RosetteResponse + public Response Call(ApiClient api) { + return Funcs.PostCall(api); + } + /// + /// FeatureAsString returns the feature enum in its endpoint string form + /// + /// feature + /// endpoint equivalent + public string FeatureAsString(MorphologyFeature feature) { + _featureEndpoint = new Dictionary() { + { MorphologyFeature.complete, "complete" }, + { MorphologyFeature.lemmas, "lemmas" }, + { MorphologyFeature.partsOfSpeech, "parts-of-speech" }, + { MorphologyFeature.compoundComponents, "compound-components" }, + { MorphologyFeature.hanReadings, "han-readings" } + }; + + return _featureEndpoint[feature]; + } + + } +} diff --git a/rosette_api/NameDeduplicationEndpoint.cs b/rosette_api/Endpoints/NameDeduplication.cs old mode 100755 new mode 100644 similarity index 78% rename from rosette_api/NameDeduplicationEndpoint.cs rename to rosette_api/Endpoints/NameDeduplication.cs index c01ff2a..5f96a45 --- a/rosette_api/NameDeduplicationEndpoint.cs +++ b/rosette_api/Endpoints/NameDeduplication.cs @@ -1,76 +1,79 @@ -namespace rosette_api -{ - public class NameDeduplicationEndpoint : EndpointCommon - { - /// - /// NameDeduplicationEndpoint constructs an object to deduplicate names through the Rosette API - /// - /// List of RosetteName objects - public NameDeduplicationEndpoint(List names) : base("name-deduplication") { - SetNames(names); - } - /// - /// SetNames assigns a list of RosetteName objects to be processed - /// - /// List of RosetteName - /// updated NameDeduplicationEndpoint object - public NameDeduplicationEndpoint SetNames(List names) { - if (names == null || names.Count == 0) { - throw new ArgumentException("Names must contain at least 1 RosetteName object."); - } - Params["names"] = names; - return this; - } - /// - /// Names returns the list of RosetteName objects - /// - public IList Names { get => - Params.ContainsKey("names") ? - Params["names"] as IList : - null; - } - /// - /// SetProfileID sets a profile ID to be used during processing - /// - /// profile ID - /// updated NameDeduplicationEndpoint object - public NameDeduplicationEndpoint SetProfileID(string profileID) { - Params["profileid"] = profileID; - return this; - } - /// - /// ProfileID returns the profile ID or empty string - /// - public string ProfileID { get => - Params.ContainsKey("profileid") ? - Params["profileid"].ToString() : - string.Empty; - } - /// - /// SetThreshold sets the threshold to be used for determining deduplication cluster sizing - /// - /// float value of threshold, default 0.75 - /// updated NameDeduplicationEndpoint object - public NameDeduplicationEndpoint SetThreshold(float threshold) { - Params["threshold"] = threshold; - return this; - } - /// - /// Threshold returns the threshold or the default, 0.75f - /// - public float Threshold { get => - Params.ContainsKey("threshold") ? - (float)Params["threshold"] : - 0.75f; - } - /// - /// Call returns the response from the server - /// - /// RosetteAPI object - /// RosetteResponse - public RosetteResponse Call(RosetteAPI api) { - return Funcs.PostCall(api); - } - - } -} +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class NameDeduplication : EndpointBase + { + /// + /// NameDeduplicationEndpoint constructs an object to deduplicate names through the Rosette API + /// + /// List of RosetteName objects + public NameDeduplication(List names) : base("name-deduplication") { + SetNames(names); + } + /// + /// SetNames assigns a list of RosetteName objects to be processed + /// + /// List of RosetteName + /// updated NameDeduplicationEndpoint object + public NameDeduplication SetNames(List names) { + if (names == null || names.Count == 0) { + throw new ArgumentException("Names must contain at least 1 RosetteName object."); + } + Params["names"] = names; + return this; + } + /// + /// Names returns the list of RosetteName objects + /// + public IList Names { get => + Params.ContainsKey("names") ? + Params["names"] as IList : + null; + } + /// + /// SetProfileID sets a profile ID to be used during processing + /// + /// profile ID + /// updated NameDeduplicationEndpoint object + public NameDeduplication SetProfileID(string profileID) { + Params["profileid"] = profileID; + return this; + } + /// + /// ProfileID returns the profile ID or empty string + /// + public string ProfileID { get => + Params.ContainsKey("profileid") ? + Params["profileid"].ToString() : + string.Empty; + } + /// + /// SetThreshold sets the threshold to be used for determining deduplication cluster sizing + /// + /// float value of threshold, default 0.75 + /// updated NameDeduplicationEndpoint object + public NameDeduplication SetThreshold(float threshold) { + Params["threshold"] = threshold; + return this; + } + /// + /// Threshold returns the threshold or the default, 0.75f + /// + public float Threshold { get => + Params.ContainsKey("threshold") ? + (float)Params["threshold"] : + 0.75f; + } + /// + /// Call returns the response from the server + /// + /// RosetteAPI object + /// RosetteResponse + public Response Call(ApiClient api) { + return Funcs.PostCall(api); + } + + } +} diff --git a/rosette_api/NameSimilarityEndpoint.cs b/rosette_api/Endpoints/NameSimilarity.cs old mode 100755 new mode 100644 similarity index 63% rename from rosette_api/NameSimilarityEndpoint.cs rename to rosette_api/Endpoints/NameSimilarity.cs index 9dfbbb5..062c677 --- a/rosette_api/NameSimilarityEndpoint.cs +++ b/rosette_api/Endpoints/NameSimilarity.cs @@ -1,20 +1,23 @@ -namespace rosette_api -{ - public class NameSimilarityEndpoint : EndpointCommon { - /// - /// NameSimilarityEndpoint checks the similarity between two RosetteName objects - /// - /// RosetteName object - /// RosetteName object - public NameSimilarityEndpoint(RosetteName? name1, RosetteName? name2) : base("name-similarity") { - ArgumentNullException.ThrowIfNull(name1); - Params["name1"] = name1; - ArgumentNullException.ThrowIfNull(name2); - Params["name2"] = name2; - } - - public RosetteResponse Call(RosetteAPI api) { - return Funcs.PostCall(api); - } - } -} +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class NameSimilarity : EndpointBase { + /// + /// NameSimilarityEndpoint checks the similarity between two RosetteName objects + /// + /// RosetteName object + /// RosetteName object + public NameSimilarity(Name? name1, Name? name2) : base("name-similarity") { + ArgumentNullException.ThrowIfNull(name1); + Params["name1"] = name1; + ArgumentNullException.ThrowIfNull(name2); + Params["name2"] = name2; + } + + public Response Call(ApiClient api) { + return Funcs.PostCall(api); + } + } +} diff --git a/rosette_api/NameTranslationEndpoint.cs b/rosette_api/Endpoints/NameTranslation.cs old mode 100755 new mode 100644 similarity index 75% rename from rosette_api/NameTranslationEndpoint.cs rename to rosette_api/Endpoints/NameTranslation.cs index 8d0a350..c0f4c26 --- a/rosette_api/NameTranslationEndpoint.cs +++ b/rosette_api/Endpoints/NameTranslation.cs @@ -1,143 +1,167 @@ -namespace rosette_api -{ - public class NameTranslationEndpoint : EndpointCommon - { - private const string NAME = "name"; - private const string ENTITY_TYPE = "entityType"; - private const string SOURCE_LANGUAGE_OF_ORIGIN = "sourceLanguageOfOrigin"; - private const string SOURCE_LANGUAGE_OF_USE = "sourceLanguageOfUse"; - private const string SOURCE_SCRIPT = "sourceScript"; - private const string TARGET_LANGUAGE = "targetLanguage"; - private const string TARGET_SCHEME = "targetScheme"; - private const string TARGET_SCRIPT = "targetScript"; - - public NameTranslationEndpoint(string name, string targetLanguage="eng") : base("name-translation") { - SetName(name); - SetTargetLanguage(targetLanguage); - } - /// - /// SetName defines the name to be translated - /// - /// name to be translated - /// this - public NameTranslationEndpoint SetName(string name) { - Params[NAME] = name; - - return this; - } - public string? Name { get => - Params.ContainsKey(NAME) ? - Params[NAME].ToString() : - string.Empty; - } - /// - /// SetEntityType sets the optional entity type, PERSON, LOCATION or ORGANIZATION - /// - /// PERSON, LOCATION, or ORGANIZATION - /// this - public NameTranslationEndpoint SetEntityType(string entityType) { - Params[ENTITY_TYPE] = entityType; - - return this; - } - public string? EntityType { get => - Params.ContainsKey(ENTITY_TYPE) ? - Params[ENTITY_TYPE].ToString() : - string.Empty; - } - /// - /// SetSourceLanguageOfOrigin sets the optional ISO 639-3 code for the name's language of origin - /// - /// ISO 639-3 language code - /// this - public NameTranslationEndpoint SetSourceLanguageOfOrigin(string sourceLanguageOfOrigin) { - Params[SOURCE_LANGUAGE_OF_ORIGIN] = sourceLanguageOfOrigin; - - return this; - } - public string? SourceLanguageOfOrigin { get => - Params.ContainsKey(SOURCE_LANGUAGE_OF_ORIGIN) ? - Params[SOURCE_LANGUAGE_OF_ORIGIN].ToString() : - string.Empty; - } - /// - /// SetSourceLanguageOfUse sets the optional ISO 639-3 code for the name's language of use - /// - /// ISO 639-3 language code - /// this - public NameTranslationEndpoint SetSourceLanguageOfUse(string sourceLanguageOfUse) { - Params[SOURCE_LANGUAGE_OF_USE] = sourceLanguageOfUse; - - return this; - } - public string? SourceLanguageOfUse { get => - Params.ContainsKey(SOURCE_LANGUAGE_OF_USE) ? - Params[SOURCE_LANGUAGE_OF_USE].ToString() : - String.Empty; - } - /// - /// SetSourceScript sets the optional ISO 15924 code for the name's script - /// - /// ISO 15294 script code - /// this - public NameTranslationEndpoint SetSourceScript(string sourceScript) { - Params[SOURCE_SCRIPT] = sourceScript; - - return this; - } - public string? SourceScript { get => - Params.ContainsKey(SOURCE_SCRIPT) ? - Params[SOURCE_SCRIPT].ToString() : - string.Empty; - } - /// - /// SetTargetLanguage sets the ISO 639-3 code for the translation language. - /// Defaults to "eng" - /// - /// ISO 639-3 language code - /// this - public NameTranslationEndpoint SetTargetLanguage(string targetLanguage) { - Params[TARGET_LANGUAGE] = targetLanguage; - - return this; - } - public string? TargetLanguage { get => - Params.ContainsKey(TARGET_LANGUAGE) ? - Params[TARGET_LANGUAGE].ToString() : - String.Empty; - } - /// - /// SetTargetScheme sets the optional transliteration scheme for the translation - /// - /// transliteration scheme - /// this - public NameTranslationEndpoint SetTargetScheme(string targetScheme) { - Params[TARGET_SCHEME] = targetScheme; - - return this; - } - public string? TargetScheme { get => - Params.ContainsKey(TARGET_SCHEME) ? - Params[TARGET_SCHEME].ToString() : - string.Empty; - } - /// - /// SetTargetScript sets the optional ISO 15924 code for the translation script - /// - /// ISO 15924 script code - /// this - public NameTranslationEndpoint SetTargetScript(string targetScript) { - Params[TARGET_SCRIPT] = targetScript; - - return this; - } - public string? TargetScript { get => Params.ContainsKey(TARGET_SCRIPT) ? - Params[TARGET_SCRIPT].ToString() : - string.Empty; - } - - public RosetteResponse Call(RosetteAPI api) { - return Funcs.PostCall(api); - } - } -} +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class NameTranslation : EndpointBase + { + private const string NAME = "name"; + private const string ENTITY_TYPE = "entityType"; + private const string SOURCE_LANGUAGE_OF_ORIGIN = "sourceLanguageOfOrigin"; + private const string SOURCE_LANGUAGE_OF_USE = "sourceLanguageOfUse"; + private const string SOURCE_SCRIPT = "sourceScript"; + private const string TARGET_LANGUAGE = "targetLanguage"; + private const string TARGET_SCHEME = "targetScheme"; + private const string TARGET_SCRIPT = "targetScript"; + private const string MAXIMUM_RESULTS = "maximumResults"; + + public NameTranslation(string name, string targetLanguage="eng") : base("name-translation") { + SetName(name); + SetTargetLanguage(targetLanguage); + } + /// + /// SetName defines the name to be translated + /// + /// name to be translated + /// this + public NameTranslation SetName(string name) { + Params[NAME] = name; + + return this; + } + public string? Name { get => + Params.ContainsKey(NAME) ? + Params[NAME].ToString() : + string.Empty; + } + /// + /// SetEntityType sets the optional entity type, PERSON, LOCATION or ORGANIZATION + /// + /// PERSON, LOCATION, or ORGANIZATION + /// this + public NameTranslation SetEntityType(string entityType) { + Params[ENTITY_TYPE] = entityType; + + return this; + } + public string? EntityType { get => + Params.ContainsKey(ENTITY_TYPE) ? + Params[ENTITY_TYPE].ToString() : + string.Empty; + } + /// + /// SetSourceLanguageOfOrigin sets the optional ISO 639-3 code for the name's language of origin + /// + /// ISO 639-3 language code + /// this + public NameTranslation SetSourceLanguageOfOrigin(string sourceLanguageOfOrigin) { + Params[SOURCE_LANGUAGE_OF_ORIGIN] = sourceLanguageOfOrigin; + + return this; + } + public string? SourceLanguageOfOrigin { get => + Params.ContainsKey(SOURCE_LANGUAGE_OF_ORIGIN) ? + Params[SOURCE_LANGUAGE_OF_ORIGIN].ToString() : + string.Empty; + } + /// + /// SetSourceLanguageOfUse sets the optional ISO 639-3 code for the name's language of use + /// + /// ISO 639-3 language code + /// this + public NameTranslation SetSourceLanguageOfUse(string sourceLanguageOfUse) { + Params[SOURCE_LANGUAGE_OF_USE] = sourceLanguageOfUse; + + return this; + } + public string? SourceLanguageOfUse { get => + Params.ContainsKey(SOURCE_LANGUAGE_OF_USE) ? + Params[SOURCE_LANGUAGE_OF_USE].ToString() : + String.Empty; + } + /// + /// SetSourceScript sets the optional ISO 15924 code for the name's script + /// + /// ISO 15294 script code + /// this + public NameTranslation SetSourceScript(string sourceScript) { + Params[SOURCE_SCRIPT] = sourceScript; + + return this; + } + public string? SourceScript { get => + Params.ContainsKey(SOURCE_SCRIPT) ? + Params[SOURCE_SCRIPT].ToString() : + string.Empty; + } + /// + /// SetTargetLanguage sets the ISO 639-3 code for the translation language. + /// Defaults to "eng" + /// + /// ISO 639-3 language code + /// this + public NameTranslation SetTargetLanguage(string targetLanguage) { + Params[TARGET_LANGUAGE] = targetLanguage; + + return this; + } + public string? TargetLanguage { get => + Params.ContainsKey(TARGET_LANGUAGE) ? + Params[TARGET_LANGUAGE].ToString() : + String.Empty; + } + /// + /// SetTargetScheme sets the optional transliteration scheme for the translation + /// + /// transliteration scheme + /// this + public NameTranslation SetTargetScheme(string targetScheme) { + Params[TARGET_SCHEME] = targetScheme; + + return this; + } + public string? TargetScheme { get => + Params.ContainsKey(TARGET_SCHEME) ? + Params[TARGET_SCHEME].ToString() : + string.Empty; + } + /// + /// SetTargetScript sets the optional ISO 15924 code for the translation script + /// + /// ISO 15924 script code + /// this + public NameTranslation SetTargetScript(string targetScript) { + Params[TARGET_SCRIPT] = targetScript; + + return this; + } + public string? TargetScript { get => Params.ContainsKey(TARGET_SCRIPT) ? + Params[TARGET_SCRIPT].ToString() : + string.Empty; + } + + /// + /// SetMaximumResults sets the optional maximum number of results to return + /// + /// maximum number of results + /// this + public NameTranslation SetMaximumResults(string maximumResults) + { + Params[MAXIMUM_RESULTS] = maximumResults; + + return this; + } + + public string? MaximumResults { get => + Params.ContainsKey(MAXIMUM_RESULTS) ? + Params[MAXIMUM_RESULTS].ToString() : + string.Empty; + } + + + + public Response Call(ApiClient api) { + return Funcs.PostCall(api); + } + } +} diff --git a/rosette_api/Endpoints/Ping.cs b/rosette_api/Endpoints/Ping.cs new file mode 100644 index 0000000..52858af --- /dev/null +++ b/rosette_api/Endpoints/Ping.cs @@ -0,0 +1,12 @@ +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints +{ + public class Ping : EndpointBase + { + public Ping() : base("ping") { } + + public Response Call(ApiClient api) => Funcs.GetCall(api); + } +} diff --git a/rosette_api/Endpoints/RecordSimilarity.cs b/rosette_api/Endpoints/RecordSimilarity.cs new file mode 100644 index 0000000..29ebb81 --- /dev/null +++ b/rosette_api/Endpoints/RecordSimilarity.cs @@ -0,0 +1,28 @@ +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Endpoints; + +public class RecordSimilarity : EndpointBase +{ + /// + /// RecordSimilarity returns the similarity score between records + /// + /// text, Uri object or FileStream + public RecordSimilarity(Dictionary? fields, + RecordSimilarityProperties? properties, + RecordSimilarityRecords? records) : base("record-similarity") + { + ArgumentNullException.ThrowIfNull(fields); + Params["fields"] = fields; + ArgumentNullException.ThrowIfNull(properties); + Params["properties"] = properties; + ArgumentNullException.ThrowIfNull(records); + Params["records"] = records; + } + + public Response Call(ApiClient api) + { + return Funcs.PostCall(api); + } +} \ No newline at end of file diff --git a/rosette_api/RelationshipsEndpoint.cs b/rosette_api/Endpoints/Relationships.cs old mode 100755 new mode 100644 similarity index 50% rename from rosette_api/RelationshipsEndpoint.cs rename to rosette_api/Endpoints/Relationships.cs index 8593926..e1a94c9 --- a/rosette_api/RelationshipsEndpoint.cs +++ b/rosette_api/Endpoints/Relationships.cs @@ -1,12 +1,14 @@ -namespace rosette_api; - -public class RelationshipsEndpoint : ContentBasedEndpoint -{ - /// - /// RelationshipsEndpoint returns the relationships between entities in the input text - /// - /// text, Uri object or FileStream - public RelationshipsEndpoint(object content) : base("relationships", content) - { - } +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Relationships : ContentEndpointBase +{ + /// + /// RelationshipsEndpoint returns the relationships between entities in the input text + /// + /// text, Uri object or FileStream + public Relationships(object content) : base("relationships", content) + { + } } \ No newline at end of file diff --git a/rosette_api/Endpoints/SemanticsVector.cs b/rosette_api/Endpoints/SemanticsVector.cs new file mode 100644 index 0000000..484b953 --- /dev/null +++ b/rosette_api/Endpoints/SemanticsVector.cs @@ -0,0 +1,14 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class SemanticsVector : ContentEndpointBase +{ + /// + /// SemanticVectorsEndpoint returns the relationships between entities in the input text + /// + /// text, Uri object or FileStream + public SemanticsVector(object content) : base("semantics/vector", content) + { + } +} \ No newline at end of file diff --git a/rosette_api/SentencesEndpoint.cs b/rosette_api/Endpoints/Sentences.cs old mode 100755 new mode 100644 similarity index 51% rename from rosette_api/SentencesEndpoint.cs rename to rosette_api/Endpoints/Sentences.cs index e0fa5dd..577953f --- a/rosette_api/SentencesEndpoint.cs +++ b/rosette_api/Endpoints/Sentences.cs @@ -1,11 +1,13 @@ -namespace rosette_api -{ - public class SentencesEndpoint : ContentBasedEndpoint { - /// - /// SentencesEndpoint returns each entity extracted from the input - /// - /// text, Uri object or FileStream - public SentencesEndpoint(object content) : base("sentences", content) { - } - } -} +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints +{ + public class Sentences : ContentEndpointBase { + /// + /// SentencesEndpoint returns each entity extracted from the input + /// + /// text, Uri object or FileStream + public Sentences(object content) : base("sentences", content) { + } + } +} diff --git a/rosette_api/SentimentEndpoint.cs b/rosette_api/Endpoints/Sentiment.cs old mode 100755 new mode 100644 similarity index 55% rename from rosette_api/SentimentEndpoint.cs rename to rosette_api/Endpoints/Sentiment.cs index 5058df4..0bbe478 --- a/rosette_api/SentimentEndpoint.cs +++ b/rosette_api/Endpoints/Sentiment.cs @@ -1,13 +1,15 @@ -namespace rosette_api -{ - public class SentimentEndpoint : ContentBasedEndpoint - { - /// - /// SentimentEndpoint analyzes the positive and negative sentiment expressed by the input - /// - /// text, Uri object or FileStream - public SentimentEndpoint(object content) : base("sentiment", content) - { - } - } +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints +{ + public class Sentiment : ContentEndpointBase + { + /// + /// SentimentEndpoint analyzes the positive and negative sentiment expressed by the input + /// + /// text, Uri object or FileStream + public Sentiment(object content) : base("sentiment", content) + { + } + } } \ No newline at end of file diff --git a/rosette_api/Endpoints/SimilarTerms.cs b/rosette_api/Endpoints/SimilarTerms.cs new file mode 100644 index 0000000..a320e8e --- /dev/null +++ b/rosette_api/Endpoints/SimilarTerms.cs @@ -0,0 +1,14 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class SimilarTerms : ContentEndpointBase +{ + /// + /// SimilarTerms returns terms that are similar to the input + /// + /// text, Uri object or FileStream + public SimilarTerms(object content) : base("semantics/similar", content) + { + } +} \ No newline at end of file diff --git a/rosette_api/SyntaxDependenciesEndpoint.cs b/rosette_api/Endpoints/SyntaxDependencies.cs old mode 100755 new mode 100644 similarity index 55% rename from rosette_api/SyntaxDependenciesEndpoint.cs rename to rosette_api/Endpoints/SyntaxDependencies.cs index 86c0d8f..271e364 --- a/rosette_api/SyntaxDependenciesEndpoint.cs +++ b/rosette_api/Endpoints/SyntaxDependencies.cs @@ -1,10 +1,12 @@ -namespace rosette_api; - -public class SyntaxDependenciesEndpoint : ContentBasedEndpoint { - /// - /// SyntaxDependenciesEndpoint returns the parse tree of the input text as a list of labeled directed links between tokens, as well as the list of tokens in the input sentence - /// - /// text, Uri object or FileStream - public SyntaxDependenciesEndpoint(object content) : base("syntax/dependencies", content) { - } -} +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class SyntaxDependencies : ContentEndpointBase { + /// + /// SyntaxDependenciesEndpoint returns the parse tree of the input text as a list of labeled directed links between tokens, as well as the list of tokens in the input sentence + /// + /// text, Uri object or FileStream + public SyntaxDependencies(object content) : base("syntax/dependencies", content) { + } +} diff --git a/rosette_api/Endpoints/TextEmbedding.cs b/rosette_api/Endpoints/TextEmbedding.cs new file mode 100644 index 0000000..7b809df --- /dev/null +++ b/rosette_api/Endpoints/TextEmbedding.cs @@ -0,0 +1,15 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints +{ + public class TextEmbedding : ContentEndpointBase + { + /// + /// TextEmbeddingEndpoint returns the embedding for the input text + /// + /// text, Uri object or FileStream + public TextEmbedding(object content) : base("text-embedding", content) + { + } + } +} \ No newline at end of file diff --git a/rosette_api/Endpoints/Tokens.cs b/rosette_api/Endpoints/Tokens.cs new file mode 100644 index 0000000..257d33c --- /dev/null +++ b/rosette_api/Endpoints/Tokens.cs @@ -0,0 +1,12 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Tokens : ContentEndpointBase { + /// + /// TokensEndpoint returns each entity extracted from the input + /// + /// text, Uri object or FileStream + public Tokens(object content) : base("tokens", content) { + } +} diff --git a/rosette_api/Endpoints/Topics.cs b/rosette_api/Endpoints/Topics.cs new file mode 100644 index 0000000..68bdadb --- /dev/null +++ b/rosette_api/Endpoints/Topics.cs @@ -0,0 +1,12 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Topics : ContentEndpointBase { + /// + /// TopicsEndpoint returns the topic extracted from the endpoint + /// + /// text, Uri object or FileStream + public Topics(object content) : base("topics", content) { + } +} diff --git a/rosette_api/Endpoints/Transliteration.cs b/rosette_api/Endpoints/Transliteration.cs new file mode 100644 index 0000000..62b2415 --- /dev/null +++ b/rosette_api/Endpoints/Transliteration.cs @@ -0,0 +1,12 @@ +using Rosette.Api.Endpoints.Core; + +namespace Rosette.Api.Endpoints; + +public class Transliteration : ContentEndpointBase { + /// + /// TransliterationEndpoint returns the transliteration of the input + /// + /// text, Uri object or FileStream + public Transliteration(object content) : base("transliteration", content) { + } +} diff --git a/rosette_api/EntitiesEndpoint.cs b/rosette_api/EntitiesEndpoint.cs deleted file mode 100755 index 6d1f324..0000000 --- a/rosette_api/EntitiesEndpoint.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace rosette_api; - -public class EntitiesEndpoint : ContentBasedEndpoint -{ - /// - /// EntitiesEndpoint returns the entities extracted from the endpoint - /// - /// text, Uri object or FileStream - public EntitiesEndpoint(object content) : base("entities", content) - { - } -} diff --git a/rosette_api/InfoEndpoint.cs b/rosette_api/InfoEndpoint.cs deleted file mode 100755 index e48dadb..0000000 --- a/rosette_api/InfoEndpoint.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace rosette_api -{ - public class InfoEndpoint : EndpointCommon - { - public InfoEndpoint() : base("info") { } - - public RosetteResponse Call(RosetteAPI api) => Funcs.GetCall(api); - } -} diff --git a/rosette_api/Models/AddressField.cs b/rosette_api/Models/AddressField.cs new file mode 100644 index 0000000..0230af9 --- /dev/null +++ b/rosette_api/Models/AddressField.cs @@ -0,0 +1,8 @@ +namespace Rosette.Api.Models; + +/// +/// Abstract parent class for UnfieldedAddress and FieldedAddress +/// +public abstract class AddressField : RecordSimilarityField +{ +} \ No newline at end of file diff --git a/rosette_api/Models/BooleanRecord.cs b/rosette_api/Models/BooleanRecord.cs new file mode 100644 index 0000000..f1e206d --- /dev/null +++ b/rosette_api/Models/BooleanRecord.cs @@ -0,0 +1,47 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a boolean record +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class BooleanRecord : RecordSimilarityField +{ + /// + /// Gets and sets the boolean record + /// + [JsonPropertyName("data")] + public bool Boolean { get; set; } + + /// + /// No-args constructor + /// + public BooleanRecord() { } + + /// + /// Constructor + /// + /// The boolean record + public BooleanRecord(bool data) + { + Boolean = data; + } + + /// + /// Equals override + /// + public override bool Equals(object? obj) => + obj is BooleanRecord other && Boolean == other.Boolean; + + /// + /// Hashcode override + /// + public override int GetHashCode() => Boolean.GetHashCode(); + + /// + /// ToString override + /// + public override string ToString() => Boolean.ToString().ToLowerInvariant(); +} \ No newline at end of file diff --git a/rosette_api/Models/DateField.cs b/rosette_api/Models/DateField.cs new file mode 100644 index 0000000..7fd78ee --- /dev/null +++ b/rosette_api/Models/DateField.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Abstract parent class for UnfieldedDate and FieldedDate +/// +public abstract class DateField : RecordSimilarityField +{ + /// + /// Gets or sets the date field's date + /// + [JsonPropertyName("date")] + public required string Date { get; set; } +} \ No newline at end of file diff --git a/rosette_api/Models/EntityType.cs b/rosette_api/Models/EntityType.cs new file mode 100644 index 0000000..6c95126 --- /dev/null +++ b/rosette_api/Models/EntityType.cs @@ -0,0 +1,16 @@ +namespace Rosette.Api.Models; + +/// +/// Represents the type of entity for name processing +/// +public enum EntityType +{ + /// Person entity type + Person, + + /// Location entity type + Location, + + /// Organization entity type + Organization +} \ No newline at end of file diff --git a/rosette_api/Models/FieldedAddressRecord.cs b/rosette_api/Models/FieldedAddressRecord.cs new file mode 100644 index 0000000..51eeeef --- /dev/null +++ b/rosette_api/Models/FieldedAddressRecord.cs @@ -0,0 +1,168 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a fielded address +/// +public class FieldedAddressRecord : AddressField +{ + [JsonPropertyName("house")] + public string? House { get; set; } + + [JsonPropertyName("houseNumber")] + public string? HouseNumber { get; set; } + + [JsonPropertyName("road")] + public string? Road { get; set; } + + [JsonPropertyName("unit")] + public string? Unit { get; set; } + + [JsonPropertyName("level")] + public string? Level { get; set; } + + [JsonPropertyName("staircase")] + public string? Staircase { get; set; } + + [JsonPropertyName("entrance")] + public string? Entrance { get; set; } + + [JsonPropertyName("suburb")] + public string? Suburb { get; set; } + + [JsonPropertyName("cityDistrict")] + public string? CityDistrict { get; set; } + + [JsonPropertyName("city")] + public string? City { get; set; } + + [JsonPropertyName("island")] + public string? Island { get; set; } + + [JsonPropertyName("stateDistrict")] + public string? StateDistrict { get; set; } + + [JsonPropertyName("state")] + public string? State { get; set; } + + [JsonPropertyName("countryRegion")] + public string? CountryRegion { get; set; } + + [JsonPropertyName("country")] + public string? Country { get; set; } + + [JsonPropertyName("worldRegion")] + public string? WorldRegion { get; set; } + + [JsonPropertyName("postcode")] + public string? Postcode { get; set; } + + [JsonPropertyName("po_box")] + public string? PoBox { get; set; } + + /// + /// No-args constructor + /// + public FieldedAddressRecord() { } + + /// + /// Full constructor + /// + public FieldedAddressRecord( + string? house = null, + string? houseNumber = null, + string? road = null, + string? unit = null, + string? level = null, + string? staircase = null, + string? entrance = null, + string? suburb = null, + string? cityDistrict = null, + string? city = null, + string? island = null, + string? stateDistrict = null, + string? state = null, + string? countryRegion = null, + string? country = null, + string? worldRegion = null, + string? postcode = null, + string? poBox = null) + { + House = house; + HouseNumber = houseNumber; + Road = road; + Unit = unit; + Level = level; + Staircase = staircase; + Entrance = entrance; + Suburb = suburb; + CityDistrict = cityDistrict; + City = city; + Island = island; + StateDistrict = stateDistrict; + State = state; + CountryRegion = countryRegion; + Country = country; + WorldRegion = worldRegion; + Postcode = postcode; + PoBox = poBox; + } + + /// + /// Equals override + /// + public override bool Equals(object? obj) => + obj is FieldedAddressRecord other && + House == other.House && + HouseNumber == other.HouseNumber && + Road == other.Road && + Unit == other.Unit && + Level == other.Level && + Staircase == other.Staircase && + Entrance == other.Entrance && + Suburb == other.Suburb && + CityDistrict == other.CityDistrict && + City == other.City && + Island == other.Island && + StateDistrict == other.StateDistrict && + State == other.State && + CountryRegion == other.CountryRegion && + Country == other.Country && + WorldRegion == other.WorldRegion && + Postcode == other.Postcode && + PoBox == other.PoBox; + + /// + /// Hashcode override + /// + public override int GetHashCode() + { + var hash = new HashCode(); + hash.Add(House); + hash.Add(HouseNumber); + hash.Add(Road); + hash.Add(Unit); + hash.Add(Level); + hash.Add(Staircase); + hash.Add(Entrance); + hash.Add(Suburb); + hash.Add(CityDistrict); + hash.Add(City); + hash.Add(Island); + hash.Add(StateDistrict); + hash.Add(State); + hash.Add(CountryRegion); + hash.Add(Country); + hash.Add(WorldRegion); + hash.Add(Postcode); + hash.Add(PoBox); + return hash.ToHashCode(); + } + + /// + /// ToString override + /// + public override string ToString() => JsonSerializer.Serialize(this); +} \ No newline at end of file diff --git a/rosette_api/Models/FieldedDateRecord.cs b/rosette_api/Models/FieldedDateRecord.cs new file mode 100644 index 0000000..57d5b1a --- /dev/null +++ b/rosette_api/Models/FieldedDateRecord.cs @@ -0,0 +1,58 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a fielded date +/// +public class FieldedDateRecord : DateField +{ + /// + /// Gets or sets the date field's format + /// + [JsonPropertyName("format")] + public string? Format { get; set; } + + /// + /// No-args constructor + /// + public FieldedDateRecord() + { + Date = string.Empty; + } + + /// + /// Full constructor + /// + /// The date in string format + /// The date's format. Rules are defined at https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html + public FieldedDateRecord(string date, string? format = null) + { + ArgumentException.ThrowIfNullOrWhiteSpace(date); + Date = date; + Format = format; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object? obj) => + obj is FieldedDateRecord other && + Date == other.Date && + Format == other.Format; + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() => HashCode.Combine(Date, Format); + + /// + /// ToString override + /// + /// This fielded date in JSON form + public override string ToString() => JsonSerializer.Serialize(this); +} \ No newline at end of file diff --git a/rosette_api/Models/FieldedNameRecord.cs b/rosette_api/Models/FieldedNameRecord.cs new file mode 100644 index 0000000..f1f6778 --- /dev/null +++ b/rosette_api/Models/FieldedNameRecord.cs @@ -0,0 +1,91 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a fielded name +/// +public class FieldedNameRecord : NameField +{ + /// + /// Gets or sets the language (ISO 639-3 code) + /// + [JsonPropertyName("language")] + public string? Language { get; set; } + + /// + /// Gets or sets the language of origin (ISO 639-3 code) + /// + [JsonPropertyName("languageOfOrigin")] + public string? LanguageOfOrigin { get; set; } + + /// + /// Gets or sets the script (ISO 15924 code for the name's script) + /// + [JsonPropertyName("script")] + public string? Script { get; set; } + + /// + /// Gets or sets the entity type (PERSON, LOCATION, or ORGANIZATION) + /// + [JsonPropertyName("entityType")] + public string? EntityType { get; set; } + + /// + /// No-args constructor + /// + public FieldedNameRecord() + { + Text = string.Empty; + } + + /// + /// Full constructor + /// + /// Text describing the name + /// Language: ISO 639-3 code (optional) + /// Language the name originates from: ISO 639-3 code (optional) + /// ISO 15924 code for the name's script (optional) + /// Entity type of the name: PERSON, LOCATION, or ORGANIZATION (optional) + public FieldedNameRecord( + string text, + string? language = null, + string? languageOfOrigin = null, + string? script = null, + string? entityType = null) + { + ArgumentException.ThrowIfNullOrWhiteSpace(text); + Text = text; + Language = language; + LanguageOfOrigin = languageOfOrigin; + Script = script; + EntityType = entityType; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object? obj) => + obj is FieldedNameRecord other && + Text == other.Text && + Language == other.Language && + LanguageOfOrigin == other.LanguageOfOrigin && + Script == other.Script && + EntityType == other.EntityType; + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() => + HashCode.Combine(Text, Language, LanguageOfOrigin, Script, EntityType); + + /// + /// ToString override + /// + /// This fielded name in JSON form + public override string ToString() => JsonSerializer.Serialize(this); +} \ No newline at end of file diff --git a/rosette_api/Models/JsonConverter/RecordSimilarityFieldConverter.cs b/rosette_api/Models/JsonConverter/RecordSimilarityFieldConverter.cs new file mode 100644 index 0000000..9c83035 --- /dev/null +++ b/rosette_api/Models/JsonConverter/RecordSimilarityFieldConverter.cs @@ -0,0 +1,67 @@ +using Rosette.Api.Models; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace rosette_api.Models.JsonConverter; + +/// +/// JsonConverter for RecordSimilarityField interface polymorphic serialization +/// +public class RecordSimilarityFieldConverter : JsonConverter +{ + public override RecordSimilarityField? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotSupportedException( + "Deserialization of RecordSimilarityField is not supported. " + + "Unfielded records cannot be reliably reconstructed from JSON responses " + + "because type information is lost. Please work with the raw JSON response data instead."); + } + + public override void Write(Utf8JsonWriter writer, RecordSimilarityField value, JsonSerializerOptions options) + { + switch (value) + { + case UnfieldedNameRecord unfieldedName: + writer.WriteStringValue(unfieldedName.Text); + break; + case UnfieldedDateRecord unfieldedDate: + writer.WriteStringValue(unfieldedDate.Date); + break; + case UnfieldedAddressRecord unfieldedAddress: + writer.WriteStringValue(unfieldedAddress.Address); + break; + case FieldedNameRecord fieldedName: + JsonSerializer.Serialize(writer, fieldedName, options); + break; + case FieldedDateRecord fieldedDate: + JsonSerializer.Serialize(writer, fieldedDate, options); + break; + case FieldedAddressRecord fieldedAddress: + JsonSerializer.Serialize(writer, fieldedAddress, options); + break; + case NumberRecord numberRecord: + writer.WriteNumberValue(numberRecord.Number); + break; + case BooleanRecord booleanRecord: + writer.WriteBooleanValue(booleanRecord.Boolean); + break; + case StringRecord stringRecord: + writer.WriteStringValue(stringRecord.Text); + break; + case UnknownFieldRecord unknownField: + if (unknownField.Data != null) + { + unknownField.Data.WriteTo(writer, options); + } + else + { + writer.WriteNullValue(); + } + break; + default: + JsonSerializer.Serialize(writer, value, value.GetType(), options); + break; + } + } +} \ No newline at end of file diff --git a/rosette_api/Models/JsonConverter/RecordSimilarityRecordsConverter.cs b/rosette_api/Models/JsonConverter/RecordSimilarityRecordsConverter.cs new file mode 100644 index 0000000..2dd4e5c --- /dev/null +++ b/rosette_api/Models/JsonConverter/RecordSimilarityRecordsConverter.cs @@ -0,0 +1,95 @@ +using Rosette.Api.Models; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace rosette_api.Models.JsonConverter; + +/// +/// JsonConverter for RecordSimilarityRecords to properly serialize RecordSimilarityField values +/// +public class RecordSimilarityRecordsConverter : JsonConverter +{ + private readonly RecordSimilarityFieldConverter _fieldConverter = new(); + + public override RecordSimilarityRecords? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) + { + using var doc = JsonDocument.ParseValue(ref reader); + var root = doc.RootElement; + + var left = ReadRecordList(root.GetProperty("left"), options); + var right = ReadRecordList(root.GetProperty("right"), options); + + return new RecordSimilarityRecords(left, right); + } + + private List> ReadRecordList( + JsonElement arrayElement, + JsonSerializerOptions options) + { + var list = new List>(); + + foreach (var objElement in arrayElement.EnumerateArray()) + { + var dict = new Dictionary(); + + foreach (var prop in objElement.EnumerateObject()) + { + var reader = new Utf8JsonReader( + System.Text.Encoding.UTF8.GetBytes(prop.Value.GetRawText())); + reader.Read(); + + var field = _fieldConverter.Read(ref reader, typeof(RecordSimilarityField), options); + if (field != null) + { + dict[prop.Name] = field; + } + } + + list.Add(dict); + } + + return list; + } + + public override void Write( + Utf8JsonWriter writer, + RecordSimilarityRecords value, + JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WritePropertyName("left"); + WriteDictionaryList(writer, value.Left, options); + + writer.WritePropertyName("right"); + WriteDictionaryList(writer, value.Right, options); + + writer.WriteEndObject(); + } + + private void WriteDictionaryList( + Utf8JsonWriter writer, + List> list, + JsonSerializerOptions options) + { + writer.WriteStartArray(); + + foreach (var dict in list) + { + writer.WriteStartObject(); + + foreach (var kvp in dict) + { + writer.WritePropertyName(kvp.Key); + _fieldConverter.Write(writer, kvp.Value, options); + } + + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + } +} \ No newline at end of file diff --git a/rosette_api/Models/JsonConverter/UnfieldedRecordSimilarityConverter.cs b/rosette_api/Models/JsonConverter/UnfieldedRecordSimilarityConverter.cs new file mode 100644 index 0000000..394cf8b --- /dev/null +++ b/rosette_api/Models/JsonConverter/UnfieldedRecordSimilarityConverter.cs @@ -0,0 +1,67 @@ +using Rosette.Api.Models; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace rosette_api.Models.JsonConverter; + +/// +/// JsonConverter for Unfielded Record Similarity objects +/// +public class UnfieldedRecordSimilarityConverter : JsonConverter +{ + /// + /// Initializes a new instance of the UnfieldedRecordSimilarityConverter class + /// + public UnfieldedRecordSimilarityConverter() + { + // Default constructor for JSON serialization + } + + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert == typeof(UnknownFieldRecord) || + typeToConvert == typeof(NumberRecord) || + typeToConvert == typeof(BooleanRecord) || + typeToConvert == typeof(UnfieldedAddressRecord) || + typeToConvert == typeof(object); + } + + public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.TokenType switch + { + JsonTokenType.Number => new NumberRecord { Number = reader.GetDouble() }, + JsonTokenType.True or JsonTokenType.False => new BooleanRecord { Boolean = reader.GetBoolean() }, + JsonTokenType.String => typeToConvert == typeof(UnfieldedAddressRecord) + ? new UnfieldedAddressRecord { Address = reader.GetString() ?? string.Empty } + : reader.GetString(), + JsonTokenType.StartObject => JsonSerializer.Deserialize(ref reader, options), + _ => null + }; + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + switch (value) + { + case UnfieldedAddressRecord unfieldedAddress: + writer.WriteStringValue(unfieldedAddress.Address); + break; + case UnknownFieldRecord unknownField: + JsonSerializer.Serialize(writer, unknownField.Data, options); + break; + case NumberRecord numberRecord: + writer.WriteNumberValue(numberRecord.Number); + break; + case BooleanRecord booleanRecord: + writer.WriteBooleanValue(booleanRecord.Boolean); + break; + case string stringValue: + writer.WriteStringValue(stringValue); + break; + default: + writer.WriteStringValue(value?.ToString() ?? string.Empty); + break; + } + } +} \ No newline at end of file diff --git a/rosette_api/RosetteName.cs b/rosette_api/Models/Name.cs old mode 100755 new mode 100644 similarity index 74% rename from rosette_api/RosetteName.cs rename to rosette_api/Models/Name.cs index 1908a64..6882901 --- a/rosette_api/RosetteName.cs +++ b/rosette_api/Models/Name.cs @@ -1,81 +1,92 @@ -using System.Text.Json.Serialization; - -namespace rosette_api; - -public class RosetteName -{ - [JsonPropertyName("text")] - public string Text { get; private set; } - - [JsonPropertyName("entityType")] - public string? EntityType { get; private set; } - - [JsonPropertyName("language")] - public string? Language { get; private set; } - - [JsonPropertyName("script")] - public string? Script { get; private set; } - - /// - /// Constructor for a Name object, used by several endpoints - /// - /// required text - /// optional entity type - /// optional language code - /// optional script code - [JsonConstructor] - public RosetteName(string text, string? entityType = null, string? language = null, string? script = null) - { - ArgumentException.ThrowIfNullOrWhiteSpace(text); - Text = text; - EntityType = entityType; - Language = language; - Script = script; - } - - /// - /// SetEntityType sets the optional entity type. PERSON, LOCATION and ORGANIZATION - /// are currently supported. - /// - /// entity type, PERSON, LOCATION or ORGANIZATION - /// updated RosetteName object - public RosetteName SetEntityType(string type) - { - ArgumentException.ThrowIfNullOrWhiteSpace(type); - - string[] validTypes = ["PERSON", "LOCATION", "ORGANIZATION"]; - if (!validTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) - { - throw new ArgumentException( - $"Entity type must be one of: {string.Join(", ", validTypes)}. Provided: {type}", - nameof(type)); - } - - EntityType = type.ToUpperInvariant(); - return this; - } - - /// - /// SetLanguage sets the optional ISO-639-3 language code for the name's language - /// - /// ISO-639-3 language code - /// updated RosetteName object - public RosetteName SetLanguage(string language) - { - ArgumentException.ThrowIfNullOrWhiteSpace(language); - Language = language; - return this; - } - - /// - /// SetScript sets the ISO-15924 code for the name's script - /// - /// ISO-15924 script code - /// updated RosetteName object - public RosetteName SetScript(string script) - { - ArgumentException.ThrowIfNullOrWhiteSpace(script); - Script = script; - return this; - } +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +public class Name +{ + [JsonPropertyName("text")] + public string Text { get; private set; } + + [JsonPropertyName("entityType")] + public string? EntityType { get; private set; } + + [JsonPropertyName("language")] + public string? Language { get; private set; } + + [JsonPropertyName("script")] + public string? Script { get; private set; } + + /// + /// Constructor for a Name object, used by several endpoints + /// + /// required text + /// optional entity type + /// optional language code + /// optional script code + [JsonConstructor] + public Name(string text, string? entityType = null, string? language = null, string? script = null) + { + ArgumentException.ThrowIfNullOrWhiteSpace(text); + Text = text; + EntityType = entityType; + Language = language; + Script = script; + } + + /// + /// SetEntityType sets the entity type using the EntityType enum + /// + /// entity type + /// updated Name object + public Name SetEntityType(EntityType type) + { + EntityType = type.ToString().ToUpperInvariant(); + return this; + } + + /// + /// SetEntityType sets the optional entity type. PERSON, LOCATION and ORGANIZATION + /// are currently supported. + /// + /// entity type, PERSON, LOCATION or ORGANIZATION + /// updated Name object + public Name SetEntityType(string type) + { + ArgumentException.ThrowIfNullOrWhiteSpace(type); + + string[] validTypes = ["PERSON", "LOCATION", "ORGANIZATION"]; + if (!validTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) + { + throw new ArgumentException( + $"Entity type must be one of: {string.Join(", ", validTypes)}. Provided: {type}", + nameof(type)); + } + + EntityType = type.ToUpperInvariant(); + return this; + } + + /// + /// SetLanguage sets the optional ISO-639-3 language code for the name's language + /// + /// ISO-639-3 language code + /// updated Name object + public Name SetLanguage(string language) + { + ArgumentException.ThrowIfNullOrWhiteSpace(language); + Language = language; + return this; + } + + /// + /// SetScript sets the ISO-15924 code for the name's script + /// + /// ISO-15924 script code + /// updated Name object + public Name SetScript(string script) + { + ArgumentException.ThrowIfNullOrWhiteSpace(script); + Script = script; + return this; + } } \ No newline at end of file diff --git a/rosette_api/Models/NameField.cs b/rosette_api/Models/NameField.cs new file mode 100644 index 0000000..a740b7d --- /dev/null +++ b/rosette_api/Models/NameField.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Abstract parent class for UnfieldedName and FieldedName +/// +public abstract class NameField : RecordSimilarityField +{ + /// + /// Gets or sets the name field's text + /// + [JsonPropertyName("text")] + public required string Text { get; set; } +} \ No newline at end of file diff --git a/rosette_api/Models/NumberRecord.cs b/rosette_api/Models/NumberRecord.cs new file mode 100644 index 0000000..adfbb0f --- /dev/null +++ b/rosette_api/Models/NumberRecord.cs @@ -0,0 +1,49 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a number record +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class NumberRecord : RecordSimilarityField +{ + public const string DATA = "data"; + + /// + /// Gets and sets the number record + /// + [JsonPropertyName("data")] + public double Number { get; set; } + + /// + /// No-args constructor + /// + public NumberRecord() { } + + /// + /// Constructor + /// + /// The number record + public NumberRecord(double data) + { + Number = data; + } + + /// + /// Equals override + /// + public override bool Equals(object? obj) => + obj is NumberRecord other && Number == other.Number; + + /// + /// Hashcode override + /// + public override int GetHashCode() => Number.GetHashCode(); + + /// + /// ToString override + /// + public override string ToString() => Number.ToString(); +} \ No newline at end of file diff --git a/rosette_api/Models/RecordFieldType.cs b/rosette_api/Models/RecordFieldType.cs new file mode 100644 index 0000000..5732b6c --- /dev/null +++ b/rosette_api/Models/RecordFieldType.cs @@ -0,0 +1,16 @@ +namespace Rosette.Api.Models; + +/// RecordFieldType +/// +/// The possible record types that can be used in the Record Similarity endpoint +/// +/// +public static class RecordFieldType +{ + public const string RniName = "rni_name"; + public const string RniDate = "rni_date"; + public const string RniAddress = "rni_address"; + public const string RniString = "rni_string"; + public const string RniNumber = "rni_number"; + public const string RniBoolean = "rni_boolean"; +} diff --git a/rosette_api/Models/RecordSimilarityField.cs b/rosette_api/Models/RecordSimilarityField.cs new file mode 100644 index 0000000..25aa547 --- /dev/null +++ b/rosette_api/Models/RecordSimilarityField.cs @@ -0,0 +1,8 @@ +namespace Rosette.Api.Models; + +/// +/// Parent Interface for RecordSimilarityField objects +/// +public interface RecordSimilarityField +{ +} \ No newline at end of file diff --git a/rosette_api/Models/RecordSimilarityFieldInfo.cs b/rosette_api/Models/RecordSimilarityFieldInfo.cs new file mode 100644 index 0000000..05a8f72 --- /dev/null +++ b/rosette_api/Models/RecordSimilarityFieldInfo.cs @@ -0,0 +1,93 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models { + + /// + /// Class for representing record similarity field information + /// + public class RecordSimilarityFieldInfo + { + /// + /// Gets or sets the record's field type + /// + [JsonPropertyName("type")] + public string Type { get; set; } + + /// + /// Gets or sets the record's field weight + /// + [JsonPropertyName("weight")] + public double? Weight { get; set; } + + /// + /// Gets or sets the record's field scoreIfNull + /// + [JsonPropertyName("scoreIfNull")] + public double? ScoreIfNull { get; set; } + + /// + /// No-args constructor + /// + public RecordSimilarityFieldInfo() { } + + /// + /// Full constructor + /// + /// The record's field type + /// The record's field weight + /// The record's field scoreIfNull + public RecordSimilarityFieldInfo(string type, double? weight, double? scoreIfNull) + { + this.Type = type; + this.Weight = weight; + this.ScoreIfNull = scoreIfNull; + } + + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object obj) + { + if (obj is RecordSimilarityFieldInfo) + { + RecordSimilarityFieldInfo other = obj as RecordSimilarityFieldInfo; + List conditions = new List() { + this.Type == other.Type, + this.Weight == other.Weight, + this.ScoreIfNull == other.ScoreIfNull + }; + return conditions.All(condition => condition); + } + else + { + return false; + } + } + + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() + { + int h0 = this.Type.GetHashCode(); + int h1 = this.Weight != null ? this.Weight.GetHashCode() : 1; + int h2 = this.ScoreIfNull != null ? this.ScoreIfNull.GetHashCode() : 1; + return h0 ^ h1 ^ h2; + } + + /// + /// ToString override. + /// + /// This record similarity field info in JSON form + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + } +} \ No newline at end of file diff --git a/rosette_api/Models/RecordSimilarityProperties.cs b/rosette_api/Models/RecordSimilarityProperties.cs new file mode 100644 index 0000000..c14bc82 --- /dev/null +++ b/rosette_api/Models/RecordSimilarityProperties.cs @@ -0,0 +1,113 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models +{ + public class RecordSimilarityProperties + { + /// + /// Gets or sets the record similarity request's score threshold + /// + [JsonPropertyName("threshold")] + public double? Threshold { get; set; } = 0.0; + + + /// + /// Gets or sets the record similarity request's include explain info parameter + /// + [JsonPropertyName("includeExplainInfo")] + public bool? IncludeExplainInfo { get; set; } + + /// + /// Gets or sets the record similarity request's parameters + /// + [JsonPropertyName("parameters")] + public Dictionary Parameters { get; set; } + + /// + /// Gets or sets the record similarity request's parameter universe + /// + [JsonPropertyName("parameterUniverse")] + public string ParameterUniverse { get; set; } + + /// + /// No-args constructor + /// + public RecordSimilarityProperties() { } + + /// + /// Includes explain info constructor. Sets the threshold to 0.0. + /// + /// The include explain info parameter + public RecordSimilarityProperties(bool includeExplainInfo) + { + this.IncludeExplainInfo = includeExplainInfo; + this.Threshold = 0.0; + this.Parameters = new Dictionary(); + this.ParameterUniverse = ""; + } + + /// + /// Full constructor + /// + /// The score threshold + /// The include explain info parameter + /// A map of string parameter names to string parameter values + /// The parameter universe to use + public RecordSimilarityProperties(double threshold, bool includeExplainInfo, Dictionary parameters, string parameterUniverse) + { + this.Threshold = threshold; + this.IncludeExplainInfo = includeExplainInfo; + this.Parameters = parameters; + this.ParameterUniverse = parameterUniverse; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object obj) + { + if (obj is RecordSimilarityProperties) + { + RecordSimilarityProperties other = obj as RecordSimilarityProperties; + List conditions = new List() { + this.Threshold == other.Threshold, + this.IncludeExplainInfo == other.IncludeExplainInfo, + this.Parameters != null && other.Parameters != null ? + Utilities.DictionaryEquals(this.Parameters, other.Parameters) : this.Parameters == other.Parameters, + this.ParameterUniverse == other.ParameterUniverse + }; + return conditions.All(condition => condition); + } + else + { + return false; + } + } + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() + { + int h0 = this.Threshold.GetHashCode(); + int h1 = this.IncludeExplainInfo.GetHashCode(); + int h2 = this.Parameters != null ? this.Parameters.GetHashCode() : 1; + int h3 = this.ParameterUniverse != null ? this.ParameterUniverse.GetHashCode() : 1; + return h0 ^ h1 ^ h2 ^ h3; + } + + /// + /// ToString override. + /// + /// This record similarity properties in JSON form + public override string ToString() + { + return JsonSerializer.Serialize(this); + } + + } +} diff --git a/rosette_api/Models/RecordSimilarityRecords.cs b/rosette_api/Models/RecordSimilarityRecords.cs new file mode 100644 index 0000000..1b8f0e7 --- /dev/null +++ b/rosette_api/Models/RecordSimilarityRecords.cs @@ -0,0 +1,79 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +[JsonConverter(typeof(RecordSimilarityRecordsConverter))] +public class RecordSimilarityRecords +{ + /// + /// Gets or sets the the record similarity request's left records + /// + [JsonPropertyName("left")] + public List> Left { get; set; } + + /// + /// Gets or sets the the record similarity request's right records + /// + [JsonPropertyName("right")] + public List> Right { get; set; } + + /// + /// No-args constructor + /// + public RecordSimilarityRecords() { } + + /// + /// Full constructor + /// + /// The left records + /// The right records + public RecordSimilarityRecords(List> left, List> right) + { + this.Left = left; + this.Right = right; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object obj) + { + if (obj is RecordSimilarityRecords) + { + RecordSimilarityRecords other = obj as RecordSimilarityRecords; + List conditions = new List() { + this.Left != null && other.Left != null ? this.Left.SequenceEqual(other.Left) : this.Left == other.Left, + this.Right != null && other.Right != null ? this.Right.SequenceEqual(other.Right) : this.Right == other.Right + }; + return conditions.All(condition => condition); + } + else + { + return false; + } + } + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() + { + int h0 = this.Left != null ? this.Left.GetHashCode() : 1; + int h1 = this.Right != null ? this.Right.GetHashCode() : 1; + return h0 ^ h1; + } + + /// + /// ToString override. + /// + /// This record similarity records in JSON form + public override string ToString() + { + return JsonSerializer.Serialize(this); + } +} diff --git a/rosette_api/RosetteResponse.cs b/rosette_api/Models/Response.cs old mode 100755 new mode 100644 similarity index 96% rename from rosette_api/RosetteResponse.cs rename to rosette_api/Models/Response.cs index f52bc2d..5a6a854 --- a/rosette_api/RosetteResponse.cs +++ b/rosette_api/Models/Response.cs @@ -2,11 +2,11 @@ using System.Text; using System.Text.Json; -namespace rosette_api; +namespace Rosette.Api.Models; -public class RosetteResponse +public class Response { - public RosetteResponse(HttpResponseMessage responseMsg) { + public Response(HttpResponseMessage responseMsg) { Content = new Dictionary(); Headers = new Dictionary(); diff --git a/rosette_api/Models/StringRecord.cs b/rosette_api/Models/StringRecord.cs new file mode 100644 index 0000000..a2a0c3e --- /dev/null +++ b/rosette_api/Models/StringRecord.cs @@ -0,0 +1,51 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing a string record +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class StringRecord : RecordSimilarityField +{ + /// + /// Gets and sets the string record + /// + [JsonPropertyName("data")] + public required string Text { get; set; } + + /// + /// No-args constructor + /// + public StringRecord() + { + Text = string.Empty; + } + + /// + /// Constructor + /// + /// The string record + public StringRecord(string data) + { + ArgumentException.ThrowIfNullOrWhiteSpace(data); + Text = data; + } + + /// + /// Equals override + /// + public override bool Equals(object? obj) => + obj is StringRecord other && Text == other.Text; + + /// + /// Hashcode override + /// + public override int GetHashCode() => Text?.GetHashCode() ?? 0; + + /// + /// ToString override + /// + public override string ToString() => Text; +} \ No newline at end of file diff --git a/rosette_api/Models/UnfieldedAddressRecord.cs b/rosette_api/Models/UnfieldedAddressRecord.cs new file mode 100644 index 0000000..2f61ecd --- /dev/null +++ b/rosette_api/Models/UnfieldedAddressRecord.cs @@ -0,0 +1,54 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing an unfielded address +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class UnfieldedAddressRecord : AddressField +{ + /// + /// Gets or sets the address field's address + /// + [JsonPropertyName("address")] + public required string Address { get; set; } + + /// + /// No-args constructor + /// + public UnfieldedAddressRecord() + { + Address = string.Empty; + } + + /// + /// Full constructor + /// + /// The address in string form + public UnfieldedAddressRecord(string address) + { + ArgumentException.ThrowIfNullOrWhiteSpace(address); + Address = address; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object? obj) => + obj is UnfieldedAddressRecord other && Address == other.Address; + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() => Address?.GetHashCode() ?? 0; + + /// + /// ToString override. Also used for JSON serialization + /// + public override string ToString() => Address; +} \ No newline at end of file diff --git a/rosette_api/Models/UnfieldedDateRecord.cs b/rosette_api/Models/UnfieldedDateRecord.cs new file mode 100644 index 0000000..03aeda0 --- /dev/null +++ b/rosette_api/Models/UnfieldedDateRecord.cs @@ -0,0 +1,48 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing an unfielded date +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class UnfieldedDateRecord : DateField +{ + /// + /// No-args constructor + /// + public UnfieldedDateRecord() + { + Date = string.Empty; + } + + /// + /// Full constructor + /// + /// The date in string form + public UnfieldedDateRecord(string date) + { + ArgumentException.ThrowIfNullOrWhiteSpace(date); + Date = date; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object? obj) => + obj is UnfieldedDateRecord other && Date == other.Date; + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() => Date?.GetHashCode() ?? 0; + + /// + /// ToString override. Also used for JSON serialization + /// + public override string ToString() => Date; +} \ No newline at end of file diff --git a/rosette_api/Models/UnfieldedNameRecord.cs b/rosette_api/Models/UnfieldedNameRecord.cs new file mode 100644 index 0000000..f8dfe1d --- /dev/null +++ b/rosette_api/Models/UnfieldedNameRecord.cs @@ -0,0 +1,48 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing an unfielded name +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class UnfieldedNameRecord : NameField +{ + /// + /// No-args constructor + /// + public UnfieldedNameRecord() + { + Text = string.Empty; + } + + /// + /// Full constructor + /// + /// The name as a string + public UnfieldedNameRecord(string text) + { + ArgumentException.ThrowIfNullOrWhiteSpace(text); + Text = text; + } + + /// + /// Equals override + /// + /// The object to compare + /// True if equal + public override bool Equals(object? obj) => + obj is UnfieldedNameRecord other && Text == other.Text; + + /// + /// Hashcode override + /// + /// The hashcode + public override int GetHashCode() => Text?.GetHashCode() ?? 0; + + /// + /// ToString override. Also used for JSON serialization + /// + public override string ToString() => Text; +} \ No newline at end of file diff --git a/rosette_api/Models/UnknownFieldRecord.cs b/rosette_api/Models/UnknownFieldRecord.cs new file mode 100644 index 0000000..e359beb --- /dev/null +++ b/rosette_api/Models/UnknownFieldRecord.cs @@ -0,0 +1,43 @@ +using rosette_api.Models.JsonConverter; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace Rosette.Api.Models; + +/// +/// Class for representing an unknown field +/// +[JsonConverter(typeof(UnfieldedRecordSimilarityConverter))] +public class UnknownFieldRecord : RecordSimilarityField +{ + /// + /// Gets the unknown field's data + /// + [JsonPropertyName("data")] + public JsonNode? Data { get; } + + /// + /// Constructor + /// + /// The data as a JsonNode + public UnknownFieldRecord(JsonNode? data) + { + Data = data; + } + + /// + /// Equals override + /// + public override bool Equals(object? obj) => + obj is UnknownFieldRecord other && JsonNode.DeepEquals(Data, other.Data); + + /// + /// Hashcode override + /// + public override int GetHashCode() => Data?.GetHashCode() ?? 0; + + /// + /// ToString override + /// + public override string ToString() => Data?.ToJsonString() ?? "null"; +} \ No newline at end of file diff --git a/rosette_api/PingEndpoint.cs b/rosette_api/PingEndpoint.cs deleted file mode 100755 index a87e855..0000000 --- a/rosette_api/PingEndpoint.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace rosette_api -{ - public class PingEndpoint : EndpointCommon - { - public PingEndpoint() : base("ping") { } - - public RosetteResponse Call(RosetteAPI api) => Funcs.GetCall(api); - } -} diff --git a/rosette_api/TextEmbeddingEndpoint.cs b/rosette_api/TextEmbeddingEndpoint.cs deleted file mode 100755 index 10ba4a9..0000000 --- a/rosette_api/TextEmbeddingEndpoint.cs +++ /dev/null @@ -1,69 +0,0 @@ -namespace rosette_api -{ - public class TextEmbeddingEndpoint : EndpointCommon { - /// - /// TextEmbeddingEndpoint returns the embedding for the input text - /// - /// text, Uri object or FileStream - public TextEmbeddingEndpoint(object content) : base("text-embedding") { - SetContent(content); - } - /// - /// SetContent sets the content to be reviewed - /// - /// text, Uri object or FileStream - /// update TextEmbedding endpoint - public TextEmbeddingEndpoint SetContent(object content) { - Funcs.Content = content; - - return this; - } - - public object Content => Funcs.Content; - /// - /// SetLanguage sets the optional ISO 639-3 language code - /// - /// ISO 639-3 language code - /// updated TextEmbedding endpoint - public TextEmbeddingEndpoint SetLanguage(string language) { - Funcs.Language = language; - - return this; - } - - public string? Language => Funcs.Language; - /// - /// SetGenre sets the optional document genre, e.g. social-media - /// - /// document genre - /// updated TextEmbedding endpoint - public TextEmbeddingEndpoint SetGenre(string genre) { - Funcs.Genre = genre; - - return this; - } - - public string? Genre => Funcs.Genre; - /// - /// SetFileContentType sets the content type of the file contents. Note that - /// it only applies when the content is a filename - /// - /// Content-Type - /// updated TextEmbedding endpoint - public TextEmbeddingEndpoint SetFileContentType(string contentType) { - Funcs.FileContentType = contentType; - - return this; - } - public string FileContentType => Funcs.FileContentType; - public string Filename => Funcs.Filename; - /// - /// Call passes the data to the server and returns the response - /// - /// RosetteAPI object - /// RosetteResponse - public RosetteResponse Call(RosetteAPI api) { - return Funcs.PostCall(api); - } - } -} diff --git a/rosette_api/TokensEndpoint.cs b/rosette_api/TokensEndpoint.cs deleted file mode 100755 index e512de4..0000000 --- a/rosette_api/TokensEndpoint.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace rosette_api; - -public class TokensEndpoint : ContentBasedEndpoint { - /// - /// TokensEndpoint returns each entity extracted from the input - /// - /// text, Uri object or FileStream - public TokensEndpoint(object content) : base("tokens", content) { - } -} diff --git a/rosette_api/TopicsEndpoint.cs b/rosette_api/TopicsEndpoint.cs deleted file mode 100755 index 87096de..0000000 --- a/rosette_api/TopicsEndpoint.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace rosette_api; - -public class TopicsEndpoint : ContentBasedEndpoint { - /// - /// TopicsEndpoint returns the topic extracted from the endpoint - /// - /// text, Uri object or FileStream - public TopicsEndpoint(object content) : base("topics", content) { - } -} diff --git a/rosette_api/TransliterationEndpoint.cs b/rosette_api/TransliterationEndpoint.cs deleted file mode 100755 index 09fc723..0000000 --- a/rosette_api/TransliterationEndpoint.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace rosette_api; - -public class TransliterationEndpoint : ContentBasedEndpoint { - /// - /// TransliterationEndpoint returns the transliteration of the input - /// - /// text, Uri object or FileStream - public TransliterationEndpoint(object content) : base("transliteration", content) { - } -} diff --git a/rosette_api/Utilities.cs b/rosette_api/Utilities.cs new file mode 100644 index 0000000..b4100f9 --- /dev/null +++ b/rosette_api/Utilities.cs @@ -0,0 +1,35 @@ +namespace Rosette.Api; + +public static class Utilities +{ + /// + /// Compares two dictionaries for equality + /// + public static bool DictionaryEquals(this IDictionary first, IDictionary second) + { + if (first == null && second == null) + { + return true; + } + if (first == null || second == null) + { + return false; + } + if (first.Count != second.Count) + { + return false; + } + foreach (var kvp in first) + { + if (!second.TryGetValue(kvp.Key, out TValue secondValue)) + { + return false; + } + if (!kvp.Value.Equals(secondValue)) + { + return false; + } + } + return true; + } +} diff --git a/tests/TestAPI.cs b/tests/ApiClientTests.cs old mode 100755 new mode 100644 similarity index 82% rename from tests/TestAPI.cs rename to tests/ApiClientTests.cs index 3271e28..c1ee05a --- a/tests/TestAPI.cs +++ b/tests/ApiClientTests.cs @@ -1,99 +1,96 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestAPI - { - private static readonly string _defaultUri = "https://api.rosette.com/rest/v1/"; - private static readonly string _testKey = "testKey"; - - private static RosetteAPI Init() { - return new RosetteAPI(_testKey); - } - - [Fact] - public void TestKey() { - RosetteAPI api = Init(); - Assert.Equal(_testKey, api.APIKey); - } - - [Fact] - public void TestNullKey() { -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - string key = null; -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8604 // Possible null reference argument. - Exception ex = Assert.Throws(() => new RosetteAPI(key)); -#pragma warning restore CS8604 // Possible null reference argument. - - Assert.Equal("Value cannot be null. (Parameter 'apiKey')", ex.Message); - } - - [Fact] - public void TestURI() { - RosetteAPI api = Init(); - Assert.Equal(_defaultUri, api.URI); - - // test alternate url as well as auto append trailing slash - string alternateUrl = "https://stage.rosette.com/rest/v1"; - api.UseAlternateURL(alternateUrl); - Assert.Equal(alternateUrl + "/", api.URI); - } - - [Fact] - public void TestConnections() { - RosetteAPI api = Init(); - Assert.Equal(2, api.ConcurrentConnections); - - api.AssignConcurrentConnections(6); - Assert.Equal(6, api.ConcurrentConnections); - } - - [Fact] - public void TestValidCustomHeader() { - RosetteAPI api = Init(); - Exception ex = Assert.Throws(() => api.AddCustomHeader("BogusHeader", "BogusValue")); - - Assert.Contains(@"Custom header name must begin with 'X-RosetteAPI-'", ex.Message); - } - - [Fact] - public void TestVersion() { - Assert.NotEmpty(RosetteAPI.Version); - } - - [Fact] - public void TestTimeout() { - RosetteAPI api = Init(); - Assert.Equal(300, api.Timeout); - - api.AssignTimeout(15); - Assert.Equal(15, api.Timeout); - } - - [Fact] - public void TestDebug() { - RosetteAPI api = Init(); - Assert.False(api.Debug); - - api.SetDebug(); - Assert.True(api.Debug); - } - - [Fact] - public void TestDefaultClient() { - RosetteAPI api = Init(); - - Assert.Equal(_defaultUri, api.Client.BaseAddress.AbsoluteUri); - var acceptHeader = new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"); - Assert.Contains(acceptHeader, api.Client.DefaultRequestHeaders.Accept); - foreach (string encodingType in new List() { "gzip", "deflate" }) { - var encodingHeader = new System.Net.Http.Headers.StringWithQualityHeaderValue(encodingType); - Assert.Contains(encodingHeader, api.Client.DefaultRequestHeaders.AcceptEncoding); - } - Assert.Equal(api.Timeout, api.Client.Timeout.TotalSeconds); - } - - } -} +namespace Rosette.Api.Tests +{ + public class ApiClientTests + { + private static readonly string _defaultUri = "https://api.rosette.com/rest/v1/"; + private static readonly string _testKey = "testKey"; + + private static ApiClient Init() { + return new ApiClient(_testKey); + } + + [Fact] + public void TestKey() { + ApiClient api = Init(); + Assert.Equal(_testKey, api.APIKey); + } + + [Fact] + public void TestNullKey() { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + string key = null; +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. + Exception ex = Assert.Throws(() => new ApiClient(key)); +#pragma warning restore CS8604 // Possible null reference argument. + + Assert.Equal("Value cannot be null. (Parameter 'apiKey')", ex.Message); + } + + [Fact] + public void TestURI() { + ApiClient api = Init(); + Assert.Equal(_defaultUri, api.URI); + + // test alternate url as well as auto append trailing slash + string alternateUrl = "https://stage.rosette.com/rest/v1"; + api.UseAlternateURL(alternateUrl); + Assert.Equal(alternateUrl + "/", api.URI); + } + + [Fact] + public void TestConnections() { + ApiClient api = Init(); + Assert.Equal(2, api.ConcurrentConnections); + + api.AssignConcurrentConnections(6); + Assert.Equal(6, api.ConcurrentConnections); + } + + [Fact] + public void TestValidCustomHeader() { + ApiClient api = Init(); + Exception ex = Assert.Throws(() => api.AddCustomHeader("BogusHeader", "BogusValue")); + + Assert.Contains(@"Custom header name must begin with 'X-RosetteAPI-'", ex.Message); + } + + [Fact] + public void TestVersion() { + Assert.NotEmpty(ApiClient.Version); + } + + [Fact] + public void TestTimeout() { + ApiClient api = Init(); + Assert.Equal(300, api.Timeout); + + api.AssignTimeout(15); + Assert.Equal(15, api.Timeout); + } + + [Fact] + public void TestDebug() { + ApiClient api = Init(); + Assert.False(api.Debug); + + api.SetDebug(); + Assert.True(api.Debug); + } + + [Fact] + public void TestDefaultClient() { + ApiClient api = Init(); + + Assert.Equal(_defaultUri, api.Client.BaseAddress.AbsoluteUri); + var acceptHeader = new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"); + Assert.Contains(acceptHeader, api.Client.DefaultRequestHeaders.Accept); + foreach (string encodingType in new List() { "gzip", "deflate" }) { + var encodingHeader = new System.Net.Http.Headers.StringWithQualityHeaderValue(encodingType); + Assert.Contains(encodingHeader, api.Client.DefaultRequestHeaders.AcceptEncoding); + } + Assert.Equal(api.Timeout, api.Client.Timeout.TotalSeconds); + } + + } +} diff --git a/tests/CategoriesTests.cs b/tests/CategoriesTests.cs new file mode 100644 index 0000000..509ae84 --- /dev/null +++ b/tests/CategoriesTests.cs @@ -0,0 +1,48 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class CategoriesTests + { + [Fact] + public void CheckBasicUsage() + { + Categories c = new Categories("Sample text for categorization"); + + Assert.Equal("categories", c.Endpoint); + Assert.Equal("Sample text for categorization", c.Content); + } + + [Fact] + public void CheckWithLanguage() + { + Categories c = new Categories("Sample text") + .SetLanguage("eng"); + + Assert.Equal("eng", c.Language); + Assert.Equal("Sample text", c.Content); + } + + [Fact] + public void CheckWithGenre() + { + Categories c = new Categories("Sample text") + .SetGenre("social-media"); + + Assert.Equal("social-media", c.Genre); + } + + [Fact] + public void CheckFluentAPI() + { + Categories c = new Categories("Sample text") + .SetLanguage("eng") + .SetGenre("social-media") + .SetOption("customOption", "value"); + + Assert.Equal("eng", c.Language); + Assert.Equal("social-media", c.Genre); + Assert.Equal("value", c.Options["customOption"]); + } + } +} \ No newline at end of file diff --git a/tests/TestEndpointCommon.cs b/tests/EndpointBaseTests.cs old mode 100755 new mode 100644 similarity index 62% rename from tests/TestEndpointCommon.cs rename to tests/EndpointBaseTests.cs index d58fc72..de099cf --- a/tests/TestEndpointCommon.cs +++ b/tests/EndpointBaseTests.cs @@ -1,18 +1,18 @@ -using rosette_api; -using Xunit; +using Rosette.Api.Endpoints; +using Rosette.Api.Endpoints.Core; -namespace tests { - public class TestEndpointCommon +namespace Rosette.Api.Tests { + public class EndpointBaseTests { - private static RosetteAPI Init() { - return new RosetteAPI("testkey"); + private static ApiClient Init() { + return new ApiClient("testkey"); } [Fact] public void CheckEndpoint() { - EndpointCommon ec = new EndpointCommon("foo"); + EndpointBase ec = new EndpointBase("foo"); Assert.Equal("foo", ec.Endpoint); } @@ -20,7 +20,7 @@ public void CheckEndpoint() { [Fact] public void CheckOptions() { - EntitiesEndpoint e = new EntitiesEndpoint("foo").SetOption("test", "value"); + Entities e = new Entities("foo").SetOption("test", "value"); Assert.Equal("value", e.Options["test"]); @@ -39,7 +39,7 @@ public void CheckOptions() { [Fact] public void CheckUrlParameters() { - EntitiesEndpoint e = new EntitiesEndpoint("foo").SetUrlParameter("test", "value"); + Entities e = new Entities("foo").SetUrlParameter("test", "value"); Assert.Equal("value", e.UrlParameters["test"]); diff --git a/tests/TestEndpointFunctions.cs b/tests/EndpointExecutorTests.cs old mode 100755 new mode 100644 similarity index 71% rename from tests/TestEndpointFunctions.cs rename to tests/EndpointExecutorTests.cs index f4fbf71..466c506 --- a/tests/TestEndpointFunctions.cs +++ b/tests/EndpointExecutorTests.cs @@ -1,140 +1,140 @@ -using Xunit; -using RichardSzalay.MockHttp; -using System.Collections.Specialized; -using System.Net; -using System.Text.Json; -using rosette_api; - -namespace tests -{ - public class TestEndpointFunctions - { - private readonly Dictionary _params; - private readonly Dictionary _options; - private readonly NameValueCollection _urlParameters; - private static readonly string _defaultUri = "https://api.rosette.com/rest/v1/*"; - - public TestEndpointFunctions() { - _params = new Dictionary(); - _options = new Dictionary(); - _urlParameters = new NameValueCollection(); - } - - [Fact] - public void CheckContent() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Empty(f.Content.ToString()!); - f.Content = "Sample Content"; - Assert.Equal("Sample Content", f.Content); - Assert.True(_params.ContainsKey("content")); - Assert.False(_params.ContainsKey("contenturi")); - } - - [Fact] - public void CheckEndpoint() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Equal("test", f.Endpoint); - } - - [Fact] - public void CheckContentUri() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Empty(f.Content.ToString()!); - f.Content = new Uri("http://google.com"); - Assert.Equal("http://google.com/", f.Content); - Assert.True(_params.ContainsKey("contenturi")); - Assert.False(_params.ContainsKey("content")); - } - - [Fact] - public void CheckFilename() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Empty(f.Content.ToString()!); - var newFile = Path.GetTempFileName(); - using (FileStream fs = File.OpenRead(newFile)) { - f.Content = fs; - Assert.Equal(newFile, f.Filename); - Assert.Empty(f.Content.ToString()!); - Assert.False(_params.ContainsKey("content")); - Assert.False(_params.ContainsKey("contenturi")); - } - } - - [Fact] - public void CheckLanguage() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Empty(f.Language!); - f.Language = "eng"; - Assert.Equal("eng", f.Language); - } - - [Fact] - public void CheckGenre() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Empty(f.Genre!); - f.Genre = "social-media"; - Assert.Equal("social-media", f.Genre); - } - - [Fact] - public void CheckFileContentType() { - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - Assert.Equal("text/plain", f.FileContentType); - f.FileContentType = "octet/stream"; - Assert.Equal("octet/stream", f.FileContentType); - } - - [Fact] - public void TestParameterSerialization() { - RosetteAPI api = new RosetteAPI("testkey"); - var mockHttp = new MockHttpMessageHandler(); - mockHttp.When(_defaultUri) - .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); - var client = mockHttp.ToHttpClient(); - - api.AssignClient(client); - - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - - _options["opt"] = true; - Dictionary paramTest = new Dictionary(); - paramTest["content"] = "Test Content"; - paramTest["options"] = _options; - - f.Content = "Test Content"; - RosetteResponse result = f.PostCall(api); - Assert.Equal(JsonSerializer.Serialize(paramTest), JsonSerializer.Serialize(f.Parameters)); - } - - [Fact] - public void TestPostCall() { - RosetteAPI api = new RosetteAPI("testkey"); - var mockHttp = new MockHttpMessageHandler(); - mockHttp.When(_defaultUri) - .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); - var client = mockHttp.ToHttpClient(); - - api.AssignClient(client); - - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - f.Content = "Test content"; - RosetteResponse result = f.PostCall(api); - Assert.Equal((int)HttpStatusCode.OK, result.StatusCode); - } - - [Fact] - public void TestGetCall() { - RosetteAPI api = new RosetteAPI("testkey"); - var mockHttp = new MockHttpMessageHandler(); - mockHttp.When(_defaultUri) - .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); - var client = mockHttp.ToHttpClient(); - - api.AssignClient(client); - - EndpointFunctions f = new EndpointFunctions(_params, _options, _urlParameters, "test"); - RosetteResponse result = f.GetCall(api); - Assert.Equal((int)HttpStatusCode.OK, result.StatusCode); - } - } -} +using RichardSzalay.MockHttp; +using System.Collections.Specialized; +using System.Net; +using System.Text.Json; +using Rosette.Api.Endpoints.Core; +using Rosette.Api.Models; + +namespace Rosette.Api.Tests +{ + public class EndpointExecutorTests + { + private readonly Dictionary _params; + private readonly Dictionary _options; + private readonly NameValueCollection _urlParameters; + private static readonly string _defaultUri = "https://api.rosette.com/rest/v1/*"; + + public EndpointExecutorTests() { + _params = new Dictionary(); + _options = new Dictionary(); + _urlParameters = new NameValueCollection(); + } + + [Fact] + public void CheckContent() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Empty(f.Content.ToString()!); + f.Content = "Sample Content"; + Assert.Equal("Sample Content", f.Content); + Assert.True(_params.ContainsKey("content")); + Assert.False(_params.ContainsKey("contenturi")); + } + + [Fact] + public void CheckEndpoint() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Equal("test", f.Endpoint); + } + + [Fact] + public void CheckContentUri() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Empty(f.Content.ToString()!); + f.Content = new Uri("http://google.com"); + Assert.Equal("http://google.com/", f.Content); + Assert.True(_params.ContainsKey("contenturi")); + Assert.False(_params.ContainsKey("content")); + } + + [Fact] + public void CheckFilename() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Empty(f.Content.ToString()!); + var newFile = Path.GetTempFileName(); + using (FileStream fs = File.OpenRead(newFile)) { + f.Content = fs; + Assert.Equal(newFile, f.Filename); + Assert.Empty(f.Content.ToString()!); + Assert.False(_params.ContainsKey("content")); + Assert.False(_params.ContainsKey("contenturi")); + } + } + + [Fact] + public void CheckLanguage() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Empty(f.Language!); + f.Language = "eng"; + Assert.Equal("eng", f.Language); + } + + [Fact] + public void CheckGenre() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Empty(f.Genre!); + f.Genre = "social-media"; + Assert.Equal("social-media", f.Genre); + } + + [Fact] + public void CheckFileContentType() { + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Assert.Equal("text/plain", f.FileContentType); + f.FileContentType = "octet/stream"; + Assert.Equal("octet/stream", f.FileContentType); + } + + [Fact] + public void TestParameterSerialization() { + ApiClient api = new ApiClient("testkey"); + var mockHttp = new MockHttpMessageHandler(); + mockHttp.When(_defaultUri) + .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); + var client = mockHttp.ToHttpClient(); + + api.AssignClient(client); + + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + + _options["opt"] = true; + Dictionary paramTest = new Dictionary(); + paramTest["content"] = "Test Content"; + paramTest["options"] = _options; + + f.Content = "Test Content"; + Response result = f.PostCall(api); + Assert.Equal(JsonSerializer.Serialize(paramTest), JsonSerializer.Serialize(f.Parameters)); + } + + [Fact] + public void TestPostCall() { + ApiClient api = new ApiClient("testkey"); + var mockHttp = new MockHttpMessageHandler(); + mockHttp.When(_defaultUri) + .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); + var client = mockHttp.ToHttpClient(); + + api.AssignClient(client); + + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + f.Content = "Test content"; + Response result = f.PostCall(api); + Assert.Equal((int)HttpStatusCode.OK, result.StatusCode); + } + + [Fact] + public void TestGetCall() { + ApiClient api = new ApiClient("testkey"); + var mockHttp = new MockHttpMessageHandler(); + mockHttp.When(_defaultUri) + .Respond(HttpStatusCode.OK, "application/json", "{\"test\": \"OK\"}"); + var client = mockHttp.ToHttpClient(); + + api.AssignClient(client); + + EndpointExecutor f = new EndpointExecutor(_params, _options, _urlParameters, "test"); + Response result = f.GetCall(api); + Assert.Equal((int)HttpStatusCode.OK, result.StatusCode); + } + } +} diff --git a/tests/EntitiesTests.cs b/tests/EntitiesTests.cs new file mode 100644 index 0000000..600d40a --- /dev/null +++ b/tests/EntitiesTests.cs @@ -0,0 +1,51 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class EntitiesTests + { + [Fact] + public void CheckBasicUsage() + { + string text = "Bill Murray will appear in new Ghostbusters film."; + Entities e = new Entities(text); + + Assert.Equal("entities", e.Endpoint); + Assert.Equal(text, e.Content); + } + + [Fact] + public void CheckWithLanguageAndGenre() + { + Entities e = new Entities("Sample text") + .SetLanguage("eng") + .SetGenre("social-media"); + + Assert.Equal("eng", e.Language); + Assert.Equal("", e.Genre); + } + + [Fact] + public void CheckWithUrlParameter() + { + Entities e = new Entities("Sample text") + .SetUrlParameter("output", "rosette"); + + Assert.Equal("rosette", e.UrlParameters["output"]); + } + + [Fact] + public void CheckFluentAPI() + { + Entities e = new Entities("Apple announced a new iPhone.") + .SetLanguage("eng") + .SetGenre("news") + .SetOption("linkEntities", true) + .SetUrlParameter("output", "rosette"); + + Assert.Equal("eng", e.Language); + Assert.True((bool)e.Options["linkEntities"]); + Assert.Equal("rosette", e.UrlParameters["output"]); + } + } +} \ No newline at end of file diff --git a/tests/LanguageTests.cs b/tests/LanguageTests.cs new file mode 100644 index 0000000..d020baa --- /dev/null +++ b/tests/LanguageTests.cs @@ -0,0 +1,43 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class LanguageTests + { + [Fact] + public void CheckBasicUsage() + { + Language l = new Language("Por favor Señorita, says the man."); + + Assert.Equal("language", l.Endpoint); + Assert.Equal("Por favor Señorita, says the man.", l.Content); + } + + [Fact] + public void CheckWithUri() + { + Uri uri = new Uri("http://example.com"); + Language l = new Language(uri); + + Assert.Equal("http://example.com/", l.Content.ToString()); + } + + [Fact] + public void CheckContentUpdate() + { + Language l = new Language("Original text") + .SetContent("Updated text"); + + Assert.Equal("Updated text", l.Content); + } + + [Fact] + public void CheckWithGenre() + { + Language l = new Language("Sample text") + .SetGenre("social-media"); + + Assert.Equal("social-media", l.Genre); + } + } +} \ No newline at end of file diff --git a/tests/NameDeduplicationTests.cs b/tests/NameDeduplicationTests.cs new file mode 100644 index 0000000..9b382a7 --- /dev/null +++ b/tests/NameDeduplicationTests.cs @@ -0,0 +1,41 @@ +using Rosette.Api.Endpoints; +using Rosette.Api.Models; + +namespace Rosette.Api.Tests +{ + public class NameDeduplicationTests + { + [Fact] + public void CheckBasicUsage() { + List names = new List { + new Name("foo"), + new Name("bar") + }; + NameDeduplication n = new NameDeduplication(names); + Assert.Equal(names, n.Names); + Assert.Equal(0.75f, n.Threshold); + } + + [Fact] + public void CheckProfileID() { + List names = new List { + new Name("foo"), + new Name("bar") + }; + NameDeduplication n = new NameDeduplication(names).SetProfileID("profileid"); + Assert.Equal(names, n.Names); + Assert.Equal("profileid", n.ProfileID); + } + + [Fact] + public void CheckThreshold() { + List names = new List { + new Name("foo"), + new Name("bar") + }; + NameDeduplication n = new NameDeduplication(names).SetThreshold(0.8f); + Assert.Equal(names, n.Names); + Assert.Equal(0.8f, n.Threshold); + } + } +} diff --git a/tests/TestNameSimilarity.cs b/tests/NameSimilarityTests.cs old mode 100755 new mode 100644 similarity index 70% rename from tests/TestNameSimilarity.cs rename to tests/NameSimilarityTests.cs index b9834e4..ce17caa --- a/tests/TestNameSimilarity.cs +++ b/tests/NameSimilarityTests.cs @@ -1,20 +1,20 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestNameSimilarity - { - [Fact] - public void CheckForNull() { - var exception = Record.Exception(() => new NameSimilarityEndpoint(null, null)); - Assert.IsType(exception); - Assert.Equal("Value cannot be null. (Parameter 'name1')", exception.Message); - - RosetteName rn = new RosetteName("foo"); - exception = Record.Exception(() => new NameSimilarityEndpoint(rn, null)); - Assert.IsType(exception); - Assert.Equal("Value cannot be null. (Parameter 'name2')", exception.Message); - } - } -} +using Rosette.Api.Endpoints; +using Rosette.Api.Models; + +namespace Rosette.Api.Tests +{ + public class NameSimilarityTests + { + [Fact] + public void CheckForNull() { + var exception = Record.Exception(() => new NameSimilarity(null, null)); + Assert.IsType(exception); + Assert.Equal("Value cannot be null. (Parameter 'name1')", exception.Message); + + Name rn = new Name("foo"); + exception = Record.Exception(() => new NameSimilarity(rn, null)); + Assert.IsType(exception); + Assert.Equal("Value cannot be null. (Parameter 'name2')", exception.Message); + } + } +} diff --git a/tests/TestRosetteName.cs b/tests/NameTests.cs old mode 100755 new mode 100644 similarity index 69% rename from tests/TestRosetteName.cs rename to tests/NameTests.cs index 2648aba..df7d178 --- a/tests/TestRosetteName.cs +++ b/tests/NameTests.cs @@ -1,50 +1,49 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestRosetteName - { - [Fact] - public void CheckName() { - RosetteName rn = new RosetteName("foo"); - Assert.Equal("foo", rn.Text); - Assert.Null(rn.EntityType); - Assert.Null(rn.Language); - Assert.Null(rn.Script); - } - - [Fact] - public void CheckWithEntityType() { - RosetteName rn = new RosetteName("foo").SetEntityType("PERSON"); - Assert.Equal("foo", rn.Text); - Assert.Equal("PERSON", rn.EntityType); - } - - [Fact] - public void CheckWithLanguage() { - RosetteName rn = new RosetteName("foo").SetLanguage("eng"); - Assert.Equal("foo", rn.Text); - Assert.Equal("eng", rn.Language); - } - - [Fact] - public void CheckWithScript() { - RosetteName rn = new RosetteName("foo").SetScript("zho"); - Assert.Equal("foo", rn.Text); - Assert.Equal("zho", rn.Script); - } - - [Fact] - public void CheckAll() { - RosetteName rn = new RosetteName("foo") - .SetEntityType("PERSON") - .SetLanguage("eng") - .SetScript("zho"); - Assert.Equal("foo", rn.Text); - Assert.Equal("PERSON", rn.EntityType); - Assert.Equal("eng", rn.Language); - Assert.Equal("zho", rn.Script); - } - } -} +using Rosette.Api.Models; + +namespace Rosette.Api.Tests +{ + public class NameTests + { + [Fact] + public void CheckName() { + Name rn = new Name("foo"); + Assert.Equal("foo", rn.Text); + Assert.Null(rn.EntityType); + Assert.Null(rn.Language); + Assert.Null(rn.Script); + } + + [Fact] + public void CheckWithEntityType() { + Name rn = new Name("foo").SetEntityType("PERSON"); + Assert.Equal("foo", rn.Text); + Assert.Equal("PERSON", rn.EntityType); + } + + [Fact] + public void CheckWithLanguage() { + Name rn = new Name("foo").SetLanguage("eng"); + Assert.Equal("foo", rn.Text); + Assert.Equal("eng", rn.Language); + } + + [Fact] + public void CheckWithScript() { + Name rn = new Name("foo").SetScript("zho"); + Assert.Equal("foo", rn.Text); + Assert.Equal("zho", rn.Script); + } + + [Fact] + public void CheckAll() { + Name rn = new Name("foo") + .SetEntityType("PERSON") + .SetLanguage("eng") + .SetScript("zho"); + Assert.Equal("foo", rn.Text); + Assert.Equal("PERSON", rn.EntityType); + Assert.Equal("eng", rn.Language); + Assert.Equal("zho", rn.Script); + } + } +} diff --git a/tests/TestNameTranslation.cs b/tests/NameTranslationTests.cs old mode 100755 new mode 100644 similarity index 81% rename from tests/TestNameTranslation.cs rename to tests/NameTranslationTests.cs index 5d32c3d..164e277 --- a/tests/TestNameTranslation.cs +++ b/tests/NameTranslationTests.cs @@ -1,42 +1,41 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestNameTranslation - { - [Fact] - public void CheckBasicUsage() { - NameTranslationEndpoint n = new NameTranslationEndpoint("foo"); - Assert.Equal("foo", n.Name); - Assert.Equal("eng", n.TargetLanguage); - Assert.Empty(n.EntityType); - Assert.Empty(n.SourceLanguageOfOrigin); - Assert.Empty(n.SourceLanguageOfUse); - Assert.Empty(n.SourceScript); - Assert.Empty(n.TargetScheme); - Assert.Empty(n.TargetScript); - } - - [Fact] - public void CheckAllUsage() { - NameTranslationEndpoint n = new NameTranslationEndpoint("foo") - .SetEntityType("PERSON") - .SetSourceLanguageOfOrigin("eng") - .SetSourceLanguageOfUse("eng") - .SetSourceScript("zho") - .SetTargetLanguage("spa") - .SetTargetScheme("BGN") - .SetTargetScript("eng"); - Assert.Equal("foo", n.Name); - Assert.Equal("spa", n.TargetLanguage); - Assert.Equal("PERSON", n.EntityType); - Assert.Equal("eng", n.SourceLanguageOfOrigin); - Assert.Equal("eng", n.SourceLanguageOfUse); - Assert.Equal("zho", n.SourceScript); - Assert.Equal("BGN", n.TargetScheme); - Assert.Equal("eng", n.TargetScript); - } - - } -} +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class NameTranslationTests + { + [Fact] + public void CheckBasicUsage() { + NameTranslation n = new NameTranslation("foo"); + Assert.Equal("foo", n.Name); + Assert.Equal("eng", n.TargetLanguage); + Assert.Empty(n.EntityType); + Assert.Empty(n.SourceLanguageOfOrigin); + Assert.Empty(n.SourceLanguageOfUse); + Assert.Empty(n.SourceScript); + Assert.Empty(n.TargetScheme); + Assert.Empty(n.TargetScript); + } + + [Fact] + public void CheckAllUsage() { + NameTranslation n = new NameTranslation("foo") + .SetEntityType("PERSON") + .SetSourceLanguageOfOrigin("eng") + .SetSourceLanguageOfUse("eng") + .SetSourceScript("zho") + .SetTargetLanguage("spa") + .SetTargetScheme("BGN") + .SetTargetScript("eng"); + Assert.Equal("foo", n.Name); + Assert.Equal("spa", n.TargetLanguage); + Assert.Equal("PERSON", n.EntityType); + Assert.Equal("eng", n.SourceLanguageOfOrigin); + Assert.Equal("eng", n.SourceLanguageOfUse); + Assert.Equal("zho", n.SourceScript); + Assert.Equal("BGN", n.TargetScheme); + Assert.Equal("eng", n.TargetScript); + } + + } +} diff --git a/tests/RelationshipsTests.cs b/tests/RelationshipsTests.cs new file mode 100644 index 0000000..9c73dc2 --- /dev/null +++ b/tests/RelationshipsTests.cs @@ -0,0 +1,39 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class RelationshipsTests + { + [Fact] + public void CheckBasicUsage() + { + string text = "John works at Microsoft."; + Relationships r = new Relationships(text); + + Assert.Equal("relationships", r.Endpoint); + Assert.Equal(text, r.Content); + } + + [Fact] + public void CheckWithLanguage() + { + Relationships r = new Relationships("Sample text") + .SetLanguage("eng"); + + Assert.Equal("eng", r.Language); + } + + [Fact] + public void CheckFluentAPI() + { + Relationships r = new Relationships("Sample relationship text.") + .SetLanguage("eng") + .SetGenre("news") + .SetOption("accuracy", "high"); + + Assert.Equal("eng", r.Language); + Assert.Equal("news", r.Genre); + Assert.Equal("high", r.Options["accuracy"]); + } + } +} \ No newline at end of file diff --git a/tests/TestRosetteResponse.cs b/tests/ResponseTests.cs old mode 100755 new mode 100644 similarity index 79% rename from tests/TestRosetteResponse.cs rename to tests/ResponseTests.cs index 6b592c2..1348bcb --- a/tests/TestRosetteResponse.cs +++ b/tests/ResponseTests.cs @@ -1,29 +1,28 @@ -using Xunit; -using System.Net; -using System.Text.Json; -using rosette_api; - -namespace tests -{ - public class TestRosetteResponse - { - [Fact] - public void CheckStatusOK() { - Dictionary data = new Dictionary { - { "content", "Some sample content" }, - { "language", "eng" } - }; - string json = JsonSerializer.Serialize(data); - - HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.OK); - msg.Content = new StringContent(json); - msg.Headers.Add("Test-Header", "Test Header Content"); - - RosetteResponse response = new RosetteResponse(msg); - - Assert.Equal((int)HttpStatusCode.OK, response.StatusCode); - Assert.Equal(json, response.ContentAsJson()); - - } - } -} +using Rosette.Api.Models; +using System.Net; +using System.Text.Json; + +namespace Rosette.Api.Tests +{ + public class ResponseTests + { + [Fact] + public void CheckStatusOK() { + Dictionary data = new Dictionary { + { "content", "Some sample content" }, + { "language", "eng" } + }; + string json = JsonSerializer.Serialize(data); + + HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.OK); + msg.Content = new StringContent(json); + msg.Headers.Add("Test-Header", "Test Header Content"); + + Response response = new Response(msg); + + Assert.Equal((int)HttpStatusCode.OK, response.StatusCode); + Assert.Equal(json, response.ContentAsJson()); + + } + } +} diff --git a/tests/SentencesTests.cs b/tests/SentencesTests.cs new file mode 100644 index 0000000..892e669 --- /dev/null +++ b/tests/SentencesTests.cs @@ -0,0 +1,37 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class SentencesTests + { + [Fact] + public void CheckBasicUsage() + { + string text = "This is the first sentence. This is the second sentence."; + Sentences s = new Sentences(text); + + Assert.Equal("sentences", s.Endpoint); + Assert.Equal(text, s.Content); + } + + [Fact] + public void CheckWithLanguage() + { + Sentences s = new Sentences("Sample text.") + .SetLanguage("eng"); + + Assert.Equal("eng", s.Language); + } + + [Fact] + public void CheckFluentAPI() + { + Sentences s = new Sentences("Text content.") + .SetLanguage("eng") + .SetGenre("news"); + + Assert.Equal("eng", s.Language); + Assert.Equal("news", s.Genre); + } + } +} \ No newline at end of file diff --git a/tests/SentimentTests.cs b/tests/SentimentTests.cs new file mode 100644 index 0000000..614829f --- /dev/null +++ b/tests/SentimentTests.cs @@ -0,0 +1,48 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class SentimentTests + { + [Fact] + public void CheckBasicUsage() + { + Sentiment s = new Sentiment("This is a great product!"); + + Assert.Equal("sentiment", s.Endpoint); + Assert.Equal("This is a great product!", s.Content); + } + + [Fact] + public void CheckWithLanguage() + { + Sentiment s = new Sentiment("Sample text") + .SetLanguage("eng"); + + Assert.Equal("eng", s.Language); + Assert.Equal("Sample text", s.Content); + } + + [Fact] + public void CheckWithGenre() + { + Sentiment s = new Sentiment("Sample text") + .SetGenre("social-media"); + + Assert.Equal("social-media", s.Genre); + } + + [Fact] + public void CheckFluentAPI() + { + Sentiment s = new Sentiment("Great service!") + .SetLanguage("eng") + .SetGenre("review") + .SetOption("sentiment.threshold", 0.5); + + Assert.Equal("eng", s.Language); + Assert.Equal("review", s.Genre); + Assert.Equal(0.5, s.Options["sentiment.threshold"]); + } + } +} \ No newline at end of file diff --git a/tests/SimilarTermsTests.cs b/tests/SimilarTermsTests.cs new file mode 100644 index 0000000..b410a45 --- /dev/null +++ b/tests/SimilarTermsTests.cs @@ -0,0 +1,37 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class SimilarTermsTests + { + [Fact] + public void CheckBasicUsage() + { + SimilarTerms st = new SimilarTerms("happy"); + + Assert.Equal("semantics/similar", st.Endpoint); + Assert.Equal("happy", st.Content); + } + + [Fact] + public void CheckWithLanguage() + { + SimilarTerms st = new SimilarTerms("computer") + .SetLanguage("eng"); + + Assert.Equal("eng", st.Language); + Assert.Equal("computer", st.Content); + } + + [Fact] + public void CheckFluentAPI() + { + SimilarTerms st = new SimilarTerms("innovation") + .SetLanguage("eng") + .SetOption("count", 10); + + Assert.Equal("eng", st.Language); + Assert.Equal(10, st.Options["count"]); + } + } +} \ No newline at end of file diff --git a/tests/TestForValidEndpoint.cs b/tests/TestForValidEndpoint.cs deleted file mode 100755 index 08dee56..0000000 --- a/tests/TestForValidEndpoint.cs +++ /dev/null @@ -1,124 +0,0 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestForValidEndpoint - { - [Fact] - public void CategoriesEndpoint() { - CategoriesEndpoint c = new CategoriesEndpoint("foo"); - - Assert.Equal("categories", c.Endpoint); - Assert.Equal("foo", c.Content); - } - [Fact] - public void EntitiesEndpoint() { - EntitiesEndpoint e = new EntitiesEndpoint("foo"); - Assert.Equal("entities", e.Endpoint); - Assert.Equal("foo", e.Content); - } - - [Fact] - public void InfoEndpoint() { - InfoEndpoint i = new InfoEndpoint(); - Assert.Equal("info", i.Endpoint); - } - - [Fact] - public void LanguageEndpoint() { - LanguageEndpoint l = new LanguageEndpoint("foo"); - - Assert.Equal("language", l.Endpoint); - Assert.Equal("foo", l.Content); - } - - [Theory] - [InlineData(rosette_api.MorphologyFeature.complete)] - [InlineData(rosette_api.MorphologyFeature.compoundComponents)] - [InlineData(rosette_api.MorphologyFeature.hanReadings)] - [InlineData(rosette_api.MorphologyFeature.lemmas)] - [InlineData(rosette_api.MorphologyFeature.partsOfSpeech)] - public void MorphologyEndpoint(MorphologyFeature feature) { - MorphologyEndpoint m = new MorphologyEndpoint("foo", feature); - - Assert.Equal("morphology/" + m.FeatureAsString(feature), m.Endpoint); - Assert.Equal("foo", m.Content); - } - - [Fact] - public void NameSimilarityEndpoint() { - RosetteName rn = new RosetteName("foo"); - NameSimilarityEndpoint ns = new NameSimilarityEndpoint(rn, rn); - Assert.Equal("name-similarity", ns.Endpoint); - } - - [Fact] - public void PingEndpoint() { - PingEndpoint p = new PingEndpoint(); - Assert.Equal("ping", p.Endpoint); - } - - [Fact] - public void RelationshipsEndpoint() { - RelationshipsEndpoint r = new RelationshipsEndpoint("foo"); - - Assert.Equal("relationships", r.Endpoint); - Assert.Equal("foo", r.Content); - } - - [Fact] - public void SentencesEndpoint() { - SentencesEndpoint s = new SentencesEndpoint("foo"); - Assert.Equal("sentences", s.Endpoint); - Assert.Equal("foo", s.Content); - } - - [Fact] - public void SentimentEndpoint() { - SentimentEndpoint s = new SentimentEndpoint("foo"); - Assert.Equal("sentiment", s.Endpoint); - Assert.Equal("foo", s.Content); - } - - [Fact] - public void SyntaxDependenciesEndpoint() { - SyntaxDependenciesEndpoint s = new SyntaxDependenciesEndpoint("foo"); - - Assert.Equal("syntax/dependencies", s.Endpoint); - Assert.Equal("foo", s.Content); - } - - [Fact] - public void TextEmbeddingEndpoint() { - TextEmbeddingEndpoint t = new TextEmbeddingEndpoint("foo"); - - Assert.Equal("text-embedding", t.Endpoint); - Assert.Equal("foo", t.Content); - } - - [Fact] - public void TokensEndpoint() { - TokensEndpoint t = new TokensEndpoint("foo"); - - Assert.Equal("tokens", t.Endpoint); - Assert.Equal("foo", t.Content); - } - - [Fact] - public void TopicsEndpoint() { - TopicsEndpoint t = new TopicsEndpoint("foo"); - - Assert.Equal("topics", t.Endpoint); - Assert.Equal("foo", t.Content); - } - - [Fact] - public void TransliterationEndpoint() { - TransliterationEndpoint t = new TransliterationEndpoint("foo"); - - Assert.Equal("transliteration", t.Endpoint); - Assert.Equal("foo", t.Content); - } - } -} diff --git a/tests/TestNameDeduplication.cs b/tests/TestNameDeduplication.cs deleted file mode 100755 index 68d6bf1..0000000 --- a/tests/TestNameDeduplication.cs +++ /dev/null @@ -1,41 +0,0 @@ -using rosette_api; -using Xunit; - -namespace tests -{ - public class TestNameDeduplication - { - [Fact] - public void CheckBasicUsage() { - List names = new List { - new RosetteName("foo"), - new RosetteName("bar") - }; - NameDeduplicationEndpoint n = new NameDeduplicationEndpoint(names); - Assert.Equal(names, n.Names); - Assert.Equal(0.75f, n.Threshold); - } - - [Fact] - public void CheckProfileID() { - List names = new List { - new RosetteName("foo"), - new RosetteName("bar") - }; - NameDeduplicationEndpoint n = new NameDeduplicationEndpoint(names).SetProfileID("profileid"); - Assert.Equal(names, n.Names); - Assert.Equal("profileid", n.ProfileID); - } - - [Fact] - public void CheckThreshold() { - List names = new List { - new RosetteName("foo"), - new RosetteName("bar") - }; - NameDeduplicationEndpoint n = new NameDeduplicationEndpoint(names).SetThreshold(0.8f); - Assert.Equal(names, n.Names); - Assert.Equal(0.8f, n.Threshold); - } - } -} diff --git a/tests/TokensTests.cs b/tests/TokensTests.cs new file mode 100644 index 0000000..3dfe7ee --- /dev/null +++ b/tests/TokensTests.cs @@ -0,0 +1,36 @@ +using Rosette.Api.Endpoints; + +namespace Rosette.Api.Tests +{ + public class TokensTests + { + [Fact] + public void CheckBasicUsage() + { + Tokens t = new Tokens("This is sample text"); + + Assert.Equal("tokens", t.Endpoint); + Assert.Equal("This is sample text", t.Content); + } + + [Fact] + public void CheckWithLanguage() + { + Tokens t = new Tokens("Sample text") + .SetLanguage("eng"); + + Assert.Equal("eng", t.Language); + } + + [Fact] + public void CheckFluentAPI() + { + Tokens t = new Tokens("Sample text") + .SetLanguage("jpn") + .SetGenre("social-media"); + + Assert.Equal("jpn", t.Language); + Assert.Equal("social-media", t.Genre); + } + } +} \ No newline at end of file diff --git a/tests/ValidEndpointTests.cs b/tests/ValidEndpointTests.cs new file mode 100644 index 0000000..a5f01b2 --- /dev/null +++ b/tests/ValidEndpointTests.cs @@ -0,0 +1,207 @@ +using Rosette.Api.Endpoints; +using Rosette.Api.Models; + +namespace Rosette.Api.Tests +{ + public class ValidEndpointTests + { + + [Fact] + public void AddressSimilarityEndpoint() + { + var a = new UnfieldedAddressRecord { Address = "foo" }; + + AddressSimilarity asim = new AddressSimilarity(a,a); + Assert.Equal("address-similarity", asim.Endpoint); + } + + [Fact] + public void CategoriesEndpoint() + { + Categories c = new Categories("foo"); + + Assert.Equal("categories", c.Endpoint); + Assert.Equal("foo", c.Content); + } + + [Fact] + public void EntitiesEndpoint() + { + Entities e = new Entities("foo"); + Assert.Equal("entities", e.Endpoint); + Assert.Equal("foo", e.Content); + } + + [Fact] + public void EventsEndpoint() + { + Events e = new Events("foo"); + Assert.Equal("events", e.Endpoint); + Assert.Equal("foo", e.Content); + } + + [Fact] + public void InfoEndpoint() + { + Info i = new Info(); + Assert.Equal("info", i.Endpoint); + } + + [Fact] + public void LanguageEndpoint() + { + Language l = new Language("foo"); + + Assert.Equal("language", l.Endpoint); + Assert.Equal("foo", l.Content); + } + + [Theory] + [InlineData(MorphologyFeature.complete)] + [InlineData(MorphologyFeature.compoundComponents)] + [InlineData(MorphologyFeature.hanReadings)] + [InlineData(MorphologyFeature.lemmas)] + [InlineData(MorphologyFeature.partsOfSpeech)] + public void MorphologyEndpoint(MorphologyFeature feature) + { + Morphology m = new Morphology("foo", feature); + + Assert.Equal("morphology/" + m.FeatureAsString(feature), m.Endpoint); + Assert.Equal("foo", m.Content); + } + + [Fact] + public void NameDeduplicationEndpoint() + { + List names = [ + new Name("foo"), + new Name("bar") + ]; + NameDeduplication nd = new NameDeduplication(names); + + Assert.Equal("name-deduplication", nd.Endpoint); + } + + [Fact] + public void NameSimilarityEndpoint() + { + Name rn = new Name("foo"); + NameSimilarity ns = new NameSimilarity(rn, rn); + Assert.Equal("name-similarity", ns.Endpoint); + } + + [Fact] + public void NameTranslationEndpoint() + { + NameTranslation nt = new NameTranslation("foo"); + + Assert.Equal("name-translation", nt.Endpoint); + } + + [Fact] + public void PingEndpoint() + { + Ping p = new Ping(); + Assert.Equal("ping", p.Endpoint); + } + + [Fact] + public void RecordSimilarityEndpoint() + { + var fields = new Dictionary(); + var properties = new RecordSimilarityProperties(); + var records = new RecordSimilarityRecords(); + + RecordSimilarity rs = new RecordSimilarity(fields, properties, records); + + Assert.Equal("record-similarity", rs.Endpoint); + } + + [Fact] + public void RelationshipsEndpoint() + { + Relationships r = new Relationships("foo"); + + Assert.Equal("relationships", r.Endpoint); + Assert.Equal("foo", r.Content); + } + + [Fact] + public void SemanticVectorsEndpoint() + { + SemanticsVector s = new SemanticsVector("foo"); + Assert.Equal("semantics/vector", s.Endpoint); + Assert.Equal("foo", s.Content); + } + + [Fact] + public void SentencesEndpoint() + { + Sentences s = new Sentences("foo"); + Assert.Equal("sentences", s.Endpoint); + Assert.Equal("foo", s.Content); + } + + [Fact] + public void SentimentEndpoint() + { + Sentiment s = new Sentiment("foo"); + Assert.Equal("sentiment", s.Endpoint); + Assert.Equal("foo", s.Content); + } + + [Fact] + public void SimilarTermsEndpoint() + { + SimilarTerms st = new SimilarTerms("foo"); + + Assert.Equal("semantics/similar", st.Endpoint); + Assert.Equal("foo", st.Content); + } + + [Fact] + public void SyntaxDependenciesEndpoint() + { + SyntaxDependencies s = new SyntaxDependencies("foo"); + + Assert.Equal("syntax/dependencies", s.Endpoint); + Assert.Equal("foo", s.Content); + } + + [Fact] + public void TextEmbeddingEndpoint() + { + TextEmbedding t = new TextEmbedding("foo"); + + Assert.Equal("text-embedding", t.Endpoint); + Assert.Equal("foo", t.Content); + } + + [Fact] + public void TokensEndpoint() + { + Tokens t = new Tokens("foo"); + + Assert.Equal("tokens", t.Endpoint); + Assert.Equal("foo", t.Content); + } + + [Fact] + public void TopicsEndpoint() + { + Topics t = new Topics("foo"); + + Assert.Equal("topics", t.Endpoint); + Assert.Equal("foo", t.Content); + } + + [Fact] + public void TransliterationEndpoint() + { + Transliteration t = new Transliteration("foo"); + + Assert.Equal("transliteration", t.Endpoint); + Assert.Equal("foo", t.Content); + } + } +} \ No newline at end of file