Files
plagiat/src/widgets/detail/lib/formatter.ts
nabijonovdavronbek619@gmail.com 238c2c1653 complate detail page
2026-04-02 19:19:06 +05:00

261 lines
8.3 KiB
TypeScript

// 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,
};
}