DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Simplify Authorization in Ruby on Rails With the Power of Pundit Gem
  • Buh-Bye, Webpack and Node.js; Hello, Rails and Import Maps
  • Building an Internal TLS and SSL Certificate Monitoring Agent: From Concept to Deployment
  • ArtiBot - Free Chat Bot for Lead Generation

Trending

  • AI Didn't Replace Seniors; It Just Made Them the Bottleneck
  • Why Your Test Automation Is Always Behind the Code And the Architecture That Fixes It
  • Jakarta EE 12: Entering the Data Age of Enterprise Java
  • Persistent Memory for AI Agents Using LangChain's Deep Agents
  1. DZone
  2. Coding
  3. Frameworks
  4. Text Summarization With OpenAI and Ruby on Rails

Text Summarization With OpenAI and Ruby on Rails

Learn how to build AI-powered text summarization in Ruby on Rails using OpenAI, including prompt optimization, long-document handling, and Sidekiq background jobs.

By 
Denys Kozlovskyi user avatar
Denys Kozlovskyi
·
Jun. 30, 26 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
81 Views

Join the DZone community and get the full member experience.

Join For Free

Modern applications deal with massive amounts of text — support tickets, CRM notes, blog posts, meeting transcripts, and internal documentation. The problem isn’t access to information anymore — it’s how quickly users can understand it.

In our CRM system, we allow publishing long-form articles to a blog. However, users rarely want to read everything up front.

To solve this, we introduced AI-powered summarization to generate short, readable previews.

This improves:

  • Content scanability
  • User engagement
  • Time-to-information

In this article, we consider:

  • What text summarization is
  • Why AI summarization is powerful
  • Setting up OpenAI in Rails
  • Implementing a summarization service
  • Building a controller endpoint
  • Handling long documents
  • Background processing with Sidekiq
  • Real-world use cases

What Is Text Summarization?

Text summarization is the process of condensing a large body of text into a shorter version while preserving its key information. There are two main approaches:

1. Extractive Summarization

This selects the most important sentences directly from the original text. Example:

Original: Ruby on Rails is a powerful web framework designed to make programming easier by favoring convention over configuration.

Summary: Ruby on Rails is a web framework that simplifies development.

2. Abstractive Summarization

This generates new sentences that capture the meaning of the text. This is where large language models like OpenAI shine.

Why Use LLMs for Summarization?

Traditional NLP methods struggle with context and nuance.

OpenAI models can provide:

  • Contextual understanding
  • Multi-paragraph reasoning
  • Domain adaptability
  • Natural-sounding summaries

This makes them ideal for summarizing in a project with different types of information processes:

  • Blog posts
  • Documents
  • Meeting transcripts
  • Customer feedback
  • Knowledge bases

Setting Up OpenAI in a Rails project

1. First of all, install the OpenAI Ruby Gem. Add the gem:

Ruby
 
gem "ruby-openai"


2. Configure the API key. Add your API key to environment variables:

Ruby
 
export OPENAI_API_KEY="your_api_key"


3. Example initializer:

Ruby
 
OpenAI.configure do |config|
  config.access_token = ENV["OPENAI_API_KEY"]
end


Creating a Summarization Service

In Rails, the best practice is to encapsulate OpenAI logic in a separate service object.

Simple example:

Ruby
 
module Openai
  class Summarizer
    def initialize(text)
      @text = text
      @client = OpenAI::Client.new
    end

    def call
      response = @client.chat(
        parameters: {
          model: "gpt-4.1-mini", #or you can select another one
          messages: [
            {
              role: "system",
              content: "You are a helpful assistant that summarizes text concisely." #you can define content with more detailed prompt
            },
            {
              role: "user",
              content: "Summarize the following text:\\n\\n#{@text}" #also here define more detailed expected response
            }
          ],
          temperature: 0.3
        }
      )

      response.dig("choices", 0, "message", "content")
    end
  end
end


Possible roles:

Plain Text
 
Role     Purpose
system - > instructions for the model
user - > input from the user
assistant - > previous AI responses


Usage:

Ruby
 
summary = Openai::Summarizer.new(article.content).call


Example: Before and After

Input (CRM article excerpt):
Our platform allows teams to manage projects, track time, and generate reports across multiple departments...

Output (AI summary):

  • Centralized platform for project and time tracking
  • Supports multi-department workflows
  • Provides reporting and analytics tools

This summary can be shown in:

  • Blog preview cards
  • Tooltips
  • Search results

Example Controller Endpoint

Now we expose this functionality via an API endpoint.

Controller example:

Ruby
 
class Api::SummariesController < ApplicationController
  def create
    text = params[:text]

    summary = Openai::Summarizer.new(text).call

    render json: {
      summary: summary
    }
  end
end


Temperature controls randomness in the output.

Plain Text
 
0.0 → deterministic
1.0 → very creative


