[AIWriteSupporter] Java Spring Framework Server Example

Sample Spring controllers that proxy AI requests for the plugin.

Text AI

GPT

import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Mono;
import java.io.*;

@RestController
public class GPTController {
    private static final String GPT_API_URL = "https://api.openai.com/v1/chat/completions";
    private static final String GPT_API_KEY = "API key";

    @PostMapping("/requestGPT")
    public SseEmitter requestGPT(@RequestBody String json) throws IOException {
        SseEmitter emitter = new SseEmitter((long)(5 * 60 * 1000));
        WebClient client = WebClient.create(GPT_API_URL);
        client.post()
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", GPT_API_KEY))   // OpenAI
            // .header("Api-Key", GPT_API_KEY)                                  // Azure OpenAI
            .body(BodyInserters.fromValue(json))
            .exchangeToFlux(response -> {
                if (response.statusCode().equals(HttpStatus.OK)) {
                    return response.bodyToFlux(String.class);
                } else {
                    return response.createException().flatMapMany(Mono::error);
                }
            })
            .doOnNext(line -> {
                try { emitter.send(SseEmitter.event().data(line)); }
                catch (IOException e) { throw new RuntimeException(e); }
            })
            .doOnError(emitter::completeWithError)
            .doOnComplete(emitter::complete)
            .subscribe();
        return emitter;
    }
}

Gemini

import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Mono;
import java.io.*;

@RestController
public class GeminiController {
    private static final String GEMINI_API_URL    = "";  // e.g. 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:streamGenerateContent'
    private static final String GEMINI_API_PARAM  = "";  // e.g. 'alt=sse&'
    private static final String GEMINI_API_KEY    = "";
    private static final String urlWithParam =
        GEMINI_API_URL + "?" + GEMINI_API_PARAM + "key=" + GEMINI_API_KEY;

    @PostMapping("/requestGemini")
    public SseEmitter requestGemini(@RequestBody String json) throws IOException {
        SseEmitter emitter = new SseEmitter((long)(5 * 60 * 1000));
        WebClient client = WebClient.create(urlWithParam);
        client.post()
            .header("Content-Type", "application/json")
            .header("Authorization", "text/json")
            .body(BodyInserters.fromValue(json))
            .exchangeToFlux(response -> {
                if (response.statusCode().equals(HttpStatus.OK)) {
                    return response.bodyToFlux(String.class);
                } else {
                    return response.createException().flatMapMany(Mono::error);
                }
            })
            .doOnNext(line -> {
                try { emitter.send(SseEmitter.event().data(line)); }
                catch (IOException e) { throw new RuntimeException(e); }
            })
            .doOnError(emitter::completeWithError)
            .doOnComplete(emitter::complete)
            .subscribe();
        return emitter;
    }
}

Image AI — DALL·E

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.*;

@RestController
public class DalleController {
    private static final String DALLE_API_URL = "https://api.openai.com/v1/images/generations";
    private static final String DALLE_API_KEY = "API key";

    private final RestTemplate restTemplate = new RestTemplate();
    private final ObjectMapper objectMapper = new ObjectMapper();

    @PostMapping("/requestDalle")
    public ResponseEntity<Map<String, Object>> requestDalle(@RequestBody Map<String, Object> json) throws IOException {
        String requestBody = objectMapper.writeValueAsString(json);

        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        headers.set("Authorization", String.format("Bearer %s", DALLE_API_KEY));
        HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);

        String responseJson = restTemplate.exchange(DALLE_API_URL, HttpMethod.POST, requestEntity, String.class).getBody();
        JsonNode responseNode = objectMapper.readTree(responseJson);

        long createdId = responseNode.path("created").asLong();
        JsonNode dataNode = responseNode.path("data").get(0);
        String base64Json = dataNode.path("b64_json").asText();

        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("created", createdId);
        resultMap.put("data", List.of(Map.of("b64_json", base64Json)));

        return ResponseEntity.ok(resultMap);
    }
}