diff --git a/CHANGELOG.md b/CHANGELOG.md index cdb281d..c2250f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,114 @@ # Changelog +## August 1, 2024 - v1.2.0 +- v1.2.0 updated release + +### 1. new methods added + +#### 1.2. Paraphrase text: `paraphrase()` +Generates a paraphrased version of the provided text. + +[Check Documentation](https://documenter.getpostman.com/view/31106842/2s9Ye8faUp#aea28008-ac67-4245-a79b-26788bce3f44) + +#### 1.2 Proofread & Grammar Check: `proofread()` + +Proofreads (and checks grammar) of the provided text. + +[Check Documentation](https://documenter.getpostman.com/view/31106842/2s9Ye8faUp#dcb4a490-1243-4001-93fc-652c570dbcd7) + +#### 1.3 Subscription Info / Quota Check: `quota()` + +Endpoint to check details regarding the subscription's current period. + +```json +{ + "timestamp": "2024-03-19T12:49:41.445736Z", + "on_trial": false, + "trial_ends": "2024-03-17T07:57:46.000000Z", + "subscribed": true, + "current_subscription_start": "2024-03-18T12:37:39.000000Z", + "current_subscription_end": "2024-04-18T12:37:39.000000Z", + "subscription_words_quota": 100000, + "subscription_words_used": 9608, + "subscription_words_used_percentage": 0.1 +} +``` +* "subscription_words_used_percentage" is a percentage of current monthly quota usage +* and might serve as an alert to the user of the depleted credits. +* With a value above 80%, it's advised to subscribe to more credits +* at https://sharpapi.com/dashboard/credits to avoid service disruption. + +[Check Documentation](https://documenter.getpostman.com/view/31106842/2s9Ye8faUp#7c401a21-8354-4589-a20a-573d1ae00d65) + +#### 1.4 Subscription Info / Quota Check: `ping()` + +Simple PING endpoint to check the availability of the API and its internal time zone (timestamp). + +```json +{ + "ping": "pong", + "timestamp": "2024-03-12T08:50:11.188308Z" +} +``` + +[Check Documentation](https://documenter.getpostman.com/view/31106842/2s9Ye8faUp#12a4aa9e-15cd-49a9-84ff-204ddc1116a3) + +### 2. New Parameters added + +#### 2.1 `max_quantity` - allows to limit the amount of returned items + +**Added to methods:** +- E-commerce > Product Categories / `productCategories()` +- Travel, Tourism & Hospitality > Tours & Activities Product Categories / `toursAndActivitiesProductCategories()` +- Travel, Tourism & Hospitality > Hospitality Product Categories / `hospitalityProductCategories()` +- HR Tech > Related Job Positions / `relatedJobPositions()` +- HR Tech > Related Skills / `relatedSkills()` + +#### 2.2 `max_length` - allows to instruct AI model to limit the output of generated text + +Please keep in mind that max_length serves as a strong suggestion for the Language Model, +rather than a strict requirement, to maintain the general sense of the outcome. + +**Added to methods:** +- E-commerce > Generate Product Intro / `generateProductIntro()` +- E-commerce > Generate Thank You E-mail / `generateThankYouEmail()` +- Content & Marketing Automation > Summarize Content / `summarizeText()` +- Content & Marketing Automation > Paraphrase Text / `paraphrase()` + +#### 2.3 `voice_tone` - Tone of voice of the generated text + +You can set your preferred writing style by providing +an optional voice_tone parameter. It can be adjectives like +`funny` or `joyous`, or even the name of a famous writer. +You can provide multiple tones at the same time. + +**Added to methods:** +- SEO > Generate SEO Tags / `generateSeoTags()` +- Content & Marketing Automation > Generate Keywords/Tags / `generateKeywords()` +- Content & Marketing Automation > Summarize Content / `summarizeText()` +- Content & Marketing Automation > Paraphrase Text / `paraphrase()` +- Content & Marketing Automation > Translate Text / `translate()` +- Travel, Tourism & Hospitality > Tours & Activities Product Categories / `toursAndActivitiesProductCategories()` +- Travel, Tourism & Hospitality > Hospitality Product Categories / `hospitalityProductCategories()` +- HR Tech > Generate Job Description / `generateJobDescription()` +- E-commerce > Product Categories / `productCategories()` +- E-commerce > Generate Product Intro / `generateProductIntro()` +- E-commerce > Generate Thank You E-mail / `generateThankYouEmail()` + +#### 2.4 `context` - adds more context/instructions for content processing + +**Added to methods:** +- HR Tech > Generate Job Description / `generateJobDescription()` +- E-commerce > Generate Thank You E-mail / `generateThankYouEmail()` +- E-commerce > Product Categories / `productCategories()` +- Travel, Tourism & Hospitality > Tours & Activities Product Categories / `toursAndActivitiesProductCategories()` +- Travel, Tourism & Hospitality > Hospitality Product Categories / `hospitalityProductCategories()` +- Content & Marketing Automation > Translate Text / `translate()` +- Content & Marketing Automation > Paraphrase Text / `paraphrase()` + +### 3.0 Moving to individual job result endpoints, each with separate data formats. + +## March 5, 2024 - v1.0.0 - v1.0.0 initial release -All notable changes to `sharpapi-flutter-client` will be documented in this file. +All notable changes to `sharpapi-flutter-client` will be documented in this file. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..464175e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) SharpAPI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index fd4e38b..ede455d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ An optional output language parameter can also be provided (`English` value is s ///*** parse resume SharpApi.parseResume( resume: File(''), + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -131,6 +132,18 @@ The only mandatory parameter is `name`. ///*** generate job description SharpApi.generateJobDescription( name: 'ANY_JOB_TITLE', + companyName: 'ANY_COMPANY_NAME', // optional company name + minimumEducation: 'Bachelor Degree', // optional minimum education + minimumWorkExperience: '2 years', // optional minimum work experience + employmentType: 'Full Time', // optional employment type + country: 'United States', // optional country + remote: true, // optional remote + visaSponsored: true, // optional visa sponsored + requiredSkills: ['skill1', 'skill2'], // optional required skills + optionalSkills: ['skill3', 'skill4'], // optional optional skills + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -147,6 +160,8 @@ value (1.0-10.0) where 10 equals 100%, the highest relevance score. ///*** related skills SharpApi.relatedSkills( skill: 'ANY_SKILL', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -163,6 +178,8 @@ float value (1.0-10.0) where 10 equals 100%, the highest relevance score. ///*** related job positions SharpApi.relatedJobPositions( jobTitle: 'ANY_JOB_TITLE', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -181,6 +198,7 @@ with a score between 0-100%. Great for sentiment report processing for any onlin ///*** product review sentiment SharpApi.productReviewSentiment( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -199,6 +217,10 @@ Comes in handy with populating product catalogue data and bulk products' process ///*** product categories SharpApi.productCategories( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity + context: 'avoid using abbreviations', // optional context + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -216,6 +238,9 @@ Comes in handy with populating product catalog data and bulk products processing ///*** generate product intro SharpApi.generateProductIntro( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -233,6 +258,10 @@ so you can personalize the rest of the email easily. ///*** generate thank you email SharpApi.generateThankYouEmail( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -242,6 +271,53 @@ so you can personalize the rest of the email easily. ### Content +#### Paraphrase / Rephrase Text + +Generates a paraphrased version of the provided text. +Only the `content` parameter is required. You can define the output language, +maximum character length, and tone of voice. + +Additional instructions on how to process the text can be provided in the context parameter. +Please keep in mind that `max_length` serves as a strong suggestion +for the Language Model, rather than a strict requirement, +to maintain the general sense of the outcome. + +You can set your preferred writing style by providing an optional `voice_tone` parameter. +It can be adjectives like `funny` or `joyous`, or even the name of a famous writer. + +This API method also provides an optional `context` parameter, +which can be used to supply additional flexible instructions for content processing. + +```dart + ///*** paraphrase text + SharpApi.paraphrase( + text: 'ANY_TEXT', + language: SharpApiLanguages.ENGLISH, // optional language + maxLength: 500, // optional length + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + ).then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); +``` + +#### Proofread Text + Grammar Check + +Proofreads (and checks grammar) a provided text. + +```dart + ///*** proofread text + SharpApi.proofread( + text: 'ANY_TEXT', + ).then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); +``` + #### Translate Text Translates provided text to selected language. 80 languages are supported. @@ -251,7 +327,9 @@ Please check included `SharpApiLanguages` _Enum_ class for details. ///*** translate text SharpApi.translate( text: 'ANY_TEXT', - language: 'ANY_LANGUAGE', // user language string from [SharpApiLanguages] class + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -320,6 +398,8 @@ Generates a list of unique keywords/tags based on the provided content. ///*** generate keywords SharpApi.generateKeywords( text: 'ANY_TEXT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -337,6 +417,9 @@ marketing introductions of longer texts. ///*** summarize text SharpApi.summarizeText( text: 'ANY_TEXT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -355,6 +438,8 @@ link to the website and pictures URL to get as many tags populated as possible. ///*** generate seo tags SharpApi.generateSeoTags( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -374,6 +459,7 @@ Great for sentiment report processing for any online store. ///*** travel review sentiment SharpApi.travelReviewSentiment( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -394,6 +480,12 @@ Only first parameter `productName` is required. ///*** tours and activities product categories SharpApi.toursAndActivitiesProductCategories( productName: 'ANY_PRODUCT_NAME', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + maxQuantity: 5, // optional max quantity + country: 'United States', // optional country + city: 'New York', // optional city ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -414,6 +506,12 @@ Only first parameter `productName` is required. ///*** hospitality product categories SharpApi.hospitalityProductCategories( productName: 'ANY_PRODUCT_NAME', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + maxQuantity: 5, // optional max quantity + country: 'United States', // optional country + city: 'New York', // optional city ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -421,6 +519,64 @@ Only first parameter `productName` is required. }); ``` +### 🤖 Technical API Endpoints + +#### Subscription information / quota check +Endpoint to check details regarding the subscription's current period + +```dart + ///*** quota + SharpApi.quota().then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); +``` + +will result in: +```json +{ + "timestamp": "2024-03-19T12:49:41.445736Z", + "on_trial": false, + "trial_ends": "2024-03-17T07:57:46.000000Z", + "subscribed": true, + "current_subscription_start": "2024-03-18T12:37:39.000000Z", + "current_subscription_end": "2024-04-18T12:37:39.000000Z", + "subscription_words_quota": 100000, + "subscription_words_used": 9608, + "subscription_words_used_percentage": 0.1 +} +``` + +`subscription_words_used_percentage` is a percentage of current monthly quota usage +and might serve as an alert to the user of the depleted credits. +With a value above 80%, it's advised to subscribe to more credits +at https://sharpapi.com/dashboard/credits to avoid service disruption. + +These values are also available in the Dashboard at https://sharpapi.com/dashboard + +#### Ping +Simple PING endpoint to check the availability of the API and it's internal timze zone (timestamp). + +```dart + ///*** ping + SharpApi.ping().then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); +``` + +will result in: +```json +{ + "ping": "pong", + "timestamp": "2024-03-12T08:50:11.188308Z" +} +``` + +--- + ### Do you think our API is missing some obvious functionality? [Please let us know»](https://github.com/sharpapi/sharpapi-php-client/issues) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 55a8cac..c0d0be4 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -66,4 +66,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 -COCOAPODS: 1.11.3 +COCOAPODS: 1.15.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 5a80edc..2e05a49 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 87131a0..8e3ca5d 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ { padding: const EdgeInsets.all(16.0), child: Column( children: [ + // SharpAPI For Hr SizedBox( width: double.infinity, child: Column( @@ -121,6 +122,8 @@ class _MyHomePageState extends State { color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(height: 16.0), + + // SharpAPI For E-commerce SizedBox( width: double.infinity, child: Column( @@ -182,6 +185,8 @@ class _MyHomePageState extends State { color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(height: 16.0), + + // SharpAPI For SEO SizedBox( width: double.infinity, child: Column( @@ -219,6 +224,8 @@ class _MyHomePageState extends State { color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(height: 16.0), + + // SharpAPI For Travel, Tourism & Hospitality SizedBox( width: double.infinity, child: Column( @@ -272,6 +279,8 @@ class _MyHomePageState extends State { color: Theme.of(context).colorScheme.onSurface, ), const SizedBox(height: 16.0), + + // SharpAPI For Content & Marketing Automation SizedBox( width: double.infinity, child: Column( @@ -337,6 +346,69 @@ class _MyHomePageState extends State { generateKeywords(); }, ), + PrimaryElevatedButton( + title: 'Paraphrase Text', + onPressed: isJobStatusPolling + ? null + : () { + paraphrase(); + }, + ), + PrimaryElevatedButton( + title: 'Proofread Text', + onPressed: isJobStatusPolling + ? null + : () { + proofread(); + }, + ), + ], + ), + ], + ), + ), + const SizedBox(height: 16.0), + Container( + width: double.infinity, + height: 1.0, + color: Theme.of(context).colorScheme.onSurface, + ), + const SizedBox(height: 16.0), + + // subscription info + SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Subscription Info', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16.0), + Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + PrimaryElevatedButton( + title: 'Quota', + onPressed: isJobStatusPolling + ? null + : () { + quota(); + }, + ), + PrimaryElevatedButton( + title: 'Ping', + onPressed: isJobStatusPolling + ? null + : () { + ping(); + }, + ), ], ), ], @@ -352,9 +424,57 @@ class _MyHomePageState extends State { } void snippet() async { + ///*** quota + SharpApi.quota().then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); + + ///*** ping + SharpApi.ping().then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); + + ///*** paraphrase text + SharpApi.paraphrase( + text: "Red Bull's Max Verstappen says this weekend's Las Vegas Grand Prix is \"99% show and 1% sporting event\". \n\n The triple world champion said he is \"not looking forward\" to the razzmatazz around the race, the first time Formula 1 cars have raced down the city's famous Strip. \n\n Other leading drivers were more equivocal about the hype.\n\n Aston Martin's Fernando Alonso said: \"With the investment that has been made and the place we are racing, it deserves a little bit [of] different treatment and extra show.\" \n\n The weekend was kick-started on Wednesday evening with a lavish opening ceremony.\n\n It featured performances from several music stars, including Kylie Minogue and Journey, and culminated in the drivers being introduced to a sparsely populated crowd in light rain by being lifted into view on hydraulic platforms under a sound-and-light show. \n\n Lewis Hamilton said: \"It's amazing to be here. It is exciting - such an incredible place, so many lights, a great energy, a great buzz. \n\n \"This is one of the most iconic cities there is. It is a big show, for sure. It is never going to be like Silverstone [in terms of history and purity]. But maybe over time the people in the community here will grow to love the sport.\" \n\n Hamilton added: \"It is a business, ultimately. You'll still see good racing here. \n\n \"Maybe the track will be good, maybe it will be bad. It was so-so on the [simulator]. Don't knock it 'til you try it. I hear there are a lot of people complaining about the direction [F1 president] Stefano [Domenicali] and [owners] Liberty have been going [but] I think they have been doing an amazing job b.\"", + language: SharpApiLanguages.ENGLISH, // optional language + maxLength: 500, // optional length + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + ).then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); + + ///*** proofread text + SharpApi.proofread( + text: "Red Bull's Max Verstappen says this weekend's Las Vegas Grand Prix is \"99% show and 1% sporting event\". \n\n The triple world champion said he is \"not looking forward\" to the razzmatazz around the race, the first time Formula 1 cars have raced down the city's famous Strip. \n\n Other leading drivers were more equivocal about the hype.\n\n Aston Martin's Fernando Alonso said: \"With the investment that has been made and the place we are racing, it deserves a little bit [of] different treatment and extra show.\" \n\n The weekend was kick-started on Wednesday evening with a lavish opening ceremony.\n\n It featured performances from several music stars, including Kylie Minogue and Journey, and culminated in the drivers being introduced to a sparsely populated crowd in light rain by being lifted into view on hydraulic platforms under a sound-and-light show. \n\n Lewis Hamilton said: \"It's amazing to be here. It is exciting - such an incredible place, so many lights, a great energy, a great buzz. \n\n \"This is one of the most iconic cities there is. It is a big show, for sure. It is never going to be like Silverstone [in terms of history and purity]. But maybe over time the people in the community here will grow to love the sport.\" \n\n Hamilton added: \"It is a business, ultimately. You'll still see good racing here. \n\n \"Maybe the track will be good, maybe it will be bad. It was so-so on the [simulator]. Don't knock it 'til you try it. I hear there are a lot of people complaining about the direction [F1 president] Stefano [Domenicali] and [owners] Liberty have been going [but] I think they have been doing an amazing job b.\"", + ).then((value) { + /// do something with the [value] here + }).catchError((error) { + /// do something with the [error] here + }); + ///*** generate job description SharpApi.generateJobDescription( name: 'ANY_JOB_TITLE', + companyName: 'ANY_COMPANY_NAME', // optional company name + minimumEducation: 'Bachelor Degree', // optional minimum education + minimumWorkExperience: '2 years', // optional minimum work experience + employmentType: 'Full Time', // optional employment type + country: 'United States', // optional country + remote: true, // optional remote + visaSponsored: true, // optional visa sponsored + requiredSkills: ['skill1', 'skill2'], // optional required skills + optionalSkills: ['skill3', 'skill4'], // optional optional skills + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -364,6 +484,8 @@ class _MyHomePageState extends State { ///*** related job positions SharpApi.relatedJobPositions( jobTitle: 'ANY_JOB_TITLE', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -373,6 +495,8 @@ class _MyHomePageState extends State { ///*** related skills SharpApi.relatedSkills( skill: 'ANY_SKILL', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -382,6 +506,7 @@ class _MyHomePageState extends State { ///*** parse resume SharpApi.parseResume( resume: File(''), + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -391,6 +516,7 @@ class _MyHomePageState extends State { ///*** product review sentiment SharpApi.productReviewSentiment( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -400,6 +526,10 @@ class _MyHomePageState extends State { ///*** product categories SharpApi.productCategories( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + maxQuantity: 5, // optional max quantity + context: 'avoid using abbreviations', // optional context + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -409,6 +539,9 @@ class _MyHomePageState extends State { ///*** generate product intro SharpApi.generateProductIntro( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -418,6 +551,10 @@ class _MyHomePageState extends State { ///*** generate thank you email SharpApi.generateThankYouEmail( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -427,6 +564,8 @@ class _MyHomePageState extends State { ///*** generate seo tags SharpApi.generateSeoTags( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -436,6 +575,7 @@ class _MyHomePageState extends State { ///*** travel review sentiment SharpApi.travelReviewSentiment( content: 'ANY_CONTENT', + language: SharpApiLanguages.ENGLISH, // optional language ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -445,6 +585,12 @@ class _MyHomePageState extends State { ///*** tours and activities product categories SharpApi.toursAndActivitiesProductCategories( productName: 'ANY_PRODUCT_NAME', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + maxQuantity: 5, // optional max quantity + country: 'United States', // optional country + city: 'New York', // optional city ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -454,6 +600,12 @@ class _MyHomePageState extends State { ///*** hospitality product categories SharpApi.hospitalityProductCategories( productName: 'ANY_PRODUCT_NAME', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context + maxQuantity: 5, // optional max quantity + country: 'United States', // optional country + city: 'New York', // optional city ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -463,7 +615,9 @@ class _MyHomePageState extends State { ///*** translate text SharpApi.translate( text: 'ANY_TEXT', - language: 'ANY_LANGUAGE', // user language string from [SharpApiLanguages] class + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + context: 'avoid using abbreviations', // optional context ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -500,6 +654,9 @@ class _MyHomePageState extends State { ///*** summarize text SharpApi.summarizeText( text: 'ANY_TEXT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone + maxLength: 500, // optional max length ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -509,6 +666,8 @@ class _MyHomePageState extends State { ///*** generate keywords SharpApi.generateKeywords( text: 'ANY_TEXT', + language: SharpApiLanguages.ENGLISH, // optional language + voiceTone: 'neutral', // optional voice tone ).then((value) { /// do something with the [value] here }).catchError((error) { @@ -1266,6 +1425,146 @@ class _MyHomePageState extends State { ); }); } + + void paraphrase() async { + setState(() { + isJobStatusPolling = true; + }); + + SharpApi.paraphrase( + text: "Red Bull's Max Verstappen says this weekend's Las Vegas Grand Prix is \"99% show and 1% sporting event\". \n\n The triple world champion said he is \"not looking forward\" to the razzmatazz around the race, the first time Formula 1 cars have raced down the city's famous Strip. \n\n Other leading drivers were more equivocal about the hype.\n\n Aston Martin's Fernando Alonso said: \"With the investment that has been made and the place we are racing, it deserves a little bit [of] different treatment and extra show.\" \n\n The weekend was kick-started on Wednesday evening with a lavish opening ceremony.\n\n It featured performances from several music stars, including Kylie Minogue and Journey, and culminated in the drivers being introduced to a sparsely populated crowd in light rain by being lifted into view on hydraulic platforms under a sound-and-light show. \n\n Lewis Hamilton said: \"It's amazing to be here. It is exciting - such an incredible place, so many lights, a great energy, a great buzz. \n\n \"This is one of the most iconic cities there is. It is a big show, for sure. It is never going to be like Silverstone [in terms of history and purity]. But maybe over time the people in the community here will grow to love the sport.\" \n\n Hamilton added: \"It is a business, ultimately. You'll still see good racing here. \n\n \"Maybe the track will be good, maybe it will be bad. It was so-so on the [simulator]. Don't knock it 'til you try it. I hear there are a lot of people complaining about the direction [F1 president] Stefano [Domenicali] and [owners] Liberty have been going [but] I think they have been doing an amazing job b.\"", + ).then((value) { + setState(() { + isJobStatusPolling = false; + }); + + displaySuccessSnackBar(); + + debugPrint('***** Paraphrase *****'); + debugPrint(value.paraphrase); + }).catchError((e) { + setState(() { + isJobStatusPolling = false; + }); + + debugPrint('error ==>> ${e.message}'); + + displayErrorSnackBar( + message: e.message, + ); + }); + } + + void proofread() async { + setState(() { + isJobStatusPolling = true; + }); + + SharpApi.proofread( + text: "Red Bull's Max Verstappen says this weekend's Las Vegas Grand Prix is \"99% show and 1% sporting event\". \n\n The triple world champion said he is \"not looking forward\" to the razzmatazz around the race, the first time Formula 1 cars have raced down the city's famous Strip. \n\n Other leading drivers were more equivocal about the hype.\n\n Aston Martin's Fernando Alonso said: \"With the investment that has been made and the place we are racing, it deserves a little bit [of] different treatment and extra show.\" \n\n The weekend was kick-started on Wednesday evening with a lavish opening ceremony.\n\n It featured performances from several music stars, including Kylie Minogue and Journey, and culminated in the drivers being introduced to a sparsely populated crowd in rain by being lifted into view on hydraulic platforms under a sound-and-light show. \n\n Lewis Hamilton said: \"It's amazing to be here. It is exciting - such an incredible place, so many lights, a great energy, a great buzz. \n\n \"This is one of the most iconic cities there is. It is a big show, for sure. It is never going to be like Silverstone [in terms of history and purity]. But maybe over time the people in the community here will grow to love the sport.\" \n\n Hamilton added: \"It is a business, ultimately. You'll still see good racing here. \n\n \"Maybe the track will be good, maybe it will be bad. It was so-so on the [simulator]. Don't knock it 'til you try it. I hear there are a lot of people complaining about the direction [F1 president] Stefano [Domenicali] and [owners] Liberty have been going [but] I think they have been doing an amazing job.\"", + ).then((value) { + setState(() { + isJobStatusPolling = false; + }); + + displaySuccessSnackBar(); + + debugPrint('***** Proofread *****'); + debugPrint(value.proofread); + }).catchError((e) { + setState(() { + isJobStatusPolling = false; + }); + + debugPrint('error ==>> ${e.message}'); + + displayErrorSnackBar( + message: e.message, + ); + }); + } + + // subscription info + void quota() async { + setState(() { + isJobStatusPolling = true; + }); + + SharpApi.quota().then((value) { + setState(() { + isJobStatusPolling = false; + }); + + displaySuccessSnackBar(); + + debugPrint('***** Timestamp *****'); + debugPrint(value.timestamp); + + debugPrint('***** Subscription Words Quota *****'); + debugPrint(value.subscriptionWordsQuota.toString()); + + debugPrint('***** Subscription Words Used *****'); + debugPrint(value.subscriptionWordsUsed.toString()); + + debugPrint('***** Subscription Words Used Percentage *****'); + debugPrint(value.subscriptionWordsUsedPercentage.toString()); + + debugPrint('***** On Trial *****'); + debugPrint(value.onTrial.toString()); + + debugPrint('***** Trial Ends *****'); + debugPrint(value.trialEnds); + + debugPrint('***** Subscribed *****'); + debugPrint(value.subscribed.toString()); + + debugPrint('***** Current Subscription Start *****'); + debugPrint(value.currentSubscriptionStart); + + debugPrint('***** Current Subscription End *****'); + debugPrint(value.currentSubscriptionEnd); + }).catchError((e) { + setState(() { + isJobStatusPolling = false; + }); + + debugPrint('error ==>> ${e.message}'); + + displayErrorSnackBar( + message: e.message, + ); + }); + } + + void ping() async { + setState(() { + isJobStatusPolling = true; + }); + + SharpApi.ping().then((value) { + setState(() { + isJobStatusPolling = false; + }); + + displaySuccessSnackBar(); + + debugPrint('***** Timestamp *****'); + debugPrint(value.timestamp); + + debugPrint('***** Ping *****'); + debugPrint(value.ping); + }).catchError((e) { + setState(() { + isJobStatusPolling = false; + }); + + debugPrint('error ==>> ${e.message}'); + + displayErrorSnackBar( + message: e.message, + ); + }); + } } class PrimaryElevatedButton extends StatelessWidget { diff --git a/lib/src/content_and_marketing/conent_and_marketing_api_service.dart b/lib/src/content_and_marketing/conent_and_marketing_api_service.dart index 5570c2a..02357a3 100644 --- a/lib/src/content_and_marketing/conent_and_marketing_api_service.dart +++ b/lib/src/content_and_marketing/conent_and_marketing_api_service.dart @@ -1,11 +1,14 @@ import 'package:sharpapi_flutter_client/src/content_and_marketing/models/detect_spam_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/keywords_and_tags_model.dart'; +import 'package:sharpapi_flutter_client/src/content_and_marketing/models/paraphrase_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/phone_model.dart'; +import 'package:sharpapi_flutter_client/src/content_and_marketing/models/proofread_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/summarize_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/translate_text_model.dart'; import 'package:sharpapi_flutter_client/src/core/SharpApiService.dart'; import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; class ContentAndMarketingApiService { @@ -22,10 +25,14 @@ class ContentAndMarketingApiService { Future _translate({ required String text, required String language, + String? voiceTone, + String? context, }) async { final result = await _repository.translate( text: text, language: language, + voiceTone: voiceTone, + context: context, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -48,6 +55,8 @@ class ContentAndMarketingApiService { Future translate({ required String text, required String language, + String? voiceTone, + String? context, }) async { GeneralModel? generalModel; @@ -55,6 +64,8 @@ class ContentAndMarketingApiService { generalModel = await _translate( text: text, language: language, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -64,7 +75,8 @@ class ContentAndMarketingApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: translateTextRoute, ); translateModel = TranslateTextModel.fromJson(result); @@ -119,7 +131,8 @@ class ContentAndMarketingApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: detectSpamRoute, ); detectSpamModel = DetectSpamModel.fromJson(result); @@ -174,7 +187,8 @@ class ContentAndMarketingApiService { try { List result = await _sharpApiService.getJobStatusResult( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: detectPhonesRoute, ); detectPhonesModel = result.map((e) => PhoneNumberModel.fromJson(e)).toList(); @@ -229,7 +243,8 @@ class ContentAndMarketingApiService { try { List result = await _sharpApiService.getJobStatusResult( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: detectEmailsRoute, ); detectEmailsModel = result.map((e) => e.toString()).toList(); @@ -246,10 +261,14 @@ class ContentAndMarketingApiService { Future _summarizeText({ required String text, required String language, + int? maxLength, + String? voiceTone, }) async { final result = await _repository.summarizeText( content: text, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -272,6 +291,8 @@ class ContentAndMarketingApiService { Future summarizeText({ required String text, required String language, + int? maxLength, + String? voiceTone, }) async { GeneralModel? generalModel; @@ -279,6 +300,8 @@ class ContentAndMarketingApiService { generalModel = await _summarizeText( text: text, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -288,7 +311,8 @@ class ContentAndMarketingApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: summarizeTextRoute, ); summarizeTextModel = SummarizeContentModel.fromJson(result); @@ -301,14 +325,144 @@ class ContentAndMarketingApiService { return summarizeTextModel; } + ///*** paraphrase content + Future _paraphraseText({ + required String text, + required String language, + String? voiceTone, + int? maxLength, + String? context, + }) async { + final result = await _repository.paraphraseText( + content: text, + language: language, + voiceTone: voiceTone, + maxLength: maxLength, + context: context, + ); + + GeneralModel generateJobDescriptionModel = GeneralModel(); + + result.fold( + (error) { + // log('error2 -> $error'); + + throw SharpApiException(error); + }, + (data) { + generateJobDescriptionModel = data; + }, + ); + + return generateJobDescriptionModel; + } + + ///*** paraphrase content implementation + Future paraphraseText({ + required String text, + required String language, + String? voiceTone, + int? maxLength, + String? context, + }) async { + GeneralModel? generalModel; + + try { + generalModel = await _paraphraseText( + text: text, + language: language, + voiceTone: voiceTone, + maxLength: maxLength, + context: context, + ); + } catch (error) { + rethrow; + } + + ParaphraseContentModel? paraphraseContentModel; + + try { + Map result = await _sharpApiService.getJobStatusResult>( + jobId: generalModel.jobId ?? '', + mainRoute: paraphraseTextRoute, + ); + + paraphraseContentModel = ParaphraseContentModel.fromJson(result); + } catch (error) { + // log('error => $error'); + + rethrow; + } + + return paraphraseContentModel; + } + + ///*** proofread content + Future _proofreadText({ + required String content, + }) async { + final result = await _repository.proofreadText( + content: content, + ); + + GeneralModel generateJobDescriptionModel = GeneralModel(); + + result.fold( + (error) { + // log('error2 -> $error'); + + throw SharpApiException(error); + }, + (data) { + generateJobDescriptionModel = data; + }, + ); + + return generateJobDescriptionModel; + } + + ///*** proofread content implementation + Future proofreadText({ + required String content, + }) async { + GeneralModel? generalModel; + + try { + generalModel = await _proofreadText( + content: content, + ); + } catch (error) { + rethrow; + } + + ProofreadContentModel? proofreadContentModel; + + try { + Map result = await _sharpApiService.getJobStatusResult>( + jobId: generalModel.jobId ?? '', + mainRoute: proofreadTextRoute, + ); + + proofreadContentModel = ProofreadContentModel.fromJson(result); + } catch (error) { + // log('error => $error'); + + rethrow; + } + + return proofreadContentModel; + } + ///*** generate keywords Future _generateKeywords({ required String text, required String language, + String? voiceTone, }) async { final result = await _repository.generateKeywords( content: text, language: language, + voiceTone: voiceTone, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -327,10 +481,11 @@ class ContentAndMarketingApiService { return generateJobDescriptionModel; } - ///*** summarize text implementation + ///*** generate keywords implementation Future generateKeywords({ required String text, required String language, + String? voiceTone, }) async { GeneralModel? generalModel; @@ -338,6 +493,7 @@ class ContentAndMarketingApiService { generalModel = await _generateKeywords( text: text, language: language, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -347,7 +503,8 @@ class ContentAndMarketingApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: generateKeywordsRoute, ); generateKeywordsModel = KeywordsAndTagsModel.fromJson(result); diff --git a/lib/src/content_and_marketing/models/paraphrase_content_model.dart b/lib/src/content_and_marketing/models/paraphrase_content_model.dart new file mode 100644 index 0000000..3b7ac6c --- /dev/null +++ b/lib/src/content_and_marketing/models/paraphrase_content_model.dart @@ -0,0 +1,11 @@ +class ParaphraseContentModel { + String? paraphrase; + + ParaphraseContentModel({ + this.paraphrase, + }); + + factory ParaphraseContentModel.fromJson(Map json) => ParaphraseContentModel( + paraphrase: json['paraphrase'], + ); +} \ No newline at end of file diff --git a/lib/src/content_and_marketing/models/proofread_content_model.dart b/lib/src/content_and_marketing/models/proofread_content_model.dart new file mode 100644 index 0000000..6a0cacb --- /dev/null +++ b/lib/src/content_and_marketing/models/proofread_content_model.dart @@ -0,0 +1,11 @@ +class ProofreadContentModel { + String? proofread; + + ProofreadContentModel({ + this.proofread, + }); + + factory ProofreadContentModel.fromJson(Map json) => ProofreadContentModel( + proofread: json['proofread'], + ); +} \ No newline at end of file diff --git a/lib/src/core/SharpApi.dart b/lib/src/core/SharpApi.dart index 4974a3b..c13ff08 100644 --- a/lib/src/core/SharpApi.dart +++ b/lib/src/core/SharpApi.dart @@ -3,7 +3,9 @@ import 'dart:io'; import 'package:sharpapi_flutter_client/src/content_and_marketing/conent_and_marketing_api_service.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/detect_spam_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/keywords_and_tags_model.dart'; +import 'package:sharpapi_flutter_client/src/content_and_marketing/models/paraphrase_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/phone_model.dart'; +import 'package:sharpapi_flutter_client/src/content_and_marketing/models/proofread_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/summarize_content_model.dart'; import 'package:sharpapi_flutter_client/src/content_and_marketing/models/translate_text_model.dart'; import 'package:sharpapi_flutter_client/src/core/di/injection.dart'; @@ -20,6 +22,9 @@ import 'package:sharpapi_flutter_client/src/hr/models/related_job_positions_mode import 'package:sharpapi_flutter_client/src/hr/models/related_skills_model.dart'; import 'package:sharpapi_flutter_client/src/seo/models/generate_seo_tags_model.dart'; import 'package:sharpapi_flutter_client/src/seo/seo_api_service.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/ping_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/quota_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/subscription_info_api_service.dart'; import 'package:sharpapi_flutter_client/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart'; class SharpApi { @@ -36,6 +41,8 @@ class SharpApi { List? requiredSkills, List? optionalSkills, String language = 'English', + String? voiceTone, + String? context, }) async { GenerateJobDescriptionDto generateJobDescriptionDto = GenerateJobDescriptionDto( name: name, @@ -49,6 +56,8 @@ class SharpApi { requiredSkills: requiredSkills, optionalSkills: optionalSkills, language: language, + voiceTone: voiceTone, + context: context, ); GenerateJobDescriptionModel? generateJobDescriptionModel; @@ -68,6 +77,7 @@ class SharpApi { static Future relatedSkills({ required String skill, String language = 'English', + int? maxQuantity, }) async { RelatedSkillsModel? relatedSkillsModel; @@ -75,6 +85,7 @@ class SharpApi { relatedSkillsModel = await sl().relatedSkills( skill: skill, language: language, + maxQuantity: maxQuantity, ); } catch (error) { rethrow; @@ -87,6 +98,7 @@ class SharpApi { static Future relatedJobPositions({ required String jobTitle, String language = 'English', + int? maxQuantity, }) async { RelatedJobPositionModel? relatedJobPositionModel; @@ -94,6 +106,7 @@ class SharpApi { relatedJobPositionModel = await sl().relatedJobPositions( jobTitle: jobTitle, language: language, + maxQuantity: maxQuantity, ); } catch (error) { rethrow; @@ -144,6 +157,9 @@ class SharpApi { static Future> productCategories({ required String content, String language = 'English', + int? maxQuantity, + String? voiceTone, + String? context, }) async { List? productCategoriesModel; @@ -151,6 +167,9 @@ class SharpApi { productCategoriesModel = await sl().productCategories( content: content, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -163,6 +182,8 @@ class SharpApi { static Future generateProductIntro({ required String content, String language = 'English', + int? maxLength, + String? voiceTone, }) async { ProductIntroModel? productIntroModel; @@ -170,6 +191,8 @@ class SharpApi { productIntroModel = await sl().generateProductIntro( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -182,6 +205,9 @@ class SharpApi { static Future generateThankYouEmail({ required String content, String language = 'English', + int? maxLength, + String? voiceTone, + String? context, }) async { ThankYouEmailModel? thankYouEmailModel; @@ -189,6 +215,9 @@ class SharpApi { thankYouEmailModel = await sl().generateThankYouEmail( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -201,6 +230,7 @@ class SharpApi { static Future generateSeoTags({ required String content, String language = 'English', + String? voiceTone, }) async { GenerateSeoTagsModel? generateSeoTagsModel; @@ -208,6 +238,7 @@ class SharpApi { generateSeoTagsModel = await sl().generateSeoTags( content: content, language: language, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -241,6 +272,9 @@ class SharpApi { String? country, String? city, String language = 'English', + int? maxQuantity, + String? voiceTone, + String? context, }) async { List? toursAndActivitiesProductCategoriesModel; @@ -250,6 +284,9 @@ class SharpApi { country: country, city: city, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -264,6 +301,9 @@ class SharpApi { String? country, String? city, String language = 'English', + int? maxQuantity, + String? voiceTone, + String? context, }) async { List? hospitalityProductCategoriesModel; @@ -273,6 +313,9 @@ class SharpApi { country: country, city: city, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -282,10 +325,11 @@ class SharpApi { } ///*** translate - static Future translate({ required String text, required String language, + String? voiceTone, + String? context, }) async { TranslateTextModel? translateModel; @@ -293,6 +337,8 @@ class SharpApi { translateModel = await sl().translate( text: text, language: language, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -358,6 +404,8 @@ class SharpApi { static Future summarizeText({ required String text, String language = 'English', + int? maxLength, + String? voiceTone, }) async { SummarizeContentModel? summarizeTextModel; @@ -365,6 +413,8 @@ class SharpApi { summarizeTextModel = await sl().summarizeText( text: text, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -373,11 +423,53 @@ class SharpApi { return summarizeTextModel; } - ///*** generate keywords + ///*** paraphrase text + static Future paraphrase({ + required String text, + String language = 'English', + String? voiceTone, + int? maxLength, + String? context, + }) async { + ParaphraseContentModel? paraphraseContentModel; + + try { + paraphraseContentModel = await sl().paraphraseText( + text: text, + language: language, + voiceTone: voiceTone, + maxLength: maxLength, + context: context, + ); + } catch (error) { + rethrow; + } + + return paraphraseContentModel; + } + ///*** proofread text + static Future proofread({ + required String text, + }) async { + ProofreadContentModel? proofreadContentModel; + + try { + proofreadContentModel = await sl().proofreadText( + content: text, + ); + } catch (error) { + rethrow; + } + + return proofreadContentModel; + } + + ///*** generate keywords static Future generateKeywords({ required String text, String language = 'English', + String? voiceTone, }) async { KeywordsAndTagsModel? generateKeywordsModel; @@ -385,6 +477,7 @@ class SharpApi { generateKeywordsModel = await sl().generateKeywords( text: text, language: language, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -392,4 +485,30 @@ class SharpApi { return generateKeywordsModel; } + + ///*** quota + static Future quota() async { + QuotaModel? quotaModel; + + try { + quotaModel = await sl().quota(); + } catch (error) { + rethrow; + } + + return quotaModel; + } + + ///*** ping + static Future ping() async { + PingModel? pingModel; + + try { + pingModel = await sl().ping(); + } catch (error) { + rethrow; + } + + return pingModel; + } } diff --git a/lib/src/core/SharpApiService.dart b/lib/src/core/SharpApiService.dart index e78743d..0edbfac 100644 --- a/lib/src/core/SharpApiService.dart +++ b/lib/src/core/SharpApiService.dart @@ -15,9 +15,11 @@ class SharpApiService { Future _getJobStatusResult({ required String jobId, + required String mainRoute, }) async { final result = await _repository.getJobStatusResult( jobId: jobId, + mainRoute: mainRoute, ); JobModel jobModel = JobModel(); @@ -37,6 +39,7 @@ class SharpApiService { Future getJobStatusResult({ required String jobId, + required String mainRoute, }) async { double waitingTime = 0; @@ -45,22 +48,22 @@ class SharpApiService { try { JobModel jobModel = await _getJobStatusResult( jobId: jobId, + mainRoute: mainRoute, ); // log('jobModel.result => ${jobModel.status}'); - if (jobModel.status == SharpApiJobStatusEnum.NEW.label || - jobModel.status == SharpApiJobStatusEnum.PENDING.label) { - + if (jobModel.status == SharpApiJobStatusEnum.NEW.label || jobModel.status == SharpApiJobStatusEnum.PENDING.label) { waitingTime = waitingTime + SharpApiConfigs.apiJobStatusPollingInterval; - if(waitingTime >= SharpApiConfigs.apiJobStatusPollingWait) { + if (waitingTime >= SharpApiConfigs.apiJobStatusPollingWait) { throw SharpApiException('Job status polling timeout!, Please try again.'); } else { await Future.delayed(Duration(seconds: SharpApiConfigs.apiJobStatusPollingInterval.toInt())); return getJobStatusResult( jobId: jobId, + mainRoute: mainRoute, ); } } else { @@ -77,4 +80,4 @@ class SharpApiService { return returnModel; } -} \ No newline at end of file +} diff --git a/lib/src/core/di/injection.dart b/lib/src/core/di/injection.dart index 0f17c87..6507bcb 100644 --- a/lib/src/core/di/injection.dart +++ b/lib/src/core/di/injection.dart @@ -6,6 +6,7 @@ import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; import 'package:sharpapi_flutter_client/src/e_commerce/e_commerce_api_service.dart'; import 'package:sharpapi_flutter_client/src/hr/hr_api_service.dart'; import 'package:sharpapi_flutter_client/src/seo/seo_api_service.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/subscription_info_api_service.dart'; import 'package:sharpapi_flutter_client/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart'; final sl = GetIt.instance; @@ -46,6 +47,13 @@ Future initDi() async { ), ); + sl.registerFactory( + () => SubscriptionInfoApiService( + repository: sl(), + sharpApiService: sl(), + ), + ); + sl.registerFactory( () => SharpApiService( repository: sl(), diff --git a/lib/src/core/models/general_model.dart b/lib/src/core/models/general_model.dart index cd0000b..bbce66c 100644 --- a/lib/src/core/models/general_model.dart +++ b/lib/src/core/models/general_model.dart @@ -1,11 +1,14 @@ class GeneralModel { final String? statusUrl; + final String? jobId; GeneralModel({ this.statusUrl, + this.jobId, }); factory GeneralModel.fromJson(Map json) => GeneralModel( statusUrl: json['status_url'], + jobId: json['job_id'], ); } \ No newline at end of file diff --git a/lib/src/core/models/job_model.dart b/lib/src/core/models/job_model.dart index 74f4082..f9420cb 100644 --- a/lib/src/core/models/job_model.dart +++ b/lib/src/core/models/job_model.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + class JobModel { String? type; String? id; @@ -15,6 +17,6 @@ class JobModel { type: json['data'] != null ? json['data']['attributes']['type'] : '', id: json['data'] != null ? json['data']['id'] : '', status: json['data'] != null ? json['data']['attributes']['status'] : '', - result: json['data'] != null ? json['data']['attributes']['result'] : null, + result: json['data'] != null ? jsonEncode(json['data']['attributes']['result']) : null, ); } \ No newline at end of file diff --git a/lib/src/core/network/remote/api_endpoints.dart b/lib/src/core/network/remote/api_endpoints.dart index 12b821e..4385f16 100644 --- a/lib/src/core/network/remote/api_endpoints.dart +++ b/lib/src/core/network/remote/api_endpoints.dart @@ -44,7 +44,17 @@ const String detectEmailsRoute = 'content/detect_emails'; const String summarizeTextRoute = 'content/summarize'; +const String paraphraseTextRoute = 'content/paraphrase'; + +const String proofreadTextRoute = 'content/proofread'; + const String generateKeywordsRoute = 'content/keywords'; // ---- job status ---- -const String jobStatusRoute = 'job/status'; \ No newline at end of file +const String jobStatusRoute = 'job/status'; + +// ---- subscription info ---- + +const String quotaRoute = 'quota'; + +const String pingRoute = 'ping'; \ No newline at end of file diff --git a/lib/src/core/network/remote/dio_helper.dart b/lib/src/core/network/remote/dio_helper.dart index f6e5e4d..b5d59a9 100644 --- a/lib/src/core/network/remote/dio_helper.dart +++ b/lib/src/core/network/remote/dio_helper.dart @@ -62,7 +62,7 @@ class DioImpl extends DioHelper { dio.options.headers = { if (isMultipart) 'Content-Type': 'multipart/form-data', - 'User-Agent': 'SharpAPIDartAgent/1.0.0', + 'User-Agent': 'SharpAPIDartAgent/1.2.0', if (!isMultipart) 'Accept': 'application/json', if (token != null) 'Authorization': 'Bearer $token' @@ -111,7 +111,7 @@ class DioImpl extends DioHelper { dio.options.headers = { if (isMultipart) 'Content-Type': 'multipart/form-data', - 'User-Agent': 'SharpAPIDartAgent/1.0.0', + 'User-Agent': 'SharpAPIDartAgent/1.2.0', if (!isMultipart) 'Accept': 'application/json', if (token != null) 'Authorization': 'Bearer $token' diff --git a/lib/src/core/network/repository.dart b/lib/src/core/network/repository.dart index 9e15bd1..5a68149 100644 --- a/lib/src/core/network/repository.dart +++ b/lib/src/core/network/repository.dart @@ -9,10 +9,13 @@ import 'package:sharpapi_flutter_client/src/core/models/job_model.dart'; import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/remote/dio_helper.dart'; import 'package:sharpapi_flutter_client/src/hr/dto/generate_job_description_dto.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/ping_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/quota_model.dart'; abstract class Repository { Future> getJobStatusResult({ required String jobId, + required String mainRoute, }); Future> generateJobDescription({ @@ -22,11 +25,13 @@ abstract class Repository { Future> relatedSkills({ required String skill, required String language, + int? maxQuantity, }); Future> relatedJobPositions({ required String jobTitle, required String language, + int? maxQuantity, }); Future> parseResume({ @@ -42,21 +47,30 @@ abstract class Repository { Future> productCategories({ required String content, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }); Future> generateProductIntro({ required String content, required String language, + int? maxLength, + String? voiceTone, }); Future> generateThankYouEmail({ required String content, required String language, + int? maxLength, + String? voiceTone, + String? context, }); Future> generateSeoTags({ required String content, required String language, + String? voiceTone, }); Future> travelReviewSentiment({ @@ -69,6 +83,9 @@ abstract class Repository { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }); Future> hospitalityProductCategories({ @@ -76,11 +93,16 @@ abstract class Repository { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }); Future> translate({ required String text, required String language, + String? voiceTone, + String? context, }); Future> detectSpam({ @@ -98,12 +120,31 @@ abstract class Repository { Future> summarizeText({ required String content, required String language, + int? maxLength, + String? voiceTone, + }); + + Future> paraphraseText({ + required String content, + required String language, + String? voiceTone, + int? maxLength, + String? context, + }); + + Future> proofreadText({ + required String content, }); Future> generateKeywords({ required String content, required String language, + String? voiceTone, }); + + Future> quota(); + + Future> ping(); } class RepoImplementation extends Repository { @@ -113,17 +154,69 @@ class RepoImplementation extends Repository { required this.dioHelper, }); + ///*** ping + @override + Future> ping() async { + return _basicErrorHandling( + onSuccess: () async { + final Response f = await dioHelper.get( + url: pingRoute, + token: SharpApiConfigs.apiKey, + ); + + // log('summarize text: ${f.data}'); + + return PingModel.fromJson(f.data); + }, + onServerError: (exception) async { + // log('errorFromRepo => ${exception.message}'); + + return exception.message; + }, + onOtherError: (exception) async { + return exception.token; + }, + ); + } + + ///*** get quota + @override + Future> quota() async { + return _basicErrorHandling( + onSuccess: () async { + final Response f = await dioHelper.get( + url: quotaRoute, + token: SharpApiConfigs.apiKey, + ); + + // log('summarize text: ${f.data}'); + + return QuotaModel.fromJson(f.data); + }, + onServerError: (exception) async { + // log('errorFromRepo => ${exception.message}'); + + return exception.message; + }, + onOtherError: (exception) async { + return exception.token; + }, + ); + } + ///*** generate keywords @override Future> generateKeywords({ required String content, required String language, + String? voiceTone, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: generateKeywordsRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (voiceTone != null) 'voice_tone': voiceTone, }); // log('generate keywords: ${f.data}'); @@ -146,12 +239,16 @@ class RepoImplementation extends Repository { Future> summarizeText({ required String content, required String language, + int? maxLength, + String? voiceTone, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: summarizeTextRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (maxLength != null) 'max_length': maxLength, + if (voiceTone != null) 'voice_tone': voiceTone, }); // log('summarize text: ${f.data}'); @@ -169,6 +266,74 @@ class RepoImplementation extends Repository { ); } + ///*** paraphrase text + @override + Future> paraphraseText({ + required String content, + required String language, + String? voiceTone, + int? maxLength, + String? context, + }) async { + return _basicErrorHandling( + onSuccess: () async { + final Response f = await dioHelper.post( + url: paraphraseTextRoute, + token: SharpApiConfigs.apiKey, + data: { + 'content': content, + 'language': language, + if (voiceTone != null) 'voice_tone': voiceTone, + if (maxLength != null) 'max_length': maxLength, + if (context != null) 'context': context, + }, + ); + + // log('summarize text: ${f.data}'); + + return GeneralModel.fromJson(f.data); + }, + onServerError: (exception) async { + // log('errorFromRepo => ${exception.message}'); + + return exception.message; + }, + onOtherError: (exception) async { + return exception.token; + }, + ); + } + + ///*** proofread text + @override + Future> proofreadText({ + required String content, + }) async { + return _basicErrorHandling( + onSuccess: () async { + final Response f = await dioHelper.post( + url: proofreadTextRoute, + token: SharpApiConfigs.apiKey, + data: { + 'content': content, + }, + ); + + // log('summarize text: ${f.data}'); + + return GeneralModel.fromJson(f.data); + }, + onServerError: (exception) async { + // log('errorFromRepo => ${exception.message}'); + + return exception.message; + }, + onOtherError: (exception) async { + return exception.token; + }, + ); + } + ///*** detect emails @override Future> detectEmails({ @@ -252,12 +417,16 @@ class RepoImplementation extends Repository { Future> translate({ required String text, required String language, + String? voiceTone, + String? context, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: translateTextRoute, token: SharpApiConfigs.apiKey, data: { 'content': text, 'language': language, + if (voiceTone != null) 'voice_tone': voiceTone, + if (context != null) 'context': context, }); // log('generate job description: ${f.data}'); @@ -282,14 +451,20 @@ class RepoImplementation extends Repository { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: hospitalityProductCategoriesRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, - if(city != null) 'city': city, - if(country != null) 'country': country, + if (city != null) 'city': city, + if (country != null) 'country': country, 'language': language, + if (maxQuantity != null) 'max_quantity': maxQuantity, + if (voiceTone != null) 'voice_tone': voiceTone, + if (context != null) 'context': context, }); // log('generate job description: ${f.data}'); @@ -314,14 +489,20 @@ class RepoImplementation extends Repository { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: toursAndActivitiesProductCategoriesRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, - if(city != null) 'city': city, - if(country != null) 'country': country, + if (city != null) 'city': city, + if (country != null) 'country': country, 'language': language, + if (maxQuantity != null) 'max_quantity': maxQuantity, + if (voiceTone != null) 'voice_tone': voiceTone, + if (context != null) 'context': context, }); // log('generate job description: ${f.data}'); @@ -339,7 +520,6 @@ class RepoImplementation extends Repository { ); } - ///*** travel review sentiment @override Future> travelReviewSentiment({ @@ -373,12 +553,14 @@ class RepoImplementation extends Repository { Future> generateSeoTags({ required String content, required String language, + String? voiceTone, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: generateSeoTagsRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (voiceTone != null) 'voice_tone': voiceTone, }); // log('generate job description: ${f.data}'); @@ -401,12 +583,18 @@ class RepoImplementation extends Repository { Future> generateThankYouEmail({ required String content, required String language, + int? maxLength, + String? voiceTone, + String? context, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: generateThankYouEmailRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (maxLength != null) 'max_length': maxLength, + if (voiceTone != null) 'voice_tone': voiceTone, + if (context != null) 'context': context, }); // log('generate job description: ${f.data}'); @@ -429,12 +617,16 @@ class RepoImplementation extends Repository { Future> generateProductIntro({ required String content, required String language, + int? maxLength, + String? voiceTone, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: generateProductIntroRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (maxLength != null) 'max_length': maxLength, + if (voiceTone != null) 'voice_tone': voiceTone, }); // log('generate job description: ${f.data}'); @@ -457,12 +649,18 @@ class RepoImplementation extends Repository { Future> productCategories({ required String content, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: productCategoriesRoute, token: SharpApiConfigs.apiKey, data: { 'content': content, 'language': language, + if (maxQuantity != null) 'max_quantity': maxQuantity, + if (voiceTone != null) 'voice_tone': voiceTone, + if (context != null) 'context': context, }); // log('generate job description: ${f.data}'); @@ -550,12 +748,14 @@ class RepoImplementation extends Repository { Future> relatedJobPositions({ required String jobTitle, required String language, + int? maxQuantity, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: relatedJobPositionsRoute, token: SharpApiConfigs.apiKey, data: { 'content': jobTitle, 'language': language, + if (maxQuantity != null) 'max_quantity': maxQuantity, }); // log('generate job description: ${f.data}'); @@ -578,12 +778,14 @@ class RepoImplementation extends Repository { Future> relatedSkills({ required String skill, required String language, + int? maxQuantity, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.post(url: relatedSkillsRoute, token: SharpApiConfigs.apiKey, data: { 'content': skill, 'language': language, + if (maxQuantity != null) 'max_quantity': maxQuantity, }); // log('generate job description: ${f.data}'); @@ -633,11 +835,12 @@ class RepoImplementation extends Repository { @override Future> getJobStatusResult({ required String jobId, + required String mainRoute, }) async { return _basicErrorHandling( onSuccess: () async { final Response f = await dioHelper.get( - url: '$jobStatusRoute/$jobId', + url: '$mainRoute/$jobStatusRoute/$jobId', token: SharpApiConfigs.apiKey, ); @@ -666,19 +869,19 @@ extension on Repository { try { final f = await onSuccess(); return Right(f); - } on ServerException catch (e, s) { + } on ServerException catch (e) { if (onServerError != null) { final f = await onServerError(e); return Left(f); } return const Left('Server Error'); - } on CacheException catch (e, s) { + } on CacheException catch (e) { if (onCacheError != null) { final f = await onCacheError(e); return Left(f); } return const Left('Cache Error'); - } catch (e, s) { + } catch (e) { if (onOtherError != null) { final f = await onOtherError(e); return Left(f); diff --git a/lib/src/e_commerce/e_commerce_api_service.dart b/lib/src/e_commerce/e_commerce_api_service.dart index 6b8e096..20622b2 100644 --- a/lib/src/e_commerce/e_commerce_api_service.dart +++ b/lib/src/e_commerce/e_commerce_api_service.dart @@ -3,6 +3,7 @@ import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; import 'package:sharpapi_flutter_client/src/core/models/category_model.dart'; import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; import 'package:sharpapi_flutter_client/src/core/models/review_sentiment_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; import 'package:sharpapi_flutter_client/src/e_commerce/models/product_intro_model.dart'; import 'package:sharpapi_flutter_client/src/e_commerce/models/thank_you_email_model.dart'; @@ -63,7 +64,8 @@ class ECommerceApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: productReviewSentimentRoute, ); productReviewModel = ReviewSentimentModel.fromJson(result); @@ -80,10 +82,16 @@ class ECommerceApiService { Future _productCategories({ required String content, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { final result = await _repository.productCategories( content: content, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); GeneralModel generalModel = GeneralModel(); @@ -106,6 +114,9 @@ class ECommerceApiService { Future> productCategories({ required String content, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { GeneralModel? generalModel; @@ -113,6 +124,9 @@ class ECommerceApiService { generalModel = await _productCategories( content: content, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -122,7 +136,8 @@ class ECommerceApiService { try { List result = await _sharpApiService.getJobStatusResult( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: productCategoriesRoute, ); productCategoriesModel = (result).map((e) => CategoryModel.fromJson(e)).toList(); @@ -139,10 +154,14 @@ class ECommerceApiService { Future _generateProductIntro({ required String content, required String language, + int? maxLength, + String? voiceTone, }) async { final result = await _repository.generateProductIntro( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); GeneralModel generalModel = GeneralModel(); @@ -165,6 +184,8 @@ class ECommerceApiService { Future generateProductIntro({ required String content, required String language, + int? maxLength, + String? voiceTone, }) async { GeneralModel? generalModel; @@ -172,6 +193,8 @@ class ECommerceApiService { generalModel = await _generateProductIntro( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -181,7 +204,8 @@ class ECommerceApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: generateProductIntroRoute, ); productIntroModel = ProductIntroModel.fromJson(result); @@ -198,10 +222,16 @@ class ECommerceApiService { Future _generateThankYouEmail({ required String content, required String language, + int? maxLength, + String? voiceTone, + String? context, }) async { final result = await _repository.generateThankYouEmail( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, + context: context, ); GeneralModel generalModel = GeneralModel(); @@ -224,6 +254,9 @@ class ECommerceApiService { Future generateThankYouEmail({ required String content, required String language, + int? maxLength, + String? voiceTone, + String? context, }) async { GeneralModel? generalModel; @@ -231,6 +264,9 @@ class ECommerceApiService { generalModel = await _generateThankYouEmail( content: content, language: language, + maxLength: maxLength, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -240,7 +276,8 @@ class ECommerceApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: generateThankYouEmailRoute, ); thankYouEmailModel = ThankYouEmailModel.fromJson(result); diff --git a/lib/src/hr/dto/generate_job_description_dto.dart b/lib/src/hr/dto/generate_job_description_dto.dart index 47d275c..f61db77 100644 --- a/lib/src/hr/dto/generate_job_description_dto.dart +++ b/lib/src/hr/dto/generate_job_description_dto.dart @@ -10,6 +10,8 @@ class GenerateJobDescriptionDto { List? requiredSkills; List? optionalSkills; String language; + String? voiceTone; + String? context; GenerateJobDescriptionDto({ required this.name, @@ -23,6 +25,8 @@ class GenerateJobDescriptionDto { this.requiredSkills, this.optionalSkills, this.language = 'English', + this.voiceTone, + this.context, }); Map toJson() => { @@ -37,5 +41,7 @@ class GenerateJobDescriptionDto { if(requiredSkills != null) 'required_skills': requiredSkills, if(optionalSkills != null) 'optional_skills': optionalSkills, 'language': language, + if(voiceTone != null) 'voice_tone': voiceTone, + if(context != null) 'context': context, }; } \ No newline at end of file diff --git a/lib/src/hr/hr_api_service.dart b/lib/src/hr/hr_api_service.dart index 4dc8051..ebb8f8d 100644 --- a/lib/src/hr/hr_api_service.dart +++ b/lib/src/hr/hr_api_service.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:sharpapi_flutter_client/src/core/SharpApiService.dart'; import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; import 'package:sharpapi_flutter_client/src/hr/dto/generate_job_description_dto.dart'; import 'package:sharpapi_flutter_client/src/hr/models/generate_job_description_model.dart'; @@ -60,7 +61,8 @@ class HrApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: generateJobDescriptionRoute, ); generateJobDescriptionModel = GenerateJobDescriptionModel.fromJson(result); @@ -77,10 +79,12 @@ class HrApiService { Future _relatedSkills({ required String skill, required String language, + int? maxQuantity, }) async { final result = await _repository.relatedSkills( skill: skill, language: language, + maxQuantity: maxQuantity, ); GeneralModel generalModel = GeneralModel(); @@ -103,6 +107,7 @@ class HrApiService { Future relatedSkills({ required String skill, required String language, + int? maxQuantity, }) async { GeneralModel? generalModel; @@ -110,6 +115,7 @@ class HrApiService { generalModel = await _relatedSkills( skill: skill, language: language, + maxQuantity: maxQuantity, ); } catch (error) { rethrow; @@ -119,7 +125,8 @@ class HrApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: relatedSkillsRoute, ); relatedSkillsModel = RelatedSkillsModel.fromJson(result); @@ -136,10 +143,12 @@ class HrApiService { Future _relatedJobPositions({ required String jobTitle, required String language, + int? maxQuantity, }) async { final result = await _repository.relatedJobPositions( jobTitle: jobTitle, language: language, + maxQuantity: maxQuantity, ); GeneralModel generalModel = GeneralModel(); @@ -162,6 +171,7 @@ class HrApiService { Future relatedJobPositions({ required String jobTitle, required String language, + int? maxQuantity, }) async { GeneralModel? generalModel; @@ -169,26 +179,28 @@ class HrApiService { generalModel = await _relatedJobPositions( jobTitle: jobTitle, language: language, + maxQuantity: maxQuantity, ); } catch (error) { rethrow; } - RelatedJobPositionModel? relatedSkillsModel; + RelatedJobPositionModel? relatedJobPositionModel; try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: relatedJobPositionsRoute, ); - relatedSkillsModel = RelatedJobPositionModel.fromJson(result); + relatedJobPositionModel = RelatedJobPositionModel.fromJson(result); } catch (error) { // log('error => $error'); rethrow; } - return relatedSkillsModel; + return relatedJobPositionModel; } ///*** parse resume @@ -237,7 +249,8 @@ class HrApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: parseResumeRoute, ); parseResumeModel = ParseResumeModel.fromJson(result); diff --git a/lib/src/seo/seo_api_service.dart b/lib/src/seo/seo_api_service.dart index b0c948f..82bfd30 100644 --- a/lib/src/seo/seo_api_service.dart +++ b/lib/src/seo/seo_api_service.dart @@ -1,6 +1,7 @@ import 'package:sharpapi_flutter_client/src/core/SharpApiService.dart'; import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; import 'package:sharpapi_flutter_client/src/seo/models/generate_seo_tags_model.dart'; @@ -18,10 +19,12 @@ class SeoApiService { Future _generateSeoTags({ required String content, required String language, + String? voiceTone, }) async { final result = await _repository.generateSeoTags( content: content, language: language, + voiceTone: voiceTone, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -44,6 +47,7 @@ class SeoApiService { Future generateSeoTags({ required String content, required String language, + String? voiceTone, }) async { GeneralModel? generalModel; @@ -51,6 +55,7 @@ class SeoApiService { generalModel = await _generateSeoTags( content: content, language: language, + voiceTone: voiceTone, ); } catch (error) { rethrow; @@ -60,7 +65,8 @@ class SeoApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: generateSeoTagsRoute, ); generateSeoTagsModel = GenerateSeoTagsModel.fromJson(result); diff --git a/lib/src/subscription_info/models/ping_model.dart b/lib/src/subscription_info/models/ping_model.dart new file mode 100644 index 0000000..bae7998 --- /dev/null +++ b/lib/src/subscription_info/models/ping_model.dart @@ -0,0 +1,14 @@ +class PingModel { + String? ping; + String? timestamp; + + PingModel({ + this.ping, + this.timestamp, + }); + + factory PingModel.fromJson(Map json) => PingModel( + ping: json['ping'], + timestamp: json['timestamp'], + ); +} \ No newline at end of file diff --git a/lib/src/subscription_info/models/quota_model.dart b/lib/src/subscription_info/models/quota_model.dart new file mode 100644 index 0000000..1ac2909 --- /dev/null +++ b/lib/src/subscription_info/models/quota_model.dart @@ -0,0 +1,35 @@ +class QuotaModel { + String? timestamp; + bool? onTrial; + String? trialEnds; + bool? subscribed; + String? currentSubscriptionStart; + String? currentSubscriptionEnd; + int? subscriptionWordsQuota; + int? subscriptionWordsUsed; + int? subscriptionWordsUsedPercentage; + + QuotaModel({ + this.timestamp, + this.onTrial, + this.trialEnds, + this.subscribed, + this.currentSubscriptionStart, + this.currentSubscriptionEnd, + this.subscriptionWordsQuota, + this.subscriptionWordsUsed, + this.subscriptionWordsUsedPercentage, + }); + + factory QuotaModel.fromJson(Map json) => QuotaModel( + timestamp: json['timestamp'], + onTrial: json['on_trial'], + trialEnds: json['trial_ends'], + subscribed: json['subscribed'], + currentSubscriptionStart: json['current_subscription_start'], + currentSubscriptionEnd: json['current_subscription_end'], + subscriptionWordsQuota: json['subscription_words_quota'], + subscriptionWordsUsed: json['subscription_words_used'], + subscriptionWordsUsedPercentage: json['subscription_words_used_percentage'], + ); +} \ No newline at end of file diff --git a/lib/src/subscription_info/subscription_info_api_service.dart b/lib/src/subscription_info/subscription_info_api_service.dart new file mode 100644 index 0000000..bad6534 --- /dev/null +++ b/lib/src/subscription_info/subscription_info_api_service.dart @@ -0,0 +1,63 @@ +import 'package:sharpapi_flutter_client/src/core/SharpApiService.dart'; +import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; +import 'package:sharpapi_flutter_client/src/core/models/category_model.dart'; +import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; +import 'package:sharpapi_flutter_client/src/core/models/review_sentiment_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; +import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; +import 'package:sharpapi_flutter_client/src/e_commerce/models/product_intro_model.dart'; +import 'package:sharpapi_flutter_client/src/e_commerce/models/thank_you_email_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/ping_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/ping_model.dart'; +import 'package:sharpapi_flutter_client/src/subscription_info/models/quota_model.dart'; + +class SubscriptionInfoApiService { + final Repository _repository; + final SharpApiService _sharpApiService; + + SubscriptionInfoApiService({ + required Repository repository, + required SharpApiService sharpApiService, + }) : _repository = repository, + _sharpApiService = sharpApiService; + + ///*** quota + Future quota() async { + final result = await _repository.quota(); + + QuotaModel quotaModel = QuotaModel(); + + result.fold( + (error) { + // log('error2 -> $error'); + + throw SharpApiException(error); + }, + (data) { + quotaModel = data; + }, + ); + + return quotaModel; + } + + ///*** ping + Future ping() async { + final result = await _repository.ping(); + + PingModel pingModel = PingModel(); + + result.fold( + (error) { + // log('error2 -> $error'); + + throw SharpApiException(error); + }, + (data) { + pingModel = data; + }, + ); + + return pingModel; + } +} \ No newline at end of file diff --git a/lib/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart b/lib/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart index 6e7a477..6cb6739 100644 --- a/lib/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart +++ b/lib/src/travel_tourism_hospitality/travel_tourism_hospitality_api_service.dart @@ -3,6 +3,7 @@ import 'package:sharpapi_flutter_client/src/core/error/exceptions.dart'; import 'package:sharpapi_flutter_client/src/core/models/category_model.dart'; import 'package:sharpapi_flutter_client/src/core/models/general_model.dart'; import 'package:sharpapi_flutter_client/src/core/models/review_sentiment_model.dart'; +import 'package:sharpapi_flutter_client/src/core/network/remote/api_endpoints.dart'; import 'package:sharpapi_flutter_client/src/core/network/repository.dart'; class TravelTourismHospitalityApiService { @@ -61,7 +62,8 @@ class TravelTourismHospitalityApiService { try { Map result = await _sharpApiService.getJobStatusResult>( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: travelReviewSentimentRoute, ); travelReviewSentimentModel = ReviewSentimentModel.fromJson(result); @@ -80,12 +82,18 @@ class TravelTourismHospitalityApiService { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { final result = await _repository.toursAndActivitiesProductCategories( content: content, city: city, country: country, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -110,6 +118,9 @@ class TravelTourismHospitalityApiService { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { GeneralModel? generalModel; @@ -119,6 +130,9 @@ class TravelTourismHospitalityApiService { city: city, country: country, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -128,7 +142,8 @@ class TravelTourismHospitalityApiService { try { List result = await _sharpApiService.getJobStatusResult( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: toursAndActivitiesProductCategoriesRoute, ); toursAndActivitiesProductCategoriesModel = result.map((e) => CategoryModel.fromJson(e)).toList(); @@ -147,12 +162,18 @@ class TravelTourismHospitalityApiService { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { final result = await _repository.hospitalityProductCategories( content: content, city: city, country: country, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); GeneralModel generateJobDescriptionModel = GeneralModel(); @@ -177,6 +198,9 @@ class TravelTourismHospitalityApiService { String? city, String? country, required String language, + int? maxQuantity, + String? voiceTone, + String? context, }) async { GeneralModel? generalModel; @@ -186,6 +210,9 @@ class TravelTourismHospitalityApiService { city: city, country: country, language: language, + maxQuantity: maxQuantity, + voiceTone: voiceTone, + context: context, ); } catch (error) { rethrow; @@ -195,7 +222,8 @@ class TravelTourismHospitalityApiService { try { List result = await _sharpApiService.getJobStatusResult( - jobId: generalModel.statusUrl != null ? generalModel.statusUrl!.split('status/').last : '', + jobId: generalModel.jobId ?? '', + mainRoute: hospitalityProductCategoriesRoute, ); hospitalityProductCategoriesModel = result.map((e) => CategoryModel.fromJson(e)).toList(); diff --git a/pubspec.yaml b/pubspec.yaml index 4d75dfb..9ee4b30 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,16 +1,16 @@ name: sharpapi_flutter_client description: AI-Powered Swiss Army Knife API for every software developer. -version: 1.0.0 +version: 1.2.0 repository: https://github.com/sharpapi/sharpapi-flutter-client environment: sdk: ^3.2.6 dependencies: - dio: ^5.4.1 + dio: ^5.5.0+1 dartz: ^0.10.1 - get_it: ^7.6.7 + get_it: ^7.7.0 dev_dependencies: - lints: ^3.0.0 + lints: ^4.0.0 test: ^1.25.2 \ No newline at end of file