A two-feature AI web app: a markdown-formatted chat and a parameterized code generator, both powered by GPT-OSS-20B served through Groq's OpenAI-compatible API. Wired together with Spring AI on the backend and React + Vite on the frontend.
- Chat tab — sends a user prompt to the Spring backend; the backend wraps it with formatting instructions so the LLM returns markdown (headings + bullets), which
react-markdownrenders on the page. - Code-generation tab — takes free-form instructions plus a target language, builds the prompt via Spring AI's
PromptTemplate, and asks the LLM to return raw runnable code (no commentary). - Tab-based UI with
localStorage-persisted active tab — refreshing the page keeps you where you were. - Groq backing inference — Spring AI's OpenAI starter is pointed at
https://api.groq.com/openaivia a base-URL override.
| Layer | Tool |
|---|---|
| Backend framework | Spring Boot 3.5.4 |
| LLM orchestration | Spring AI 1.0.1 (spring-ai-starter-model-openai) |
| Language | Java 22 (with --enable-preview) |
| LLM | GPT-OSS-20B via Groq |
| Frontend framework | React 19 + Vite 7 |
| Markdown rendering | react-markdown |
| Build / package | Maven (backend), npm (frontend) |
AI-Hub-SpringBoot/
├── assets/ Images for this README
├── spring/ Spring Boot service
│ ├── pom.xml
│ └── src/main/
│ ├── java/com/ai/demo/
│ │ ├── DemoApplication.java Boot entry point
│ │ ├── GenAIController.java REST endpoints (/chat, /code)
│ │ ├── ChatService.java Conversational chat via Spring AI
│ │ ├── CodeSnippet.java Code generation via PromptTemplate
│ │ └── WebConfig.java CORS for the Vite dev server
│ └── resources/
│ └── application.yml Spring AI client config (env-driven)
└── react-app/ React + Vite frontend
├── package.json
├── vite.config.js
└── src/
├── main.jsx Mount point
├── App.jsx Tab switcher
└── components/
├── ChatComponent.jsx Chat UI (calls /chat)
└── CodeSnippet.jsx Code UI (calls /code)
Free tier — no credit card. Visit console.groq.com/keys and copy a key.
cp .env.example .env
# Edit .env and paste your real key after GROQ_API_KEY=Then export it into your shell before starting the app (or use a tool like direnv to auto-load .env):
export GROQ_API_KEY=gsk_your_actual_keyapplication.yml reads this via ${GROQ_API_KEY:API_KEY_HERE} — Spring uses the fallback placeholder only if the env var is missing, so missing keys fail loudly at the first LLM call.
cd spring
./mvnw spring-boot:runcd react-app
npm install
npm run devOpen http://localhost:5173 and try both tabs.
Both endpoints return plain text (not JSON). The frontend consumes them via fetch().then(r => r.text()).
| Method | Path | Query params | Returns |
|---|---|---|---|
GET |
/chat |
prompt |
Markdown-formatted answer from the LLM |
GET |
/code |
instructions, language (default: any) |
Raw runnable code, no commentary |
- Groq's LPU architecture delivers fast token-throughput inference compared to typical GPU-backed APIs — the chat and code endpoints return full responses in 1-2 seconds on average prompts.
- OpenAI-compatible API means Spring AI's OpenAI starter works out of the box: just override
base-url. No custom client code needed. - GPT-OSS-20B is an open-weights 20B-parameter model — competitive on reasoning and code while remaining fully transparent.
A few intentional choices worth calling out:
- No streaming on the wire. Both backend (
chatModel.call(...)) and frontend (fetch().then(r => r.text())) are synchronous full-response. Adding SSE would mean switching to Spring WebFlux + reactiveChatClient.stream()plus anEventSourceon the client — possible follow-up, not yet built. PromptTemplatefor code generation. Lets the template live as data (not interpolated strings), making it easy to externalize prompts to a YAML file later if needed.- CORS scoped to the Vite dev port. Production would replace the hardcoded
http://localhost:5173with the deployed frontend origin or read it fromapplication.yml. - Temperature = 0.4. Low variance so both chat and code outputs stay consistent and predictable. Tune up if creative writing is added.


