सामग्री पर जाएँ

AI एक्सटेंशन ​

AI एक्सटेंशन एक टूलबार बटन जोड़ता है जो प्रॉम्प्ट डायलॉग खोलता है, अनुरोध आपके चुने प्रदाता को भेजता है, स्ट्रीम होता परिणाम दिखाता है, और मोड के अनुसार क्रिया बटन (डालें / बदलें / अंत में जोड़ें) से उसे एडिटर में डालता है।

vue
<Tiptapify
  :content="content"
  :items="['ai', '|', 'bold', 'italic']"
  :ai="{
    aiProvider,
    model: 'gpt-4.1-mini',
    stream: true,
  }"
/>

ai prop true (डिफ़ॉल्ट के साथ विकल्प) या एक विकल्प ऑब्जेक्ट (TiptapifyAiOptions) स्वीकार करता है। टूलबार का ai आइटम हमेशा पंजीकृत रहता है, लेकिन aiProvider सेट न हो तो बटन अक्षम रहता है।

चलने वाले डेमो के लिए AI उदाहरण और विकल्पों के पूरे संदर्भ के लिए Props देखें।

आर्किटेक्चर ​

Tiptapify.vue            Toolbar item `ai`           Dialog.vue
  resolves the `ai`     ->  Button.vue               ->  builds the request
  prop into a resolved  ->  (disabled without        ->  calls aiProvider(request, context, stream)
  options object and    ->    aiProvider)           ->  streams chunks into result/reasoning fields
  provides it (inject   ->  opens the dialog        ->  the action button (Insert/Replace/Append) places the result into the editor
  'tiptapifyAi')
  • Tiptapify ai prop को सामान्यीकृत करता है: ai: true खाली विकल्प ऑब्जेक्ट बन जाता है, promptExamples स्थानीयकृत डिफ़ॉल्ट पर लौट आता है, और परिणाम inject('tiptapifyAi') (TiptapifyAiResolvedOptions या false) के ज़रिए वंशज कंपोनेंट को उपलब्ध होता है।
  • टूलबार आइटम (src/components/Toolbar/ai.ts) Button.vue रेंडर करता है। बटन aiProvider की उपलब्धता जाँचता है और Dialog.vue खोलता है।
  • Dialog.vue पूरे अनुरोध जीवनचक्र का मालिक है: अनुरोध बनाना, प्रदाता को कॉल करना, स्ट्रीमिंग और परिणाम डालना।

प्रदाता अनुबंध ​

ts
type TiptapifyAiProvider = (
  request: TiptapifyAiRequest,
  context: TiptapifyAiEditorContext,
  stream?: TiptapifyAiStream,
) => Promise<TiptapifyAiResponse | TiptapifyAiOpenAiResponse | string>

प्रदाता एक साधारण async फ़ंक्शन है जिसे आप लागू करते हैं। tiptapify खुद कोई API कॉल नहीं करता — OpenAI-संगत request ऑब्जेक्ट को संभाल सकने वाली कोई भी चीज़ चलती है (fetch, कोई SDK, बैकएंड एडेप्टर)। अपवाद aiEndpoint बैकएंड मोड है (बैकएंड जनरेशन देखें), जहाँ tiptapify अनुरोध आपके एंडपॉइंट पर भेजता है।

अनुरोध (TiptapifyAiRequest) आपके chatCompletionOptions से फैलाया जाता है, फिर प्लगइन उसमें और जोड़ता है:

फ़ील्डस्रोत
messagesदिया गया हो तो createMessages(context), अन्यथा डिफ़ॉल्ट जोड़ी: एक सिस्टम संदेश (आपका systemPrompt या बिल्ट-इन डिफ़ॉल्ट) और एक उपयोगकर्ता संदेश, जिसमें प्रॉम्प्ट, चुना हुआ एडिटर टेक्स्ट, उसके आसपास का टेक्स्ट और केवल चयन के लिए (या कुछ चुना न होने पर पूरे टेक्स्ट के लिए) उत्तर देने का नियम शामिल होता है
modelmodel विकल्प, सेट होने पर
temperaturetemperature विकल्प, सेट होने पर
streamstream विकल्प, या chatCompletionOptions.stream
enable_thinking / reasoning_effortसोच का टॉगल / प्रयास ड्रॉपडाउन — नीचे देखें

