paint-brush
কীভাবে আপনার নিজের যেকোন জিপিটি তৈরি করবেন - একটি বট যা আপনি যেভাবে চান সেভাবে উত্তর দেয়দ্বারা@balakhonoff
1,545 পড়া
1,545 পড়া

কীভাবে আপনার নিজের যেকোন জিপিটি তৈরি করবেন - একটি বট যা আপনি যেভাবে চান সেভাবে উত্তর দেয়

দ্বারা Kirill Balakhonov24m2023/07/25
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

আমরা ChatGPT-এর একটি কাস্টমাইজড সংস্করণ তৈরি করার বিষয়ে কথা বলব যা একটি বড় জ্ঞানের ভিত্তি বিবেচনা করে প্রশ্নের উত্তর দেয়। আমরা OpenAI থেকে প্রাসঙ্গিক এম্বেডিং ব্যবহার করব (জ্ঞানের ভিত্তি থেকে প্রাসঙ্গিক প্রশ্নগুলির সত্যিকারের উচ্চ-মানের অনুসন্ধানের জন্য)। আমরা স্বাভাবিক মানুষের ভাষায় উত্তর বিন্যাস করব.
featured image - কীভাবে আপনার নিজের যেকোন জিপিটি তৈরি করবেন - একটি বট যা আপনি যেভাবে চান সেভাবে উত্তর দেয়
Kirill Balakhonov HackerNoon profile picture
0-item
1-item
2-item


সবাইকে অভিবাদন! সম্প্রতি, আমি আমার অনুশীলনের সময় একটি আকর্ষণীয় সমাধান প্রয়োগ করেছি যা আমি দীর্ঘ সময়ের জন্য চেষ্টা করতে চেয়েছিলাম, এবং এখন আমি ব্যাখ্যা করতে প্রস্তুত যে আপনি কীভাবে অন্য কোনও কাজের জন্য অনুরূপ কিছু তৈরি করতে পারেন। আমরা ChatGPT-এর একটি কাস্টমাইজড সংস্করণ তৈরি করার বিষয়ে কথা বলব যা প্রশ্নের উত্তর দেয়, একটি বৃহৎ জ্ঞানের ভিত্তিকে বিবেচনায় নিয়ে যা প্রম্পটের আকার দ্বারা সীমাবদ্ধ নয় (অর্থাৎ আপনি প্রতিটির আগে সমস্ত তথ্য যোগ করতে পারবেন না। ChatGPT কে প্রশ্ন করুন)।


এটি অর্জনের জন্য, আমরা OpenAI থেকে প্রাসঙ্গিক এম্বেডিং ব্যবহার করব (জ্ঞানের ভিত্তি থেকে প্রাসঙ্গিক প্রশ্নগুলির সত্যিকারের উচ্চ-মানের অনুসন্ধানের জন্য) এবং ChatGPT API নিজেই (প্রাকৃতিক মানব ভাষায় উত্তরগুলি ফর্ম্যাট করতে)।


উপরন্তু, এটা অনুমান করা হয় যে সহকারী শুধুমাত্র স্পষ্টভাবে বলা প্রশ্নোত্তর প্রশ্নের উত্তর দিতে পারে না , বরং প্রশ্নোত্তরগুলির সাথে পরিচিত একজন ব্যক্তি উত্তর দিতে পারে। আপনি যদি একটি বৃহৎ জ্ঞানের ভিত্তি ব্যবহার করে সাড়া দেয় এমন সহজ বটগুলি কীভাবে তৈরি করতে হয় তা শিখতে আগ্রহী হলে, বিশদ বিবরণে স্বাগতম।


আমি উল্লেখ করতে চাই যে কিছু লাইব্রেরি প্রকল্প রয়েছে যা একটি কাঠামোর আকারে এই কাজটি সমাধান করার চেষ্টা করে, উদাহরণস্বরূপ, LangChain , এবং আমি এটি ব্যবহার করার চেষ্টাও করেছি। যাইহোক, যে কোনও কাঠামোর মতো যা বিকাশের প্রাথমিক পর্যায়ে রয়েছে, কিছু ক্ষেত্রে, এটি জিনিসগুলিকে সহজ করার পরিবর্তে সীমাবদ্ধ করার প্রবণতা রাখে। বিশেষ করে, এই টাস্কটি সমাধান করার প্রথম থেকেই, আমি বুঝতে পেরেছিলাম যে আমি ডেটা দিয়ে কী করতে চাই এবং কীভাবে এটি নিজে করতে হবে তা জানতাম (প্রসঙ্গ-ভিত্তিক অনুসন্ধান সহ, প্রম্পটে সঠিক প্রসঙ্গ সেট করা, তথ্যের উত্সগুলি একত্রিত করা)।


কিন্তু আমি একটি গ্রহণযোগ্য স্তরের গুণমানের সাথে ঠিক এটি করার জন্য ফ্রেমওয়ার্কটি কনফিগার করতে পারিনি এবং ফ্রেমওয়ার্কটি ডিবাগ করা এই কাজের জন্য ওভারকিলের মতো মনে হয়েছিল। শেষ পর্যন্ত, আমি আমার নিজস্ব বয়লারপ্লেট কোড তৈরি করেছি এবং এই পদ্ধতির সাথে সন্তুষ্ট ছিলাম।

টাস্ক

আমি যে টাস্কে কাজ করছিলাম তা আমাকে সংক্ষিপ্তভাবে বর্ণনা করতে দিন, এবং আপনি আপনার নিজের কাজে একই কোড ব্যবহার করতে পারেন, ডেটা সোর্স এবং প্রম্পটগুলিকে আপনার জন্য উপযুক্ত করে প্রতিস্থাপন করতে পারেন। আপনার এখনও বটের যুক্তির উপর সম্পূর্ণ নিয়ন্ত্রণ থাকবে।


কোড লেখার সময়, আমি প্রায়ই ChatGPT ব্যবহার করি (এবং আমি এতে লজ্জিত নই🙂)। যাইহোক, 2022+ বছরের জন্য ডেটার অভাবের কারণে, কখনও কখনও তুলনামূলকভাবে নতুন প্রযুক্তির সাথে সমস্যা হয়।


