first-step

This commit is contained in:
init_mahdi 2025-12-03 15:22:54 +03:30
commit 9850f8598e
34 changed files with 4462 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# env
.env_back/
.env
frontEnd/node_modules/
D:\init_mahdi\project\wordbank_git\bankword\.env
# cache
__pycache__/
# big data
make_data_llm/

0
__init__.py Normal file
View File

299
base_model.py Normal file
View File

@ -0,0 +1,299 @@
from pydantic import BaseModel
from typing import List, Optional, Union
# برچسب های گرامری
word_class_dict = {
"noun": "اسم",
"proper_noun": "اسم خاص",
"plural_noun": "اسم جمع",
"verb": "فعل",
"auxiliary_verb": "فعل کمکی",
"adjective": "صفت",
"adverb": "قید",
"pronoun": "ضمیر",
"conjunction": "حرف ربط",
"particle": "حروف ربط کوچک",
"preposition": "حرف اضافه",
"interjection": "صوت/حرف ندا",
"numeral": "عدد",
"determiner": "تعیین کننده",
"classifier": "شمارنده",
"modal_verb": "فعل وجهی",
"brand": "نام تجاری",
"trademark": "علامت تجاری",
"rare": "نادر",
"nonce": "واژه ساخته شده برای یک موقعیت خاص",
"constructed": "ساخته شده توسط هوش مصنوعی",
"neologism": "واژه تازه ابداع شده",
"unknown": "ناشناخته",
"other": "غیره",
}
# برچسب های غیر گرامری کلمه
tags_dict = {
"loanword": "واژه وام گرفته شده",
"foreign": "واژه خارجی گردان شده",
"formal": "رسمی",
"informal": "غیررسمی",
"colloquial": "محاوره ای/گفتاری",
"slang": "عامیانه",
"vulgar": "رکیک",
"offensive": "توهین آمیز",
"derogatory": "تحقیرآمیز",
"euphemistic": "مؤدبانه",
"archaic": "منسوخ",
"archaism": "کلمه ای قدیمی که گاهی برای اثر هنری استفاده می شود",
"obsolete": "کاملاً منسوخ شده",
"dated": "قدیمی ولی هنوز کمی استفاده می شود",
"historical": "تاریخی",
"poetic": "کاربرد شعری",
"literary": "ادبی",
"modern": "مدرن",
"literal": "",
"figurative": "",
"idiomatic": "اصطلاحی",
"metaphorical": "اصطلاحی",
"hyperbolic": "اغراق آمیز",
"regional": "منطقه ای",
"dialect": "لهجه ای",
"united-state": "آمریکایی",
"united-kingdom": "بریتانیایی",
"per-iranian": "فارسی ایران",
"per-afghanian": "فارسی افغانستان",
"per-tajiks": "فارسی تاجیکستان",
"persian-gulf-arabic": "عربی خلیج فارس",
"egyptian-arabic": "عربی مصری",
"yemenian-arabic": "عربی یمنی",
"tehrani": "لهجه تهرانی",
"qomi": "لهجه قمی",
"colloquial-ersian": "فارسی محاوره ای",
"humorous": "طنزآمیز",
"sarcastic": "کنایه ای",
"ironic": "طعنه آمیز",
"pejorative": "تحقیرآمیز",
"affectionate": "محبت آمیز",
"neutral": "خنثی",
"elevated": "فاخر",
"polite": "مؤدبانه",
"rude": "بی ادبانه",
"gendered": "(مذکر/مونث) جنسیتی",
"inclusive": "خنثی جنسیتی",
"racist": "نژادپرستانه",
"classist": "طبقاتی",
}
# زبان کلمه
lang_dict = {
"persian": "فارسی",
"old_persian": "فارسی کهن",
"arabic": "عربی",
"english": "انگلیسی",
"turkish": "ترکی",
"kurdish": "کوردی",
"azeri": "آذری",
"etc": "سایر زبان ها",
}
# حوزه کلمه
scope_dict = {
"medical": "پزشکی",
"legal": "حقوقی",
"scientific": "علمی",
"technical": "فنی",
"religious": "مذهبی",
"mythological": "اساطیری",
"military": "نظامی",
"internet": "اینترنت",
"unknown": "ناشناخته",
"other": "سایر حوزه ها",
"public": "روزمره",
"economic ": "اقتصادی",
"financial": "مالی",
"business": "تجارت",
"tax": "مالیات",
"budget": "بودجه",
"industry": "صنعت",
"agricultural": "کشاورزی",
"transportation": "حمل و نقل",
"estate": "املاک",
"insurance": "بیمه",
"social": "اجتماعی",
"culture": "فرهنگ",
"literature": "ادبیات",
"art": "هنر",
"ُsport": "ورزش",
"family": "خانواده",
"education": "آموزش",
"media": "رسانه",
"environment": "محیط زیست",
"administrative": "اداری",
"security": "امنیت",
"police": "انتظامی",
"elections": "انتخابات",
"development": "توسعه",
"documents": "اسناد",
"civil": "مدنی",
"political": "سیاسی",
"historical": "تاریخی",
"philosophical": "فلسفی",
"technology": "فناوری",
}
# Base-Model
class WordCorrector(BaseModel):
id:str # شناسه یکتا داخل دیتابیس
word: str # کلمه
is_correct: bool = False # آیا املای کلمه درست است؟
nearest_correct_word: str # کلمه اصلاح‌شده
origin: str = "" # مصدر
stem: str = "" # ریشه
is_proper_noun: Optional[bool] = False # اگر اسم است: True = خاص، False = عام
word_class: Optional[Union[List[str], str]]
# = [
# "noun",
# "proper_noun",
# "plural_noun",
# "verb",
# "auxiliary_verb",
# "adjective",
# "adverb",
# "pronoun",
# "conjunction",
# "particle",
# "preposition",
# "interjection",
# "numeral",
# "determiner",
# "classifier",
# "modal_verb",
# "brand",
# "trademark",
# "rare",
# "nonce",
# "constructed",
# "neologism",
# "unknown",
# "other",
# ]
tags: Optional[Union[List[str], str]]
# = [
# "loanword",
# "foreign",
# "formal",
# "informal",
# "colloquial",
# "slang",
# "vulgar",
# "offensive",
# "derogatory",
# "euphemistic",
# "archaic",
# "archaism",
# "obsolete",
# "dated",
# "historical",
# "poetic",
# "literary",
# "modern",
# "literal",
# "figurative",
# "idiomatic",
# "metaphorical",
# "hyperbolic",
# "regional",
# "dialect",
# "united-state",
# "united-kingdom",
# "per-iranian",
# "per-afghanian",
# "per-tajiks",
# "persian-gulf-arabic",
# "egyptian-arabic",
# "yemenian-arabic",
# "tehrani",
# "qomi",
# "colloquial-ersian",
# "humorous",
# "sarcastic",
# "ironic",
# "pejorative",
# "affectionate",
# "neutral",
# "elevated",
# "polite",
# "rude",
# "gendered",
# "inclusive",
# "racist",
# "classist",
# ]
ner_description: Optional[str] = "" # تشریح کلمه
llm_description: Optional[str] = "" # توضیحات مدل درباره کلمه
user_description: Optional[str] = "" # توضیحات شخص درباره کلمه
admin_description: Optional[str] = "" # توضیحات متخصص درباره کلمه
confidence: Optional[float] = None # اطمینان مدل
lang: Optional[Union[List[str], str]]
# = [
# "persian",
# "old_persian",
# "arabic",
# "english",
# "turkish",
# "kurdish",
# "azeri",
# "etc",
# ]
scope: Optional[Union[List[str], str]]
# = [
# "medical",
# "legal",
# "scientific",
# "technical",
# "religious",
# "mythological",
# "military",
# "internet",
# "unknown",
# "other",
# "public",
# "economic ",
# "financial",
# "business",
# "tax",
# "budget",
# "industry",
# "agricultural",
# "transportation",
# "estate",
# "insurance",
# "social",
# "culture",
# "literature",
# "art",
# "ُsport",
# "family",
# "education",
# "media",
# "environment",
# "administrative",
# "security",
# "police",
# "elections",
# "development",
# "documents",
# "civil",
# "political",
# "historical",
# "philosophical",
# "technology",
# ]
# مدل برای POST درخواست‌ها
class IDRequest(BaseModel):
id: int = None
name: Optional[str] = None # فیلد اختیاری برای تست

