Skip to content

Auto-Tag: auto/area-basic/seaborn #39

Auto-Tag: auto/area-basic/seaborn

Auto-Tag: auto/area-basic/seaborn #39

Workflow file for this run

name: "Bot: Auto-Tag"
run-name: "Auto-Tag: ${{ github.event.pull_request.head.ref }}"
on:
pull_request:
types: [closed]
jobs:
auto-tag:
name: Generate Tags for Merged Plot
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Check conditions
id: check
run: |
MERGED="${{ github.event.pull_request.merged }}"
BRANCH="${{ github.event.pull_request.head.ref }}"
LABELS="${{ join(github.event.pull_request.labels.*.name, ',') }}"
if [[ "$MERGED" != "true" ]]; then
echo "::notice::Skipping: PR was closed but not merged"
echo "should_run=false" >> $GITHUB_OUTPUT
exit 0
fi
if [[ ! "$LABELS" =~ ai-approved ]]; then
echo "::notice::Skipping: PR does not have 'ai-approved' label"
echo "should_run=false" >> $GITHUB_OUTPUT
exit 0
fi
if [[ ! "$BRANCH" =~ ^auto/ ]]; then
echo "::notice::Skipping: Branch '$BRANCH' is not auto/*"
echo "should_run=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "should_run=true" >> $GITHUB_OUTPUT
- name: Checkout code
if: steps.check.outputs.should_run == 'true'
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
if: steps.check.outputs.should_run == 'true'
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
if: steps.check.outputs.should_run == 'true'
uses: astral-sh/setup-uv@v7
- name: Install dependencies
if: steps.check.outputs.should_run == 'true'
run: |
uv sync --all-extras
- name: Extract spec ID from branch
if: steps.check.outputs.should_run == 'true'
id: extract_spec
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
SPEC_ID=$(echo "$BRANCH" | sed 's/auto\///')
echo "spec_id=$SPEC_ID" >> $GITHUB_OUTPUT
echo "Extracted spec ID: $SPEC_ID"
- name: Find related issue
if: steps.check.outputs.should_run == 'true'
id: find_issue
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Try to find issue from PR body
PR_BODY="${{ github.event.pull_request.body }}"
ISSUE_NUM=$(echo "$PR_BODY" | grep -oP '#\K\d+' | head -1 || echo "")
if [ -z "$ISSUE_NUM" ]; then
# Search by spec ID
SPEC_ID="${{ steps.extract_spec.outputs.spec_id }}"
ISSUE_NUM=$(gh issue list --label plot-request --search "$SPEC_ID in:title" --json number -q '.[0].number' || echo "")
fi
echo "issue_num=$ISSUE_NUM" >> $GITHUB_OUTPUT
echo "Found issue: #$ISSUE_NUM"
- name: Read spec and code files
if: steps.check.outputs.should_run == 'true'
id: read_files
run: |
SPEC_ID="${{ steps.extract_spec.outputs.spec_id }}"
# Read spec file
SPEC_FILE="specs/${SPEC_ID}.md"
if [ -f "$SPEC_FILE" ]; then
SPEC_CONTENT=$(cat "$SPEC_FILE")
echo "spec_exists=true" >> $GITHUB_OUTPUT
else
echo "spec_exists=false" >> $GITHUB_OUTPUT
SPEC_CONTENT=""
fi
# Find plot files
PLOT_FILES=$(find plots -name "*.py" -path "*/${SPEC_ID}/*" 2>/dev/null | head -5)
echo "plot_files<<EOF" >> $GITHUB_OUTPUT
echo "$PLOT_FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Generate tags with Claude
id: generate_tags
if: steps.check.outputs.should_run == 'true' && steps.read_files.outputs.spec_exists == 'true'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
SPEC_ID="${{ steps.extract_spec.outputs.spec_id }}"
# Read spec content
SPEC_CONTENT=$(cat "specs/${SPEC_ID}.md")
# Read first plot file as example
PLOT_FILE=$(echo "${{ steps.read_files.outputs.plot_files }}" | head -1)
if [ -n "$PLOT_FILE" ] && [ -f "$PLOT_FILE" ]; then
PLOT_CONTENT=$(cat "$PLOT_FILE")
else
PLOT_CONTENT=""
fi
# Create prompt for Claude
cat > /tmp/tag_prompt.txt << 'PROMPTEOF'
Analyze this plot specification and implementation to generate a hierarchical tag structure.
## Specification:
${SPEC_CONTENT}
## Implementation (example):
${PLOT_CONTENT}
## Task:
Generate a 5-level tag hierarchy for this plot. Format as JSON:
{
"level1_category": "visualization_type",
"level2_type": "specific_chart_type",
"level3_style": "style_variant",
"level4_features": ["feature1", "feature2"],
"level5_use_cases": ["use_case1", "use_case2"],
"search_tags": ["tag1", "tag2", "tag3"]
}
Categories:
- Level 1: Main category (scatter, bar, line, heatmap, distribution, comparison, etc.)
- Level 2: Specific type (scatter-basic, bar-grouped, line-multi, etc.)
- Level 3: Style variant (default, minimal, presentation, publication, etc.)
- Level 4: Features used (gridlines, annotations, legends, colors, etc.)
- Level 5: Use cases (exploratory, presentation, publication, dashboard, etc.)
Return ONLY valid JSON, no markdown formatting.
PROMPTEOF
# Replace placeholders
sed -i "s|\${SPEC_CONTENT}|${SPEC_CONTENT}|g" /tmp/tag_prompt.txt
sed -i "s|\${PLOT_CONTENT}|${PLOT_CONTENT}|g" /tmp/tag_prompt.txt
# Call Claude API (with timeout)
RESPONSE=$(curl -s --max-time 60 --connect-timeout 10 https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d "{
\"model\": \"claude-sonnet-4-20250514\",
\"max_tokens\": 1024,
\"messages\": [{
\"role\": \"user\",
\"content\": $(cat /tmp/tag_prompt.txt | jq -Rs .)
}]
}")
# Validate API response
if ! echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null 2>&1; then
echo "::warning::API response invalid or empty"
echo "Response: $(echo "$RESPONSE" | jq -r '.error // .' 2>/dev/null || echo "$RESPONSE")"
echo "tags_generated=false" >> $GITHUB_OUTPUT
exit 0
fi
# Extract tags from response
TAGS=$(echo "$RESPONSE" | jq -r '.content[0].text // empty')
if [ -n "$TAGS" ]; then
echo "$TAGS" > /tmp/generated_tags.json
echo "tags_generated=true" >> $GITHUB_OUTPUT
else
echo "tags_generated=false" >> $GITHUB_OUTPUT
fi
- name: Post tags to issue
if: steps.check.outputs.should_run == 'true' && steps.generate_tags.outputs.tags_generated == 'true' && steps.find_issue.outputs.issue_num != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ISSUE_NUM="${{ steps.find_issue.outputs.issue_num }}"
SPEC_ID="${{ steps.extract_spec.outputs.spec_id }}"
TAGS=$(cat /tmp/generated_tags.json)
# Format tags as markdown
cat > /tmp/tag_comment.md << COMMENTEOF
## 🏷️ Auto-Generated Tags
Plot \`${SPEC_ID}\` has been merged and tagged.
### Tag Hierarchy
\`\`\`json
${TAGS}
\`\`\`
### Quick Search Tags
$(echo "$TAGS" | jq -r '.search_tags // [] | map("- `" + . + "`") | join("\n")' 2>/dev/null || echo "- No search tags generated")
---
🤖 *Generated by [bot-auto-tag workflow](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*
COMMENTEOF
gh issue comment "$ISSUE_NUM" --body-file /tmp/tag_comment.md
- name: Save tags to database (placeholder)
if: steps.check.outputs.should_run == 'true' && steps.generate_tags.outputs.tags_generated == 'true'
run: |
# TODO: Implement database storage
# This would call an API endpoint to store the tags
echo "Tags generated for ${{ steps.extract_spec.outputs.spec_id }}"
echo "Database storage not yet implemented"
cat /tmp/generated_tags.json