বিশেষ করে, গ্রাফ প্রোটোকলের জন্য সাবগ্রাফ তৈরি করার সময় (ইভিএম-সামঞ্জস্যপূর্ণ ব্লকচেইনগুলি থেকে সূচীকৃত ডেটা পুনরুদ্ধার করার জন্য ETL তৈরির সবচেয়ে জনপ্রিয় উপায়, আপনি আমার আগের নিবন্ধগুলি [ 1 ] এবং [ 2 ] তে এটি সম্পর্কে আরও পড়তে পারেন), লাইব্রেরিগুলি নিজেই বেশ কিছু ব্রেকিং সামঞ্জস্য পরিবর্তন হয়েছে। চ্যাটজিপিটি থেকে "পুরানো" উত্তরগুলি আর সহায়ক নয়, এবং আমাকে সঠিক উত্তরগুলি অনুসন্ধান করতে হবে হয় দুষ্প্রাপ্য ডকুমেন্টেশনে বা, সবচেয়ে খারাপ ক্ষেত্রে, বিকাশকারীদের ডিসকর্ডে, যা খুব সুবিধাজনক নয় (এটি স্ট্যাকওভারফ্লো-এর মতো নয়)।


সমস্যার দ্বিতীয় অংশটি হল যে প্রতিবার আপনাকে কথোপকথনের প্রসঙ্গটি সঠিকভাবে প্রদান করতে হবে কারণ ChatGPT প্রায়শই সাবগ্রাফের বিষয় থেকে দূরে সরে যায়, গ্রাফকিউএল, এসকিউএল বা উচ্চতর গণিত (“দ্য গ্রাফ”, “সাবগ্রাফ” ইত্যাদিতে ঝাঁপিয়ে পড়ে। অনন্য পদ নয় এবং অনেকগুলি ভিন্ন ব্যাখ্যা এবং বিষয় রয়েছে)।


তাই, সাবগ্রাফ কোডে ত্রুটিগুলি সংশোধন করার জন্য ChatGPT-এর সাথে অল্প সময়ের জন্য লড়াই করার পরে, আমি আমার নিজস্ব SubgraphGPT বট তৈরি করার সিদ্ধান্ত নিয়েছি, যা সর্বদা সঠিক প্রেক্ষাপটে থাকবে এবং বিকাশকারীদের বিরোধের জ্ঞানের ভিত্তি এবং বার্তাগুলিকে বিবেচনায় নিয়ে উত্তর দেওয়ার চেষ্টা করবে। .


পুনশ্চ. আমি একটি ওয়েব3 পরিকাঠামো প্রদানকারী chainstack.com- এ প্রধান পণ্য ব্যবস্থাপক হিসেবে কাজ করি এবং সাবগ্রাফ হোস্টিং পরিষেবার উন্নয়নের জন্য আমি দায়ী৷ তাই আমাকে সাবগ্রাফের সাথে অনেক বেশি কাজ করতে হবে, ব্যবহারকারীদের এই তুলনামূলকভাবে নতুন প্রযুক্তি বুঝতে সাহায্য করে।

শীর্ষ স্তরের সমাধান

শেষ পর্যন্ত, এই সমস্যাটি সমাধান করার জন্য, আমি দুটি উত্স ব্যবহার করার সিদ্ধান্ত নিয়েছি:

  1. প্রশ্ন এবং উত্তরগুলির একটি ম্যানুয়ালি সংকলিত জ্ঞানের ভিত্তি, আধা-অন্ধ মোডে নির্বাচিত (প্রায়শই আমি প্রশ্ন হিসাবে ডকুমেন্টেশন থেকে বিষয়ের শিরোনাম এবং উত্তর হিসাবে তথ্যের সম্পূর্ণ অনুচ্ছেদটি নিয়েছি)।

  2. গত 2 বছর থেকে প্রোটোকল ডেভেলপার ডিসকর্ড থেকে রপ্তানি করা বার্তাগুলি (2021 সালের শেষ থেকে হারিয়ে যাওয়া সময়কে কভার করতে)।


এরপরে, ChatGPT API-তে একটি অনুরোধ রচনা করার জন্য প্রতিটি উত্সের জন্য বিভিন্ন পদ্ধতি ব্যবহার করা হয়েছিল, বিশেষত:


ম্যানুয়ালি কম্পাইল করা প্রশ্নোত্তরের জন্য,

  1. প্রতিটি প্রশ্নের জন্য, একটি প্রাসঙ্গিক এম্বেডিং তৈরি করা হয় (একটি ভেক্টর এই প্রশ্নটিকে একটি বহুমাত্রিক অবস্থায় বর্ণনা করে), পাঠ্য-এমবেডিং-এডা-002 মডেলের মাধ্যমে প্রাপ্ত,

  2. তারপর, একটি কোসাইন দূরত্ব অনুসন্ধান ফাংশন ব্যবহার করে, জ্ঞানের ভিত্তি থেকে শীর্ষ 3টি সর্বাধিক অনুরূপ প্রশ্ন পাওয়া যায় (3টির পরিবর্তে, আপনার ডেটাসেটের জন্য সবচেয়ে উপযুক্ত নম্বর ব্যবহার করা যেতে পারে),

  3. এই 3টি প্রশ্নের উত্তর চূড়ান্ত প্রম্পটে " এই প্রশ্নোত্তর স্নিপেটটি শুধুমাত্র প্রদত্ত প্রশ্নের সাথে প্রাসঙ্গিক হলেই ব্যবহার করুন " এর আনুমানিক বর্ণনা সহ যোগ করা হয়েছে৷


    ডিসকর্ড থেকে রপ্তানি করা বার্তাগুলির জন্য, নিম্নলিখিত অ্যালগরিদম ব্যবহার করা হয়েছিল:

  4. একটি প্রশ্ন চিহ্ন ধারণকারী প্রতিটি বার্তার জন্য, একটি প্রাসঙ্গিক এম্বেডিংও তৈরি করা হয় (একই মডেল ব্যবহার করে),

  5. তারপর, একইভাবে, শীর্ষ 5টি সর্বাধিক অনুরূপ প্রশ্ন নির্বাচন করা হয়,

  6. এবং উত্তরের প্রেক্ষাপট হিসাবে, সেই প্রশ্নের পরবর্তী 20টি বার্তা যোগ করা হয়েছে, যেগুলিতে প্রশ্নের উত্তর ধারণ করার একটি নির্দিষ্ট সম্ভাবনা রয়েছে বলে ধরে নেওয়া হয়,

  7. এবং এই তথ্যটি চূড়ান্ত প্রম্পটে প্রায় এইভাবে যুক্ত করা হয়েছে: " আপনি যদি সংযুক্ত প্রশ্নোত্তর স্নিপেটে প্রশ্নের একটি স্পষ্ট উত্তর খুঁজে না পান, তাহলে মূল প্রশ্নের উত্তর দেওয়ার জন্য বিকাশকারীর নিম্নলিখিত চ্যাট অংশগুলি আপনার জন্য উপযোগী হতে পারে .. "