संदर्भ (TiptapifyAiEditorContext) प्रदाता को एडिटर की पूरी स्थिति देता है: prompt, selectedText, textBefore / textAfter (चयन के पैराग्राफ़ का उसके आसपास का टेक्स्ट, हर तरफ़ अधिकतम 500 अक्षर), text, html, json और mode (insert / replace / append)।

जो चयन किसी शब्द के भीतर शुरू या खत्म होता है, वह पूरा शब्द ले लेता है, और डिफ़ॉल्ट संदेश चयन के आसपास का टेक्स्ट केवल चयन के लिए उत्तर देने के नियम के साथ भेजते हैं: केवल एक टुकड़ा देने पर मॉडल उसे पूरा टेक्स्ट समझकर पूरा कर देता है, और बदलाव चयन के बाद वाले हिस्से को दोहरा देता।

उत्तर: प्रदाता कंटेंट को साधारण string के रूप में, { content } (TiptapifyAiResponse) के रूप में, या OpenAI-संगत choices पेलोड (TiptapifyAiOpenAiResponse) के रूप में लौटा सकता है। डायलॉग उसी क्रम में कंटेंट निकालता है और शुरुआती खाली जगह हटा देता है। अस्वीकार होने पर त्रुटि संदेश डायलॉग में दिखता है (या त्रुटि Error इंस्टेंस न हो तो ai.error) और डायलॉग खुला रहता है।

बैकएंड जनरेशन (aiEndpoint) ​

aiProvider लागू करने के बजाय AI सुविधा को किसी बैकएंड LLM एंडपॉइंट की ओर इंगित करें:

ts
// example
const ai = {
  aiEndpoint: '/api/ai/generate',
  model: 'gpt-4.1-mini',
  stream: true,
}

फिर tiptapify अनुरोध खुद बनाकर एंडपॉइंट पर पोस्ट करता है। दोनों सेट होने पर स्पष्ट aiProvider हमेशा प्राथमिकता पाता है।

अनुरोध — एक न्यूनतम JSON पेलोड (TiptapifyAiBackendRequest):

फ़ील्डकब भेजा जाता है
promptहमेशा — डायलॉग में टाइप किया गया अनुरोध
instructionहमेशा — आपका systemPrompt, कस्टम createMessages का सिस्टम संदेश, या बिल्ट-इन डिफ़ॉल्ट
streamकेवल stream: true होने पर
thinkingकेवल डायलॉग का सोच टॉगल चालू होने पर
reasoning_effortकेवल जब उपयोगकर्ता ने कोई स्तर चुना हो (default नहीं)
modelकेवल model विकल्प सेट होने पर

उत्तर — उदारता से स्वीकार किया जाता है: साधारण स्ट्रिंग, { content } ऑब्जेक्ट, या OpenAI-संगत choices पेलोड।

स्ट्रीमिंग — जब अनुरोध में stream: true हो, तो उत्तर की बॉडी SSE स्ट्रीम के रूप में पढ़ी जाती है (data: पंक्तियाँ, जो data: [DONE] से समाप्त होती हैं)। स्वीकृत चंक प्रारूप:

  • OpenAI-शैली — data: {"choices":[{"delta":{"content":"…", "reasoning_content":"…"}}]}
  • सरल — data: {"type":"content"|"reasoning","data":"…"}
  • सपाट — data: {"content":"…","reasoning_content":"…"}
  • सादा टेक्स्ट — data: some text (गैर-JSON data पंक्ति कंटेंट चंक है)

content चंक onChunk के ज़रिए परिणाम फ़ील्ड अपडेट करते हैं, reasoning_content चंक onReasoning के ज़रिए सोच पैनल को भरते हैं। अगर बैकएंड stream को अनदेखा करके साधारण बॉडी के साथ उत्तर देता है, तो वही बॉडी उपयोग होती है। रोकें पर क्लिक या डायलॉग बंद करने से अनुरोध रुक जाता है; आंशिक रूप से स्ट्रीम हुआ कंटेंट परिणाम फ़ील्ड में रखा जाता है।

