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