はじめに
このプラットフォームは単にランダムなデザインを生成するだけではありません。AI は各ユーザーの美的嗜好を理解し、時間の経過とともにより適切なデザインを作成する必要があります。この記事では、オンボーディング データから好みを分析する AI モジュールである スタイル分析エンジン を構築します。
1. オンボーディングの流れ
User đăng ký platform
│
├── Upload 5–10 ảnh design yêu thích
│ (áo thun, artwork, meme, illustration...)
│
├── AI phân tích:
│ ├── Color palette preference
│ ├── Typography style
│ ├── Pattern/layout preference
│ └── Aesthetic category
│
└── Tạo User Style Profile
├── Style vector (CLIP embedding)
├── Dominant colors
├── Preferred categories
└── Confidence score
2. クリップベースのスタイルプロファイリング
class StyleProfiler:
"""Tạo style profile từ ảnh user upload"""
def __init__(self):
self.clip_model = CLIPModel.from_pretrained(
"openai/clip-vit-large-patch14-336"
)
self.clip_processor = CLIPProcessor.from_pretrained(
"openai/clip-vit-large-patch14-336"
)
self.color_extractor = ColorExtractor()
def create_profile(
self, images: list[Image.Image]
) -> StyleProfile:
# 1. Extract CLIP embeddings
embeddings = [
self._get_embedding(img) for img in images
]
# 2. Compute average style vector
style_vector = torch.stack(embeddings).mean(dim=0)
style_vector = style_vector / style_vector.norm()
# 3. Classify aesthetics
aesthetics = self._classify_aesthetics(images)
# 4. Extract color preferences
color_prefs = self._aggregate_colors(images)
# 5. Detect patterns
patterns = self._detect_patterns(images)
return StyleProfile(
style_vector=style_vector,
aesthetics=aesthetics,
color_preferences=color_prefs,
pattern_preferences=patterns,
confidence=self._calculate_confidence(embeddings),
)
def _classify_aesthetics(
self, images: list[Image.Image]
) -> dict:
"""Classify aesthetic style across all images"""
all_styles = {}
for img in images:
styles = self.style_analyzer.classify_style(img)
for style, score in styles.items():
if style not in all_styles:
all_styles[style] = []
all_styles[style].append(score)
# Average scores
avg_styles = {
style: sum(scores) / len(scores)
for style, scores in all_styles.items()
}
# Return top 3
sorted_styles = sorted(
avg_styles.items(), key=lambda x: x[1], reverse=True
)
return dict(sorted_styles[:3])
def _aggregate_colors(
self, images: list[Image.Image]
) -> list[dict]:
"""Tổng hợp color palette từ tất cả ảnh"""
all_colors = []
for img in images:
colors = self.color_extractor.extract_palette(img, n_colors=3)
all_colors.extend(colors)
# Cluster lại để tìm dominant colors
from sklearn.cluster import KMeans
import numpy as np
rgb_values = np.array([c["rgb"] for c in all_colors])
kmeans = KMeans(n_clusters=5, n_init=10, random_state=42)
kmeans.fit(rgb_values)
dominant = []
for center in kmeans.cluster_centers_:
rgb = tuple(center.astype(int))
dominant.append({
"rgb": rgb,
"hex": "#{:02x}{:02x}{:02x}".format(*rgb),
})
return dominant
def _calculate_confidence(
self, embeddings: list[torch.Tensor]
) -> float:
"""
Confidence = mức độ consistent của style
Nếu tất cả ảnh cùng style → confidence cao
Nếu ảnh rất đa dạng → confidence thấp
"""
if len(embeddings) < 2:
return 0.5
# Pairwise cosine similarity
similarities = []
for i in range(len(embeddings)):
for j in range(i + 1, len(embeddings)):
sim = torch.cosine_similarity(
embeddings[i], embeddings[j], dim=0
)
similarities.append(sim.item())
avg_similarity = sum(similarities) / len(similarities)
# Normalize to 0-1 range
return min(max(avg_similarity, 0), 1)
3. スタイルプロファイルのストレージ
@dataclass
class StyleProfile:
style_vector: torch.Tensor # CLIP embedding (768-dim)
aesthetics: dict # {"cyberpunk": 0.7, "neon": 0.5}
color_preferences: list[dict] # Top 5 colors
pattern_preferences: list[str] # ["geometric", "typography"]
confidence: float # 0-1
def to_storage(self) -> dict:
"""Serialize cho database storage"""
return {
"style_vector": self.style_vector.tolist(),
"aesthetics": self.aesthetics,
"color_preferences": self.color_preferences,
"pattern_preferences": self.pattern_preferences,
"confidence": self.confidence,
}
# Storage: Vector DB (Qdrant/Pinecone)
async def store_profile(
user_id: str, profile: StyleProfile
):
# Store style vector trong Vector DB
await vector_db.upsert(
collection="user_styles",
points=[{
"id": user_id,
"vector": profile.style_vector.tolist(),
"payload": {
"aesthetics": profile.aesthetics,
"colors": profile.color_preferences,
"confidence": profile.confidence,
},
}],
)
4. 類似ユーザーの発見
class SimilarUsersFinder:
"""Tìm users có gu tương tự (cho collaborative filtering)"""
async def find_similar(
self, user_id: str, top_k: int = 20
) -> list[dict]:
# Get user's style vector
user_profile = await vector_db.get(
collection="user_styles", id=user_id
)
# Search similar vectors
results = await vector_db.search(
collection="user_styles",
query_vector=user_profile.vector,
limit=top_k + 1, # +1 because self is included
)
# Exclude self
similar = [
r for r in results if r.id != user_id
]
return similar[:top_k]
概要
スタイル分析エンジン:
- オンボーディング — ユーザーが 5 ~ 10 枚の写真をアップロード → AI 分析
- CLIP プロファイリング — 美的センスを表す 768 次元のベクトル スタイルを作成します。
- 美的分類 — サイバーパンク、ミニマル、ヴィンテージ、ゲームを検出します...
- 色の集約 — 好みに基づいて主要な色を合成します
- 信頼スコアリング — スタイルの好みの明確さを評価します
- 類似ユーザー — 類似性ベクトルを介して類似ユーザーを検索します
次の記事: 行動学習 — AI は時間の経過とともに使用行動から学習します。