हेडर — aiHeaders (एक Record<string, string>) Content-Type: application/json के ऊपर मिलाए जाते हैं। aiHeaders में Authorization हेडर जैसा है वैसा रखा जाता है; अन्यथा tokenProvider का टोकन Authorization: Bearer <token> के रूप में भेजा जाता है।

त्रुटियाँ — गैर-OK उत्तर बैकएंड का त्रुटि संदेश (JSON { error } / { message } या कच्ची बॉडी) डायलॉग में दिखाता है।

स्ट्रीमिंग ​

जब stream: true हो (या chatCompletionOptions.stream true हो), डायलॉग तीसरे आर्गुमेंट के रूप में एक TiptapifyAiStream ऑब्जेक्ट देता है:

ts
type TiptapifyAiStream = {
  signal: AbortSignal,
  onChunk: (chunk: string) => void,
  onReasoning: (chunk: string) => void,
}
  • signal — इसे fetch (या अपनी SDK कॉल) को दें। उपयोगकर्ता के रोकें पर क्लिक करने या डायलॉग बंद करने पर यह रुक जाता है, ताकि चल रहे अनुरोध चलते न रहें।
  • onChunk — हर कंटेंट चंक को परिणाम फ़ील्ड में जोड़ें। जनरेट करते समय परिणाम फ़ील्ड केवल-पढ़ने वाला रहता है और आंशिक रूप से स्ट्रीम हुआ कंटेंट रखा जाता है (आप रोक सकते हैं, फिर उसे डाल सकते हैं या छोड़ सकते हैं)।
  • onReasoning — मॉडल का तर्क/सोच आउटपुट (जैसे Qwen/DeepSeek/o-series का reasoning_content डेल्टा) परिणाम के ऊपर समेटे जा सकने वाले सोच पैनल को भेजें। स्ट्रीमिंग के दौरान पैनल अपने-आप खुलता और स्क्रॉल होता है। तर्क आउटपुट केवल दिखाने के लिए है और एडिटर में कभी नहीं डाला जाता।

जो प्रदाता स्ट्रीम नहीं करते वे stream आर्गुमेंट को अनदेखा करते हैं — यह वैकल्पिक है।

सोच और तर्क प्रयास ​

डायलॉग के दो उपयोगकर्ता नियंत्रण अनुरोध के फ़ील्ड से जुड़ते हैं। दोनों विकल्पों के ज़रिए वैकल्पिक हैं और प्लगइन के अधीन हैं — इन फ़ील्ड को आप chatCompletionOptions में खुद सेट नहीं करते (और नहीं करना चाहिए)।

  • thinking: true सोच टॉगल दिखाता है (डिफ़ॉल्ट रूप से चालू, हर डायलॉग खुलने पर रीसेट)। प्लगइन टॉगल का मान अनुरोध में enable_thinking: true | false के रूप में लिखता है।
  • thinking गायब हो या thinking: false टॉगल छिपा देता है और प्लगइन enable_thinking: false भेजता है, ताकि जो मॉडल डिफ़ॉल्ट रूप से सोचते हैं वे न सोचें।
  • reasoningEffort: { options, default? } तर्क प्रयास ड्रॉपडाउन दिखाता है। options वे कस्टम प्रयास स्तर सूचीबद्ध करता है जो आप देना चाहते हैं ('low' | 'medium' | 'high' | 'xhigh' | 'max'); एक्सटेंशन खुद हमेशा एक default आइटम जोड़ता है (सोच-मोड का आधार), इसलिए आप अपने कॉन्फ़िग में default कभी सूचीबद्ध नहीं करते। default फ़ील्ड डायलॉग खुलते समय आपके कस्टम स्तरों में से एक को पहले से चुनता है — छोड़ने पर default पहले से चुना रहता है। मान हर बार खुलने पर रीसेट होता है। ड्रॉपडाउन तभी रेंडर होता है जब options गैर-खाली सूची हो, thinking सक्षम हो और सोच टॉगल चालू हो।
  • showReasoning (डिफ़ॉल्ट false) समेटे जा सकने वाले सोच पैनल को नियंत्रित करता है, जो मॉडल की तर्क प्रक्रिया (reasoning_content डेल्टा) स्ट्रीम करता है। सोच चालू रखते हुए वह पैनल दिखाने के लिए showReasoning: true सेट करें — मॉडल फिर भी तर्क करता है, परिणाम उसी तरह लागू होता है, केवल चरण-दर-चरण तर्क अतिरिक्त रूप से दिखाया जाता है।

