get-reading-time 1.0.4 → 1.2.0
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 +21 -0
- package/README.md +116 -85
- package/dist/index.d.mts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +136 -2
- package/dist/index.mjs +133 -2
- package/package.json +10 -2
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,36 +1,29 @@
|
|
|
1
|
-
|
|
2
1
|
# Text Analysis Tool
|
|
3
2
|
|
|
4
3
|
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.
|
|
5
4
|
|
|
6
5
|
## Features
|
|
7
6
|
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
- **Readability Score**: Calculates the Flesch Reading Ease score to evaluate the text's readability.
|
|
19
|
-
|
|
20
|
-
- **Sentiment Analysis**: Analyzes the sentiment of the text (Positive, Negative, or Neutral).
|
|
21
|
-
|
|
22
|
-
- **SEO-friendly Keywords**: Extracts the top 5 SEO-friendly keywords or key phrases (bi-grams and tri-grams) from the text.
|
|
23
|
-
|
|
7
|
+
- **Reading Time**: Estimates how long it will take to read the given text based on a default or custom reading speed (words per minute).
|
|
8
|
+
- **Word Count**: Counts the number of words in the text.
|
|
9
|
+
- **Character Count**: Counts the number of characters (excluding spaces) in the text.
|
|
10
|
+
- **Sentence Count**: Counts the number of sentences based on punctuation marks.
|
|
11
|
+
- **Link Count**: Detects and counts the number of URLs in the text.
|
|
12
|
+
- **Readability Score**: Calculates the Flesch Reading Ease score to evaluate the text's readability.
|
|
13
|
+
- **Sentiment Analysis**: Analyzes the sentiment of the text (Positive, Negative, or Neutral).
|
|
14
|
+
- **SEO-friendly Keywords**: Extracts the top 5 SEO-friendly keywords or key phrases (bi-grams and tri-grams) from the text.
|
|
15
|
+
- **aiTexGen**: Allows users to generate content based on a search prompt using the Cohere AI API, with a specified word count.
|
|
24
16
|
|
|
25
17
|
## Installation
|
|
26
18
|
|
|
27
19
|
To install the package from npm, run:
|
|
28
|
-
|
|
20
|
+
|
|
21
|
+
```bash
|
|
29
22
|
npm i get-reading-time
|
|
30
23
|
```
|
|
31
24
|
|
|
32
|
-
|
|
33
25
|
Or using yarn:
|
|
26
|
+
|
|
34
27
|
```bash
|
|
35
28
|
yarn add get-reading-time
|
|
36
29
|
```
|
|
@@ -38,54 +31,106 @@ yarn add get-reading-time
|
|
|
38
31
|
## Usage
|
|
39
32
|
|
|
40
33
|
Here’s how you can use the analyzeText function to analyze a piece of text:
|
|
34
|
+
|
|
41
35
|
```bash
|
|
42
36
|
import { analyzeText } from "get-reading-time/dist/index.js";
|
|
43
37
|
```
|
|
44
|
-
|
|
38
|
+
|
|
39
|
+
### Example Code
|
|
40
|
+
|
|
45
41
|
```javascript
|
|
46
|
-
const text =
|
|
42
|
+
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`;
|
|
47
43
|
|
|
48
|
-
const result =
|
|
44
|
+
const result = analyzeText(text);
|
|
49
45
|
|
|
50
46
|
// Analyze the text
|
|
51
47
|
try {
|
|
52
|
-
|
|
48
|
+
const result = analyzeText(text);
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
// Output the analysis results
|
|
51
|
+
console.log("Text Analysis Result:");
|
|
52
|
+
console.log(JSON.stringify(result, null, 2));
|
|
57
53
|
} catch (error) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
// Narrow the type of error to Error
|
|
55
|
+
if (error instanceof Error) {
|
|
56
|
+
console.error("Error analyzing text:", error.message);
|
|
57
|
+
} else {
|
|
58
|
+
console.error("Unknown error:", error);
|
|
59
|
+
}
|
|
64
60
|
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Example Output
|
|
65
64
|
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"readingTime": {
|
|
68
|
+
"minutes": 0.09,
|
|
69
|
+
"seconds": 5.1
|
|
70
|
+
},
|
|
71
|
+
"wordCount": 17,
|
|
72
|
+
"characterCount": 132,
|
|
73
|
+
"sentenceCount": 3,
|
|
74
|
+
"linkCount": 2,
|
|
75
|
+
"links": [
|
|
76
|
+
"https://linkedin.com/in/06nurahmed",
|
|
77
|
+
"https://github.com/nurahmed123"
|
|
78
|
+
],
|
|
79
|
+
"readabilityScore": 21.93039215686275,
|
|
80
|
+
"sentiment": "Neutral",
|
|
81
|
+
"keywords": ["example", "text.", "contains", "words,", "sentences,"]
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### aiTexGen: Generate your content
|
|
86
|
+
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.
|
|
87
|
+
|
|
88
|
+
### Usage
|
|
89
|
+
To use the **aiTexGen** feature, follow these steps:
|
|
90
|
+
```bash
|
|
91
|
+
import { aiTexGen } from "get-reading-time/dist/index.js";
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Example Code
|
|
95
|
+
- Create your [Api key](https://dashboard.cohere.com/api-keys) From here.
|
|
96
|
+
```javascript
|
|
97
|
+
// Replace this with your Cohere API key
|
|
98
|
+
const apiKey = '<api-key>';
|
|
99
|
+
const generator = new aiTexGen(apiKey);
|
|
100
|
+
|
|
101
|
+
async function testGenerateContent() {
|
|
102
|
+
try {
|
|
103
|
+
// Define a topic and word count for testing
|
|
104
|
+
const topic = 'arduino';
|
|
105
|
+
const wordCount = 100;
|
|
106
|
+
|
|
107
|
+
// Call the generateContent method
|
|
108
|
+
const result = await generator.generateContent(topic, wordCount);
|
|
109
|
+
|
|
110
|
+
// Output the result in JSON format
|
|
111
|
+
console.log('Generated Content (JSON Format):');
|
|
112
|
+
console.log(JSON.stringify(result, null, 2)); // Pretty print the JSON output
|
|
113
|
+
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('Error during content generation:', error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Run the test
|
|
119
|
+
testGenerateContent();
|
|
66
120
|
```
|
|
67
121
|
### Example Output
|
|
68
122
|
```json
|
|
69
123
|
{
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"seconds": 5.23
|
|
73
|
-
},
|
|
74
|
-
"wordCount": 13,
|
|
75
|
-
"characterCount": 68,
|
|
76
|
-
"sentenceCount": 2,
|
|
77
|
-
"linkCount": 1,
|
|
78
|
-
"readabilityScore": 78.5,
|
|
79
|
-
"sentiment": "Positive",
|
|
80
|
-
"keywords": ["example", "text", "words", "sentences", "links"]
|
|
124
|
+
"topic": "arduino",
|
|
125
|
+
"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."
|
|
81
126
|
}
|
|
82
127
|
```
|
|
128
|
+
|
|
83
129
|
## Parameters
|
|
84
130
|
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
|
|
131
|
+
- text: The text to be analyzed (required).
|
|
132
|
+
- wordsPerMinute: The reading speed in words per minute (optional, default is 200 words per minute).
|
|
133
|
+
- **apiKey**: Your Cohere API key to use this feature (required).
|
|
89
134
|
|
|
90
135
|
## Functions
|
|
91
136
|
|
|
@@ -93,45 +138,30 @@ try {
|
|
|
93
138
|
|
|
94
139
|
Analyzes the provided text and returns an object containing:
|
|
95
140
|
|
|
96
|
-
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- readabilityScore: Flesch Reading Ease score (higher is easier to read).
|
|
107
|
-
|
|
108
|
-
- sentiment: Sentiment of the text (Positive, Negative, or Neutral).
|
|
109
|
-
|
|
110
|
-
- keywords: Top 5 SEO-friendly keywords or key phrases.
|
|
111
|
-
|
|
141
|
+
- readingTime: Estimated reading time in minutes and seconds.
|
|
142
|
+
- wordCount: Total word count.
|
|
143
|
+
- characterCount: Total character count (excluding spaces).
|
|
144
|
+
- sentenceCount: Total sentence count.
|
|
145
|
+
- linkCount: Number of links (URLs) in the text.
|
|
146
|
+
- readabilityScore: Flesch Reading Ease score (higher is easier to read).
|
|
147
|
+
- sentiment: Sentiment of the text (Positive, Negative, or Neutral).
|
|
148
|
+
- keywords: Top 5 SEO-friendly keywords or key phrases.
|
|
149
|
+
### Generate Content(topic: string, wordCount: number)
|
|
150
|
+
Generates content based on the given topic and word count using the Cohere AI API and returns the generated content.
|
|
112
151
|
|
|
113
152
|
### Helper Functions
|
|
114
153
|
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
|
|
127
|
-
- **analyzeSentiment(text: string)**: Analyzes sentiment using Sentiment.js.
|
|
128
|
-
|
|
129
|
-
- **extractKeywords(text: string)**: Extracts the top 5 SEO-friendly keywords or key phrases.
|
|
130
|
-
|
|
131
|
-
- **extractNGrams(words: string[])**: Extracts bi-grams and tri-grams from the list of words.
|
|
132
|
-
|
|
133
|
-
- **isStopWord(word: string, stopWords: Set<string>)**: Checks if a word is a stop word to exclude from keyword extraction.
|
|
134
|
-
|
|
154
|
+
- **cleanTextInput(text: string)**: Cleans and normalizes the input text.
|
|
155
|
+
- **calculateWordCount(text: string)**: Counts the number of words.
|
|
156
|
+
- **calculateCharacterCount(text: string)**: Counts the number of characters (excluding spaces).
|
|
157
|
+
- **calculateSentenceCount(text: string)**: Counts the number of sentences based on punctuation.
|
|
158
|
+
- **countLinks(text: string)**: Counts the number of links (URLs) in the text.
|
|
159
|
+
- **calculateReadabilityScore(text: string)**: Calculates the Flesch Reading Ease score.
|
|
160
|
+
- **analyzeSentiment(text: string)**: Analyzes sentiment using Sentiment.js.
|
|
161
|
+
- **extractKeywords(text: string)**: Extracts the top 5 SEO-friendly keywords or key phrases.
|
|
162
|
+
- **extractNGrams(words: string[])**: Extracts bi-grams and tri-grams from the list of words.
|
|
163
|
+
- **isStopWord(word: string, stopWords: Set<string>)**: Checks if a word is a stop word to exclude from keyword extraction.
|
|
164
|
+
- **generateContent(words: string[])**: Genarate text based on the query and word limit.
|
|
135
165
|
|
|
136
166
|
## Contributing
|
|
137
167
|
|
|
@@ -139,8 +169,9 @@ Feel free to fork the repository, make your changes, and submit a pull request.
|
|
|
139
169
|
|
|
140
170
|
## License
|
|
141
171
|
|
|
142
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
172
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/nurahmed123/get-reading-time/blob/main/LICENSE) file for details.
|
|
173
|
+
[](https://www.npmjs.com/get-reading-time)
|
|
143
174
|
|
|
144
175
|
## Contact
|
|
145
176
|
|
|
146
|
-
For any questions or inquiries, feel free to contact [[06nurahmed@gmail.com](06nurahmed@gmail.com)].
|
|
177
|
+
For any questions or inquiries, feel free to contact [[06nurahmed@gmail.com](06nurahmed@gmail.com)].
|
package/dist/index.d.mts
CHANGED
|
@@ -14,4 +14,31 @@ interface TextAnalysisResult {
|
|
|
14
14
|
}
|
|
15
15
|
declare function analyzeText(text: string, wordsPerMinute?: number): TextAnalysisResult;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Formats an article by correcting punctuation and capitalization,
|
|
19
|
+
* intelligently inferring sentence boundaries and adding missing punctuation.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} article - The raw input string to be formatted.
|
|
22
|
+
* @returns {{ original: string, formatted: string }} - A JSON object with the original and formatted strings.
|
|
23
|
+
* @throws {TypeError} If the input is not a valid non-empty string.
|
|
24
|
+
*/
|
|
25
|
+
declare const getPunch: (article: string) => {
|
|
26
|
+
original: string;
|
|
27
|
+
formatted: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
declare class AiTexGen {
|
|
31
|
+
private cohereClient;
|
|
32
|
+
constructor(apiKey: string);
|
|
33
|
+
private validateInputs;
|
|
34
|
+
generateContent(topic: string, wordCount?: number): Promise<{
|
|
35
|
+
topic: string;
|
|
36
|
+
content: string;
|
|
37
|
+
}>;
|
|
38
|
+
private processContent;
|
|
39
|
+
private extractTextFromObject;
|
|
40
|
+
private createErrorResponse;
|
|
41
|
+
private formatErrorDetails;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { AiTexGen as aiTexGen, analyzeText, getPunch };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,4 +14,31 @@ interface TextAnalysisResult {
|
|
|
14
14
|
}
|
|
15
15
|
declare function analyzeText(text: string, wordsPerMinute?: number): TextAnalysisResult;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Formats an article by correcting punctuation and capitalization,
|
|
19
|
+
* intelligently inferring sentence boundaries and adding missing punctuation.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} article - The raw input string to be formatted.
|
|
22
|
+
* @returns {{ original: string, formatted: string }} - A JSON object with the original and formatted strings.
|
|
23
|
+
* @throws {TypeError} If the input is not a valid non-empty string.
|
|
24
|
+
*/
|
|
25
|
+
declare const getPunch: (article: string) => {
|
|
26
|
+
original: string;
|
|
27
|
+
formatted: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
declare class AiTexGen {
|
|
31
|
+
private cohereClient;
|
|
32
|
+
constructor(apiKey: string);
|
|
33
|
+
private validateInputs;
|
|
34
|
+
generateContent(topic: string, wordCount?: number): Promise<{
|
|
35
|
+
topic: string;
|
|
36
|
+
content: string;
|
|
37
|
+
}>;
|
|
38
|
+
private processContent;
|
|
39
|
+
private extractTextFromObject;
|
|
40
|
+
private createErrorResponse;
|
|
41
|
+
private formatErrorDetails;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
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
|
-
|
|
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,117 @@ 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_compromise = __toESM(require("compromise"));
|
|
190
|
+
var getPunch = (article) => {
|
|
191
|
+
if (typeof article !== "string" || article.trim().length === 0) {
|
|
192
|
+
throw new TypeError("Invalid input: article must be a non-empty string.");
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const doc = (0, import_compromise.default)(article);
|
|
196
|
+
const formatted = doc.sentences().normalize().out("text");
|
|
197
|
+
return {
|
|
198
|
+
original: article.trim(),
|
|
199
|
+
formatted
|
|
200
|
+
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
throw new Error(`Error processing the article: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/utils/aiTexGen.ts
|
|
207
|
+
var import_cohere_ai = require("cohere-ai");
|
|
208
|
+
var AiTexGen = class {
|
|
209
|
+
constructor(apiKey) {
|
|
210
|
+
if (!apiKey || typeof apiKey !== "string") {
|
|
211
|
+
throw this.createErrorResponse("API_KEY_MISSING", "A valid API key must be provided.", 400);
|
|
212
|
+
}
|
|
213
|
+
this.cohereClient = new import_cohere_ai.CohereClientV2({ token: apiKey });
|
|
214
|
+
}
|
|
215
|
+
// Validate user input (topic and word count)
|
|
216
|
+
validateInputs(topic, wordCount) {
|
|
217
|
+
if (typeof topic !== "string" || topic.trim().length === 0) {
|
|
218
|
+
throw this.createErrorResponse("INVALID_TOPIC", "Topic must be a non-empty string.", 400);
|
|
219
|
+
}
|
|
220
|
+
if (typeof wordCount !== "number" || wordCount <= 0) {
|
|
221
|
+
console.warn("Invalid word count provided. Defaulting to 100 words.");
|
|
222
|
+
wordCount = 100;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Generate content using Cohere's API
|
|
226
|
+
generateContent(topic, wordCount = 100) {
|
|
227
|
+
return __async(this, null, function* () {
|
|
228
|
+
var _a;
|
|
229
|
+
try {
|
|
230
|
+
this.validateInputs(topic, wordCount);
|
|
231
|
+
const prompt = `Write a detailed article about ${topic}, aiming for maximum ${wordCount} words.`;
|
|
232
|
+
const response = yield this.cohereClient.chat({
|
|
233
|
+
model: "command-r-plus",
|
|
234
|
+
// Specify the model you want to use
|
|
235
|
+
messages: [
|
|
236
|
+
{
|
|
237
|
+
role: "user",
|
|
238
|
+
content: prompt
|
|
239
|
+
// Use the prompt with the topic and word count
|
|
240
|
+
}
|
|
241
|
+
]
|
|
242
|
+
});
|
|
243
|
+
const content = this.processContent((_a = response.message) == null ? void 0 : _a.content);
|
|
244
|
+
return {
|
|
245
|
+
topic,
|
|
246
|
+
content
|
|
247
|
+
};
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error("Error generating content from Cohere API:", error);
|
|
250
|
+
throw this.createErrorResponse("API_ERROR", "Failed to generate content from Cohere API.", 500, this.formatErrorDetails(error));
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Helper method to process the content and format it properly
|
|
255
|
+
processContent(content) {
|
|
256
|
+
if (!content || content.length === 0) {
|
|
257
|
+
return "No content generated or content is empty.";
|
|
258
|
+
}
|
|
259
|
+
return content.map((item) => {
|
|
260
|
+
if (typeof item === "string") {
|
|
261
|
+
return item.trim();
|
|
262
|
+
} else if (typeof item === "object") {
|
|
263
|
+
return this.extractTextFromObject(item);
|
|
264
|
+
}
|
|
265
|
+
return "";
|
|
266
|
+
}).join(" ").trim();
|
|
267
|
+
}
|
|
268
|
+
// Helper method to safely extract text from an object, if needed
|
|
269
|
+
extractTextFromObject(obj) {
|
|
270
|
+
if (obj && obj.text) {
|
|
271
|
+
return obj.text.trim();
|
|
272
|
+
}
|
|
273
|
+
return "";
|
|
274
|
+
}
|
|
275
|
+
// Helper method to create an error response with a status code
|
|
276
|
+
createErrorResponse(code, message, statusCode, details) {
|
|
277
|
+
return {
|
|
278
|
+
error: {
|
|
279
|
+
code,
|
|
280
|
+
message,
|
|
281
|
+
statusCode,
|
|
282
|
+
details: details || ""
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// Helper method to format error details (narrowing down the 'unknown' type)
|
|
287
|
+
formatErrorDetails(error) {
|
|
288
|
+
if (error instanceof Error) {
|
|
289
|
+
return error.message;
|
|
290
|
+
} else {
|
|
291
|
+
return "An unknown error occurred.";
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
163
295
|
// Annotate the CommonJS export names for ESM import in node:
|
|
164
296
|
0 && (module.exports = {
|
|
165
|
-
|
|
297
|
+
aiTexGen,
|
|
298
|
+
analyzeText,
|
|
299
|
+
getPunch
|
|
166
300
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
|
-
|
|
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,116 @@ 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 nlp from "compromise";
|
|
153
|
+
var getPunch = (article) => {
|
|
154
|
+
if (typeof article !== "string" || article.trim().length === 0) {
|
|
155
|
+
throw new TypeError("Invalid input: article must be a non-empty string.");
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const doc = nlp(article);
|
|
159
|
+
const formatted = doc.sentences().normalize().out("text");
|
|
160
|
+
return {
|
|
161
|
+
original: article.trim(),
|
|
162
|
+
formatted
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
throw new Error(`Error processing the article: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/utils/aiTexGen.ts
|
|
170
|
+
import { CohereClientV2 } from "cohere-ai";
|
|
171
|
+
var AiTexGen = class {
|
|
172
|
+
constructor(apiKey) {
|
|
173
|
+
if (!apiKey || typeof apiKey !== "string") {
|
|
174
|
+
throw this.createErrorResponse("API_KEY_MISSING", "A valid API key must be provided.", 400);
|
|
175
|
+
}
|
|
176
|
+
this.cohereClient = new CohereClientV2({ token: apiKey });
|
|
177
|
+
}
|
|
178
|
+
// Validate user input (topic and word count)
|
|
179
|
+
validateInputs(topic, wordCount) {
|
|
180
|
+
if (typeof topic !== "string" || topic.trim().length === 0) {
|
|
181
|
+
throw this.createErrorResponse("INVALID_TOPIC", "Topic must be a non-empty string.", 400);
|
|
182
|
+
}
|
|
183
|
+
if (typeof wordCount !== "number" || wordCount <= 0) {
|
|
184
|
+
console.warn("Invalid word count provided. Defaulting to 100 words.");
|
|
185
|
+
wordCount = 100;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Generate content using Cohere's API
|
|
189
|
+
generateContent(topic, wordCount = 100) {
|
|
190
|
+
return __async(this, null, function* () {
|
|
191
|
+
var _a;
|
|
192
|
+
try {
|
|
193
|
+
this.validateInputs(topic, wordCount);
|
|
194
|
+
const prompt = `Write a detailed article about ${topic}, aiming for maximum ${wordCount} words.`;
|
|
195
|
+
const response = yield this.cohereClient.chat({
|
|
196
|
+
model: "command-r-plus",
|
|
197
|
+
// Specify the model you want to use
|
|
198
|
+
messages: [
|
|
199
|
+
{
|
|
200
|
+
role: "user",
|
|
201
|
+
content: prompt
|
|
202
|
+
// Use the prompt with the topic and word count
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
});
|
|
206
|
+
const content = this.processContent((_a = response.message) == null ? void 0 : _a.content);
|
|
207
|
+
return {
|
|
208
|
+
topic,
|
|
209
|
+
content
|
|
210
|
+
};
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error("Error generating content from Cohere API:", error);
|
|
213
|
+
throw this.createErrorResponse("API_ERROR", "Failed to generate content from Cohere API.", 500, this.formatErrorDetails(error));
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// Helper method to process the content and format it properly
|
|
218
|
+
processContent(content) {
|
|
219
|
+
if (!content || content.length === 0) {
|
|
220
|
+
return "No content generated or content is empty.";
|
|
221
|
+
}
|
|
222
|
+
return content.map((item) => {
|
|
223
|
+
if (typeof item === "string") {
|
|
224
|
+
return item.trim();
|
|
225
|
+
} else if (typeof item === "object") {
|
|
226
|
+
return this.extractTextFromObject(item);
|
|
227
|
+
}
|
|
228
|
+
return "";
|
|
229
|
+
}).join(" ").trim();
|
|
230
|
+
}
|
|
231
|
+
// Helper method to safely extract text from an object, if needed
|
|
232
|
+
extractTextFromObject(obj) {
|
|
233
|
+
if (obj && obj.text) {
|
|
234
|
+
return obj.text.trim();
|
|
235
|
+
}
|
|
236
|
+
return "";
|
|
237
|
+
}
|
|
238
|
+
// Helper method to create an error response with a status code
|
|
239
|
+
createErrorResponse(code, message, statusCode, details) {
|
|
240
|
+
return {
|
|
241
|
+
error: {
|
|
242
|
+
code,
|
|
243
|
+
message,
|
|
244
|
+
statusCode,
|
|
245
|
+
details: details || ""
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// Helper method to format error details (narrowing down the 'unknown' type)
|
|
250
|
+
formatErrorDetails(error) {
|
|
251
|
+
if (error instanceof Error) {
|
|
252
|
+
return error.message;
|
|
253
|
+
} else {
|
|
254
|
+
return "An unknown error occurred.";
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
129
258
|
export {
|
|
130
|
-
|
|
259
|
+
AiTexGen as aiTexGen,
|
|
260
|
+
analyzeText,
|
|
261
|
+
getPunch
|
|
131
262
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get-reading-time",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
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,15 @@
|
|
|
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",
|
|
151
|
+
"compromise": "^14.14.3",
|
|
144
152
|
"sentiment": "^5.0.2",
|
|
145
153
|
"tsup": "^8.3.5"
|
|
146
154
|
}
|