Additional Useful Parameters

Also added parameters for improving summarization.

1. max_tokens: Limits the size of the generated response. Example:

Ruby
 
max_tokens: 200 #This prevents extremely long outputs.


2. top_pAlternative randomness control.

Example:

Ruby
 
top_p: 0.9 #Usually you adjust temperature or top_p, not both


3. frequency_penalty discourages repeated phrases.

Example:

Ruby
 
frequency_penalty: 0.2 #Useful when summaries become repetitive


4. presence_penalty encourages introducing new ideas.

Example:

Ruby
 
presence_penalty: 0.1 #Not usually necessary for summarization, but can be used in specific tasks


Prompt Engineering for Better Summaries and Why It Is Important

The prompt design significantly impacts the output quality. Instead of a generic prompt:

Plain Text
 
"Summarize this text"


Use structured instructions:

Plain Text
 
"Summarize the following text in 3 bullet points. Focus on the key ideas and avoid unnecessary details."


This simple change improves clarity, consistency, and usefulness of the generated summary.

In practice, prompt design becomes even more important when working with different types of content, such as technical documentation, CRM notes, etc. I wrote more about the features of Prompt Engineering on practical examples in my other article.

Example of a more structured prompt:

Ruby
 
{
  role: "user",
  content: <<~PROMPT
    Summarize the following article in 5 bullet points.

    #{@text}
  PROMPT
}


Handling Very Long Documents

LLMs have token limits, so large texts must be processed in chunks.

Typical approach looks like this:

  1. Split text into chunks
  2. Summarize each chunk
  3. Combine summaries
  4. Generate a final summary

Avoid Naive Chunking

This is not ideal:

Ruby
 
text.scan(/.{1,3000}/m)


It may cut sentences in half.

Prefer:

  • Splitting by paragraphs
  • Splitting by sentence boundaries

Text Chunking

Ruby
 
class TextChunker
  def self.chunk(text)
    text.split("\\n\\n")
  end
end


Chunk Summarization

Ruby
 
def summarize_long_text(text)
  chunks = TextChunker.chunk(text)

  partial_summaries = chunks.map do |chunk|
    Openai::Summarizer.new(chunk).call
  end

  Openai::Summarizer.new(partial_summaries.join("\\n")).call
end


Using Background Jobs for Summarization

Summarizing large text can take some time, so it’s better to process it asynchronously.

Example of our service usage with Sidekiq:

Generate Summary Job

Ruby
 
class GenerateSummaryJob
  include Sidekiq::Job

  def perform(article_id)
    article = Article.find(article_id)

    summary = Openai::Summarizer.new(article.content).call

    article.update!(summary: summary)
  end
end


Error Handling

Always assume external APIs can fail.

Ruby
 
rescueStandardError=>e
    Rails.logger.error(e.message)
    fallback_summary
end


Also consider:

  • Retries
  • Timeouts
  • Monitoring

Cost Optimization

When you use AI features in production, cost management becomes critical. depends primarily on token usage, meaning the more text you send and receive, the more you pay.

Some tips for cost optimization that you need to know:

1. Limit Input Size

The most effective optimization is reducing the amount of text sent to the AI model.

Instead of summarizing an entire document, you can:

  • Extract relevant sections
  • Summarize those sections only

Example filtering before sending to OpenAI:

Ruby
 
class TextPreprocessor
  MAX_LENGTH = 5000

  def self.clean(text)
    text.strip[0...MAX_LENGTH]
  end
end


Usage:

Ruby
 
clean_text = TextPreprocessor.clean(article.content)
summary = Openai::Summarizer.new(clean_text).call


This ensures you never send extremely large inputs.

2. Choose the Right Model

Not every task requires the most powerful model. For summarization, smaller models often perform well.

Example:

Ruby
 
model: "gpt-4.1-mini"


Advantages:

  • Much cheaper
  • Faster responses
  • Good summarization quality

So, use larger models only for complex reasoning tasks.

3. Token Counting Before Requests

Sometimes the text is larger than expected. Using a token estimation step helps prevent sending oversized prompts.

Example:

Ruby
 
def too_large?(text)
  text.length > 12000
end


If too large:

  • chunk text into smaller chunks
  • summarize in parts (chunks)

Conclusion

Throughout this article, we built a summarization pipeline in Rails using a clean service-oriented approach:

  • Simple summarization service
  • Prompt optimization
  • Chunking for large documents
  • Background processing with Sidekiq
  • Cost and reliability improvements
Ruby (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Simplify Authorization in Ruby on Rails With the Power of Pundit Gem
  • Buh-Bye, Webpack and Node.js; Hello, Rails and Import Maps
  • Building an Internal TLS and SSL Certificate Monitoring Agent: From Concept to Deployment
  • ArtiBot - Free Chat Bot for Lead Generation

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook