feat: Add AI quality features - character memory, content filter, style guard, quality gate
This commit is contained in:
208
frontend/src/services/quality-api.ts
Normal file
208
frontend/src/services/quality-api.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* Quality API Client
|
||||
*
|
||||
* Provides client methods for AI quality features:
|
||||
* - Character memory management
|
||||
* - Content filtering
|
||||
* - Style guard
|
||||
* - Quality gate evaluation
|
||||
*/
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api'
|
||||
|
||||
export interface Character {
|
||||
id: string
|
||||
name: string
|
||||
appearance_description: string
|
||||
clothing_description: string
|
||||
distinctive_features: string[]
|
||||
character_type: string
|
||||
reference_image?: string
|
||||
}
|
||||
|
||||
export interface ContentCheckResult {
|
||||
passed: boolean
|
||||
category: 'safe' | 'sensitive' | 'blocked'
|
||||
flagged_items: string[]
|
||||
reason?: string
|
||||
}
|
||||
|
||||
export interface StyleAnchor {
|
||||
color_palette: string
|
||||
art_style: string
|
||||
composition_style: string
|
||||
texture: string
|
||||
lighting: string
|
||||
style_prefix: string
|
||||
reference_image?: string
|
||||
}
|
||||
|
||||
export interface QualityScore {
|
||||
overall_score: number
|
||||
aesthetic_score: number
|
||||
alignment_score: number
|
||||
technical_score: number
|
||||
passed: boolean
|
||||
issues: string[]
|
||||
}
|
||||
|
||||
class QualityApiClient {
|
||||
private baseUrl = API_BASE
|
||||
|
||||
// ============================================================
|
||||
// Character Memory
|
||||
// ============================================================
|
||||
|
||||
async getCharacters(storyboardId: string): Promise<Character[]> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/characters/${storyboardId}`
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to get characters')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async createCharacter(
|
||||
storyboardId: string,
|
||||
data: Omit<Character, 'id'>
|
||||
): Promise<Character> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/characters/${storyboardId}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
}
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create character')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async updateCharacter(
|
||||
storyboardId: string,
|
||||
charId: string,
|
||||
data: Omit<Character, 'id'>
|
||||
): Promise<Character> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/characters/${storyboardId}/${charId}`,
|
||||
{
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
}
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update character')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async deleteCharacter(storyboardId: string, charId: string): Promise<void> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/characters/${storyboardId}/${charId}`,
|
||||
{ method: 'DELETE' }
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete character')
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Content Filter
|
||||
// ============================================================
|
||||
|
||||
async checkContent(text: string): Promise<ContentCheckResult> {
|
||||
const response = await fetch(`${this.baseUrl}/quality/check-content`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to check content')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Style Guard
|
||||
// ============================================================
|
||||
|
||||
async extractStyle(
|
||||
storyboardId: string,
|
||||
imagePath: string
|
||||
): Promise<StyleAnchor> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/extract-style/${storyboardId}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ image_path: imagePath }),
|
||||
}
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to extract style')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async getStyle(storyboardId: string): Promise<StyleAnchor | null> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/style/${storyboardId}`
|
||||
)
|
||||
if (response.status === 404) {
|
||||
return null
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to get style')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async applyStyle(
|
||||
storyboardId: string,
|
||||
prompt: string
|
||||
): Promise<{ styled_prompt: string }> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/quality/apply-style/${storyboardId}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt }),
|
||||
}
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to apply style')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Quality Gate
|
||||
// ============================================================
|
||||
|
||||
async evaluateImage(
|
||||
imagePath: string,
|
||||
prompt: string,
|
||||
narration?: string
|
||||
): Promise<QualityScore> {
|
||||
const response = await fetch(`${this.baseUrl}/quality/evaluate-image`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
image_path: imagePath,
|
||||
prompt,
|
||||
narration,
|
||||
}),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to evaluate image')
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const qualityApi = new QualityApiClient()
|
||||
Reference in New Issue
Block a user