তদ্ব্যতীত, যদি বিষয়টি স্পষ্টভাবে দেওয়া না হয়, প্রশ্নোত্তর স্নিপেট এবং চ্যাটের উপস্থিতি উত্তরগুলিতে অস্পষ্টতার দিকে নিয়ে যেতে পারে, যা দেখতে পারে, উদাহরণস্বরূপ, নিম্নরূপ:



সুতরাং, এটি বোঝা যায় যে প্রশ্নটি প্রসঙ্গ থেকে বিচ্ছিন্ন ছিল এবং উত্তরটিও প্রসঙ্গ থেকে বিচ্ছিন্ন হয়ে গৃহীত হয়েছিল। তারপরে বলা হয়েছিল যে এই জাতীয় ডেটা ব্যবহার করা যেতে পারে এবং এটি নিম্নলিখিত হিসাবে সংক্ষিপ্ত করে:

  1. আসলে উত্তরটা এরকম হতে পারে...
  2. এবং যদি আমরা প্রেক্ষাপট বিবেচনা করি, তাহলে এটি এরকম হবে ...


এটি এড়াতে, আমরা একটি বিষয়ের ধারণাটি প্রবর্তন করি, যা স্পষ্টভাবে সংজ্ঞায়িত করা হয়েছে এবং প্রম্পটের শুরুতে সন্নিবেশ করা হয়েছে:

"আমাকে 'দ্য গ্রাফ সাবগ্রাফ ডেভেলপমেন্ট' বিষয়ের সাথে সম্পর্কিত একটি প্রশ্নের উত্তর পেতে হবে: {{{একটি সাবগ্রাফ কী?}}}"


উপরন্তু, শেষ বাক্যে, আমি এটিও যোগ করি:

সবশেষে, উপরের তথ্যগুলো পর্যাপ্ত না হলে, আপনি প্রশ্নটির উত্তর দিতে 'দ্য গ্রাফ সাবগ্রাফ ডেভেলপমেন্ট' বিষয়ে আপনার জ্ঞান ব্যবহার করতে পারেন।


শেষ পর্যন্ত, সম্পূর্ণ প্রম্পট (চ্যাট থেকে প্রাপ্ত অংশ বাদ দিয়ে) নিম্নরূপ দেখায়:

 ==I need to get an answer to the question related to the topic of "The Graph subgraph development": {{{what is a subgraph?}}}.== ==Possibly, you might find an answer in these Q&As \[use the information only if it is actually relevant and useful for the question answering\]:== ==Q: <What is a subgraph?>== ==A: <A subgraph is a custom API built on blockchain data. Subgraphs are queried using the GraphQL query language and are deployed to a Graph Node using the Graph CLI. Once deployed and published to The Graph's decentralized network, Indexers process subgraphs and make them available to be queried by subgraph consumers.>== ==Q: <Am I still able to create a subgraph if my smart contracts don't have events?>== ==A: <It is highly recommended that you structure your smart contracts to have events associated with data you are interested in querying. Event handlers in the subgraph are triggered by contract events and are by far the fastest way to retrieve useful data. If the contracts you are working with do not contain events, your subgraph can use call and block handlers to trigger indexing. Although this is not recommended, as performance will be significantly slower.>== ==Q: <How do I call a contract function or access a public state variable from my subgraph mappings?>== ==A: <Take a look at Access to smart contract state inside the section AssemblyScript API. https://thegraph.com/docs/en/developing/assemblyscript-api/>== ==Finally, only if the information above was not enough you can use your knowledge in the topic of "The Graph subgraph development" to answer the question.==


ইনপুটে এই সেমি-অটো-জেনারেটেড প্রম্পটের সাথে উপরের অনুরোধের প্রতিক্রিয়া শুরু থেকেই সঠিক দেখায়:



এই ক্ষেত্রে, বট অবিলম্বে সঠিক কী দিয়ে উত্তর দেয় এবং আরও প্রাসঙ্গিক তথ্য যোগ করে, তাই উত্তরটি প্রশ্নোত্তরগুলির মতো সোজা মনে হয় না (আমি আপনাকে মনে করিয়ে দিচ্ছি যে এই প্রশ্নটি প্রশ্ন ও উত্তরের তালিকায় রয়েছে), কিন্তু সঙ্গে যুক্তিসঙ্গত ব্যাখ্যা যা আংশিকভাবে নিম্নলিখিত প্রশ্নের সমাধান করে।

সোর্স কোড

আমার এখনই নোট করা উচিত যে শেষে রিপোজিটরিতে একটি লিঙ্ক থাকবে , যাতে আপনি "বিষয়" আপনার নিজস্ব, প্রশ্নোত্তর নলেজ বেস ফাইলটি আপনার নিজের সাথে প্রতিস্থাপন করে, এবং আপনার নিজস্ব API কীগুলি প্রদান করে বটটিকে যেমনটি চালাতে পারেন। OpenAI এবং টেলিগ্রাম বটের জন্য। সুতরাং এখানে বর্ণনাটি GitHub-এর সোর্স কোডের সাথে সম্পূর্ণরূপে মিলিত হওয়ার উদ্দেশ্যে নয়, বরং কোডের প্রধান দিকগুলিকে হাইলাইট করার উদ্দেশ্যে।

