DEV Community

Phil IPS
Phil IPS

Posted on

Complete Guide: Using Gemini 3.6 Flash via Unorouter API

Complete Guide: Using Gemini 3.6 Flash via Unorouter API

A comprehensive tutorial with runnable Python code for integrating Google's free Gemini 3.6 Flash model through the Unorouter API.

Introduction

Gemini 3.6 Flash is Google's latest fast and efficient AI model, available for free through Unorouter's unified API gateway. This tutorial provides step-by-step instructions and complete Python code examples for text generation, chat completion, and streaming responses.

Prerequisites

  • Python 3.8 or higher
  • requests library: pip install requests
  • Unorouter account (free at unorouter.com)
  • API key from your Unorouter dashboard

Quick Start: Basic Text Generation

import requests
import os
from typing import Optional

# Configuration
UNOROUTER_BASE_URL = "https://api.unorouter.com/v1"
MODEL = "google/gemini-3.6-flash:free"

class GeminiClient:
    """Client for interacting with Gemini 3.6 Flash via Unorouter."""

    def __init__(self, api_key: Optional[str] = None):
        self.api_key = api_key or os.getenv("UNOROUTER_API_KEY")
        if not self.api_key:
            raise ValueError("API key required. Set UNOROUTER_API_KEY environment variable.")

        self.headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        self.url = f"{UNOROUTER_BASE_URL}/chat/completions"

    def generate(self, 
                 prompt: str, 
                 temperature: float = 0.7,
                 max_tokens: int = 1000,
                 system_prompt: Optional[str] = None) -> str:
        """Generate text completion."""
        messages = []
        if system_prompt:
            messages.append({"role": "system", "content": system_prompt})
        messages.append({"role": "user", "content": prompt})

        data = {
            "model": MODEL,
            "messages": messages,
            "temperature": temperature,
            "max_tokens": max_tokens
        }

        response = requests.post(self.url, headers=self.headers, json=data, timeout=30)
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]

# Usage Example
if __name__ == "__main__":
    client = GeminiClient()

    # Simple text generation
    prompt = "Write a Python function to calculate fibonacci numbers"
    result = client.generate(prompt)
    print(f"Prompt: {prompt}")
    print(f"Response:\n{result}")
Enter fullscreen mode Exit fullscreen mode

Advanced Features

Streaming Responses for Real-Time Output

import json

def stream_generate(self, prompt: str, system_prompt: Optional[str] = None):
    """Stream text generation for real-time display."""
    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})

    data = {
        "model": MODEL,
        "messages": messages,
        "temperature": 0.7,
        "max_tokens": 1000,
        "stream": True
    }

    response = requests.post(
        self.url, 
        headers=self.headers, 
        json=data, 
        timeout=30,
        stream=True
    )
    response.raise_for_status()

    for line in response.iter_lines():
        if line:
            line = line.decode('utf-8')
            if line.startswith('data: '):
                line = line[6:]
                if line.strip() == '[DONE]':
                    break
                try:
                    chunk = json.loads(line)
                    content = chunk["choices"][0]["delta"].get("content", "")
                    if content:
                        print(content, end="", flush=True)
                except:
                    pass
    print()

# Add to class
GeminiClient.stream = stream_generate

# Usage
client.stream("Write a short story about a robot learning to paint")
Enter fullscreen mode Exit fullscreen mode

Multi-Turn Conversations

class ChatSession:
    """Maintains conversation context across multiple turns."""

    def __init__(self, client: GeminiClient, system_prompt: Optional[str] = None):
        self.client = client
        self.messages = []
        if system_prompt:
            self.messages.append({"role": "system", "content": system_prompt})

    def send(self, user_message: str) -> str:
        self.messages.append({"role": "user", "content": user_message})

        data = {
            "model": MODEL,
            "messages": self.messages,
            "temperature": 0.7,
            "max_tokens": 1000
        }

        response = requests.post(self.client.url, headers=self.client.headers, json=data, timeout=30)
        response.raise_for_status()

        reply = response.json()["choices"][0]["message"]["content"]
        self.messages.append({"role": "assistant", "content": reply})
        return reply

    def get_history(self) -> list:
        return self.messages

# Usage
client = GeminiClient()
chat = ChatSession(client, "You are a helpful Python tutor.")

print(chat.send("How do I read a JSON file in Python?"))
print(chat.send("Can you show me with error handling?"))
print(chat.send("What about writing JSON files?"))
Enter fullscreen mode Exit fullscreen mode

Error Handling & Rate Limiting

import time
from functools import wraps

def retry_on_rate_limit(max_retries: int = 3, base_delay: float = 2.0):
    """Decorator for handling rate limits with exponential backoff."""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except requests.exceptions.HTTPError as e:
                    if e.response.status_code in (429, 503):
                        delay = base_delay ** attempt
                        print(f"Rate limited. Waiting {delay}s... (attempt {attempt + 1}/{max_retries})")
                        time.sleep(delay)
                    else:
                        raise
            raise Exception(f"Max retries ({max_retries}) exceeded")
        return wrapper
    return decorator

