Skip to content

Commit 73caf68

Browse files
committed
user js server
1 parent 85de3bc commit 73caf68

File tree

8 files changed

+141
-86
lines changed

8 files changed

+141
-86
lines changed

README.md

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Web Summarizer - Chrome Extension
1+
# TLDR - Chrome Extension
22

33
A Chrome extension that extracts and summarizes text from any webpage using the **BART (large) model**.
44

@@ -34,33 +34,51 @@ https://github.com/user-attachments/assets/1edca9a0-0b38-4025-9840-86c557379f0a
3434

3535
---
3636

37-
## Backend Setup (Flask Server)
38-
This extension requires a Flask backend to process summaries.
37+
## Backend Setup (Node.js + Ollama)
3938

40-
### 1. Install dependencies
41-
```sh
42-
pip install flask flask-cors huggingface_hub python-dotenv
43-
```
39+
This project uses [Ollama](https://ollama.com) to run the `deepseek-r1` large language model (LLM) **locally**, with an Express.js backend acting as the middleman between your frontend and the LLM.
4440

45-
### 2. Set up the API Key
46-
Create a `.env` file in the Flask project and add:
41+
### Prerequisites
4742

48-
```sh
49-
API_KEY=your-huggingface-api-key
50-
```
43+
- [Node.js](https://nodejs.org/) installed
44+
- [Ollama](https://ollama.com/download) installed (macOS, Linux, or Windows)
45+
46+
---
47+
48+
### Step 1: Install Ollama
49+
50+
Download and install Ollama for your OS from the official site:
51+
52+
https://ollama.com/download
5153

52-
### 3. Run the Server
53-
To start the Flask backend, run:
54+
After installing, verify the CLI is available:
5455

55-
```sh
56-
python3 server.py
56+
```bash
57+
ollama --version
5758
```
5859

59-
## Speech Synthesis Fix
60-
If "Read Aloud" does not work, try running this in Chrome DevTools (F12 > Console):
60+
### Step 2: Run the DeepSeek-R1 Model
6161

62-
```sh
63-
speechSynthesis.speak(new SpeechSynthesisUtterance("Test speech synthesis."));
62+
We're using the `deepseek-r1` model — a powerful.
63+
64+
To download and launch it, run:
65+
66+
```bash
67+
ollama run deepseek-r1
6468
```
69+
### Step 3: Run the Node Backend
6570
71+
Install dependencies:
6672
73+
```bash
74+
npm install
75+
```
76+
77+
Install dependencies:
78+
```bash
79+
node server.js
80+
```
81+
The server will be running at:
82+
```bash
83+
http://localhost:5000
84+
```

content.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,44 @@
1-
function getPageText() {
2-
return document.body.innerText;
3-
}
4-
5-
console.log("Content script loaded!");
6-
7-
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
1+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
82
if (message.action === "summarize") {
93
let selectedText = window.getSelection().toString().trim();
104
let text = selectedText || document.body.innerText.trim();
115

6+
console.log("Text being sent to BART:", text);
7+
128
if (text.length > 0) {
13-
sendResponse({ text: text });
9+
fetch("http://localhost:5000/summarize", {
10+
method: "POST",
11+
headers: { "Content-Type": "application/json" },
12+
body: JSON.stringify({ text }),
13+
})
14+
.then(response => response.json())
15+
.then(data => {
16+
console.log("Raw Data from BART:", data);
17+
18+
let summaryText = data.summary;
19+
20+
if (typeof summaryText === "string" && summaryText.startsWith("{")) {
21+
try {
22+
let parsed = JSON.parse(summaryText);
23+
if (parsed && typeof parsed === "object") {
24+
summaryText = parsed.summary || summaryText;
25+
}
26+
} catch (e) {
27+
console.error("Error parsing nested JSON:", e);
28+
}
29+
}
30+
31+
sendResponse({ summary: summaryText });
32+
})
33+
.catch(error => {
34+
console.error("Error during fetch:", error);
35+
sendResponse({ error: "Failed to summarize." });
36+
});
37+
38+
return true;
1439
} else {
1540
sendResponse({ error: "No text found or selected." });
1641
}
1742
}
1843
return true;
1944
});
20-
21-
22-
23-
24-

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"manifest_version": 3,
3-
"name": "Web Summarizer",
3+
"name": "TLDR",
44
"version": "1.0",
55
"description": "Summarizes articles using AI.",
66
"permissions": ["activeTab", "storage", "scripting"],

package.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
{
22
"dependencies": {
3+
"cors": "^2.8.5",
4+
"dotenv": "^16.4.7",
5+
"express": "^4.21.2",
36
"ollama": "^0.5.14"
4-
}
7+
},
8+
"name": "chrome-extension",
9+
"version": "1.0.0",
10+
"description": "A Chrome extension that extracts and summarizes text from any webpage using the **BART (large) model**.",
11+
"main": "content.js",
12+
"scripts": {
13+
"test": "echo \"Error: no test specified\" && exit 1",
14+
"start": "node server.js"
15+
},
16+
"keywords": [],
17+
"author": "",
18+
"license": "ISC"
519
}

popup.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@
6464
</style>
6565
</head>
6666
<body>
67-
<h2>Web Summarizer</h2>
67+
<h2>TLDR</h2>
6868
<button id="summarize">Summarize</button>
69-
<button id="readAloud" disabled>🔊 Read Aloud</button>
69+
<button id="readAloud" disabled>Read Aloud</button>
7070
<p id="summary">Your summary will appear here...</p>
7171

7272
<script src="popup.js"></script>

