Skip to content

Commit 4e0b913

Browse files
authored
Merge pull request #55 from GlebkaF/test-songs
Test songs
2 parents 28f2653 + e6078ed commit 4e0b913

File tree

14 files changed

+2275
-81
lines changed

14 files changed

+2275
-81
lines changed

app/admin/preset/create/[id]/page.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ export default async function PresetCreatePage({
6262
);
6363
}
6464

65+
// Сортируем артистов на сервере, чтобы избежать hydration mismatch
66+
const sortedArtists = [...artistsRaw].sort((a, b) => {
67+
// Используем простую сортировку с явной локалью для детерминированности
68+
return a.title.localeCompare(b.title, "en", { sensitivity: "base" });
69+
});
70+
6571
return (
6672
<div className="min-h-screen bg-gray-100">
6773
<header className="bg-white shadow-sm border-b">
@@ -90,7 +96,7 @@ export default async function PresetCreatePage({
9096
</header>
9197

9298
<main className="max-w-4xl mx-auto px-4 py-8">
93-
<PresetCreateForm generation={generation} artists={artistsRaw} />
99+
<PresetCreateForm generation={generation} artists={sortedArtists} />
94100
</main>
95101
</div>
96102
);

app/api/generate-chain/route.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ export function generateStaticParams() {
77

88
interface GenerateChainRequest {
99
prompt: string;
10+
songsterrData?: {
11+
url: string;
12+
artist: string;
13+
title: string;
14+
trackType: string;
15+
trackName?: string;
16+
suggestedPart: string;
17+
};
1018
}
1119

1220
interface GenerateChainResponse {
@@ -19,26 +27,48 @@ interface ErrorResponse {
1927
}
2028

2129
/**
22-
* API endpoint для генерации Chain на основе текстового описания
30+
* API endpoint для генерации Chain на основе текстового описания или промпта из Songsterr
2331
* POST /api/generate-chain
24-
* Body: { prompt: string }
32+
* Body: { prompt: string, songsterrData?: {...} }
2533
*/
2634
export async function POST(
27-
request: Request
35+
request: Request,
2836
): Promise<NextResponse<GenerateChainResponse | ErrorResponse>> {
2937
try {
30-
// Получаем prompt из тела запроса
31-
const { prompt } = (await request.json()) as GenerateChainRequest;
38+
// Получаем prompt и опциональные метаданные из тела запроса
39+
const { prompt, songsterrData } =
40+
(await request.json()) as GenerateChainRequest;
3241

3342
if (!prompt || typeof prompt !== "string") {
3443
return NextResponse.json(
3544
{ error: "Prompt is required" },
36-
{ status: 400 }
45+
{ status: 400 },
46+
);
47+
}
48+
49+
console.log(`🎸 Generating chain from prompt: "${prompt}"`);
50+
if (songsterrData) {
51+
console.log(
52+
`📊 With Songsterr metadata: ${songsterrData.artist} - ${songsterrData.title} (${songsterrData.suggestedPart})`,
3753
);
3854
}
3955

4056
const generator = await createGenerator();
41-
const generationId = await generator.generate(prompt);
57+
const generationId = await generator.generate(
58+
prompt,
59+
songsterrData?.url,
60+
songsterrData
61+
? {
62+
artist: songsterrData.artist,
63+
title: songsterrData.title,
64+
trackType: songsterrData.trackType,
65+
suggestedPart: songsterrData.suggestedPart,
66+
...(songsterrData.trackName
67+
? { trackName: songsterrData.trackName }
68+
: {}),
69+
}
70+
: undefined,
71+
);
4272

4373
// Формируем ответ
4474
const response: GenerateChainResponse = {
@@ -54,7 +84,7 @@ export async function POST(
5484
{
5585
error: error instanceof Error ? error.message : "Internal server error",
5686
},
57-
{ status: 500 }
87+
{ status: 500 },
5888
);
5989
}
6090
}

app/api/preset/create/route.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ interface CreatePresetRequest {
2020
imageUrl?: string | null;
2121
tabsUrl?: string;
2222
pickup: {
23-
type: string;
24-
tone: number;
25-
position: string;
23+
type: "humbucker" | "single";
24+
tone: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
25+
position: "neck" | "bridge" | "middle";
2626
};
2727
}
2828

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
import { NextResponse } from "next/server";
2-
import { createGenerator } from "../../../lib/ai-generator/create-generator";
32
import {
43
extractSongsterrId,
54
fetchSongsterrData,
65
buildPromptWithMetadata,
76
} from "../../../lib/utils/songsterr";
7+
import { generateFullPrompt } from "../../../lib/utils/track-name-generator";
88

99
// Исключаем этот API роут из статической генерации
1010
export function generateStaticParams() {
1111
return [{ id: "this-is-a-dummy-id-for-static-build" }];
1212
}
1313

14-
interface GenerateFromSongsterrRequest {
14+
interface SongsterrToPromptRequest {
1515
songsterrUrl: string;
1616
trackType?: string; // "Rhythm" | "Solo" | "Lead"
1717
}
1818

19-
interface GenerateFromSongsterrResponse {
20-
generationId: string;
21-
message: string;
19+
interface SongsterrToPromptResponse {
2220
prompt: string;
23-
songData: {
21+
metadata: {
22+
url: string;
2423
artist: string;
2524
title: string;
25+
trackType: string;
26+
trackName?: string;
27+
suggestedPart: string;
2628
};
2729
}
2830

@@ -31,17 +33,17 @@ interface ErrorResponse {
3133
}
3234

3335
/**
34-
* API endpoint для генерации Chain на основе ссылки Songsterr
35-
* POST /api/generate-from-songsterr
36+
* API endpoint для генерации промпта из ссылки Songsterr
37+
* POST /api/songsterr-to-prompt
3638
* Body: { songsterrUrl: string, trackType?: string }
3739
*/
3840
export async function POST(
3941
request: Request,
40-
): Promise<NextResponse<GenerateFromSongsterrResponse | ErrorResponse>> {
42+
): Promise<NextResponse<SongsterrToPromptResponse | ErrorResponse>> {
4143
try {
4244
// Получаем данные из тела запроса
4345
const { songsterrUrl, trackType } =
44-
(await request.json()) as GenerateFromSongsterrRequest;
46+
(await request.json()) as SongsterrToPromptRequest;
4547

4648
// Валидация входных данных
4749
if (!songsterrUrl || typeof songsterrUrl !== "string") {
@@ -51,7 +53,9 @@ export async function POST(
5153
);
5254
}
5355

54-
// Шаг 1: Извлекаем ID из URL
56+
console.log(`🎸 Generating prompt from Songsterr URL: ${songsterrUrl}`);
57+
58+
// Шаг 1: Извлекаем songId и trackId из URL
5559
const extracted = extractSongsterrId(songsterrUrl);
5660
if (!extracted) {
5761
return NextResponse.json(
@@ -84,36 +88,50 @@ export async function POST(
8488
);
8589
}
8690

87-
// Шаг 3: Формируем промпт с метаданными с учетом конкретного trackId из URL
91+
// Шаг 3: Получаем метаданные с учетом конкретного trackId из URL
8892
const promptResult = buildPromptWithMetadata(songData, trackType, trackId);
89-
console.log(`💡 Generated prompt: "${promptResult.prompt}"`);
9093
console.log("📊 Metadata:", promptResult.metadata);
9194

92-
// Шаг 4: Запускаем генератор с сформированным промптом
93-
const generator = await createGenerator();
94-
const generationId: string = await generator.generate(
95-
promptResult.prompt,
96-
songsterrUrl,
97-
promptResult.metadata,
98-
);
95+
// Шаг 4: Генерируем полный промпт через AI с полной свободой
96+
const trackNameData: {
97+
artist: string;
98+
title: string;
99+
trackType: string;
100+
trackName?: string;
101+
} = {
102+
artist: promptResult.metadata.artist,
103+
title: promptResult.metadata.title,
104+
trackType: promptResult.metadata.trackType,
105+
...(promptResult.metadata.trackName
106+
? { trackName: promptResult.metadata.trackName }
107+
: {}),
108+
};
109+
const finalPrompt = await generateFullPrompt(trackNameData);
110+
console.log(`💡 AI generated full prompt: "${finalPrompt}"`);
99111

100-
console.log(`✅ Generation created with ID: ${generationId}`);
112+
// Извлекаем suggestedPart из промпта (простая эвристика для обратной совместимости)
113+
const words = finalPrompt.split(" ");
114+
const suggestedPart = words.slice(-3).join(" "); // последние 3 слова
101115

102116
// Формируем ответ
103-
const response: GenerateFromSongsterrResponse = {
104-
generationId,
105-
message: "Generation created successfully from Songsterr URL",
106-
prompt: promptResult.prompt,
107-
songData: {
108-
artist: songData.artist,
109-
title: songData.title,
117+
const response: SongsterrToPromptResponse = {
118+
prompt: finalPrompt,
119+
metadata: {
120+
url: songsterrUrl,
121+
artist: promptResult.metadata.artist,
122+
title: promptResult.metadata.title,
123+
trackType: promptResult.metadata.trackType,
124+
suggestedPart,
125+
...(promptResult.metadata.trackName
126+
? { trackName: promptResult.metadata.trackName }
127+
: {}),
110128
},
111129
};
112130

113-
// Отправляем ответ
131+
console.log(`✅ Prompt generated successfully`);
114132
return NextResponse.json(response);
115133
} catch (error) {
116-
console.error("Error in generate-from-songsterr API:", error);
134+
console.error("Error generating prompt from Songsterr:", error);
117135
return NextResponse.json(
118136
{
119137
error: error instanceof Error ? error.message : "Internal server error",

components/GeneratorForm.tsx

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function GeneratorForm(): React.ReactElement {
5454
setIsLoading(false);
5555
}
5656
} else {
57-
// Генерация из Songsterr URL
57+
// Генерация из Songsterr URL (два последовательных вызова)
5858
if (!songsterrUrl.trim()) {
5959
setError("Пожалуйста, введите ссылку на Songsterr");
6060
return;
@@ -64,7 +64,9 @@ export function GeneratorForm(): React.ReactElement {
6464
setError("");
6565

6666
try {
67-
const response = await fetch("/api/generate-from-songsterr", {
67+
// Шаг 1: Генерация промпта из Songsterr URL
68+
console.log("Step 1: Generating prompt from Songsterr...");
69+
const promptResponse = await fetch("/api/songsterr-to-prompt", {
6870
method: "POST",
6971
headers: {
7072
"Content-Type": "application/json",
@@ -75,21 +77,56 @@ export function GeneratorForm(): React.ReactElement {
7577
}),
7678
});
7779

78-
if (!response.ok) {
79-
const errorData = (await response.json()) as { error: string };
80-
throw new Error(errorData.error || `Ошибка: ${response.statusText}`);
80+
if (!promptResponse.ok) {
81+
const errorData = (await promptResponse.json()) as { error: string };
82+
throw new Error(
83+
errorData.error || `Ошибка: ${promptResponse.statusText}`,
84+
);
8185
}
8286

83-
const data = (await response.json()) as {
87+
const promptData = (await promptResponse.json()) as {
88+
prompt: string;
89+
metadata: {
90+
url: string;
91+
artist: string;
92+
title: string;
93+
trackType: string;
94+
trackName?: string;
95+
suggestedPart: string;
96+
};
97+
};
98+
99+
console.log(`Step 1 complete: "${promptData.prompt}"`);
100+
101+
// Шаг 2: Генерация цепи из промпта
102+
console.log("Step 2: Generating chain...");
103+
const chainResponse = await fetch("/api/generate-chain", {
104+
method: "POST",
105+
headers: {
106+
"Content-Type": "application/json",
107+
},
108+
body: JSON.stringify({
109+
prompt: promptData.prompt,
110+
songsterrData: promptData.metadata,
111+
}),
112+
});
113+
114+
if (!chainResponse.ok) {
115+
const errorData = (await chainResponse.json()) as { error: string };
116+
throw new Error(
117+
errorData.error || `Ошибка: ${chainResponse.statusText}`,
118+
);
119+
}
120+
121+
const chainData = (await chainResponse.json()) as {
84122
generationId: string;
85123
message: string;
86-
prompt: string;
87124
};
88125

89-
console.log(`Generated prompt from Songsterr: ${data.prompt}`);
126+
console.log("Step 2 complete: Chain generated");
90127

91128
// Перенаправляем на страницу с результатом генерации
92-
router.push(`/admin/generation/${data.generationId}`);
129+
router.push(`/admin/generation/${chainData.generationId}`);
93130
} catch (err) {
94131
setError(err instanceof Error ? err.message : "Произошла ошибка");
95132
setIsLoading(false);

0 commit comments

Comments
 (0)