1 - ভার্চুয়াল পরিবেশ প্রস্তুত করা

আসুন একটি নতুন ভার্চুয়াল পরিবেশ তৈরি করি এবং requirements.txt থেকে নির্ভরতাগুলি ইনস্টল করি:


 virtualenv -p python3.8 .venv source .venv/bin/activate pip install -r requirements.txt

2 - জ্ঞানের ভিত্তি, ম্যানুয়ালি সংগৃহীত

উপরে উল্লিখিত হিসাবে, এটি অনুমান করা হয় যে প্রশ্ন এবং উত্তরগুলির একটি তালিকা রয়েছে, এই ক্ষেত্রে নিম্নলিখিত ধরণের একটি এক্সেল ফাইলের বিন্যাসে:



প্রদত্ত একটির সাথে সর্বাধিক অনুরূপ প্রশ্নটি খুঁজে পেতে, আমাদের এই ফাইলের প্রতিটি লাইনে প্রশ্নের একটি এমবেডিং (রাষ্ট্রীয় স্থানের একটি বহুমাত্রিক ভেক্টর) যুক্ত করতে হবে। আমরা এর জন্য add_embeddings.py ফাইলটি ব্যবহার করব। স্ক্রিপ্টটি বেশ কয়েকটি সহজ অংশ নিয়ে গঠিত।

লাইব্রেরি আমদানি করা এবং কমান্ড লাইন আর্গুমেন্ট পড়া:


 import pandas as pd import openai import argparse # Create an Argument Parser object parser = argparse.ArgumentParser(description='Adding embeddings for each line of csv file') # Add the arguments parser.add_argument('--openai_api_key', type=str, help='API KEY of OpenAI API to create contextual embeddings for each line') parser.add_argument('--file', type=str, help='A source CSV file with the text data') parser.add_argument('--colname', type=str, help='Column name with the texts') # Parse the command-line arguments args = parser.parse_args() # Access the argument values openai.api_key = args.openai_api_key file = args.file colname = args.colname


এরপরে, একটি পান্ডাস ডেটাফ্রেমে ফাইলটি পড়া এবং একটি প্রশ্ন চিহ্নের উপস্থিতির উপর ভিত্তি করে প্রশ্নগুলি ফিল্টার করা। এই কোড স্নিপেটটি জ্ঞানের ভিত্তির পাশাপাশি Discord থেকে অশোধিত বার্তা স্ট্রীমগুলি পরিচালনা করার জন্য সাধারণ, তাই ধরে নিয়েছি যে প্রশ্নগুলি প্রায়শই নকল করা হয়, আমি রুক্ষ নন-প্রশ্ন ফিল্টারিংয়ের এমন একটি সহজ পদ্ধতি রাখার সিদ্ধান্ত নিয়েছি।


 if file[-4:] == '.csv': df = pd.read_csv(file) else: df = pd.read_excel(file) # filter NAs df = df[~df[colname].isna()] # Keep only questions df = df[df[colname].str.contains('\?')]


এবং পরিশেষে - মডেল টেক্সট-এমবেডিং-এডা-002- এর API-কে কল করে একটি এম্বেডিং তৈরি করার জন্য একটি ফাংশন, যেহেতু API মাঝে মাঝে ওভারলোড হতে পারে এবং একটি ত্রুটির সাথে সাড়া দিতে পারে, এবং প্রতিটি সারিতে এই ফাংশনটি প্রয়োগ করতে পারে। ডেটাফ্রেমের।


 def get_embedding(text, model="text-embedding-ada-002"): i = 0 max_try = 3 # to avoid random OpenAI API fails: while i < max_try: try: text = text.replace("\n", " ") result = openai.Embedding.create(input=[text], model=model)['data'][0]['embedding'] return result except: i += 1 def process_row(x): return get_embedding(x, model='text-embedding-ada-002') df['ada_embedding'] = df[colname].apply(process_row) df.to_csv(file[:-4]+'_question_embed.csv', index=False)


শেষ পর্যন্ত, এই স্ক্রিপ্টটি নিম্নলিখিত কমান্ডের সাথে কল করা যেতে পারে:


 python add_embeddings.py \ --openai_api_key="xxx" \ --file="./subgraphs_faq.xlsx" \ --colname="Question"


OpenAI API কী সেট আপ করুন, নলেজ বেস সহ ফাইল এবং কলামের নাম যেখানে প্রশ্ন পাঠ্যটি অবস্থিত। চূড়ান্ত তৈরি করা ফাইল, subgraphs_faq._question_embed.csv-এ "প্রশ্ন", "উত্তর" এবং "ada_embedding " কলাম রয়েছে।

3 - ডিসকর্ড থেকে ডেটা সংগ্রহ (ঐচ্ছিক)

আপনি যদি একটি সাধারণ বটের প্রতি আগ্রহী হন যা শুধুমাত্র ম্যানুয়ালি সংগ্রহ করা জ্ঞানের ভিত্তিতে প্রতিক্রিয়া জানায়, আপনি এটি এবং নিম্নলিখিত বিভাগটি এড়িয়ে যেতে পারেন। যাইহোক, ডিসকর্ড চ্যানেল এবং একটি টেলিগ্রাম গ্রুপ উভয় থেকে ডেটা সংগ্রহের জন্য আমি এখানে সংক্ষেপে কোড উদাহরণ প্রদান করব। discord-channel-data-collection.py ফাইল দুটি অংশ নিয়ে গঠিত। প্রথম অংশে লাইব্রেরি আমদানি করা এবং কমান্ড লাইন আর্গুমেন্ট শুরু করা অন্তর্ভুক্ত:


 import requests import json import pandas as pd import argparse # Create an Argument Parser object parser = argparse.ArgumentParser(description='Discord Channel Data Collection Script') # Add the arguments parser.add_argument('--channel_id', type=str, help='Channel ID from the URL of a channel in browser https://discord.com/channels/xxx/{CHANNEL_ID}') parser.add_argument('--authorization_key', type=str, help='Authorization Key. Being on the discord channel page, start typing anything, then open developer tools -> Network -> Find "typing" -> Headers -> Authorization.') # Parse the command-line arguments args = parser.parse_args() # Access the argument values channel_id = args.channel_id authorization_key = args.authorization_key


