Skip to content

Commit 7d7e2ce

Browse files
authored
Optionally run Jina reader output through Claude with summary prompt
https://gist.github.com/simonw/f768916929eb5b7268354ddcb1021b94
1 parent 0af3172 commit 7d7e2ce

File tree

1 file changed

+130
-6
lines changed

1 file changed

+130
-6
lines changed

jina-reader.html

+130-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
font-size: 24px;
1818
margin-bottom: 20px;
1919
}
20-
#url-input, #format-select, #submit-btn, #markdown-raw, #copy-btn {
20+
#url-input, #format-select, #submit-btn, #markdown-raw, #copy-btn, #prompt-textarea, #run-prompt-btn {
2121
font-size: 16px;
2222
padding: 5px;
2323
margin-bottom: 10px;
@@ -29,33 +29,55 @@
2929
#format-select {
3030
width: 20%;
3131
}
32-
#submit-btn, #copy-btn {
32+
#submit-btn, .copy-btn, #run-prompt-btn {
3333
background-color: #4CAF50;
3434
color: white;
3535
border: 2px solid #4CAF50;
3636
cursor: pointer;
3737
}
38-
#submit-btn:hover, #copy-btn:hover {
38+
#submit-btn:hover, .copy-btn:hover, #run-prompt-btn:hover {
3939
background-color: #45a049;
4040
}
41-
#markdown-raw {
41+
#markdown-raw, #prompt-textarea {
4242
width: 100%;
4343
height: 200px;
4444
margin-top: 20px;
4545
resize: vertical;
4646
}
47+
#prompt-textarea {
48+
height: 100px;
49+
}
4750
#markdown-rendered {
4851
margin-top: 20px;
4952
border: 1px solid #ccc;
5053
padding: 10px;
5154
overflow-wrap: break-word;
5255
}
53-
#loading {
56+
#loading, #prompt-loading {
5457
display: none;
5558
margin-top: 20px;
5659
}
57-
#result {
60+
#result, #prompt-result {
5861
display: none;
62+
line-height: 1.5;
63+
font-size: 16px;
64+
}
65+
#prompt-rendered {
66+
font-family: system-ui, -apple-system, sans-serif;
67+
max-width: 65ch;
68+
margin: 1.5em 0;
69+
}
70+
#prompt-rendered p {
71+
margin: 1em 0;
72+
line-height: 1.6;
73+
}
74+
#prompt-rendered ul {
75+
margin: 1em 0;
76+
padding-left: 2em;
77+
}
78+
#prompt-rendered li {
79+
margin: 0.5em 0;
80+
line-height: 1.4;
5981
}
6082
iframe {
6183
width: 100%;
@@ -103,6 +125,17 @@ <h1>Jina Reader</h1>
103125
<iframe id="markdown-rendered" sandbox></iframe>
104126
</div>
105127

128+
<div id="prompt-section" style="margin-top: 2em; padding-top: 2em; border-top: 1px solid #eee; display: none;">
129+
<h2>Run a prompt with Claude</h2>
130+
<textarea id="prompt-textarea">Respond in markdown. You summarize the pasted in text. Start with a overall summary in a single paragraph. Then show a bullet pointed list of the most interesting illustrative quotes from the piece. Then a bullet point list of the most unusual ideas. Finally provide a longer summary that covers points not included already</textarea>
131+
<button id="run-prompt-btn">Run prompt</button>
132+
<div id="prompt-loading" style="margin: 1em 0; font-style: italic;">Generating...</div>
133+
<div id="prompt-result">
134+
<div id="prompt-rendered"></div>
135+
<button id="prompt-copy-btn" class="copy-btn" style="margin-top: 1em;">Copy to clipboard</button>
136+
</div>
137+
</div>
138+
106139
<script>
107140
const urlForm = document.getElementById('url-form');
108141
const urlInput = document.getElementById('url-input');
@@ -113,6 +146,14 @@ <h1>Jina Reader</h1>
113146
const copyBtn = document.getElementById('copy-btn');
114147
const markdownRendered = document.getElementById('markdown-rendered');
115148

149+
// Claude elements
150+
const promptTextarea = document.getElementById('prompt-textarea');
151+
const runPromptBtn = document.getElementById('run-prompt-btn');
152+
const promptLoading = document.getElementById('prompt-loading');
153+
const promptResult = document.getElementById('prompt-result');
154+
const promptRendered = document.getElementById('prompt-rendered');
155+
const promptCopyBtn = document.getElementById('prompt-copy-btn');
156+
116157
urlForm.addEventListener('submit', async (e) => {
117158
e.preventDefault();
118159
const url = urlInput.value;
@@ -157,11 +198,13 @@ <h1>Jina Reader</h1>
157198
}
158199
markdownRendered.srcdoc = htmlContent;
159200
result.style.display = 'block';
201+
document.getElementById('prompt-section').style.display = 'block';
160202
} catch (error) {
161203
console.error('Error fetching content:', error);
162204
markdownRaw.value = 'Error fetching content. Please try again.';
163205
markdownRendered.srcdoc = '<p>Error fetching content. Please try again.</p>';
164206
result.style.display = 'block';
207+
document.getElementById('prompt-section').style.display = 'none';
165208
} finally {
166209
loading.style.display = 'none';
167210
}
@@ -178,6 +221,87 @@ <h1>Jina Reader</h1>
178221
copyBtn.textContent = originalText;
179222
}, 1500);
180223
});
224+
225+
// Get the API key from localStorage or prompt the user to enter it
226+
function getApiKey() {
227+
let apiKey = localStorage.getItem("ANTHROPIC_API_KEY");
228+
if (!apiKey) {
229+
apiKey = prompt("Please enter your Anthropic API key:");
230+
if (apiKey) {
231+
localStorage.setItem("ANTHROPIC_API_KEY", apiKey);
232+
}
233+
}
234+
return apiKey;
235+
}
236+
237+
// Handle Claude prompt
238+
runPromptBtn.addEventListener('click', async () => {
239+
const apiKey = getApiKey();
240+
if (!apiKey) {
241+
alert("API key not found. Please enter your Anthropic API key.");
242+
return;
243+
}
244+
245+
// Get the prompt and content
246+
const systemPrompt = promptTextarea.value;
247+
const content = markdownRaw.value;
248+
249+
if (!content) {
250+
alert("No content to analyze. Please fetch a URL first.");
251+
return;
252+
}
253+
254+
promptLoading.style.display = 'block';
255+
promptResult.style.display = 'none';
256+
257+
try {
258+
const response = await fetch("https://api.anthropic.com/v1/messages", {
259+
method: "POST",
260+
headers: {
261+
"x-api-key": apiKey,
262+
"anthropic-version": "2023-06-01",
263+
"content-type": "application/json",
264+
"anthropic-dangerous-direct-browser-access": "true"
265+
},
266+
body: JSON.stringify({
267+
model: "claude-3-5-haiku-latest",
268+
max_tokens: 4096,
269+
system: systemPrompt,
270+
messages: [
271+
{
272+
role: "user",
273+
content: content
274+
}
275+
]
276+
})
277+
});
278+
279+
const data = await response.json();
280+
console.log(JSON.stringify(data, null, 2));
281+
const markdown = data.content[0].text;
282+
283+
promptRendered.innerHTML = marked.parse(markdown);
284+
promptResult.style.display = 'block';
285+
286+
let responseMarkdown = markdown;
287+
promptRendered.innerHTML = marked.parse(responseMarkdown);
288+
289+
promptCopyBtn.onclick = () => {
290+
navigator.clipboard.writeText(responseMarkdown);
291+
const originalText = promptCopyBtn.textContent;
292+
promptCopyBtn.textContent = 'Copied';
293+
setTimeout(() => {
294+
promptCopyBtn.textContent = originalText;
295+
}, 1500);
296+
};
297+
298+
} catch (error) {
299+
console.error("Error calling Claude API:", error);
300+
promptRendered.innerHTML = '<p class="error">Error generating summary. Please try again.</p>';
301+
} finally {
302+
promptLoading.style.display = 'none';
303+
}
304+
});
181305
</script>
182306
</body>
183307
</html>

0 commit comments

Comments
 (0)