13
frontEnd/index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>بانک کلمات هم آوا</title>
</head>
<body class="bg-background">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

2697
frontEnd/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
frontEnd/package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "bank-words-frontend",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview --port 5173"
},
"dependencies": {
"axios": "^1.6.7",
"vue": "^2.7.16",
"vue-router": "^3.6.5"
},
"devDependencies": {
"@vitejs/plugin-vue2": "^2.3.1",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.3",
"vite": "^5.4.0"
}
}

View File

@ -0,0 +1,7 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>بانک کلمات هم آوا</title>
</head>
<body class="bg-background">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

42
frontEnd/src/App.vue Normal file
View File

@ -0,0 +1,42 @@
<template>
<div class="min-h-screen bg-background text-gray-900 flex flex-col">
<header class="shadow bg-navbar_bg">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-between">
<div class="flex items-center space-x-4 rtl:space-x-reverse">
<div class="w-10 h-10 bg-primary rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-lg">ب</span>
</div>
<h1 class="text-xl font-semibold text-primary">بانک کلمات هم آوا</h1>
</div>
<nav class="space-x-4 rtl:space-x-reverse">
<router-link class="text-gray-700 hover:text-primary" to="/">خانه</router-link>
<router-link class="text-gray-700 hover:text-primary" to="/words">لیست کلمات</router-link>
</nav>
</div>
</header>
<main class="flex-1">
<router-view />
</main>
<footer class="bg-gray-800 text-white py-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center">
<p class="text-gray-300">© 2024 بانک کلمات هم آوا - تمامی حقوق محفوظ است</p>
<p class="text-sm text-gray-400 mt-2">نسخه تست - در حال توسعه</p>
</div>
</div>
</footer>
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
<style>
</style>

View File

@ -0,0 +1,9 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html, body, #app {
height: 100%;
}

View File