দ্বিতীয়টি হল চ্যানেল থেকে ডেটা পুনরুদ্ধার এবং একটি পান্ডাস ডেটাফ্রেমে সংরক্ষণ করার জন্য ফাংশন, সেইসাথে নির্দিষ্ট পরামিতি সহ এর কল।


 def retrieve_messages(channel_id, authorization_key): num = 0 limit = 100 headers = { 'authorization': authorization_key } last_message_id = None # Create a pandas DataFrame df = pd.DataFrame(columns=['id', 'dt', 'text', 'author_id', 'author_username', 'is_bot', 'is_reply', 'id_reply']) while True: query_parameters = f'limit={limit}' if last_message_id is not None: query_parameters += f'&before={last_message_id}' r = requests.get( f'https://discord.com/api/v9/channels/{channel_id}/messages?{query_parameters}', headers=headers ) jsonn = json.loads(r.text) if len(jsonn) == 0: break for value in jsonn: is_reply = False id_reply = '0' if 'message_reference' in value and value['message_reference'] is not None: if 'message_id' in value['message_reference'].keys(): is_reply = True id_reply = value['message_reference']['message_id'] text = value['content'] if 'embeds' in value.keys(): if len(value['embeds'])>0: for x in value['embeds']: if 'description' in x.keys(): if text != '': text += ' ' + x['description'] else: text = x['description'] df_t = pd.DataFrame({ 'id': value['id'], 'dt': value['timestamp'], 'text': text, 'author_id': value['author']['id'], 'author_username': value['author']['username'], 'is_bot': value['author']['bot'] if 'bot' in value['author'].keys() else False, 'is_reply': is_reply, 'id_reply': id_reply, }, index=[0]) if len(df) == 0: df = df_t.copy() else: df = pd.concat([df, df_t], ignore_index=True) last_message_id = value['id'] num = num + 1 print('number of messages we collected is', num) # Save DataFrame to a CSV file df.to_csv(f'../discord_messages_{channel_id}.csv', index=False) if __name__ == '__main__': retrieve_messages(channel_id, authorization_key)


এখানে দরকারী তথ্য থেকে, একটি বিশদ বিবরণ রয়েছে যা আমি প্রতিবার প্রয়োজনে খুঁজে পাচ্ছি না - একটি অনুমোদন কী প্রাপ্ত করা। ব্রাউজারে খোলা ডিসকর্ড চ্যানেলের URL থেকে channel_id প্রাপ্ত করা যেতে পারে (লিংকের শেষ দীর্ঘ সংখ্যা) বিবেচনা করে, অনুমোদন_কি শুধুমাত্র চ্যানেলে একটি বার্তা টাইপ করা শুরু করে, তারপর বিকাশকারী সরঞ্জামগুলি ব্যবহার করে খুঁজে পেতে পারে। নেটওয়ার্ক বিভাগে " টাইপিং " নামক ইভেন্ট এবং হেডার থেকে প্যারামিটার বের করুন।



এই প্যারামিটারগুলি পাওয়ার পরে, আপনি চ্যানেল থেকে সমস্ত বার্তা সংগ্রহ করতে নিম্নলিখিত কমান্ডটি চালাতে পারেন (আপনার নিজস্ব মানগুলি প্রতিস্থাপন করুন):


 python discord-channel-data-collection.py \ --channel_id=123456 \ --authorization_key="123456qwerty"


4 - টেলিগ্রাম থেকে ডেটা সংগ্রহ করা

যেহেতু আমি প্রায়শই টেলিগ্রামে চ্যাট/চ্যানেল থেকে বিভিন্ন ডেটা ডাউনলোড করি, তাই আমি এটির জন্য কোড প্রদান করার সিদ্ধান্ত নিয়েছি, যা একটি অনুরূপ বিন্যাস তৈরি করে ( add_embeddings.py স্ক্রিপ্টের ক্ষেত্রে সামঞ্জস্যপূর্ণ) CSV ফাইল। সুতরাং, telegram-group-data-collection.py স্ক্রিপ্টটি নিম্নরূপ দেখায়। লাইব্রেরি আমদানি করা এবং কমান্ড লাইন থেকে আর্গুমেন্ট শুরু করা:


 import pandas as pd import argparse from telethon import TelegramClient # Create an Argument Parser object parser = argparse.ArgumentParser(description='Telegram Group Data Collection Script') # Add the arguments parser.add_argument('--app_id', type=int, help='Telegram APP id from https://my.telegram.org/apps') parser.add_argument('--app_hash', type=str, help='Telegram APP hash from https://my.telegram.org/apps') parser.add_argument('--phone_number', type=str, help='Telegram user phone number with the leading "+"') parser.add_argument('--password', type=str, help='Telegram user password') parser.add_argument('--group_name', type=str, help='Telegram group public name without "@"') parser.add_argument('--limit_messages', type=int, help='Number of last messages to download') # Parse the command-line arguments args = parser.parse_args() # Access the argument values app_id = args.app_id app_hash = args.app_hash phone_number = args.phone_number password = args.password group_name = args.group_name limit_messages = args.limit_messages


আপনি দেখতে পাচ্ছেন, আপনি নিজেকে প্রথম ব্যক্তি হিসাবে অনুমোদন না করে চ্যাট থেকে সমস্ত বার্তা ডাউনলোড করতে পারবেন না। অন্য কথায়, https://my.telegram.org/apps (APP_ID এবং APP_HASH পাওয়ার) মাধ্যমে একটি অ্যাপ তৈরি করার পাশাপাশি, আপনাকে টেলিথন লাইব্রেরি থেকে টেলিগ্রামক্লায়েন্ট ক্লাসের একটি উদাহরণ তৈরি করতে আপনার ফোন নম্বর এবং পাসওয়ার্ড ব্যবহার করতে হবে। .


