Add market watch and match hub workflows
这个提交包含在:
@@ -25,6 +25,7 @@ type NormalizedPlan = z.infer<typeof normalizedPlanSchema>;
|
||||
type NormalizedAdjustedPlan = z.infer<typeof normalizedAdjustedPlanSchema>;
|
||||
|
||||
const dayKeyPattern = /^day[_\s-]?(\d+)$/i;
|
||||
const EMPTY_PLAN_ERROR_MESSAGE = "训练计划结果为空,请重试或缩小训练重点后再生成。";
|
||||
|
||||
function extractTextContent(content: unknown) {
|
||||
if (typeof content === "string") {
|
||||
@@ -66,6 +67,15 @@ function toPositiveInteger(value: unknown, fallback: number) {
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
||||
}
|
||||
|
||||
function firstMeaningfulText(...values: Array<unknown>) {
|
||||
for (const value of values) {
|
||||
if (typeof value === "string" && value.trim().length > 0) {
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function inferCategory(...values: Array<unknown>) {
|
||||
const text = values
|
||||
.filter((value): value is string => typeof value === "string")
|
||||
@@ -118,6 +128,52 @@ function normalizeExercise(
|
||||
};
|
||||
}
|
||||
|
||||
function createFallbackExercise(day: number, section: Record<string, unknown>) {
|
||||
const focus = firstMeaningfulText(section.focus, section.summary, section.title, section.theme);
|
||||
if (!focus) return null;
|
||||
|
||||
return normalizeExercise(day, {
|
||||
day,
|
||||
name: focus,
|
||||
description: firstMeaningfulText(section.summary, section.description, `${focus}训练`) ?? `${focus}训练`,
|
||||
duration: section.duration ?? section.duration_minutes ?? 12,
|
||||
tips: firstMeaningfulText(section.tips, section.notes, `重点关注:${focus}`) ?? `重点关注:${focus}`,
|
||||
sets: 3,
|
||||
reps: 10,
|
||||
}, section);
|
||||
}
|
||||
|
||||
function normalizeCanonicalPlan(
|
||||
raw: Record<string, unknown>,
|
||||
fallbackTitle: string,
|
||||
): NormalizedPlan {
|
||||
const rawExercises = Array.isArray(raw.exercises)
|
||||
? raw.exercises.filter(
|
||||
(item): item is Record<string, unknown> =>
|
||||
Boolean(item) && typeof item === "object" && !Array.isArray(item),
|
||||
)
|
||||
: [];
|
||||
|
||||
const exercises = rawExercises.map((exercise, index) =>
|
||||
normalizeExercise(
|
||||
toPositiveInteger(exercise.day, index + 1),
|
||||
exercise,
|
||||
),
|
||||
);
|
||||
|
||||
if (exercises.length === 0) {
|
||||
throw new Error(EMPTY_PLAN_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
return normalizedPlanSchema.parse({
|
||||
title:
|
||||
typeof raw.title === "string" && raw.title.trim().length > 0
|
||||
? raw.title.trim()
|
||||
: fallbackTitle,
|
||||
exercises,
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeDayMapPlan(
|
||||
raw: Record<string, unknown>,
|
||||
fallbackTitle: string
|
||||
@@ -143,9 +199,21 @@ function normalizeDayMapPlan(
|
||||
)
|
||||
: [];
|
||||
|
||||
for (const exercise of sectionExercises) {
|
||||
exercises.push(normalizeExercise(day, exercise, section));
|
||||
if (sectionExercises.length > 0) {
|
||||
for (const exercise of sectionExercises) {
|
||||
exercises.push(normalizeExercise(day, exercise, section));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const fallbackExercise = createFallbackExercise(day, section);
|
||||
if (fallbackExercise) {
|
||||
exercises.push(fallbackExercise);
|
||||
}
|
||||
}
|
||||
|
||||
if (exercises.length === 0) {
|
||||
throw new Error(EMPTY_PLAN_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
return normalizedPlanSchema.parse({
|
||||
@@ -164,7 +232,7 @@ export function normalizeTrainingPlanResponse(params: {
|
||||
const raw = parseJsonContent(params.content);
|
||||
|
||||
if (Array.isArray(raw.exercises)) {
|
||||
return normalizedPlanSchema.parse(raw);
|
||||
return normalizeCanonicalPlan(raw, params.fallbackTitle);
|
||||
}
|
||||
|
||||
return normalizeDayMapPlan(raw, params.fallbackTitle);
|
||||
@@ -177,8 +245,9 @@ export function normalizeAdjustedPlanResponse(params: {
|
||||
const raw = parseJsonContent(params.content);
|
||||
|
||||
if (Array.isArray(raw.exercises)) {
|
||||
const normalized = normalizeCanonicalPlan(raw, params.fallbackTitle);
|
||||
return normalizedAdjustedPlanSchema.parse({
|
||||
...raw,
|
||||
...normalized,
|
||||
adjustmentNotes:
|
||||
typeof raw.adjustmentNotes === "string" && raw.adjustmentNotes.trim().length > 0
|
||||
? raw.adjustmentNotes.trim()
|
||||
|
||||
在新工单中引用
屏蔽一个用户