@ -0,0 +1,97 @@
<template>
<div class="fixed inset-0 flex items-center justify-center z-50">
<div class="absolute inset-0 bg-black/40"></div>
<div class="relative bg-white w-full max-w-2xl rounded-xl shadow-lg p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-800">جستجوی پیشرفته</h3>
<router-link to="/" class="text-gray-500 hover:text-gray-700"></router-link>
</div>
<form class="grid grid-cols-1 md:grid-cols-2 gap-4" @submit.prevent="onSearch">
<div class="md:col-span-2">
<label class="block text-sm text-gray-600 mb-1">کلمه</label>
<input v-model="filters.word" type="text" class="w-full border rounded px-3 py-2 focus:ring focus:border-primary" placeholder="جستجوی کلمه" />
</div>
<div class="md:col-span-2 flex items-center space-x-2 rtl:space-x-reverse">
<input id="is_correct" v-model="filters.is_correct" type="checkbox" class="h-4 w-4 text-primary" />
<label for="is_correct" class="text-sm text-gray-700">درست باشد</label>
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">برچسبها</label>
<input v-model="tagsString" type="text" placeholder="مثال: formal, literary" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">زبان</label>
<input v-model="langString" type="text" placeholder="مثال: persian" class="w-full border rounded px-3 py-2" />
</div>
<div class="md:col-span-2">
<label class="block text-sm text-gray-600 mb-1">دامنه</label>
<input v-model="scopeString" type="text" placeholder="مثال: ادبیات, آموزش" class="w-full border rounded px-3 py-2" />
</div>
<div class="md:col-span-2 flex justify-end">
<button type="submit" class="px-4 py-2 rounded bg-primary text-white hover:opacity-90">جستجو</button>
</div>
</form>
<div v-if="results.length" class="mt-6 space-y-2">
<div v-for="r in results" :key="r.id || r.word" class="flex items-center justify-between bg-gray-50 rounded p-3">
<div>
<div class="font-medium">{{ r.word }}</div>
<div class="text-xs text-gray-500">{{ (r.tags || []).join(', ') }}</div>
</div>
<router-link :to="{ name: 'word-edit', params: { id: r.id }, state: { word: r } }" class="px-3 py-1 rounded bg-accent text-white">ویرایش</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
import { searchWords } from '@/services/api';
export default {
name: 'SearchModal',
data() {
return {
filters: {
word: '',
is_correct: false,
tags: [],
lang: [],
scope: []
},
results: []
};
},
computed: {
tagsString: {
get() { return (this.filters.tags || []).join(', '); },
set(v) { this.filters.tags = this.csvToArray(v); }
},
langString: {
get() { return (this.filters.lang || []).join(', '); },
set(v) { this.filters.lang = this.csvToArray(v); }
},
scopeString: {
get() { return (this.filters.scope || []).join(', '); },
set(v) { this.filters.scope = this.csvToArray(v); }
}
},
methods: {
csvToArray(v) {
return (v || '').split(',').map(s => s.trim()).filter(Boolean);
},
async onSearch() {
try {
const { data } = await searchWords(this.filters);
this.results = Array.isArray(data) ? data : (data.items || []);
} catch (e) {
alert('خطا در جستجو');
}
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,26 @@
<template>
<div class="p-4 bg-white rounded-lg shadow hover:shadow-md transition">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold text-gray-800">{{ item.word }}</h3>
<span :class="item.is_correct ? 'text-green-600' : 'text-red-600'">{{ item.is_correct ? 'درست' : 'نادرست' }}</span>
</div>
<p class="text-gray-600 mt-2" v-if="item.admin_description">{{ item.admin_description }}</p>
<div class="text-sm text-gray-500 mt-3">
<span class="mr-2" v-for="t in item.tags" :key="t">#{{ t }}</span>
</div>
</div>
</template>
<script>
export default {
name: 'WordCard',
props: {
item: { type: Object, required: true }
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,97 @@
<template>
<form class="space-y-4" @submit.prevent="onSubmit">
<div>
<label class="block text-sm text-gray-600 mb-1">کلمه</label>
<input v-model="form.word" type="text" class="w-full border rounded px-3 py-2 focus:outline-none focus:ring focus:border-primary" required />
</div>
<div class="flex items-center space-x-2 rtl:space-x-reverse">
<input id="is_correct" v-model="form.is_correct" type="checkbox" class="h-4 w-4 text-primary" />
<label for="is_correct" class="text-sm text-gray-700">درست است</label>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-sm text-gray-600 mb-1">ریشه</label>
<input v-model="form.stem" type="text" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">اصل</label>
<input v-model="form.origin" type="text" class="w-full border rounded px-3 py-2" />
</div>
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">کلاس واژه</label>
<input v-model="wordClass" type="text" placeholder="مثال: noun, plural_noun" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">برچسبها</label>
<input v-model="tagsString" type="text" placeholder="مثال: formal, literary" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">زبان</label>
<input v-model="langString" type="text" placeholder="مثال: persian, arabic" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">دامنه</label>
<input v-model="scopeString" type="text" placeholder="مثال: ادبیات, آموزش" class="w-full border rounded px-3 py-2" />
</div>
<div>
<label class="block text-sm text-gray-600 mb-1">توضیح مدیر</label>
<textarea v-model="form.admin_description" rows="3" class="w-full border rounded px-3 py-2"></textarea>
</div>
<div class="pt-2">
<button type="submit" class="px-4 py-2 rounded bg-primary text-white hover:opacity-90">ذخیره</button>
</div>
</form>
</template>
<script>
export default {
name: 'WordForm',
props: {
value: { type: Object, required: true }
},
data() {
return {
form: { ...this.value },
tagsStringLocal: (this.value.tags || []).join(', '),
langStringLocal: (this.value.lang || []).join(', '),
scopeStringLocal: (this.value.scope || []).join(', '),
wordClassLocal: (this.value.word_class || []).join(', ')
};
},
computed: {
tagsString: {
get() { return this.tagsStringLocal; },
set(v) { this.tagsStringLocal = v; this.form.tags = this.csvToArray(v); }
},
langString: {
get() { return this.langStringLocal; },
set(v) { this.langStringLocal = v; this.form.lang = this.csvToArray(v); }
},
scopeString: {
get() { return this.scopeStringLocal; },
set(v) { this.scopeStringLocal = v; this.form.scope = this.csvToArray(v); }
},
wordClass: {
get() { return this.wordClassLocal; },
set(v) { this.wordClassLocal = v; this.form.word_class = this.csvToArray(v); }
}
},
methods: {
csvToArray(v) {
return (v || '')
.split(',')
.map(s => s.trim())
.filter(Boolean);
},
onSubmit() {
this.$emit('submit', this.form);
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,40 @@
<template>
<div>
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">کلمه</th>
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">درست</th>
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">زبان</th>
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">برچسبها</th>
<th class="px-4 py-2"></th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="row in rows" :key="row.id || row.word">
<td class="px-4 py-2 whitespace-nowrap">{{ row.word }}</td>
<td class="px-4 py-2">{{ row.is_correct ? '✓' : '✗' }}</td>
<td class="px-4 py-2">{{ (row.lang || []).join(', ') }}</td>
<td class="px-4 py-2">{{ (row.tags || []).join(', ') }}</td>
<td class="px-4 py-2 text-left">
<button class="px-3 py-1 rounded bg-primary text-white" @click="$emit('edit', row)">ویرایش</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'WordTable',
props: {
rows: { type: Array, default: () => [] }
}
};
</script>
<style>
</style>

13
frontEnd/src/main.js Normal file
View File

@ -0,0 +1,13 @@
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import './assets/tailwind.css';
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App)
}).$mount('#app');

View File

@ -0,0 +1,55 @@
<template>
<div class="space-y-4">
<h2 class="text-xl font-semibold">افزودن کلمه جدید</h2>
<div class="bg-white shadow rounded-lg p-4">
<WordForm :value="emptyWord" @submit="submit" />
</div>
</div>
</template>
<script>
import { createWord } from '@/services/api';
import WordForm from '@/components/WordForm.vue';
export default {
name: 'AddWord',
components: { WordForm },
data() {
return {
emptyWord: {
word: '',
is_correct: true,
nearest_correct_word: '',
origin: '',
stem: '',
is_proper_noun: false,
word_class: [],
tags: [],
ner_description: '',
llm_description: '',
user_description: '',
admin_description: '',
confidence: 1,
lang: [],
scope: []
}
};
},
methods: {
async submit(payload) {
try {
await createWord(payload);
this.$router.push('/words');
} catch (e) {
alert('خطا در ایجاد کلمه');
}
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,23 @@
<template>
<div class="max-w-4xl mx-auto p-4">
<h2 class="text-2xl font-bold mb-6 text-center">تصحیح کلمه پیشرفته</h2>
<div class="bg-white rounded-xl shadow-lg p-8">
<div class="text-center text-gray-500">
<div class="text-6xl mb-4">🚧</div>
<h3 class="text-xl font-semibold mb-2">در حال توسعه</h3>
<p>این بخش به زودی راهاندازی خواهد شد</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'AdvancedCorrect'
};
</script>
<style>
</style>

View File

@ -0,0 +1,25 @@
<template>
<div class="space-y-6">
<div class="bg-white shadow rounded-lg p-6">
<h2 class="text-lg font-semibold mb-2">داشبورد</h2>
<p class="text-gray-600">نمای کلی از سیستم و دسترسی سریع.</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<router-link to="/words" class="block bg-primary text-white rounded-lg p-6 shadow hover:opacity-90 transition">
لیست کلمات
</router-link>
<router-link to="/search" class="block bg-accent text-white rounded-lg p-6 shadow hover:opacity-90 transition">
جستجو
</router-link>
</div>
</div>
</template>
<script>
export default { name: 'Dashboard' };
</script>
<style>
</style>

View File

@ -0,0 +1,96 @@
<template>
<div class="max-w-7xl mx-auto p-4">
<!-- Main Cards Section -->
<div class="mb-12">
<h2 class="text-3xl font-bold text-center mb-8 text-gray-800">خدمات ما</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<!-- لیست کلمات -->
<router-link to="/words" class="group">
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div class="text-center">
<div class="w-16 h-16 bg-primary rounded-full flex items-center justify-center mx-auto mb-4 group-hover:bg-primary/80 transition-colors">
<span class="text-white text-2xl">📚</span>
</div>
<h3 class="text-xl font-semibold text-gray-800 mb-2">لیست کلمات</h3>
<p class="text-gray-600 text-sm">مشاهده و جستجو در بانک کلمات</p>
</div>
</div>
</router-link>
<!-- تصحیح کلمه -->
<router-link to="/correct" class="group">
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div class="text-center">
<div class="w-16 h-16 bg-accent rounded-full flex items-center justify-center mx-auto mb-4 group-hover:bg-accent/80 transition-colors">
<span class="text-white text-2xl"></span>
</div>
<h3 class="text-xl font-semibold text-gray-800 mb-2">تصحیح کلمه</h3>
<p class="text-gray-600 text-sm">تصحیح سریع کلمات نادرست</p>
</div>
</div>
</router-link>
<!-- تصحیح کلمه پیشرفته -->
<router-link to="/advanced-correct" class="group">
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div class="text-center">
<div class="w-16 h-16 bg-purple-500 rounded-full flex items-center justify-center mx-auto mb-4 group-hover:bg-purple-600 transition-colors">
<span class="text-white text-2xl">🔧</span>
</div>
<h3 class="text-xl font-semibold text-gray-800 mb-2">تصحیح پیشرفته</h3>
<p class="text-gray-600 text-sm">تصحیح هوشمند با الگوریتمهای پیشرفته</p>
</div>
</div>
</router-link>
<!-- اضافه کردن کلمه -->
<router-link to="/add" class="group">
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div class="text-center">
<div class="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-4 group-hover:bg-green-600 transition-colors">
<span class="text-white text-2xl"></span>
</div>
<h3 class="text-xl font-semibold text-gray-800 mb-2">اضافه کردن کلمه</h3>
<p class="text-gray-600 text-sm">افزودن کلمات جدید به بانک</p>
</div>
</div>
</router-link>
</div>
</div>
<!-- Articles Section -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-2xl font-bold text-center mb-6 text-gray-800">مقالات</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="border rounded-lg p-4 hover:shadow-md transition-shadow">
<h3 class="font-semibold text-gray-800 mb-2">راهنمای استفاده از سیستم</h3>
<p class="text-gray-600 text-sm">نحوه استفاده از امکانات مختلف سیستم تصحیح کلمات</p>
<div class="mt-2 text-xs text-gray-500">5 دقیقه مطالعه</div>
</div>
<div class="border rounded-lg p-4 hover:shadow-md transition-shadow">
<h3 class="font-semibold text-gray-800 mb-2">الگوریتمهای تصحیح</h3>
<p class="text-gray-600 text-sm">توضیح روشهای مختلف تصحیح کلمات در سیستم</p>
<div class="mt-2 text-xs text-gray-500">10 دقیقه مطالعه</div>
</div>
<div class="border rounded-lg p-4 hover:shadow-md transition-shadow">
<h3 class="font-semibold text-gray-800 mb-2">بهروزرسانیها</h3>
<p class="text-gray-600 text-sm">آخرین تغییرات و بهبودهای سیستم</p>
<div class="mt-2 text-xs text-gray-500">3 دقیقه مطالعه</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'HomePage'
};
</script>
<style>
</style>

View File

@ -0,0 +1,15 @@
<template>
<div class="flex items-center justify-center">
<SearchModal />
</div>
</template>
<script>
import SearchModal from '@/components/SearchModal.vue';
export default { name: 'SearchPage', components: { SearchModal } };
</script>
<style>
</style>

View File

@ -0,0 +1,23 @@
<template>
<div class="max-w-4xl mx-auto p-4">
<h2 class="text-2xl font-bold mb-6 text-center">تصحیح کلمه</h2>
<div class="bg-white rounded-xl shadow-lg p-8">
<div class="text-center text-gray-500">
<div class="text-6xl mb-4">🚧</div>
<h3 class="text-xl font-semibold mb-2">در حال توسعه</h3>
<p>این بخش به زودی راهاندازی خواهد شد</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'WordCorrect'
};
</script>
<style>
</style>

View File

@ -0,0 +1,70 @@
<template>
<div class="space-y-6">
<div class="bg-white shadow rounded-lg p-8 text-center">
<div class="text-3xl font-bold text-gray-900">"{{ word.word }}"</div>
<div class="mt-2 text-sm text-gray-500">درست: {{ word.is_correct ? 'بله' : 'خیر' }}</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-white shadow rounded-lg p-4">
<h3 class="font-semibold mb-2">مشخصات</h3>
<ul class="text-sm text-gray-700 space-y-1">
<li><strong>ریشه:</strong> {{ word.stem }}</li>
<li><strong>اصل:</strong> {{ word.origin }}</li>
<li><strong>کلاس:</strong> {{ (word.word_class || []).join(', ') }}</li>
<li><strong>زبان:</strong> {{ (word.lang || []).join(', ') }}</li>
<li><strong>دامنه:</strong> {{ (word.scope || []).join(', ') }}</li>
<li><strong>برچسبها:</strong> {{ (word.tags || []).join(', ') }}</li>
<li><strong>اعتماد:</strong> {{ word.confidence }}</li>
</ul>
</div>
<div class="bg-white shadow rounded-lg p-4">
<h3 class="font-semibold mb-2">توضیحات</h3>
<div class="text-sm text-gray-700 space-y-2">
<p v-if="word.ner_description"><strong>NER:</strong> {{ word.ner_description }}</p>
<p v-if="word.llm_description"><strong>LLM:</strong> {{ word.llm_description }}</p>
<p v-if="word.admin_description"><strong>مدیر:</strong> {{ word.admin_description }}</p>
<p v-if="word.user_description"><strong>کاربر:</strong> {{ word.user_description }}</p>
</div>
</div>
</div>
<div>
<router-link class="px-4 py-2 rounded bg-gray-100" to="/words">بازگشت</router-link>
</div>
</div>
</template>
<script>
import { getWord } from '@/services/api';
export default {
name: 'WordDetails',
props: { id: String },
data() {
return {
word: {}
};
},
async created() {
await this.fetchWord();
},
methods: {
async fetchWord() {
try {
const id = this.$route.params.id;
const { data } = await getWord(id);
this.word = data || {};
} catch (e) {
this.word = {};
}
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,65 @@
<template>
<div class="space-y-4">
<h2 class="text-xl font-semibold">ویرایش کلمه</h2>
<div class="bg-white shadow rounded-lg p-4">
<WordForm v-if="word" :value="word" @submit="save" />
<div v-else class="text-gray-500">در حال بارگذاری...</div>
</div>
</div>
</template>
<script>
import { updateWord } from '@/services/api';
import WordForm from '@/components/WordForm.vue';
export default {
name: 'WordEditor',
components: { WordForm },
props: { id: String },
data() {
return {
word: null
};
},
created() {
// In a real app, fetch by id. For now, load from history state or mock
if (history.state && history.state.word) {
this.word = history.state.word;
} else {
this.word = {
id: this.$route.params.id,
word: 'کتاب',
is_correct: true,
nearest_correct_word: 'کتاب',
origin: 'نوشتن',
stem: 'کتاب',
is_proper_noun: false,
word_class: ['noun'],
tags: ['formal'],
ner_description: 'واژه‌ای که به اثر مکتوب اشاره دارد.',
llm_description: 'این واژه در زمینه‌های آموزشی، ادبی و علمی کاربرد دارد.',
user_description: '',
admin_description: 'کتاب یک اثر چاپی یا دیجیتال است.',
confidence: 0.98,
lang: ['persian'],
scope: ['ادبیات']
};
}
},
methods: {
async save(payload) {
try {
await updateWord(this.$route.params.id, payload);
this.$router.push({ name: 'words' });
} catch (e) {
alert('خطا در ذخیره‌سازی');
}
}
}
};
</script>
<style>
</style>

View File

@ -0,0 +1,122 @@
<template>
<div class="space-y-4">
<div class="flex items-center justify-between">
<h2 class="text-xl font-semibold">لیست کلمات</h2>
<div class="flex items-center gap-3">
<label class="text-sm text-gray-600">تعداد در صفحه</label>
<select
v-model.number="pageSize"
@change="fetchWords"
class="border rounded px-2 py-1"
>
<option :value="10">10</option>
<option :value="20">20</option>
<option :value="50">50</option>
<option :value="100">100</option>
</select>
<router-link to="/add" class="px-4 py-2 rounded bg-primary text-white"
>افزودن کلمه</router-link
>
</div>
</div>
<div class="bg-white shadow rounded-lg">
<ul class="divide-y divide-gray-200">
<li
v-for="item in words"
:key="item.edited_at"
class="p-4 hover:bg-gray-50 cursor-pointer flex items-center justify-between"
@click="openDetails(item)"
>
<div>
<div class="font-large text-gray-900 ">{{ item.word }}</div>
<div class="text-xs text-gray-500 mt-1">
<span class="ml-3"
>تست شده : {{ item.is_correct ? "بله" : "خیر" }}</span
>
<span class="ml-3">
زبان:
{{Array.isArray(item.lang) ? item.lang.join(", ") : item.lang || "نامشخص"}}
</span>
<span class="ml-3"> مصدر کلمه: {{ item.origin && item.origin !== '' ? item.origin : "نامشخص" }}</span>
<span class="ml-3">ریشه کلمه: {{ item.stem && item.stem !== '' ? item.stem : "نامشخص" }}</span>
<span class="">برچسبها: {{ (item.tags || []).join(", ") }}</span>
</div>
</div>
</li>
</ul>
<div v-if="loading" class="p-3 text-sm text-gray-500 border-t">
در حال بارگذاری...
</div>
<div v-if="error" class="p-3 text-sm text-red-600 border-t">
{{ error }}
</div>
</div>
</div>
</template>
<script>
import { getWords } from "@/services/api";
export default {
name: "WordList",
data() {
return {
words: [],
pageSize: 100,
loading: false,
error: null,
};
},
created() {
this.fetchWords();
},
methods: {
async fetchWords() {
this.loading = true;
this.error = null;
try {
const response = await getWords({ page_size: this.pageSize });
// بررسی دقیق ساختار
if (!response || !response.data) {
console.error("❌ Response or response.data is undefined!");
this.error = "داده‌ای از سرور دریافت نشد";
return;
}
const data = response.data;
// اگر داده آرایه است
if (Array.isArray(data)) {
this.words = data;
}
// اگر داده داخل result بود
else if (data.result) {
this.words = data.result;
}
// اگر هیچکدام نبود
else {
console.error("❌ Unknown data structure:", data);
this.words = [];
this.error = "ساختار داده دریافتی معتبر نیست";
}
} catch (e) {
console.error("Error fetching words:", e);
this.error = "خطا در دریافت داده‌ها";
} finally {
this.loading = false;
}
},
openDetails(item) {
if (item && item.id) {
this.$router.push({ name: "word-details", params: { id: item.id } });
}
},
},
};
</script>
<style></style>

View File

@ -0,0 +1,22 @@
import Vue from 'vue';
import Router from 'vue-router';
import HomePage from '@/pages/HomePage.vue';
import WordList from '@/pages/WordList.vue';
import WordCorrect from '@/pages/WordCorrect.vue';
import AdvancedCorrect from '@/pages/AdvancedCorrect.vue';
import AddWord from '@/pages/AddWord.vue';
Vue.use(Router);
export default new Router({
mode: 'hash',
routes: [
{ path: '/', name: 'home', component: HomePage },
{ path: '/words', name: 'words', component: WordList },
{ path: '/correct', name: 'correct', component: WordCorrect },
{ path: '/advanced-correct', name: 'advanced-correct', component: AdvancedCorrect },
{ path: '/add', name: 'add-word', component: AddWord }
]
});

View File

@ -0,0 +1,15 @@
import axios from 'axios';
const API = axios.create({
baseURL: 'http://localhost:8020/api'
});
export const getWords = (params) => API.get('/words', { params });
export const searchWords = (filters) => API.post('/search', filters);
export const updateWord = (id, data) => API.put(`/words/${id}`, data);
export const createWord = (data) => API.post('/words', data);
export const getWord = (id) => API.get(`/words/${id}`);
export default API;

View File

@ -0,0 +1,20 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx}'
],
theme: {
extend: {
colors: {
primary: '#4F46E5',
accent: '#22C55E',
background: '#F9FAFB',
navbar_bg: '#06b6d4',
darkbg: '#1F2937'
}
}
},
plugins: []
};

22
frontEnd/vite.config.js Normal file
View File

@ -0,0 +1,22 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue2';
import path from 'path';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(process.cwd(), 'src')
}
},
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8020',
changeOrigin: true
}
}
}
});

