get-reading-time 1.0.5 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Md Nur Ahmad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  # Text Analysis Tool
2
3
 
3
4
  A simple text analysis tool that provides insights into text such as reading time, word count, sentiment, readability score, link count, and SEO-friendly keywords.
@@ -12,6 +13,8 @@ A simple text analysis tool that provides insights into text such as reading tim
12
13
  - **Readability Score**: Calculates the Flesch Reading Ease score to evaluate the text's readability.
13
14
  - **Sentiment Analysis**: Analyzes the sentiment of the text (Positive, Negative, or Neutral).
14
15
  - **SEO-friendly Keywords**: Extracts the top 5 SEO-friendly keywords or key phrases (bi-grams and tri-grams) from the text.
16
+ - **aiTexGen**: Allows users to generate content based on a search prompt using the Cohere AI API, with a specified word count.
17
+ - **Automatic Punctuation and Capitalization**: Automatically adds proper punctuation and capitalizes the beginning of sentences in a provided text.
15
18
 
16
19
  ## Installation
17
20
 
@@ -35,7 +38,7 @@ Here’s how you can use the analyzeText function to analyze a piece of text:
35
38
  import { analyzeText } from "get-reading-time/dist/index.js";
36
39
  ```
37
40
 
38
- // Example input text
41
+ ### Example Code
39
42
 
40
43
  ```javascript
41
44
  const text = `This is an example of text. It contains words, sentences, and links like there are https://linkedin.com/in/06nurahmed https://github.com/nurahmed123`;
@@ -81,10 +84,95 @@ try {
81
84
  }
