правильный запрос и парс данных

This commit is contained in:
Nastya 2025-06-18 11:01:08 +03:00
parent 1ee85347ee
commit a1ac81e793
2 changed files with 51 additions and 244 deletions

@ -79,16 +79,28 @@ export const publicationMakeRequest = ({ url, body }: PublicationMakeRequestPara
let globalStatus: string | null = null;
let isFirstRequest = true;
export async function getData({ quizId }: { quizId: string }): Promise<{
/*
если запросить 0 вопросов - придёт items: null
если не запрашивать конфиг - поле конфига вообще не придёт
*/
interface GetDataProps {
quizId: string;
limit: number;
page: number;
needConfig: boolean;
}
export async function getData({ quizId, limit, page, needConfig }: GetDataProps): Promise<{
data: GetQuizDataResponse | null;
isRecentlyCompleted: boolean;
error?: AxiosError;
}> {
const body = {
quiz_id: quizId,
limit: 100,
page: 0,
need_config: true,
limit,
page,
need_config: needConfig,
} as any;
if (paudParam) body.auditory = Number(paudParam);
@ -111,7 +123,12 @@ export async function getData({ quizId }: { quizId: string }): Promise<{
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
//Тут ещё проверка на антифрод без парса конфига. Нам не интересно время если не нужно запрещать проходить чаще чем в сутки
if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) {
if (
needConfig &&
data?.settings !== undefined &&
typeof sessions[quizId] === "number" &&
data.settings.cfg.includes('antifraud":true')
) {
// unix время. Если меньше суток прошло - выводить ошибку, иначе пустить дальше
if (Date.now() - sessions[quizId] < 86400000) {
return { data, isRecentlyCompleted: true };
@ -128,113 +145,10 @@ export async function getData({ quizId }: { quizId: string }): Promise<{
}
}
export async function getDataSingle({ quizId, page }: { quizId: string; page?: number }): Promise<{
data: GetQuizDataResponse | null;
isRecentlyCompleted: boolean;
error?: AxiosError;
}> {
try {
// Первый запрос: 1 вопрос + конфиг
if (isFirstRequest) {
const { data, headers } = await axios<GetQuizDataResponse>(
domain + `/answer/v1.0.0/settings${window.location.search}`,
{
method: "POST",
headers: {
"X-Sessionkey": SESSIONS,
"Content-Type": "application/json",
DeviceType: DeviceType,
Device: Device,
OS: OSDevice,
Browser: userAgent,
},
data: {
quiz_id: quizId,
limit: 1,
page: 0,
need_config: true,
},
}
);
export async function getAndParceData(props: GetDataProps) {
if (!props.quizId) throw new Error("No quiz id");
globalStatus = data.settings.status;
isFirstRequest = false;
SESSIONS = headers["x-sessionkey"] || SESSIONS;
// Проверка антифрода
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
if (typeof sessions[quizId] === "number" && data.settings.cfg.includes('antifraud":true')) {
if (Date.now() - sessions[quizId] < 86400000) {
return { data, isRecentlyCompleted: true };
}
}
// Если статус не AI - сразу делаем запрос за всеми вопросами
if (globalStatus !== "ai") {
const secondResponse = await axios<GetQuizDataResponse>(
domain + `/answer/v1.0.0/settings${window.location.search}`,
{
method: "POST",
headers: {
"X-Sessionkey": SESSIONS,
"Content-Type": "application/json",
DeviceType: DeviceType,
Device: Device,
OS: OSDevice,
Browser: userAgent,
},
data: {
quiz_id: quizId,
limit: 100,
page: 0,
need_config: false,
},
}
);
return {
data: { ...data, items: secondResponse.data.items },
isRecentlyCompleted: false,
};
}
return { data, isRecentlyCompleted: false };
}
// Последующие запросы
const response = await axios<GetQuizDataResponse>(domain + `/answer/v1.0.0/settings${window.location.search}`, {
method: "POST",
headers: {
"X-Sessionkey": SESSIONS,
"Content-Type": "application/json",
DeviceType: DeviceType,
Device: Device,
OS: OSDevice,
Browser: userAgent,
},
data: {
quiz_id: quizId,
limit: 1,
page: page,
need_config: false,
},
});
return {
data: response.data,
isRecentlyCompleted: false,
};
} catch (error) {
return {
data: null,
isRecentlyCompleted: false,
error: error as AxiosError,
};
}
}
export async function getQuizData({ quizId, status = "" }: { quizId: string; status?: string }) {
if (!quizId) throw new Error("No quiz id");
const response = await getData({ quizId });
const response = await getData(props);
const quizDataResponse = response.data;
if (response.error) {
@ -252,8 +166,10 @@ export async function getQuizData({ quizId, status = "" }: { quizId: string; sta
throw new Error("Quiz not found");
}
//Парсим строки в строках
const quizSettings = replaceSpacesToEmptyLines(parseQuizData(quizDataResponse));
//Единоразово стрингифаим ВСЁ распаршенное и удаляем лишние пробелы
const res = JSON.parse(
JSON.stringify({ data: quizSettings })
.replaceAll(/\\" \\"/g, '""')
@ -263,124 +179,6 @@ export async function getQuizData({ quizId, status = "" }: { quizId: string; sta
return res;
}
let page = 1;
export async function getQuizDataAI(quizId: string) {
console.log("[getQuizDataAI] Starting with quizId:", quizId); // Добавлено
let maxRetries = 50;
if (!quizId) {
console.error("[getQuizDataAI] Error: No quiz id provided");
throw new Error("No quiz id");
}
let lastError: Error | null = null;
let responseData: any = null;
// Первый цикл - обработка result вопросов
console.log("[getQuizDataAI] Starting result retries loop"); // Добавлено
let resultRetryCount = 0;
while (resultRetryCount < maxRetries) {
try {
console.log(`[getQuizDataAI] Attempt ${resultRetryCount + 1} for result questions, page: ${page}`);
const response = await getData({ quizId });
console.log("[getQuizDataAI] Response from getData:", response);
if (response.error) {
console.error("[getQuizDataAI] Error in response:", response.error);
throw response.error;
}
if (!response.data) {
console.error("[getQuizDataAI] Error: Quiz not found");
throw new Error("Quiz not found");
}
const hasAiResult = response.data.items.some((item) => item.typ === "result");
console.log("[getQuizDataAI] Has AI result:", hasAiResult);
if (hasAiResult) {
page++;
resultRetryCount++;
console.log(`[getQuizDataAI] Found result question, incrementing page to ${page}`);
continue;
}
responseData = response;
console.log("[getQuizDataAI] Found non-result questions, breaking loop");
break;
} catch (error) {
lastError = error as Error;
resultRetryCount++;
console.error(`[getQuizDataAI] Error in attempt ${resultRetryCount}:`, error);
if (resultRetryCount >= maxRetries) {
console.error("[getQuizDataAI] Max retries reached for result questions");
break;
}
const delay = 1500 * resultRetryCount;
console.log(`[getQuizDataAI] Waiting ${delay}ms before next retry`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
if (!responseData) {
console.error("[getQuizDataAI] Failed after result retries, throwing error");
throw lastError || new Error("Failed to get quiz data after result retries");
}
// Второй цикл - обработка пустого массива
console.log("[getQuizDataAI] Starting empty items retry loop"); // Добавлено
let isEmpty = !responseData.data?.items.length;
let emptyRetryCount = 0;
while (isEmpty && emptyRetryCount < maxRetries) {
try {
console.log(`[getQuizDataAI] Empty items retry ${emptyRetryCount + 1}`);
await new Promise((resolve) => setTimeout(resolve, 1000));
const response = await getData({ quizId });
if (response.error) {
console.error("[getQuizDataAI] Error in empty items check:", response.error);
throw response.error;
}
if (!response.data) {
console.error("[getQuizDataAI] Error: Quiz not found in empty check");
throw new Error("Quiz not found");
}
isEmpty = !response.data.items.length;
console.log("[getQuizDataAI] Is items empty:", isEmpty);
if (!isEmpty) {
responseData = response;
console.log("[getQuizDataAI] Found non-empty items, updating responseData");
}
emptyRetryCount++;
} catch (error) {
lastError = error as Error;
emptyRetryCount++;
console.error(`[getQuizDataAI] Error in empty check attempt ${emptyRetryCount}:`, error);
if (emptyRetryCount >= maxRetries) {
console.error("[getQuizDataAI] Max empty retries reached");
break;
}
}
}
if (isEmpty) {
console.error("[getQuizDataAI] Items still empty after retries");
throw new Error("Items array is empty after maximum retries");
}
// Финальная обработка
console.log("[getQuizDataAI] Processing final response data");
console.log("[getQuizDataAI] Final response before return:", responseData);
return responseData.data.items;
}
type SendAnswerProps = {
questionId: string;
body: string | string[];
@ -389,8 +187,6 @@ type SendAnswerProps = {
};
export function sendAnswer({ questionId, body, qid, preview = false }: SendAnswerProps) {
console.log("qid");
console.log(qid);
if (preview) return;
const formData = new FormData();

@ -3,7 +3,7 @@ import { QuizSettings } from "@model/settingsData";
export interface GetQuizDataResponse {
cnt: number;
settings: {
settings?: {
fp: boolean;
rep: boolean;
name: string;
@ -27,6 +27,13 @@ export interface GetQuizDataResponse {
}
export function parseQuizData(quizDataResponse: GetQuizDataResponse): Omit<QuizSettings, "recentlyCompleted"> {
const readyData = {
cnt: quizDataResponse.cnt,
show_badge: quizDataResponse.show_badge,
settings: {} as QuizSettings["settings"],
questions: [] as QuizSettings["questions"],
} as QuizSettings;
const items: QuizSettings["questions"] = quizDataResponse.items.map((item) => {
const content = JSON.parse(item.c);
@ -41,17 +48,21 @@ export function parseQuizData(quizDataResponse: GetQuizDataResponse): Omit<QuizS
} as unknown as AnyTypedQuizQuestion;
});
const settings: QuizSettings["settings"] = {
fp: quizDataResponse.settings.fp,
rep: quizDataResponse.settings.rep,
name: quizDataResponse.settings.name,
cfg: JSON.parse(quizDataResponse?.settings.cfg),
lim: quizDataResponse.settings.lim,
due: quizDataResponse.settings.due,
delay: quizDataResponse.settings.delay,
pausable: quizDataResponse.settings.pausable,
status: quizDataResponse.settings.status,
};
readyData.questions = items;
return { cnt: quizDataResponse.cnt, settings, questions: items, show_badge: quizDataResponse.show_badge };
if (quizDataResponse?.settings !== undefined) {
readyData.settings = {
fp: quizDataResponse.settings.fp,
rep: quizDataResponse.settings.rep,
name: quizDataResponse.settings.name,
cfg: JSON.parse(quizDataResponse?.settings.cfg),
lim: quizDataResponse.settings.lim,
due: quizDataResponse.settings.due,
delay: quizDataResponse.settings.delay,
pausable: quizDataResponse.settings.pausable,
status: quizDataResponse.settings.status,
};
}
return readyData;
}