অতিরিক্তভাবে, আপনার টেলিগ্রাম চ্যাটের সর্বজনীন গ্রুপ_নাম প্রয়োজন এবং পুনরুদ্ধার করা সর্বশেষ বার্তাগুলির সংখ্যা স্পষ্টভাবে উল্লেখ করতে হবে। সামগ্রিকভাবে, আমি টেলিগ্রাম API থেকে কোনো অস্থায়ী বা স্থায়ী নিষেধাজ্ঞা না পেয়ে যে কোনো সংখ্যক রপ্তানি করা বার্তার সাথে এই পদ্ধতিটি বহুবার করেছি, যখন কেউ একটি অ্যাকাউন্ট থেকে খুব ঘন ঘন বার্তা পাঠায়।


স্ক্রিপ্টের দ্বিতীয় অংশে বার্তা রপ্তানি করার জন্য প্রকৃত ফাংশন রয়েছে এবং এটি কার্যকর করা হয়েছে (সমালোচনামূলক ত্রুটিগুলি এড়াতে প্রয়োজনীয় ফিল্টারিং সহ যা সংগ্রহ অর্ধেক পথ বন্ধ করে দেবে):


 async def main(): messages = await client.get_messages(group_name, limit=limit_messages) df = pd.DataFrame(columns=['date', 'user_id', 'raw_text', 'views', 'forwards', 'text', 'chan', 'id']) for m in messages: if m is not None: if 'from_id' in m.__dict__.keys(): if m.from_id is not None: if 'user_id' in m.from_id.__dict__.keys(): df = pd.concat([df, pd.DataFrame([{'date': m.date, 'user_id': m.from_id.user_id, 'raw_text': m.raw_text, 'views': m.views, 'forwards': m.forwards, 'text': m.text, 'chan': group_name, 'id': m.id}])], ignore_index=True) df = df[~df['user_id'].isna()] df = df[~df['text'].isna()] df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date').reset_index(drop=True) df.to_csv(f'../telegram_messages_{group_name}.csv', index=False) client = TelegramClient('session', app_id, app_hash) client.start(phone=phone_number, password=password) with client: client.loop.run_until_complete(main())


শেষ পর্যন্ত, এই স্ক্রিপ্টটি নিম্নলিখিত কমান্ডের সাহায্যে কার্যকর করা যেতে পারে (মানগুলি আপনার নিজের সাথে প্রতিস্থাপন করুন):


 python telegram-group-data-collection.py \ --app_id=123456 --app_hash="123456qwerty" \ --phone_number="+xxxxxx" --password="qwerty123" \ --group_name="xxx" --limit_messages=10000


5 - টেলিগ্রাম বট স্ক্রিপ্ট যা আসলে প্রশ্নের উত্তর দেয়

বেশিরভাগ সময়, আমি আমার পোষা প্রজেক্টগুলিকে টেলিগ্রাম বটগুলিতে মুড়িয়ে রাখি কারণ এটি চালু করার জন্য ন্যূনতম প্রচেষ্টার প্রয়োজন এবং অবিলম্বে সম্ভাব্যতা দেখায়। এই ক্ষেত্রে, আমিও তাই করেছি। আমি অবশ্যই বলব যে বট কোডে আমি সাবগ্রাফজিপিটি বটের প্রোডাকশন সংস্করণে ব্যবহার করি এমন সমস্ত কর্নার কেস ধারণ করে না, কারণ এতে আমার অন্য একটি পোষা প্রকল্প থেকে উত্তরাধিকার সূত্রে প্রাপ্ত যুক্তি রয়েছে। পরিবর্তে, আমি ন্যূনতম পরিমাণ মৌলিক কোড রেখেছি যা আপনার প্রয়োজনের জন্য পরিবর্তন করা সহজ হওয়া উচিত।

টেলিগ্রাম-bot.py স্ক্রিপ্টটি বেশ কয়েকটি অংশ নিয়ে গঠিত। প্রথমত, আগের মতো, লাইব্রেরিগুলি আমদানি করা হয় এবং কমান্ড লাইন আর্গুমেন্ট শুরু হয়।


 import threading import telegram from telegram.ext import Updater, CommandHandler, MessageHandler, Filters import openai from openai.embeddings_utils import cosine_similarity import numpy as np import pandas as pd import argparse import functools # Create an Argument Parser object parser = argparse.ArgumentParser(description='Run the bot which uses prepared knowledge base enriched with contextual embeddings') # Add the arguments parser.add_argument('--openai_api_key', type=str, help='API KEY of OpenAI API to create contextual embeddings for each line') parser.add_argument('--telegram_bot_token', type=str, help='A telegram bot token obtained via @BotFather') parser.add_argument('--file', type=str, help='A source CSV file with the questions, answers and embeddings') parser.add_argument('--topic', type=str, help='Write the topic to add a default context for the bot') parser.add_argument('--start_message', type=str, help="The text that will be shown to the users after they click /start button/command", default="Hello, World!") parser.add_argument('--model', type=str, help='A model of ChatGPT which will be used', default='gpt-3.5-turbo-16k') parser.add_argument('--num_top_qa', type=str, help="The number of top similar questions' answers as a context", default=3) # Parse the command-line arguments args = parser.parse_args() # Access the argument values openai.api_key = args.openai_api_key token = args.telegram_bot_token file = args.file topic = args.topic model = args.model num_top_qa = args.num_top_qa start_message = args.start_message


অনুগ্রহ করে মনে রাখবেন যে এই ক্ষেত্রে, আপনার একটি OpenAI API কী-এরও প্রয়োজন হবে, কারণ জ্ঞানের ভিত্তি থেকে ব্যবহারকারীর দ্বারা প্রবেশ করানো প্রশ্নের সাথে সবচেয়ে অনুরূপ প্রশ্নটি খুঁজে পেতে, আপনাকে প্রথমে কল করে সেই প্রশ্নটির এমবেডিং পেতে হবে এপিআই যেমন আমরা জ্ঞানের ভিত্তির জন্য করেছি।


