برنامه نویسی

اشیاء سرویس در Ruby on Rails: بهترین روش‌ها برای کدهای تمیز و قابل نگهداری

بسیاری از اوقات ما نیاز داریم که برنامه ROR خود را با دنیای خارج در میان بگذاریم، یا برای استفاده از سرویسی که اطلاعاتی را در اختیار ما قرار می دهد یا اینکه خودمان اطلاعاتی را ارسال کنیم.

و ما می توانیم این کار را به دو صورت انجام دهیم،
راه غارنشین، که با استفاده از HTTParty ساده است و شامل روشی برای تماس با API در کنترلر یا مدل ما است. این بدون هیچ مشکلی کار خواهد کرد، اگر فقط پروژه شما باشد نگهداری از آن سریع و شاید آسان است.

راه روبی روی ریل، به این ترتیب یک دایرکتوری برای سرویس های پروژه خود به نام “سرویس ها” در دایرکتوری “app” ایجاد می کنیم که در آن همه سرویس های خارجی یا API هایی را که پروژه ما مصرف می کند قرار می دهیم.

با استفاده از شیک بودن آن، قصد داریم با Chat GPT ارتباط برقرار کنیم.

باشه بریم سر کار

HTTParty را نصب کنید

gem 'httparty'

ما از HTTParty gem برای انجام تمام درخواست های HTTP خود استفاده می کنیم.
برای نصب آن کافیست کد بالا را به خود اضافه کنید Gemfile و سپس اجرا کنید bundle install.

پیکربندی سرویس

برای برقراری ارتباط con Chat GPT، باید یک API KEY یا TOKEN را در سرصفحه های درخواست خود ارسال کنیم، و برای ایمن نگه داشتن آن، آن را در فایل اعتبارنامه Rails ذخیره می کنیم.
با اجرای این دستور در ترمینال خود می توانید فایل اعتبارنامه را ویرایش کنید

EDITOR="nano" bin/rails credentials:edit

این فایل اعتبار شما را با استفاده از “nano” به عنوان ویرایشگر متن باز می کند.
هنگامی که آن را ویرایش کردید، خط پیکربندی زیر را اضافه کنید

chatgpt_api_key: YOUR-API-KEY

اگر از nano استفاده می کنید، لطفا ویرایشگر را ذخیره و ببندید، Ctrl + x این ترفند را انجام خواهد داد.

شروع ساخت سرویس

ما می توانیم تمام خدمات خود را به عنوان ماژول در نظر بگیریم، ساختار زیر را ببینید

➜  chatgpt_service git:(master)  tree app/services
app/services
├── chat_gpt
│   ├── data
│   │   ├── chat_completions_choice_item_data.rb
│   │   ├── completions_choice_item_data.rb
│   │   ├── models_item_data.rb
│   │   └── models_list_data.rb
│   ├── responses
│   │   ├── base_response.rb
│   │   ├── chat_completions_response.rb
│   │   ├── completions_response.rb
│   │   └── models_list_response.rb
│   └── service.rb
└── http_response.rb

4 directories, 10 files

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ایده این است که یک ماژول برای محصور کردن API که می‌خواهیم مصرف کنیم و در داخل آن قرار دهیم Service کلاس با تمام روش های درخواست یا ارسال اطلاعات.
در داخل پاسخ‌ها، کلاس‌های خود را ذخیره می‌کنیم که مسئول مدیریت اطلاعات برگردانده شده توسط API هستند.
در صورتی که API داده‌های پیچیده یا بسیاری از اشیاء را در داخل یکدیگر برگرداند، می‌توانید از کلاس‌های داده استفاده کنید، کلاس‌هایی که در داخل می‌توانید مشاهده کنید. data فهرست راهنما.

نگران کد نباشید، از آنجایی که من یک مخزن عمومی Github با این پروژه آماده کردم، به آن نگاهی بیندازید: https://github.com/paul-ot/ror_chatgpt_client

برای توضیح ساختار سرویس فوق می توان گفت که سرویس برای هر نقطه پایانی که استفاده می کنیم یک متد عمومی خواهد داشت، به عنوان مثال در مورد ما سه روش عمومی در سرویس داریم.
completions، chat_completions و models_list.

