Con_Ana2 / app.py
Rasha-83's picture
Update app.py
0e703eb verified
import gradio as gr
from transformers import AutoTokenizer, AutoModel, PreTrainedTokenizerFast
import torch
import numpy as np
from typing import List, Dict
class SentenceEncoder:
def __init__(self, model_name="aubmindlab/bert-large-arabertv2", max_length=512):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModel.from_pretrained(model_name)
self.max_length = max_length
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.model.to(self.device)
def mean_pooling(self, model_output, attention_mask):
"""تجميع متوسط التمثيل للجملة"""
token_embeddings = model_output[0]
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
def encode(self, sentences: List[str]) -> np.ndarray:
"""تحويل الجمل إلى متجهات"""
# تحويل النص إلى tokens
encoded_input = self.tokenizer(
sentences,
padding=True,
truncation=True,
max_length=self.max_length,
return_tensors='pt'
).to(self.device)
# الحصول على التمثيلات
with torch.no_grad():
model_output = self.model(**encoded_input)
# تجميع المتوسط للحصول على تمثيل الجملة
sentence_embeddings = self.mean_pooling(model_output, encoded_input['attention_mask'])
# تطبيع المتجهات
sentence_embeddings = torch.nn.functional.normalize(sentence_embeddings, p=2, dim=1)
return sentence_embeddings.cpu().numpy()
class ContractAnalyzer:
def __init__(self):
print("جاري تحميل النموذج...")
self.encoder = SentenceEncoder()
print("تم تحميل النموذج بنجاح!")
self.legal_keywords = [
"يلتزم", "الزام", "يتعهد", "يحق", "لا يحق", "شرط جزائي",
"فسخ العقد", "إنهاء", "تعويض", "غرامة", "مدة العقد",
"طرف أول", "طرف ثاني", "قيمة العقد", "التزامات", "سداد",
"دفعات", "ينكل", "ضمان", "مخالفة", "إخلال", "قوة قاهرة"
]
self.analysis_prompt = """
تحليل العقد القانوني:
1. معلومات أساسية:
- تاريخ العقد: {date}
- الأطراف المتعاقدة: {parties}
- موضوع العقد: {subject}
2. تحليل المحتوى (درجة التشابه): {similarity_score}
3. المخاطر المحتملة:
{risks}
4. العناصر المفقودة أو غير الواضحة:
{missing_elements}
5. توصيات قانونية:
{recommendations}
"""
def extract_contract_info(self, text):
"""استخراج المعلومات الأساسية من العقد"""
info = {
"date": "غير محدد",
"parties": [],
"subject": "غير محدد"
}
# البحث عن التاريخ
date_indicators = ["بتاريخ", "في يوم", "الموافق"]
for indicator in date_indicators:
if indicator in text:
# استخراج التاريخ باستخدام تعبير نمطي بسيط
start_idx = text.find(indicator)
end_idx = text.find("\n", start_idx)
if end_idx == -1:
end_idx = text.find(".", start_idx)
if end_idx != -1:
info["date"] = text[start_idx:end_idx].strip()
# البحث عن الأطراف
party_indicators = ["طرف أول", "طرف ثاني", "الطرف الأول", "الطرف الثاني", "الفريق الأول", "الفريق الثاني"]
for indicator in party_indicators:
if indicator in text:
start_idx = text.find(indicator)
end_idx = text.find("\n", start_idx)
if end_idx == -1:
end_idx = text.find(".", start_idx)
if end_idx != -1:
info["parties"].append(text[start_idx:end_idx].strip())
# البحث عن الموضوع
if info["subject"] == "غير محدد":
# البحث في الجمل الأولى من العقد
first_sentences = text.split('\n')[:3] # أول ثلاث جمل
for sentence in first_sentences:
if any(word in sentence.lower() for word in ["اتفاق", "عقد", "تعاقد"]):
info["subject"] = sentence.strip()
break
return info
def compute_similarity(self, sentences: List[str]) -> float:
"""حساب درجة التشابه بين الجمل"""
if not sentences:
return 0.0
embeddings = self.encoder.encode(sentences)
if len(embeddings) < 2:
return 1.0
# حساب مصفوفة التشابه
similarity_matrix = np.dot(embeddings, embeddings.T)
# حساب متوسط التشابه
n = len(similarity_matrix)
similarity_sum = (similarity_matrix.sum() - n) / (n * (n - 1)) if n > 1 else 0
return float(similarity_sum)
def analyze_contract(self, contract_text: str) -> str:
try:
# تقسيم النص إلى جمل
sentences = [s.strip() for s in contract_text.split('.') if len(s.strip()) > 5]
# حساب درجة التشابه
similarity_score = self.compute_similarity(sentences)
# استخراج المعلومات وتحليل المخاطر
contract_info = self.extract_contract_info(contract_text)
results = self.analyze_content(sentences)
# تنسيق النتائج
formatted_results = self.analysis_prompt.format(
date=contract_info["date"],
parties="\n".join(contract_info["parties"]) or "غير محدد",
subject=contract_info["subject"],
similarity_score=f"{similarity_score:.2%}",
risks="\n".join([f"• {risk}" for risk in results["risks"]]) or "لا توجد مخاطر واضحة",
missing_elements="\n".join([f"• {element}" for element in results["missing_elements"]]) or "لا توجد عناصر مفقودة",
recommendations="\n".join([f"• {rec}" for rec in results["recommendations"]]) or "لا توجد توصيات إضافية"
)
return formatted_results
except Exception as e:
return f"حدث خطأ أثناء التحليل: {str(e)}"
def analyze_content(self, sentences: List[str]) -> Dict:
"""تحليل محتوى العقد"""
results = {
"risks": [],
"missing_elements": [],
"recommendations": []
}
# تحليل المخاطر والعناصر المفقودة
for sentence in sentences:
# تحليل المخاطر
risk_words = ["مخالفة", "خرق", "نزاع", "خلاف", "إخلال", "فسخ"]
if any(word in sentence.lower() for word in risk_words):
results["risks"].append(sentence.strip())
# التحقق من العناصر المفقودة
required_elements = [
"مدة العقد", "قيمة العقد", "التزامات الطرفين",
"طريقة السداد", "الضمانات", "شروط الإنهاء"
]
for element in required_elements:
if not any(element in s for s in sentences):
results["missing_elements"].append(element)
results["recommendations"].append(f"يجب إضافة {element} بشكل واضح في العقد")
return results
# إنشاء كائن المحلل
analyzer = ContractAnalyzer()
# دالة التحليل لواجهة gradio
def analyze_text(text):
return analyzer.analyze_contract(text)
# تكوين واجهة gradio
iface = gr.Interface(
fn=analyze_text,
inputs=gr.Textbox(
placeholder="أدخل نص العقد هنا...",
label="نص العقد",
lines=30,
rtl=True, # إضافة دعم RTL للمدخلات
),
outputs=gr.Textbox(
label="نتائج التحليل",
lines=30,
rtl=True, # إضافة دعم RTL للمخرجات
),
title="محلل العقود القانونية ",
description="""
قم بإدخال نص العقد القانوني للحصول على تحليل شامل يتضمن:
• المعلومات الأساسية للعقد
• المخاطر المحتملة
• العناصر المفقودة
• التوصيات القانونية
""",
theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="blue",
neutral_hue="blue",
),
css="""
.gradio-container {
direction: rtl !important;
text-align: right !important;
}
.output-markdown {
direction: rtl !important;
text-align: right !important;
}
.input-markdown {
direction: rtl !important;
text-align: right !important;
}
label {
text-align: right !important;
}
.prose {
direction: rtl !important;
text-align: right !important;
}
"""
)
# تشغيل الواجهة
iface.launch(share=True, debug=True)