Codette3.0 / src /components /ai_driven_creativity.py
Raiff1982's picture
Upload 117 files
6d6b8af verified
"""
AI-Driven Creativity Component for Codette
Handles creative generation and novel idea synthesis
"""
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime
import random
logger = logging.getLogger(__name__)
try:
import numpy as np
except Exception:
np = None
class AIDrivenCreativity:
"""Manages AI-driven creative processes for Codette"""
def __init__(self,
creativity_threshold: float = 0.7,
novelty_weight: float = 0.6,
memory_depth: int = 100):
"""Initialize the creativity engine"""
self.creativity_threshold = creativity_threshold
self.novelty_weight = novelty_weight
self.memory_depth = memory_depth
# Initialize state
self.creative_memory = []
self.idea_patterns = {}
self.current_state = {
"creativity_level": 1.0,
"exploration_phase": "divergent",
"pattern_recognition": {},
"active_concepts": set()
}
logger.info("AI-Driven Creativity engine initialized")
def generate_creative_response(self,
input_data: Dict[str, Any],
context: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Generate a creative response to input"""
try:
# Process input
processed_input = self._process_input(input_data)
# Generate ideas
ideas = self._generate_ideas(processed_input, context)
# Evaluate and select best ideas
evaluated_ideas = self._evaluate_ideas(ideas)
# Synthesize final response
response = self._synthesize_response(evaluated_ideas)
# Update memory and patterns
self._update_memory(response)
return response
except Exception as e:
logger.error(f"Error generating creative response: {e}")
return {"error": str(e)}
def _process_input(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
"""Process and analyze input for creative potential"""
try:
# Extract key concepts
concepts = self._extract_concepts(input_data)
# Analyze patterns
patterns = self._analyze_patterns(concepts)
# Calculate creative potential
creative_potential = self._calculate_creative_potential(concepts, patterns)
return {
"concepts": concepts,
"patterns": patterns,
"creative_potential": creative_potential,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"Error processing input: {e}")
return {}
def _generate_ideas(self,
processed_input: Dict[str, Any],
context: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
"""Generate multiple creative ideas"""
ideas = []
try:
concepts = processed_input.get("concepts", [])
patterns = processed_input.get("patterns", {})
# Generate through different methods
ideas.extend(self._generate_by_combination(concepts))
ideas.extend(self._generate_by_analogy(concepts, patterns))
ideas.extend(self._generate_by_mutation(concepts))
if context:
ideas.extend(self._generate_contextual_ideas(concepts, context))
except Exception as e:
logger.error(f"Error generating ideas: {e}")
return ideas
def _evaluate_ideas(self,
ideas: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Evaluate and rank generated ideas"""
try:
evaluated_ideas = []
for idea in ideas:
# Calculate metrics
novelty = self._calculate_novelty(idea)
usefulness = self._calculate_usefulness(idea)
coherence = self._calculate_coherence(idea)
# Combine scores
total_score = (
novelty * self.novelty_weight +
usefulness * 0.3 +
coherence * 0.1
)
evaluated_ideas.append({
"idea": idea,
"scores": {
"novelty": novelty,
"usefulness": usefulness,
"coherence": coherence,
"total": total_score
}
})
# Sort by total score
return sorted(evaluated_ideas,
key=lambda x: x["scores"]["total"],
reverse=True)
except Exception as e:
logger.error(f"Error evaluating ideas: {e}")
return []
def _synthesize_response(self,
evaluated_ideas: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Synthesize final creative response"""
try:
if not evaluated_ideas:
return {
"status": "error",
"message": "No valid ideas generated"
}
# Select top ideas
top_ideas = evaluated_ideas[:3]
# Combine elements from top ideas
synthesized = self._combine_ideas(top_ideas)
return {
"status": "success",
"creative_response": synthesized,
"supporting_ideas": top_ideas,
"creativity_metrics": {
"novelty": float(np.mean([i["scores"]["novelty"] for i in top_ideas])) if np is not None else float(sum(i["scores"]["novelty"] for i in top_ideas)/len(top_ideas)),
"usefulness": float(np.mean([i["scores"]["usefulness"] for i in top_ideas])) if np is not None else float(sum(i["scores"]["usefulness"] for i in top_ideas)/len(top_ideas)),
"coherence": float(np.mean([i["scores"]["coherence"] for i in top_ideas])) if np is not None else float(sum(i["scores"]["coherence"] for i in top_ideas)/len(top_ideas))
},
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"Error synthesizing response: {e}")
return {"status": "error", "message": str(e)}
def _extract_concepts(self, data: Dict[str, Any]) -> List[str]:
"""Extract key concepts from input data"""
concepts = set()
try:
# Extract from different data types
if isinstance(data, dict):
for key, value in data.items():
concepts.add(str(key))
if isinstance(value, (str, int, float)):
concepts.add(str(value))
elif isinstance(value, (list, dict)):
concepts.update(self._extract_concepts({"item": value}))
elif isinstance(data, list):
for item in data:
if isinstance(item, (str, int, float)):
concepts.add(str(item))
elif isinstance(item, (list, dict)):
concepts.update(self._extract_concepts({"item": item}))
except Exception as e:
logger.error(f"Error extracting concepts: {e}")
return list(concepts)
def _analyze_patterns(self, concepts: List[str]) -> Dict[str, Any]:
"""Analyze patterns in concepts"""
patterns = {}
try:
# Frequency analysis
pattern_freq = {}
for concept in concepts:
for stored_pattern in self.idea_patterns:
if concept in stored_pattern:
pattern_freq[stored_pattern] = pattern_freq.get(stored_pattern, 0) + 1
# Find associations
associations = {}
for i, concept1 in enumerate(concepts):
for concept2 in concepts[i+1:]:
pair = (concept1, concept2)
if pair in self.idea_patterns:
associations[pair] = self.idea_patterns[pair]
patterns = {
"frequencies": pattern_freq,
"associations": associations,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"Error analyzing patterns: {e}")
return patterns
def _calculate_creative_potential(self,
concepts: List[str],
patterns: Dict[str, Any]) -> float:
"""Calculate creative potential of input"""
try:
if not concepts:
return 0.0
# Factor calculations
novelty = len(set(concepts) - set(self.current_state["active_concepts"]))
pattern_richness = len(patterns.get("associations", {}))
concept_diversity = len(set(concepts))
# Combine factors
potential = (
0.4 * (novelty / max(1, len(concepts))) +
0.3 * (pattern_richness / max(1, len(concepts) * (len(concepts) - 1) / 2)) +
0.3 * (concept_diversity / max(1, len(concepts)))
)
return min(1.0, max(0.0, potential))
except Exception as e:
logger.error(f"Error calculating creative potential: {e}")
return 0.0
def _generate_by_combination(self, concepts: List[str]) -> List[Dict[str, Any]]:
"""Generate ideas by combining concepts"""
ideas = []
try:
# Generate random combinations
for _ in range(min(len(concepts) * 2, 10)):
if len(concepts) >= 2:
selected = random.sample(concepts, 2)
ideas.append({
"type": "combination",
"elements": selected,
"description": f"Fusion of {selected[0]} and {selected[1]}",
"timestamp": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Error in combination generation: {e}")
return ideas
def _generate_by_analogy(self,
concepts: List[str],
patterns: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Generate ideas through analogical thinking"""
ideas = []
try:
associations = patterns.get("associations", {})
for concept in concepts:
# Find related concepts from patterns
related = [
pair[1] for pair in associations.keys()
if pair[0] == concept
]
if related:
analogy = random.choice(related)
ideas.append({
"type": "analogy",
"source": concept,
"target": analogy,
"description": f"Analogical mapping from {concept} to {analogy}",
"timestamp": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Error in analogy generation: {e}")
return ideas
def _generate_by_mutation(self, concepts: List[str]) -> List[Dict[str, Any]]:
"""Generate ideas by mutating existing concepts"""
ideas = []
try:
for concept in concepts:
# Simple character mutation
if len(concept) > 3:
mutated = list(concept)
pos = random.randint(0, len(mutated) - 1)
mutated[pos] = chr(ord(mutated[pos]) + 1)
ideas.append({
"type": "mutation",
"original": concept,
"mutated": "".join(mutated),
"description": f"Mutation of {concept}",
"timestamp": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Error in mutation generation: {e}")
return ideas
def _generate_contextual_ideas(self,
concepts: List[str],
context: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Generate ideas based on context"""
ideas = []
try:
context_concepts = self._extract_concepts(context)
# Find intersections between context and current concepts
common = set(concepts) & set(context_concepts)
for concept in common:
ideas.append({
"type": "contextual",
"concept": concept,
"context": str(context),
"description": f"Contextual application of {concept}",
"timestamp": datetime.now().isoformat()
})
except Exception as e:
logger.error(f"Error in contextual generation: {e}")
return ideas
def _calculate_novelty(self, idea: Dict[str, Any]) -> float:
"""Calculate novelty of an idea"""
try:
# Compare with memory
similar_ideas = [
mem for mem in self.creative_memory
if self._calculate_similarity(idea, mem) > 0.8
]
return 1.0 - (len(similar_ideas) / max(1, len(self.creative_memory)))
except Exception as e:
logger.error(f"Error calculating novelty: {e}")
return 0.0
def _calculate_usefulness(self, idea: Dict[str, Any]) -> float:
"""Calculate potential usefulness of an idea"""
try:
# Basic heuristics for usefulness
type_scores = {
"combination": 0.8, # Combinations often useful
"analogy": 0.7, # Analogies can provide insights
"mutation": 0.5, # Mutations are less predictable
"contextual": 0.9 # Contextual ideas highly useful
}
base_score = type_scores.get(idea.get("type", ""), 0.5)
# Adjust based on description length (proxy for complexity)
description = idea.get("description", "")
length_factor = min(1.0, len(description) / 100) # Normalize
return (base_score + length_factor) / 2
except Exception as e:
logger.error(f"Error calculating usefulness: {e}")
return 0.0
def _calculate_coherence(self, idea: Dict[str, Any]) -> float:
"""Calculate internal coherence of an idea"""
try:
# Check if all required fields are present
required_fields = ["type", "description", "timestamp"]
completeness = sum(1 for field in required_fields if field in idea) / len(required_fields)
# Check for internal consistency
consistency = 1.0
if idea.get("type") == "combination" and "elements" not in idea:
consistency *= 0.5
elif idea.get("type") == "analogy" and ("source" not in idea or "target" not in idea):
consistency *= 0.5
elif idea.get("type") == "mutation" and ("original" not in idea or "mutated" not in idea):
consistency *= 0.5
return (completeness + consistency) / 2
except Exception as e:
logger.error(f"Error calculating coherence: {e}")
return 0.0
def _calculate_similarity(self, idea1: Dict[str, Any], idea2: Dict[str, Any]) -> float:
"""Calculate similarity between two ideas"""
try:
# Compare types
type_similarity = 1.0 if idea1.get("type") == idea2.get("type") else 0.0
# Compare descriptions
desc1 = idea1.get("description", "").lower()
desc2 = idea2.get("description", "").lower()
words1 = set(desc1.split())
words2 = set(desc2.split())
if not words1 or not words2:
desc_similarity = 0.0
else:
common_words = words1 & words2
desc_similarity = len(common_words) / len(words1 | words2)
return (type_similarity + desc_similarity) / 2
except Exception as e:
logger.error(f"Error calculating similarity: {e}")
return 0.0
def _combine_ideas(self, ideas: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Combine multiple ideas into a cohesive response"""
try:
if not ideas:
return {}
# Extract best elements
elements = []
descriptions = []
for idea in ideas:
idea_data = idea.get("idea", {})
if "elements" in idea_data:
elements.extend(idea_data["elements"])
if "description" in idea_data:
descriptions.append(idea_data["description"])
# Combine into new idea
combined = {
"type": "synthesis",
"elements": list(set(elements)),
"description": " | ".join(descriptions[:2]), # Limit description length
"component_ideas": len(ideas),
"timestamp": datetime.now().isoformat()
}
return combined
except Exception as e:
logger.error(f"Error combining ideas: {e}")
return {}
def _update_memory(self, response: Dict[str, Any]):
"""Update creative memory and patterns"""
try:
# Add to memory
self.creative_memory.append(response)
# Trim memory if needed
if len(self.creative_memory) > self.memory_depth:
self.creative_memory = self.creative_memory[-self.memory_depth:]
# Update patterns
if "creative_response" in response:
elements = response["creative_response"].get("elements", [])
for i, elem1 in enumerate(elements):
for elem2 in elements[i+1:]:
self.idea_patterns[(elem1, elem2)] = datetime.now().isoformat()
# Update current state
self.current_state["creativity_level"] = np.mean([
response.get("creativity_metrics", {}).get("novelty", 0.5),
response.get("creativity_metrics", {}).get("usefulness", 0.5)
]) if np is not None else float(sum([
response.get("creativity_metrics", {}).get("novelty", 0.5),
response.get("creativity_metrics", {}).get("usefulness", 0.5)
]) / 2)
# Update active concepts
if "creative_response" in response:
self.current_state["active_concepts"].update(
response["creative_response"].get("elements", [])
)
except Exception as e:
logger.error(f"Error updating memory: {e}")
def get_state(self) -> Dict[str, Any]:
"""Get current state of the creativity engine"""
return self.current_state.copy()
def get_memory(self) -> List[Dict[str, Any]]:
"""Get creative memory"""
return self.creative_memory.copy()
def get_patterns(self) -> Dict[str, Any]:
"""Get identified idea patterns"""
return self.idea_patterns.copy()