উপরন্তু, আপনার প্রয়োজন হবে:


  • টেলিগ্রাম_বট_টোকেন - বটফাদার থেকে টেলিগ্রাম বটের একটি টোকেন
  • ফাইল - নলেজ বেস ফাইলের একটি পথ (আমি ইচ্ছাকৃতভাবে এখানে ডিসকর্ডের বার্তাগুলির সাথে কেসটি এড়িয়ে চলেছি, যেহেতু আমি মনে করি এটি একটি বিশেষ কাজ, তবে প্রয়োজনে সেগুলি কোডে সহজেই একত্রিত করা যেতে পারে)
  • বিষয় - বিষয়ের পাঠ্য প্রণয়ন (নিবন্ধের শুরুতে উল্লিখিত) যেখানে বট কাজ করবে
  • start_message - যে বার্তাটি ব্যবহারকারী /start এ ক্লিক করেছে সে দেখতে পাবে (ডিফল্টরূপে, "হ্যালো, ওয়ার্ল্ড!")
  • মডেল - মডেলের পছন্দ (ডিফল্টরূপে সেট)
  • num_top_qa - জ্ঞানের ভিত্তি থেকে সর্বাধিক অনুরূপ প্রশ্ন-উত্তরের সংখ্যা যা ChatGPT অনুরোধের প্রসঙ্গ হিসাবে ব্যবহার করা হবে


তারপরে নলেজ বেস ফাইলের লোডিং এবং প্রশ্ন এম্বেডিংয়ের প্রাথমিককরণ অনুসরণ করে।


 # reading QA file with embeddings df_qa = pd.read_csv(file) df_qa['ada_embedding'] = df_qa.ada_embedding.apply(eval).apply(np.array)


ChatGPT API-তে একটি অনুরোধ করার জন্য, এটি জেনে যে এটি কখনও কখনও ওভারলোডের কারণে একটি ত্রুটির সাথে সাড়া দেয়, আমি একটি ত্রুটির ক্ষেত্রে স্বয়ংক্রিয় অনুরোধ পুনরায় চেষ্টা করার সাথে একটি ফাংশন ব্যবহার করি।


 def retry_on_error(func): @functools.wraps(func) def wrapper(*args, **kwargs): max_retries = 3 for i in range(max_retries): try: return func(*args, **kwargs) except Exception as e: print(f"Error occurred, retrying ({i+1}/{max_retries} attempts)...") # If all retries failed, raise the last exception raise e return wrapper @retry_on_error def call_chatgpt(*args, **kwargs): return openai.ChatCompletion.create(*args, **kwargs)


OpenAI-এর সুপারিশ অনুসারে, টেক্সটকে এম্বেডিং-এ রূপান্তর করার আগে, স্পেস দিয়ে নতুন লাইন প্রতিস্থাপন করা উচিত।


 def get_embedding(text, model="text-embedding-ada-002"): text = text.replace("\n", " ") return openai.Embedding.create(input=[text], model=model)['data'][0]['embedding']


সর্বাধিক অনুরূপ প্রশ্নগুলি অনুসন্ধান করতে, আমরা সরাসরি ওপেনই লাইব্রেরি থেকে নেওয়া দুটি প্রশ্নের এম্বেডিংয়ের মধ্যে কোসাইন দূরত্ব গণনা করি।


 def search_similar(df, question, n=3, pprint=True): embedding = get_embedding(question, model='text-embedding-ada-002') df['similarities'] = df.ada_embedding.apply(lambda x: cosine_similarity(x, embedding)) res = df.sort_values('similarities', ascending=False).head(n) return res


প্রদত্ত একটির সাথে সবচেয়ে অনুরূপ প্রশ্ন-উত্তর জোড়ার একটি তালিকা পাওয়ার পরে, আপনি সেগুলিকে একটি পাঠ্যে সংকলন করতে পারেন, এটিকে এমনভাবে চিহ্নিত করে যাতে ChatGPT দ্ব্যর্থহীনভাবে নির্ধারণ করতে পারে কী কী।


 def collect_text_qa(df): text = '' for i, row in df.iterrows(): text += f'Q: <'+row['Question'] + '>\nA: <'+ row['Answer'] +'>\n\n' print('len qa', len(text.split(' '))) return text


এর পরে, নিবন্ধের একেবারে শুরুতে বর্ণিত প্রম্পটের "টুকরা" একটি সম্পূর্ণরূপে সংগ্রহ করা ইতিমধ্যেই প্রয়োজনীয়।


 def collect_full_prompt(question, qa_prompt, chat_prompt=None): prompt = f'I need to get an answer to the question related to the topic of "{topic}": ' + "{{{"+ question +"}}}. " prompt += '\n\nPossibly, you might find an answer in these Q&As [use the information only if it is actually relevant and useful for the question answering]: \n\n' + qa_prompt # edit if you need to use this also if chat_prompt is not None: prompt += "---------\nIf you didn't find a clear answer in the Q&As, possibly, these talks from chats might be helpful to answer properly [use the information only if it is actually relevant and useful for the question answering]: \n\n" + chat_prompt prompt += f'\nFinally, only if the information above was not enough you can use your knowledge in the topic of "{topic}" to answer the question.' return prompt


এই ক্ষেত্রে, আমি ডিসকর্ড থেকে বার্তাগুলি ব্যবহার করে অংশটি সরিয়ে দিয়েছি, তবে আপনি এখনও যুক্তি অনুসরণ করতে পারেন যদি chat_prompt!= কিছুই না।


এছাড়াও, আমাদের একটি ফাংশন প্রয়োজন যা ChatGPT API থেকে প্রাপ্ত প্রতিক্রিয়াকে টেলিগ্রাম বার্তাগুলিতে বিভক্ত করে (4096 অক্ষরের বেশি নয়):


 def telegram_message_format(text): max_message_length = 4096 if len(text) > max_message_length: parts = [] while len(text) > max_message_length: parts.append(text[:max_message_length]) text = text[max_message_length:] parts.append(text) return parts else: return [text]


