chore: removed create recipe from session modal and rest api (#9916)
This commit is contained in:
@@ -459,7 +459,6 @@ derive_utoipa!(IconTheme as IconThemeSchema);
|
||||
super::routes::schedule::kill_running_job,
|
||||
super::routes::schedule::inspect_running_job,
|
||||
super::routes::schedule::sessions_handler,
|
||||
super::routes::recipe::create_recipe,
|
||||
super::routes::recipe::encode_recipe,
|
||||
super::routes::recipe::decode_recipe,
|
||||
super::routes::recipe::scan_recipe,
|
||||
@@ -597,9 +596,6 @@ derive_utoipa!(IconTheme as IconThemeSchema);
|
||||
super::routes::schedule::ListSchedulesResponse,
|
||||
super::routes::schedule::SessionsQuery,
|
||||
super::routes::schedule::SessionDisplayInfo,
|
||||
super::routes::recipe::CreateRecipeRequest,
|
||||
super::routes::recipe::AuthorRequest,
|
||||
super::routes::recipe::CreateRecipeResponse,
|
||||
super::routes::recipe::EncodeRecipeRequest,
|
||||
super::routes::recipe::EncodeRecipeResponse,
|
||||
super::routes::recipe::DecodeRecipeRequest,
|
||||
|
||||
@@ -43,27 +43,6 @@ use crate::routes::recipe_utils::{
|
||||
};
|
||||
use crate::state::AppState;
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateRecipeRequest {
|
||||
session_id: String,
|
||||
#[serde(default)]
|
||||
author: Option<AuthorRequest>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct AuthorRequest {
|
||||
#[serde(default)]
|
||||
contact: Option<String>,
|
||||
#[serde(default)]
|
||||
metadata: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
pub struct CreateRecipeResponse {
|
||||
recipe: Option<Recipe>,
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct EncodeRecipeRequest {
|
||||
recipe: Recipe,
|
||||
@@ -148,82 +127,6 @@ pub struct RecipeToYamlResponse {
|
||||
yaml: String,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/recipes/create",
|
||||
request_body = CreateRecipeRequest,
|
||||
responses(
|
||||
(status = 200, description = "Recipe created successfully", body = CreateRecipeResponse),
|
||||
(status = 400, description = "Bad request"),
|
||||
(status = 412, description = "Precondition failed - Agent not available"),
|
||||
(status = 500, description = "Internal server error")
|
||||
),
|
||||
tag = "Recipe Management"
|
||||
)]
|
||||
async fn create_recipe(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(request): Json<CreateRecipeRequest>,
|
||||
) -> Result<Json<CreateRecipeResponse>, StatusCode> {
|
||||
tracing::info!(
|
||||
"Recipe creation request received for session_id: {}",
|
||||
request.session_id
|
||||
);
|
||||
|
||||
let session = match state
|
||||
.session_manager()
|
||||
.get_session(&request.session_id, true)
|
||||
.await
|
||||
{
|
||||
Ok(session) => session,
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to get session: {}", e);
|
||||
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
let conversation = match session.conversation.clone() {
|
||||
Some(conversation) => conversation,
|
||||
None => {
|
||||
let error_message = "Session has no conversation".to_string();
|
||||
let error_response = CreateRecipeResponse {
|
||||
recipe: None,
|
||||
error: Some(error_message),
|
||||
};
|
||||
return Ok(Json(error_response));
|
||||
}
|
||||
};
|
||||
|
||||
let agent = state.get_agent_for_route(request.session_id).await?;
|
||||
|
||||
let recipe_result = agent.create_recipe(&session.id, conversation).await;
|
||||
|
||||
match recipe_result {
|
||||
Ok(mut recipe) => {
|
||||
if let Some(author_req) = request.author {
|
||||
recipe.author = Some(goose::recipe::Author {
|
||||
contact: author_req.contact,
|
||||
metadata: author_req.metadata,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Json(CreateRecipeResponse {
|
||||
recipe: Some(recipe),
|
||||
error: None,
|
||||
}))
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error details: {:?}", e);
|
||||
#[cfg(feature = "telemetry")]
|
||||
goose::posthog::emit_error("recipe_create_failed", &e.to_string());
|
||||
let error_response = CreateRecipeResponse {
|
||||
recipe: None,
|
||||
error: Some(format!("Failed to create recipe: {}", e)),
|
||||
};
|
||||
Ok(Json(error_response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/recipes/encode",
|
||||
@@ -571,7 +474,6 @@ async fn recipe_to_yaml(
|
||||
|
||||
pub fn routes(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route("/recipes/create", post(create_recipe))
|
||||
.route("/recipes/encode", post(encode_recipe))
|
||||
.route("/recipes/decode", post(decode_recipe))
|
||||
.route("/recipes/scan", post(scan_recipe))
|
||||
|
||||
@@ -2418,45 +2418,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/recipes/create": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Recipe Management"
|
||||
],
|
||||
"operationId": "create_recipe",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateRecipeRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Recipe created successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateRecipeResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request"
|
||||
},
|
||||
"412": {
|
||||
"description": "Precondition failed - Agent not available"
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/recipes/decode": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -3984,19 +3945,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"AuthorRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"contact": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"metadata": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"CallToolRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -4482,42 +4430,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateRecipeRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"session_id"
|
||||
],
|
||||
"properties": {
|
||||
"author": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AuthorRequest"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateRecipeResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"recipe": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Recipe"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateScheduleRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -42,11 +42,6 @@ export type Author = {
|
||||
metadata?: string | null;
|
||||
};
|
||||
|
||||
export type AuthorRequest = {
|
||||
contact?: string | null;
|
||||
metadata?: string | null;
|
||||
};
|
||||
|
||||
export type CallToolRequest = {
|
||||
arguments: unknown;
|
||||
name: string;
|
||||
@@ -178,16 +173,6 @@ export type CreateCustomProviderResponse = {
|
||||
provider_name: string;
|
||||
};
|
||||
|
||||
export type CreateRecipeRequest = {
|
||||
author?: AuthorRequest | null;
|
||||
session_id: string;
|
||||
};
|
||||
|
||||
export type CreateRecipeResponse = {
|
||||
error?: string | null;
|
||||
recipe?: Recipe | null;
|
||||
};
|
||||
|
||||
export type CreateScheduleRequest = {
|
||||
cron: string;
|
||||
id: string;
|
||||
@@ -3645,37 +3630,6 @@ export type McpUiProxyResponses = {
|
||||
200: unknown;
|
||||
};
|
||||
|
||||
export type CreateRecipeData = {
|
||||
body: CreateRecipeRequest;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/recipes/create';
|
||||
};
|
||||
|
||||
export type CreateRecipeErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: unknown;
|
||||
/**
|
||||
* Precondition failed - Agent not available
|
||||
*/
|
||||
412: unknown;
|
||||
/**
|
||||
* Internal server error
|
||||
*/
|
||||
500: unknown;
|
||||
};
|
||||
|
||||
export type CreateRecipeResponses = {
|
||||
/**
|
||||
* Recipe created successfully
|
||||
*/
|
||||
200: CreateRecipeResponse;
|
||||
};
|
||||
|
||||
export type CreateRecipeResponse2 = CreateRecipeResponses[keyof CreateRecipeResponses];
|
||||
|
||||
export type DecodeRecipeData = {
|
||||
body: DecodeRecipeRequest;
|
||||
path?: never;
|
||||
|
||||
@@ -29,9 +29,6 @@ import { useToolCount } from './alerts/useToolCount';
|
||||
import { getThinkingMessage, getTextAndImageContent } from '../types/message';
|
||||
import ParameterInputModal from './ParameterInputModal';
|
||||
import { substituteParameters } from '../utils/parameterSubstitution';
|
||||
import CreateRecipeFromSessionModal from './recipes/CreateRecipeFromSessionModal';
|
||||
import { toastSuccess } from '../toasts';
|
||||
import { Recipe } from '../recipe';
|
||||
import { useAutoSubmit } from '../hooks/useAutoSubmit';
|
||||
import { Goose } from './icons';
|
||||
import EnvironmentBadge from './GooseSidebar/EnvironmentBadge';
|
||||
@@ -46,18 +43,6 @@ const i18n = defineMessages({
|
||||
id: 'baseChat.goHome',
|
||||
defaultMessage: 'Go home',
|
||||
},
|
||||
noSession: {
|
||||
id: 'baseChat.noSession',
|
||||
defaultMessage: 'No Session',
|
||||
},
|
||||
recipeCreatedTitle: {
|
||||
id: 'baseChat.recipeCreatedTitle',
|
||||
defaultMessage: 'Recipe created successfully!',
|
||||
},
|
||||
recipeCreatedMessage: {
|
||||
id: 'baseChat.recipeCreatedMessage',
|
||||
defaultMessage: '"{title}" has been saved and is ready to use.',
|
||||
},
|
||||
});
|
||||
|
||||
interface BaseChatProps {
|
||||
@@ -101,7 +86,6 @@ export default function BaseChat({
|
||||
const contentClassName = cn('pr-1 pb-10 pt-12', (isMobile || isNavCollapsed) && 'pt-16');
|
||||
const { droppedFiles, setDroppedFiles, handleDrop, handleDragOver } = useFileDrop();
|
||||
const onStreamFinish = useCallback(() => {}, []);
|
||||
const [isCreateRecipeModalOpen, setIsCreateRecipeModalOpen] = useState(false);
|
||||
|
||||
const {
|
||||
session,
|
||||
@@ -312,15 +296,6 @@ export default function BaseChat({
|
||||
return undefined;
|
||||
}, [isActiveSession, sessionId, chatState]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleMakeAgent = () => {
|
||||
setIsCreateRecipeModalOpen(true);
|
||||
};
|
||||
|
||||
window.addEventListener('make-agent-from-chat', handleMakeAgent);
|
||||
return () => window.removeEventListener('make-agent-from-chat', handleMakeAgent);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleSessionForked = (event: Event) => {
|
||||
const customEvent = event as CustomEvent<{
|
||||
@@ -352,20 +327,6 @@ export default function BaseChat({
|
||||
};
|
||||
}, [location.pathname, navigate]);
|
||||
|
||||
const handleRecipeCreated = (recipe: Recipe) => {
|
||||
toastSuccess({
|
||||
title: intl.formatMessage(i18n.recipeCreatedTitle),
|
||||
msg: intl.formatMessage(i18n.recipeCreatedMessage, { title: recipe.title }),
|
||||
});
|
||||
};
|
||||
|
||||
const chat: ChatType = {
|
||||
messages,
|
||||
recipe,
|
||||
sessionId,
|
||||
name: session?.name || intl.formatMessage(i18n.noSession),
|
||||
};
|
||||
|
||||
const lastSetNameRef = useRef<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
@@ -597,13 +558,6 @@ export default function BaseChat({
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CreateRecipeFromSessionModal
|
||||
isOpen={isCreateRecipeModalOpen}
|
||||
onClose={() => setIsCreateRecipeModalOpen(false)}
|
||||
sessionId={chat.sessionId}
|
||||
onRecipeCreated={handleRecipeCreated}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -162,10 +162,6 @@ const i18n = defineMessages({
|
||||
id: 'chatInput.viewEditRecipe',
|
||||
defaultMessage: 'View/Edit Recipe',
|
||||
},
|
||||
createRecipeFromSession: {
|
||||
id: 'chatInput.createRecipeFromSession',
|
||||
defaultMessage: 'Create Recipe from Session',
|
||||
},
|
||||
});
|
||||
|
||||
interface ChatInputProps {
|
||||
|
||||
@@ -1,411 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useForm } from '@tanstack/react-form';
|
||||
import { Recipe } from '../../recipe';
|
||||
import { Geese } from '../icons/Geese';
|
||||
import { X, Save, Play, Loader2 } from 'lucide-react';
|
||||
import { Button } from '../ui/button';
|
||||
import { RecipeFormFields } from './shared/RecipeFormFields';
|
||||
import { RecipeFormData } from './shared/recipeFormSchema';
|
||||
import { createRecipe } from '../../api/sdk.gen';
|
||||
import { RecipeParameter } from './shared/recipeFormSchema';
|
||||
import { toastError } from '../../toasts';
|
||||
import { saveRecipe } from '../../recipe/recipe_management';
|
||||
import { errorMessage } from '../../utils/conversionUtils';
|
||||
import { defineMessages, useIntl } from '../../i18n';
|
||||
|
||||
const i18n = defineMessages({
|
||||
title: {
|
||||
id: 'createRecipeFromSession.title',
|
||||
defaultMessage: 'Create Recipe from Session',
|
||||
},
|
||||
subtitle: {
|
||||
id: 'createRecipeFromSession.subtitle',
|
||||
defaultMessage: 'Create a reusable recipe based on your current conversation.',
|
||||
},
|
||||
analyzingTitle: {
|
||||
id: 'createRecipeFromSession.analyzingTitle',
|
||||
defaultMessage: 'Analyzing your conversation',
|
||||
},
|
||||
stageReading: {
|
||||
id: 'createRecipeFromSession.stageReading',
|
||||
defaultMessage: 'Reading your conversation...',
|
||||
},
|
||||
stageIdentifying: {
|
||||
id: 'createRecipeFromSession.stageIdentifying',
|
||||
defaultMessage: 'Identifying key patterns...',
|
||||
},
|
||||
stageExtracting: {
|
||||
id: 'createRecipeFromSession.stageExtracting',
|
||||
defaultMessage: 'Extracting main topics...',
|
||||
},
|
||||
stageGenerating: {
|
||||
id: 'createRecipeFromSession.stageGenerating',
|
||||
defaultMessage: 'Generating recipe structure...',
|
||||
},
|
||||
stageFinalizing: {
|
||||
id: 'createRecipeFromSession.stageFinalizing',
|
||||
defaultMessage: 'Finalizing details...',
|
||||
},
|
||||
stageComplete: {
|
||||
id: 'createRecipeFromSession.stageComplete',
|
||||
defaultMessage: 'Complete!',
|
||||
},
|
||||
extractingInsights: {
|
||||
id: 'createRecipeFromSession.extractingInsights',
|
||||
defaultMessage: 'Extracting insights from your chat',
|
||||
},
|
||||
cancel: {
|
||||
id: 'createRecipeFromSession.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
creating: {
|
||||
id: 'createRecipeFromSession.creating',
|
||||
defaultMessage: 'Creating...',
|
||||
},
|
||||
createRecipe: {
|
||||
id: 'createRecipeFromSession.createRecipe',
|
||||
defaultMessage: 'Create Recipe',
|
||||
},
|
||||
createAndRunRecipe: {
|
||||
id: 'createRecipeFromSession.createAndRunRecipe',
|
||||
defaultMessage: 'Create & Run Recipe',
|
||||
},
|
||||
failedToCreateTitle: {
|
||||
id: 'createRecipeFromSession.failedToCreateTitle',
|
||||
defaultMessage: 'Failed to create recipe',
|
||||
},
|
||||
failedToCreateDefaultMsg: {
|
||||
id: 'createRecipeFromSession.failedToCreateDefaultMsg',
|
||||
defaultMessage: 'An unexpected error occurred while creating the recipe. Please try again.',
|
||||
},
|
||||
});
|
||||
|
||||
interface CreateRecipeFromSessionModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
sessionId: string;
|
||||
onRecipeCreated?: (recipe: Recipe) => void;
|
||||
}
|
||||
|
||||
export default function CreateRecipeFromSessionModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
sessionId,
|
||||
onRecipeCreated,
|
||||
}: CreateRecipeFromSessionModalProps) {
|
||||
const intl = useIntl();
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [isAnalyzing, setIsAnalyzing] = useState(false);
|
||||
const [analysisStage, setAnalysisStage] = useState<string>('');
|
||||
const [hasAnalyzed, setHasAnalyzed] = useState(false);
|
||||
|
||||
// Initialize form with empty values for new recipe
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
title: '',
|
||||
description: '',
|
||||
instructions: '',
|
||||
prompt: '',
|
||||
activities: [] as string[],
|
||||
parameters: [] as RecipeParameter[],
|
||||
jsonSchema: '',
|
||||
subRecipes: [],
|
||||
recipeName: '',
|
||||
global: true,
|
||||
} as RecipeFormData,
|
||||
onSubmit: async ({ value }) => {
|
||||
await handleCreateRecipe(value);
|
||||
},
|
||||
});
|
||||
|
||||
// Track form validity with state to make it reactive
|
||||
const [isFormValid, setIsFormValid] = useState(false);
|
||||
|
||||
// Analyze messages and prefill form when modal opens
|
||||
useEffect(() => {
|
||||
if (isOpen && sessionId && !hasAnalyzed) {
|
||||
setIsAnalyzing(true);
|
||||
|
||||
// Create a sequence of analysis stages for better UX
|
||||
const stages = [
|
||||
intl.formatMessage(i18n.stageReading),
|
||||
intl.formatMessage(i18n.stageIdentifying),
|
||||
intl.formatMessage(i18n.stageExtracting),
|
||||
intl.formatMessage(i18n.stageGenerating),
|
||||
intl.formatMessage(i18n.stageFinalizing),
|
||||
];
|
||||
|
||||
let currentStageIndex = 0;
|
||||
setAnalysisStage(stages[0]);
|
||||
|
||||
// Update stage every 800ms
|
||||
const stageInterval = setInterval(() => {
|
||||
currentStageIndex = (currentStageIndex + 1) % stages.length;
|
||||
setAnalysisStage(stages[currentStageIndex]);
|
||||
}, 800);
|
||||
|
||||
// Call the backend to analyze messages and create a recipe
|
||||
createRecipe({
|
||||
body: { session_id: sessionId },
|
||||
throwOnError: true,
|
||||
})
|
||||
.then((response) => {
|
||||
clearInterval(stageInterval);
|
||||
setAnalysisStage(intl.formatMessage(i18n.stageComplete));
|
||||
|
||||
if (response.data?.recipe) {
|
||||
const recipe = response.data.recipe;
|
||||
|
||||
// Prefill the form with the analyzed recipe information
|
||||
form.setFieldValue('title', recipe.title || '');
|
||||
form.setFieldValue('description', recipe.description || '');
|
||||
form.setFieldValue('instructions', recipe.instructions || '');
|
||||
form.setFieldValue('activities', recipe.activities || []);
|
||||
form.setFieldValue('parameters', recipe.parameters || []);
|
||||
|
||||
if (recipe.response?.json_schema) {
|
||||
form.setFieldValue(
|
||||
'jsonSchema',
|
||||
JSON.stringify(recipe.response.json_schema, null, 2)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error('No recipe in response:', response);
|
||||
}
|
||||
setHasAnalyzed(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to analyze messages:', error);
|
||||
setAnalysisStage('Analysis failed');
|
||||
})
|
||||
.finally(() => {
|
||||
clearInterval(stageInterval);
|
||||
setHasAnalyzed(true);
|
||||
setTimeout(() => {
|
||||
setIsAnalyzing(false);
|
||||
setAnalysisStage('');
|
||||
}, 500); // Brief delay to show completion
|
||||
});
|
||||
}
|
||||
}, [isOpen, sessionId, hasAnalyzed, form, intl]);
|
||||
|
||||
// Reset analysis state when modal closes
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setHasAnalyzed(false);
|
||||
setIsAnalyzing(false);
|
||||
setAnalysisStage('');
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// Subscribe to form changes using the form's subscribe method
|
||||
useEffect(() => {
|
||||
const unsubscribe = form.store.subscribe(() => {
|
||||
const hasTitle = form.state.values.title?.trim();
|
||||
const hasDescription = form.state.values.description?.trim();
|
||||
const hasInstructions = form.state.values.instructions?.trim();
|
||||
const valid = !!(hasTitle && hasDescription && hasInstructions);
|
||||
|
||||
setIsFormValid(valid);
|
||||
});
|
||||
|
||||
// Initial validation check
|
||||
const hasTitle = form.state.values.title?.trim();
|
||||
const hasDescription = form.state.values.description?.trim();
|
||||
const hasInstructions = form.state.values.instructions?.trim();
|
||||
const valid = !!(hasTitle && hasDescription && hasInstructions);
|
||||
setIsFormValid(valid);
|
||||
|
||||
return unsubscribe;
|
||||
}, [form]);
|
||||
|
||||
const handleCreateRecipe = async (formData: RecipeFormData, runAfterSave = false) => {
|
||||
if (!isFormValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsCreating(true);
|
||||
try {
|
||||
const formattedSubRecipes =
|
||||
formData.subRecipes.length > 0
|
||||
? formData.subRecipes.map((subRecipe) => ({
|
||||
name: subRecipe.name,
|
||||
path: subRecipe.path,
|
||||
description: subRecipe.description || undefined,
|
||||
values:
|
||||
subRecipe.values && Object.keys(subRecipe.values).length > 0
|
||||
? subRecipe.values
|
||||
: undefined,
|
||||
sequential_when_repeated: subRecipe.sequential_when_repeated,
|
||||
}))
|
||||
: undefined;
|
||||
|
||||
const recipe: Recipe = {
|
||||
title: formData.title,
|
||||
description: formData.description,
|
||||
instructions: formData.instructions,
|
||||
prompt: formData.prompt || undefined,
|
||||
activities: formData.activities.filter((activity) => activity.trim() !== ''),
|
||||
parameters: formData.parameters.map((param) => ({
|
||||
key: param.key,
|
||||
input_type: param.input_type || 'string',
|
||||
requirement: param.requirement,
|
||||
description: param.description,
|
||||
...(param.requirement === 'optional' && param.default ? { default: param.default } : {}),
|
||||
...(param.input_type === 'select' && param.options
|
||||
? {
|
||||
options: param.options.filter((opt: string) => opt.trim() !== ''),
|
||||
}
|
||||
: {}),
|
||||
})),
|
||||
response:
|
||||
formData.jsonSchema && formData.jsonSchema.trim()
|
||||
? {
|
||||
json_schema: JSON.parse(formData.jsonSchema),
|
||||
}
|
||||
: undefined,
|
||||
sub_recipes: formattedSubRecipes,
|
||||
};
|
||||
|
||||
const { id: recipeId } = await saveRecipe(recipe, null);
|
||||
|
||||
onRecipeCreated?.(recipe);
|
||||
onClose();
|
||||
|
||||
if (runAfterSave) {
|
||||
window.electron.createChatWindow({ recipeId });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create recipe:', error);
|
||||
toastError({
|
||||
title: intl.formatMessage(i18n.failedToCreateTitle),
|
||||
msg: errorMessage(
|
||||
error,
|
||||
intl.formatMessage(i18n.failedToCreateDefaultMsg)
|
||||
),
|
||||
});
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[400] flex items-center justify-center bg-black/50 p-4"
|
||||
data-testid="create-recipe-modal"
|
||||
>
|
||||
<div className="bg-background-primary border border-border-primary rounded-lg w-full max-w-4xl h-full max-h-[90vh] flex flex-col shadow-xl">
|
||||
{/* Header */}
|
||||
<div
|
||||
className="flex items-center justify-between p-6 border-b border-border-primary shrink-0"
|
||||
data-testid="modal-header"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-background-primary rounded-full flex items-center justify-center">
|
||||
<Geese className="w-6 h-6 text-iconProminent" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-medium text-text-primary">{intl.formatMessage(i18n.title)}</h1>
|
||||
<p className="text-text-secondary text-sm">
|
||||
{intl.formatMessage(i18n.subtitle)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={onClose}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="p-2 hover:bg-background-secondary rounded-lg transition-colors"
|
||||
data-testid="close-button"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto px-6 py-4 min-h-0" data-testid="modal-content">
|
||||
{isAnalyzing ? (
|
||||
<div
|
||||
className="flex flex-col items-center justify-center h-full min-h-[300px] space-y-4"
|
||||
data-testid="analyzing-state"
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
<Loader2
|
||||
className="w-6 h-6 animate-spin text-iconProminent"
|
||||
data-testid="analysis-spinner"
|
||||
/>
|
||||
<div
|
||||
className="text-lg font-medium text-text-primary"
|
||||
data-testid="analyzing-title"
|
||||
>
|
||||
{intl.formatMessage(i18n.analyzingTitle)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="text-text-secondary text-center max-w-md"
|
||||
data-testid="analysis-stage"
|
||||
>
|
||||
{analysisStage}
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 text-text-secondary">
|
||||
<Geese className="w-5 h-5 animate-pulse" />
|
||||
<span className="text-sm">{intl.formatMessage(i18n.extractingInsights)}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div data-testid="form-state">
|
||||
<RecipeFormFields form={form} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div
|
||||
className="flex items-center justify-between p-6 border-t border-border-primary shrink-0"
|
||||
data-testid="modal-footer"
|
||||
>
|
||||
<Button
|
||||
onClick={onClose}
|
||||
variant="ghost"
|
||||
className="px-4 py-2 text-text-secondary rounded-lg hover:bg-background-secondary transition-colors"
|
||||
data-testid="cancel-button"
|
||||
>
|
||||
{intl.formatMessage(i18n.cancel)}
|
||||
</Button>
|
||||
|
||||
<div className="flex gap-3">
|
||||
{!isAnalyzing && (
|
||||
<>
|
||||
<Button
|
||||
onClick={() => {
|
||||
form.handleSubmit();
|
||||
}}
|
||||
disabled={!isFormValid || isCreating}
|
||||
variant="outline"
|
||||
className="px-4 py-2 border border-border-primary rounded-lg hover:bg-background-secondary transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-testid="create-recipe-button"
|
||||
>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
{isCreating ? intl.formatMessage(i18n.creating) : intl.formatMessage(i18n.createRecipe)}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleCreateRecipe(form.state.values, true);
|
||||
}}
|
||||
disabled={!isFormValid || isCreating}
|
||||
className="px-4 py-2 text-text-inverse rounded-lg hover:bg-opacity-90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-testid="create-and-run-recipe-button"
|
||||
>
|
||||
<Play className="w-4 h-4 mr-2" />
|
||||
{isCreating ? intl.formatMessage(i18n.creating) : intl.formatMessage(i18n.createAndRunRecipe)}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, type RenderOptions, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import CreateRecipeFromSessionModal from '../CreateRecipeFromSessionModal';
|
||||
import { createRecipe } from '../../../api/sdk.gen';
|
||||
import type { CreateRecipeResponse } from '../../../api/types.gen';
|
||||
import { IntlTestWrapper } from '../../../i18n/test-utils';
|
||||
|
||||
const renderWithIntl = (ui: React.ReactElement, options?: RenderOptions) =>
|
||||
render(ui, { wrapper: IntlTestWrapper, ...options });
|
||||
|
||||
vi.mock('../../../api/sdk.gen', () => ({
|
||||
createRecipe: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../toasts', () => ({
|
||||
toastError: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../recipe/recipe_management', () => ({
|
||||
saveRecipe: vi.fn().mockResolvedValue({ id: 'mock-recipe-id', fileName: 'mock-recipe.yaml' }),
|
||||
}));
|
||||
|
||||
vi.mock('../../ConfigContext', () => ({
|
||||
useConfig: () => ({
|
||||
extensionsList: [],
|
||||
getExtensions: vi.fn().mockResolvedValue([]),
|
||||
getProviders: vi.fn().mockResolvedValue([]),
|
||||
}),
|
||||
}));
|
||||
|
||||
const mockCreateRecipe = vi.mocked(createRecipe);
|
||||
|
||||
describe('CreateRecipeFromSessionModal', () => {
|
||||
const defaultProps = {
|
||||
isOpen: true,
|
||||
onClose: vi.fn(),
|
||||
sessionId: 'test-session-id',
|
||||
onRecipeCreated: vi.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
const mockResponse: CreateRecipeResponse = {
|
||||
recipe: {
|
||||
title: 'Analyzed Recipe Title',
|
||||
description: 'Analyzed description',
|
||||
instructions: 'Analyzed instructions with {{param1}}',
|
||||
prompt: 'Analyzed prompt',
|
||||
activities: ['activity1', 'activity2'],
|
||||
parameters: [
|
||||
{
|
||||
key: 'param1',
|
||||
description: 'Auto-detected parameter',
|
||||
input_type: 'string',
|
||||
requirement: 'required',
|
||||
},
|
||||
],
|
||||
response: {
|
||||
json_schema: { type: 'object' },
|
||||
},
|
||||
},
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
mockCreateRecipe.mockResolvedValue({
|
||||
data: mockResponse,
|
||||
error: undefined,
|
||||
request: new globalThis.Request('http://localhost/test'),
|
||||
response: new globalThis.Response(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('Modal Rendering', () => {
|
||||
it('renders modal when open', () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('create-recipe-modal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render when closed', () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} isOpen={false} />);
|
||||
|
||||
expect(screen.queryByTestId('create-recipe-modal')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders modal header with close button', () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('modal-header')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('close-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onClose when close button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await user.click(screen.getByTestId('close-button'));
|
||||
expect(defaultProps.onClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analysis Workflow', () => {
|
||||
it('shows analyzing state initially', () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('analyzing-state')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('analyzing-title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays analysis progress indicator', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('analysis-stage')).toBeInTheDocument();
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
const stageElement = screen.getByTestId('analysis-stage');
|
||||
expect(stageElement).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 1000 }
|
||||
);
|
||||
});
|
||||
|
||||
it('shows loading indicator during analysis', () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('analysis-spinner')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('transitions to form state after analysis completes', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('form-state')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
|
||||
expect(screen.queryByTestId('analyzing-state')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Pre-filling', () => {
|
||||
it('pre-fills form with analyzed data', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
// Wait for analysis to complete and form to be pre-filled
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByDisplayValue('Analyzed Recipe Title')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
expect(screen.getByDisplayValue('Analyzed description')).toBeInTheDocument();
|
||||
expect(screen.getByDisplayValue('Analyzed instructions with {{param1}}')).toBeInTheDocument();
|
||||
const promptInput = screen.getByTestId('prompt-input');
|
||||
expect(promptInput).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows recipe form fields after analysis', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('recipe-form')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('title-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('description-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('instructions-input')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('prompt-input')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Interactions', () => {
|
||||
it('allows editing form fields', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('title-input')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
const titleInput = screen.getByTestId('title-input');
|
||||
await user.clear(titleInput);
|
||||
await user.type(titleInput, 'Modified Title');
|
||||
|
||||
expect(screen.getByDisplayValue('Modified Title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('validates required fields', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('create-recipe-button')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
const titleInput = screen.getByTestId('title-input');
|
||||
await user.clear(titleInput);
|
||||
|
||||
const createButton = screen.getByTestId('create-recipe-button');
|
||||
expect(createButton).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Recipe Creation', () => {
|
||||
it('enables create button when form is valid', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
const createButton = screen.getByTestId('create-recipe-button');
|
||||
expect(createButton).toBeEnabled();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
});
|
||||
|
||||
it('creates recipe and closes modal when form is submitted', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('create-recipe-button')).toBeEnabled();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
await user.click(screen.getByTestId('create-recipe-button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(defaultProps.onRecipeCreated).toHaveBeenCalled();
|
||||
expect(defaultProps.onClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Modal Footer', () => {
|
||||
it('shows cancel button in all states', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('cancel-button')).toBeInTheDocument();
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('create-recipe-button')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('cancel-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onClose when cancel button is clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await user.click(screen.getByTestId('cancel-button'));
|
||||
expect(defaultProps.onClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows different button states based on workflow stage', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('cancel-button')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('create-recipe-button')).not.toBeInTheDocument();
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('create-recipe-button')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('create-and-run-recipe-button')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
it('handles analysis errors gracefully', async () => {
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} sessionId="" />);
|
||||
|
||||
expect(screen.getByTestId('create-recipe-modal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles form validation errors', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithIntl(<CreateRecipeFromSessionModal {...defaultProps} />);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(screen.getByTestId('title-input')).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
|
||||
await user.clear(screen.getByTestId('title-input'));
|
||||
await user.clear(screen.getByTestId('description-input'));
|
||||
await user.clear(screen.getByTestId('instructions-input'));
|
||||
|
||||
const createButton = screen.getByTestId('create-recipe-button');
|
||||
expect(createButton).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "Go home"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "No Session"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\" has been saved and is ready to use."
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "Recipe created successfully!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "Extension Updated"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "Context window"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "Create Recipe from Session"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "Dictation Error"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "View/edit recipe"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "Analyzing your conversation"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "Cancel"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "Create & Run Recipe"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "Create Recipe"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "Creating..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "Extracting insights from your chat"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "An unexpected error occurred while creating the recipe. Please try again."
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "Failed to create recipe"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "Complete!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "Extracting main topics..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "Finalizing details..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "Generating recipe structure..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "Identifying key patterns..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "Reading your conversation..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "Create a reusable recipe based on your current conversation."
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "Create Recipe from Session"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "Cancel"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "Ir al inicio"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "Sin sesión"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\" se guardó y está lista para usar."
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "¡Receta creada con éxito!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "Extensión actualizada"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "Ventana de contexto"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "Crear Receta desde la sesión"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "Error de dictado"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "Ver/editar receta"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "Analizando tu conversación"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "Cancelar"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "Crear y ejecutar Receta"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "Crear Receta"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "Creando..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "Extrayendo ideas de tu chat"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "Ocurrió un error inesperado al crear la receta. Inténtalo de nuevo."
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "No se pudo crear la receta"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "¡Completado!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "Extrayendo los temas principales..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "Finalizando los detalles..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "Generando la estructura de la receta..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "Identificando patrones clave..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "Leyendo tu conversación..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "Crea una receta reutilizable a partir de tu conversación actual."
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "Crear Receta desde la sesión"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "Cancelar"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "घर जाओ"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "कोई सत्र नहीं"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\" सहेजा गया है और उपयोग के लिए तैयार है।"
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "रेसिपी सफलतापूर्वक बनाई गई!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "एक्सटेंशन अपडेट किया गया"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "प्रसंग विंडो"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "सत्र से रेसिपी बनाएं"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "श्रुतलेख त्रुटि"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "रेसिपी देखें/संपादित करें"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "आपकी बातचीत का विश्लेषण"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "रद्द करें"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "रेसिपी बनाएं और चलाएं"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "रेसिपी बनाएं"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "बनाया जा रहा है..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "आपकी चैट से अंतर्दृष्टि निकालना"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "रेसिपी बनाते समय एक अप्रत्याशित त्रुटि उत्पन्न हुई. कृपया पुन: प्रयास करें।"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "रेसिपी बनाने में विफल"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "पूरा!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "मुख्य विषय निकाले जा रहे हैं..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "विवरण को अंतिम रूप दिया जा रहा है..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "रेसिपी संरचना तैयार की जा रही है..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "प्रमुख पैटर्न की पहचान..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "आपकी बातचीत पढ़ रहा हूँ..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "अपनी मौजूदा बातचीत के आधार पर दोबारा इस्तेमाल होने वाली रेसिपी बनाएं।"
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "सत्र से रेसिपी बनाएं"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "रद्द करें"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "ホームへ"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "セッションなし"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\" を保存しました。使用できます。"
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "レシピを作成しました!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "拡張機能を更新しました"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "コンテキストウィンドウ"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "セッションからレシピを作成"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "音声入力エラー"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "レシピを表示/編集"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "会話を分析中"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "キャンセル"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "レシピを作成して実行"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "レシピを作成"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "作成中..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "チャットからインサイトを抽出中"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "レシピの作成中に予期しないエラーが発生しました。もう一度お試しください。"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "レシピの作成に失敗しました"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "完了!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "主要トピックを抽出中..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "詳細を仕上げ中..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "レシピ構造を生成中..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "主要なパターンを特定中..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "会話を読み込み中..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "現在の会話に基づいて、再利用可能なレシピを作成します。"
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "セッションからレシピを作成"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "キャンセル"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "홈으로 이동"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "세션 없음"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\"이 저장되어 사용할 수 있습니다."
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "레시피가 성공적으로 생성되었습니다!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "익스텐션이 업데이트되었습니다."
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "컨텍스트 창"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "세션에서 레시피 생성"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "받아쓰기 오류"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "레시피 보기/수정"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "대화 분석 중"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "취소"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "레시피 생성 및 실행"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "레시피 생성"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "생성 중..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "채팅에서 통찰력 추출"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "레시피를 생성하는 중에 예상치 못한 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "레시피를 생성하지 못했습니다."
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "완료!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "주요 주제 추출 중..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "세부정보를 마무리하는 중..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "레시피 구조 생성 중..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "주요 패턴 식별 중..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "대화를 읽는 중..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "현재 대화를 기반으로 재사용 가능한 레시피를 만드세요."
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "세션에서 레시피 생성"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "취소"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "На главную"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "Нет сеанса"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "«{title}» сохранено и готово к использованию."
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "Рецепт успешно создан!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "Расширение обновлено"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "Контекстное окно"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "Создать рецепт из сеанса"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "Ошибка диктовки"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "Просмотреть/изменить рецепт"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "Анализ вашего разговора"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "Отмена"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "Создать и запустить рецепт"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "Создать рецепт"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "Создание..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "Извлечение сведений из вашего чата"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "При создании рецепта произошла непредвиденная ошибка. Повторите попытку."
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "Не удалось создать рецепт"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "Готово!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "Извлечение основных тем..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "Завершение деталей..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "Создание структуры рецепта..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "Определение ключевых шаблонов..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "Чтение вашего разговора..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "Создайте повторно используемый рецепт на основе текущего разговора."
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "Создать рецепт из сеанса"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "Отмена"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "Ana sayfaya git"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "Oturum Yok"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "\"{title}\" kaydedildi ve kullanıma hazır."
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "Tarif başarıyla oluşturuldu!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "Uzantı Güncellendi"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "Bağlam penceresi"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "Oturumdan Tarif Oluştur"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "Dikte Hatası"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "Tarifi görüntüle/düzenle"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "Konuşmanızı analiz etme"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "İptal"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "Tarif Oluştur ve Çalıştır"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "Tarif Oluştur"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "Oluşturuluyor..."
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "Sohbetinizden içgörüler çıkarma"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "Tarif oluşturulurken beklenmeyen bir hata oluştu. Lütfen tekrar deneyin."
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "Tarif oluşturulamadı"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "Tamamla!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "Ana konular çıkarılıyor..."
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "Ayrıntılar tamamlanıyor..."
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "Tarif yapısı oluşturuluyor..."
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "Anahtar kalıpları belirlemek..."
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "Konuşmanızı okuyorum..."
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "Mevcut konuşmanıza göre yeniden kullanılabilir bir tarif oluşturun."
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "Oturumdan Tarif Oluştur"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "İptal"
|
||||
},
|
||||
|
||||
@@ -116,15 +116,6 @@
|
||||
"baseChat.goHome": {
|
||||
"defaultMessage": "回到首页"
|
||||
},
|
||||
"baseChat.noSession": {
|
||||
"defaultMessage": "无会话"
|
||||
},
|
||||
"baseChat.recipeCreatedMessage": {
|
||||
"defaultMessage": "“{title}”已保存,可以使用了。"
|
||||
},
|
||||
"baseChat.recipeCreatedTitle": {
|
||||
"defaultMessage": "配方创建成功!"
|
||||
},
|
||||
"bottomMenuExtensionSelection.extensionUpdated": {
|
||||
"defaultMessage": "扩展已更新"
|
||||
},
|
||||
@@ -167,9 +158,6 @@
|
||||
"chatInput.contextWindow": {
|
||||
"defaultMessage": "上下文窗口"
|
||||
},
|
||||
"chatInput.createRecipeFromSession": {
|
||||
"defaultMessage": "从会话创建配方"
|
||||
},
|
||||
"chatInput.dictationError": {
|
||||
"defaultMessage": "语音输入错误"
|
||||
},
|
||||
@@ -401,54 +389,6 @@
|
||||
"createEditRecipe.viewEditRecipeTitle": {
|
||||
"defaultMessage": "查看/编辑配方"
|
||||
},
|
||||
"createRecipeFromSession.analyzingTitle": {
|
||||
"defaultMessage": "正在分析你的对话"
|
||||
},
|
||||
"createRecipeFromSession.cancel": {
|
||||
"defaultMessage": "取消"
|
||||
},
|
||||
"createRecipeFromSession.createAndRunRecipe": {
|
||||
"defaultMessage": "创建并运行配方"
|
||||
},
|
||||
"createRecipeFromSession.createRecipe": {
|
||||
"defaultMessage": "创建配方"
|
||||
},
|
||||
"createRecipeFromSession.creating": {
|
||||
"defaultMessage": "创建中…"
|
||||
},
|
||||
"createRecipeFromSession.extractingInsights": {
|
||||
"defaultMessage": "正在从你的聊天中提取要点"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateDefaultMsg": {
|
||||
"defaultMessage": "创建配方时发生意外错误,请重试。"
|
||||
},
|
||||
"createRecipeFromSession.failedToCreateTitle": {
|
||||
"defaultMessage": "创建配方失败"
|
||||
},
|
||||
"createRecipeFromSession.stageComplete": {
|
||||
"defaultMessage": "完成!"
|
||||
},
|
||||
"createRecipeFromSession.stageExtracting": {
|
||||
"defaultMessage": "正在提取主要话题…"
|
||||
},
|
||||
"createRecipeFromSession.stageFinalizing": {
|
||||
"defaultMessage": "正在敲定细节…"
|
||||
},
|
||||
"createRecipeFromSession.stageGenerating": {
|
||||
"defaultMessage": "正在生成配方结构…"
|
||||
},
|
||||
"createRecipeFromSession.stageIdentifying": {
|
||||
"defaultMessage": "正在识别关键模式…"
|
||||
},
|
||||
"createRecipeFromSession.stageReading": {
|
||||
"defaultMessage": "正在阅读你的对话…"
|
||||
},
|
||||
"createRecipeFromSession.subtitle": {
|
||||
"defaultMessage": "基于当前对话创建一份可复用的配方。"
|
||||
},
|
||||
"createRecipeFromSession.title": {
|
||||
"defaultMessage": "从会话创建配方"
|
||||
},
|
||||
"createSubRecipeInline.cancel": {
|
||||
"defaultMessage": "取消"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user