package projects
import (
"context"
"fmt"
"log/slog"
"github.com/firebase/genkit/go/ai"
)
type classificationInput struct {
Projects []projectInfo `json:"projects"`
}
type projectInfo struct {
Number int `json:"number"`
Title string `json:"title"`
Description string `json:"description"`
}
type classificationOutput struct {
Classifications []projectClassification `json:"classifications"`
}
type projectClassification struct {
Number int `json:"number"`
Category string `json:"category"`
Reasoning string `json:"reasoning"`
}
func (s *Service) classifyProjects(ctx context.Context, projects []Project) error {
if len(projects) == 0 {
return nil
}
if s.classifierPrompt == nil {
return fmt.Errorf("classifier prompt not configured")
}
input := classificationInput{
Projects: make([]projectInfo, 0),
}
projectMap := make(map[int]*Project)
for i := range projects {
proj := &projects[i]
projectMap[proj.Number] = proj
if proj.Category == "" && !proj.Closed {
input.Projects = append(input.Projects, projectInfo{
Number: proj.Number,
Title: proj.Title,
Description: proj.Description,
})
}
}
if len(input.Projects) == 0 {
slog.Info("no projects need classification")
return nil
}
slog.Info("classifying projects with LLM", "count", len(input.Projects))
resp, err := s.classifierPrompt.Execute(ctx, ai.WithInput(input))
if err != nil {
return fmt.Errorf("LLM classification failed: %w", err)
}
var output classificationOutput
if err := resp.Output(&output); err != nil {
return fmt.Errorf("failed to parse classification output: %w", err)
}
for _, classification := range output.Classifications {
if proj, exists := projectMap[classification.Number]; exists {
proj.Category = classification.Category
proj.CategoryReasoning = classification.Reasoning
slog.Info("classified project",
"number", classification.Number,
"title", proj.Title,
"category", classification.Category,
"reasoning", classification.Reasoning)
}
}
return nil
}