Class: OllamaChat::FollowChat

Inherits:
Object
  • Object
show all
Includes:
Ollama, Ollama::Handlers::Concern, MessageFormat, Term::ANSIColor
Defined in:
lib/ollama_chat/follow_chat.rb

Overview

A class that handles chat responses and manages the flow of conversation between the user and Ollama models.

This class is responsible for processing Ollama API responses, updating message history, displaying formatted output to the terminal, and managing voice synthesis for spoken responses. It acts as a handler for streaming responses and ensures proper formatting and display of both regular content and thinking annotations.

Examples:

Processing a chat response

follow_chat = OllamaChat::FollowChat.new(chat: chat_instance, messages: message_list)
follow_chat.call(response)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageFormat

#message_type, #talk_annotate, #think_annotate

Constructor Details

#initialize(chat:, messages:, voice: nil, output: STDOUT) ⇒ OllamaChat::FollowChat

Initializes a new instance of OllamaChat::FollowChat.

conversation context. conversation history. should be printed. Defaults to STDOUT.

Parameters:

  • chat (OllamaChat::Chat)

    The chat object, which represents the

  • messages (#to_a)

    A collection of message objects, representing the

  • voice (String) (defaults to: nil)

    (optional) to speek with if any.

  • output (IO) (defaults to: STDOUT)

    (optional) The output stream where terminal output



30
31
32
33
34
35
36
37
# File 'lib/ollama_chat/follow_chat.rb', line 30

def initialize(chat:, messages:, voice: nil, output: STDOUT)
  super(output:)
  @chat        = chat
  @output.sync = true
  @say         = voice ? Handlers::Say.new(voice:) : NOP
  @messages    = messages
  @user        = nil
end

Instance Attribute Details

#messagesOllamaChat::MessageList<Ollama::Message> (readonly)

Returns the conversation history (an array of message objects).

the conversation.

Returns:



43
44
45
# File 'lib/ollama_chat/follow_chat.rb', line 43

def messages
  @messages
end

Instance Method Details

#call(response) ⇒ OllamaChat::FollowChat

Invokes the chat flow based on the provided Ollama server response.

The response is expected to be a parsed JSON object containing information about the user input and the assistant’s response.

If the response indicates an assistant message, this method:

1. Ensures that an assistant response exists in the message history (if
   not already present).
2. Updates the last message with the new content and thinking (if
   applicable).
3. Displays the formatted terminal output for the user.
4. Outputs the voice response (if configured).

Regardless of whether an assistant message is present, this method also outputs evaluation statistics (if applicable).

server.

Parameters:

  • response (Ollama::Response)

    The parsed JSON response from the Ollama

Returns:



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/ollama_chat/follow_chat.rb', line 65

def call(response)
  debug_output(response)

  if response&.message&.role == 'assistant'
    ensure_assistant_response_exists
    update_last_message(response)
    display_formatted_terminal_output
    @say.call(response)
  end

  output_eval_stats(response)

  self
end

#debug_output(response) ⇒ Object (private)

The debug_output method conditionally outputs the response object using jj when debugging is enabled.

Parameters:

  • response (Object)

    the response object to be outputted



176
177
178
# File 'lib/ollama_chat/follow_chat.rb', line 176

def debug_output(response)
  @chat.debug and jj response
end

#display_formatted_terminal_outputObject (private)

The display_formatted_terminal_output method formats and outputs the terminal content by processing the last message’s content and thinking, then prints it to the output. It handles markdown parsing and annotation based on chat settings, and ensures proper formatting with clear screen and move home commands. The method takes into account whether markdown and thinking modes are enabled to determine how to process and display the content.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ollama_chat/follow_chat.rb', line 121

def display_formatted_terminal_output
  content, thinking = @messages.last.content, @messages.last.thinking
  if @chat.markdown.on?
    content = talk_annotate { @chat.kramdown_ansi_parse(content) }
    if @chat.think.on?
      thinking = think_annotate { @chat.kramdown_ansi_parse(content) }
    end
  else
    content = talk_annotate { content }
    @chat.think.on? and thinking = think_annotate { @messages.last.thinking.full? }
  end
  @output.print(*([
    clear_screen, move_home, @user, ?\n, thinking, content
  ].compact))
end

#ensure_assistant_response_existsObject (private)

The ensure_assistant_response_exists method ensures that the last message in the conversation is from the assistant role.

If the last message is not from an assistant, it adds a new assistant message with empty content and optionally includes thinking content if the chat’s think mode is enabled. It also updates the user display variable to reflect the assistant’s message type and styling.



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/ollama_chat/follow_chat.rb', line 89

def ensure_assistant_response_exists
  if @messages&.last&.role != 'assistant'
    @messages << Message.new(
      role: 'assistant',
      content: '',
      thinking: ('' if @chat.think.on?)
    )
    @user = message_type(@messages.last.images) + " " +
      bold { color(111) { 'assistant:' } }
  end
end

#eval_stats(response) ⇒ String (private)

The eval_stats method processes response statistics and formats them into a colored, readable string output.

the evaluation process including durations, counts, and rates, styled with colors and formatting

Parameters:

  • response (Object)

    the response object containing evaluation metrics

Returns:

  • (String)

    a formatted string with statistical information about



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/ollama_chat/follow_chat.rb', line 145

def eval_stats(response)
  eval_duration        = response.eval_duration / 1e9
  prompt_eval_duration = response.prompt_eval_duration / 1e9
  stats_text = {
    eval_duration:        Tins::Duration.new(eval_duration),
    eval_count:           response.eval_count.to_i,
    eval_rate:            bold { "%.2f t/s" % (response.eval_count.to_i / eval_duration) } + color(111),
    prompt_eval_duration: Tins::Duration.new(prompt_eval_duration),
    prompt_eval_count:    response.prompt_eval_count.to_i,
    prompt_eval_rate:     bold { "%.2f t/s" % (response.prompt_eval_count.to_i / prompt_eval_duration) } + color(111),
    total_duration:       Tins::Duration.new(response.total_duration / 1e9),
    load_duration:        Tins::Duration.new(response.load_duration / 1e9),
  }.map { _1 * ?= } * ' '
  '📊 ' + color(111) {
    Kramdown::ANSI::Width.wrap(stats_text, percentage: 90).gsub(/(?<!\A)^/, '   ')
  }
end

#output_eval_stats(response) ⇒ Object (private)

The output_eval_stats method outputs evaluation statistics to the specified output stream.

Parameters:

  • response (Object)

    the response object containing evaluation data



167
168
169
170
# File 'lib/ollama_chat/follow_chat.rb', line 167

def output_eval_stats(response)
  response.done or return
  @output.puts "", eval_stats(response)
end

#update_last_message(response) ⇒ Object (private)

The update_last_message method appends the content of a response to the last message in the conversation. It also appends thinking content to the last message if thinking is enabled and thinking content is present.

and thinking

Parameters:

  • response (Object)

    the response object containing message content



107
108
109
110
111
112
# File 'lib/ollama_chat/follow_chat.rb', line 107

def update_last_message(response)
  @messages.last.content << response.message&.content
  if @chat.think.on? and response_thinking = response.message&.thinking.full?
    @messages.last.thinking << response_thinking
  end
end