82
85
  ```
83
86
 
87
+ ### aiTexGen: Generate your content
88
+ This new feature allows users to generate content using Cohere AI. You provide your Cohere API key, a search prompt, and a word count, and it will return the generated content.
89
+
90
+ ### Usage
91
+ To use the **aiTexGen** feature, follow these steps:
92
+ ```bash
93
+ import { aiTexGen } from "get-reading-time/dist/index.js";
94
+ ```
95
+
96
+ ### Example Code
97
+ - Create your [Api key](https://dashboard.cohere.com/api-keys) From here.
98
+ ```javascript
99
+ // Replace this with your Cohere API key
100
+ const apiKey = '<api-key>';
101
+ const generator = new aiTexGen(apiKey);
102
+
103
+ async function testGenerateContent() {
104
+ try {
105
+ // Define a topic and word count for testing
106
+ const topic = 'arduino';
107
+ const wordCount = 100;
108
+
109
+ // Call the generateContent method
110
+ const result = await generator.generateContent(topic, wordCount);
111
+
112
+ // Output the result in JSON format
113
+ console.log('Generated Content (JSON Format):');
114
+ console.log(JSON.stringify(result, null, 2)); // Pretty print the JSON output
115
+
116
+ } catch (error) {
117
+ console.error('Error during content generation:', error);
118
+ }
119
+ }
120
+ // Run the test
121
+ testGenerateContent();
122
+ ```
123
+ ### Example Output
124
+ ```json
125
+ {
126
+ "topic": "arduino",
127
+ "content": "Arduino is an open-source electronics platform based on easy-to-use hardware and software. It's designed to make interactive projects accessible to everyone, from artists and designers to hobbyists and engineers. \n\nAt the heart of the Arduino platform is the Arduino board, a simple microcontroller board that can read inputs and turn them into outputs, such as turning on an LED light or activating a motor. \n\nWhat makes Arduino unique is its user-friendly approach, with a simplified programming language and easy-to-use hardware, making it a popular choice for beginners and professionals alike. With its versatility and robust community support, Arduino has become a go-to platform for creating interactive, sensor-based projects and prototypes."
128
+ }
129
+ ```
130
+
131
+ ### Automatic Punctuation and Capitalization
132
+
133
+ You can now pass an article to the `analyzeText` function, and it will automatically fix punctuation and capitalize the first letter of sentences. This feature helps to improve the readability of raw text.
134
+
135
+ #### Example Code
136
+ Import the package and follow the steps:
137
+ ```javascript
138
+ import { getPunch } from 'get-reading-time/dist/index.js';
139
+ ```
140
+
141
+ ```javascript
142
+ // Example to test with a string
143
+ const content = "once a lion a fox and a wolf went hunting they ultimately spotted a stag and killed him for their food while sharing the hunt quarter me this stag roared the lion and other animals skinned and cut the spoil into four equal parts";
144
+ async function GetPunch() {
145
+ try {
146
+ // Call the getPunch function with content
147
+ const result = await getPunch(content);
148
+
149
+ // Check the result and log it as a formatted JSON response
150
+ if (result.status_code === 200) {
151
+ console.log(JSON.stringify(result, null, 2));
152
+ } else {
153
+ console.error("Error:", JSON.stringify(result, null, 2));
154
+ }
155
+ } catch (error) {
156
+ // Handle unexpected errors
157
+ console.error("Unexpected Error:", error);
158
+ }
159
+ }
160
+ // Run the test
161
+ GetPunch();
162
+ ```
163
+
164
+ ### Example Output
165
+ ```json
166
+ {
167
+ "content": "Once a Lion, a Fox and a Wolf went hunting, they ultimately found a stag and killed him for their food while sharing the hunt quarter me. This stag roared the Lion and other animals skinned and cut the spoil into four equal parts.",
168
+ "status_code": 200
169
+ }
170
+ ```
84
171
  ## Parameters
85
172
 
86
173
  - text: The text to be analyzed (required).
87
174
  - wordsPerMinute: The reading speed in words per minute (optional, default is 200 words per minute).
175
+ - **apiKey**: Your Cohere API key to use this feature (required).
88
176
 
89
177
  ## Functions
90
178
 
@@ -100,6 +188,8 @@ Analyzes the provided text and returns an object containing:
100
188
  - readabilityScore: Flesch Reading Ease score (higher is easier to read).
101
189
  - sentiment: Sentiment of the text (Positive, Negative, or Neutral).
102
190
  - keywords: Top 5 SEO-friendly keywords or key phrases.
191
+ ### Generate Content(topic: string, wordCount: number)
192
+ Generates content based on the given topic and word count using the Cohere AI API and returns the generated content.
103
193
 
104
194
  ### Helper Functions
105
195
 
@@ -113,6 +203,8 @@ Analyzes the provided text and returns an object containing:
113
203
  - **extractKeywords(text: string)**: Extracts the top 5 SEO-friendly keywords or key phrases.
114
204
  - **extractNGrams(words: string[])**: Extracts bi-grams and tri-grams from the list of words.
115
205
  - **isStopWord(word: string, stopWords: Set<string>)**: Checks if a word is a stop word to exclude from keyword extraction.
206
+ - **generateContent(words: string[])**: Genarate text based on the query and word limit.
207
+ - **autoPunctuateAndCapitalize(text: string)**: Adds punctuation and capitalization to the content.
116
208
 
117
209
  ## Contributing
118
210
 
@@ -120,7 +212,8 @@ Feel free to fork the repository, make your changes, and submit a pull request.
120
212
 
121
213
  ## License
122
214
 
123
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
215
+ This project is licensed under the MIT License - see the [LICENSE](https://github.com/nurahmed123/get-reading-time/blob/main/LICENSE) file for details.
216
+ [![npm version](https://badge.fury.io/js/get-reading-time.svg)](https://www.npmjs.com/get-reading-time)
124
217
 
125
218
  ## Contact
126
219
 
package/dist/index.d.mts CHANGED
@@ -14,4 +14,26 @@ interface TextAnalysisResult {
14
14
  }
15
15
  declare function analyzeText(text: string, wordsPerMinute?: number): TextAnalysisResult;
16
16
 
17
- export { analyzeText };
17
+ type ApiResponse = {
18
+ formatted_text?: string;
19
+ error?: string;
20
+ status_code: number;
21
+ content?: string;
22
+ };
23
+ declare function getPunch(next: string): Promise<ApiResponse>;
24
+
25
+ declare class AiTexGen {
26
+ private cohereClient;
27
+ constructor(apiKey: string);
28
+ private validateInputs;
29
+ generateContent(topic: string, wordCount?: number): Promise<{
30
+ topic: string;
31
+ content: string;
32
+ }>;
33
+ private processContent;
34
+ private extractTextFromObject;
35
+ private createErrorResponse;
36
+ private formatErrorDetails;
37
+ }
38
+
39
+ export { AiTexGen as aiTexGen, analyzeText, getPunch };
package/dist/index.d.ts CHANGED
@@ -14,4 +14,26 @@ interface TextAnalysisResult {
14
14
  }
15
15
  declare function analyzeText(text: string, wordsPerMinute?: number): TextAnalysisResult;
16
16
 
17
- export { analyzeText };
17
+ type ApiResponse = {
18
+ formatted_text?: string;
19
+ error?: string;
20
+ status_code: number;
21
+ content?: string;
22
+ };
23
+ declare function getPunch(next: string): Promise<ApiResponse>;
24
+
25
+ declare class AiTexGen {
26
+ private cohereClient;
27
+ constructor(apiKey: string);
28
+ private validateInputs;
29
+ generateContent(topic: string, wordCount?: number): Promise<{
30
+ topic: string;
31
+ content: string;
32
+ }>;
33
+ private processContent;
34
+ private extractTextFromObject;
35
+ private createErrorResponse;
36
+ private formatErrorDetails;
37
+ }
38
+
39
+ export { AiTexGen as aiTexGen, analyzeText, getPunch };
package/dist/index.js CHANGED
@@ -26,13 +26,37 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var __async = (__this, __arguments, generator) => {
30
+ return new Promise((resolve, reject) => {
31
+ var fulfilled = (value) => {
32
+ try {
33
+ step(generator.next(value));
34
+ } catch (e) {
35
+ reject(e);
36
+ }
37
+ };
38
+ var rejected = (value) => {
39
+ try {
40
+ step(generator.throw(value));
41
+ } catch (e) {
42
+ reject(e);
43
+ }
44
+ };
45
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
46
+ step((generator = generator.apply(__this, __arguments)).next());
47
+ });
48
+ };
29
49
 
30
50
  // src/index.ts
31
51
  var index_exports = {};
32
52
  __export(index_exports, {
33
- analyzeText: () => analyzeText
53
+ aiTexGen: () => AiTexGen,
54
+ analyzeText: () => analyzeText,
55
+ getPunch: () => getPunch
34
56
  });
35
57
  module.exports = __toCommonJS(index_exports);
58
+
59
+ // src/utils/analyzeText.ts
36
60
  var import_sentiment = __toESM(require("sentiment"));
37
61
  var DEFAULT_READING_SPEED = 200;
38
62
  function analyzeText(text, wordsPerMinute = DEFAULT_READING_SPEED) {
@@ -160,7 +184,124 @@ function extractNGrams(words) {
160
184
  function isStopWord(word, stopWords) {
161
185
  return stopWords.has(word);
162
186
  }
187
+
188
+ // src/utils/getPunch.ts
189
+ var import_axios = __toESM(require("axios"));
190
+ var API_URL = "https://e4fc-35-185-85-107.ngrok-free.app/get-reading-time";
191
+ var SECRET_CODE = "amrseccode";
192
+ function getPunch(next) {
193
+ return __async(this, null, function* () {
194
+ var _a;
195
+ try {
196
+ const response = yield import_axios.default.post(API_URL, {
197
+ secret_code: SECRET_CODE,
198
+ content: next
199
+ });
200
+ return {
201
+ content: response.data.formatted_text || "No content returned",
202
+ status_code: 200
203
+ };
204
+ } catch (error) {
205
+ return {
206
+ error: ((_a = error.response) == null ? void 0 : _a.data) || "Failed to get response from the server.",
207
+ status_code: 500
208
+ };
209
+ }
210
+ });
211
+ }
212
+
213
+ // src/utils/aiTexGen.ts
214
+ var import_cohere_ai = require("cohere-ai");
215
+ var AiTexGen = class {
216
+ constructor(apiKey) {
217
+ if (!apiKey || typeof apiKey !== "string") {
218
+ throw this.createErrorResponse("API_KEY_MISSING", "A valid API key must be provided.", 400);
219
+ }
220
+ this.cohereClient = new import_cohere_ai.CohereClientV2({ token: apiKey });
221
+ }
222
+ // Validate user input (topic and word count)
223
+ validateInputs(topic, wordCount) {
224
+ if (typeof topic !== "string" || topic.trim().length === 0) {
225
+ throw this.createErrorResponse("INVALID_TOPIC", "Topic must be a non-empty string.", 400);
226
+ }
227
+ if (typeof wordCount !== "number" || wordCount <= 0) {
228
+ console.warn("Invalid word count provided. Defaulting to 100 words.");
229
+ wordCount = 100;
230
+ }
231
+ }
232
+ // Generate content using Cohere's API
233
+ generateContent(topic, wordCount = 100) {
234
+ return __async(this, null, function* () {
235
+ var _a;
236
+ try {
237
+ this.validateInputs(topic, wordCount);
238
+ const prompt = `Write a detailed article about ${topic}, aiming for maximum ${wordCount} words.`;
239
+ const response = yield this.cohereClient.chat({
240
+ model: "command-r-plus",
241
+ // Specify the model you want to use
242
+ messages: [
243
+ {
244
+ role: "user",
245
+ content: prompt
246
+ // Use the prompt with the topic and word count
247
+ }
248
+ ]
249
+ });
250
+ const content = this.processContent((_a = response.message) == null ? void 0 : _a.content);
251
+ return {
252
+ topic,
253
+ content
254
+ };
255
+ } catch (error) {
256
+ console.error("Error generating content from Cohere API:", error);
257
+ throw this.createErrorResponse("API_ERROR", "Failed to generate content from Cohere API.", 500, this.formatErrorDetails(error));
258
+ }
259
+ });
260
+ }
261
+ // Helper method to process the content and format it properly
262
+ processContent(content) {
263
+ if (!content || content.length === 0) {
264
+ return "No content generated or content is empty.";
265
+ }
266
+ return content.map((item) => {
267
+ if (typeof item === "string") {
268
+ return item.trim();
269
+ } else if (typeof item === "object") {
270
+ return this.extractTextFromObject(item);
271
+ }
272
+ return "";
273
+ }).join(" ").trim();
274
+ }
275
+ // Helper method to safely extract text from an object, if needed
276
+ extractTextFromObject(obj) {
277
+ if (obj && obj.text) {
278
+ return obj.text.trim();
279
+ }
280
+ return "";
281
+ }
282
+ // Helper method to create an error response with a status code
283
+ createErrorResponse(code, message, statusCode, details) {
284
+ return {
285
+ error: {
286
+ code,
287
+ message,
288
+ statusCode,
289
+ details: details || ""
290
+ }
291
+ };
292
+ }
293
+ // Helper method to format error details (narrowing down the 'unknown' type)
294
+ formatErrorDetails(error) {
295
+ if (error instanceof Error) {
296
+ return error.message;
297
+ } else {
298
+ return "An unknown error occurred.";
299
+ }
300
+ }
301
+ };
163
302
  // Annotate the CommonJS export names for ESM import in node:
164
303
  0 && (module.exports = {
165
- analyzeText
304
+ aiTexGen,
305
+ analyzeText,
306
+ getPunch
166
307
  });
package/dist/index.mjs CHANGED
@@ -1,4 +1,25 @@
1
- // src/index.ts
1
+ var __async = (__this, __arguments, generator) => {
2
+ return new Promise((resolve, reject) => {
3
+ var fulfilled = (value) => {
4
+ try {
5
+ step(generator.next(value));
6
+ } catch (e) {
7
+ reject(e);
8
+ }
9
+ };
10
+ var rejected = (value) => {
11
+ try {
12
+ step(generator.throw(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ };
17
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
18
+ step((generator = generator.apply(__this, __arguments)).next());
19
+ });
20
+ };
21
+
22
+ // src/utils/analyzeText.ts
2
23
  import Sentiment from "sentiment";
3
24
  var DEFAULT_READING_SPEED = 200;
4
25
  function analyzeText(text, wordsPerMinute = DEFAULT_READING_SPEED) {
@@ -126,6 +147,123 @@ function extractNGrams(words) {
126
147
  function isStopWord(word, stopWords) {
127
148
  return stopWords.has(word);
128
149
  }
150
+
151
+ // src/utils/getPunch.ts
152
+ import axios from "axios";
153
+ var API_URL = "https://e4fc-35-185-85-107.ngrok-free.app/get-reading-time";
154
+ var SECRET_CODE = "amrseccode";
155
+ function getPunch(next) {
156
+ return __async(this, null, function* () {
157
+ var _a;
158
+ try {
159
+ const response = yield axios.post(API_URL, {
160
+ secret_code: SECRET_CODE,
161
+ content: next
162
+ });
163
+ return {
164
+ content: response.data.formatted_text || "No content returned",
165
+ status_code: 200
166
+ };
167
+ } catch (error) {
168
+ return {
169
+ error: ((_a = error.response) == null ? void 0 : _a.data) || "Failed to get response from the server.",
170
+ status_code: 500
171
+ };
172
+ }
173
+ });
174
+ }
175
+
176
+ // src/utils/aiTexGen.ts
177
+ import { CohereClientV2 } from "cohere-ai";
178
+ var AiTexGen = class {
179
+ constructor(apiKey) {
180
+ if (!apiKey || typeof apiKey !== "string") {
181
+ throw this.createErrorResponse("API_KEY_MISSING", "A valid API key must be provided.", 400);
182
+ }
183
+ this.cohereClient = new CohereClientV2({ token: apiKey });
184
+ }
185
+ // Validate user input (topic and word count)
186
+ validateInputs(topic, wordCount) {
187
+ if (typeof topic !== "string" || topic.trim().length === 0) {
188
+ throw this.createErrorResponse("INVALID_TOPIC", "Topic must be a non-empty string.", 400);
189
+ }
190
+ if (typeof wordCount !== "number" || wordCount <= 0) {
191
+ console.warn("Invalid word count provided. Defaulting to 100 words.");
192
+ wordCount = 100;
193
+ }
194
+ }
195
+ // Generate content using Cohere's API
196
+ generateContent(topic, wordCount = 100) {
197
+ return __async(this, null, function* () {
198
+ var _a;
199
+ try {
200
+ this.validateInputs(topic, wordCount);
201
+ const prompt = `Write a detailed article about ${topic}, aiming for maximum ${wordCount} words.`;
202
+ const response = yield this.cohereClient.chat({
203
+ model: "command-r-plus",
204
+ // Specify the model you want to use
205
+ messages: [
206
+ {
207
+ role: "user",
208
+ content: prompt
209
+ // Use the prompt with the topic and word count
210
+ }
211
+ ]
212
+ });
213
+ const content = this.processContent((_a = response.message) == null ? void 0 : _a.content);
214
+ return {
215
+ topic,
216
+ content
217
+ };
218
+ } catch (error) {
219
+ console.error("Error generating content from Cohere API:", error);
220
+ throw this.createErrorResponse("API_ERROR", "Failed to generate content from Cohere API.", 500, this.formatErrorDetails(error));
221
+ }
222
+ });
223
+ }
224
+ // Helper method to process the content and format it properly
225
+ processContent(content) {
226
+ if (!content || content.length === 0) {
227
+ return "No content generated or content is empty.";
228
+ }
229
+ return content.map((item) => {
230
+ if (typeof item === "string") {
231
+ return item.trim();
232
+ } else if (typeof item === "object") {
233
+ return this.extractTextFromObject(item);
234
+ }
235
+ return "";
236
+ }).join(" ").trim();
237
+ }
238
+ // Helper method to safely extract text from an object, if needed
239
+ extractTextFromObject(obj) {
240
+ if (obj && obj.text) {
241
+ return obj.text.trim();
242
+ }
243
+ return "";
244
+ }
245
+ // Helper method to create an error response with a status code
246
+ createErrorResponse(code, message, statusCode, details) {
247
+ return {
248
+ error: {
249
+ code,
250
+ message,
251
+ statusCode,
252
+ details: details || ""
253
+ }
254
+ };
255
+ }
256
+ // Helper method to format error details (narrowing down the 'unknown' type)
257
+ formatErrorDetails(error) {
258
+ if (error instanceof Error) {
259
+ return error.message;
260
+ } else {
261
+ return "An unknown error occurred.";
262
+ }
263
+ }
264
+ };
129
265
  export {
130
- analyzeText
266
+ AiTexGen as aiTexGen,
267
+ analyzeText,
268
+ getPunch
131
269
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "get-reading-time",
3
- "version": "1.0.5",
3
+ "version": "1.2.1",
4
4
  "main": "/dist/index.js",
5
5
  "module": "/dist/index.mjs",
6
6
  "types": "/dist/index.d.ts",
@@ -12,7 +12,11 @@
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/nurahmed123/get-reading-time.git"
15
+ "url": "git+https://github.com/nurahmed123/get-reading-time.git",
16
+ "license": "https://github.com/nurahmed123/get-reading-time/blob/main/LICENSE"
17
+ },
18
+ "publishConfig": {
19
+ "registry": "https://www.npmjs.com/package/get-reading-time"
16
20
  },
17
21
  "keywords": [
18
22
  "Reading",
@@ -136,11 +140,14 @@
136
140
  "homepage": "https://github.com/nurahmed123/get-reading-time#readme",
137
141
  "description": "",
138
142
  "devDependencies": {
143
+ "@types/axios": "^0.9.36",
139
144
  "@types/node": "^22.10.2",
140
145
  "@types/sentiment": "^5.0.4",
141
146
  "typescript": "^5.7.2"
142
147
  },
143
148
  "dependencies": {
149
+ "axios": "^1.7.9",
150
+ "cohere-ai": "^7.15.0",
144
151
  "sentiment": "^5.0.2",
145
152
  "tsup": "^8.3.5"
146
153
  }