# Apply to generate method
@retry_on_rate_limit(max_retries=3)
def robust_generate(self, prompt: str, **kwargs) -> str:
    return self.generate(prompt, **kwargs)

GeminiClient.robust_generate = robust_generate
Enter fullscreen mode Exit fullscreen mode

Complete Working Example

Save this as gemini_demo.py and run it:

#!/usr/bin/env python3
"""
Complete Gemini 3.6 Flash Demo via Unorouter
Run: python gemini_demo.py
"""

import os
import requests
import json
import time
from typing import Optional

# ============== CONFIGURATION ==============
UNOROUTER_BASE_URL = "https://api.unorouter.com/v1"
MODEL = "google/gemini-3.6-flash:free"
API_KEY = os.getenv("UNOROUTER_API_KEY")

if not API_KEY:
    print("ERROR: Please set UNOROUTER_API_KEY environment variable")
    print("Get your free key at: https://unorouter.com")
    exit(1)

# ============== CLIENT CLASS ==============
class GeminiClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        self.url = f"{UNOROUTER_BASE_URL}/chat/completions"

    def generate(self, prompt: str, temperature: float = 0.7, max_tokens: int = 1000) -> str:
        data = {
            "model": MODEL,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": temperature,
            "max_tokens": max_tokens
        }
        response = requests.post(self.url, headers=self.headers, json=data, timeout=30)
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]

    def stream(self, prompt: str):
        data = {
            "model": MODEL,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.7,
            "max_tokens": 1000,
            "stream": True
        }
        response = requests.post(self.url, headers=self.headers, json=data, timeout=30, stream=True)
        response.raise_for_status()

        for line in response.iter_lines():
            if line:
                line = line.decode('utf-8')
                if line.startswith('data: '):
                    line = line[6:]
                    if line.strip() == '[DONE]':
                        break
                    try:
                        chunk = json.loads(line)
                        content = chunk["choices"][0]["delta"].get("content", "")
                        if content:
                            print(content, end="", flush=True)
                    except:
                        pass
        print()

# ============== DEMO FUNCTIONS ==============
def demo_basic_generation(client: GeminiClient):
    print("=" * 60)
    print("DEMO 1: Basic Text Generation")
    print("=" * 60)
    prompt = "Explain decorators in Python in 3 sentences"
    print(f"Prompt: {prompt}\n")
    result = client.generate(prompt)
    print(f"Response:\n{result}\n")

def demo_streaming(client: GeminiClient):
    print("=" * 60)
    print("DEMO 2: Streaming Response")
    print("=" * 60)
    prompt = "Write a haiku about coding"
    print(f"Prompt: {prompt}\nResponse: ")
    client.stream(prompt)
    print()

def demo_code_generation(client: GeminiClient):
    print("=" * 60)
    print("DEMO 3: Code Generation")
    print("=" * 60)
    prompt = """Write a complete Python class for a simple REST API client with:
    - GET, POST, PUT, DELETE methods
    - Automatic JSON handling
    - Error handling with retries
    - Type hints"""
    print(f"Prompt: {prompt}\n")
    result = client.generate(prompt, temperature=0.5, max_tokens=1500)
    print(f"Response:\n{result}\n")

def demo_creative_writing(client: GeminiClient):
    print("=" * 60)
    print("DEMO 4: Creative Writing")
    print("=" * 60)
    prompt = "Write a micro-fiction story (100 words) about an AI that discovers it can dream"
    print(f"Prompt: {prompt}\n")
    result = client.generate(prompt, temperature=0.9, max_tokens=500)
    print(f"Response:\n{result}\n")

# ============== MAIN ==============
if __name__ == "__main__":
    print("Gemini 3.6 Flash via Unorouter - Complete Demo")
    print("=" * 60)

    client = GeminiClient(API_KEY)

    demo_basic_generation(client)
    demo_streaming(client)
    demo_code_generation(client)
    demo_creative_writing(client)

    print("=" * 60)
    print("All demos completed successfully!")
    print("=" * 60)
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Secure API Keys: Use environment variables, never hardcode
  2. Handle Rate Limits: Implement exponential backoff (shown above)
  3. Set Timeouts: Prevent hanging requests (30s recommended)
  4. Use Appropriate Temperatures:
    • 0.3-0.5 for code/factual tasks
    • 0.7-0.9 for creative writing
  5. Monitor Token Usage: Free tier has limits
  6. Cache Responses: During development to save API calls

Troubleshooting

Error Solution
401 Unauthorized Check API key is correct and set in environment
429 Too Many Requests Implement backoff, reduce request frequency
503 Service Unavailable Wait and retry, service may be temporarily overloaded
Timeout Increase timeout, check network connectivity

Conclusion

The Unorouter API with Gemini 3.6 Flash provides a powerful, free way to integrate AI text generation into your Python applications. With the examples above, you can build chatbots, content generators, code assistants, and more - all without any API costs.

Next Steps:

  • Experiment with different prompts and temperatures
  • Build a CLI tool or web app using this client
  • Explore other free models available on Unorouter
  • Add conversation memory for chat applications

Published as part of the AI Tutorials series on Dev.to

Top comments (0)