complate detail page
This commit is contained in:
260
src/widgets/detail/lib/formatter.ts
Normal file
260
src/widgets/detail/lib/formatter.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
// utils/transformPlagiatResponse.ts
|
||||
|
||||
interface HighlightSegment {
|
||||
text: string;
|
||||
plagiarized: boolean;
|
||||
}
|
||||
|
||||
interface SemanticMetrics {
|
||||
totalWords: number;
|
||||
uniqueWords: number;
|
||||
lexicalUniqueness: number;
|
||||
avgWordLength: number;
|
||||
geoAvgWordLength: number;
|
||||
minWordLength: number;
|
||||
maxWordLength: number;
|
||||
sentences: number;
|
||||
avgWordsPerSentence: number;
|
||||
polysyllabicWords: number;
|
||||
polysyllabicPercent: number;
|
||||
totalChars: number;
|
||||
charsNoSpaces: number;
|
||||
vowels: number;
|
||||
consonants: number;
|
||||
punctuation: number;
|
||||
uppercase: number;
|
||||
lowercase: number;
|
||||
digits: number;
|
||||
capsLockWords: number;
|
||||
stopWords: number;
|
||||
stopWordsPercent: number;
|
||||
junkWords: number;
|
||||
junkPercent: number;
|
||||
maxConsecutiveRepeats: number;
|
||||
top5Words: string;
|
||||
spamRatio: number;
|
||||
hasHtml: boolean;
|
||||
hasEmail: boolean;
|
||||
hasUrl: boolean;
|
||||
hasDate: boolean;
|
||||
hasPhone: boolean;
|
||||
startsEqualsEnd: boolean;
|
||||
isPalindrome: boolean;
|
||||
hasQuestion: boolean;
|
||||
hasExclamation: boolean;
|
||||
paragraphs: number;
|
||||
lines: number;
|
||||
latinPercent: number;
|
||||
cyrillicPercent: number;
|
||||
longWords16plus: number;
|
||||
}
|
||||
|
||||
interface Certificate {
|
||||
verificationCode: string;
|
||||
issuerName: string;
|
||||
issuedAt: string;
|
||||
expiresAt: string;
|
||||
downloadUrl: string;
|
||||
}
|
||||
|
||||
interface Source {
|
||||
url: string;
|
||||
matchPercentage: number;
|
||||
module: string;
|
||||
}
|
||||
|
||||
interface PlagiatData {
|
||||
name: string;
|
||||
initials: string;
|
||||
email: string;
|
||||
location: string;
|
||||
fileName: string;
|
||||
checkedAt: string;
|
||||
humanPercent: number;
|
||||
aiPercent: number;
|
||||
plagiarismPercent: number;
|
||||
originalityPercent: number;
|
||||
citationPercent: number;
|
||||
highlightedText: HighlightSegment[];
|
||||
sources: Source[];
|
||||
semantic: SemanticMetrics;
|
||||
certificate: Certificate | null;
|
||||
}
|
||||
|
||||
interface ApiRes {
|
||||
ai: number;
|
||||
hash: string;
|
||||
text: string;
|
||||
citation: number;
|
||||
plagiarism: number;
|
||||
originality: number;
|
||||
}
|
||||
|
||||
interface ApiAnalyzeText {
|
||||
Цифр: number;
|
||||
Гласных: number;
|
||||
'URL найден': string;
|
||||
'Стоп-слов': number;
|
||||
'ТОП-5 слов': string;
|
||||
'Email найден': string;
|
||||
Палиндром: string;
|
||||
Согласных: number;
|
||||
'Слов в CAPSLOCK': number;
|
||||
'Без пробелов': number;
|
||||
'Дата найдена': string;
|
||||
'Доля мусора (%)': number;
|
||||
'Начало = Конец': string;
|
||||
'Строчных букв': number;
|
||||
'Заглавных букв': number;
|
||||
'Символов всего': number;
|
||||
'Телефон найден': string;
|
||||
'Доля латиницы (%)': number;
|
||||
'Мин. длина слова': number;
|
||||
'Уникальных слов': number;
|
||||
'Доля стоп-слов (%)': number;
|
||||
'Наличие HTML-тегов': string;
|
||||
'Доля кириллицы (%)': number;
|
||||
'Количество строк': number;
|
||||
'Макс. длина слова': number;
|
||||
'Знаков препинания': number;
|
||||
'Мусорные слова (шт)': number;
|
||||
'Средняя длина слов': number;
|
||||
'Количество абзацев': number;
|
||||
'Вопросительный знак': string;
|
||||
'Восклицательный знак': string;
|
||||
'Заспамленность (max/total)': number;
|
||||
'Общее количество слов': number;
|
||||
'Слов длиной 16+ символов': number;
|
||||
'Количество предложений': number;
|
||||
'Полисиллабических слов': number;
|
||||
'Макс. подряд повторов слова': number;
|
||||
'Лексическая уникальность (%)': number;
|
||||
'Доля полисиллабических слов (%)': number;
|
||||
'Геометрическая средняя длина слов': number;
|
||||
'Среднее количество слов в предложении': number;
|
||||
}
|
||||
|
||||
interface ApiResultJson {
|
||||
ok: boolean;
|
||||
res: ApiRes;
|
||||
error: string;
|
||||
success: string;
|
||||
text_res: string;
|
||||
analyze_text: ApiAnalyzeText;
|
||||
}
|
||||
|
||||
interface ApiResult {
|
||||
id: number;
|
||||
document: number;
|
||||
result_json: ApiResultJson;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface ApiDocument {
|
||||
id: number;
|
||||
title: string;
|
||||
file: string;
|
||||
certificate: boolean;
|
||||
text: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
results: ApiResult[];
|
||||
}
|
||||
|
||||
// ─── Parsers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function parseHighlightedText(textRes: string): HighlightSegment[] {
|
||||
const segments: HighlightSegment[] = [];
|
||||
const parts = textRes.split(/(<sel>[\s\S]*?<\/sel>)/g);
|
||||
|
||||
for (const part of parts) {
|
||||
if (part.startsWith('<sel>')) {
|
||||
segments.push({ text: part.replace(/<\/?sel>/g, ''), plagiarized: true });
|
||||
} else if (part) {
|
||||
segments.push({ text: part, plagiarized: false });
|
||||
}
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
function parseAnalyzeText(a: ApiAnalyzeText): SemanticMetrics {
|
||||
const bool = (v: string): boolean => v === 'Да';
|
||||
|
||||
return {
|
||||
totalWords: a['Общее количество слов'],
|
||||
uniqueWords: a['Уникальных слов'],
|
||||
lexicalUniqueness: a['Лексическая уникальность (%)'],
|
||||
avgWordLength: a['Средняя длина слов'],
|
||||
geoAvgWordLength: a['Геометрическая средняя длина слов'],
|
||||
minWordLength: a['Мин. длина слова'],
|
||||
maxWordLength: a['Макс. длина слова'],
|
||||
sentences: a['Количество предложений'],
|
||||
avgWordsPerSentence: a['Среднее количество слов в предложении'],
|
||||
polysyllabicWords: a['Полисиллабических слов'],
|
||||
polysyllabicPercent: a['Доля полисиллабических слов (%)'],
|
||||
totalChars: a['Символов всего'],
|
||||
charsNoSpaces: a['Без пробелов'],
|
||||
vowels: a['Гласных'],
|
||||
consonants: a['Согласных'],
|
||||
punctuation: a['Знаков препинания'],
|
||||
uppercase: a['Заглавных букв'],
|
||||
lowercase: a['Строчных букв'],
|
||||
digits: a['Цифр'],
|
||||
capsLockWords: a['Слов в CAPSLOCK'],
|
||||
stopWords: a['Стоп-слов'],
|
||||
stopWordsPercent: a['Доля стоп-слов (%)'],
|
||||
junkWords: a['Мусорные слова (шт)'],
|
||||
junkPercent: a['Доля мусора (%)'],
|
||||
maxConsecutiveRepeats: a['Макс. подряд повторов слова'],
|
||||
top5Words: a['ТОП-5 слов'],
|
||||
spamRatio: a['Заспамленность (max/total)'],
|
||||
hasHtml: bool(a['Наличие HTML-тегов']),
|
||||
hasEmail: bool(a['Email найден']),
|
||||
hasUrl: bool(a['URL найден']),
|
||||
hasDate: bool(a['Дата найдена']),
|
||||
hasPhone: bool(a['Телефон найден']),
|
||||
startsEqualsEnd: bool(a['Начало = Конец']),
|
||||
isPalindrome: bool(a['Палиндром']),
|
||||
hasQuestion: bool(a['Вопросительный знак']),
|
||||
hasExclamation: bool(a['Восклицательный знак']),
|
||||
paragraphs: a['Количество абзацев'],
|
||||
lines: a['Количество строк'],
|
||||
latinPercent: a['Доля латиницы (%)'],
|
||||
cyrillicPercent: a['Доля кириллицы (%)'],
|
||||
longWords16plus: a['Слов длиной 16+ символов'],
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Main transformer ─────────────────────────────────────────────────────────
|
||||
|
||||
export function transformPlagiatResponse(apiDoc: ApiDocument): PlagiatData {
|
||||
const result = apiDoc.results[0];
|
||||
const res = result.result_json.res;
|
||||
const analyze = result.result_json.analyze_text;
|
||||
|
||||
const nameParts = apiDoc.text.trim().split(/\s+/);
|
||||
const initials = nameParts
|
||||
.slice(0, 2)
|
||||
.map((n) => n[0]?.toUpperCase() ?? '')
|
||||
.join('');
|
||||
|
||||
return {
|
||||
name: apiDoc.text,
|
||||
initials,
|
||||
email: '',
|
||||
location: '',
|
||||
fileName: apiDoc.file.split('/').pop() ?? apiDoc.file,
|
||||
checkedAt: apiDoc.created_at.slice(0, 10),
|
||||
humanPercent: 100 - res.ai,
|
||||
aiPercent: res.ai,
|
||||
plagiarismPercent: res.plagiarism,
|
||||
originalityPercent: res.originality,
|
||||
citationPercent: res.citation,
|
||||
highlightedText: parseHighlightedText(result.result_json.text_res),
|
||||
sources: [],
|
||||
semantic: parseAnalyzeText(analyze),
|
||||
certificate: null,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user