293
main.py Normal file
View File

@ -0,0 +1,293 @@
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from fastapi.middleware.cors import CORSMiddleware
import asyncio
import requests
import time
from base_model import (
word_class_dict,
tags_dict,
lang_dict,
scope_dict,
WordCorrector,
IDRequest,
)
from fastapi import Request
from fastapi import Query, Request
import orjson
from multiprocessing import Pool
import orjson
import requests
import asyncio
import time
# ساخت برنامه
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # یا لیست دامنه‌هایی که می‌خوای اجازه داشته باشن
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
def sample_data_with_id(n_out):
result = []
for i in range(n_out):
sample_data = {
"id": "11111111111",
"word": "تست",
"is_correct": True,
"nearest_correct_word": "اصلاح شده",
"origin": "اصلاحی",
"stem": "اصلاح",
"is_proper_noun": False,
"word_class": "نادر",
"tags": ["عامیانه", "محاوره‌ای"],
"ner_description": "شسیبشسیبیسشبش",
"llm_description": "شسیبشسیبسشبش",
"user_description": "شیسبشسبیشسیب",
"admin_description": "شسیبشسب",
"confidence": 0.000005,
"lang": "فارسی",
"scope": "سایر",
"edited_at": i + 100,
}
result.append(sample_data)
return result
# -------------------------
# GET endpoints
# -------------------------
@app.get("/")
async def root():
return {"message": "API is running successfully!"}
@app.get("/api/words")
async def get_words(request: Request, page_size: int = Query(100)):
print("Headers:", request.headers) # هدرهای درخواست
print("Query Params:", request.query_params)
# یک لیست استاتیک از کلمات
result = sample_data_with_id(page_size)
print(f"Returning {len(result)} words")
return {"result": result}
@app.get("/api/word/{word_id}")
async def get_words(request: Request, page_size: int = Query(100)):
print("Headers:", request.headers) # هدرهای درخواست
print("Query Params:", request.query_params)
# یک لیست استاتیک از کلمات
result = sample_data_with_id(page_size)
print(f"Returning {len(result)} words")
return {"result": result}
# -------------------------
# POST endpoints
# -------------------------
@app.post("/api/search")
async def search_word(data: IDRequest) -> WordCorrector:
# (request: Request):
# body = await request.json()
# print("Request Body:", body) # نمایش JSON ورودی
# return {"status": "ok", "received": body}
return sample_data
@app.post("/api/update")
async def update_word(data: IDRequest) -> WordCorrector:
return {
"status": "updated",
"updated_id": data.id,
"name": data.name or "no name provided",
"message": "Word updated successfully!",
}
async def get_from_es():
pass
async def add_from_es():
pass
async def update_from_es():
pass
async def insert_from_json_file(data, es_name="aiword"):
# باید با الاستیک هلپر نوشته شود
output_format = {
"title": "",
"is_correct": False,
"nearest_correct_word": "",
"stem": "",
"origin": "",
"word_classes": [],
"word_tags": [],
"is_proper_noun": False,
"ner_description": "",
"llm_description": "",
"user_description": "",
"admin_description": "",
"confidence": 0.0,
"language_key": "persian",
"domain_tags": [],
}
input_format = {
"word": "آب",
"result": {
"word": "آب",
"is_correct": False,
"origin": "آب",
"word_class": "noun",
"proper_noun": False,
"tags": [],
"description": "A common noun meaning 'water' in Persian.",
"confidence": 1.0,
},
}
# URL مقصد
url = f"http://localhost:8010/v1/indices/{es_name}/insert"
# هدر برای ارسال JSON
headers = {"Content-Type": "application/json"}
result = []
for item in data:
if item['result'] != "model-failed" and isinstance(item["result"], dict):
# result.append(
if item["result"]["is_correct"] is True:
is_correct = 'صحیح'
elif item["result"]["is_correct"] is False:
is_correct = 'غلط'
else:
is_correct = 'نامشخص'
if item["result"]["proper_noun"] is True:
is_proper_noun = 'خاص'
if item["result"]["proper_noun"] is False:
is_proper_noun = 'عام'
else:
is_proper_noun = 'نامشخص'
payload = {
"document": {
"title": item["word"],
"is_correct": is_correct,
"nearest_correct_word": item["result"]["word"],
"stem": "",
"origin": item["result"]["origin"],
"word_classes": [item["result"]["word_class"]],
"word_tags": item["result"]["tags"],
"is_proper_noun": is_proper_noun,
"ner_description": item["result"]["description"],
"llm_description": "",
"user_description": "",
"admin_description": "",
"time_create":int(time.time()),
"confidence": item["result"]["confidence"] if "confidence" in item["result"] else 0.0,
"language_key": "persian",
"domain_tags": [],
"ref_key":"llm_msl_v1",
}
}
# break
else:
print(f'Unable to process item: {item}')
payload = {
"document": {
"title": item["word"],
"is_correct": 'نامشخص',
"nearest_correct_word": '',
"stem": "",
"origin": '',
"word_classes": [],
"word_tags": [],
"is_proper_noun": 'نامشخص',
"ner_description": '',
"llm_description": "",
"user_description": "",
"admin_description": "",
"time_create":int(time.time()),
"confidence": 0.0,
"language_key": "persian",
"domain_tags": [],
"ref_key":"llm_msl_v1",
}
}
try:
print(f'payload {payload}')
response = requests.post(url, json=payload, headers=headers)
print(f"وضعیت ارسال برای '{item['word']}': {response.status_code}")
if response.status_code not in (200, 201):
print("خطا در بدنه پاسخ:", response.text)
except requests.exceptions.RequestException as e:
print(f"خطا در ارسال درخواست برای '{item['word']}': {e}")
def wrapper(item_index_pair):
i, item = item_index_pair
print(f"--- {i}/ item -> {item}")
asyncio.run(insert_from_json_file([item]))
if __name__ == "__main__":
json_file = r"D:\init_mahdi\project\bank_words_per\make_data_llm\llm_data\temp.json"
with open(json_file, "rb") as f:
data = orjson.loads(f.read())
# data = data[8881:]
for i, j in enumerate(data):
if j['word'] == 'آوانویسیهایش':
print(f'found it ->{i} ->{j}')
data = data[i+1:]
total = len(data)
print(
f'data-> {data[0]}',
f'total {total}',
sep='\n'
)
# برای هر آیتم، ایندکس رو هم ارسال می‌کنیم
indexed_data = list(enumerate(data, start=4393))
with Pool(6) as p: # 6 هسته CPU
p.map(wrapper, indexed_data)
################################################
# json_file = r"D:\init_mahdi\project\bank_words_per\make_data_llm\llm_data\temp.json"
# with open(json_file, "rb") as f:
# data = orjson.loads(f.read())
# for i, j in enumerate(data, start=1):
# if i >= 4393:
# print(f"--- {i}/ {len(data)} --- j-> {j}")
# # break
# asyncio.run(insert_from_json_file([j]))
# import uvicorn
# uvicorn.run("main:app", host="0.0.0.0", port=8020, reload=True)

