AI-powered applications are shifting from static responses to real-time streaming experiences. Instead of waiting seconds for a full response, users now expect results to appear instantly—token by token.
In this tutorial, you will build a real-time text summarization web app in Go that streams responses from GPT as they are generated.
By the end, you’ll have:
- A Go backend using Gin
- Real-time streaming using Server-Sent Events (SSE)
- Integration with OpenAI GPT streaming API
- A minimal frontend that updates live
What You Will Build
You will create:
User Input → Go Server → GPT Streaming API → SSE → Browser UI
The summary will appear progressively, just like ChatGPT typing.
Prerequisites
Before starting, make sure you have:
- Go 1.22 or newer
- An OpenAI API key
- Basic knowledge of:
- Go
- HTTP APIs
- JavaScript (for frontend)
Step 1: Create the Go Project
Create a new directory and initialize a Go module:
mkdir go-ai-summarizer
cd go-ai-summarizer
go mod init go-ai-summarizer
Project Structure
We’ll keep things simple:
go-ai-summarizer/
├── main.go
├── handler.go
├── openai.go
├── static/
│ └── index.html
Step 2: Install Dependencies
Install required libraries:
go get github.com/gin-gonic/gin
go get github.com/openai/openai-go
Why These Libraries?
- Gin → Fast and minimal HTTP framework
- openai-go → Official SDK with streaming support
Step 3: Create the Main Server
Create main.go:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Serve frontend
r.Static("/static", "./static")
// API route
r.GET("/summarize", StreamSummaryHandler)
r.Run(":8080")
}
What This Does
- Serves static frontend files
- Exposes
/summarizeendpoint - Runs server on port 8080
Step 4: Build the SSE Handler
Create handler.go:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func StreamSummaryHandler(c *gin.Context) {
text := c.Query("text")
if text == "" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "text query parameter is required",
})
return
}
// Set SSE headers
c.Writer.Header().Set("Content-Type", "text/event-stream")
c.Writer.Header().Set("Cache-Control", "no-cache")
c.Writer.Header().Set("Connection", "keep-alive")
c.Writer.Header().Set("Transfer-Encoding", "chunked")
streamSummary(text, c)
}
Step 5: Understand Server-Sent Events (SSE)
Before continuing, let’s clarify how SSE works.
Key Characteristics
- One-way streaming (server → client)
- Uses HTTP (no WebSocket needed)
- Browser support via
EventSource
SSE Format
Each message must follow:
data: your message here
Notice the double newline — this is critical.
Step 6: Implement OpenAI Streaming
Create openai.go:
package main
import (
"bufio"
"bytes"
"fmt"
"net/http"
"os"
"github.com/gin-gonic/gin"
)
func streamSummary(text string, c *gin.Context) {
apiKey := os.Getenv("OPENAI_API_KEY")
url := "https://api.openai.com/v1/responses"
payload := []byte(fmt.Sprintf(`{
"model": "gpt-4.1-mini",
"input": "Summarize this text:\n\n%s",
"stream": true
}`, text))
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
sendSSE(c, "ERROR: "+err.Error())
return
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
// SSE format: lines start with "data: "
if len(line) > 6 && line[:6] == "data: " {
data := line[6:]
if data == "[DONE]" {
break
}
sendSSE(c, data)
}
}
}
Step 7: Create SSE Utility Function
Add a helper function in the main.go:
func sendSSE(c *gin.Context, message string) {
fmt.Fprintf(c.Writer, "data: %s\n\n", message)
c.Writer.Flush()
}
Why Flush Is Important
Without Flush():
- Data stays buffered
- No real-time streaming happens
Step 8: Build the Frontend
Create static/index.html:
<!doctype html>
<html>
<head>
<title>AI Summarizer</title>
<style>
body {
font-family: Arial;
max-width: 800px;
margin: auto;
}
textarea {
width: 100%;
}
pre {
background: #f4f4f4;
padding: 10px;
}
</style>
</head>
<body>
<h1>Real-Time AI Summarizer</h1>
<textarea id="input" rows="10" placeholder="Paste text here..."></textarea>
<br /><br />
<button onclick="summarize()">Summarize</button>
<h2>Summary</h2>
<pre id="output"></pre>
<script>
function summarize() {
const text = document.getElementById("input").value;
const output = document.getElementById("output");
output.textContent = "";
const url = `/summarize?text=${encodeURIComponent(text)}`;
const eventSource = new EventSource(url);
eventSource.onmessage = function (event) {
output.textContent += event.data;
};
eventSource.onerror = function () {
eventSource.close();
};
}
</script>
</body>
</html>
Step 9: Run the Application
Set API Key
export OPENAI_API_KEY=your_api_key_here
Run Server
go run .
Open Browser
http://localhost:8080/static/index.html
Step 10: Testing the App
Paste a long article or paragraph and click Summarize.
You should see:
- Text appearing gradually
- No waiting for full completion
- Smooth real-time updates
Step 11: Common Pitfalls
1. No Streaming Output
Make sure:
c.Writer.Flush()
is called.
2. CORS Issues
If frontend is separate, add:
r.Use(cors.Default())
3. API Key Not Set
Check:
echo $OPENAI_API_KEY
Step 12: Enhancements
Here are ways to improve this project:
1. Switch to WebSockets
For bidirectional communication:
- Chat apps
- Interactive editing
2. Add Loading Indicator
Show the user that streaming has started.
3. Token Buffering
Improve formatting:
output.textContent += event.data + " ";
4. Rate Limiting
Prevent abuse using middleware.
5. Multi-User Sessions
Use session IDs or JWT.
6. Deploy to Production
- Use Docker
- Add HTTPS
- Deploy on:
- VPS
- Fly.io
- Railway
Step 13: Conclusion
You’ve built a real-time AI-powered summarization app in Go using:
- Gin for backend
- SSE for streaming
- OpenAI GPT streaming API
This architecture is highly reusable for:
- AI chat applications
- Live content generation
- Coding assistants
- Document analysis tools
You can find the full source code on our GitHub.
We know that building beautifully designed Mobile and Web Apps from scratch can be frustrating and very time-consuming. Check Envato unlimited downloads and save development and design time.
That's just the basics. If you need more deep learning about Go/Golang, you can take the following cheap course:
- Go - The Complete Guide
- NEW-Comprehensive Go Bootcamp with gRPC and Protocol Buffers
- Backend Master Class [Golang + Postgres + Kubernetes + gRPC]
- Complete Microservices with Go
- Backend Engineering with Go
- Introduction to AI and Machine Learning with Go (Golang)
- Working with Concurrency in Go (Golang)
- Introduction to Testing in Go (Golang)
- Design Patterns in Go
- Go Bootcamp: Master Golang with 1000+ Exercises and Projects
Thanks!
