APIを使った開発が初めての方も、このガイド读完すればSSE(Server-Sent Events)を使ったリアルタイム通信を完全に理解できるようになります。HolyShehe AIでは、レートが¥1=$1(公式¥7.3=$1比85%節約)で、登録時に無料クレジットを獲得できます。

SSE(Server-Sent Events)とは?

SSEは、服务器からクライアントへリアルタイムでデータを送り続ける技術です。従来のHTTPリクエスト不同的是、接続を开后したまま随时数据を送信できます。

このような場面で使えます

前提条件

このガイドでは以下のものを使います:

JavaScriptでの実装(ブラウザ編)

まずはブラウザで動くシンプルなストリーミングデモを作りましょう。HTMLファイルを作成して以下のコードを貼り付けてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>HolySheep AI Streaming Demo</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
        #output { 
            background: #f5f5f5; 
            padding: 20px; 
            border-radius: 8px; 
            min-height: 200px;
            white-space: pre-wrap;
        }
        button { 
            background: #4CAF50; 
            color: white; 
            padding: 15px 30px; 
            border: none; 
            border-radius: 5px; 
            cursor: pointer;
            font-size: 16px;
        }
        button:hover { background: #45a049; }
    </style>
</head>
<body>
    <h1>🤖 HolySheep AI Streaming Demo</h1>
    <textarea id="prompt" rows="3" style="width: 100%; margin: 10px 0;" placeholder="質問を入力してください...">日本の四季について教えてください</textarea>
    <button onclick="startStreaming()">Stream Start(ストリーミング開始)</button>
    <div id="output"></div>

    <script>
        async function startStreaming() {
            const output = document.getElementById('output');
            const prompt = document.getElementById('prompt').value;
            
            // HolySheep AI API endpoint
            const baseUrl = 'https://api.holysheep.ai/v1';
            
            output.textContent = '接続中...\n';

            try {
                const response = await fetch(${baseUrl}/chat/completions, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
                    },
                    body: JSON.stringify({
                        model: 'gpt-4o-mini',
                        messages: [
                            { role: 'user', content: prompt }
                        ],
                        stream: true  // ★重要:streamをtrueに設定
                    })
                });

                if (!response.ok) {
                    throw new Error(HTTPエラー: ${response.status});
                }

                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let fullResponse = '';

                output.textContent = '応答中...\n';

                while (true) {
                    const { done, value } = await reader.read();
                    if (done) break;

                    const chunk = decoder.decode(value);
                    // SSE形式を解析(data: {...} 行を処理)
                    const lines = chunk.split('\n');
                    
                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            const data = line.slice(6);
                            if (data === '[DONE]') {
                                console.log('ストリーミング完了');
                                return;
                            }
                            try {
                                const parsed = JSON.parse(data);
                                const content = parsed.choices?.[0]?.delta?.content;
                                if (content) {
                                    fullResponse += content;
                                    output.textContent = fullResponse;
                                }
                            } catch (e) {
                                // JSON解析エラーは無視(途中のデータ対応)
                            }
                        }
                    }
                }

            } catch (error) {
                output.textContent = エラー発生: ${error.message};
                console.error('ストリーミングエラー:', error);
            }
        }
    </script>
</body>
</html>

ポイント解説:

Pythonでの実装(リクエストライブラリ)

バックエンドでPythonを使う場合、以下のコードでストリーミングを実装できます。HolySheep AIのAPIは下延迟<50ms的超低延迟特点があります。

import requests
import json

