summarize-meeting 0.2.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd8ba0fbf2d8b0610cebeccbd7906283f9b39a357dc594026dd31c4853488b92
4
- data.tar.gz: 6ab995e6472dc2b9cd749a99f8f5ecb634de40baf8645a66e2b2a761676b235e
3
+ metadata.gz: 44c7e54486689e6bfa88f4b9ee7e0e82cf90220d64becacc16755ebdd8977dca
4
+ data.tar.gz: 0a905c1c9bc06bbe8f5cc825410aa3771597680526f11c6a7775afb9aed2d5b1
5
5
  SHA512:
6
- metadata.gz: 90d848336e888922379d35d17b54fcd7312e5671005f1731ac93921e724c0b17c013c4230615e0842a771afc824af15280d18db1104ee404ffb9a8c8356545d7
7
- data.tar.gz: ba360026742a884fb68cd7c2f5f079b1502da67da3ed9747f30585ff109ca59ddbb00869d18e796ad4ee38d439e4f063ced2a65609ec74f5d6f9b8844344ff28
6
+ metadata.gz: 2975c64d3571e15303d164014182e477c387fef9bac96aa9bdd5e7b3088eff238f8379e4305b9ec9442faf12a13bd2a1f63d5a7188ceca74dc7ccd42c9e8e475
7
+ data.tar.gz: 9f48334f5e4df0969de1ddc3055c677f1e2e7df2ea2bda38624e6cfcb5175ba8fa655092bf6bb02080f96b43f827827e1feb1a78fa181cb6b49142c3ecf0aefc
@@ -44,9 +44,10 @@ def main
44
44
  end
45
45
 
46
46
  transcript_file = ARGV[0]
47
- transcript = File.read(transcript_file)
47
+ transcript = File.read(transcript_file, encoding: "UTF-8")
48
48
 
49
49
  meeting = SummarizeMeeting::Meeting.new(transcript)
50
+
50
51
  summary = meeting.summarize
51
52
  summary_file_name = if options[:output_file]
52
53
  options[:output_file]
@@ -1,11 +1,17 @@
1
- require "openai"
2
-
3
1
  module SummarizeMeeting
4
2
  module Ai
3
+ class OpenAiError < StandardError; end
4
+ MAX_TOTAL_TOKENS = 4096
5
+ WORDS_PER_TOKEN = 0.75
6
+
5
7
  @@access_token = ENV["OPENAI_KEY"]
6
8
  @@organization_id = ENV["OPENAI_ORG"]
7
9
 
8
10
  def self.client
11
+ @client ||= new_client(access_token: access_token, organization_id: organization_id)
12
+ end
13
+
14
+ def self.new_client(access_token:, organization_id:)
9
15
  OpenAI::Client.new(access_token: access_token, organization_id: organization_id)
10
16
  end
11
17
 
@@ -24,5 +30,27 @@ module SummarizeMeeting
24
30
  def self.organization_id=(id)
25
31
  @@organization_id = id
26
32
  end
33
+
34
+ def self.calculate_token_word_count(token_count)
35
+ (token_count * WORDS_PER_TOKEN.to_f).ceil
36
+ end
37
+
38
+ def self.calculate_word_token_count(word_count)
39
+ (word_count / WORDS_PER_TOKEN.to_f).ceil
40
+ end
41
+
42
+ def self.chat(messages, client: self.client)
43
+ parameters = {
44
+ model: "gpt-3.5-turbo",
45
+ messages: messages,
46
+ }
47
+ response = client.chat(parameters: parameters)
48
+ content = response.dig("choices", 0, "message", "content")
49
+ if !content
50
+ raise OpenAiError, "No response from OpenAI"
51
+ else
52
+ content
53
+ end
54
+ end
27
55
  end
28
56
  end
@@ -4,6 +4,8 @@ require "openai"
4
4
 
5
5
  module SummarizeMeeting
6
6
  class Meeting
7
+ RESPONSE_RESERVE_TOKENS = 500
8
+
7
9
  LINE_SUMMARY_PROMPT_TEMPLATE = [
8
10
  {
9
11
  role: "system",
@@ -60,17 +62,14 @@ module SummarizeMeeting
60
62
  attr_reader :transcript
61
63
 
62
64
  def summarize
63
-
64
65
  # Step 1. Split the transcript into lines.
65
- lines = transcript.split("\n")
66
+ lines = transcript.lines
66
67
 
67
68
  # Step 2. Calculate the maximum chunk size in words.
68
- max_total_tokens = 4000
69
- response_token_reserve = 500
70
- template_tokens = LINE_SUMMARY_PROMPT_TEMPLATE.map { |line| line[:content].split.size }.sum
71
- max_chunk_tokens = max_total_tokens - response_token_reserve - template_tokens
72
- words_per_token = 0.7
73
- max_chunk_word_count = max_chunk_tokens * words_per_token
69
+ template_word_count = LINE_SUMMARY_PROMPT_TEMPLATE.map { |line| line[:content].split.size }.sum
70
+ template_token_count = SummarizeMeeting::Ai.calculate_word_token_count(template_word_count)
71
+ max_chunk_token_count = SummarizeMeeting::Ai::MAX_TOTAL_TOKENS - RESPONSE_RESERVE_TOKENS - template_token_count
72
+ max_chunk_word_count = SummarizeMeeting::Ai.calculate_token_word_count(max_chunk_token_count)
74
73
 
75
74
  # Step 3. Split the transcript into equally sized chunks.
76
75
  chunks = split_lines_into_equal_size_chunks(lines, max_chunk_word_count)
@@ -86,27 +85,14 @@ module SummarizeMeeting
86
85
  consolidated_template = CONSOLIDATED_SUMMARY_PROMPT_TEMPLATE
87
86
  prompt = Mustache.render(consolidated_template.to_json, { notes: previous_chunks_summary.to_json })
88
87
  messages = JSON.parse(prompt)
89
- response = SummarizeMeeting::Ai.client.chat(
90
- parameters: {
91
- model: "gpt-3.5-turbo",
92
- messages: messages,
93
- }
94
- )
95
- response.dig("choices", 0, "message", "content")
88
+ SummarizeMeeting::Ai.chat(messages: messages)
96
89
  end
97
90
 
98
91
  def summarize_chunk(chunk, chunk_index, chunk_count, previous_chunks_summary)
99
92
  template = LINE_SUMMARY_PROMPT_TEMPLATE
100
93
  prompt = Mustache.render(template.to_json, { chunkCount: chunk_count, chunkIndex: chunk_index + 1, chunk: chunk.join("\n").to_json })
101
94
  messages = JSON.parse(prompt)
102
-
103
- response = SummarizeMeeting::Ai.client.chat(
104
- parameters: {
105
- model: "gpt-3.5-turbo",
106
- messages: messages,
107
- }
108
- )
109
- response.dig("choices", 0, "message", "content")
95
+ SummarizeMeeting::Ai.chat(messages: messages)
110
96
  end
111
97
 
112
98
  def split_lines_into_equal_size_chunks(lines, max_chunk_word_count)
@@ -1,3 +1,3 @@
1
1
  module SummarizeMeeting
2
- VERSION = "0.2.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -3,4 +3,4 @@ require_relative "./summarize-meeting/ai"
3
3
  require_relative "./summarize-meeting/meeting"
4
4
 
5
5
  module SummarizeMeeting
6
- end
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: summarize-meeting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Devine
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-03 00:00:00.000000000 Z
11
+ date: 2023-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: optparse