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
38 changes: 17 additions & 21 deletions app/(main)/assessment/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,11 @@ function PageContent() {
showToastError("Dataset is required");
return;
}
if (columnMapping.textColumns.length === 0) {
showToastError("Map at least one text column");
return;
}
if (!promptTemplate.trim()) {
showToastError("Prompt is required");
if (
columnMapping.textColumns.length === 0 &&
columnMapping.attachments.length === 0
) {
showToastError("Map at least one text or attachment column");
return;
}
if (!outputSchema.some((field) => field.name.trim())) {
Expand Down Expand Up @@ -271,34 +270,31 @@ function PageContent() {
};

const hasDataset = !!datasetId && columns.length > 0;
const hasMapperSelection = columnMapping.textColumns.length > 0;
const hasPromptTemplate = promptTemplate.trim().length > 0;
const hasMapperSelection =
columnMapping.textColumns.length > 0 ||
columnMapping.attachments.length > 0;
const hasConfiguredResponseFormat = outputSchema.some((field) =>
field.name.trim(),
);
const canReachReview =
hasPromptTemplate && configs.length > 0 && hasConfiguredResponseFormat;
const canReachReview = configs.length > 0 && hasConfiguredResponseFormat;
const canSubmitAssessment =
!!datasetId &&
hasMapperSelection &&
hasPromptTemplate &&
hasConfiguredResponseFormat &&
configs.length > 0 &&
experimentName.trim().length > 0 &&
!isSubmitting;
const submitBlockerMessage = !datasetId
? "Select a dataset to submit"
: !hasMapperSelection
? "Map at least one text column to submit"
: !hasPromptTemplate
? "Write a prompt to submit"
: !hasConfiguredResponseFormat
? "Set response format to submit"
: configs.length === 0
? "Select at least one configuration to submit"
: !experimentName.trim()
? "Enter an experiment name to submit"
: "";
? "Map at least one text or attachment column to submit"
: !hasConfiguredResponseFormat
? "Set response format to submit"
: configs.length === 0
? "Select at least one configuration to submit"
: !experimentName.trim()
? "Enter an experiment name to submit"
: "";
const effectiveCompletedConfigSteps = useMemo(() => {
const merged = new Set(completedConfigSteps);
if (hasMapperSelection) merged.add(1);
Expand Down
27 changes: 27 additions & 0 deletions app/api/assessment/runs/[run_id]/post-processing/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// BFF proxy — PATCH /api/v1/assessment/runs/:id/post-processing
import { NextRequest } from "next/server";
import { proxyErrorResponse, proxyJsonResponse } from "@/app/api/_routeProxy";
import type { RouteContext } from "@/app/lib/types/assessment";

export async function PATCH(
request: NextRequest,
context: RouteContext<"run_id">,
) {
try {
const { run_id } = await context.params;
const body = await request.json();
return await proxyJsonResponse(
request,
`/api/v1/assessment/runs/${run_id}/post-processing`,
{
method: "PATCH",
body: JSON.stringify(body),
},
);
} catch (error: unknown) {
return proxyErrorResponse(
"Assessment run post-processing proxy error:",
error,
);
}
}
12 changes: 7 additions & 5 deletions app/components/assessment/ColumnMapperStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ export default function ColumnMapperStep({
const mappedCount = columnConfigs.filter(
(config) => config.role !== "unmapped",
).length;
const hasText = columnConfigs.some((config) => config.role === "text");
const hasMappedColumn = columnConfigs.some(
(config) => config.role === "text" || config.role === "attachment",
);

return (
<div className="flex h-full min-h-0 w-full flex-col">
Expand Down Expand Up @@ -383,17 +385,17 @@ export default function ColumnMapperStep({
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
<span
className={`text-xs ${
hasText ? "text-text-secondary" : "text-status-warning"
hasMappedColumn ? "text-text-secondary" : "text-status-warning"
}`}
>
{hasText
{hasMappedColumn
? "Ready to continue."
: "Select at least one Text column."}
: "Map at least one Text or Attachment column."}
</span>
<Button
type="button"
onClick={handleNext}
disabled={!hasText}
disabled={!hasMappedColumn}
className="!rounded-lg"
>
Next: Eliminatory
Expand Down
14 changes: 9 additions & 5 deletions app/components/assessment/PrefilterStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ export default function PrefilterStep({
);
const [isPromptModalOpen, setIsPromptModalOpen] = useState(false);

const trHasColumns = trColumns.length > 0 || trAttachmentColumns.length > 0;

const handleNext = () => {
const config: PrefilterConfig = {};
if (trEnabled && trColumns.length > 0 && trPrompt.trim()) {
if (trEnabled && trHasColumns && trPrompt.trim()) {
config.topic_relevance = {
columns: trColumns,
prompt: trPrompt.trim(),
Expand All @@ -103,7 +105,7 @@ export default function PrefilterStep({
onNext();
};

const trValid = !trEnabled || (trColumns.length > 0 && !!trPrompt.trim());
const trValid = !trEnabled || (trHasColumns && !!trPrompt.trim());
const dupValid = !dupEnabled || dupColumns.length > 0;
const canProceed = trValid && dupValid;

Expand Down Expand Up @@ -142,16 +144,18 @@ export default function PrefilterStep({
<div>
<label className="mb-2 block text-xs font-medium text-text-secondary">
Columns to evaluate
<span className="ml-1 text-status-error-text">*</span>
{attachmentColumns.length === 0 && (
<span className="ml-1 text-status-error-text">*</span>
)}
</label>
<ColumnChips
columns={columns}
selected={trColumns}
onChange={setTrColumns}
/>
{trColumns.length === 0 && (
{trColumns.length === 0 && trAttachmentColumns.length === 0 && (
<p className="mt-1.5 text-xs text-status-warning">
Select at least one column.
Select at least one text or document column.
</p>
)}
{trColumns.length > 0 && (
Expand Down
17 changes: 9 additions & 8 deletions app/components/assessment/PromptAndConfigStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import {
type PromptAndConfigStepProps,
type VersionListState,
} from "@/app/lib/types/assessment";
import type { ConfigBlob, ConfigPublic } from "@/app/lib/types/configs";
import type {
CompletionConfig,
ConfigBlob,
ConfigPublic,
} from "@/app/lib/types/configs";
import useLatestConfigModels from "@/app/hooks/useLatestConfigModels";
import AssessmentConfiguration from "./prompt-config/AssessmentConfiguration";
import SetupProgress from "./prompt-config/SetupProgress";
Expand Down Expand Up @@ -93,13 +97,10 @@ export default function PromptAndConfigStep({
[promptTemplate, textColumns],
);
const namedSchemaFields = outputSchema.filter((field) => field.name.trim());
const hasPromptTemplate = promptTemplate.trim().length > 0;
const hasConfiguredResponseFormat = namedSchemaFields.length > 0;
const canProceed =
hasPromptTemplate && configs.length > 0 && hasConfiguredResponseFormat;
const nextBlockerMessage = !hasPromptTemplate
? "Write a prompt to continue"
: configs.length === 0
const canProceed = configs.length > 0 && hasConfiguredResponseFormat;
const nextBlockerMessage =
configs.length === 0
? "Select at least one configuration to continue"
: !hasConfiguredResponseFormat
? "Set response format to continue"
Expand Down Expand Up @@ -299,7 +300,7 @@ export default function PromptAndConfigStep({
}));
};

const handleProviderChange = (provider: "openai") => {
const handleProviderChange = (provider: CompletionConfig["provider"]) => {
const defaultModel = getDefaultModelForProvider(provider);
setDraft((prev) => ({
...prev,
Expand Down
7 changes: 5 additions & 2 deletions app/components/assessment/prompt-config/ConfigCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
ModelOption,
ValueSetter,
} from "@/app/lib/types/assessment";
import type { CompletionConfig } from "@/app/lib/types/configs";
import ConfigParamControl from "./ConfigParamControl";

export interface ConfigCreatorProps {
Expand All @@ -19,7 +20,7 @@ export interface ConfigCreatorProps {
isSaving: boolean;
setConfigName: ValueSetter<string>;
setCommitMessage: ValueSetter<string>;
onProviderChange: ValueSetter<"openai">;
onProviderChange: ValueSetter<CompletionConfig["provider"]>;
onModelChange: ValueSetter<string>;
onParamChange: (key: string, value: string | number) => void;
onSave: () => void | Promise<void>;
Expand Down Expand Up @@ -56,7 +57,9 @@ export default function ConfigCreator({
</label>
<Select
value={currentProvider}
onChange={(e) => onProviderChange(e.target.value as "openai")}
onChange={(e) =>
onProviderChange(e.target.value as CompletionConfig["provider"])
}
className={selectClass}
options={[...PROVIDER_OPTIONS]}
/>
Expand Down
3 changes: 3 additions & 0 deletions app/components/assessment/prompt-config/UserPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default function UserPrompt({
<span className="text-base font-semibold text-text-primary">
User prompt
</span>
<span className="rounded-full bg-bg-secondary px-2 py-0.5 text-[10px] font-medium text-text-secondary">
Optional
</span>
</Button>
<InfoTooltip
text={
Expand Down
18 changes: 9 additions & 9 deletions app/lib/data/assessmentModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,42 +266,42 @@ export const ASSESSMENT_MODEL_CONFIGS: AssessmentModelConfig[] = [
},
// Google (Gemini)
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-2.0-flash-lite",
config: GEMINI_TEMPERATURE_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-2.0-flash",
config: GEMINI_TEMPERATURE_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-2.5-flash-lite",
config: GEMINI_TEMPERATURE_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-2.5-flash",
config: GEMINI_TEMPERATURE_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-2.5-pro",
config: GEMINI_TEMPERATURE_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-3.1-flash-lite",
config: GEMINI_THINKING_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-3.1-pro-preview",
config: GEMINI_THINKING_NO_MINIMAL_CONFIG,
},
{
provider: "google",
provider: "google-aistudio",
model_name: "gemini-3-flash-preview",
config: GEMINI_THINKING_CONFIG,
},
Expand All @@ -319,7 +319,7 @@ export const ASSESSMENT_MODEL_CONFIGS: AssessmentModelConfig[] = [

export const PROVIDER_OPTIONS = [
{ value: "openai", label: "OpenAI" },
{ value: "google", label: "Google (Gemini)" },
{ value: "google-aistudio", label: "Google (Gemini)" },
{ value: "anthropic", label: "Anthropic (Claude)" },
] as const;

Expand Down
2 changes: 1 addition & 1 deletion app/lib/types/assessment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export interface ConfigParamDefinition {
}

export interface AssessmentModelConfig {
provider: "openai" | "google" | "anthropic";
provider: "openai" | "google" | "google-aistudio" | "anthropic";
model_name: string;
config: Record<string, ConfigParamDefinition>;
}
Expand Down
2 changes: 1 addition & 1 deletion app/lib/types/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export interface CompletionParams {
}

export interface CompletionConfig {
provider: "openai" | "google";
provider: "openai" | "google" | "google-aistudio" | "anthropic";
type?: "text" | "stt" | "tts";
params: CompletionParams;
}
Expand Down
Loading