This document describes the new story generation API endpoints added to MyEnglishNote.
The story generation feature allows users to:
- Upload images and identify objects using Deepseek Vision API
- Generate English fairy tales based on identified objects
- Manage characters (protagonists) for stories
- Search and manage generated stories
- Share stories via unique tokens
- Favorite stories
All endpoints require JWT authentication via the Authorization header:
Authorization: Bearer <jwt_token>
POST /api/character/add
Content-Type: application/json
{
"name": "Tom",
"description": "A curious little boy",
"avatarUrl": "https://example.com/avatar.jpg"
}Response:
{
"code": 200,
"msg": "操作成功",
"data": {
"id": 1,
"userId": 1,
"name": "Tom",
"description": "A curious little boy",
"avatarUrl": "https://example.com/avatar.jpg",
"storyCount": 0,
"createdAt": "2025-02-11 10:00:00"
}
}GET /api/character/list?pageNum=1&pageSize=10Response:
{
"total": 5,
"rows": [
{
"id": 1,
"name": "Tom",
"description": "A curious little boy",
"storyCount": 3
}
],
"code": 200,
"msg": "查询成功"
}GET /api/character/{id}PUT /api/character/{id}
Content-Type: application/json
{
"name": "Tom Jr.",
"description": "Updated description"
}DELETE /api/character/{id}POST /api/story/generate
Content-Type: application/json
{
"image": "base64_encoded_image_data_or_url",
"imageType": "base64", // or "url"
"characterId": 1,
"title": "Tom's Adventure" // optional
}Response:
{
"code": 200,
"msg": "操作成功",
"data": {
"success": true,
"storyId": 1,
"title": "Tom's Adventure",
"content": "Once upon a time, Tom found a magical book...",
"objects": ["book", "lamp", "chair", "desk"],
"characterName": "Tom",
"imageUrl": null,
"processingTime": 5234
}
}Error Response:
{
"code": 500,
"msg": "生成故事失败: No objects identified in the image",
"data": {
"success": false,
"errorMessage": "No objects identified in the image",
"processingTime": 1234
}
}GET /api/story/list?pageNum=1&pageSize=10&characterId=1&isFavorite=1Query Parameters:
characterId(optional): Filter by characterisFavorite(optional): Filter favorites (0 or 1)
Response:
{
"total": 10,
"rows": [
{
"id": 1,
"title": "Tom's Adventure",
"content": "Once upon a time...",
"objects": "[\"book\",\"lamp\"]",
"characterName": "Tom",
"isFavorite": 1,
"viewCount": 15,
"shareCount": 3,
"createdAt": "2025-02-11 10:00:00"
}
],
"code": 200,
"msg": "查询成功"
}GET /api/story/{id}PUT /api/story/{id}
Content-Type: application/json
{
"title": "Updated Title",
"content": "Updated content..."
}DELETE /api/story/{id}POST /api/story/{id}/favoriteResponse:
{
"code": 200,
"msg": "收藏成功"
}DELETE /api/story/{id}/favoritePOST /api/story/{id}/shareResponse:
{
"code": 200,
"msg": "操作成功",
"data": {
"shareToken": "abc123def456",
"shareUrl": "/api/story/shared/abc123def456"
}
}GET /api/story/shared/{shareToken}Response:
{
"code": 200,
"msg": "操作成功",
"data": {
"id": 1,
"title": "Tom's Adventure",
"content": "Once upon a time...",
"characterName": "Tom",
"objects": "[\"book\",\"lamp\"]",
"viewCount": 16
}
}POST /api/search/stories?keyword=adventure&threshold=0.7&maxResults=10Query Parameters:
keyword(optional): Search keywordthreshold(optional): Similarity threshold (0-1), default: 0.7maxResults(optional): Maximum results, default: 10
Response:
{
"code": 200,
"msg": "操作成功",
"data": [
{
"id": 1,
"title": "Tom's Adventure",
"content": "Once upon a time...",
"characterName": "Tom"
}
]
}POST /api/search/characters?keyword=tomResponse:
{
"code": 200,
"msg": "操作成功",
"data": [
{
"id": 1,
"name": "Tom",
"description": "A curious little boy",
"storyCount": 3
}
]
}POST /api/search/all?keyword=adventure&threshold=0.7&maxResults=10Response:
{
"code": 200,
"msg": "操作成功",
"data": {
"stories": [...],
"characters": [...],
"totalStories": 5,
"totalCharacters": 2
}
}CREATE TABLE `character` (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
description VARCHAR(500),
avatar_url VARCHAR(500),
story_count INT DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
del_flag CHAR(1) DEFAULT '0'
);CREATE TABLE story (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
character_id BIGINT NOT NULL,
title VARCHAR(255) NOT NULL,
content LONGTEXT NOT NULL,
objects JSON,
image_url VARCHAR(500),
embedding JSON,
embedding_model VARCHAR(100),
is_favorite TINYINT DEFAULT 0,
view_count INT DEFAULT 0,
share_count INT DEFAULT 0,
share_token VARCHAR(100) UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
del_flag CHAR(1) DEFAULT '0',
FOREIGN KEY (character_id) REFERENCES `character`(id) ON DELETE CASCADE
);CREATE TABLE story_favorite (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
story_id BIGINT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_user_story (user_id, story_id),
FOREIGN KEY (story_id) REFERENCES story(id) ON DELETE CASCADE
);| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request (validation error) |
| 401 | Unauthorized (invalid token) |
| 403 | Forbidden (no permission) |
| 404 | Not Found |
| 500 | Internal Server Error |
- Create a character:
curl -X POST http://localhost:9501/api/character/add \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Alice",
"description": "A brave girl"
}'- Generate a story from an image:
curl -X POST http://localhost:9501/api/story/generate \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
"imageType": "base64",
"characterId": 1
}'- Get generated stories:
curl -X GET "http://localhost:9501/api/story/list?pageNum=1&pageSize=10" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"- Share a story:
curl -X POST http://localhost:9501/api/story/1/share \
-H "Authorization: Bearer YOUR_JWT_TOKEN"- Supports Base64 encoded images (JPEG, PNG, GIF)
- Supports direct image URLs
- Automatic image format detection
- Uses Deepseek Vision API for object recognition
- Uses Deepseek Chat API
- Generates 200-300 word stories
- Includes all identified objects
- Educational and child-friendly content
- Simple English vocabulary for learners
- Automatic embedding generation for stories
- Uses Deepseek Embedding API
- Supports RAG-based semantic search
- Stored as JSON in database
- Average story generation time: 3-8 seconds
- Includes retry mechanism with exponential backoff
- Configurable timeout (default: 30 seconds)
- Caching of embeddings
Add to application-rag.yml:
rag:
deepseek:
api-key: ${DEEPSEEK_API_KEY}
api-endpoint: https://api.deepseek.com
embedding-path: /v1/embeddings
chat-path: /v1/chat/completions
embedding-model: deepseek-embedding
chat-model: deepseek-chat
multimodal-model: deepseek-chat
timeout: 30
max-retries: 3- Authentication: All endpoints require valid JWT token
- Authorization: Users can only access their own stories and characters
- Input Validation: All inputs are validated
- SQL Injection: Protected by MyBatis parameter binding
- XSS: Content is properly escaped in responses
- Rate Limiting: Consider implementing rate limiting for story generation
- Support for multiple images per story
- Story templates and themes
- Audio narration of stories
- Collaborative story writing
- Story collections and albums
- Export stories as PDF or ebook
- Multi-language support