File size: 5,802 Bytes
9281fab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""
Code Generator Agent for CoDA.

Synthesizes executable Python visualization code by integrating
specifications from upstream agents.
"""

from typing import Optional

from pydantic import BaseModel, Field

from coda.core.base_agent import AgentContext, BaseAgent
from coda.core.llm import LLMProvider
from coda.core.memory import SharedMemory


class GeneratedCode(BaseModel):
    """Structured output from the Code Generator."""
    
    code: str = Field(default="", description="The generated Python code")
    dependencies: list[str] = Field(
        default_factory=lambda: ["matplotlib", "pandas"],
        description="Required Python packages"
    )
    output_filename: str = Field(
        default="output.png",
        description="Name of the output visualization file"
    )
    documentation: str = Field(
        default="Generated visualization code",
        description="Brief documentation of the code"
    )
    quality_score: float = Field(
        default=5.0,
        description="Self-assessed code quality (0-10)"
    )
    potential_issues: list[str] = Field(
        default_factory=list,
        description="Potential issues or edge cases"
    )


class CodeGeneratorAgent(BaseAgent[GeneratedCode]):
    """
    Generates executable Python visualization code.
    
    Integrates all upstream specifications (data processing, visual mapping,
    design specs) into working code.
    """
    
    MEMORY_KEY = "generated_code"
    
    def __init__(
        self,
        llm: LLMProvider,
        memory: SharedMemory,
        name: Optional[str] = None,
    ) -> None:
        super().__init__(llm, memory, name or "CodeGenerator")
    
    def _get_system_prompt(self) -> str:
        return """You are an expert Python Developer specializing in data visualization.

Your expertise is in writing clean, efficient, and well-documented Python code for data visualization using matplotlib, seaborn, and pandas.

Your responsibilities:
1. Generate complete, executable Python code
2. Integrate all specifications from the design and mapping agents
3. Handle data loading and transformation correctly
4. Apply proper styling and formatting
5. Include error handling for robustness
6. Write clear documentation

Code requirements:
- Use matplotlib and seaborn as primary libraries
- Include all necessary imports at the top
- Load data from the specified file paths
- Apply all transformations before plotting
- Set figure size, colors, and labels as specified
- Save the output to a file (PNG format)
- Use descriptive variable names
- Add comments for complex operations

IMPORTANT styling rules:
- For seaborn barplots, ALWAYS use hue parameter: sns.barplot(..., hue='category_column', legend=False)
- Use ONLY these reliable palettes: 'viridis', 'plasma', 'inferno', 'magma', 'cividis', 'Deep', 'Muted', 'Pastel'
- DO NOT use complex or custom named palettes like 'tableau10' or 'husl' unless you are sure.
- When in doubt, omit the palette argument or use 'viridis'.
- Always use plt.tight_layout() before saving.

Always respond with a valid JSON object containing the code and metadata."""
    
    def _build_prompt(self, context: AgentContext) -> str:
        data_analysis = self._get_from_memory("data_analysis") or {}
        visual_mapping = self._get_from_memory("visual_mapping") or {}
        design_spec = self._get_from_memory("design_spec") or {}
        search_results = self._get_from_memory("search_results") or {}
        
        file_info = data_analysis.get("files", [])
        data_paths = [f.get("file_path", "") for f in file_info] if file_info else context.data_paths
        
        code_examples = search_results.get("examples", [])
        examples_section = ""
        if code_examples:
            examples_section = "\nReference Code Examples:\n"
            for ex in code_examples[:2]:
                if isinstance(ex, dict):
                    examples_section += f"```python\n# {ex.get('title', 'Example')}\n{ex.get('code', '')}\n```\n"
        
        feedback_section = ""
        if context.feedback:
            feedback_section = f"""
Code Feedback (iteration {context.iteration}):
{context.feedback}

Fix the issues mentioned in the feedback.
"""
        
        return f"""Generate Python visualization code based on the following specifications.

User Query: {context.query}

Data Files: {data_paths}

Visual Mapping:
- Chart Type: {visual_mapping.get('chart_type', 'line')}
- X-Axis: {visual_mapping.get('x_axis') or 'Not specified (infer from data or chart type)'}
- Y-Axis: {visual_mapping.get('y_axis') or 'Not specified (infer from data or chart type)'}
- Color Encoding: {visual_mapping.get('color_encoding')}
- Transformations: {visual_mapping.get('transformations', [])}

Design Specification:
- Colors: {design_spec.get('color_scheme', {})}
- Layout: {design_spec.get('layout', {})}
- Typography: {design_spec.get('typography', {})}
- Annotations: {design_spec.get('annotations', [])}
- Guidelines: {design_spec.get('implementation_guidelines', [])}
{examples_section}{feedback_section}

Generate a complete Python script that:
1. Imports all necessary libraries
2. Loads the data file(s)
3. Applies required transformations
4. Creates the visualization with specified styling
5. Saves to 'output.png'

Respond with a JSON object:
- code: Complete Python code as a string
- dependencies: List of required packages
- output_filename: Output file name
- documentation: Brief description
- quality_score: Self-assessment 0-10
- potential_issues: List of potential issues

JSON Response:"""
    
    def _parse_response(self, response: str) -> GeneratedCode:
        data = self._extract_json(response)
        return GeneratedCode(**data)
    
    def _get_output_key(self) -> str:
        return self.MEMORY_KEY