Closed Hisma closed 1 year ago
I'm starting to think however that maybe I'm missing the point of smol dev. The point is to get you 90+% of the way there, not actually build a 100% working app right?
I mean, I can easily add my own icons in this case.
So what I did was just copy the 3 image icons from the "chrome example" folder to the "generated" folder, and the extension worked. So in reality, the example prompt made working code, and I just had to supply the images myself.
If that is what the goal of smol developer, I'm perfectly happy with that.
I would just highly recommend you make this more clear in the readme documentation that when you run the example you tell us to run to test if smol dev is working or not, you need to take the extra step of supplying the chrome extension image files.
@swyxio, please confirm my assumptions here, and I'll close this.
@Hisma yes, these assumptions are correct! it was always designed to co-design a codebase, and eventually be cleanly weaned off.
Tested several times, always with the same results.
I get no errors in the console. Here is what I run -
modal run main.py --prompt prompt.md --model=gpt-4
Here is the result - `✓ Initialized. View app at https://modal.com/apps/ap-2X0ikxpFtqmLoE63zZSiah ✓ Created objects. ├── 🔨 Created generate_response. ├── 🔨 Created mount /mnt/nas/developer/main.py ├── 🔨 Created mount /mnt/nas/developer/utils.py ├── 🔨 Created mount /mnt/nas/developer/constants.py └── 🔨 Created generate_file. hi its me, 🐣the smol developer🐣! you said you wanted: a Chrome Manifest V3 extension that reads the current page, and offers a popup UI that has the page title+content and a textarea for a prompt (with a default value we specify). When the user hits submit, it sends the page title+content to the Anthropic Claude API along with the up to date prompt to summarize it. The user can modify that prompt and re-send the prompt+content to get another summary view of the content.
Only when clicked:
content_script.js
on the currently open tab, and accesses the titlepageTitle
and main content (innerText)pageContent
of the currently open page (extracted via an injected content script, and sent over using astorePageContent
action)storePageContent
data and stores itloadingIndicator
, while waiting for the anthropic api to returngetPageContent
action (and the background listens for thegetPageContent
action and retrieves that data) and displays the title at the top of the popupapiKey
, and if it isn't stored, asks for an API key to Anthropic Claude and stores it.at the bottom of the popup, show a vertically resizable form that has:
userPrompt
userPrompt
has a default value ofstylePrompt
stylePrompt
has a default value ofsendButton
(tactile styling that "depresses" on click)sendButton
is clicked, calls the Anthropic model endpoint https://api.anthropic.com/v1/complete with:claude-instant-v1
model (ifpageContent
is <70k words) or theclaude-instant-v1-100k
model (if more)content
Important Details:
It has to run in a browser environment, so no Nodejs APIs allowed.
the return signature of the anthropic api is curl https://api.anthropic.com/v1/complete\ -H "x-api-key: $API_KEY"\ -H 'content-type: application/json'\ -d '{ "prompt": "\n\nHuman: Tell me a haiku about trees\n\nAssistant: ", "model": "claude-v1", "max_tokens_to_sample": 1000, "stop_sequences": ["\n\nHuman:"] }' {"completion":" Here is a haiku about trees:\n\nSilent sentinels, \nStanding solemn in the woods,\nBranches reaching sky.","stop":"\n\nHuman:","stop_reason":"stop_sequence","truncated":false,"log_id":"f5d95cf326a4ac39ee36a35f434a59d5","model":"claude-v1","exception":null}
in the string prompt sent to Anthropic, first include the page title and page content, and finally append the prompt, clearly vertically separated by spacing.
if the Anthropic api call is a 401, handle that by clearing the stored anthropic api key and asking for it again.
add styles to make sure the popup's styling follows the basic rules of web design, for example having margins around the body, and a system font stack.
style the popup body with but insist on body margins of 16 and a minimum width of 400 and height of 600.
debugging notes
inside of background.js, just take the getPageContent response directly
inside of popup.js, Update the function calls to
requestAnthropicSummary
inpopup.js
to pass theapiKey
:in
popup.js
, store the defaultPrompt at the top level. also, give a HTML format to the anthropic prompt89 tokens in prompt: You are an AI developer who is trying to write a p... 1785 tokens in prompt: a Chrome Manifest V3 extension that reads the curr... [ "manifest.json", "background.js", "content_script.js", "popup.html", "popup.js", "styles.css" ] 145 tokens in prompt: You are an AI developer who is trying to write a p... 1785 tokens in prompt: a Chrome Manifest V3 extension that reads the curr... Shared dependencies:
Exported variables:
defaultPrompt
defaultStyle
finalPrompt
Data schemas:
storePageContent
action datagetPageContent
action dataID names of DOM elements:
loadingIndicator
userPrompt
stylePrompt
sendButton
content
Message names:
storePageContent
getPageContent
Function names:
requestAnthropicSummary
shared_dependencies.md Shared dependencies:Exported variables:
defaultPrompt
defaultStyle
finalPrompt
Data schemas:
storePageContent
action datagetPageContent
action dataID names of DOM elements:
loadingIndicator
userPrompt
stylePrompt
sendButton
content
Message names:
storePageContent
getPageContent
Function names:
requestAnthropicSummary
2032 tokens in prompt: You are an AI developer who is trying to write a p... 1952 tokens in prompt: We have broken up the program into per-file g... 2032 tokens in prompt: You are an AI developer who is trying to write a p... 1952 tokens in prompt: We have broken up the program into per-file g... 2032 tokens in prompt: You are an AI developer who is trying to write a p... 1954 tokens in prompt: We have broken up the program into per-file g... 2032 tokens in prompt: You are an AI developer who is trying to write a p... 1952 tokens in prompt: We have broken up the program into per-file g... 2032 tokens in prompt: You are an AI developer who is trying to write a p... 1952 tokens in prompt: We have broken up the program into per-file g... content_script.js // content_script.jsfunction getPageTitleAndContent() { const pageTitle = document.title; const pageContent = document.body.innerText; return { pageTitle, pageContent }; }
chrome.runtime.sendMessage( { action: 'storePageContent', ...getPageTitleAndContent() }, (response) => { if (response.success) { console.log('Page content stored successfully'); } else { console.error('Failed to store page content'); } } ); 2032 tokens in prompt: You are an AI developer who is trying to write a p... 1952 tokens in prompt: We have broken up the program into per-file g... background.js chrome.runtime.onInstalled.addListener(() => { chrome.action.onClicked.addListener((tab) => { chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['content_script.js'], }); }); });
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'storePageContent') { chrome.storage.local.set({ pageContent: request }, () => { sendResponse({ success: true }); chrome.action.setPopup({ popup: 'popup.html' }, () => { chrome.action.openPopup(); }); }); } else if (request.action === 'getPageContent') { chrome.storage.local.get(['pageContent'], (result) => { sendResponse(result); }); } return true; }); manifest.json { "manifest_version": 3, "name": "Anthropic Claude Summarizer", "version": "1.0.0", "description": "A Chrome extension that summarizes web pages using the Anthropic Claude API.", "permissions": ["activeTab", "storage"], "action": { "default_popup": "popup.html", "default_icon": { "16": "icon16.png", "48": "icon48.png", "128": "icon128.png" } }, "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": [""],
"js": ["content_script.js"],
"run_at": "document_idle"
}
],
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}
}
popup.html
<!DOCTYPE html>
styles.css body { margin: 16px; min-width: 400px; min-height: 600px; }
loadingIndicator {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; height: 10px; overflow: hidden; background-color: #f0f0f0; border-radius: 5px; }
loadingIndicator:before {
content: ""; position: absolute; top: 0; left: 0; width: 50%; height: 100%; background: linear-gradient(45deg, #f06, transparent); animation: loading 1s infinite; }
@keyframes loading { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
textarea { resize: vertical; }
sendButton {
background-color: #4CAF50; border: none; color: white; padding: 8px 16px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 4px; transition: background-color 0.3s, transform 0.3s; }
sendButton:hover {
background-color: #45a049; }
sendButton:active {
transform: translateY(2px); } popup.js document.addEventListener('DOMContentLoaded', () => { const loadingIndicator = document.getElementById('loadingIndicator'); const userPrompt = document.getElementById('userPrompt'); const stylePrompt = document.getElementById('stylePrompt'); const sendButton = document.getElementById('sendButton'); const content = document.getElementById('content');
const defaultPrompt = 'Please provide a detailed, easy to read HTML summary of the given content'; const defaultStyle = `Respond with 3-4 highlights per section with important keywords, people, numbers, and facts bolded in this HTML format:
{title here}
{section title here}
{summary of the section with important keywords, people, numbers, and facts bolded and key quotes repeated}
{second section here}
{summary of the section with important keywords, people, numbers, and facts bolded and key quotes repeated}
{summary of the section with important keywords, people, numbers, and facts bolded and key quotes repeated}
{third section here}
With all the words in brackets replaced by the summary of the content. sanitize non visual HTML tags with HTML entities, so becomes <template> but stays the same. Only draw from the source content, do not hallucinate. Finally, end with other questions that the user might want answered based on this source content:
Next prompts