Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ coverage.xml
.tox/
.nox/
.pytest_cache

# Test files and generated data
SeedsInstructions.json
seeds_housing.json
app/test_models.py
freeform_data_*.json

#old code
app/frontend/
app/launch_streamlit.py
Expand Down
1 change: 1 addition & 0 deletions app/client/src/api/Datasets/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type DatasetResponse = {
schema: string | null;
custom_prompt: string;
total_count: number;
completed_rows: number | null;
num_questions: number;
job_id: string;
job_name: string;
Expand Down
22 changes: 13 additions & 9 deletions app/client/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import {
const baseUrl = import.meta.env.VITE_AMP_URL;

export const usefetchTopics = (useCase: string): UseFetchApiReturn<FetchTopicsResp> => {
const url = `${baseUrl}/use-cases/${isEmpty(useCase) ? 'custom' : useCase}/topics`;
const url = isEmpty(useCase) ? '' : `${baseUrl}/use-cases/${useCase}/topics`;
return useFetch(url);
}

export const useFetchExamples = (useCase: string): UseFetchApiReturn<FetchExamplesResp> => {
const url = `${baseUrl}/${isEmpty(useCase) ? 'custom' : useCase}/gen_examples`;
const url = isEmpty(useCase) ? '' : `${baseUrl}/${useCase}/gen_examples`;
return useFetch(url);
}

Expand All @@ -27,21 +27,25 @@ export const useFetchModels = (): UseFetchApiReturn<FetchModelsResp> => {
return useFetch(url);
}

export const useFetchDefaultPrompt = (useCase: string, workflowType?: WorkerType): UseFetchApiReturn<FetchDefaultPromptResp> => {
let url = `${baseUrl}/${isEmpty(useCase) ? 'custom' : useCase}/gen_prompt`;
export const useFetchDefaultPrompt = (useCase: string, workflowType?: string): UseFetchApiReturn<FetchDefaultPromptResp> => {
if (isEmpty(useCase)) {
return { data: null, loading: false, error: null };
}

let url = `${baseUrl}/${useCase}/gen_prompt`;
if (workflowType && workflowType === 'freeform') {
url = `${baseUrl}/${isEmpty(useCase) ? 'custom' : useCase}/gen_freeform_prompt`;
url = `${baseUrl}/${useCase}/gen_freeform_prompt`;
}
return useFetch(url);
}

export const useFetchDefaultSchema = (): UseFetchApiReturn<FetchDefaultSchemaResp> => {
const url = `${baseUrl}/sql_schema`;
export const useFetchDefaultSchema = (shouldFetch: boolean = true): UseFetchApiReturn<FetchDefaultSchemaResp> => {
const url = shouldFetch ? `${baseUrl}/sql_schema` : '';
return useFetch(url);
}

export const useFetchDefaultModelParams = (): UseFetchApiReturn<FetchDefaultParamsResp> => {
const url = `${baseUrl}/model/parameters`;
export const useFetchDefaultModelParams = (shouldFetch: boolean = true): UseFetchApiReturn<FetchDefaultParamsResp> => {
const url = shouldFetch ? `${baseUrl}/model/parameters` : '';
return useFetch(url);
}

Expand Down
136 changes: 132 additions & 4 deletions app/client/src/api/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { useState, useMemo, useEffect } from 'react';
import { UseDeferredFetchApiReturn, UseFetchApiReturn } from './types';


import { useQuery } from '@tanstack/react-query';

export function useFetch<T>(url: string): UseFetchApiReturn<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<Error | null>(null);
const memoizedUrl = useMemo(() => url, [url]);

useEffect(() => {
// Don't make API call if URL is empty (for regeneration scenarios)
if (!memoizedUrl || memoizedUrl.trim() === '') {
setData(null);
setLoading(false);
setError(null);
return;
}

setLoading(true);
const fetchData = async () => {
try {
const response = await fetch(memoizedUrl, {
Expand All @@ -29,7 +37,12 @@ export function useFetch<T>(url: string): UseFetchApiReturn<T> {
fetchData();
}, [memoizedUrl]);

return { data, loading, error };
// Return false for loading when URL is empty
return {
data,
loading: (!memoizedUrl || memoizedUrl.trim() === '') ? false : loading,
error
};
}

interface UseGetApiReturn<T> {
Expand Down Expand Up @@ -77,6 +90,7 @@ export function useGetApi<T>(url: string): UseGetApiReturn<T> {

return { data, loading, error, triggerGet };
}

export function useDeferredFetch<T>(url: string): UseDeferredFetchApiReturn<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(true);
Expand Down Expand Up @@ -192,3 +206,117 @@ export function useDeleteApi<T>(url: string): UseDeleteApiReturn<T> {
return { data, loading, error, triggerDelete };
}

// Use case types and enums
export enum UseCaseId {
CODE_GENERATION = 'code_generation',
TEXT2SQL = 'text2sql',
CUSTOM = 'custom',
LENDING_DATA = 'lending_data',
CREDIT_CARD_DATA = 'credit_card_data',
TICKETING_DATASET = 'ticketing_dataset',
}

export interface UseCase {
id: string;
name: string;
}

export interface UseCasesResponse {
usecases: UseCase[];
}

const fetchUseCases = async (): Promise<UseCasesResponse> => {
const BASE_API_URL = import.meta.env.VITE_AMP_URL;
const response = await fetch(`${BASE_API_URL}/use-cases`);
if (!response.ok) {
throw new Error('Failed to fetch use cases');
}
return response.json();
};

export const useUseCases = () => {
return useQuery<UseCasesResponse>({
queryKey: ['useCases'],
queryFn: fetchUseCases,
staleTime: 10 * 60 * 1000, // Cache for 10 minutes
retry: 3, // Retry 3 times on failure
retryDelay: (attemptIndex: number) => Math.min(1000 * 2 ** attemptIndex, 30000), // Exponential backoff
refetchOnWindowFocus: false, // Don't refetch when window gains focus
refetchOnMount: false, // Don't refetch on component mount if data exists
});
};

export const useUseCaseMapping = () => {
const { data: useCasesData, isLoading, isError, error } = useUseCases();

// Create a lookup map for fast O(1) access
const useCaseMap = useMemo(() => {
if (!useCasesData?.usecases) return {};

return (useCasesData as UseCasesResponse).usecases.reduce((acc: Record<string, string>, useCase: UseCase) => {
acc[useCase.id] = useCase.name;
return acc;
}, {} as Record<string, string>);
}, [useCasesData]);

// Helper function to get use case name with better fallback
const getUseCaseName = (id: string): string => {
if (isError) {
return id || 'N/A';
}

if (isLoading) {
return id || 'Loading...';
}

const name = useCaseMap[id];

// Log missing use cases in development
if (!name && id && typeof window !== 'undefined' && window.location.hostname === 'localhost') {
console.warn(`Missing use case mapping for: ${id}`);
}

return name || id || 'N/A';
};

// Get all use cases as array (useful for dropdowns)
const useCases = useMemo(() => {
return (useCasesData as UseCasesResponse)?.usecases || [];
}, [useCasesData]);

return {
useCaseMap,
useCases,
getUseCaseName,
isLoading,
isError,
error
};
};

// Hook to provide use case options for dropdowns and forms
export const useUseCaseOptions = () => {
const { useCases, isLoading, isError } = useUseCaseMapping();

// Transform use cases to option format used in dropdowns
const useCaseOptions = useMemo(() => {
return useCases.map((useCase: UseCase) => ({
label: useCase.name,
value: useCase.id
}));
}, [useCases]);

// Helper function to get use case type/name by id (replaces getUsecaseType)
const getUseCaseType = (id: string): string => {
const useCase = useCases.find((uc: UseCase) => uc.id === id);
return useCase?.name || id || 'N/A';
};

return {
useCaseOptions,
getUseCaseType,
isLoading,
isError
};
};

15 changes: 12 additions & 3 deletions app/client/src/components/Datasets/Datasets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Link } from "react-router-dom";
import { HuggingFaceIconUrl, Pages } from "../../types";
import { blue } from '@ant-design/colors';
import DateTime from "../DateTime/DateTime";
import { TRANSLATIONS } from "../../constants";
import { useUseCaseMapping } from "../../api/hooks";
import DeleteConfirmWarningModal from './DeleteConfirmModal';
import DatasetExportModal, { ExportResult } from '../Export/ExportModal';

Expand All @@ -22,6 +22,7 @@ const { Paragraph, Text } = Typography;
export default function DatasetsComponent() {
const datasetHistoryAPI = useGetDatasetHistory();
const deleteDatasetHistoryAPI = useDeleteDataset();
const { getUseCaseName } = useUseCaseMapping();
const [toggleDatasetDetailModal, setToggleDatasetDetailModal] = React.useState(false);
const [toggleDatasetExportModal, setToggleDatasetExportModal] = React.useState(false);
const [exportResult, setExportResult] = React.useState<ExportResult>();
Expand Down Expand Up @@ -65,19 +66,27 @@ export default function DatasetsComponent() {
key: '3',
title: 'Model',
dataIndex: 'model_id',
render: (modelId) => <Tooltip title={modelId}><Paragraph style={{ width: 150, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{modelId}</Paragraph></Tooltip>
render: (modelId: string) => <Tooltip title={modelId}><Paragraph style={{ width: 150, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{modelId}</Paragraph></Tooltip>
},
{
key: '4',
title: 'Questions Per Topic',
dataIndex: 'num_questions',
width: 150
},
{
key: '4a',
title: 'Completed Rows',
dataIndex: 'completed_rows',
width: 120,
align: 'center',
render: (completed_rows: number | null) => <>{completed_rows != null ? completed_rows : 'N/A'}</>
},
{
key: '5',
title: 'Use Case',
dataIndex: 'use_case',
render: (useCase) => <Paragraph style={{ width: 200, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{TRANSLATIONS[useCase]}</Paragraph>
render: (useCase: string) => <Paragraph style={{ width: 200, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{getUseCaseName(useCase)}</Paragraph>
},
{
key: '6',
Expand Down
5 changes: 3 additions & 2 deletions app/client/src/components/Evaluations/Evaluations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
import { DownOutlined, FolderViewOutlined, ThunderboltOutlined } from '@ant-design/icons';

import { blue } from '@ant-design/colors';
import { TRANSLATIONS } from "../../constants";
import { useUseCaseMapping } from "../../api/hooks";
import DateTime from "../DateTime/DateTime";
import styled from "styled-components";
import { Pages } from "../../types";
Expand All @@ -23,6 +23,7 @@ const ModalButtonGroup = styled(Flex)`
export default function Evaluations() {
const evaluationsHistoryAPI = useGetEvaluationsHistory();
const deleteEvaluationHistoryAPI = useDeleteEvaluation();
const { getUseCaseName } = useUseCaseMapping();
const [toggleEvaluationDetailModal, setToggleEvaluationDetailModal] = React.useState(false);
const [evaluationDetail, setEvaluationDetail] = React.useState<EvaluationResponse>({} as EvaluationResponse);

Expand All @@ -46,7 +47,7 @@ export default function Evaluations() {
key: '4',
title: 'Use Case',
dataIndex: 'use_case',
render: (useCase) => <Paragraph style={{ width: 200, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{TRANSLATIONS[useCase]}</Paragraph>
render: (useCase: string) => <Paragraph style={{ width: 200, marginBottom: 0 }} ellipsis={{ rows: 1 }}>{getUseCaseName(useCase)}</Paragraph>
},
{
key: '5',
Expand Down
15 changes: 12 additions & 3 deletions app/client/src/pages/DataGenerator/Configure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import isFunction from 'lodash/isFunction';
import { useEffect, useState } from 'react';
import { Flex, Form, Input, Select, Typography } from 'antd';
import styled from 'styled-components';
import { useLocation } from 'react-router-dom';
import { File, WorkflowType } from './types';
import { useFetchModels } from '../../api/api';
import { MODEL_PROVIDER_LABELS } from './constants';
Expand Down Expand Up @@ -52,6 +53,7 @@ const Configure = () => {
const formData = Form.useWatch((values) => values, form);
const { setIsStepValid } = useWizardCtx();
const { data } = useFetchModels();
const location = useLocation();
const [selectedFiles, setSelectedFiles] = useState(
!isEmpty(form.getFieldValue('doc_paths')) ? form.getFieldValue('doc_paths') : []);

Expand All @@ -73,12 +75,19 @@ const Configure = () => {
validateForm()
}, [form, formData])

// keivan
// Only set default inference_type for completely new datasets
useEffect(() => {
if (formData && formData?.inference_type === undefined) {
const isRegenerating = location.state?.data || location.state?.internalRedirect;
const existingInferenceType = form.getFieldValue('inference_type');

// Only set default if:
// 1. NOT regenerating an existing dataset
// 2. No existing inference_type value in form
// 3. formData watch shows undefined (initial state)
if (!isRegenerating && !existingInferenceType && formData && formData?.inference_type === undefined) {
form.setFieldValue('inference_type', ModelProviders.CAII);
}
}, [formData]);
}, [formData, location.state, form]);

const labelCol = {
span: 8
Expand Down
Loading
Loading