Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update prompt config page (PR 1) #286

Merged
merged 14 commits into from
Jan 11, 2024
Merged
2 changes: 1 addition & 1 deletion .github/workflows/tests-ts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ on:
- 'services/cohere-connector/**'
- 'shared/ts/**'
env:
NODE_OPTIONS: '--max_old_space_size=4096'
NODE_OPTIONS: '--no-deprecation --max_old_space_size=4096'
DEEPSOURCE_DSN: ${{secrets.DEEPSOURCE_DSN}}
jobs:
test:
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ repos:
hooks:
- id: codespell
additional_dependencies: ['tomli']
exclude: 'go.*'
13 changes: 7 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@
"@firebase/analytics": "^0.10.0",
"@firebase/app": "^0.9.25",
"@firebase/auth": "^1.5.1",
"@segment/analytics-next": "^1.62.0",
"@segment/analytics-next": "^1.63.0",
"@uidotdev/usehooks": "^2.4.1",
"dayjs": "^1.11.10",
"deepmerge-ts": "^5.1.0",
"fast-deep-equal": "^3.1.3",
"firebase": "^10.7.1",
"next": "14.0.4",
"next-intl": "^3.4.1",
"next-intl": "^3.4.2",
"persist-and-sync": "^1.2.1",
"react": "18.2.0",
"react-bootstrap-icons": "^1.10.3",
"react-dom": "18.2.0",
"react-loading-icons": "^1.1.0",
"react-string-replace": "^1.1.1",
"react-syntax-highlighter": "^15.5.0",
"react-tailwindcss-datepicker": "^1.6.6",
"sharp": "^0.33.1",
Expand All @@ -38,17 +39,17 @@
"@svgr/webpack": "^8.1.0",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@testing-library/dom": "^9.3.3",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^6.2.0",
"@testing-library/react": "^14.1.2",
"@types/react": "18.2.47",
"@types/react-dom": "18.2.18",
"@types/react-syntax-highlighter": "^15.5.11",
"@types/validator": "^13.11.7",
"@types/validator": "^13.11.8",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"daisyui": "^4.5.0",
"jsdom": "^23.1.0",
"daisyui": "^4.6.0",
"jsdom": "^23.2.0",
"mock-socket": "^9.3.1",
"postcss": "8.4.33",
"sass": "^1.69.7",
Expand Down
21 changes: 16 additions & 5 deletions frontend/public/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@
"submit": "Submit"
},
"configCodeSnippet": {
"createAPIKey": "Create API Key",
"dartInstallationText": "Add the dependency to your application's pubspec.yaml file:",
"documentation": "Documentation",
"implement": "Implement"
"implement": "Implement",
"importText": "You can now import and initialize the client in your code:",
"kotlinInstallationText": "Add the dependency to your application's build.gradle.kts file:",
"swiftInstallationText": "Add the dependency to your application's Package.swift:",
"usageRequestText": "Use the client to request a prompt using the config:",
"usageStreamText": "Or request a streaming response using the config:"
},
"createApplication": {
"applicationCreated": "Application Created",
Expand Down Expand Up @@ -103,13 +108,16 @@
"continueButtonText": "Continue",
"createConfig": "Create Configuration",
"createPromptConfigTitle": "New Model Configuration",
"credits": "Credits Left: ",
"credits": "Free Credits Left: ",
"duration": "Duration",
"durationTooltip": "Duration: Total time for complete output. Output streams automatically, with the first response occurring almost immediately.",
"errorCreatingConfig": "An error occurred creating the config",
"errorRefreshingProject": "An error occurred refreshing the project",
"finishReason": "Finish Reason",
"message": "Message",
"messageContent": "Prompt Template",
"modelResponse": "Model Response",
"modelResponse": "Model Response",
"modelType": "Model",
"modelVendor": "Provider",
"noVariablesHeadline": "The template has no variables - add as necessary or click on run test",
Expand Down Expand Up @@ -139,11 +147,11 @@
"saveButtonText": "Save",
"saveMessage": "Add Message",
"skipAndSaveButtonText": "Skip Testing and Save",
"testInputs": "Test Inputs",
"testName": "Test Name",
"testResults": "Test Results",
"totalCost": "Total Cost",
"variables": "Variables",
"variablesTooltip": "Required test inputs. Please add the values for the template variables.",
"variablesTooltip": "Required test inputs. Please add the values for the template variables. Variables are values defined inside '{'} in the template",
"wrapVariable": "use '{ '} to wrap a variable"
},
"createProject": {
Expand All @@ -154,6 +162,7 @@
"createApiKey": "Create API Key",
"createApiKeyPlaceholder": "Provide a name for your new API key",
"invalidLengthErrorMessage": "Name must be at least {numCharacters} characters long",
"invalidNameErrorMessage": "Name must be unique",
"nameInputAltLabel": "* must be unique",
"optional": "optional",
"projectInputLabel": "Project Name",
Expand Down Expand Up @@ -319,6 +328,7 @@
"promptHeader": "Prompt Testing",
"savedPromptConfig": "Saved Templates"
},

