Skip to content

Commit 1b33824

Browse files
author
Raman Kumar
committed
Introducing ChatClient api.
1 parent 5c5953b commit 1b33824

8 files changed

Lines changed: 256 additions & 130 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
hs_err_pid*
2424
replay_pid*
2525

26-
.idea
26+
.idea/
2727
/ai-swagger-spring-boot-starter/.mvn/
2828
/ai-swagger-spring-boot-starter/mvnw
2929
/ai-swagger-spring-boot-starter/mvnw.cmd
@@ -33,4 +33,3 @@ replay_pid*
3333
/ai-swagger-helper-starter/.mvn/
3434
/ai-swagger-helper-starter/ai-swagger-helper-starter.iml
3535
/ai-swagger-helper-starter/mvnw.cmd
36-
/.idea/

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# 🚀 AI Dev Tools for Spring Boot
2+
3+
A collection of **AI-powered Spring Boot starters** focused on **enhancing developer experience (DX)** during local development and testing.
4+
5+
This repository contains production-grade tooling ideas that integrate deeply with the Spring ecosystem to help developers:
6+
- Fix APIs faster
7+
- Reduce repetitive work
8+
- Improve development experience during local runs
9+
10+
> 🎯 **Goal**: Build AI-assisted developer tooling, not end-user applications.
11+
12+
---
13+
14+
## 📦 Repository Structure
15+
16+
This is a **multi-module Maven project** with a shared parent POM.
17+
```
18+
ai-dev-tools
19+
├── .github/workflows
20+
├── LICENCE
21+
├── pom.xml # Parent POM
22+
├── ai-swagger-helper-starter # Swagger/OpenAPI DX tools
23+
├── demo-app # Usage example for all starters
24+
└── README.md
25+
```
26+
27+
28+
Each module:
29+
- Is a **Spring Boot starter**
30+
- Is independently usable
31+
- Focuses on a specific developer pain point
32+
33+
---
34+
35+
## 🧠 Why AI + Spring Boot Starters?
36+
37+
Traditional developer tools provide **raw data** (logs, specs, stack traces).
38+
These starters use AI to convert that data into **actionable insights**.
39+
40+
Examples:
41+
- Explaining *why* an API change is breaking
42+
- Generating realistic request payloads from OpenAPI
43+
- Summarizing errors instead of dumping stack traces
44+
- Reducing cognitive load during development
45+
46+
AI is used **only where reasoning or summarization adds value**, not as a gimmick.
47+
48+
---
49+
50+
## 🧩 Available Starters
51+
52+
### 1️⃣ AI Swagger Helper Starter
53+
📁 `ai-swagger-helper-starter`
54+
55+
Enhancements for Swagger / OpenAPI during development.
56+
57+
**Features**
58+
- Adds a Swagger UI extension
59+
- Generates realistic, real-world request bodies
60+
- Helps developers test APIs faster without manually crafting payloads
61+
62+
**Use case**
63+
- Local development
64+
- API testing
65+
66+
---
67+
68+
## 🛠 Planned / In-Progress Starters
69+
70+
- **AI Exception Explainer Starter**
71+
Converts Spring stack traces into human-readable explanations.
72+
73+
- **AI Exception Handler**
74+
75+
(Each starter will live in its own module with independent documentation.)*
76+
77+
---
78+
79+
80+
## 🧰 Tech Stack
81+
82+
- Java 21+
83+
- Spring Boot 4
84+
- Spring Auto-Configuration
85+
- OpenAPI / Swagger
86+
- Maven (multi-module)
87+
- OpenRouter LLM integration (pluggable)
88+
89+
---
90+
91+
## 📌 Who Is This For?
92+
93+
- Backend developers working with Spring Boot
94+
- Engineers interested in platform / tooling work
95+
- Developers exploring AI-assisted development workflows
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# DevTools AI – Swagger Helper Starter
2+
3+
A Spring Boot starter that improves **Swagger / OpenAPI developer experience** by automatically generating request bodies during development.
4+
5+
The starter supports both **local random generation** and **optional AI-powered generation** (via Spring AI), with safe fallbacks and zero impact on application startup.
6+
7+
AI is treated as an **optional enhancement**, not a requirement.
8+
9+
---
10+
11+
## 🎯 Problem
12+
13+
During backend development, generating request bodies for APIs is:
14+
15+
- repetitive
16+
- time-consuming
17+
- error-prone
18+
- especially painful for complex schemas
19+
20+
Swagger UI shows schemas, but developers still have to manually craft payloads.
21+
22+
This starter removes that friction.
23+
24+
---
25+
26+
## ✨ Features
27+
28+
- Swagger UI extension with **Generate Request Body** action
29+
- Local random request body generation (default)
30+
- Optional AI-powered request body generation
31+
- Automatic fallback to random generation on AI failure
32+
- Fully configurable via properties
33+
34+
---
35+
36+
## 📦 Installation
37+
38+
### Maven
39+
40+
```xml
41+
<dependency>
42+
<groupId>io.github.rexrk</groupId>
43+
<artifactId>ai-swagger-helper-starter</artifactId>
44+
<version>0.0.1-SNAPSHOT</version>
45+
</dependency>
46+
```
47+
48+
---
49+
50+
## ⚙️ Configuration
51+
52+
Configure Spring AI (example with OpenAI):
53+
```yaml
54+
spring:
55+
ai:
56+
openai:
57+
api-key: YOUR_API_KEY
58+
```
59+
60+
61+
```yaml
62+
devtools:
63+
ai:
64+
swagger:
65+
enabled: true
66+
mode: random
67+
```
68+
69+
## 🔁 Generation Modes
70+
71+
| Mode | Behavior |
72+
|-----|----------|
73+
| random | Always use local random generation |
74+
| ai | Use AI if available, fallback to random |
75+
| auto | Use AI when configured, otherwise random |
76+
77+
---

