@fettstorch/clai 0.1.2 ā 0.1.4
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/README.md +2 -2
- package/dist/cli.js +13 -3
- package/dist/index.js +8 -2
- package/package.json +1 -1
- package/src/cli.ts +6 -1
- package/src/openai.ts +3 -3
- package/src/scraper.ts +9 -1
- package/src/summarizer.ts +3 -1
package/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Command Line AI Interface (CLAI)
|
2
2
|
|
3
3
|
A tool for AI powered web search/scrape and summarization in the Terminal.
|
4
|
-
Built for fun
|
4
|
+
Built for fun in order to learn more about AI and CLIs.
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
@@ -13,7 +13,7 @@ Install it locally in order to use the clai function in your project.
|
|
13
13
|
```bash
|
14
14
|
npm install clai
|
15
15
|
```
|
16
|
-
Using both the CLI tool and the clai function requires an OpenAI API key.
|
16
|
+
Using both the CLI tool and the clai function requires an OpenAI API key. For the CLI tool make sure to set the `OPENAI_API_KEY` environment variable.
|
17
17
|
|
18
18
|
## OpenAI API Key Setup
|
19
19
|
|
package/dist/cli.js
CHANGED
@@ -67816,7 +67816,10 @@ async function scrape(input) {
|
|
67816
67816
|
}
|
67817
67817
|
}
|
67818
67818
|
function isValidUrl(input) {
|
67819
|
-
|
67819
|
+
if (input.includes(" "))
|
67820
|
+
return false;
|
67821
|
+
const tldPattern = /^[^\s]+\.[a-z]{2,}$/i;
|
67822
|
+
return tldPattern.test(input);
|
67820
67823
|
}
|
67821
67824
|
function normalizeUrl(url) {
|
67822
67825
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
@@ -67834,6 +67837,8 @@ async function getGoogleResults(query) {
|
|
67834
67837
|
const urlLower = url.toLowerCase();
|
67835
67838
|
return !urlLower.includes("www.google") && !urlLower.includes("gstatic.com") && !urlLower.includes("googleapis.com") && !urlLower.includes("googleadservices") && queryWords.some((word) => urlLower.includes(word));
|
67836
67839
|
}));
|
67840
|
+
console.log("queryWords", queryWords);
|
67841
|
+
console.log("filteredUrls", filteredUrls);
|
67837
67842
|
const results = [...filteredUrls].slice(0, 3);
|
67838
67843
|
if (results.length === 0) {
|
67839
67844
|
throw new Error("No search results found");
|
@@ -72936,10 +72941,11 @@ async function summarizeWebPage(content, openAIApiKey) {
|
|
72936
72941
|
}
|
72937
72942
|
}
|
72938
72943
|
};
|
72939
|
-
|
72944
|
+
const result = await openai.completeStructured(prompt2, {
|
72940
72945
|
temperature: 0.3,
|
72941
72946
|
responseSchema: schema
|
72942
72947
|
});
|
72948
|
+
return result;
|
72943
72949
|
}
|
72944
72950
|
|
72945
72951
|
// src/index.ts
|
@@ -73012,6 +73018,9 @@ async function animateText(text3, delay = 25) {
|
|
73012
73018
|
process.stdin.removeListener("keypress", keypressHandler);
|
73013
73019
|
process.stdout.write("\n");
|
73014
73020
|
}
|
73021
|
+
function formatMarkdownForTerminal(text3) {
|
73022
|
+
return text3.replace(/\*\*(.*?)\*\*/g, (_3, content) => source_default.bold(content));
|
73023
|
+
}
|
73015
73024
|
async function analyzeInput(input, openAIKey) {
|
73016
73025
|
const spinner = ora("Analyzing content...").start();
|
73017
73026
|
try {
|
@@ -73019,7 +73028,8 @@ async function analyzeInput(input, openAIKey) {
|
|
73019
73028
|
spinner.succeed("Analysis complete");
|
73020
73029
|
console.log(source_default.green.bold(`
|
73021
73030
|
\uD83D\uDCDD Summary:`));
|
73022
|
-
|
73031
|
+
const formattedContent = formatMarkdownForTerminal(result.summary);
|
73032
|
+
await animateText(formattedContent);
|
73023
73033
|
const { selectedLink } = await esm_default12.prompt([
|
73024
73034
|
{
|
73025
73035
|
type: "list",
|
package/dist/index.js
CHANGED
@@ -41021,7 +41021,10 @@ async function scrape(input) {
|
|
41021
41021
|
}
|
41022
41022
|
}
|
41023
41023
|
function isValidUrl(input) {
|
41024
|
-
|
41024
|
+
if (input.includes(" "))
|
41025
|
+
return false;
|
41026
|
+
const tldPattern = /^[^\s]+\.[a-z]{2,}$/i;
|
41027
|
+
return tldPattern.test(input);
|
41025
41028
|
}
|
41026
41029
|
function normalizeUrl(url) {
|
41027
41030
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
@@ -41039,6 +41042,8 @@ async function getGoogleResults(query) {
|
|
41039
41042
|
const urlLower = url.toLowerCase();
|
41040
41043
|
return !urlLower.includes("www.google") && !urlLower.includes("gstatic.com") && !urlLower.includes("googleapis.com") && !urlLower.includes("googleadservices") && queryWords.some((word) => urlLower.includes(word));
|
41041
41044
|
}));
|
41045
|
+
console.log("queryWords", queryWords);
|
41046
|
+
console.log("filteredUrls", filteredUrls);
|
41042
41047
|
const results = [...filteredUrls].slice(0, 3);
|
41043
41048
|
if (results.length === 0) {
|
41044
41049
|
throw new Error("No search results found");
|
@@ -46141,10 +46146,11 @@ async function summarizeWebPage(content, openAIApiKey) {
|
|
46141
46146
|
}
|
46142
46147
|
}
|
46143
46148
|
};
|
46144
|
-
|
46149
|
+
const result = await openai.completeStructured(prompt, {
|
46145
46150
|
temperature: 0.3,
|
46146
46151
|
responseSchema: schema
|
46147
46152
|
});
|
46153
|
+
return result;
|
46148
46154
|
}
|
46149
46155
|
|
46150
46156
|
// src/index.ts
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
@@ -87,6 +87,10 @@ async function animateText(text: string, delay = 25) {
|
|
87
87
|
process.stdout.write('\n');
|
88
88
|
}
|
89
89
|
|
90
|
+
function formatMarkdownForTerminal(text: string): string {
|
91
|
+
return text.replace(/\*\*(.*?)\*\*/g, (_, content) => chalk.bold(content));
|
92
|
+
}
|
93
|
+
|
90
94
|
async function analyzeInput(input: string, openAIKey: string) {
|
91
95
|
const spinner = ora('Analyzing content...').start();
|
92
96
|
|
@@ -95,7 +99,8 @@ async function analyzeInput(input: string, openAIKey: string) {
|
|
95
99
|
spinner.succeed('Analysis complete');
|
96
100
|
|
97
101
|
console.log(chalk.green.bold('\nš Summary:'));
|
98
|
-
|
102
|
+
const formattedContent = formatMarkdownForTerminal(result.summary);
|
103
|
+
await animateText(formattedContent);
|
99
104
|
|
100
105
|
// Prompt user to select a link
|
101
106
|
const { selectedLink } = await inquirer.prompt([
|
package/src/openai.ts
CHANGED
@@ -6,7 +6,7 @@ const MAX_INPUT_TOKENS = 10000;
|
|
6
6
|
function truncateContent(content: string): string {
|
7
7
|
const maxChars = MAX_INPUT_TOKENS * 4;
|
8
8
|
if (content.length <= maxChars) return content;
|
9
|
-
return content.slice(0, maxChars)
|
9
|
+
return content.slice(0, maxChars);
|
10
10
|
}
|
11
11
|
|
12
12
|
export interface StructuredResponse<T> {
|
@@ -53,8 +53,8 @@ class OpenAIWrapper {
|
|
53
53
|
): Promise<T> {
|
54
54
|
const truncatedPrompt = truncateContent(prompt);
|
55
55
|
const {
|
56
|
-
model = 'gpt-
|
57
|
-
temperature =
|
56
|
+
model = 'gpt-4o-mini',
|
57
|
+
temperature = 1.6,
|
58
58
|
functionName = 'generate_response',
|
59
59
|
responseSchema
|
60
60
|
} = options;
|
package/src/scraper.ts
CHANGED
@@ -41,7 +41,12 @@ export async function scrape(input: string): Promise<ScrapedData[]> {
|
|
41
41
|
// --- module private
|
42
42
|
|
43
43
|
function isValidUrl(input: string): boolean {
|
44
|
-
|
44
|
+
// Check for whitespace
|
45
|
+
if (input.includes(' ')) return false;
|
46
|
+
|
47
|
+
// Check for common TLDs using regex
|
48
|
+
const tldPattern = /^[^\s]+\.[a-z]{2,}$/i;
|
49
|
+
return tldPattern.test(input);
|
45
50
|
}
|
46
51
|
|
47
52
|
function normalizeUrl(url: string): string {
|
@@ -74,6 +79,9 @@ async function getGoogleResults(query: string): Promise<string[]> {
|
|
74
79
|
})
|
75
80
|
);
|
76
81
|
|
82
|
+
console.log('queryWords', queryWords);
|
83
|
+
console.log('filteredUrls', filteredUrls);
|
84
|
+
|
77
85
|
const results = [...filteredUrls].slice(0, 3);
|
78
86
|
|
79
87
|
if (results.length === 0) {
|
package/src/summarizer.ts
CHANGED
@@ -70,8 +70,10 @@ export async function summarizeWebPage(content: string, openAIApiKey: string): P
|
|
70
70
|
}
|
71
71
|
};
|
72
72
|
|
73
|
-
|
73
|
+
const result = await openai.completeStructured<SummaryResult>(prompt, {
|
74
74
|
temperature: 0.3,
|
75
75
|
responseSchema: schema
|
76
76
|
});
|
77
|
+
|
78
|
+
return result;
|
77
79
|
}
|