first-step
This commit is contained in:
commit
9850f8598e
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal 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
0
__init__.py
Normal file
299
base_model.py
Normal file
299
base_model.py
Normal 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
13
frontEnd/index.html
Normal 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
2697
frontEnd/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
frontEnd/package.json
Normal file
24
frontEnd/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
|
||||
7
frontEnd/postcss.config.cjs
Normal file
7
frontEnd/postcss.config.cjs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
|
||||
13
frontEnd/public/index.html
Normal file
13
frontEnd/public/index.html
Normal 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
42
frontEnd/src/App.vue
Normal 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>
|
||||
|
||||
|
||||
9
frontEnd/src/assets/tailwind.css
Normal file
9
frontEnd/src/assets/tailwind.css
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html, body, #app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
97
frontEnd/src/components/SearchModal.vue
Normal file
97
frontEnd/src/components/SearchModal.vue
Normal 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>
|
||||
|
||||
|
||||
26
frontEnd/src/components/WordCard.vue
Normal file
26
frontEnd/src/components/WordCard.vue
Normal 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>
|
||||
|
||||
|
||||
97
frontEnd/src/components/WordForm.vue
Normal file
97
frontEnd/src/components/WordForm.vue
Normal 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>
|
||||
|
||||
|
||||
40
frontEnd/src/components/WordTable.vue
Normal file
40
frontEnd/src/components/WordTable.vue
Normal 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
13
frontEnd/src/main.js
Normal 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');
|
||||
|
||||
|
||||
55
frontEnd/src/pages/AddWord.vue
Normal file
55
frontEnd/src/pages/AddWord.vue
Normal 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>
|
||||
|
||||
|
||||
|
||||
23
frontEnd/src/pages/AdvancedCorrect.vue
Normal file
23
frontEnd/src/pages/AdvancedCorrect.vue
Normal 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>
|
||||
|
||||
|
||||
25
frontEnd/src/pages/Dashboard.vue
Normal file
25
frontEnd/src/pages/Dashboard.vue
Normal 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>
|
||||
|
||||
|
||||
96
frontEnd/src/pages/HomePage.vue
Normal file
96
frontEnd/src/pages/HomePage.vue
Normal 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>
|
||||
|
||||
|
||||
15
frontEnd/src/pages/SearchPage.vue
Normal file
15
frontEnd/src/pages/SearchPage.vue
Normal 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>
|
||||
|
||||
|
||||
23
frontEnd/src/pages/WordCorrect.vue
Normal file
23
frontEnd/src/pages/WordCorrect.vue
Normal 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>
|
||||
|
||||
|
||||
70
frontEnd/src/pages/WordDetails.vue
Normal file
70
frontEnd/src/pages/WordDetails.vue
Normal 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>
|
||||
|
||||
|
||||
|
||||
65
frontEnd/src/pages/WordEditor.vue
Normal file
65
frontEnd/src/pages/WordEditor.vue
Normal 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>
|
||||
|
||||
|
||||
122
frontEnd/src/pages/WordList.vue
Normal file
122
frontEnd/src/pages/WordList.vue
Normal 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>
|
||||
22
frontEnd/src/router/index.js
Normal file
22
frontEnd/src/router/index.js
Normal 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 }
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
15
frontEnd/src/services/api.js
Normal file
15
frontEnd/src/services/api.js
Normal 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;
|
||||
|
||||
|
||||
20
frontEnd/tailwind.config.cjs
Normal file
20
frontEnd/tailwind.config.cjs
Normal 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
22
frontEnd/vite.config.js
Normal 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
293
main.py
Normal 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
0
manage_es.py
Normal file
25
readme.md
Normal file
25
readme.md
Normal 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
4
requierments.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
fastapi
|
||||
uvicorn
|
||||
requests
|
||||
orjson
|
||||
35
testi.py
Normal file
35
testi.py
Normal 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
145
testttt.py
Normal 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": [],
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user