বটটি ধাপগুলির একটি সাধারণ ক্রম দিয়ে শুরু হয়, /start কমান্ড দ্বারা ট্রিগার করার জন্য দুটি ফাংশন বরাদ্দ করে এবং ব্যবহারকারীর কাছ থেকে একটি ব্যক্তিগত বার্তা গ্রহণ করে:


 bot = telegram.Bot(token=token) updater = Updater(token=token, use_context=True) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler("start", start, filters=Filters.chat_type.private)) dispatcher.add_handler(MessageHandler(~Filters.command & Filters.text, message_handler)) updater.start_polling()


/শুরুতে সাড়া দেওয়ার কোডটি সোজা:


 def start(update, context): user = update.effective_user context.bot.send_message(chat_id=user.id, text=start_message)


এবং একটি ফ্রি-ফর্ম বার্তার প্রতিক্রিয়ার জন্য, এটি পুরোপুরি পরিষ্কার নয়।


প্রথমত , বিভিন্ন ব্যবহারকারীদের থেকে থ্রেড ব্লক করা এড়াতে, আসুন অবিলম্বে থ্রেডিং লাইব্রেরি ব্যবহার করে স্বাধীন প্রক্রিয়াগুলিতে তাদের "বিচ্ছিন্ন" করি।


 def message_handler(update, context): thread = threading.Thread(target=long_running_task, args=(update, context)) thread.start()


দ্বিতীয়ত , সমস্ত যুক্তি লং_রানিং_টাস্ক ফাংশনের ভিতরে ঘটবে। আমি ইচ্ছাকৃতভাবে প্রধান খণ্ডগুলিকে চেষ্টা/ব্যতীত বট-এর কোড পরিবর্তন করার সময় সহজে স্থানীয়করণের ত্রুটিগুলিকে মোড়ানো করেছি।


  • প্রথমত, আমরা বার্তাটি পুনরুদ্ধার করি এবং ত্রুটিটি পরিচালনা করি যদি ব্যবহারকারী একটি বার্তার পরিবর্তে একটি ফাইল বা চিত্র পাঠায়।
  • তারপর, আমরা search_similar ব্যবহার করে সবচেয়ে অনুরূপ প্রশ্ন-উত্তর অনুসন্ধান করি।
  • এর পরে, আমরা collect_text_qa ব্যবহার করে সমস্ত প্রশ্ন-উত্তর একটি পাঠ্যে সংগ্রহ করি।
  • এবং আমরা collect_full_prompt ব্যবহার করে ChatGPT API-এর জন্য চূড়ান্ত প্রম্পট তৈরি করি।


 def long_running_task(update, context): user = update.effective_user context.bot.send_message(chat_id=user.id, text='🕰️⏰🕙⏱️⏳...') try: question = update.message.text.strip() except Exception as e: context.bot.send_message(chat_id=user.id, text=f"🤔It seems like you're sending not text to the bot. Currently, the bot can only work with text requests.") return try: qa_found = search_similar(df_qa, question, n=num_top_qa) qa_prompt = collect_text_qa(qa_found) full_prompt = collect_full_prompt(question, qa_prompt) except Exception as e: context.bot.send_message(chat_id=user.id, text=f"Search failed. Debug needed.") return


যেহেতু আপনার নিজের সাথে জ্ঞানের ভিত্তি এবং বিষয় প্রতিস্থাপন করার সময় ত্রুটি হতে পারে, উদাহরণস্বরূপ, বিন্যাসের কারণে, একটি মানব-পাঠযোগ্য ত্রুটি প্রদর্শিত হয়।


এরপরে, অনুরোধটি একটি অগ্রণী সিস্টেম বার্তা সহ ChatGPT API-এ পাঠানো হয় যা ইতিমধ্যেই নিজেকে প্রমাণ করেছে: " আপনি একজন সহায়ক সহকারী৷ " ফলে আউটপুট প্রয়োজনে একাধিক বার্তায় বিভক্ত এবং ব্যবহারকারীকে ফেরত পাঠানো হয়৷


 try: print(full_prompt) completion = call_chatgpt( model=model, n=1, messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": full_prompt}] ) result = completion['choices'][0]['message']['content'] except Exception as e: context.bot.send_message(chat_id=user.id, text=f'It seems like the OpenAI service is responding with errors. Try sending the request again.') return parts = telegram_message_format(result) for part in parts: update.message.reply_text(part, reply_to_message_id=update.message.message_id)



যে কোডের সাথে অংশটি শেষ করে।

প্রোটোটাইপ

এখন, এই ধরনের একটি বটের একটি প্রোটোটাইপ নিম্নলিখিত লিঙ্কে একটি সীমিত বিন্যাসে উপলব্ধ। যেহেতু এপিআই অর্থপ্রদান করা হয়, আপনি প্রতিদিন 3টি পর্যন্ত অনুরোধ করতে পারেন, তবে আমি মনে করি না এটি কাউকে সীমাবদ্ধ করবে, কারণ সবচেয়ে আকর্ষণীয় জিনিসটি একটি সংকীর্ণ বিষয়ে ফোকাস করা বিশেষায়িত বট নয়, তবে যেকোনও জিপিটি প্রকল্পের কোড , যা এই উদাহরণের উপর ভিত্তি করে আপনার জ্ঞানের ভিত্তিতে আপনার নির্দিষ্ট কাজটি সমাধান করার জন্য কীভাবে আপনার নিজস্ব বট তৈরি করবেন তার একটি সংক্ষিপ্ত নির্দেশনা সহ GitHub- এ উপলব্ধ। আপনি যদি শেষ পর্যন্ত পড়ে থাকেন, আমি আশা করি এই নিবন্ধটি আপনার জন্য সহায়ক হয়েছে।



একটি বটের সাথে দৈনিক যোগাযোগের স্ক্রিনশট