HolySheep AI API設定

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY" def stream_chat(): """ストリーミングチャットデモ""" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "PythonでのSSEストリーミングの実装方法を教えて"} ], "stream": True # ★ストリーミングモードON } print("🤖 HolySheep AI 接続中...\n") try: # POSTリクエストを送信(SSE用的是EventSource形式) response = requests.post( f"{BASE_URL}/chat/completions", headers=headers, json=payload, stream=True # ★重要:stream=True必须设置 ) response.raise_for_status() full_response = "" # 逐行読み取り for line in response.iter_lines(): if line: # SSE格式: "data: {...}" line_text = line.decode('utf-8') if line_text.startswith('data: '): data_content = line_text[6:] # 移除 "data: " 前缀 if data_content == '[DONE]': print("\n\n✅ ストリーミング完了!") break try: data = json.loads(data_content) # 提取内容片段 delta = data.get('choices', [{}])[0].get('delta', {}) content = delta.get('content', '') if content: print(content, end='', flush=True) full_response += content except json.JSONDecodeError: # JSON解析エラーは無視 pass print(f"\n\n📊 合計文字数: {len(full_response)}") except requests.exceptions.RequestException as e: print(f"❌ リクエストエラー: {e}") if __name__ == "__main__": stream_chat()

Pythonでの実装(aiohttp版:异步并发处理)

より高度な実装として、aiohttpを使った非同期バージョンも紹介します。複数の同時ストリームを管理する場合に有効です。

import aiohttp
import asyncio
import json

BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"

async def stream_chat_async(session, prompt: str):
    """非同期ストリーミング関数"""
    
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    
    payload = {
        "model": "gpt-4o-mini",
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "stream": True
    }
    
    try:
        async with session.post(
            f"{BASE_URL}/chat/completions",
            headers=headers,
            json=payload
        ) as response:
            
            full_response = ""
            
            async for line in response.content:
                line_text = line.decode('utf-8').strip()
                
                if line_text.startswith('data: '):
                    data_content = line_text[6:]
                    
                    if data_content == '[DONE]':
                        break
                    
                    try:
                        data = json.loads(data_content)
                        content = data.get('choices', [{}])[0].get('delta', {}).get('content', '')
                        
                        if content:
                            print(content, end='', flush=True)
                            full_response += content
                            
                    except json.JSONDecodeError:
                        pass
            
            return full_response
            
    except aiohttp.ClientError as e:
        print(f"接続エラー: {e}")
        return None

async def main():
    """メイン関数:複数同時リクエスト"""
    
    async with aiohttp.ClientSession() as session:
        # 同時実行したい質問リスト
        tasks = [
            stream_chat_async(session, "AI的好处是什么?"),
            stream_chat_async(session, "请介绍一下你自己"),
        ]
        
        # asyncio.gatherで並列実行
        results = await asyncio.gather(*tasks)
        
        print(f"\n\n✅ {len(results)}件の応答を完了")

if __name__ == "__main__":
    asyncio.run(main())

SSEプロトコルの详细说明

SSE响应数据的格式如下:

data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1234567890,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}

data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1234567890,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"content":","},"finish_reason":null}]}

data: [DONE]

每行的结构:

実践例:聊天应用の構築

ここからは实际のアプリケーションに組み込む方法を説明します。React + Node.jsの構成で完全なチャットUIを作成します。

バックエンド(Node.js/Express)

const express = require('express');
const fetch = require('node-fetch');
const app = express();

app.use(express.json());

// HolySheep AI API設定
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const API_KEY = process.env.HOLYSHEEP_API_KEY || 'YOUR_HOLYSHEEP_API_KEY';

app.post('/api/chat', async (req, res) => {
    const { message, history = [] } = req.body;
    
    // SSEヘッダー設定
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('Access-Control-Allow-Origin', '*');
    
    try {
        const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
            method: 'POST',
            headers: {
                'Authorization': Bearer ${API_KEY},
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: 'gpt-4o-mini',
                messages: [
                    ...history.map(h => ({ role: h.role, content: h.content })),
                    { role: 'user', content: message }
                ],
                stream: true
            })
        });
        
        // ストリームをリアルタイムで転送
        for await (const chunk of response.body) {
            res.write(chunk);
        }
        
        res.write('data: [DONE]\n\n');
        res.end();
        
    } catch (error) {
        console.error('APIエラー:', error);
        res.status(500).json({ error: '内部サーバーエラー' });
    }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(🚀 サーバー起動: http://localhost:${PORT});
});

フロントエンド(React)

import React, { useState } from 'react';

function ChatApp() {
    const [messages, setMessages] = useState([]);
    const [input, setInput] = useState('');
    const [isStreaming, setIsStreaming] = useState(false);

    const sendMessage = async () => {
        if (!input.trim() || isStreaming) return;
        
        const userMessage = { role: 'user', content: input };
        setMessages(prev => [...prev, userMessage]);
        setInput('');
        setIsStreaming(true);
        
        // _assistant用の临时状态
        const assistantMessage = { role: 'assistant', content: '' };
        setMessages(prev => [...prev, assistantMessage]);
        
        try {
            const response = await fetch('/api/chat', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    message: input,
                    history: messages
                })
            });
            
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            let fullContent = '';
            
            while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                
                const chunk = decoder.decode(value);
                const lines = chunk.split('\n');
                
                for (const line of lines) {
                    if (line.startsWith('data: ')) {
                        const data = line.slice(6);
                        if (data === '[DONE]') {
                            setIsStreaming(false);
                            return;
                        }
                        
                        try {
                            const parsed = JSON.parse(data);
                            const content = parsed.choices?.[0]?.delta?.content;
                            
                            if (content) {
                                fullContent += content;
                                // 最後のメッセージをリアルタイム更新
                                setMessages(prev => {
                                    const updated = [...prev];
                                    updated[updated.length - 1] = {
                                        ...updated[updated.length - 1],
                                        content: fullContent
                                    };
                                    return updated;
                                });
                            }
                        } catch (e) {}
                    }
                }
            }
        } catch (error) {
            console.error('エラー:', error);
        }
        
        setIsStreaming(false);
    };

    return (
        <div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
            <h1>🤖 HolySheep AI Chat</h1>
            <div style={{ height: '400px', overflowY: 'auto', border: '1px solid #ccc', padding: '10px' }}>
                {messages.map((msg, i) => (
                    <div key={i} style={{ 
                        textAlign: msg.role === 'user' ? 'right' : 'left',
                        margin: '10px 0'
                    }}>
                        <strong>{msg.role === 'user' ? 'あなた' : 'AI'}: </strong>
                        {msg.content}
                    </div>
                ))}
            </div>
            <div style={{ marginTop: '10px' }}>
                <input
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                    onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
                    disabled={isStreaming}
                    style={{ width: '80%', padding: '10px' }}
                />
                <button onClick={sendMessage} disabled={isStreaming} style={{ padding: '10px 20px' }}>
                    {isStreaming ? '送信中...' : '送信'}
                </button>
            </div>
        </div>
    );
}

export default ChatApp;

よくあるエラーと対処法

実装中に遭遇する可能性があるエラーとその解决方案をまとめました。

エラー1: CORSポリシーエラー

// ❌ エラー内容
Access to fetch at 'https://api.holysheep.ai/v1/chat/completions' 
from origin 'http://localhost:3000' has been blocked by CORS policy

// ✅ 解決方法
// ブラウザから直接APIを呼ぶ場合は、バックエンドプロキシを使用

// Expressサーバーの設定に以下を追加
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    if (req.method === 'OPTIONS') {
        return res.sendStatus(200);
    }
    next();
});

エラー2: Streamモードが無効

// ❌ エラー内容
{
    "error": {
        "message": "Invalid request: stream option required for streaming",
        "type": "invalid_request_error",
        "code": "stream_required"
    }
}

// ✅ 解決方法
// payloadにstream: trueを追加

const payload = {
    model: 'gpt-4o-mini',
    messages: [{ role: 'user', content: 'こんにちは' }],
    stream: true  // ★これを必ず含める
};

// またはfetch.thenでエラー処理
fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify({
        // ...
        stream: true  // 大文字ではなく小文字
    })
})

エラー3: JSON解析エラー(途中のデータ)

// ❌ エラー内容
JSON.parse error: Unexpected end of JSON input

// ✅ 解決方法
// SSEのchunkは途中で切れる場合があるため、try-catchで包む

async function parseStream(response) {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';  // バッファを使って途中データ不退不失
    
    while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split('\n');
        buffer = lines.pop() || '';  // 最後の不完全な行を保持
        
        for (const line of lines) {
            if (line.startsWith('data: ')) {
                try {
                    const data = JSON.parse(line.slice(6));
                    if (data === '[DONE]') return;
                    // 正常なデータを処理
                    console.log(data.choices?.[0]?.delta?.content);
                } catch (e) {
                    // JSON解析エラーは無視して次へ
                    continue;
                }
            }
        }
    }
}

エラー4: API Key認証エラー

// ❌ エラー内容
{
    "error": {
        "message": "Incorrect API key provided",
        "type": "authentication_error"
    }
}

// ✅ 解決方法

// 1. ヘッダーの形式を確認(大文字小文字を正確に)
headers: {
    'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'  // Bearerが必要
}

// 2. 環境変数からの読み込みを推奨
const API_KEY = process.env.HOLYSHEEP_API_KEY;
if (!API_KEY) {
    throw new Error('HOLYSHEEP_API_KEYが設定されていません');
}

// 3. キーの先頭・末尾に空白が入っていないか確認
const cleanKey = API_KEY.trim();

エラー5: 接続超时・ネットワークエラー

// ❌ エラー内容
TypeError: Failed to fetch
net::ERR_CONNECTION_TIMED_OUT

// ✅ 解決方法(fetch APIの場合)
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 60000);  // 60秒

try {
    const response = await fetch(url, {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(payload),
        signal: controller.signal
    });
    clearTimeout(timeoutId);
    // 正常処理
} catch (error) {
    if (error.name === 'AbortError') {
        console.error('リクエストがタイムアウトしました');
    }
}

// Python (requests) の場合
import requests

response = requests.post(
    url,
    headers=headers,
    json=payload,
    stream=True,
    timeout=60  # タイムアウト設定
)