0
manage_es.py Normal file
View File

25
readme.md Normal file
View File

@ -0,0 +1,25 @@
- frontEnd
Vue 2 + Vite app in frontEnd with Tailwind, router, pages, components
and an API service pointing to http://localhost:8020/api. Next, run:
npm install
npm run dev
Files added:
frontEnd/package.json, vite.config.js, tailwind.config.cjs, postcss.config.cjs, index.html
src/main.js, src/App.vue, src/assets/tailwind.css
src/router/index.js
src/services/api.js
src/pages/Dashboard.vue, src/pages/WordList.vue, src/pages/WordEditor.vue, src/pages/SearchPage.vue
src/components/WordTable.vue, src/components/WordCard.vue, src/components/WordForm.vue, src/components/SearchModal.vue
src/mock/sampleWord.json
API proxy in dev is also set in vite.config.js for /api to http://localhost:8020.
Search flow:
Go to /search, submit filters; it POSTs to /api/search and shows results with an edit link to /word/:id/edit.
If you want, I can install dependencies and start the dev server now.
-----------------------------------------------------------------------------------------------------------------------------
- backEnd
FastApi
-----------------------------------------------------------------------------------------------------------------------------

4
requierments.txt Normal file
View File

@ -0,0 +1,4 @@
fastapi
uvicorn
requests
orjson

