0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring AIとOpenAIを使用したチャットアプリケーション実装

Posted at

Spring AIとOpenAIを使用したチャットアプリケーション実装

はじめに

この記事では、Spring AIとOpenAIのAPIを使用して、シンプルなチャットアプリケーションを実装する方法を説明します。Spring AIを使用することで、OpenAIのAPIを簡単に統合し、効率的なチャット機能を実装することができます。

1. プロジェクトのセットアップ

依存関係の追加

まず、build.gradleファイルに必要な依存関係を追加します:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
    implementation 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

アプリケーションの設定

application.propertiesファイルにOpenAIのAPIキーを設定します:

spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.model=gpt-3.5-turbo
spring.ai.openai.temperature=0.7

2. チャットアプリケーションの実装

チャットメッセージのモデル

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatMessage {
    private String role;
    private String content;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatRequest {
    private String message;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatResponse {
    private String response;
}

チャットサービスの実装

@Service
@Slf4j
public class ChatService {
    private final ChatClient chatClient;

    public ChatService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public ChatResponse chat(ChatRequest request) {
        try {
            String response = chatClient.prompt(request.getMessage())
                .call()
                .content();
            return new ChatResponse(response);
        } catch (Exception e) {
            log.error("チャット処理中にエラーが発生しました", e);
            throw new RuntimeException("チャット処理に失敗しました", e);
        }
    }
}

コントローラーの実装

@RestController
@RequestMapping("/api/chat")
@Slf4j
public class ChatController {
    private final ChatService chatService;

    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    @PostMapping
    public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
        log.info("チャットリクエスト受信: {}", request.getMessage());
        ChatResponse response = chatService.chat(request);
        return ResponseEntity.ok(response);
    }
}

3. 高度な機能の実装

会話履歴の保持

@Service
@Slf4j
public class ChatHistoryService {
    private final Map<String, List<ChatMessage>> conversationHistory = new ConcurrentHashMap<>();

    public void addMessage(String sessionId, ChatMessage message) {
        conversationHistory.computeIfAbsent(sessionId, k -> new ArrayList<>())
            .add(message);
    }

    public List<ChatMessage> getHistory(String sessionId) {
        return conversationHistory.getOrDefault(sessionId, new ArrayList<>());
    }
}

ストリーミングレスポンスの実装

@Service
@Slf4j
public class StreamingChatService {
    private final ChatClient chatClient;

    public StreamingChatService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public Flux<String> streamChat(String message) {
        return chatClient.prompt(message)
            .stream()
            .map(response -> response.getResult().getOutput().getContent());
    }
}

@RestController
@RequestMapping("/api/chat")
public class StreamingChatController {
    private final StreamingChatService streamingChatService;

    @PostMapping("/stream")
    public Flux<String> streamChat(@RequestBody ChatRequest request) {
        return streamingChatService.streamChat(request.getMessage());
    }
}

4. エラーハンドリング

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        log.error("予期せぬエラーが発生しました", e);
        return ResponseEntity
            .status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(new ErrorResponse("エラーが発生しました", e.getMessage()));
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
    private String message;
    private String details;
}

5. 使用例

cURLを使用したAPI呼び出し

curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "こんにちは、自己紹介をしてください"}'

ストリーミングAPIの呼び出し

curl -X POST http://localhost:8080/api/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "長い文章を生成してください"}'

6. セキュリティ考慮事項

  1. APIキーの保護

    • 環境変数での管理
    • 本番環境での適切な認証情報管理
  2. レート制限の実装

    @Service
    public class RateLimiter {
        private final Map<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();
        private static final int MAX_REQUESTS_PER_MINUTE = 60;
    
        public boolean isAllowed(String userId) {
            AtomicInteger count = requestCounts.computeIfAbsent(userId, k -> new AtomicInteger(0));
            return count.incrementAndGet() <= MAX_REQUESTS_PER_MINUTE;
        }
    }
    

まとめ

この記事では、Spring AIとOpenAIを使用したチャットアプリケーションの基本的な実装方法を説明しました。実装した機能は以下の通りです:

  • 基本的なチャット機能
  • 会話履歴の保持
  • ストリーミングレスポンス
  • エラーハンドリング
  • レート制限

これらの機能を組み合わせることで、実用的なチャットアプリケーションを構築することができます。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?