मुख्य सामग्री पर जाएं

Qwen-Agent: डेमो प्रोजेक्ट के साथ एक गाइड

सीखें कि Qwen-Agent और Qwen3 का उपयोग करके रियल-टाइम वेबपेज समरीज़र एक्सटेंशन कैसे बनाएं।
अपडेट किया गया 2 अक्टू॰ 2026  · 12 मि॰ पढ़ें

AI के साथ खोजें

ChatGPTClaudePerplexity

इस ब्लॉग पोस्ट में, मैं आपको एक ब्राउज़र एक्सटेंशन बनाना सिखाऊंगा जो 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 ऐप बनाना आसान बनाता है:

  • FastAPI के जरिए तेज़ इंटीग्रेशन
  • फ्रंटएंड UI के लिए बिल्ट-इन स्ट्रीमिंग
  • कस्टमाइज़ेबल फ़ंक्शन टूलचेन
  • पूर्ण ऑफ़लाइन गोपनीयता और प्रदर्शन

प्रोजेक्ट ओवरव्यू: रियल-टाइम वेब समरीज़र एक्सटेंशन

इस सेक्शन में, हम 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: प्लॉटिंग या विज़ुअल आउटपुट दिखाने के लिए उपयोग होती है (वैकल्पिक) 

यदि आप यह प्रोजेक्ट लोकली चलाना चाहते हैं, तो सभी डिपेंडेंसीज़ इंस्टॉल करने के लिए यह कमांड चलाएं:

pip install -r requirements.txt

स्टेप 1.2: DockerFile सेटअप (वैकल्पिक)

अब, एक 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 सर्विस होस्ट करके ऑफ़लाइन इन्फ़रेंस सक्षम करता है।

ollama pull qwen3:1.7b
ollama serve 

स्टेप 1.4: FastAPI समरीज़ेशन सर्वर बनाना

फ़ाइल 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()
class RequestData(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")
async def summarize_stream_status(data: RequestData):
    user_input = data.content
    def stream():
        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 = None
            for item in reversed(result_list):
                if isinstance(item, list):
                    for subitem in reversed(item):
                        if isinstance(subitem, dict) and "content" in subitem:
                            last_content = subitem["content"]
                            break
                if last_content:
                    break
            if not 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)
            yield f"\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 एक्सटेंशन का विज़िबल इंटरफ़ेस परिभाषित करती है। यह सक्रिय टैब से जुड़कर विज़िबल टेक्स्ट कैप्चर करती है और इसे आपके बैकएंड सर्वर पर भेजती है। 

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Summarizer Assistant</title>
  <style>
    body {
      width: 500px;
      height: 600px;
      background-color: aliceblue;
      
      
      
    }
    .container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 15px;
    }
    button {
      border: none;
      border-radius: 5px;
      background-
      color: white;
      
      
      cursor: pointer;
    }
    button:hover {
      background-
    }
    pre {
      background-
      border: 1px solid #ccc;
      border-radius: 5px;
      
      width: 90%;
      height: 350px;
      overflow: auto;
    }
    input[type="text"] {
      
      width: 90%;
      border-radius: 5px;
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>Summarize Current Page</h2>
    <button id="summarizeBtn">Summarize</button>
    <pre id="output">Summary will appear here...</pre>
  </div>
  <script src="popup.js"></script>
</body>
</html>

आइए ऊपर के कोड को चरण-बद्ध तरीके से समझें:

  1. पहले, हम एक बेसिक HTML संरचना सेट करते हैं, जिसमें <head> टैग में कैरेक्टर एनकोडिंग, व्यूपोर्ट सेटिंग्स और <title> टैग के लिए मेटा टैग शामिल हैं।
  2. फिर, <body> टैग के अंदर, एक कंटेनर सभी UI एलिमेंट्स को रखता है, जिनमें शामिल हैं:
  • एक <h2> हेडिंग जो उपयोगकर्ता को वर्तमान पेज का सार निकालने के लिए प्रेरित करती है।
  • एक Summarize बटन (“#summarizeBtn”) जिसे क्लिक करने पर कंटेंट एक्सट्रैक्शन और समरीकरण ट्रिगर होता है।
  • एक <pre> एलिमेंट (“#output”) जो स्ट्रीम होते हुए समरी दिखाने के लिए स्क्रॉल करने योग्य पैनल के रूप में काम करता है।
  1. एम्बेडेड CSS के जरिए स्टाइलिंग परिभाषित है ताकि पॉपअप साफ़-सुथरा और पठनीय दिखे। pre ब्लॉक आउटपुट को स्क्रॉल करने योग्य और अलग दिखाने के लिए उपयोग होता है।
  2. स्क्रिप्ट 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 = await fetch(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 = new TextDecoder();
            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 और कंटेंट स्क्रिप्ट्स के बीच पुल का काम करती है। यह सुनिश्चित करती है कि संदेश पासिंग और समरीज़ेशन का समन्वय परदे के पीछे सही ढंग से हो।

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
    if (request.type === "SUMMARIZE_PAGE") {
      const tabId = sender.tab.id;
        chrome.scripting.executeScript(
        {
          target: { tabId },
          func: () => {
            try {
              return document.body?.innerText || 'EMPTY';
            } catch (e) {
              return 'SCRIPT_ERROR';
            }
          }
        },
        async (results) => {
          const pageText = results?.[0]?.result || '';
          if (!pageText || pageText === 'SCRIPT_ERROR') {
            chrome.runtime.sendMessage({
              type: 'SUMMARY_RESULT',
              summary: ' Failed to read page text.',
            });
            return;
          }
          chrome.storage.local.get(['database_host'], async function (result) {
            const host = result.database_host || '127.0.0.1';
            try {
              const response = await fetch(http://${host}:7864/summarize_stream_status, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ content: pageText }),
              });
              const reader = response.body.getReader();
              const decoder = new TextDecoder();
              let fullSummary = '';
              while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                const chunk = decoder.decode(value, { stream: true });
                fullSummary += chunk;
                chrome.runtime.sendMessage({
                  type: 'SUMMARY_PROGRESS',
                  chunk
                });
              }
              chrome.runtime.sendMessage({
                type: 'SUMMARY_DONE',
                summary: fullSummary
              });
            } catch (err) {
              chrome.runtime.sendMessage({
                type: 'SUMMARY_RESULT',
                summary: ' Error during summarization: ' + err.message
              });
            }
          });
        }
      );
      return true; 
    }
  });
  

