diff --git a/lib/weiyiai.rb b/lib/weiyiai.rb new file mode 100644 index 0000000..35b297c --- /dev/null +++ b/lib/weiyiai.rb @@ -0,0 +1,30 @@ +require 'net/http' +require_relative 'weiyiai/error/error' +require_relative 'weiyiai/openai/client' +require_relative 'weiyiai/slack/client' +require_relative 'weiyiai/client' + +# USAGE +# require "weiyiai" +# +# Slack.configure do |config| +# config.token = 'TOKEN' +# end +# @weiyiai = WeiyiAI::Client.new( +# openai_configs: { +# access_token: 'TOKEN', +# organization_id: 'ORG_ID' +# }, +# slack_configs: { +# connection: Slack::Web::Client.new, +# realtime_connection: Slack::RealTime::Client.new, +# default_channel: '#project-acw' +# } +# ) +# chat_res = @weiyiai.openai.chat( +# parameters: { +# messages: [{ role: 'user', content: 'Summarize this page: https://zh.wikipedia.org/zh-tw/ChatGPT' }] +# } +# ) +# chat_res = @weiyiai.openai.completions(parameters: {prompt: "What is top 10 news today"}) +# @weiyiai.slack.listen \ No newline at end of file diff --git a/lib/weiyiai/client.rb b/lib/weiyiai/client.rb new file mode 100644 index 0000000..2141d87 --- /dev/null +++ b/lib/weiyiai/client.rb @@ -0,0 +1,18 @@ + +module WeiyiAI + class Client + attr_accessor :openai, :slack + def initialize(openai_configs: nil, slack_configs: nil, default_channel: nil) + @openai = WeiyiAI::OpenAI::Client.new(openai_configs) + @slack = WeiyiAI::Slack::Client.new(slack_configs) + end + + def prompt + # @openai.chat + end + + def respond + # @slack.post + end + end +end diff --git a/lib/weiyiai/error/error.rb b/lib/weiyiai/error/error.rb new file mode 100644 index 0000000..d616197 --- /dev/null +++ b/lib/weiyiai/error/error.rb @@ -0,0 +1,7 @@ +module WeiyiAI + module Error + class ConfigurationError < StandardError; end + class OpenAIError < StandardError; end + class SlackError < StandardError; end + end +end diff --git a/lib/weiyiai/openai/client.rb b/lib/weiyiai/openai/client.rb new file mode 100644 index 0000000..2361aa3 --- /dev/null +++ b/lib/weiyiai/openai/client.rb @@ -0,0 +1,74 @@ +# curl https://api.openai.com/v1/models \ +# -H "Authorization: Bearer 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" +module WeiyiAI + module OpenAI + class Client + attr_writer :access_token, :organization_id + attr_reader :response + + DEFAULT_API_VERSION = 'v1'.freeze + DEFAULT_URI_BASE = 'https://api.openai.com/'.freeze + DEFAULT_TIMEOUT = 120 + + def initialize(access_token: nil, organization_id: nil) + @access_token = access_token + @organization_id = organization_id + end + + # chat_res = @weiyiai.openai.chat(parameters: {messages: [{role: "user", content: "Summarize this page: https://zh.wikipedia.org/zh-tw/ChatGPT"}]}) + def chat(parameters: {}) + default_parameters = { model: 'gpt-3.5-turbo' } + + res = Net::HTTP.post( + URI("#{base_uri}/chat/completions"), + JSON.generate(parameters.merge(default_parameters)), + headers + ) + + respond(method: "#{__method__}", response: res) + end + + # chat_res = @weiyiai.openai.completions(parameters: {prompt: "Say this is a test"}) + def completions(parameters: {}) + default_parameters = { model: 'text-davinci-003' } + res = Net::HTTP.post( + URI("#{base_uri}/completions"), + JSON.generate(parameters.merge(default_parameters)), + headers + ) + respond(method: "#{__method__}", response: res) + end + + private def base_uri + DEFAULT_URI_BASE + DEFAULT_API_VERSION + end + + private def headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{@access_token}", + 'OpenAI-Organization' => @organization_id + } + end + + private def respond(method: nil, response: nil) + case response + when Net::HTTPSuccess, Net::HTTPRedirection + serialize(method: method, response_body: JSON.parse(response.body)) + else + raise WeiyiAI::Error::OpenAIError, "[#{response.code}] #{response.body}" + end + end + + private def serialize(method: nil, response_body: nil) + @response = response_body + case method + when "chat" + @response['choices'].map { |h| h['message']['content'] }.join("\n") + when "completions" + @response['choices'].map { |h| h['text'] }.join("\n") + end + end + end + end +end diff --git a/lib/weiyiai/slack/client.rb b/lib/weiyiai/slack/client.rb new file mode 100644 index 0000000..bf8f8cb --- /dev/null +++ b/lib/weiyiai/slack/client.rb @@ -0,0 +1,55 @@ +module WeiyiAI + module Slack + class Client + attr_accessor :connection, :realtime_connection + attr_reader :default_channel + def initialize(connection: nil, realtime_connection: nil, default_channel: nil) + @connection = connection + @realtime_connection = realtime_connection + @default_channel = default_channel + end + + def post + @connection.chat_postMessage( + channel: @channel, + as_user: true, + mrkdwn: true, + blocks: [ + { + "type": 'section', + "text": { + "type": 'mrkdwn', + "text": result.gsub('**', '*') + } + } + ] + ) + end + + def listen + @realtime_connection.on :hello do + puts "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." + end + + @realtime_connection.on :message do |data| + case data.text + when 'bot hi' + @realtime_connection.message(channel: data.channel, text: "Hi <@#{data.user}>!") + when /^bot/ + @realtime_connection.message(channel: data.channel, text: "Sorry <@#{data.user}>, what?") + end + end + + @realtime_connection.on :close do |_data| + puts 'Client is about to disconnect' + end + + @realtime_connection.on :closed do |_data| + puts 'Client has disconnected successfully!' + end + + @realtime_connection.start! + end + end + end +end