"promptConfig": {
"apiCalls": "API Calls",
"cancel": "Cancel",
Expand All @@ -344,6 +354,7 @@
"name": "Name",
"overview": "Overview",
"promptDeleted": "Model Configuration Deleted",
"promptTemplate": "Prompt Template",
"save": "Save",
"saveAsNew": "Save as New",
"settings": "Settings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ describe('PromptConfigCreateWizard Page tests', () => {
} = renderHook(useToasts);

await waitFor(() => {
expect(toasts[0].message).toBe('failed');
expect(toasts[0].message).toBe('Something went wrong');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Record } from 'react-bootstrap-icons';
import { memo, useCallback, useEffect, useState } from 'react';
import { Oval } from 'react-loading-icons';
import { shallow } from 'zustand/shallow';

import { handleCreatePromptConfig } from '@/api';
import { handleCreatePromptConfig, handleRetrieveProjects } from '@/api';
import { Navbar } from '@/components/navbar';
import { PromptConfigBaseForm } from '@/components/projects/[projectId]/applications/[applicationId]/config-create-wizard/base-form';
import { PromptConfigParametersAndPromptForm } from '@/components/projects/[projectId]/applications/[applicationId]/config-create-wizard/parameters-and-prompt-form';
Expand All @@ -20,14 +19,24 @@ import {
useApplication,
useProject,
usePromptConfigs,
useSetProjects,
} from '@/stores/api-store';
import {
PromptConfigWizardStore,
usePromptWizardStore,
WizardStage,
wizardStoreSelector,
} from '@/stores/prompt-config-wizard-store';
import { CoherePromptMessage, ModelVendor, OpenAIPromptMessage } from '@/types';
import {
CohereModelType,
CoherePromptMessage,
ModelParameters,
ModelType,
ModelVendor,
OpenAIModelType,
OpenAIPromptMessage,
ProviderMessageType,
} from '@/types';
import { setRouteParams } from '@/utils/navigation';

const stepColor = 'step-secondary';
Expand All @@ -43,8 +52,8 @@ function shouldAllowContinue(store: PromptConfigWizardStore) {
return false;
}
if (store.modelVendor === ModelVendor.Cohere) {
const [message] = store.messages as CoherePromptMessage[];
return message.message.trim().length;
const messages = store.messages as CoherePromptMessage[];
return !!messages[0]?.message.trim().length;
}
return store.messages.every(
(message) => (message as OpenAIPromptMessage).content.trim().length,
Expand All @@ -54,6 +63,79 @@ function shouldAllowContinue(store: PromptConfigWizardStore) {
return true;
}

const WizardStageComponent = memo(
<T extends ModelVendor>({
store,
validateConfigName,
setNameIsValid,
handleConfigNameChange,
handleModelTypeChange,
handleModelVendorChange,
handleParametersChange,
handleMessagesChange,
handleTemplateVariablesChange,
applicationId,
projectId,
credits,
handleError,
handleRefreshProject,
}: {
applicationId: string;
credits: string;
handleConfigNameChange: (value: string) => void;
handleError: (error: unknown) => void;
handleMessagesChange: (value: ProviderMessageType<T>[]) => void;
handleModelTypeChange: (value: ModelType<T>) => void;
handleModelVendorChange: (value: ModelVendor) => void;
handleParametersChange: (value: ModelParameters<T>) => void;
handleRefreshProject: () => Promise<void>;
handleTemplateVariablesChange: (value: Record<string, string>) => void;
projectId: string;
setNameIsValid: (value: boolean) => void;
store: PromptConfigWizardStore;
validateConfigName: (value: string) => boolean;
}) =>
store.wizardStage === WizardStage.NAME_AND_MODEL ? (
<PromptConfigBaseForm
validateConfigName={validateConfigName}
configName={store.configName}
modelType={store.modelType}
modelVendor={store.modelVendor}
setIsValid={setNameIsValid}
setConfigName={handleConfigNameChange}
setModelType={
handleModelTypeChange as (
value: OpenAIModelType | CohereModelType,
) => void
}
setVendor={handleModelVendorChange}
/>
) : store.wizardStage === WizardStage.PARAMETERS_AND_PROMPT ? (
<PromptConfigParametersAndPromptForm
modelVendor={store.modelVendor as T}
messages={store.messages as ProviderMessageType<T>[]}
setParameters={handleParametersChange}
setMessages={handleMessagesChange}
existingParameters={undefined}
modelType={store.modelType as ModelType<T>}
/>
) : (
<PromptConfigTestingForm
messages={store.messages}
templateVariables={store.templateVariables}
setTemplateVariables={handleTemplateVariablesChange}
applicationId={applicationId}
projectId={projectId}
projectCredits={credits}
modelType={store.modelType}
modelVendor={store.modelVendor}
parameters={store.parameters}
handleError={handleError}
handleRefreshProject={handleRefreshProject}
/>
),
);

export default function PromptConfigCreateWizard({
params: { applicationId, projectId },
}: {
Expand All @@ -66,6 +148,7 @@ export default function PromptConfigCreateWizard({
const project = useProject(projectId);
const promptConfigs = usePromptConfigs();
const router = useRouter();
const setProjects = useSetProjects();
const user = useAuthenticatedUser();

const { initialized, page, track } = useAnalytics();
Expand Down Expand Up @@ -109,71 +192,14 @@ export default function PromptConfigCreateWizard({
[store.setTemplateVariables],
);

const wizardStageComponentMap: Record<WizardStage, React.ReactElement> = {
[WizardStage.NAME_AND_MODEL]: useMemo(
() => (
<PromptConfigBaseForm
validateConfigName={validateConfigName}
configName={store.configName}
modelType={store.modelType}
modelVendor={store.modelVendor}
setIsValid={setNameIsValid}
setConfigName={handleConfigNameChange}
setModelType={handleModelTypeChange}
setVendor={handleModelVendorChange}
/>
),
[
store.configName,
handleConfigNameChange,
store.modelType,
store.modelVendor,
handleModelTypeChange,
handleModelVendorChange,
promptConfigs,
],
),
[WizardStage.PARAMETERS_AND_PROMPT]: useMemo(
() => (
<PromptConfigParametersAndPromptForm
modelVendor={store.modelVendor}
messages={store.messages}
setParameters={handleParametersChange}
setMessages={handleMessagesChange}
existingParameters={undefined}
modelType={store.modelType}
/>
),
[
store.modelVendor,
store.messages,
store.parameters,
handleParametersChange,
handleMessagesChange,
],
),
[WizardStage.TEST]: useMemo(
() => (
<PromptConfigTestingForm
messages={store.messages}
templateVariables={store.templateVariables}
setTemplateVariables={handleTemplateVariablesChange}
applicationId={applicationId}
projectId={projectId}
projectCredits={project?.credits}
modelType={store.modelType}
modelVendor={store.modelVendor}
parameters={store.parameters}
handleError={handleError}
/>
),
[
store.messages,
store.templateVariables,
handleTemplateVariablesChange,
],
),
};
const handleRefreshProject = useCallback(async () => {
try {
const projects = await handleRetrieveProjects();
setProjects(projects);
} catch {
handleError(t('errorRefreshingProject'));
}
}, [setProjects]);

useEffect(() => {
if (initialized) {
Expand Down Expand Up @@ -215,8 +241,8 @@ export default function PromptConfigCreateWizard({
promptConfigId,
}),
);
} catch (e) {
handleError(e);
} catch {
handleError(t('errorCreatingConfig'));
setIsLoading(false);
}
};
Expand Down Expand Up @@ -252,7 +278,26 @@ export default function PromptConfigCreateWizard({
</ul>
</div>
<div className="transform transition-transform duration-300 ease-in-out rounded-data-card shadow-xl">
{wizardStageComponentMap[store.wizardStage]}
<WizardStageComponent
applicationId={applicationId}
credits={project?.credits ?? '1'}
handleConfigNameChange={handleConfigNameChange}
handleError={handleError}
handleMessagesChange={handleMessagesChange}
handleModelTypeChange={handleModelTypeChange}
handleModelVendorChange={
handleModelVendorChange
}
handleParametersChange={handleParametersChange}
handleRefreshProject={handleRefreshProject}
handleTemplateVariablesChange={
handleTemplateVariablesChange
}
projectId={projectId}
setNameIsValid={setNameIsValid}
store={store}
validateConfigName={validateConfigName}
/>
<div className="divider divide-accent" />
<div className="items-center justify-end px-5 modal-action">
<div className="flex justify-between gap-4">
Expand Down
Loading
Loading