宠物故事生成器初学者教程 目录 前置条件 理解项目结构 核心组件解析 主应用程序 Web控制器 故事服务 Web模板 配置 运行应用程序 整体工作流程 理解AI集成 下一步 前置条件 开始之前,请确保您已准备好以下内容: 安装了Java 21或更高版本 使用Maven进行依赖管理 拥有一个GitHub账户,并设置了具有 权限的个人访问令牌(PAT) 对Java、Spring Boot和Web开发有基本了解 理解项目结构 宠物故事项目包含以下重要文件: 核心组件解析 主应用程序 文件: 这是我们Spring Boot应用程序的入口点: 功能说明: 注解启用自动配置和组件扫描 在端口8080上启动嵌入式Web服务器(Tomcat) 自动创建所有必要的Spring Bean和服务 Web控制器
开始之前,请确保您已准备好以下内容:
models:read权限的个人访问令牌(PAT)宠物故事项目包含以下重要文件:
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
文件: PetStoryApplication.java
这是我们Spring Boot应用程序的入口点:
@SpringBootApplication public class PetStoryApplication { public static void main(String[] args) { SpringApplication.run(PetStoryApplication.class, args); } }
功能说明:
@SpringBootApplication注解启用自动配置和组件扫描文件: PetController.java
负责处理所有Web请求和用户交互:
@Controller public class PetController { private final StoryService storyService; public PetController(StoryService storyService) { this.storyService = storyService; } @GetMapping("/") public String index() { return "index"; // Returns index.html template } @PostMapping("/generate-story") public String generateStory(@RequestParam("description") String description, Model model, RedirectAttributes redirectAttributes) { // Input validation if (description.trim().isEmpty()) { redirectAttributes.addFlashAttribute("error", "Please provide a description."); return "redirect:/"; } // Sanitize input for security String sanitizedDescription = sanitizeInput(description); // Generate story with error handling try { String story = storyService.generateStory(sanitizedDescription); model.addAttribute("caption", sanitizedDescription); model.addAttribute("story", story); return "result"; // Returns result.html template } catch (Exception e) { // Use fallback story if AI fails 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)); // Limit length } }
关键功能:
@GetMapping("/")显示上传表单,@PostMapping("/generate-story")处理提交Model将数据传递给HTML模板备用系统:
控制器包含预先编写的故事模板,当AI服务不可用时会使用这些模板:
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..." }; // Use description hash for consistent responses int index = Math.abs(description.hashCode() % storyTemplates.length); return storyTemplates[index]; }
文件: StoryService.java
此服务与GitHub Models通信以生成故事:
@Service public class StoryService { private final OpenAIClient openAIClient; private final String modelName; public StoryService(@Value("${github.models.endpoint}") String endpoint, @Value("${github.models.model}") String modelName) { String githubToken = System.getenv("GITHUB_TOKEN"); if (githubToken == null || githubToken.isBlank()) { throw new IllegalStateException("GITHUB_TOKEN environment variable must be set"); } // Create OpenAI client configured for GitHub Models this.openAIClient = OpenAIOkHttpClient.builder() .baseUrl(endpoint) .apiKey(githubToken) .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; // Configure the AI request ChatCompletionCreateParams params = ChatCompletionCreateParams.builder() .model(modelName) .addSystemMessage(systemPrompt) .addUserMessage(userPrompt) .maxCompletionTokens(500) // Limit response length .temperature(0.8) // Control creativity (0.0-1.0) .build(); // Send request and get response ChatCompletion response = openAIClient.chat().completions().create(params); return response.choices().get(0).message().content().orElse(""); } }
关键组件:
文件: index.html (上传表单)
用户描述宠物的主页面:
<!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>
文件: result.html (故事展示)
显示生成的故事:
<!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>
模板功能:
th:属性实现动态内容文件: application.properties
应用程序的配置设置:
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 # GitHub Models configuration github.models.endpoint=https://models.github.ai/inference github.models.model=openai/gpt-4.1-nano
配置说明:
首先,您需要将GitHub令牌设置为环境变量:
Windows (命令提示符):
set GITHUB_TOKEN=your_github_token_here
Windows (PowerShell):
$env:GITHUB_TOKEN="your_github_token_here"
Linux/macOS:
export GITHUB_TOKEN=your_github_token_here
为什么需要这样做:
models:read权限提供AI推理的访问权限进入项目目录:
cd 04-PracticalSamples/petstory
构建应用程序:
mvn clean compile
启动服务器:
mvn spring-boot:run
应用程序将在http://localhost:8080上启动。
http://localhost:8080以下是生成宠物故事的完整流程:
/generate-storyPetController验证并清理输入StoryService向GitHub Models API发送请求result.html并显示故事错误处理流程:
如果AI服务失败:
应用程序使用GitHub Models,提供对各种AI模型的免费访问:
// Authentication with GitHub token this.openAIClient = OpenAIOkHttpClient.builder() .baseUrl("https://models.github.ai/inference") .apiKey(githubToken) .build();
服务使用精心设计的提示以获得良好的结果:
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.";
提取并验证AI响应:
ChatCompletion response = openAIClient.chat().completions().create(params); String story = response.choices().get(0).message().content().orElse("");
有关更多示例,请参阅第4章:实用样例
免责声明:
本文档使用AI翻译服务Co-op Translator进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。