ai-swagger-helper-starter/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
<dependency>
4343
<groupId>org.springframework.ai</groupId>
44-
<artifactId>spring-ai-openai</artifactId>
44+
<artifactId>spring-ai-starter-model-openai</artifactId>
4545
</dependency>
4646

4747
<dependency>

ai-swagger-helper-starter/src/main/java/io/github/rexrk/AiSwaggerHelperAutoConfiguration.java

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
import org.springdoc.webmvc.ui.SwaggerIndexPageTransformer;
1515
import org.springdoc.webmvc.ui.SwaggerIndexTransformer;
1616
import org.springdoc.webmvc.ui.SwaggerWelcomeCommon;
17-
import org.springframework.ai.openai.OpenAiChatModel;
18-
import org.springframework.ai.openai.OpenAiChatOptions;
19-
import org.springframework.ai.openai.api.OpenAiApi;
17+
import org.springframework.ai.chat.client.ChatClient;
2018
import org.springframework.beans.factory.ObjectProvider;
2119
import org.springframework.boot.autoconfigure.AutoConfiguration;
2220
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -44,7 +42,7 @@
4442
jakarta.servlet.http.HttpServletRequest.class,
4543
})
4644
@ConditionalOnProperty(
47-
prefix = "ai.swagger.helper",
45+
prefix = AiSwaggerHelperProperties.prefix,
4846
name = "enabled",
4947
havingValue = BooleanUtils.TRUE,
5048
matchIfMissing = true
@@ -70,34 +68,10 @@ public ObjectMapper objectMapper() {
7068
/**
7169
* 1️⃣ Spring-Ai configuration
7270
*/
73-
74-
@Bean
75-
@ConditionalOnMissingBean(OpenAiApi.class)
76-
@ConditionalOnProperty(prefix = "ai.swagger.helper", name = "api-key")
77-
public OpenAiApi openAiApi(AiSwaggerHelperProperties properties) {
78-
return OpenAiApi.builder()
79-
.apiKey(properties.getApiKey())
80-
.baseUrl(properties.getBaseUrl())
81-
.build();
82-
83-
}
84-
8571
@Bean
8672
@ConditionalOnMissingBean
87-
@ConditionalOnProperty(prefix = "ai.swagger.helper", name = "api-key")
88-
public OpenAiChatModel openAiChatModel(
89-
AiSwaggerHelperProperties properties,
90-
OpenAiApi openAiApi) {
91-
OpenAiChatOptions options = OpenAiChatOptions.builder()
92-
.model(properties.getModelName())
93-
.temperature(properties.getTemperature())
94-
.extraBody(properties.getOptions())
95-
.build();
96-
97-
return OpenAiChatModel.builder()
98-
.openAiApi(openAiApi)
99-
.defaultOptions(options)
100-
.build();
73+
public ChatClient chatClient(ChatClient.Builder chatClientBuilder) {
74+
return chatClientBuilder.build();
10175
}
10276

10377
/**
@@ -106,10 +80,14 @@ public OpenAiChatModel openAiChatModel(
10680

10781
@Bean
10882
public AiRequestBodyGeneratorService aiRequestBodyGeneratorService(
109-
ObjectProvider<OpenAiChatModel> chatModel,
83+
ObjectProvider<ChatClient> chatClientObjectProvider,
11084
ObjectMapper objectMapper
11185
) {
112-
return new AiRequestBodyGeneratorService(chatModel.getIfAvailable(), objectMapper);
86+
return new AiRequestBodyGeneratorService(
87+
chatClientObjectProvider.getIfAvailable(),
88+
objectMapper,
89+
properties.getMode()
90+
);
11391

11492
}
11593

@@ -218,6 +196,6 @@ public Resource transform(HttpServletRequest request, Resource resource,
218196

219197
@PostConstruct
220198
void logProps() {
221-
if (properties.isEnabled()) log.info("AI Swagger Helper enabled");
199+
if (properties.isEnabled()) log.info("AI Swagger Helper enabled. Mode: {}", properties.getMode());
222200
}
223201
}

ai-swagger-helper-starter/src/main/java/io/github/rexrk/AiSwaggerHelperProperties.java

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,16 @@
22

33
import org.springframework.boot.context.properties.ConfigurationProperties;
44

5-
import java.util.HashMap;
6-
import java.util.Map;
7-
8-
@ConfigurationProperties(prefix = "ai.swagger.helper")
5+
@ConfigurationProperties(prefix = AiSwaggerHelperProperties.prefix)
96
public class AiSwaggerHelperProperties {
7+
public static final String prefix = "devtools.ai.swagger";
8+
private boolean enabled = true;
9+
private Mode mode = Mode.AUTO;
1010

11-
private boolean enabled = true; // Enable/disable AI generation feature
12-
private String baseUrl = "https://openrouter.ai/api";
13-
private String apiKey;
14-
private String modelName = "openai/gpt-oss-20b:free";
15-
private double temperature = 0.7;
16-
private Map<String, Object> options = new HashMap<>();
17-
18-
// Getters and Setters
19-
public String getApiKey() {
20-
return apiKey;
21-
}
22-
23-
public void setApiKey(String apiKey) {
24-
this.apiKey = apiKey;
25-
}
26-
27-
public String getModelName() {
28-
return modelName;
29-
}
30-
31-
public void setModelName(String modelName) {
32-
this.modelName = modelName;
33-
}
34-
35-
public double getTemperature() {
36-
return temperature;
37-
}
38-
39-
public void setTemperature(float temperature) {
40-
this.temperature = temperature;
11+
public enum Mode {
12+
AI,
13+
RANDOM,
14+
AUTO
4115
}
4216

4317
public boolean isEnabled() {
@@ -48,19 +22,11 @@ public void setEnabled(boolean enabled) {
4822
this.enabled = enabled;
4923
}
5024

51-
public Map<String, Object> getOptions() {
52-
return options;
53-
}
54-
55-
public void setOptions(Map<String, Object> options) {
56-
this.options = options;
57-
}
58-
59-
public String getBaseUrl() {
60-
return baseUrl;
25+
public Mode getMode() {
26+
return mode;
6127
}
6228

63-
public void setBaseUrl(String baseUrl) {
64-
this.baseUrl = baseUrl;
29+
public void setMode(Mode mode) {
30+
this.mode = mode;
6531
}
6632
}

0 commit comments

Comments
 (0)