allow create new simulator with new prompt
This commit is contained in:
parent
12293a0bcb
commit
c7f33047ef
@ -242,6 +242,7 @@ model Model {
|
|||||||
model SimulatorRun {
|
model SimulatorRun {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
userId String
|
userId String
|
||||||
|
name String @default("Simulation Run") // 运行名称
|
||||||
promptId String
|
promptId String
|
||||||
promptVersionId String? // 可选,如果选择了特定版本
|
promptVersionId String? // 可选,如果选择了特定版本
|
||||||
modelId String
|
modelId String
|
||||||
|
@ -20,7 +20,25 @@ export async function GET(
|
|||||||
id,
|
id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
},
|
},
|
||||||
include: {
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
status: true,
|
||||||
|
userInput: true,
|
||||||
|
promptContent: true,
|
||||||
|
output: true,
|
||||||
|
error: true,
|
||||||
|
createdAt: true,
|
||||||
|
completedAt: true,
|
||||||
|
temperature: true,
|
||||||
|
maxTokens: true,
|
||||||
|
topP: true,
|
||||||
|
frequencyPenalty: true,
|
||||||
|
presencePenalty: true,
|
||||||
|
inputTokens: true,
|
||||||
|
outputTokens: true,
|
||||||
|
totalCost: true,
|
||||||
|
duration: true,
|
||||||
prompt: {
|
prompt: {
|
||||||
select: { id: true, name: true, content: true }
|
select: { id: true, name: true, content: true }
|
||||||
},
|
},
|
||||||
@ -90,7 +108,17 @@ export async function PATCH(
|
|||||||
...(duration !== undefined && { duration }),
|
...(duration !== undefined && { duration }),
|
||||||
...(status === "completed" && { completedAt: new Date() }),
|
...(status === "completed" && { completedAt: new Date() }),
|
||||||
},
|
},
|
||||||
include: {
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
status: true,
|
||||||
|
output: true,
|
||||||
|
error: true,
|
||||||
|
inputTokens: true,
|
||||||
|
outputTokens: true,
|
||||||
|
totalCost: true,
|
||||||
|
duration: true,
|
||||||
|
completedAt: true,
|
||||||
prompt: {
|
prompt: {
|
||||||
select: { id: true, name: true }
|
select: { id: true, name: true }
|
||||||
},
|
},
|
||||||
|
@ -26,7 +26,19 @@ export async function GET(request: NextRequest) {
|
|||||||
const [runs, total] = await Promise.all([
|
const [runs, total] = await Promise.all([
|
||||||
prisma.simulatorRun.findMany({
|
prisma.simulatorRun.findMany({
|
||||||
where,
|
where,
|
||||||
include: {
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
status: true,
|
||||||
|
userInput: true,
|
||||||
|
output: true,
|
||||||
|
error: true,
|
||||||
|
createdAt: true,
|
||||||
|
completedAt: true,
|
||||||
|
inputTokens: true,
|
||||||
|
outputTokens: true,
|
||||||
|
totalCost: true,
|
||||||
|
duration: true,
|
||||||
prompt: {
|
prompt: {
|
||||||
select: { id: true, name: true }
|
select: { id: true, name: true }
|
||||||
},
|
},
|
||||||
@ -70,6 +82,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const {
|
const {
|
||||||
|
name,
|
||||||
promptId,
|
promptId,
|
||||||
promptVersionId,
|
promptVersionId,
|
||||||
modelId,
|
modelId,
|
||||||
@ -80,18 +93,40 @@ export async function POST(request: NextRequest) {
|
|||||||
topP,
|
topP,
|
||||||
frequencyPenalty,
|
frequencyPenalty,
|
||||||
presencePenalty,
|
presencePenalty,
|
||||||
|
// 用于创建新prompt的字段
|
||||||
|
createNewPrompt,
|
||||||
|
newPromptName,
|
||||||
|
newPromptContent,
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
// 验证用户是否拥有该prompt
|
let finalPromptId = promptId;
|
||||||
const prompt = await prisma.prompt.findFirst({
|
|
||||||
where: {
|
|
||||||
id: promptId,
|
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!prompt) {
|
// 如果是创建新prompt模式
|
||||||
return NextResponse.json({ error: "Prompt not found" }, { status: 404 });
|
if (createNewPrompt && newPromptContent) {
|
||||||
|
// 创建新的prompt
|
||||||
|
const newPrompt = await prisma.prompt.create({
|
||||||
|
data: {
|
||||||
|
userId: user.id,
|
||||||
|
name: newPromptName || name || "New Prompt",
|
||||||
|
content: newPromptContent,
|
||||||
|
visibility: "private",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
finalPromptId = newPrompt.id;
|
||||||
|
} else if (promptId) {
|
||||||
|
// 验证用户是否拥有该prompt
|
||||||
|
const prompt = await prisma.prompt.findFirst({
|
||||||
|
where: {
|
||||||
|
id: promptId,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!prompt) {
|
||||||
|
return NextResponse.json({ error: "Prompt not found" }, { status: 404 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({ error: "Either promptId or newPromptContent is required" }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证模型是否可用
|
// 验证模型是否可用
|
||||||
@ -108,7 +143,8 @@ export async function POST(request: NextRequest) {
|
|||||||
const run = await prisma.simulatorRun.create({
|
const run = await prisma.simulatorRun.create({
|
||||||
data: {
|
data: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
promptId,
|
name: name || "Simulation Run",
|
||||||
|
promptId: finalPromptId,
|
||||||
promptVersionId,
|
promptVersionId,
|
||||||
modelId,
|
modelId,
|
||||||
userInput,
|
userInput,
|
||||||
|
@ -33,6 +33,7 @@ import { getPromptContent } from '@/lib/simulator-utils'
|
|||||||
|
|
||||||
interface SimulatorRun {
|
interface SimulatorRun {
|
||||||
id: string
|
id: string
|
||||||
|
name: string
|
||||||
status: string
|
status: string
|
||||||
userInput: string
|
userInput: string
|
||||||
promptContent?: string | null
|
promptContent?: string | null
|
||||||
@ -252,7 +253,7 @@ export default function SimulatorRunPage({ params }: { params: Promise<{ id: str
|
|||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-bold text-foreground mb-2">
|
<h1 className="text-3xl font-bold text-foreground mb-2">
|
||||||
{run.prompt.name}
|
{run.name}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="flex items-center space-x-4 text-sm text-muted-foreground">
|
<div className="flex items-center space-x-4 text-sm text-muted-foreground">
|
||||||
<Badge className={`border ${getStatusColor(run.status)}`}>
|
<Badge className={`border ${getStatusColor(run.status)}`}>
|
||||||
|
@ -65,6 +65,10 @@ export default function NewSimulatorRunPage() {
|
|||||||
const [editablePromptContent, setEditablePromptContent] = useState('')
|
const [editablePromptContent, setEditablePromptContent] = useState('')
|
||||||
const [isEditingPrompt, setIsEditingPrompt] = useState(false)
|
const [isEditingPrompt, setIsEditingPrompt] = useState(false)
|
||||||
|
|
||||||
|
// 新增状态
|
||||||
|
const [simulatorName, setSimulatorName] = useState('')
|
||||||
|
const [promptInputMode, setPromptInputMode] = useState<'select' | 'create'>('select') // 选择模式:选择现有提示词 或 创建新提示词
|
||||||
|
|
||||||
// Advanced settings
|
// Advanced settings
|
||||||
const [temperature, setTemperature] = useState('0.7')
|
const [temperature, setTemperature] = useState('0.7')
|
||||||
const [maxTokens, setMaxTokens] = useState('')
|
const [maxTokens, setMaxTokens] = useState('')
|
||||||
@ -128,6 +132,11 @@ export default function NewSimulatorRunPage() {
|
|||||||
} else if (prompt) {
|
} else if (prompt) {
|
||||||
setEditablePromptContent(prompt.content)
|
setEditablePromptContent(prompt.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动填充名称(如果当前名称为空)
|
||||||
|
if (!simulatorName && prompt) {
|
||||||
|
setSimulatorName(`${prompt.name} 模拟运行`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleVersionChange = (versionId: string) => {
|
const handleVersionChange = (versionId: string) => {
|
||||||
@ -186,29 +195,68 @@ export default function NewSimulatorRunPage() {
|
|||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (!selectedPromptId || !selectedModelId || !userInput.trim()) {
|
|
||||||
|
// 验证必填字段
|
||||||
|
if (!selectedModelId || !userInput.trim() || !simulatorName.trim()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在创建模式下,需要有提示词内容
|
||||||
|
if (promptInputMode === 'create' && !editablePromptContent.trim()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在选择模式下,需要选择提示词
|
||||||
|
if (promptInputMode === 'select' && !selectedPromptId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsCreating(true)
|
setIsCreating(true)
|
||||||
try {
|
try {
|
||||||
|
const requestBody: {
|
||||||
|
name: string;
|
||||||
|
modelId: string;
|
||||||
|
userInput: string;
|
||||||
|
temperature: number;
|
||||||
|
maxTokens?: number;
|
||||||
|
topP: number;
|
||||||
|
frequencyPenalty: number;
|
||||||
|
presencePenalty: number;
|
||||||
|
createNewPrompt?: boolean;
|
||||||
|
newPromptName?: string;
|
||||||
|
newPromptContent?: string;
|
||||||
|
promptId?: string;
|
||||||
|
promptVersionId?: string;
|
||||||
|
promptContent?: string;
|
||||||
|
} = {
|
||||||
|
name: simulatorName,
|
||||||
|
modelId: selectedModelId,
|
||||||
|
userInput,
|
||||||
|
temperature: parseFloat(temperature),
|
||||||
|
maxTokens: maxTokens ? parseInt(maxTokens) : undefined,
|
||||||
|
topP: parseFloat(topP),
|
||||||
|
frequencyPenalty: parseFloat(frequencyPenalty),
|
||||||
|
presencePenalty: parseFloat(presencePenalty),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promptInputMode === 'create') {
|
||||||
|
// 创建新提示词模式
|
||||||
|
requestBody.createNewPrompt = true
|
||||||
|
requestBody.newPromptName = simulatorName.replace(' 模拟运行', '')
|
||||||
|
requestBody.newPromptContent = editablePromptContent
|
||||||
|
} else {
|
||||||
|
// 选择现有提示词模式
|
||||||
|
requestBody.promptId = selectedPromptId
|
||||||
|
requestBody.promptVersionId = selectedVersionId || undefined
|
||||||
|
requestBody.promptContent = getCustomPromptContent()
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch('/api/simulator', {
|
const response = await fetch('/api/simulator', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(requestBody),
|
||||||
promptId: selectedPromptId,
|
|
||||||
promptVersionId: selectedVersionId || undefined,
|
|
||||||
modelId: selectedModelId,
|
|
||||||
userInput,
|
|
||||||
promptContent: getCustomPromptContent(),
|
|
||||||
temperature: parseFloat(temperature),
|
|
||||||
maxTokens: maxTokens ? parseInt(maxTokens) : undefined,
|
|
||||||
topP: parseFloat(topP),
|
|
||||||
frequencyPenalty: parseFloat(frequencyPenalty),
|
|
||||||
presencePenalty: parseFloat(presencePenalty),
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@ -267,104 +315,178 @@ export default function NewSimulatorRunPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
{/* Select Prompt */}
|
{/* Prompt Configuration */}
|
||||||
<Card className="p-6">
|
<Card className="p-6">
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold mb-2 flex items-center">
|
<h2 className="text-xl font-semibold mb-2 flex items-center">
|
||||||
<Zap className="h-5 w-5 mr-2" />
|
<Zap className="h-5 w-5 mr-2" />
|
||||||
{t('selectPrompt')}
|
提示词配置
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
Choose the prompt you want to test with the AI model
|
选择现有提示词或直接输入新的提示词内容
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
{/* 模式切换 */}
|
||||||
<div>
|
<div className="mb-6">
|
||||||
<Label htmlFor="prompt" className="text-sm font-medium">{t('prompt')}</Label>
|
<div className="flex space-x-1 p-1 bg-muted rounded-lg">
|
||||||
<select
|
<button
|
||||||
id="prompt"
|
type="button"
|
||||||
value={selectedPromptId}
|
className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||||
onChange={(e) => handlePromptChange(e.target.value)}
|
promptInputMode === 'select'
|
||||||
className="w-full mt-1 bg-background border border-input rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ring"
|
? 'bg-background text-foreground shadow-sm'
|
||||||
required
|
: 'text-muted-foreground hover:text-foreground'
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setPromptInputMode('select')
|
||||||
|
setEditablePromptContent('')
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<option value="">{t('selectPromptPlaceholder')}</option>
|
选择现有提示词
|
||||||
{prompts.map(prompt => (
|
</button>
|
||||||
<option key={prompt.id} value={prompt.id}>
|
<button
|
||||||
{prompt.name}
|
type="button"
|
||||||
</option>
|
className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||||
))}
|
promptInputMode === 'create'
|
||||||
</select>
|
? 'bg-background text-foreground shadow-sm'
|
||||||
|
: 'text-muted-foreground hover:text-foreground'
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setPromptInputMode('create')
|
||||||
|
setSelectedPromptId('')
|
||||||
|
setSelectedVersionId('')
|
||||||
|
if (!simulatorName) {
|
||||||
|
setSimulatorName('新模拟运行')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
直接输入提示词
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{selectedPrompt && selectedPrompt.versions.length > 0 && (
|
|
||||||
<div>
|
<div className="space-y-4">
|
||||||
<Label htmlFor="version" className="text-sm font-medium">{t('version')}</Label>
|
{promptInputMode === 'select' && (
|
||||||
<select
|
<>
|
||||||
id="version"
|
<div>
|
||||||
value={selectedVersionId}
|
<Label htmlFor="prompt" className="text-sm font-medium">{t('prompt')}</Label>
|
||||||
onChange={(e) => handleVersionChange(e.target.value)}
|
<select
|
||||||
className="w-full mt-1 bg-background border border-input rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ring"
|
id="prompt"
|
||||||
>
|
value={selectedPromptId}
|
||||||
<option value="">{t('useLatestVersion')}</option>
|
onChange={(e) => handlePromptChange(e.target.value)}
|
||||||
{selectedPrompt.versions
|
className="w-full mt-1 bg-background border border-input rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ring"
|
||||||
.sort((a, b) => b.version - a.version)
|
required
|
||||||
.map(version => (
|
>
|
||||||
<option key={version.id} value={version.id}>
|
<option value="">{t('selectPromptPlaceholder')}</option>
|
||||||
v{version.version}
|
{prompts.map(prompt => (
|
||||||
|
<option key={prompt.id} value={prompt.id}>
|
||||||
|
{prompt.name}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedPrompt && selectedPrompt.versions.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="version" className="text-sm font-medium">{t('version')}</Label>
|
||||||
|
<select
|
||||||
|
id="version"
|
||||||
|
value={selectedVersionId}
|
||||||
|
onChange={(e) => handleVersionChange(e.target.value)}
|
||||||
|
className="w-full mt-1 bg-background border border-input rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-ring"
|
||||||
|
>
|
||||||
|
<option value="">{t('useLatestVersion')}</option>
|
||||||
|
{selectedPrompt.versions
|
||||||
|
.sort((a, b) => b.version - a.version)
|
||||||
|
.map(version => (
|
||||||
|
<option key={version.id} value={version.id}>
|
||||||
|
v{version.version}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 名称输入框 - 在提示词选择下方 */}
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="simulatorName" className="text-sm font-medium">运行名称</Label>
|
||||||
|
<Input
|
||||||
|
id="simulatorName"
|
||||||
|
type="text"
|
||||||
|
value={simulatorName}
|
||||||
|
onChange={(e) => setSimulatorName(e.target.value)}
|
||||||
|
placeholder="输入模拟运行的名称"
|
||||||
|
className="mt-1"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
|
为此次模拟运行设置一个易于识别的名称
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{promptInputMode === 'create' && (
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground mb-2">
|
||||||
|
💡 系统将自动创建一个新的提示词并关联到此模拟运行
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{editablePromptContent && (
|
{/* 提示词内容显示/编辑 */}
|
||||||
|
{(editablePromptContent || promptInputMode === 'create') && (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Label className="text-sm font-medium">{t('promptContent')}</Label>
|
<Label className="text-sm font-medium">
|
||||||
<div className="flex items-center space-x-2">
|
{promptInputMode === 'create' ? '提示词内容' : t('promptContent')}
|
||||||
{!isEditingPrompt && (
|
</Label>
|
||||||
<Button
|
{promptInputMode === 'select' && (
|
||||||
type="button"
|
<div className="flex items-center space-x-2">
|
||||||
variant="outline"
|
{!isEditingPrompt && (
|
||||||
size="sm"
|
|
||||||
onClick={handleEditPrompt}
|
|
||||||
>
|
|
||||||
<Edit className="h-3 w-3 mr-1" />
|
|
||||||
{t('edit')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{isEditingPrompt && (
|
|
||||||
<>
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleCancelPromptEdit}
|
onClick={handleEditPrompt}
|
||||||
>
|
>
|
||||||
{t('cancel')}
|
<Edit className="h-3 w-3 mr-1" />
|
||||||
|
{t('edit')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
)}
|
||||||
type="button"
|
{isEditingPrompt && (
|
||||||
variant="default"
|
<>
|
||||||
size="sm"
|
<Button
|
||||||
onClick={handleSavePromptEdit}
|
type="button"
|
||||||
>
|
variant="outline"
|
||||||
{t('save')}
|
size="sm"
|
||||||
</Button>
|
onClick={handleCancelPromptEdit}
|
||||||
</>
|
>
|
||||||
)}
|
{t('cancel')}
|
||||||
</div>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="default"
|
||||||
|
size="sm"
|
||||||
|
onClick={handleSavePromptEdit}
|
||||||
|
>
|
||||||
|
{t('save')}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isEditingPrompt ? (
|
|
||||||
|
{(isEditingPrompt || promptInputMode === 'create') ? (
|
||||||
<Textarea
|
<Textarea
|
||||||
value={editablePromptContent}
|
value={editablePromptContent}
|
||||||
onChange={(e) => setEditablePromptContent(e.target.value)}
|
onChange={(e) => setEditablePromptContent(e.target.value)}
|
||||||
className="min-h-32 font-mono text-sm"
|
className="min-h-32 font-mono text-sm"
|
||||||
placeholder={t('promptContentPlaceholder')}
|
placeholder={promptInputMode === 'create' ? "请输入提示词内容..." : t('promptContentPlaceholder')}
|
||||||
|
required={promptInputMode === 'create'}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-1 p-4 bg-muted rounded-md border max-h-48 overflow-y-auto">
|
<div className="mt-1 p-4 bg-muted rounded-md border max-h-48 overflow-y-auto">
|
||||||
@ -573,7 +695,14 @@ export default function NewSimulatorRunPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isCreating || !selectedPromptId || !selectedModelId || !userInput.trim()}
|
disabled={
|
||||||
|
isCreating ||
|
||||||
|
!selectedModelId ||
|
||||||
|
!userInput.trim() ||
|
||||||
|
!simulatorName.trim() ||
|
||||||
|
(promptInputMode === 'select' && !selectedPromptId) ||
|
||||||
|
(promptInputMode === 'create' && !editablePromptContent.trim())
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{isCreating ? (
|
{isCreating ? (
|
||||||
<>
|
<>
|
||||||
|
@ -29,6 +29,7 @@ import { useLocale } from 'next-intl'
|
|||||||
|
|
||||||
interface SimulatorRun {
|
interface SimulatorRun {
|
||||||
id: string
|
id: string
|
||||||
|
name: string
|
||||||
status: string
|
status: string
|
||||||
userInput: string
|
userInput: string
|
||||||
output?: string
|
output?: string
|
||||||
@ -321,7 +322,7 @@ export default function SimulatorPage() {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center space-x-3 mb-3">
|
<div className="flex items-center space-x-3 mb-3">
|
||||||
<h3 className="font-semibold text-foreground">{run.prompt.name}</h3>
|
<h3 className="font-semibold text-foreground">{run.name}</h3>
|
||||||
<Badge className={`border ${getStatusColor(run.status)}`}>
|
<Badge className={`border ${getStatusColor(run.status)}`}>
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
{getStatusIcon(run.status)}
|
{getStatusIcon(run.status)}
|
||||||
|
Loading…
Reference in New Issue
Block a user