Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion auto-analyst-backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ migrations/
alembic.ini


*-2.db
*.db

schema*.md

Expand Down
3 changes: 0 additions & 3 deletions auto-analyst-backend/chat_database.db

This file was deleted.

986 changes: 682 additions & 304 deletions auto-analyst-backend/scripts/populate_agent_templates.py

Large diffs are not rendered by default.

268 changes: 165 additions & 103 deletions auto-analyst-backend/src/agents/agents.py

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions auto-analyst-backend/src/db/schemas/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ class AgentTemplate(Base):
category = Column(String(50), nullable=True) # 'Visualization', 'Modelling', 'Data Manipulation'
is_premium_only = Column(Boolean, default=False) # True if template requires premium subscription

# Agent variant support
variant_type = Column(String(20), default='individual') # 'planner', 'individual', or 'both'
base_agent = Column(String(100), nullable=True) # Base agent name for variants (e.g., 'preprocessing_agent')

# Status and metadata
is_active = Column(Boolean, default=True)

Expand Down
187 changes: 128 additions & 59 deletions auto-analyst-backend/src/routes/templates_routes.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion auto-analyst-frontend/components/chat/AgentSuggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ export default function AgentSuggestions({
// Fetch template agents
const fetchTemplateAgents = async (): Promise<AgentSuggestion[]> => {
try {
const templatesUrl = `${API_URL}/templates/categories`
// Only fetch individual variants for @ mentions
const templatesUrl = `${API_URL}/templates/categories?variant_type=individual`
const response = await fetch(templatesUrl)

if (response.ok) {
Expand Down
29 changes: 11 additions & 18 deletions auto-analyst-frontend/components/custom-templates/TemplateCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useState } from 'react'
import { motion } from 'framer-motion'
import { Sparkles, Lock, TrendingUp, Check } from 'lucide-react'
import { Badge } from '../ui/badge'
Expand All @@ -23,6 +23,8 @@ export default function TemplateCard({
wouldExceedMax = false,
onToggleChange
}: TemplateCardProps) {
const [imageError, setImageError] = useState(false)

// User can only toggle if they have access (covers both free and premium users)
// Premium-only templates are only toggleable by premium users (hasAccess = true for premium)
// Also cannot disable if this is the last template
Expand Down Expand Up @@ -54,6 +56,9 @@ export default function TemplateCard({

const statusInfo = getStatusInfo()

// Remove "(Planner)" suffix from display name since we're in a planner context
const cleanDisplayName = template.display_name?.replace(/\s*\(Planner\)\s*$/i, '') || template.template_name

return (
<motion.div
initial={{ opacity: 0, y: 20 }}
Expand Down Expand Up @@ -82,32 +87,20 @@ export default function TemplateCard({
<div className="flex items-center gap-2 mb-2">
{/* Template Icon */}
<div className="flex-shrink-0 w-5 h-5 flex items-center justify-center">
{template.icon_url ? (
<>
{template.icon_url && !imageError ? (
<img
src={template.icon_url}
alt={`${template.template_name} icon`}
className="w-5 h-5 object-contain"
onError={(e) => {
// Fallback to Sparkles icon if image fails to load
const target = e.target as HTMLImageElement;
target.style.display = 'none';
const fallback = target.nextElementSibling as HTMLElement;
if (fallback) {
fallback.style.display = 'block';
}
}}
/>
{/* Fallback icon - hidden by default when image exists */}
<Sparkles className="w-4 h-4 text-[#FF7F7F]" style={{ display: 'none' }} />
</>
onError={() => setImageError(true)}
/>
) : (
// Show Sparkles icon if no icon_url
// Show Sparkles icon if no icon_url or image failed to load
<Sparkles className="w-4 h-4 text-[#FF7F7F]" />
)}
</div>

<h3 className="font-medium text-gray-900 text-sm">{template.display_name}</h3>
<h3 className="font-medium text-gray-900 text-sm">{cleanDisplayName}</h3>
<div className="flex items-center gap-1">
{template.is_premium_only && (
<Badge variant="outline" className="text-xs border-[#FF7F7F] text-[#FF7F7F] px-1 py-0 h-5 flex items-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export default function TemplatesModal({
const loadTemplatesForFreeUsers = async () => {
setLoading(true)
try {
// Fetch all templates (no user-specific data needed)
const response = await fetch(`${API_URL}/templates/`).catch(err => {
// Fetch all planner templates (no user-specific data needed for free users)
const response = await fetch(`${API_URL}/templates/?variant_type=planner`).catch(err => {
throw new Error(`Templates endpoint failed: ${err.message}`)
})

Expand Down Expand Up @@ -97,14 +97,14 @@ export default function TemplatesModal({
const loadData = async () => {
setLoading(true)
try {
// Fetch global template data with global usage counts
// Fetch global template data with global usage counts (planner variants only for modal)
const [templatesResponse, preferencesResponse] = await Promise.all([
fetch(`${API_URL}/templates/`).catch(err => {
fetch(`${API_URL}/templates/?variant_type=planner`).catch(err => {
throw new Error(`Templates endpoint failed: ${err.message}`)
}), // Global templates with global usage counts
fetch(`${API_URL}/templates/user/${userId}`).catch(err => {
}), // Global planner templates with global usage counts
fetch(`${API_URL}/templates/user/${userId}?variant_type=planner`).catch(err => {
throw new Error(`Preferences endpoint failed: ${err.message}`)
}) // User preferences with per-user usage
}) // User preferences for planner variants
])

// Check templates response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export function useTemplates({ userId, enabled = true }: UseTemplatesProps): Use

try {
const [templatesResponse, preferencesResponse] = await Promise.all([
fetch(`${API_URL}/templates/`).catch(err => {
fetch(`${API_URL}/templates/?variant_type=planner`).catch(err => {
throw new Error(`Templates endpoint failed: ${err.message}`)
}),
fetch(`${API_URL}/templates/user/${userId}`).catch(err => {
fetch(`${API_URL}/templates/user/${userId}?variant_type=planner`).catch(err => {
throw new Error(`Preferences endpoint failed: ${err.message}`)
})
])
Expand Down
6 changes: 5 additions & 1 deletion auto-analyst-frontend/components/landing/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ export default function HeroSection() {
}, [])

const handleGetStarted = () => {
router.push('/chat')
if (session) {
router.push('/chat')
} else {
router.push('/login?callbackUrl=/chat')
}
}

const handleCustomSolution = () => {
Expand Down
Loading