क्योंकि प्रदाता (खास तौर पर vLLM/LM Studio) एक ही अनुरोध में enable_thinking और reasoning_effort को अस्वीकार करते हैं, प्लगइन दोनों में से ठीक एक भेजता है:

स्थितिअनुरोध फ़ील्ड
सोच चालू, प्रयास = default (या कोई प्रयास कॉन्फ़िगर नहीं)enable_thinking (टॉगल से)
सोच चालू, प्रयास = low / medium / high / xhigh / maxreasoning_effort (ड्रॉपडाउन से); टॉगल अक्षम रहता है
सोच बंद (टॉगल बंद, या कॉन्फ़िग में thinking सक्षम नहीं)enable_thinking: false; reasoning_effort नहीं भेजा जाता

त्रुटियाँ ​

डायलॉग विफल अनुरोध को कच्ची त्रुटि दिखाने के बजाय समझाता है, और उसके बाद सेवा का अपना संदेश जोड़ता है:

क्या हुआस्पष्टीकरण
ब्राउज़र को कोई उत्तर नहीं मिला (Failed to fetch, NetworkError…, Load failed)सेवा बंद है, पहुँच से बाहर है, या CORS ने उत्तर रोक दिया; ब्राउज़र कंसोल बताता है कि कौन सा
401 / 403API कुंजी या पहुँच अधिकार जाँचें
404एंडपॉइंट का पथ जाँचें
408 / 504 / टाइमआउटसेवा ने समय पर उत्तर नहीं दिया
429बहुत अधिक अनुरोध
5xxसेवा उपलब्ध नहीं है (मॉडल लोड हो रहा है, व्यस्त है)

aiEndpoint के साथ स्थिति उत्तर से आती है। कस्टम aiProvider को वही स्पष्टीकरण status वाली त्रुटि फेंककर मिलते हैं:

ts
if (!response.ok) {
  const body = await response.json().catch(() => null)
  throw Object.assign(new Error(body?.error?.message ?? ''), { status: response.status })
}

कोई भी अन्य त्रुटि अपने संदेश के साथ दिखाई जाती है।

परिणाम डालना ​

क्रिया बटन पर — डालें, बदलें या अंत में जोड़ें, मोड के अनुसार — डायलॉग result को एडिटर में रखता है:

  • मोड — डायलॉग का क्रिया बटन स्प्लिट बटन है। मुख्य भाग परिणाम को पहले से चुने मोड (डालें / बदलें / अंत में जोड़ें) में लागू करता है: mode विकल्प उसे पहले से चुनता है, या डायलॉग खुलते समय टेक्स्ट चुना हुआ हो तो बदलें और अन्यथा डालें। बटन के दाईं ओर छोटा "और" (⋮) भाग बाकी मोड वाला मेन्यू खोलता है — उनमें से किसी पर क्लिक करने से परिणाम तुरंत उसी मोड में लागू हो जाता है। डालें परिणाम को कर्सर पर रखता है, बदलें चुने हुए टेक्स्ट (जो उत्पादित करें पर क्लिक के समय पकड़ा गया) को बदलता है, और अंत में जोड़ें उसे दस्तावेज़ के अंत में जोड़ता है।
  • अक्षर सीमा — जब एडिटर limit के साथ कॉन्फ़िगर हो (CharacterCount एक्सटेंशन हर उस गैर-पेस्ट ट्रांज़ैक्शन को अस्वीकार करता है जो दस्तावेज़ को सीमा से बड़ा करे), तो परिणाम फ़ील्ड के नीचे generated / limit अक्षर काउंटर दिखता है (स्ट्रीमिंग के दौरान लाइव, सीमा पार होने पर हल्का लाल) और परिणाम सीमा से बड़ा होने पर जनरेशन के तुरंत बाद डायलॉग ai.limit_exceeded चेतावनी दिखाता है। तब डालें बटन और उसका वैकल्पिक-मोड मेन्यू अक्षम हो जाते हैं: परिणाम पूरा-या-कुछ नहीं की तरह लागू होता है, इसलिए लागू करने से पहले उसे छोटा करना होगा।

MIT लाइसेंस के तहत जारी।