इस ब्लॉग पोस्ट में, मैं आपको एक ब्राउज़र एक्सटेंशन बनाना सिखाऊंगा जो Qwen-Agent की मदद से किसी भी वेबपेज की सामग्री को रियल टाइम में संक्षेपित करता है। हम यह कवर करेंगे कि कैसे:
Ollama के जरिए अपने सिस्टम पर Alibaba का Qwen3 मॉडल चलाएं
संरचित प्रॉम्प्टिंग और टूल उपयोग के लिए Qwen-Agent का इस्तेमाल करें
स्ट्रीमिंग UI अपडेट्स के साथ Chrome एक्सटेंशन बनाएं
रियल-टाइम समरी के लिए FastAPI बैकएंड जोड़ें
अंत तक, आपके पास Qwen3 द्वारा संचालित एक ऑफ़लाइन-सक्षम समरी एजेंट होगा, जो आपके ब्राउज़र में एक क्लिक में वेबपेज पढ़कर उसका सार प्रस्तुत करेगा।
हम अपने पाठकों को AI की ताज़ा खबरों से अपडेट रखते हैं The Median के जरिए—हमारा मुफ़्त शुक्रवार न्यूज़लेटर जो हफ्ते की मुख्य कहानियों को सरलता से समझाता है। सब्सक्राइब करें और हफ्ते में कुछ ही मिनटों में तेज़ रहें:
Qwen-Agent क्या है?
Qwen-Agent Alibaba द्वारा बनाया गया एक हल्का Python फ्रेमवर्क है, जो Qwen3 मॉडल परिवार के साथ शक्तिशाली LLM एप्लिकेशन विकसित करने के लिए बनाया गया है। यह मुख्य रूप से समर्थन देता है:
निर्देश-पालन करने वाले एजेंट
टूल उपयोग और फ़ंक्शन कॉलिंग
मेमोरी और मल्टी-टर्न प्लैनिंग
संरचित संदेशों के जरिए लचीला प्रॉम्प्टिंग
मूल रूप से, Qwen-Agent मजबूत तर्क और कोड निष्पादन क्षमताओं के साथ मॉड्यूलर AI एजेंट बनाना सरल बनाता है। इसमें LLM रैपर्स और टूल जैसे एटॉमिक घटक शामिल हैं, साथ ही वर्कफ़्लो ऑर्केस्ट्रेशन के लिए उच्च-स्तरीय Agent क्लासेज़ भी।
Qwen-Agent क्लाउड-आधारित API (जैसे Alibaba DashScope) और स्थानीय OpenAI-कंपैटिबल रनटाइम जैसे vLLM और Ollama दोनों के साथ काम करता है। यह निम्नलिखित के साथ शक्तिशाली LLM ऐप बनाना आसान बनाता है:
इस सेक्शन में, हम Qwen-Agent द्वारा संचालित रियल-टाइम समरीज़र एक्सटेंशन बनाएंगे। इसमें शामिल है:
एक FastAPI बैकएंड जो वेबपेज टेक्स्ट लेकर समरी लौटाता है
दिखाई दे रही पेज सामग्री को कैप्चर करने के लिए Chrome एक्सटेंशन पॉप-अप
समरी बनते समय स्ट्रीमिंग UI
Ollama के जरिए लोकली चल रहा Qwen3:1.7B से संचालित बैकएंड
आइए इस प्रोजेक्ट के हर भाग को क्रम से समझें।
स्टेप 1: Qwen3 बैकएंड सेटअप करना
इस स्टेप में, हम उन सभी कोड फ़ाइलों को कवर करेंगे जिन्हें हमें अपने बैकएंड को एक्सटेंशन के साथ समकालिक रूप से काम कराने के लिए तैयार करना है।
स्टेप 1.1: डिपेंडेंसीज़ और लाइब्रेरीज़
सबसे पहले अपने सिस्टम पर ollama इंस्टॉल करें। इसके बाद, बैकएंड के लिए सभी Python डिपेंडेंसीज़ को requirements.txt. में सूचीबद्ध करें। इससे मशीनों और कंटेनरों में समान एनवायरनमेंट सेटअप सुनिश्चित होता है।
fastapi
uvicorn
python-dateutil
python-dotenv
qwen-agent[code_interpreter]
matplotlibसंचालित द्वारा
प्रत्येक लाइब्रेरी का उपयोग इस प्रकार है:
qwen-agent[code_interpreter]: यह टूल-उपयोग समर्थन के साथ एक कोर एजेंट फ्रेमवर्क है, जो कोड निष्पादन और संरचित तर्क सक्षम करता है।
fastapi और uvicorn: ये लाइब्रेरीज़ मिलकर असिंक्रोनस API बैकएंड चलाती हैं और आपकी समरी लॉजिक सर्व करती हैं।
python-dotenv और python-dateutil: ये यूटिलिटी लाइब्रेरीज़ एनवायरनमेंट वेरिएबल्स और दिनांक/समय प्रोसेसिंग संभालती हैं (भविष्य में स्केलिंग के लिए उपयोगी)।
matplotlib: प्लॉटिंग या विज़ुअल आउटपुट दिखाने के लिए उपयोग होती है (वैकल्पिक)
यदि आप यह प्रोजेक्ट लोकली चलाना चाहते हैं, तो सभी डिपेंडेंसीज़ इंस्टॉल करने के लिए यह कमांड चलाएं:
अब, एक Dockerfile सेट करें जो हमारे ऐप के साथ एक न्यूनतम Python एनवायरनमेंट बनाता है और पोर्ट 7864 को एक्सपोज़ करता है, जिससे Chrome एक्सटेंशन FastAPI बैकएंड को रिक्वेस्ट भेज सके।
FROM python:3.10
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 7864
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7864"]संचालित द्वारा
यदि आप Docker की जगह Uvicorn का उपयोग करके लोकली प्रोजेक्ट चलाना चुनते हैं, तो यह सेटअप वैकल्पिक है।
स्टेप 1.3: Ollama के साथ Qwen सर्व करना
अगला, आपको Ollama का उपयोग करके Qwen3 मॉडल को लोकली पुल और सर्व करना होगा। यह स्टेप आपके मशीन पर LLM सर्विस होस्ट करके ऑफ़लाइन इन्फ़रेंस सक्षम करता है।
फ़ाइल app.py एक FastAPI सर्वर परिभाषित करती है जो Qwen-Agent के जरिए लोकली चल रहे Qwen3:1.7B मॉडल का उपयोग कर वेबपेज सामग्री की रियल-टाइम समरी स्ट्रीम करता है।
स्टेप 1.4.1: इम्पोर्ट्स
शुरू करें FastAPI, स्ट्रीमिंग यूटिलिटीज़, और Qwen-Agent के घटक जैसे Assistant को इम्पोर्ट करके, जो मॉडल और उसके टूल्स को रैप करता है।
import re
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from typing import List, Dict, Any
from qwen_agent.agents import Assistant
import loggingसंचालित द्वारा
स्टेप 1.4.2: FastAPI ऐप इनिशियलाइज़ेशन
इसके बाद, हम एक सरल RequestData स्कीमा परिभाषित करते हैं जो सामग्री प्राप्त करता है, और Assistant का एक बॉट इंस्टेंस बनाते हैं।
app = FastAPI()classRequestData(BaseModel):
content:str
bot = Assistant(
llm={"model":"qwen3:1.7b","model_server":"http://localhost:11434/v1","api_key":"EMPTY"},
function_list=["code_interpreter"],
system_message="You are a summarization assistant. Directly output the cleaned summary of the given text without any reasoning, self-talk, thoughts, or internal planning steps. Do not include phrases like 'I think', 'maybe', 'let's', 'the user wants', or anything not part of the final summary. Your output must look like it was written by an editor, not a model.")संचालित द्वारा
ऊपर दिए गए कोड में, bot Qwen-Agent की Assistant क्लास का इंस्टेंस है, जिसे Ollama के जरिए लोकली सर्व किए गए Qwen3:1.7B मॉडल से इंटरैक्ट करने के लिए कॉन्फ़िगर किया गया है। यह बिल्ट-इन code_interpreter टूल का उपयोग करके सामग्री पर विचार कर सकता है और ज़रूरत पड़ने पर Python कोड चला सकता है। एक कस्टम system_message इसे संक्षिप्त वेबपेज समरी बनाने के लिए निर्देशित करता है।
नोट: आप qwen3:0.6b या qwen3:1.7b जैसे छोटे मॉडल का उपयोग कर सकते हैं ताकि प्रतिक्रिया समय और मेमोरी उपयोग को काफी कम किया जा सके। यह खासकर तेज़ समरीकरण कार्यों के लिए उपयोगी है, जहां अधिक तर्क की आवश्यकता नहीं है।
स्टेप 1.4.3: समराइज़र रूट
अंत में, एक एंडपॉइंट इनकमिंग सामग्री को पढ़ता है और जैसे-जैसे मॉडल टेक्स्ट जनरेट करता है, लाइव समरी देता है। यह स्ट्रीमिंग आउटपुट का उपयोग करता है ताकि उपयोगकर्ता को पूरी प्रतिक्रिया का इंतज़ार न करना पड़े।
@app.post("/summarize_stream_status")asyncdefsummarize_stream_status(data: RequestData):
user_input = data.content
defstream():try:yield"🔍 Reading content on website...\n"print(" Received text:", user_input[:200])
messages =[{"role":"system","content":"You are a summarization assistant. Directly output the cleaned summary of the given text without any reasoning, self-talk, thoughts, or internal planning steps. Do not include phrases like 'I think', 'maybe', 'let's', 'the user wants', or anything not part of the final summary. Your output must look like it was written by an editor, not a model."},{"role":"user","content":"<nothink>\nSummarize the following text clearly and concisely. Do not include any internal thoughts, planning, or reasoning. Just return the final summary:\n\n"+ user_input +"\n</nothink>"}]yield"🧠 Generating summary...\n"
result = bot.run(messages)
result_list =list(result)print(" Raw result:", result_list)# Extract summary
last_content =Nonefor item inreversed(result_list):ifisinstance(item,list):for subitem inreversed(item):ifisinstance(subitem,dict)and"content"in subitem:
last_content = subitem["content"]breakif last_content:breakifnot last_content:yield" No valid summary found.\n"return
summary = re.sub(r"</?think>","", last_content)
summary = re.sub(r"(?s)^.*?(Summary:|Here's a summary|The key points are|Your tutorial|This tutorial|To summarize|Final summary:)","",
summary,
flags=re.IGNORECASE
)
summary = re.sub(r"\n{3,}","\n\n", summary)
summary = summary.strip()yield"\n📄 Summary:\n"+ summary +"\n"except Exception as e:print(" Error:", e)yieldf"\n Error: {str(e)}\n"return StreamingResponse(stream(), media_type="text/plain")संचालित द्वारा
हमारा समराइज़र इस तरह काम करता है:
फ़ंक्शन RequestData स्कीमा का उपयोग करके POST डेटा रिसीव करता है, जिसमें content नाम का फ़ील्ड अपेक्षित है जो कच्चा वेबपेज टेक्स्ट रखता है।
एक नेस्टेड stream() जेनरेटर फ़ंक्शन क्रमशः संदेश भेजने के लिए परिभाषित है। इससे अंतिम समरी पूरी होने से पहले रियल-टाइम फीडबैक फ्रंटएंड तक जाता रहता है।
संदेश सूची में यूज़र संदेश के भीतर स्पष्ट रूप से </nothink> टैग रैपर शामिल है ताकि आंतरिक तर्क को दबाया जा सके, और एक विस्तृत सिस्टम प्रॉम्प्ट इस व्यवहार को सुदृढ़ करता है।
Qwen-Agent बॉट को bot.run(messages) के जरिए कॉल किया जाता है, जहां messages में एक यूज़र इनपुट संदेश शामिल है।
मॉडल प्रतिक्रियाएँ स्ट्रीम होकर result_list में इकट्ठी होती हैं। फिर कोड LLM द्वारा लौटाए गए नवीनतम कंटेंट स्ट्रिंग को निकालने के लिए सूची को उल्टे क्रम में लूप करता है।
आउटपुट से Qwen के आंतरिक तर्क मार्कर जैसे <think> और </think> को regex के जरिए हटाकर अंतिम समरी को साफ़ किया जाता है।
यदि वैध कंटेंट नहीं मिलता, तो एक फॉलबैक संदेश भेजा जाता है। अन्यथा, साफ़ की गई समरी फ्रंटएंड तक स्ट्रीम की जाती है।
स्टेप 2: Chrome एक्सटेंशन बनाना
यह सेक्शन एक्सटेंशन सेटअप के लिए जरूरी सभी फ़ाइलों को समझाता है, जिनमें फ्रंटएंड UI, पेज कंटेंट निकालने की लॉजिक, बैकग्राउंड कम्युनिकेशन स्क्रिप्ट्स, और कॉन्फ़िगरेशन मेटाडेटा शामिल हैं।
इंडिविजुअल स्क्रिप्ट्स देखने से पहले, हर फ़ाइल क्या करती है उसका सरल विवरण:
manifest.json: यह एक कॉन्फ़िगरेशन फ़ाइल है जो एक्सटेंशन का मेटाडेटा, परमिशन, और स्क्रिप्ट्स परिभाषित करती है।
popup.html: यह स्क्रिप्ट Chrome एक्सटेंशन पॉप-अप के लिए विज़िबल UI परिभाषित करती है, जिसमें एक बटन और आउटपुट पैनल है।
popup.js: यह फ्रंटएंड लॉजिक संभालता है, वर्तमान टैब का टेक्स्ट कैप्चर करता है और समरी रिस्पॉन्स को UI तक स्ट्रीम करता है।
content.js: अनुरोध मिलने पर यह विज़िबल वेबपेज सामग्री निकालता है—कंटेंट स्क्रिप्ट के रूप में।
background.js: यह स्क्रिप्ट बैकएंड कम्युनिकेशन को समन्वित करती है और स्ट्रीमिंग समरी को पॉप-अप तक पहुंचाती है।
icon.png: यह Chrome के टूलबार और एक्सटेंशन मैनेजर में दिखने वाला एक्सटेंशन आइकन है।
मिलकर, ये फ़ाइलें एक्सटेंशन को इंटरैक्टिव, रिएक्टिव बनाती हैं और इसे स्थानीय मॉडल सर्वर से बात करने में सक्षम बनाती हैं।
स्टेप 1: एक्सटेंशन मेटाडेटा
स्क्रिप्ट manifest.json Chrome के लिए मेटाडेटा रखती है। यह एक्सटेंशन का व्यवहार, परमिशन, बैकग्राउंड सर्विस वर्कर और पॉप-अप UI परिभाषित करती है।
{"manifest_version":3,"name":"Web Summarizer","version":"1.0","description":"Summarize the content of the current page using a local LLM agent.","permissions":["scripting","activeTab","storage"],"host_permissions":["<all_urls>"],"action":{"default_popup":"popup.html","default_icon":"icon.png"},"background":{"service_worker":"background.js"},"content_scripts":[{"matches":["<all_urls>"],"js":["content.js"],"run_at":"document_idle"}]}संचालित द्वारा
यह फ़ाइल आपके Chrome एक्सटेंशन की कॉन्फ़िगरेशन और क्षमताएं परिभाषित करती है। यह आवश्यक परमिशन देती है जैसे scripting (JavaScript इंजेक्ट करने के लिए), activeTab (वर्तमान टैब तक पहुंचने के लिए), और storage (यूज़र प्रेफरेंसेज़ सेव करने के लिए)।
host_permissions फ़ील्ड में "<all_urls>" एक्सटेंशन को किसी भी वेबपेज पर चलने देता है। यह popup.html और icon.png के जरिए एक्सटेंशन का UI सेट करता है, और सर्विस वर्कर (background.js) का उपयोग करके बैकग्राउंड व्यवहार रजिस्टर करता है। अंत में, यह एक कंटेंट स्क्रिप्ट (content.js) परिभाषित करता है जो सभी लोडेड पेजों पर चलती है, ताकि जरूरत पड़ने पर वेबपेज सामग्री के साथ इंटरेक्शन हो सके।
स्टेप 2: विज़िबल इंटरफ़ेस बनाना
फ़ाइल popup.html एक्सटेंशन का विज़िबल इंटरफ़ेस परिभाषित करती है। यह सक्रिय टैब से जुड़कर विज़िबल टेक्स्ट कैप्चर करती है और इसे आपके बैकएंड सर्वर पर भेजती है।
पहले, हम एक बेसिक HTML संरचना सेट करते हैं, जिसमें <head> टैग में कैरेक्टर एनकोडिंग, व्यूपोर्ट सेटिंग्स और <title> टैग के लिए मेटा टैग शामिल हैं।
फिर, <body> टैग के अंदर, एक कंटेनर सभी UI एलिमेंट्स को रखता है, जिनमें शामिल हैं:
एक <h2> हेडिंग जो उपयोगकर्ता को वर्तमान पेज का सार निकालने के लिए प्रेरित करती है।
एक Summarize बटन (“#summarizeBtn”) जिसे क्लिक करने पर कंटेंट एक्सट्रैक्शन और समरीकरण ट्रिगर होता है।
एक <pre> एलिमेंट (“#output”) जो स्ट्रीम होते हुए समरी दिखाने के लिए स्क्रॉल करने योग्य पैनल के रूप में काम करता है।
एम्बेडेड CSS के जरिए स्टाइलिंग परिभाषित है ताकि पॉपअप साफ़-सुथरा और पठनीय दिखे। pre ब्लॉक आउटपुट को स्क्रॉल करने योग्य और अलग दिखाने के लिए उपयोग होता है।
स्क्रिप्ट popup.js बटन क्लिक सुनती है, पेज कंटेंट निकालती है, उसे FastAPI बैकएंड पर भेजती है, और स्ट्रीमिंग समरी टेक्स्ट के साथ आउटपुट पैनल अपडेट करती है।
स्टेप 3: फ्रंटएंड UI बनाना
फ़ाइल popup.js एक फ्रंटएंड लॉजिक कंट्रोलर है जो बटन क्लिक पर प्रतिक्रिया देता है, वर्तमान टैब से टेक्स्ट निकालता है, उसे बैकएंड तक भेजता है, और रियल टाइम में आउटपुट एरिया में समरी स्ट्रीम करता है।
document.addEventListener('DOMContentLoaded',function(){let serverAddress ='127.0.0.1';
document.getElementById('summarizeBtn').addEventListener('click',async()=>{const[tab]=await chrome.tabs.query({active:true,currentWindow:true});
chrome.scripting.executeScript({target:{tabId: tab.id },func:()=>{try{return document.body?.innerText ||'EMPTY';}catch(e){return'SCRIPT_ERROR';}}},async(results)=>{const pageText = results?.[0]?.result ||'';
console.log(' Extracted text:', pageText.slice(0,500));if(pageText ==='SCRIPT_ERROR'){
document.getElementById('output').innerText ='Could not access page content (script error).';return;}if(!pageText || pageText.trim()==='EMPTY'){
document.getElementById('output').innerText =' No page text found.';return;}try{
console.log( Sending streaming POST to http://${serverAddress}:7864/summarize_stream_status);const res =awaitfetch(http://${serverAddress}:7864/summarize_stream_status,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({content: pageText }),});const reader = res.body.getReader();const decoder =newTextDecoder();let resultText ='';while(true){const{ done, value }=await reader.read();if(done)break;const chunk = decoder.decode(value,{stream:true});
resultText += chunk;
document.getElementById('output').innerText = resultText;}}catch(err){
console.error(' Fetch error:', err);
document.getElementById('output').innerText =' Failed to get summary.\n'+ err.message;}});});});संचालित द्वारा
यह JavaScript फ़ाइल Chrome एक्सटेंशन के फ्रंटएंड UI लॉजिक को संचालित करती है, जिससे उपयोगकर्ता एक क्लिक में वेबपेज सामग्री निकालकर उसका सार बना सकते हैं।
यह ऐसे काम करती है:
जब पॉप-अप लोड होता है (DOMContentLoaded), "Summarize" बटन पर एक इवेंट लिस्नर लगाया जाता है।
बटन क्लिक पर, एक्सटेंशन chrome.tabs.query के जरिए मौजूदा सक्रिय टैब को क्वेरी करता है।
इसके बाद chrome.scripting.executeScript का उपयोग करके उस टैब के अंदर एक कंटेंट स्क्रिप्ट चलाता है, जो पेज बॉडी के innerText को निकालने की कोशिश करती है।
यदि स्क्रिप्ट फेल होती है या खाली कंटेंट लौटाती है, तो UI में उपयुक्त फॉलबैक संदेश दिखाए जाते हैं।
यदि टेक्स्ट सफलतापूर्वक निकाला जाता है, तो इसे http://127.0.0.1:7864/summarize_stream_status पर लोकल FastAPI बैकएंड को POST रिक्वेस्ट के रूप में भेज दिया जाता है।
रिस्पॉन्स को res.body.getReader() के जरिए स्ट्रीम किया जाता है, जिससे आउटपुट पैनल में समरी के हिस्से रियल टाइम में दिखाई देते रहते हैं।
एक TextDecoder स्ट्रीम किए गए हर हिस्से को डिकोड करता है और उसे लाइव डिस्प्ले में जोड़ता है।
कोई भी नेटवर्क या बैकएंड त्रुटि पकड़ी जाती है और पॉप-अप इंटरफ़ेस में दिखाई जाती है ताकि डिबगिंग या यूज़र फीडबैक मिल सके।
स्टेप 4: वेबपेज सामग्री निकालना
बैकएंड तक वेबपेज कंटेंट भेजने से पहले, हमें इसे वर्तमान टैब से निकालने का तरीका चाहिए। स्क्रिप्ट content.js बैकग्राउंड या पॉपअप स्क्रिप्ट्स से संदेश सुनती है और वेबपेज से विज़िबल टेक्स्ट कंटेंट लौटाती है।
chrome.runtime.onMessage.addListener((request, sender, sendResponse)=>{if(request.type ==="GET_PAGE_TEXT"){const bodyText = document.body.innerText.trim();sendResponse({text: bodyText ||null});}});संचालित द्वारा
यह स्क्रिप्ट "GET_PAGE_TEXT" प्रकार के संदेशों को सुनती है और प्रतिक्रिया में विज़िबल बॉडी टेक्स्ट (document.body.innerText) निकालकर वापस भेजती है। इससे बैकग्राउंड वर्कर हर बार कोड इंजेक्ट किए बिना आसानी से वेबपेज सामग्री मांग सकता है—कम्युनिकेशन साफ़ और असिंक्रोनस बना रहता है।
स्टेप 5: बैकएंड कोऑर्डिनेशन
बैकग्राउंड स्क्रिप्ट (background.js) पॉपअप UI और कंटेंट स्क्रिप्ट्स के बीच पुल का काम करती है। यह सुनिश्चित करती है कि संदेश पासिंग और समरीज़ेशन का समन्वय परदे के पीछे सही ढंग से हो।
ऊपर का कोड कंटेंट एक्सट्रैक्शन, समरीकरण, और रियल-टाइम अपडेट्स के सुचारू प्रवाह को सुनिश्चित करता है। यह इस तरह काम करता है:
यह पॉपअप में बटन क्लिक से ट्रिगर हुए "SUMMARIZE_PAGE" प्रकार के संदेश को सुनता है।
ट्रिगर होने पर, यह sender.tab.id से सक्रिय टैब पहचानता है और chrome.scripting.executeScript के जरिए वेबपेज से विज़िबल टेक्स्ट निकालने के लिए एक स्क्रिप्ट चलाता है।
यदि कंटेंट एक्सेस नहीं हो पाता या खाली होता है, तो फॉलबैक संदेश भेज दिया जाता है।
अन्यथा, यह Chrome के लोकल स्टोरेज से database_host (आम तौर पर 127.0.0.1) निकालता है और निकाली गई सामग्री के साथ FastAPI बैकएंड को POST रिक्वेस्ट भेजता है।
फिर यह एक स्ट्रीमिंग कनेक्शन खोलता है और ReadableStreamDefaultReader का उपयोग करके रिस्पॉन्स को टुकड़ों में पढ़ता है।
जैसे ही हर हिस्सा डिकोड होता है, यह 'SUMMARY_PROGRESS' प्रकार के साथ chrome.runtime.sendMessage के जरिए पॉपअप को अंतरिम अपडेट भेजता है।
स्ट्रीम समाप्त होने पर, यह पूरी समरी के साथ अंतिम संदेश भेजता है। अगर इस प्रक्रिया में कोई त्रुटि होती है, तो फॉलबैक संदेश भेजा जाता है।
यह बैकग्राउंड स्क्रिप्ट Chrome एक्सटेंशन में रियल-टाइम, स्ट्रीमिंग समरी को सक्षम करने की कुंजी है—बिना UI को ब्लॉक किए या पेज रीलोड किए।
स्टेप 6: एक्सटेंशन आइकन जोड़ना
एक्सटेंशन के लिए कोई आइकन छवि चुनें या बनाएं और इसे एक्सटेंशन फ़ोल्डर में icon.png के रूप में सेव करें। हम यह इस्तेमाल करेंगे:
FireFly से जेनरेट की गई छवि
आपकी संपूर्ण फ़ोल्डर संरचना इस प्रकार दिखनी चाहिए:
सब कुछ लोकली चलाने के लिए, टर्मिनल में यह कमांड चलाएं:
uvicorn backend.app:app --host0.0.0.0 --port7864संचालित द्वारा
यह Docker के बिना लोकल डेवलपमेंट या डिबगिंग के लिए आदर्श है। Docker में चलाने के लिए, अपने टर्मिनल में ये कमांड एक-एक करके चलाएं:
docker build -t qwen-agent-backend .docker run -p7864:7864 qwen-agent-backendसंचालित द्वारा
Chrome एक्सटेंशन पोर्ट 7864 से संचार करता है। अब, Chrome पर अपना एक्सटेंशन चलाने के लिए निम्न चरणों का पालन करें:
Chrome खोलें और “Extensions” पर क्लिक करें(सर्च बार के दाईं ओर)।
“Developer mode” ऑन करें और “Load unpacked” (ऊपर बाएँ) पर क्लिक करें।
इसके बाद, सभी फ़ाइलों वाला हमारा एक्सटेंशन फ़ोल्डर लोड करें और कन्फर्मेशन का इंतज़ार करें।
जब पॉप-अप एक्सटेंशन सेटअप कन्फर्म कर दे, तो किसी भी वेबपेज पर एक्सटेंशन आइकन क्लिक करें और अपने लोकल Qwen3 मॉडल का उपयोग करते हुए स्ट्रीमिंग समरी प्राप्त करें।
आइए नतीजे देखें:
निष्कर्ष
इस प्रोजेक्ट में, हमने Qwen-Agent फ्रेमवर्क और Qwen3:1.7B मॉडल (Ollama के जरिए लोकली चल रहा) का उपयोग करके रियल-टाइम वेबपेज समरीकरण असिस्टेंट बनाया। हमने LLM इन्फ़रेंस संभालने के लिए FastAPI बैकएंड विकसित किया और इसे Chrome एक्सटेंशन के साथ जोड़ा जो विज़िबल पेज कंटेंट कैप्चर करता है और लाइव-स्ट्रीम्ड समरी दिखाता है।
यह डेमो दिखाता है कि Qwen-Agent कैसे ब्राउज़र में पूरी तरह ऑफ़लाइन, टूल-समर्थित तर्क वर्कफ़्लोज़ सक्षम कर सकता है। यह अधिक उन्नत लोकल एजेंट—जैसे ब्राउज़र ऑटोमेशन टूल्स, रिसर्च कोपायलट्स, या डॉक्यूमेंट-आधारित चैटबॉट्स—बनाने की नींव रखता है।
AI एजेंट्स के बारे में और जानने के लिए, ये ब्लॉग देखें:
मैं एमएल (Gen AI) में Google Developers Expert, Kaggle 3x Expert, और Women Techmakers एंबेसडर हूँ, तथा तकनीक क्षेत्र में 3+ वर्षों का अनुभव रखती हूँ। मैंने 2020 में एक हेल्थ-टेक स्टार्टअप की सह-स्थापना की और वर्तमान में Georgia Tech से कंप्यूटर विज्ञान में मास्टर कर रही हूँ, जिसमें मेरा विशेषज्ञता क्षेत्र मशीन लर्निंग है।
इस ब्लॉग पोस्ट में, मैं आपको एक ब्राउज़र एक्सटेंशन बनाना सिखाऊंगा जो Qwen-Agent की मदद से किसी भी वेबपेज की सामग्री को रियल टाइम में संक्षेपित करता है। हम यह कवर करेंगे कि कैसे:
अंत तक, आपके पास Qwen3 द्वारा संचालित एक ऑफ़लाइन-सक्षम समरी एजेंट होगा, जो आपके ब्राउज़र में एक क्लिक में वेबपेज पढ़कर उसका सार प्रस्तुत करेगा।
हम अपने पाठकों को AI की ताज़ा खबरों से अपडेट रखते हैं The Median के जरिए—हमारा मुफ़्त शुक्रवार न्यूज़लेटर जो हफ्ते की मुख्य कहानियों को सरलता से समझाता है। सब्सक्राइब करें और हफ्ते में कुछ ही मिनटों में तेज़ रहें:
Qwen-Agent क्या है?
Qwen-Agent Alibaba द्वारा बनाया गया एक हल्का Python फ्रेमवर्क है, जो Qwen3 मॉडल परिवार के साथ शक्तिशाली LLM एप्लिकेशन विकसित करने के लिए बनाया गया है। यह मुख्य रूप से समर्थन देता है:
मूल रूप से, Qwen-Agent मजबूत तर्क और कोड निष्पादन क्षमताओं के साथ मॉड्यूलर AI एजेंट बनाना सरल बनाता है। इसमें LLM रैपर्स और टूल जैसे एटॉमिक घटक शामिल हैं, साथ ही वर्कफ़्लो ऑर्केस्ट्रेशन के लिए उच्च-स्तरीय
Agentक्लासेज़ भी।Qwen-Agent क्लाउड-आधारित API (जैसे Alibaba DashScope) और स्थानीय OpenAI-कंपैटिबल रनटाइम जैसे vLLM और Ollama दोनों के साथ काम करता है। यह निम्नलिखित के साथ शक्तिशाली LLM ऐप बनाना आसान बनाता है:
प्रोजेक्ट ओवरव्यू: रियल-टाइम वेब समरीज़र एक्सटेंशन
इस सेक्शन में, हम Qwen-Agent द्वारा संचालित रियल-टाइम समरीज़र एक्सटेंशन बनाएंगे। इसमें शामिल है:
आइए इस प्रोजेक्ट के हर भाग को क्रम से समझें।
स्टेप 1: Qwen3 बैकएंड सेटअप करना
इस स्टेप में, हम उन सभी कोड फ़ाइलों को कवर करेंगे जिन्हें हमें अपने बैकएंड को एक्सटेंशन के साथ समकालिक रूप से काम कराने के लिए तैयार करना है।
स्टेप 1.1: डिपेंडेंसीज़ और लाइब्रेरीज़
सबसे पहले अपने सिस्टम पर ollama इंस्टॉल करें। इसके बाद, बैकएंड के लिए सभी Python डिपेंडेंसीज़ को
requirements.txt.में सूचीबद्ध करें। इससे मशीनों और कंटेनरों में समान एनवायरनमेंट सेटअप सुनिश्चित होता है।प्रत्येक लाइब्रेरी का उपयोग इस प्रकार है:
qwen-agent[code_interpreter]: यह टूल-उपयोग समर्थन के साथ एक कोर एजेंट फ्रेमवर्क है, जो कोड निष्पादन और संरचित तर्क सक्षम करता है।fastapiऔरuvicorn: ये लाइब्रेरीज़ मिलकर असिंक्रोनस API बैकएंड चलाती हैं और आपकी समरी लॉजिक सर्व करती हैं।python-dotenvऔरpython-dateutil: ये यूटिलिटी लाइब्रेरीज़ एनवायरनमेंट वेरिएबल्स और दिनांक/समय प्रोसेसिंग संभालती हैं (भविष्य में स्केलिंग के लिए उपयोगी)।matplotlib: प्लॉटिंग या विज़ुअल आउटपुट दिखाने के लिए उपयोग होती है (वैकल्पिक)यदि आप यह प्रोजेक्ट लोकली चलाना चाहते हैं, तो सभी डिपेंडेंसीज़ इंस्टॉल करने के लिए यह कमांड चलाएं:
स्टेप 1.2: DockerFile सेटअप (वैकल्पिक)
अब, एक Dockerfile सेट करें जो हमारे ऐप के साथ एक न्यूनतम Python एनवायरनमेंट बनाता है और पोर्ट 7864 को एक्सपोज़ करता है, जिससे Chrome एक्सटेंशन FastAPI बैकएंड को रिक्वेस्ट भेज सके।
यदि आप Docker की जगह Uvicorn का उपयोग करके लोकली प्रोजेक्ट चलाना चुनते हैं, तो यह सेटअप वैकल्पिक है।
स्टेप 1.3: Ollama के साथ Qwen सर्व करना
अगला, आपको Ollama का उपयोग करके Qwen3 मॉडल को लोकली पुल और सर्व करना होगा। यह स्टेप आपके मशीन पर LLM सर्विस होस्ट करके ऑफ़लाइन इन्फ़रेंस सक्षम करता है।
स्टेप 1.4: FastAPI समरीज़ेशन सर्वर बनाना
फ़ाइल
app.pyएक FastAPI सर्वर परिभाषित करती है जो Qwen-Agent के जरिए लोकली चल रहे Qwen3:1.7B मॉडल का उपयोग कर वेबपेज सामग्री की रियल-टाइम समरी स्ट्रीम करता है।स्टेप 1.4.1: इम्पोर्ट्स
शुरू करें FastAPI, स्ट्रीमिंग यूटिलिटीज़, और Qwen-Agent के घटक जैसे
Assistantको इम्पोर्ट करके, जो मॉडल और उसके टूल्स को रैप करता है।स्टेप 1.4.2: FastAPI ऐप इनिशियलाइज़ेशन
इसके बाद, हम एक सरल
RequestDataस्कीमा परिभाषित करते हैं जो सामग्री प्राप्त करता है, औरAssistantका एक बॉट इंस्टेंस बनाते हैं।ऊपर दिए गए कोड में,
botQwen-Agent कीAssistantक्लास का इंस्टेंस है, जिसे Ollama के जरिए लोकली सर्व किए गए Qwen3:1.7B मॉडल से इंटरैक्ट करने के लिए कॉन्फ़िगर किया गया है। यह बिल्ट-इनcode_interpreterटूल का उपयोग करके सामग्री पर विचार कर सकता है और ज़रूरत पड़ने पर Python कोड चला सकता है। एक कस्टमsystem_messageइसे संक्षिप्त वेबपेज समरी बनाने के लिए निर्देशित करता है।नोट: आप
qwen3:0.6bयाqwen3:1.7bजैसे छोटे मॉडल का उपयोग कर सकते हैं ताकि प्रतिक्रिया समय और मेमोरी उपयोग को काफी कम किया जा सके। यह खासकर तेज़ समरीकरण कार्यों के लिए उपयोगी है, जहां अधिक तर्क की आवश्यकता नहीं है।स्टेप 1.4.3: समराइज़र रूट
अंत में, एक एंडपॉइंट इनकमिंग सामग्री को पढ़ता है और जैसे-जैसे मॉडल टेक्स्ट जनरेट करता है, लाइव समरी देता है। यह स्ट्रीमिंग आउटपुट का उपयोग करता है ताकि उपयोगकर्ता को पूरी प्रतिक्रिया का इंतज़ार न करना पड़े।
हमारा समराइज़र इस तरह काम करता है:
RequestDataस्कीमा का उपयोग करकेPOSTडेटा रिसीव करता है, जिसमेंcontentनाम का फ़ील्ड अपेक्षित है जो कच्चा वेबपेज टेक्स्ट रखता है।stream()जेनरेटर फ़ंक्शन क्रमशः संदेश भेजने के लिए परिभाषित है। इससे अंतिम समरी पूरी होने से पहले रियल-टाइम फीडबैक फ्रंटएंड तक जाता रहता है।</nothink>टैग रैपर शामिल है ताकि आंतरिक तर्क को दबाया जा सके, और एक विस्तृत सिस्टम प्रॉम्प्ट इस व्यवहार को सुदृढ़ करता है।bot.run(messages)के जरिए कॉल किया जाता है, जहांmessagesमें एक यूज़र इनपुट संदेश शामिल है।result_listमें इकट्ठी होती हैं। फिर कोड LLM द्वारा लौटाए गए नवीनतम कंटेंट स्ट्रिंग को निकालने के लिए सूची को उल्टे क्रम में लूप करता है।<think>और</think>को regex के जरिए हटाकर अंतिम समरी को साफ़ किया जाता है।स्टेप 2: Chrome एक्सटेंशन बनाना
यह सेक्शन एक्सटेंशन सेटअप के लिए जरूरी सभी फ़ाइलों को समझाता है, जिनमें फ्रंटएंड UI, पेज कंटेंट निकालने की लॉजिक, बैकग्राउंड कम्युनिकेशन स्क्रिप्ट्स, और कॉन्फ़िगरेशन मेटाडेटा शामिल हैं।
इंडिविजुअल स्क्रिप्ट्स देखने से पहले, हर फ़ाइल क्या करती है उसका सरल विवरण:
manifest.json: यह एक कॉन्फ़िगरेशन फ़ाइल है जो एक्सटेंशन का मेटाडेटा, परमिशन, और स्क्रिप्ट्स परिभाषित करती है।popup.html: यह स्क्रिप्ट Chrome एक्सटेंशन पॉप-अप के लिए विज़िबल UI परिभाषित करती है, जिसमें एक बटन और आउटपुट पैनल है।popup.js: यह फ्रंटएंड लॉजिक संभालता है, वर्तमान टैब का टेक्स्ट कैप्चर करता है और समरी रिस्पॉन्स को UI तक स्ट्रीम करता है।content.js: अनुरोध मिलने पर यह विज़िबल वेबपेज सामग्री निकालता है—कंटेंट स्क्रिप्ट के रूप में।background.js: यह स्क्रिप्ट बैकएंड कम्युनिकेशन को समन्वित करती है और स्ट्रीमिंग समरी को पॉप-अप तक पहुंचाती है।icon.png: यह Chrome के टूलबार और एक्सटेंशन मैनेजर में दिखने वाला एक्सटेंशन आइकन है।मिलकर, ये फ़ाइलें एक्सटेंशन को इंटरैक्टिव, रिएक्टिव बनाती हैं और इसे स्थानीय मॉडल सर्वर से बात करने में सक्षम बनाती हैं।
स्टेप 1: एक्सटेंशन मेटाडेटा
स्क्रिप्ट
manifest.jsonChrome के लिए मेटाडेटा रखती है। यह एक्सटेंशन का व्यवहार, परमिशन, बैकग्राउंड सर्विस वर्कर और पॉप-अप UI परिभाषित करती है।यह फ़ाइल आपके Chrome एक्सटेंशन की कॉन्फ़िगरेशन और क्षमताएं परिभाषित करती है। यह आवश्यक परमिशन देती है जैसे
scripting(JavaScript इंजेक्ट करने के लिए),activeTab(वर्तमान टैब तक पहुंचने के लिए), औरstorage(यूज़र प्रेफरेंसेज़ सेव करने के लिए)।host_permissionsफ़ील्ड में "<all_urls>" एक्सटेंशन को किसी भी वेबपेज पर चलने देता है। यहpopup.htmlऔरicon.pngके जरिए एक्सटेंशन का UI सेट करता है, और सर्विस वर्कर (background.js) का उपयोग करके बैकग्राउंड व्यवहार रजिस्टर करता है। अंत में, यह एक कंटेंट स्क्रिप्ट (content.js) परिभाषित करता है जो सभी लोडेड पेजों पर चलती है, ताकि जरूरत पड़ने पर वेबपेज सामग्री के साथ इंटरेक्शन हो सके।स्टेप 2: विज़िबल इंटरफ़ेस बनाना
फ़ाइल
popup.htmlएक्सटेंशन का विज़िबल इंटरफ़ेस परिभाषित करती है। यह सक्रिय टैब से जुड़कर विज़िबल टेक्स्ट कैप्चर करती है और इसे आपके बैकएंड सर्वर पर भेजती है।आइए ऊपर के कोड को चरण-बद्ध तरीके से समझें:
<head>टैग में कैरेक्टर एनकोडिंग, व्यूपोर्ट सेटिंग्स और<title>टैग के लिए मेटा टैग शामिल हैं।<body>टैग के अंदर, एक कंटेनर सभी UI एलिमेंट्स को रखता है, जिनमें शामिल हैं:<h2>हेडिंग जो उपयोगकर्ता को वर्तमान पेज का सार निकालने के लिए प्रेरित करती है।Summarizeबटन (“#summarizeBtn”) जिसे क्लिक करने पर कंटेंट एक्सट्रैक्शन और समरीकरण ट्रिगर होता है।<pre>एलिमेंट (“#output”) जो स्ट्रीम होते हुए समरी दिखाने के लिए स्क्रॉल करने योग्य पैनल के रूप में काम करता है।preब्लॉक आउटपुट को स्क्रॉल करने योग्य और अलग दिखाने के लिए उपयोग होता है।popup.jsबटन क्लिक सुनती है, पेज कंटेंट निकालती है, उसे FastAPI बैकएंड पर भेजती है, और स्ट्रीमिंग समरी टेक्स्ट के साथ आउटपुट पैनल अपडेट करती है।स्टेप 3: फ्रंटएंड UI बनाना
फ़ाइल
popup.jsएक फ्रंटएंड लॉजिक कंट्रोलर है जो बटन क्लिक पर प्रतिक्रिया देता है, वर्तमान टैब से टेक्स्ट निकालता है, उसे बैकएंड तक भेजता है, और रियल टाइम में आउटपुट एरिया में समरी स्ट्रीम करता है।यह JavaScript फ़ाइल Chrome एक्सटेंशन के फ्रंटएंड UI लॉजिक को संचालित करती है, जिससे उपयोगकर्ता एक क्लिक में वेबपेज सामग्री निकालकर उसका सार बना सकते हैं।
यह ऐसे काम करती है:
DOMContentLoaded), "Summarize" बटन पर एक इवेंट लिस्नर लगाया जाता है।chrome.tabs.queryके जरिए मौजूदा सक्रिय टैब को क्वेरी करता है।chrome.scripting.executeScriptका उपयोग करके उस टैब के अंदर एक कंटेंट स्क्रिप्ट चलाता है, जो पेज बॉडी केinnerTextको निकालने की कोशिश करती है।http://127.0.0.1:7864/summarize_stream_statusपर लोकल FastAPI बैकएंड को POST रिक्वेस्ट के रूप में भेज दिया जाता है।res.body.getReader()के जरिए स्ट्रीम किया जाता है, जिससे आउटपुट पैनल में समरी के हिस्से रियल टाइम में दिखाई देते रहते हैं।TextDecoderस्ट्रीम किए गए हर हिस्से को डिकोड करता है और उसे लाइव डिस्प्ले में जोड़ता है।स्टेप 4: वेबपेज सामग्री निकालना
बैकएंड तक वेबपेज कंटेंट भेजने से पहले, हमें इसे वर्तमान टैब से निकालने का तरीका चाहिए। स्क्रिप्ट
content.jsबैकग्राउंड या पॉपअप स्क्रिप्ट्स से संदेश सुनती है और वेबपेज से विज़िबल टेक्स्ट कंटेंट लौटाती है।यह स्क्रिप्ट "GET_PAGE_TEXT" प्रकार के संदेशों को सुनती है और प्रतिक्रिया में विज़िबल बॉडी टेक्स्ट (
document.body.innerText) निकालकर वापस भेजती है। इससे बैकग्राउंड वर्कर हर बार कोड इंजेक्ट किए बिना आसानी से वेबपेज सामग्री मांग सकता है—कम्युनिकेशन साफ़ और असिंक्रोनस बना रहता है।स्टेप 5: बैकएंड कोऑर्डिनेशन
बैकग्राउंड स्क्रिप्ट (
background.js) पॉपअप UI और कंटेंट स्क्रिप्ट्स के बीच पुल का काम करती है। यह सुनिश्चित करती है कि संदेश पासिंग और समरीज़ेशन का समन्वय परदे के पीछे सही ढंग से हो।ऊपर का कोड कंटेंट एक्सट्रैक्शन, समरीकरण, और रियल-टाइम अपडेट्स के सुचारू प्रवाह को सुनिश्चित करता है। यह इस तरह काम करता है:
sender.tab.idसे सक्रिय टैब पहचानता है औरchrome.scripting.executeScriptके जरिए वेबपेज से विज़िबल टेक्स्ट निकालने के लिए एक स्क्रिप्ट चलाता है।database_host(आम तौर पर127.0.0.1) निकालता है और निकाली गई सामग्री के साथ FastAPI बैकएंड कोPOSTरिक्वेस्ट भेजता है।ReadableStreamDefaultReaderका उपयोग करके रिस्पॉन्स को टुकड़ों में पढ़ता है।chrome.runtime.sendMessageके जरिए पॉपअप को अंतरिम अपडेट भेजता है।यह बैकग्राउंड स्क्रिप्ट Chrome एक्सटेंशन में रियल-टाइम, स्ट्रीमिंग समरी को सक्षम करने की कुंजी है—बिना UI को ब्लॉक किए या पेज रीलोड किए।
स्टेप 6: एक्सटेंशन आइकन जोड़ना
एक्सटेंशन के लिए कोई आइकन छवि चुनें या बनाएं और इसे एक्सटेंशन फ़ोल्डर में
icon.pngके रूप में सेव करें। हम यह इस्तेमाल करेंगे:FireFly से जेनरेट की गई छवि
आपकी संपूर्ण फ़ोल्डर संरचना इस प्रकार दिखनी चाहिए:
स्टेप 3: ऐप चलाना
सब कुछ लोकली चलाने के लिए, टर्मिनल में यह कमांड चलाएं:
यह Docker के बिना लोकल डेवलपमेंट या डिबगिंग के लिए आदर्श है। Docker में चलाने के लिए, अपने टर्मिनल में ये कमांड एक-एक करके चलाएं:
Chrome एक्सटेंशन पोर्ट 7864 से संचार करता है। अब, Chrome पर अपना एक्सटेंशन चलाने के लिए निम्न चरणों का पालन करें:
आइए नतीजे देखें:
निष्कर्ष
इस प्रोजेक्ट में, हमने Qwen-Agent फ्रेमवर्क और Qwen3:1.7B मॉडल (Ollama के जरिए लोकली चल रहा) का उपयोग करके रियल-टाइम वेबपेज समरीकरण असिस्टेंट बनाया। हमने LLM इन्फ़रेंस संभालने के लिए FastAPI बैकएंड विकसित किया और इसे Chrome एक्सटेंशन के साथ जोड़ा जो विज़िबल पेज कंटेंट कैप्चर करता है और लाइव-स्ट्रीम्ड समरी दिखाता है।
यह डेमो दिखाता है कि Qwen-Agent कैसे ब्राउज़र में पूरी तरह ऑफ़लाइन, टूल-समर्थित तर्क वर्कफ़्लोज़ सक्षम कर सकता है। यह अधिक उन्नत लोकल एजेंट—जैसे ब्राउज़र ऑटोमेशन टूल्स, रिसर्च कोपायलट्स, या डॉक्यूमेंट-आधारित चैटबॉट्स—बनाने की नींव रखता है।
AI एजेंट्स के बारे में और जानने के लिए, ये ब्लॉग देखें: