Spring AI integration for Azure OpenAI services providing chat completion, text embeddings, image generation, and audio transcription with GPT, DALL-E, and Whisper models
Production-ready examples for common use cases.
Build an intelligent customer support system with context and memory.
@Service
public class CustomerSupportService {
@Autowired
private AzureOpenAiChatModel chatModel;
@Autowired
private AzureOpenAiEmbeddingModel embeddingModel;
private final Map<String, List<Message>> sessions = new ConcurrentHashMap<>();
public String handleCustomerQuery(String sessionId, String query) {
// Get or create conversation history
List<Message> history = sessions.computeIfAbsent(
sessionId,
k -> new ArrayList<>()
);
// Retrieve relevant knowledge base articles
EmbeddingResponse queryEmbedding = embeddingModel.call(
new EmbeddingRequest(List.of(query), null)
);
List<String> relevantArticles = searchKnowledgeBase(
queryEmbedding.getResults().get(0).getOutput()
);
// Build context-aware prompt
String context = "Knowledge Base:\n" + String.join("\n", relevantArticles);
String systemPrompt = "You are a helpful customer support agent. " +
"Use the knowledge base to answer questions accurately. " +
"If you don't know, say so.\n\n" + context;
// Add to conversation
if (history.isEmpty()) {
history.add(new SystemMessage(systemPrompt));
}
history.add(new UserMessage(query));
// Generate response
ChatResponse response = chatModel.call(new Prompt(history));
String answer = response.getResult().getOutput().getText();
// Update history
history.add(new AssistantMessage(answer));
// Limit history size
if (history.size() > 20) {
history = history.subList(history.size() - 20, history.size());
sessions.put(sessionId, history);
}
return answer;
}
}Analyze large documents and generate summaries.
@Service
public class DocumentAnalysisService {
@Autowired
private AzureOpenAiChatModel chatModel;
@Autowired
private AzureOpenAiEmbeddingModel embeddingModel;
public DocumentSummary analyzeDocument(String document) {
// Split into chunks if too long
List<String> chunks = splitIntoChunks(document, 4000);
// Summarize each chunk
List<String> chunkSummaries = chunks.stream()
.map(chunk -> {
AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
.temperature(0.3) // Low temp for factual summaries
.maxTokens(500)
.build();
Prompt prompt = new Prompt(
"Summarize this text concisely:\n\n" + chunk,
options
);
return chatModel.call(prompt)
.getResult()
.getOutput()
.getText();
})
.collect(Collectors.toList());
// Generate final summary
String combinedSummaries = String.join("\n\n", chunkSummaries);
Prompt finalPrompt = new Prompt(
"Create a comprehensive summary from these section summaries:\n\n" +
combinedSummaries
);
String finalSummary = chatModel.call(finalPrompt)
.getResult()
.getOutput()
.getText();
// Extract key points with structured output
Map<String, Object> schema = Map.of(
"type", "object",
"properties", Map.of(
"key_points", Map.of(
"type", "array",
"items", Map.of("type", "string")
),
"topics", Map.of(
"type", "array",
"items", Map.of("type", "string")
),
"sentiment", Map.of("type", "string")
)
);
AzureOpenAiResponseFormat format = AzureOpenAiResponseFormat.builder()
.type(AzureOpenAiResponseFormat.Type.JSON_SCHEMA)
.jsonSchema(AzureOpenAiResponseFormat.JsonSchema.builder()
.name("DocumentAnalysis")
.schema(schema)
.strict(true)
.build())
.build();
AzureOpenAiChatOptions analysisOptions = AzureOpenAiChatOptions.builder()
.responseFormat(format)
.build();
Prompt analysisPrompt = new Prompt(
"Analyze this document and extract key points, topics, and sentiment:\n\n" +
finalSummary,
analysisOptions
);
String analysisJson = chatModel.call(analysisPrompt)
.getResult()
.getOutput()
.getText();
return new DocumentSummary(finalSummary, analysisJson);
}
}Build a semantic search engine with re-ranking.
@Service
public class SemanticSearchService {
@Autowired
private AzureOpenAiEmbeddingModel embeddingModel;
@Autowired
private AzureOpenAiChatModel chatModel;
private final VectorDatabase vectorDb;
public List<SearchResult> search(String query, int topK) {
// 1. Generate query embedding
EmbeddingResponse queryEmbedding = embeddingModel.call(
new EmbeddingRequest(
List.of(query),
AzureOpenAiEmbeddingOptions.builder()
.inputType("query")
.build()
)
);
// 2. Vector similarity search
List<Document> candidates = vectorDb.similaritySearch(
queryEmbedding.getResults().get(0).getOutput(),
topK * 3 // Get more candidates for re-ranking
);
// 3. Re-rank with LLM
String reRankPrompt = buildReRankPrompt(query, candidates);
AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
.temperature(0.0)
.responseFormat(AzureOpenAiResponseFormat.builder()
.type(AzureOpenAiResponseFormat.Type.JSON_OBJECT)
.build())
.build();
Prompt prompt = new Prompt(reRankPrompt, options);
String reRankedJson = chatModel.call(prompt)
.getResult()
.getOutput()
.getText();
// 4. Parse and return top results
return parseReRankedResults(reRankedJson, topK);
}
public void indexDocuments(List<String> documents) {
// Batch embed documents
EmbeddingResponse embeddings = embeddingModel.call(
new EmbeddingRequest(
documents,
AzureOpenAiEmbeddingOptions.builder()
.inputType("document")
.build()
)
);
// Store in vector database
for (int i = 0; i < documents.size(); i++) {
vectorDb.store(
documents.get(i),
embeddings.getResults().get(i).getOutput()
);
}
}
}Generate blog posts, social media content, and images.
@Service
public class ContentGenerationService {
@Autowired
private AzureOpenAiChatModel chatModel;
@Autowired
private AzureOpenAiImageModel imageModel;
public BlogPost generateBlogPost(String topic, String targetAudience) {
// 1. Generate outline
Prompt outlinePrompt = new Prompt(
String.format(
"Create a detailed blog post outline about '%s' for %s. " +
"Include 5-7 main sections with subsections.",
topic, targetAudience
)
);
String outline = chatModel.call(outlinePrompt)
.getResult()
.getOutput()
.getText();
// 2. Generate full content
AzureOpenAiChatOptions contentOptions = AzureOpenAiChatOptions.builder()
.temperature(0.8) // More creative
.maxTokens(3000)
.build();
Prompt contentPrompt = new Prompt(
String.format(
"Write a comprehensive blog post based on this outline:\n\n%s\n\n" +
"Make it engaging, informative, and suitable for %s.",
outline, targetAudience
),
contentOptions
);
StringBuilder fullContent = new StringBuilder();
Flux<ChatResponse> stream = chatModel.stream(contentPrompt);
stream.subscribe(chunk -> {
String token = chunk.getResult().getOutput().getText();
if (token != null) {
fullContent.append(token);
}
});
// 3. Generate featured image
Prompt imagePrompt = new ImagePrompt(
String.format(
"Professional blog header image for article about %s, " +
"modern design, high quality, suitable for tech blog",
topic
)
);
AzureOpenAiImageOptions imageOptions = AzureOpenAiImageOptions.builder()
.width(1792)
.height(1024)
.style("natural")
.build();
imageOptions.setQuality("hd");
ImageResponse imageResponse = imageModel.call(imagePrompt);
String imageUrl = imageResponse.getResult().getOutput().getUrl();
// 4. Generate social media snippets
Prompt socialPrompt = new Prompt(
"Create 3 engaging social media posts (Twitter, LinkedIn, Facebook) " +
"to promote this blog post:\n\n" + fullContent.toString()
);
String socialSnippets = chatModel.call(socialPrompt)
.getResult()
.getOutput()
.getText();
return new BlogPost(
topic,
fullContent.toString(),
imageUrl,
socialSnippets
);
}
}Transcribe meetings and generate actionable insights.
@Service
public class MeetingAnalysisService {
@Autowired
private AzureOpenAiAudioTranscriptionModel transcriptionModel;
@Autowired
private AzureOpenAiChatModel chatModel;
public MeetingReport analyzeMeeting(Resource audioFile) {
// 1. Transcribe with timestamps
AzureOpenAiAudioTranscriptionOptions options =
AzureOpenAiAudioTranscriptionOptions.builder()
.language("en")
.responseFormat(
AzureOpenAiAudioTranscriptionOptions
.TranscriptResponseFormat.VERBOSE_JSON
)
.granularityType(List.of(
AzureOpenAiAudioTranscriptionOptions.GranularityType.SEGMENT
))
.temperature(0.0f)
.build();
AudioTranscriptionPrompt prompt = new AudioTranscriptionPrompt(
audioFile,
options
);
AudioTranscriptionResponse response = transcriptionModel.call(prompt);
String transcript = response.getResult().getOutput();
// 2. Extract action items
Map<String, Object> actionSchema = Map.of(
"type", "object",
"properties", Map.of(
"action_items", Map.of(
"type", "array",
"items", Map.of(
"type", "object",
"properties", Map.of(
"task", Map.of("type", "string"),
"assignee", Map.of("type", "string"),
"deadline", Map.of("type", "string")
)
)
),
"decisions", Map.of(
"type", "array",
"items", Map.of("type", "string")
),
"topics", Map.of(
"type", "array",
"items", Map.of("type", "string")
)
)
);
AzureOpenAiResponseFormat format = AzureOpenAiResponseFormat.builder()
.type(AzureOpenAiResponseFormat.Type.JSON_SCHEMA)
.jsonSchema(AzureOpenAiResponseFormat.JsonSchema.builder()
.name("MeetingAnalysis")
.schema(actionSchema)
.strict(true)
.build())
.build();
AzureOpenAiChatOptions analysisOptions = AzureOpenAiChatOptions.builder()
.responseFormat(format)
.temperature(0.0)
.build();
Prompt analysisPrompt = new Prompt(
"Analyze this meeting transcript and extract action items, " +
"decisions made, and topics discussed:\n\n" + transcript,
analysisOptions
);
String analysisJson = chatModel.call(analysisPrompt)
.getResult()
.getOutput()
.getText();
// 3. Generate summary
Prompt summaryPrompt = new Prompt(
"Create a concise executive summary of this meeting:\n\n" + transcript
);
String summary = chatModel.call(summaryPrompt)
.getResult()
.getOutput()
.getText();
return new MeetingReport(transcript, summary, analysisJson);
}
}Build personalized product recommendations.
@Service
public class RecommendationService {
@Autowired
private AzureOpenAiEmbeddingModel embeddingModel;
@Autowired
private AzureOpenAiChatModel chatModel;
public List<Product> getRecommendations(
User user,
List<Product> browsedProducts,
int count
) {
// 1. Create user profile embedding
String userProfile = buildUserProfile(user, browsedProducts);
EmbeddingResponse profileEmbedding = embeddingModel.call(
new EmbeddingRequest(List.of(userProfile), null)
);
// 2. Find similar products
List<Product> candidates = findSimilarProducts(
profileEmbedding.getResults().get(0).getOutput(),
count * 5
);
// 3. Use LLM to rank and explain
String rankingPrompt = buildRankingPrompt(user, candidates);
AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
.temperature(0.3)
.responseFormat(AzureOpenAiResponseFormat.builder()
.type(AzureOpenAiResponseFormat.Type.JSON_OBJECT)
.build())
.build();
Prompt prompt = new Prompt(rankingPrompt, options);
String rankedJson = chatModel.call(prompt)
.getResult()
.getOutput()
.getText();
return parseRecommendations(rankedJson, count);
}
public void indexProducts(List<Product> products) {
// Batch embed product descriptions
List<String> descriptions = products.stream()
.map(p -> p.getName() + " " + p.getDescription())
.collect(Collectors.toList());
EmbeddingResponse embeddings = embeddingModel.call(
new EmbeddingRequest(descriptions, null)
);
// Store embeddings
for (int i = 0; i < products.size(); i++) {
productIndex.store(
products.get(i),
embeddings.getResults().get(i).getOutput()
);
}
}
}Review code and provide suggestions.
@Service
public class CodeReviewService {
@Autowired
private AzureOpenAiChatModel chatModel;
public CodeReviewResult reviewCode(String code, String language) {
// Define review schema
Map<String, Object> schema = Map.of(
"type", "object",
"properties", Map.of(
"issues", Map.of(
"type", "array",
"items", Map.of(
"type", "object",
"properties", Map.of(
"severity", Map.of("type", "string"),
"line", Map.of("type", "integer"),
"description", Map.of("type", "string"),
"suggestion", Map.of("type", "string")
)
)
),
"score", Map.of("type", "integer"),
"summary", Map.of("type", "string")
)
);
AzureOpenAiResponseFormat format = AzureOpenAiResponseFormat.builder()
.type(AzureOpenAiResponseFormat.Type.JSON_SCHEMA)
.jsonSchema(AzureOpenAiResponseFormat.JsonSchema.builder()
.name("CodeReview")
.schema(schema)
.strict(true)
.build())
.build();
AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
.responseFormat(format)
.temperature(0.0)
.build();
Prompt prompt = new Prompt(
String.format(
"Review this %s code for:\n" +
"- Security vulnerabilities\n" +
"- Performance issues\n" +
"- Code quality\n" +
"- Best practices\n\n" +
"Code:\n```%s\n%s\n```",
language, language, code
),
options
);
String reviewJson = chatModel.call(prompt)
.getResult()
.getOutput()
.getText();
return parseCodeReview(reviewJson);
}
}tessl i tessl/maven-org-springframework-ai--spring-ai-azure-openai@1.1.1