ऊपर का कोड कंटेंट एक्सट्रैक्शन, समरीकरण, और रियल-टाइम अपडेट्स के सुचारू प्रवाह को सुनिश्चित करता है। यह इस तरह काम करता है:

  • यह पॉपअप में बटन क्लिक से ट्रिगर हुए "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 के रूप में सेव करें। हम यह इस्तेमाल करेंगे:

Extension Icon

FireFly से जेनरेट की गई छवि

आपकी संपूर्ण फ़ोल्डर संरचना इस प्रकार दिखनी चाहिए:

QWEN-WEB-SUMMARIZER/
├── backend/
│   ├── app.py
│   ├── Dockerfile
│   └── requirements.txt
├── extension/
│   ├── background.js
│   ├── content.js
│   ├── icon.png
│   ├── manifest.json
│   ├── popup.html
│   └── popup.js

स्टेप 3: ऐप चलाना

सब कुछ लोकली चलाने के लिए, टर्मिनल में यह कमांड चलाएं:

uvicorn backend.app:app --host 0.0.0.0 --port 7864

यह Docker के बिना लोकल डेवलपमेंट या डिबगिंग के लिए आदर्श है। Docker में चलाने के लिए, अपने टर्मिनल में ये कमांड एक-एक करके चलाएं:

docker build -t qwen-agent-backend .
docker run -p 7864:7864 qwen-agent-backend

Chrome एक्सटेंशन पोर्ट 7864 से संचार करता है। अब, Chrome पर अपना एक्सटेंशन चलाने के लिए निम्न चरणों का पालन करें:

  • Chrome खोलें और “Extensions” पर क्लिक करें (सर्च बार के दाईं ओर)।
  • “Developer mode” ऑन करें और “Load unpacked” (ऊपर बाएँ) पर क्लिक करें। 

Chrome Extension tab for activating an extension powered by Qwen-Agent

  • इसके बाद, सभी फ़ाइलों वाला हमारा एक्सटेंशन फ़ोल्डर लोड करें और कन्फर्मेशन का इंतज़ार करें।
  • जब पॉप-अप एक्सटेंशन सेटअप कन्फर्म कर दे, तो किसी भी वेबपेज पर एक्सटेंशन आइकन क्लिक करें और अपने लोकल Qwen3 मॉडल का उपयोग करते हुए स्ट्रीमिंग समरी प्राप्त करें।

आइए नतीजे देखें:

Qwen-Agent Extension example

निष्कर्ष

इस प्रोजेक्ट में, हमने Qwen-Agent फ्रेमवर्क और Qwen3:1.7B मॉडल (Ollama के जरिए लोकली चल रहा) का उपयोग करके रियल-टाइम वेबपेज समरीकरण असिस्टेंट बनाया। हमने LLM इन्फ़रेंस संभालने के लिए FastAPI बैकएंड विकसित किया और इसे Chrome एक्सटेंशन के साथ जोड़ा जो विज़िबल पेज कंटेंट कैप्चर करता है और लाइव-स्ट्रीम्ड समरी दिखाता है।

यह डेमो दिखाता है कि Qwen-Agent कैसे ब्राउज़र में पूरी तरह ऑफ़लाइन, टूल-समर्थित तर्क वर्कफ़्लोज़ सक्षम कर सकता है। यह अधिक उन्नत लोकल एजेंट—जैसे ब्राउज़र ऑटोमेशन टूल्स, रिसर्च कोपायलट्स, या डॉक्यूमेंट-आधारित चैटबॉट्स—बनाने की नींव रखता है।

AI एजेंट्स के बारे में और जानने के लिए, ये ब्लॉग देखें:


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

मैं एमएल (Gen AI) में Google Developers Expert, Kaggle 3x Expert, और Women Techmakers एंबेसडर हूँ, तथा तकनीक क्षेत्र में 3+ वर्षों का अनुभव रखती हूँ। मैंने 2020 में एक हेल्थ-टेक स्टार्टअप की सह-स्थापना की और वर्तमान में Georgia Tech से कंप्यूटर विज्ञान में मास्टर कर रही हूँ, जिसमें मेरा विशेषज्ञता क्षेत्र मशीन लर्निंग है।

विषय
एआई एजेंट्स
कृत्रिम बुद्धिमत्ता

इन कोर्सेस के साथ AI सीखें!

कोर्स

AI Agents परिचय

1 घंटा 30 मिनट
145.4K
AI एजेंटों की मूल बातें, उनके घटक और वास्तविक उपयोग सीखें—कोडिंग की जरूरत नहीं।
विवरण देखेंRight Arrow
पाठ्यक्रम शुरू करें

लर्निंग पाथ

एआई मूलभूत बातें

10 घंटा
AI की मूल बातें जानें, काम के लिए AI का प्रभावी उपयोग करना सीखें, और ChatGPT जैसे मॉडल्स में गहराई से उतरकर गतिशील AI परिदृश्य को समझें।
और देखेंRight Arrow