module ChatGpt
  class Service
    include HTTParty
    base_uri 'https://api.openai.com/v1'

    # ...

    def completions(prompt, model = nil)
      @model = model unless model.nil?

      response = self.class.post(
        COMPLETIONS_PATH,
        body: completions_body(prompt),
        headers: common_headers,
        timeout: TIMEOUT_SECONDS
      )

      ChatGpt::Responses::CompletionsResponse.new(response)
    end

    def chat_completions(message, model = nil)
      @model = model unless model.nil?

      response = self.class.post(
        COMPLETIONS_PATH,
        body: chat_completions_body(message),
        headers: common_headers,
        timeout: TIMEOUT_SECONDS
      )

      ChatGpt::Responses::ChatCompletionsResponse.new(response)
    end

    def models_list
      response = self.class.get(
        MODELS_PATH,
        headers: common_headers,
        timeout: TIMEOUT_SECONDS
      )

      ChatGpt::Responses::ModelsListResponse.new(response)
    end

    # ...

  end
end

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر متد پاسخ خود را برمی‌گرداند، به این معنی که هر متد یک پاسخ متفاوت، کلاس متفاوتی را که در داخل ذخیره می‌شود، برمی‌گرداند responses دایرکتوری، ما این کار را از این طریق انجام می دهیم تا پاسخ ها را جدا کنیم و روش های مختلفی برای دریافت اطلاعات از پاسخ های JSON ایجاد کنیم.

به پاسخ ها توجه کنید

روش تکمیل:

    def completions(prompt, model = nil)
      # ...

      ChatGpt::Responses::CompletionsResponse.new(response)
    end
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

روش تکمیل چت:

    def chat_completions(message, model = nil)
      # ...

      ChatGpt::Responses::ChatCompletionsResponse.new(response)
    end
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

لیست مدل ها:

    def models_list
      # ...

      ChatGpt::Responses::ModelsListResponse.new(response)
    end
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا هر کلاس پاسخ از a ارث می برد ChatGpt::Responses::BaseResponse کلاسی که شامل متدهای رایج در بین پاسخ ها، پیام خطا است.

BaseResponse

module ChatGpt
  module Responses
    class BaseResponse < HttpResponse
      def error_message
        response_body.dig('error', 'message')
      end
    end
  end
end
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همزمان، ChatGpt::Responses::BaseResponse ارث می برد از HttpResponse کلاس، که شامل متدهای بسیار رایج است، برای مثال مسئول تعیین می کند که آیا پاسخ خوب بوده یا نه، و همچنین پاسخ را به شی JSON تبدیل می کند.

HttpResponse

class HttpResponse
  attr_reader :response

  def initialize(response)
    @response = response
  end

  def response_body
    response.body.present? ? JSON.parse(response.body) : {}
  rescue JSON::ParserError
    {}
  end

  def successful?
    response.code.to_i == Rack::Utils::SYMBOL_TO_STATUS_CODE[:ok]
  end

  def failed?
    !successful?
  end
end

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من این کار را در آن راه انجام دادم تا آن را قابل استفاده مجددتر کنم، بنابراین شما می توانید چندین سرویس با پاسخ های خاص خود داشته باشید و از این به ارث برسید. HttpResponse کلاس

در مورد استفاده از این سرویس، بسیار ساده است

1- یک نمونه سرویس ایجاد کنید

> service = ChatGpt::Service.new

=> #<ChatGpt::Service:0x00007fccde2ed0d0 @model="gpt-3.5-turbo">
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2- می توانید به صورت زیر سعی کنید لیست مدل های GPT را دریافت کنید

response = service.models_list

=> #<ChatGpt::Responses::ModelsListResponse:0x00007fccdd7d6390 @response=#<HTTParty::Response:0x7fccdd6c7ad0 parsed_response={"object"=>"list", "data"=>[{"id"=>"babbage", "object"=>"model", "created"=>1649358449, "owned_by"=>"openai", "permission"=>[{"id"=>"modelperm-49FUp5v084tBB49tC4z8LPH5", ...>

> response.items.count
=> 64

> response.items.first
=> #<ChatGpt::Data::ModelsItemData:0x00007fccde9cfa60 @params={"id"=>"babbage", "object"=>"model", "created"=>1649358449, "owned_by"=>"openai", "permission"=>[{"id"=>"modelperm-49FUp5v084tBB49tC4z8LPH5", "object"=>"model_permission", "created"=>1669085501, "allow_create_engine"=>false, "allow_sampling"=>true, "allow_logprobs"=>true, "allow_search_indices"=>false, "allow_view"=>true, "allow_fine_tuning"=>false, "organization"=>"*", "group"=>nil, "is_blocking"=>false}], "root"=>"babbage", "parent"=>nil}>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای مثال‌های بیشتر لطفاً به مخزن Github مراجعه کنید، یک فایل README.md به همراه آنها دارد.

امیدوارم چیز مفیدی ارائه داده باشم و امیدوارم توانسته باشم دیدگاه خود را در مورد استفاده از خدمات در Ruby on Rails توضیح دهم.

با تشکر برای خواندن!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا