Průvodce generátorem příběhů o mazlíčcích pro začátečníky
July 2, 2026 · View on GitHub
Obsah
- Předpoklady
- Pochopení struktury projektu
- Vysvětlení hlavních komponent
- Spuštění aplikace
- Jak to vše spolu funguje
- Pochopení AI integrace
- Další kroky
Prerekvizity
Před zahájením se ujistěte, že máte:
- Nainstalováno Java 21 nebo vyšší
- Maven pro správu závislostí
- Nasazený model Azure AI Foundry (zprovozněte pomocí
azd up— viz Kapitola 2), přihlášený přesaz login(autentizace bez klíče) - Základní znalosti Javy, Spring Boot a webového vývoje
Pochopení struktury projektu
Projekt příběhů o mazlíčcích obsahuje několik důležitých souborů:
petstory/
├── src/main/java/com/example/petstory/
│ ├── PetStoryApplication.java # Main Spring Boot application
│ ├── PetController.java # Web request handler
│ ├── StoryService.java # AI story generation service
│ └── SecurityConfig.java # Security configuration
├── src/main/resources/
│ ├── application.properties # App configuration
│ └── templates/
│ ├── index.html # Upload form page
│ └── result.html # Story display page
└── pom.xml # Maven dependencies
Vysvětlení hlavních komponent
1. Hlavní aplikace
Soubor: PetStoryApplication.java
Toto je vstupní bod naší Spring Boot aplikace:
@SpringBootApplication
public class PetStoryApplication {
public static void main(String[] args) {
SpringApplication.run(PetStoryApplication.class, args);
}
}
Co toto dělá:
- Anotace
@SpringBootApplicationpovoluje automatickou konfiguraci a skenování komponent - Spouští zabudovaný webový server (Tomcat) na portu 8080
- Automaticky vytváří všechny potřebné Spring beany a služby
2. Webový kontroler
Soubor: PetController.java
Tento zpracovává všechny webové požadavky a interakce uživatele:
@Controller
public class PetController {
private final StoryService storyService;
public PetController(StoryService storyService) {
this.storyService = storyService;
}
@GetMapping("/")
public String index() {
return "index"; // Vrací šablonu index.html
}
@PostMapping("/generate-story")
public String generateStory(@RequestParam("description") String description,
Model model,
RedirectAttributes redirectAttributes) {
// Kontrola vstupních dat
if (description.trim().isEmpty()) {
redirectAttributes.addFlashAttribute("error", "Please provide a description.");
return "redirect:/";
}
// Očistit vstup pro bezpečnost
String sanitizedDescription = sanitizeInput(description);
// Generovat příběh s ošetřením chyb
try {
String story = storyService.generateStory(sanitizedDescription);
model.addAttribute("caption", sanitizedDescription);
model.addAttribute("story", story);
return "result"; // Vrací šablonu result.html
} catch (Exception e) {
// Použít záložní příběh, pokud AI selže
String fallbackStory = generateFallbackStory(sanitizedDescription);
model.addAttribute("story", fallbackStory);
return "result";
}
}
private String sanitizeInput(String input) {
return input.replaceAll("[<>\"'&]", "") // Remove dangerous characters
.trim()
.substring(0, Math.min(input.length(), 500)); // Omezit délku
}
}
Klíčové vlastnosti:
- Zpracování tras:
@GetMapping("/")zobrazí formulář pro nahrání,@PostMapping("/generate-story")zpracuje odeslaná data - Validace vstupů: Kontroluje prázdné popisy a omezení délky
- Bezpečnost: Čistí uživatelský vstup, aby předešel útokům XSS
- Zpracování chyb: Poskytuje záložní příběhy, když AI služba selže
- Vazba modelu: Předává data do HTML šablon pomocí Spring
Model
Záložní systém: Kontroler obsahuje předpřipravené šablony příběhů, které se použijí, pokud není AI služba dostupná:
private String generateFallbackStory(String description) {
String[] storyTemplates = {
"Meet the most wonderful pet in the world – a furry ball of energy...",
"Once upon a time, there lived a remarkable pet whose heart was as big...",
"In a cozy home filled with love, there lived an extraordinary pet..."
};
// Použijte hash popisu pro konzistentní odpovědi
int index = Math.abs(description.hashCode() % storyTemplates.length);
return storyTemplates[index];
}
3. Služba pro příběhy
Soubor: StoryService.java
Tato služba komunikuje s Azure AI Foundry pro generování příběhů s autentizací bez klíče:
@Service
public class StoryService {
private final OpenAIClient openAIClient;
private final String modelName;
public StoryService(@Value("${azure.openai.endpoint:}") String endpoint,
@Value("${azure.openai.deployment:gpt-4o-mini}") String modelName) {
this.modelName = modelName;
if (endpoint == null || endpoint.isBlank()) {
endpoint = System.getenv("AZURE_OPENAI_ENDPOINT");
}
// OpenAI-kompatibilní konec Foundry se nachází pod /openai/v1/
String baseUrl = (endpoint.endsWith("/") ? endpoint : endpoint + "/") + "openai/v1/";
// Autentizace bez klíče pomocí Microsoft Entra ID (žádný API klíč)
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
this.openAIClient = OpenAIOkHttpClient.builder()
.baseUrl(baseUrl)
.credential(BearerTokenCredential.create(
AuthenticationUtil.getBearerTokenSupplier(credential, "https://ai.azure.com/.default")))
.build();
}
public String generateStory(String description) {
String systemPrompt = "You are a creative storyteller who writes fun, " +
"family-friendly short stories about pets. " +
"Keep stories under 500 words and appropriate for all ages.";
String userPrompt = "Write a fun short story about a pet described as: " + description;
// Nakonfigurujte požadavek AI
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(modelName)
.addSystemMessage(systemPrompt)
.addUserMessage(userPrompt)
.maxCompletionTokens(500) // Omezte délku odpovědi
.temperature(0.8) // Řiďte kreativitu (0.0-1.0)
.build();
// Odešlete požadavek a získejte odpověď
ChatCompletion response = openAIClient.chat().completions().create(params);
return response.choices().get(0).message().content().orElse("");
}
}
Klíčové složky:
- OpenAI klient: Používá oficiální OpenAI Java SDK nakonfigurované pro Azure AI Foundry (bezklíčová autentizace)
- Systémový prompt: Určuje chování AI, aby psala příběhy o mazlíčcích vhodné pro rodiny
- Uživatelský prompt: Říká AI, jaký příběh má napsat na základě popisu
- Parametry: Řídí délku a kreativitu příběhu
- Zpracování chyb: Vyvolává výjimky, které kontroler zachytí a zpracuje
4. Webové šablony
Soubor: index.html (Formulář pro nahrání)
Hlavní stránka, kde uživatelé popisují své mazlíčky:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Pet Story Generator</title>
<!-- CSS styling -->
</head>
<body>
<div class="container">
<h1>Pet Story Generator</h1>
<p>Describe your pet and we'll create a fun story about them!</p>
<!-- Error message display -->
<div th:if="${error}" class="error" th:text="${error}"></div>
<!-- Story generation form -->
<form action="/generate-story" method="post">
<div class="form-group">
<label for="description">Describe your pet:</label>
<textarea id="description" name="description"
placeholder="Tell us about your pet - what they look like, their personality, favorite activities..."
maxlength="1000" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Generate Story</button>
</form>
<!-- Image upload section with client-side processing -->
<div class="upload-section">
<h2>Or Upload a Photo</h2>
<input type="file" id="imageInput" accept="image/*" />
<button onclick="analyzeImage()" class="upload-btn">Analyze Image</button>
</div>
<script>
// Client-side image analysis using Transformers.js
async function analyzeImage() {
// Image processing code here
// Generates description automatically from uploaded image
}
</script>
</div>
</body>
</html>
Soubor: result.html (Zobrazení příběhu)
Zobrazuje vygenerovaný příběh:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Pet Story Result</title>
</head>
<body>
<div class="container">
<h1>Your Pet's Story</h1>
<div class="result-section">
<div class="result-label">Pet Description:</div>
<div class="result-content" th:text="${caption}"></div>
</div>
<div class="result-section">
<div class="result-label">Generated Story:</div>
<div class="result-content" th:text="${story}"></div>
</div>
<div class="result-section" th:if="${analysisType}">
<div class="result-label">Analysis Type:</div>
<div class="result-content" th:text="${analysisType}"></div>
</div>
<a href="/" class="back-link">Generate Another Story</a>
</div>
</body>
</html>
Vlastnosti šablony:
- Integrace Thymeleaf: Používá atributy
th:pro dynamický obsah - Responzivní design: CSS stylování pro mobily i desktop
- Zpracování chyb: Zobrazuje uživateli chyby validace
- Zpracování na klientovi: JavaScript pro analýzu obrázků (pomocí Transformers.js)
5. Konfigurace
Soubor: application.properties
Nastavení konfigurace aplikace:
spring.application.name=pet-story-app
# File upload limits
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
# Logging configuration
logging.level.com.example.petstory=INFO
# Azure AI Foundry (keyless) configuration
azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT:}
azure.openai.deployment=${AZURE_OPENAI_DEPLOYMENT:gpt-4o-mini}
Vysvětlení konfigurace:
- Nahrávání souborů: Povolení obrázků do 10MB
- Protokolování: Řízení, jaké informace se logují při běhu
- Azure AI Foundry: Specifikace endpointu a modelu (bezklíčová autentizace)
- Bezpečnost: Konfigurace zpracování chyb, aby se nezobrazovaly citlivé informace
Spuštění aplikace
Krok 1: Přihlaste se a nastavte endpoint
Autentizace probíhá bez klíče (Microsoft Entra ID), proto se nepoužívá API klíč. Přihlaste se a nastavte svůj Foundry endpoint:
Windows (Příkazový řádek):
az login
set AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
Windows (PowerShell):
az login
$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
Linux/macOS:
az login
export AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
Proč je to potřeba:
- Azure AI Foundry používá Microsoft Entra ID pro autentizaci požadavků na inference
- Bezklíčová autentizace znamená, že v kódu ani prostředí nejsou žádná tajemství
- Váš účet potřebuje roli Cognitive Services OpenAI User na zdroji
Krok 2: Sestavte a spusťte
Přejděte do složky projektu:
cd 04-PracticalSamples/petstory
Sestavte aplikaci:
mvn clean compile
Spusťte server:
mvn spring-boot:run
Aplikace se spustí na adrese http://localhost:8080.
Krok 3: Testujte aplikaci
- Otevřete
http://localhost:8080ve svém prohlížeči - Popište svého mazlíčka do textového pole (např. "Hrníček hravý zlatý retrívr, který rád aportuje")
- Klikněte na "Generate Story", aby vám AI vytvořila příběh
- Alternativně nahrajte obrázek mazlíčka pro automatické vygenerování popisu
- Prohlédněte si kreativní příběh založený na vámi zadaném popisu mazlíčka
Jak to vše spolu funguje
Tady je celý proces, když vygenerujete příběh o mazlíčkovi:
- Uživatelský vstup: Vy popíšete mazlíčka ve webovém formuláři
- Odeslání formuláře: Prohlížeč pošle POST požadavek na
/generate-story - Zpracování kontrolerem:
PetControllervstup validuje a čistí - Volání AI služby:
StoryServiceodešle požadavek modelu Azure AI Foundry - Generování příběhu: AI vygeneruje kreativní příběh podle popisu
- Zpracování odpovědi: Kontroler obdrží příběh a vloží ho do modelu
- Rendrování šablony: Thymeleaf vykreslí
result.htmls příběhem - Zobrazení: Uživatel uvidí vygenerovaný příběh ve svém prohlížeči
Zpracování chyb: Pokud AI služba selže:
- Kontroler zachytí výjimku
- Vygeneruje záložní příběh pomocí předpřipravených šablon
- Zobrazí záložní příběh s upozorněním, že AI není dostupná
- Uživatel stále obdrží příběh, aby byla zajištěna dobrá uživatelská zkušenost
Pochopení AI integrace
Azure AI Foundry (bez klíče)
Aplikace používá Azure AI Foundry s bezklíčovou autentizací (Microsoft Entra ID):
// Autentizace bez klíče - bez API klíče
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
this.openAIClient = OpenAIOkHttpClient.builder()
.baseUrl(endpoint + "openai/v1/")
.credential(BearerTokenCredential.create(
AuthenticationUtil.getBearerTokenSupplier(credential, "https://ai.azure.com/.default")))
.build();
Tvorba promptů
Služba používá pečlivě navržené prompty pro dosažení dobrých výsledků:
String systemPrompt = "You are a creative storyteller who writes fun, " +
"family-friendly short stories about pets. " +
"Keep stories under 500 words and appropriate for all ages.";
Zpracování odpovědi
Odpověď AI se extrahuje a validuje:
ChatCompletion response = openAIClient.chat().completions().create(params);
String story = response.choices().get(0).message().content().orElse("");
Další kroky
Pro více příkladů viz Kapitola 04: Praktické ukázky
Prohlášení o omezení odpovědnosti: Tento dokument byl přeložen pomocí AI překladatelské služby Co-op Translator. Přestože usilujeme o co největší přesnost, mějte prosím na paměti, že automatizované překlady mohou obsahovat chyby nebo nepřesnosti. Originální dokument v jeho mateřském jazyce by měl být považován za autoritativní zdroj. Pro kritické informace se doporučuje profesionální lidský překlad. Nejsme odpovědní za jakékoli nedorozumění nebo nesprávné interpretace vzniklé použitím tohoto překladu.