popup.js

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,16 @@ document.getElementById("summarize").addEventListener("click", async () => {
1515
chrome.tabs.sendMessage(tab.id, { action: "summarize" }, async (response) => {
1616
if (chrome.runtime.lastError) {
1717
console.error("Error:", chrome.runtime.lastError.message);
18-
summaryElement.innerText = "Error: Content script not loaded. Try reloading the page.";
18+
summaryElement.innerText = "Error: Content script not loaded. Reload page or wait a couple seconds for page to finish loading.";
1919
return;
2020
}
2121

22-
if (!response || !response.text) {
22+
if (!response || !response.summary) {
2323
summaryElement.innerText = response?.error || "Failed to extract text.";
2424
return;
2525
}
2626

27-
const apiResponse = await fetch("http://localhost:5000/summarize", {
28-
method: "POST",
29-
headers: { "Content-Type": "application/json" },
30-
body: JSON.stringify({ text: response.text })
31-
});
32-
33-
if (!apiResponse.ok) {
34-
if (apiResponse.status === 500) {
35-
summaryElement.innerText = "Request failed. Document may be too long.";
36-
return;
37-
}
38-
throw new Error(`Server error: ${apiResponse.status}`);
39-
}
40-
41-
const data = await apiResponse.json();
42-
43-
const summaryText = data.summary?.summary_text || data.summary || "No summary available.";
44-
summaryElement.innerText = summaryText;
27+
summaryElement.innerText = response.summary;
4528
readAloudButton.disabled = false;
4629
});
4730
} catch (error) {
@@ -58,7 +41,7 @@ document.getElementById("readAloud").addEventListener("click", () => {
5841
if (isSpeaking) {
5942
speechSynthesis.cancel();
6043
isSpeaking = false;
61-
document.getElementById("readAloud").innerText = "🔊 Read Aloud";
44+
document.getElementById("readAloud").innerText = "Read Aloud";
6245
} else {
6346
speechUtterance = new SpeechSynthesisUtterance(summaryText);
6447
speechUtterance.rate = 1;
@@ -71,12 +54,7 @@ document.getElementById("readAloud").addEventListener("click", () => {
7154

7255
speechUtterance.onend = () => {
7356
isSpeaking = false;
74-
document.getElementById("readAloud").innerText = "🔊 Read Aloud";
57+
document.getElementById("readAloud").innerText = "Read Aloud";
7558
};
7659
}
77-
});
78-
79-
80-
81-
82-
60+
});

server.js

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,45 @@
1-
import { Ollama } from 'ollama'
2-
3-
let content = "BART model pre-trained on English language, and fine-tuned on CNN Daily Mail. It was introduced in the paper BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension by Lewis et al. and first released in [this repository (https://github.com/pytorch/fairseq/tree/master/examples/bart).Disclaimer: The team releasing BART did not write a model card for this model so this model card has been written by the Hugging Face team.Model description BART is a transformer encoder-encoder (seq2seq) model with a bidirectional (BERT-like) encoder and an autoregressive (GPT-like) decoder. BART is pre-trained by (1) corrupting text with an arbitrary noising function, and (2) learning a model to reconstruct the original text.BART is particularly effective when fine-tuned for text generation (e.g. summarization, translation) but also works well for comprehension tasks (e.g. text classification, question answering). This particular checkpoint has been fine-tuned on CNN Daily Mail, a large collection of text-summary pairs."
4-
5-
const summarize = async (content, showThinking = false) => {
6-
const ollama = new Ollama({ host: 'http://127.0.0.1:11434' })
7-
const prompt = "Please provide a concise summary of the following content:"
8-
const response = await ollama.chat({
9-
model: 'deepseek-r1:1.5b',
10-
messages: [{ role: 'user', content: `${prompt} ${content}` }],
11-
})
12-
const messageContent = response.message.content
13-
if (showThinking == true){
14-
return messageContent
15-
} else {
16-
// return messageContent.replace(/<\s*think\s*>[\s\S]*<\s*\/\s*think\s*>/gi, '')
17-
// return messageContent.split("</think>", 1)[1];
18-
return messageContent.split("</think>", 2)[1];
1+
import express from "express";
2+
import cors from "cors";
3+
import { Ollama } from "ollama";
4+
5+
const app = express();
6+
app.use(express.json());
7+
app.use(cors());
8+
9+
const ollama = new Ollama();
10+
11+
app.post("/summarize", async (req, res) => {
12+
try {
13+
const { text } = req.body;
14+
if (!text) {
15+
return res.status(400).json({ error: "Text is required - try selecting the text you want to summarize." });
16+
}
17+
18+
console.log("Text being sent to BART:", text);
19+
20+
const response = await ollama.chat({
21+
model: "deepseek-r1:1.5b",
22+
messages: [{ role: "user", content: `Summarize this text in 2-3 sentences: ${text}` }],
23+
});
24+
25+
console.log("Server esponse from BART:", response);
26+
27+
if (!response || !response.message || !response.message.content || response.message.content.trim() === "{}") {
28+
return res.status(500).json({ error: "Unexpected response from BART. Try again with a shorter text." });
29+
}
30+
31+
let summary = response.message.content.trim();
32+
33+
if(summary.includes("</think")){
34+
summary = summary.split("</think>", 2)[1]?.trim() || summary;
35+
}
36+
37+
res.json({ summary });
38+
39+
} catch (error) {
40+
console.error("Threw an error:", error);
41+
res.status(500).json({ error: "BART cannot summarize", details: error.message });
1942
}
20-
}
21-
const response = await summarize(content)
22-
console.log(response)
43+
});
44+
45+
app.listen(5000, () => console.log("Server running on port 5000"));

server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
## not being used
2+
13
import os
24
from flask import Flask, request, jsonify
35
from flask_cors import CORS

0 commit comments

Comments
 (0)