35
testi.py Normal file
View File

@ -0,0 +1,35 @@
{
"title": "آباد",
"is_correct": true,
"nearest_correct_word": "آباد",
"stem": "آباد",
"origin": "آباد",
"word_classes": "adjective",
"word_tags": [],
"is_proper_noun": false,
"ner_description": "An adjective meaning prosperous, flourishing, or inhabited.",
"llm_description": "",
"user_description": "",
"admin_description": "",
"confidence": 0.00,
"language_key": "persian",
"domain_tags": [],
"time_create": "2024-05-20 14:30:00",
"time_edit": "2024-05-20 14:30:00"
}
{
"word": "\n",
"result": {
"word": "آباد",
"is_correct": true,
"origin": "آباد",
"word_class": "adjective",
"proper_noun": false,
"tags": [],
"description": ,
"confidence": 0.95
}
},
{'word': 'آب', 'result': {'word': 'آب', 'is_correct': True, 'origin': 'آب', 'word_class': 'noun', 'proper_noun': False, 'tags': [], 'description': "A common noun meaning 'water' in Persian.", 'confidence': 1.0}}

145
testttt.py Normal file
View File

@ -0,0 +1,145 @@
{
"detail": {
"valid": False,
"field_validations": {
"title": {
"valid": True,
"value": "آب",
"errors": [],
"warnings": [],
"field_name": "title",
"field_type": "text",
},
"is_correct": {
"valid": True,
"value": "صحیح",
"errors": [],
"warnings": [],
"field_name": "is_correct",
"field_type": "keyword",
},
"nearest_correct_word": {
"valid": True,
"value": "آب",
"errors": [],
"warnings": [],
"field_name": "nearest_correct_word",
"field_type": "text",
},
"stem": {
"valid": True,
"value": "",
"errors": [],
"warnings": [],
"field_name": "stem",
"field_type": "keyword",
},
"origin": {
"valid": True,
"value": "آب",
"errors": [],
"warnings": [],
"field_name": "origin",
"field_type": "keyword",
},
"word_classes": {
"valid": True,
"value": ["noun"],
"errors": [],
"warnings": [],
"field_name": "word_classes",
"field_type": "keyword",
},
"word_tags": {
"valid": True,
"value": [],
"errors": [],
"warnings": [],
"field_name": "word_tags",
"field_type": "keyword",
},
"is_proper_noun": {
"valid": False,
"value": "عام",
"errors": ["Value must be an integer"],
"warnings": [],
"field_name": "is_proper_noun",
"field_type": "integer",
},
"ner_description": {
"valid": True,
"value": 'A common noun meaning "water" in Persian.',
"errors": [],
"warnings": [],
"field_name": "ner_description",
"field_type": "text",
},
"llm_description": {
"valid": True,
"value": "",
"errors": [],
"warnings": [],
"field_name": "llm_description",
"field_type": "text",
},
"user_description": {
"valid": True,
"value": "",
"errors": [],
"warnings": [],
"field_name": "user_description",
"field_type": "text",
},
"admin_description": {
"valid": True,
"value": "",
"errors": [],
"warnings": [],
"field_name": "admin_description",
"field_type": "text",
},
"time_create": {
"valid": True,
"value": "2025-09-29 20:03:29",
"errors": [],
"warnings": [],
"field_name": "time_create",
"field_type": "date",
},
"confidence": {
"valid": True,
"value": 1.0,
"errors": [],
"warnings": [],
"field_name": "confidence",
"field_type": "float",
},
"language_key": {
"valid": True,
"value": "persian",
"errors": [],
"warnings": [],
"field_name": "language_key",
"field_type": "keyword",
},
"domain_tags": {
"valid": True,
"value": [],
"errors": [],
"warnings": [],
"field_name": "domain_tags",
"field_type": "keyword",
},
"ref_key": {
"valid": True,
"value": "llm_msl_v1",
"errors": [],
"warnings": [],
"field_name": "ref_key",
"field_type": "keyword",
},
},
"errors": ["Value must be an integer"],
"warnings": [],
}
}