Spaces:
Paused
Paused
import os | |
import json | |
import re | |
import requests | |
import numpy as np | |
from typing import Dict, List, Any, Union, Tuple, Optional | |
from datetime import datetime | |
class LLMProcessor: | |
""" | |
فئة للتعامل مع نماذج اللغة الكبيرة (LLM) لتحليل المناقصات | |
""" | |
def __init__(self, model_name: str = "claude-3-haiku-20240307", use_rag: bool = True): | |
""" | |
تهيئة معالج نماذج اللغة الكبيرة | |
المعاملات: | |
---------- | |
model_name : str, optional | |
اسم النموذج المستخدم (افتراضي: "claude-3-haiku-20240307") | |
use_rag : bool, optional | |
استخدام تقنية RAG (Retrieval-Augmented Generation) (افتراضي: True) | |
""" | |
self.model_name = model_name | |
self.use_rag = use_rag | |
# الحصول على مفتاح واجهة برمجة التطبيقات من متغيرات البيئة | |
self.api_key = os.getenv("ANTHROPIC_API_KEY") | |
# تهيئة قاعدة بيانات المتجهات إذا كان استخدام RAG مفعلاً | |
if self.use_rag: | |
self.vector_db = VectorDB() | |
def analyze_requirements(self, requirements: List[Dict[str, Any]], context: Dict[str, Any]) -> Dict[str, Any]: | |
""" | |
تحليل المتطلبات باستخدام نموذج اللغة الكبيرة | |
المعاملات: | |
---------- | |
requirements : List[Dict[str, Any]] | |
قائمة المتطلبات المستخرجة من المستندات | |
context : Dict[str, Any] | |
معلومات السياق الإضافية | |
المخرجات: | |
-------- | |
Dict[str, Any] | |
نتائج تحليل المتطلبات | |
""" | |
# إعداد الاستعلام بناءً على المتطلبات والسياق | |
prompt = self._prepare_requirements_prompt(requirements, context) | |
# استدعاء النموذج | |
response = self._call_llm(prompt) | |
# معالجة الاستجابة | |
analysis = self._parse_requirements_response(response) | |
return analysis | |
def analyze_local_content(self, local_content_data: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]: | |
""" | |
تحليل بيانات المحتوى المحلي باستخدام نموذج اللغة الكبيرة | |
المعاملات: | |
---------- | |
local_content_data : Dict[str, Any] | |
بيانات المحتوى المحلي المستخرجة | |
context : Dict[str, Any] | |
معلومات السياق الإضافية | |
المخرجات: | |
-------- | |
Dict[str, Any] | |
نتائج تحليل المحتوى المحلي | |
""" | |
# إعداد الاستعلام بناءً على بيانات المحتوى المحلي والسياق | |
prompt = self._prepare_local_content_prompt(local_content_data, context) | |
# استدعاء النموذج | |
response = self._call_llm(prompt) | |
# معالجة الاستجابة | |
analysis = self._parse_local_content_response(response) | |
return analysis | |
def analyze_supply_chain(self, supply_chain_data: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]: | |
""" | |
تحليل بيانات سلسلة الإمداد باستخدام نموذج اللغة الكبيرة | |
المعاملات: | |
---------- | |
supply_chain_data : Dict[str, Any] | |
بيانات سلسلة الإمداد المستخرجة | |
context : Dict[str, Any] | |
معلومات السياق الإضافية | |
المخرجات: | |
-------- | |
Dict[str, Any] | |
نتائج تحليل سلسلة الإمداد | |
""" | |
# إعداد الاستعلام بناءً على بيانات سلسلة الإمداد والسياق | |
prompt = self._prepare_supply_chain_prompt(supply_chain_data, context) | |
# استدعاء النموذج | |
response = self._call_llm(prompt) | |
# معالجة الاستجابة | |
analysis = self._parse_supply_chain_response(response) | |
return analysis | |
def generate_summary(self, extracted_data: Dict[str, Any], analysis_results: Dict[str, Any]) -> Dict[str, Any]: | |
""" | |
إعداد ملخص شامل للمناقصة ونتائج التحليل | |
المعاملات: | |
---------- | |
extracted_data : Dict[str, Any] | |
البيانات المستخرجة من المستندات | |
analysis_results : Dict[str, Any] | |
نتائج التحليلات المختلفة | |
المخرجات: | |
-------- | |
Dict[str, Any] | |
الملخص والتوصيات | |
""" | |
# إعداد الاستعلام بناءً على البيانات المستخرجة ونتائج التحليل | |
prompt = self._prepare_summary_prompt(extracted_data, analysis_results) | |
# استدعاء النموذج | |
response = self._call_llm(prompt) | |
# معالجة الاستجابة | |
summary = self._parse_summary_response(response) | |
return summary | |
def _prepare_requirements_prompt(self, requirements: List[Dict[str, Any]], context: Dict[str, Any]) -> str: | |
""" | |
إعداد استعلام لتحليل المتطلبات | |
""" | |
prompt = """ | |
أنت خبير في تحليل المناقصات والعقود. يرجى تحليل المتطلبات التالية وتقديم نظرة ثاقبة حول جودتها واكتمالها ووضوحها وأي فجوات أو مخاطر محتملة. | |
المتطلبات: | |
""" | |
for i, req in enumerate(requirements): | |
prompt += f"\n{i+1}. {req.get('title', 'متطلب')}: {req.get('description', '')}" | |
prompt += f"\n الفئة: {req.get('category', 'عامة')}, الأهمية: {req.get('importance', 'عادية')}" | |
prompt += """ | |
الرجاء تقديم التحليل التالي: | |
1. ملخص عام للمتطلبات | |
2. تقييم جودة المتطلبات (الوضوح، الاكتمال، القابلية للقياس) | |
3. تحديد أي فجوات أو تناقضات في المتطلبات | |
4. توصيات لتحسين المتطلبات | |
5. المخاطر المحتملة المرتبطة بهذه المتطلبات | |
يرجى تقديم إجابتك في تنسيق JSON مع المفاتيح التالية: summary, quality_assessment, gaps, recommendations, risks | |
""" | |
# إضافة معلومات السياق | |
if context: | |
prompt += "\n\nمعلومات إضافية للسياق:\n" | |
for key, value in context.items(): | |
prompt += f"{key}: {value}\n" | |
# إضافة محتوى RAG إذا كان مفعلاً | |
if self.use_rag: | |
relevant_content = self.vector_db.retrieve_similar_content( | |
" ".join([req.get("title", "") + " " + req.get("description", "") for req in requirements]) | |
) | |
if relevant_content: | |
prompt += "\n\nمعلومات ذات صلة من مناقصات سابقة:\n" | |
for i, content in enumerate(relevant_content): | |
prompt += f"{i+1}. {content}\n" | |
return prompt | |
def _prepare_local_content_prompt(self, local_content_data: Dict[str, Any], context: Dict[str, Any]) -> str: | |
""" | |
إعداد استعلام لتحليل المحتوى المحلي | |
""" | |
prompt = """ | |
أنت خبير في تحليل المحتوى المحلي في المناقصات. يرجى تحليل بيانات المحتوى المحلي التالية وتقديم نظرة ثاقبة حول الامتثال لمتطلبات المحتوى المحلي وفرص التحسين. | |
بيانات المحتوى المحلي: | |
""" | |
# إضافة بيانات المحتوى المحلي | |
prompt += f"\nالنسبة الإجمالية للمحتوى المحلي: {local_content_data.get('overall_percentage', 'غير محدد')}%" | |
if "breakdown" in local_content_data: | |
prompt += "\n\nتفاصيل المحتوى المحلي:" | |
for category, percentage in local_content_data["breakdown"].items(): | |
prompt += f"\n- {category}: {percentage}%" | |
if "requirements" in local_content_data: | |
prompt += "\n\nمتطلبات المحتوى المحلي:" | |
for i, req in enumerate(local_content_data["requirements"]): | |
prompt += f"\n{i+1}. {req.get('title', '')}: {req.get('description', '')}" | |
prompt += """ | |
الرجاء تقديم التحليل التالي: | |
1. تقييم الامتثال لمتطلبات المحتوى المحلي | |
2. فرص تحسين نسبة المحتوى المحلي | |
3. استراتيجيات لزيادة المحتوى المحلي | |
4. المخاطر المرتبطة بالمحتوى المحلي | |
5. أفضل الممارسات من مشاريع مماثلة | |
يرجى تقديم إجابتك في تنسيق JSON مع المفاتيح التالية: compliance_assessment, improvement_opportunities, strategies, risks, best_practices | |
""" | |
# إضافة معلومات السياق | |
if context: | |
prompt += "\n\nمعلومات إضافية للسياق:\n" | |
for key, value in context.items(): | |
prompt += f"{key}: {value}\n" | |
# إضافة محتوى RAG إذا كان مفعلاً | |
if self.use_rag: | |
relevant_content = self.vector_db.retrieve_similar_content("المحتوى المحلي نطاقات توطين") | |
if relevant_content: | |
prompt += "\n\nمعلومات ذات صلة من مناقصات سابقة:\n" | |
for i, content in enumerate(relevant_content): | |
prompt += f"{i+1}. {content}\n" | |
return prompt | |
def _prepare_supply_chain_prompt(self, supply_chain_data: Dict[str, Any], context: Dict[str, Any]) -> str: | |
""" | |
إعداد استعلام لتحليل سلسلة الإمداد | |
""" | |
prompt = """ | |
أنت خبير في تحليل سلسلة الإمداد في المناقصات. يرجى تحليل بيانات سلسلة الإمداد التالية وتقديم نظرة ثاقبة حول المخاطر وفرص التحسين. | |
بيانات سلسلة الإمداد: | |
""" | |
# إضافة بيانات سلسلة الإمداد | |
if "potential_suppliers" in supply_chain_data: | |
prompt += "\n\nالموردين المحتملين:" | |
for i, supplier in enumerate(supply_chain_data["potential_suppliers"][:5]): # أخذ أول 5 موردين | |
prompt += f"\n{i+1}. {supplier.get('name', '')}, التقييم: {supplier.get('rating', '')}, نسبة المحتوى المحلي: {supplier.get('local_content_percentage', '')}%" | |
if "needed_materials" in supply_chain_data: | |
prompt += "\n\nالمواد المطلوبة:" | |
for i, material in enumerate(supply_chain_data["needed_materials"]): | |
prompt += f"\n{i+1}. {material.get('name', '')}, التوفر المحلي: {material.get('local_availability', '')}" | |
if "risks" in supply_chain_data: | |
prompt += "\n\nالمخاطر:" | |
for i, risk in enumerate(supply_chain_data["risks"]): | |
prompt += f"\n{i+1}. {risk.get('title', '')}: {risk.get('description', '')}" | |
prompt += """ | |
الرجاء تقديم التحليل التالي: | |
1. تقييم عام لسلسلة الإمداد | |
2. نقاط القوة والضعف في سلسلة الإمداد | |
3. استراتيجيات لتحسين سلسلة الإمداد | |
4. فرص لزيادة المحتوى المحلي في سلسلة الإمداد | |
5. خطة للتخفيف من مخاطر سلسلة الإمداد | |
يرجى تقديم إجابتك في تنسيق JSON مع المفاتيح التالية: overall_assessment, strengths_weaknesses, improvement_strategies, local_content_opportunities, risk_mitigation_plan | |
""" | |
# إضافة معلومات السياق | |
if context: | |
prompt += "\n\nمعلومات إضافية للسياق:\n" | |
for key, value in context.items(): | |
prompt += f"{key}: {value}\n" | |
# إضافة محتوى RAG إذا كان مفعلاً | |
if self.use_rag: | |
relevant_content = self.vector_db.retrieve_similar_content("سلسلة الإمداد موردين مواد مخاطر") | |
if relevant_content: | |
prompt += "\n\nمعلومات ذات صلة من مناقصات سابقة:\n" | |
for i, content in enumerate(relevant_content): | |
prompt += f"{i+1}. {content}\n" | |
return prompt | |
def _prepare_summary_prompt(self, extracted_data: Dict[str, Any], analysis_results: Dict[str, Any]) -> str: | |
""" | |
إعداد استعلام لإعداد ملخص شامل | |
""" | |
prompt = """ | |
أنت خبير في تحليل المناقصات والعقود. يرجى إعداد ملخص تنفيذي شامل للمناقصة وتقديم توصيات استراتيجية بناءً على البيانات ونتائج التحليل المقدمة. | |
معلومات المناقصة: | |
""" | |
# إضافة معلومات أساسية عن المناقصة | |
if "project_title" in extracted_data: | |
prompt += f"\nعنوان المشروع: {extracted_data.get('project_title', '')}" | |
if "project_type" in extracted_data: | |
prompt += f"\nنوع المشروع: {extracted_data.get('project_type', '')}" | |
if "financial_data" in extracted_data and "total_cost" in extracted_data["financial_data"]: | |
total_cost = extracted_data["financial_data"]["total_cost"] | |
prompt += f"\nالقيمة الإجمالية: {total_cost.get('value', '')} {total_cost.get('currency', 'ريال')}" | |
# إضافة ملخص نتائج التحليل | |
prompt += "\n\nملخص نتائج التحليل:" | |
if "requirements" in analysis_results: | |
req_count = len(analysis_results["requirements"].get("requirements", [])) | |
prompt += f"\n- تم تحليل {req_count} متطلبات" | |
if "compliance" in analysis_results["requirements"]: | |
compliance_rate = analysis_results["requirements"]["compliance"].get("compliance_rate", 0) | |
prompt += f", نسبة الامتثال: {compliance_rate}%" | |
if "local_content" in analysis_results: | |
local_content = analysis_results["local_content"] | |
prompt += f"\n- المحتوى المحلي: {local_content.get('overall_percentage', 0)}%" | |
if "supply_chain" in analysis_results: | |
supply_chain = analysis_results["supply_chain"] | |
suppliers_count = len(supply_chain.get("potential_suppliers", [])) | |
risks_count = len(supply_chain.get("risks", [])) | |
prompt += f"\n- سلسلة الإمداد: {suppliers_count} موردين محتملين, {risks_count} مخاطر محددة" | |
if "cost_analysis" in analysis_results: | |
cost_analysis = analysis_results["cost_analysis"] | |
if "contingency_reserve" in cost_analysis: | |
prompt += f"\n- احتياطي الطوارئ المقترح: {cost_analysis.get('contingency_reserve', 0)} ريال" | |
prompt += """ | |
الرجاء إعداد: | |
1. ملخص تنفيذي (500-700 كلمة) يشمل: | |
- نظرة عامة على المناقصة | |
- النقاط الرئيسية من التحليل | |
- الفرص والتحديات الرئيسية | |
- توصيات استراتيجية | |
2. قائمة بأهم 5-7 توصيات مرتبة حسب الأولوية، مع شرح موجز لكل توصية | |
يرجى تقديم إجابتك في تنسيق JSON مع المفاتيح التالية: executive_summary, key_recommendations | |
""" | |
# إضافة محتوى RAG إذا كان مفعلاً | |
if self.use_rag: | |
query = f"{extracted_data.get('project_title', '')} {extracted_data.get('project_type', '')}" | |
relevant_content = self.vector_db.retrieve_similar_content(query) | |
if relevant_content: | |
prompt += "\n\nمعلومات ذات صلة من مناقصات سابقة:\n" | |
for i, content in enumerate(relevant_content): | |
prompt += f"{i+1}. {content}\n" | |
return prompt | |
def _call_llm(self, prompt: str) -> str: | |
""" | |
استدعاء نموذج اللغة الكبيرة | |
""" | |
try: | |
# استدعاء واجهة برمجة التطبيقات Anthropic | |
headers = { | |
"Content-Type": "application/json", | |
"X-API-Key": self.api_key, | |
"anthropic-version": "2023-06-01" | |
} | |
data = { | |
"model": self.model_name, | |
"messages": [ | |
{"role": "user", "content": prompt} | |
], | |
"max_tokens": 2000, | |
"temperature": 0.2 | |
} | |
response = requests.post( | |
"https://api.anthropic.com/v1/messages", | |
headers=headers, | |
json=data | |
) | |
if response.status_code == 200: | |
result = response.json() | |
return result["content"][0]["text"] | |
else: | |
print(f"Error calling LLM API: {response.status_code}, {response.text}") | |
return f"Error: {response.status_code}, {response.text}" | |
except Exception as e: | |
print(f"Exception calling LLM API: {str(e)}") | |
return f"Error: {str(e)}" | |
def _parse_requirements_response(self, response: str) -> Dict[str, Any]: | |
""" | |
معالجة استجابة تحليل المتطلبات | |
""" | |
try: | |
# محاولة استخراج JSON من الاستجابة | |
json_pattern = r'```json(.*?)```' | |
json_match = re.search(json_pattern, response, re.DOTALL) | |
if json_match: | |
json_str = json_match.group(1) | |
return json.loads(json_str) | |
# محاولة تحميل الاستجابة الكاملة كـ JSON | |
return json.loads(response) | |
except Exception as e: | |
print(f"Error parsing requirements response: {str(e)}") | |
# إذا فشل تحليل JSON، إرجاع النص كملخص | |
return { | |
"summary": response, | |
"error": str(e) | |
} | |
def _parse_local_content_response(self, response: str) -> Dict[str, Any]: | |
""" | |
معالجة استجابة تحليل المحتوى المحلي | |
""" | |
try: | |
# محاولة استخراج JSON من الاستجابة | |
json_pattern = r'```json(.*?)```' | |
json_match = re.search(json_pattern, response, re.DOTALL) | |
if json_match: | |
json_str = json_match.group(1) | |
return json.loads(json_str) | |
# محاولة تحميل الاستجابة الكاملة كـ JSON | |
return json.loads(response) | |
except Exception as e: | |
print(f"Error parsing local content response: {str(e)}") | |
# إذا فشل تحليل JSON، إرجاع النص كتقييم | |
return { | |
"compliance_assessment": response, | |
"error": str(e) | |
} | |
def _parse_supply_chain_response(self, response: str) -> Dict[str, Any]: | |
""" | |
معالجة استجابة تحليل سلسلة الإمداد | |
""" | |
try: | |
# محاولة استخراج JSON من الاستجابة | |
json_pattern = r'```json(.*?)```' | |
json_match = re.search(json_pattern, response, re.DOTALL) | |
if json_match: | |
json_str = json_match.group(1) | |
return json.loads(json_str) | |
# محاولة تحميل الاستجابة الكاملة كـ JSON | |
return json.loads(response) | |
except Exception as e: | |
print(f"Error parsing supply chain response: {str(e)}") | |
# إذا فشل تحليل JSON، إرجاع النص كتقييم | |
return { | |
"overall_assessment": response, | |
"error": str(e) | |
} | |
def _parse_summary_response(self, response: str) -> Dict[str, Any]: | |
""" | |
معالجة استجابة الملخص | |
""" | |
try: | |
# محاولة استخراج JSON من الاستجابة | |
json_pattern = r'```json(.*?)```' | |
json_match = re.search(json_pattern, response, re.DOTALL) | |
if json_match: | |
json_str = json_match.group(1) | |
return json.loads(json_str) | |
# محاولة تحميل الاستجابة الكاملة كـ JSON | |
return json.loads(response) | |
except Exception as e: | |
print(f"Error parsing summary response: {str(e)}") | |
# إذا فشل تحليل JSON، إرجاع النص كملخص | |
return { | |
"executive_summary": response, | |
"error": str(e) | |
} | |
class ArabicBERTModel: | |
""" | |
فئة للتعامل مع نموذج BERT العربي المخصص لتحليل المناقصات | |
""" | |
def __init__(self, model_path: str = "arabic-bert-base"): | |
""" | |
تهيئة نموذج BERT العربي | |
المعاملات: | |
---------- | |
model_path : str, optional | |
مسار نموذج BERT العربي (افتراضي: "arabic-bert-base") | |
""" | |
self.model_path = model_path | |
# تحميل النموذج | |
# في التطبيق الفعلي، يتم تحميل النموذج باستخدام مكتبة transformers | |
# self.tokenizer = AutoTokenizer.from_pretrained(model_path) | |
# self.model = AutoModel.from_pretrained(model_path) | |
# تمثيل مؤقت للنموذج | |
self.model_loaded = False | |
def extract_entities(self, text: str) -> Dict[str, List[Dict[str, Any]]]: | |
""" | |
استخراج الكيانات من النص | |
المعاملات: | |
---------- | |
text : str | |
النص المراد استخراج الكيانات منه | |
المخرجات: | |
-------- | |
Dict[str, List[Dict[str, Any]]] | |
الكيانات المستخرجة مصنفة حسب النوع | |
""" | |
# في التطبيق الفعلي، يتم استخدام النموذج لاستخراج الكيانات | |
# هذا تمثيل مؤقت للوظيفة | |
entities = { | |
"organizations": [], | |
"persons": [], | |
"locations": [], | |
"dates": [], | |
"money": [] | |
} | |
# استخراج المنظمات (مثال) | |
org_pattern = r'(شركة|مؤسسة|هيئة|وزارة)\s+([^\n.,]{3,50})' | |
org_matches = re.finditer(org_pattern, text) | |
for match in org_matches: | |
entity_text = match.group(0) | |
entities["organizations"].append({ | |
"text": entity_text, | |
"start": match.start(), | |
"end": match.end(), | |
"confidence": 0.85 | |
}) | |
# استخراج الأشخاص (مثال) | |
person_pattern = r'(المهندس|الدكتور|السيد)\s+([^\n.,]{3,50})' | |
person_matches = re.finditer(person_pattern, text) | |
for match in person_matches: | |
entity_text = match.group(0) | |
entities["persons"].append({ | |
"text": entity_text, | |
"start": match.start(), | |
"end": match.end(), | |
"confidence": 0.8 | |
}) | |
return entities | |
def classify_text(self, text: str, categories: List[str]) -> Dict[str, float]: | |
""" | |
تصنيف النص إلى فئات محددة | |
المعاملات: | |
---------- | |
text : str | |
النص المراد تصنيفه | |
categories : List[str] | |
قائمة الفئات المحتملة | |
المخرجات: | |
-------- | |
Dict[str, float] | |
درجات الثقة لكل فئة | |
""" | |
# في التطبيق الفعلي، يتم استخدام النموذج لتصنيف النص | |
# هذا تمثيل مؤقت للوظيفة | |
# توليد درجات ثقة عشوائية للفئات | |
import random | |
scores = {} | |
total_score = 0 | |
for category in categories: | |
score = random.random() | |
scores[category] = score | |
total_score += score | |
# تطبيع درجات الثقة | |
for category in scores: | |
scores[category] = round(scores[category] / total_score, 2) | |
return scores | |
def extract_keywords(self, text: str, top_n: int = 10) -> List[Dict[str, Any]]: | |
""" | |
استخراج الكلمات المفتاحية من النص | |
المعاملات: | |
---------- | |
text : str | |
النص المراد استخراج الكلمات المفتاحية منه | |
top_n : int, optional | |
عدد الكلمات المفتاحية المراد استخراجها (افتراضي: 10) | |
المخرجات: | |
-------- | |
List[Dict[str, Any]] | |
الكلمات المفتاحية مع درجات الأهمية | |
""" | |
# في التطبيق الفعلي، يتم استخدام النموذج لاستخراج الكلمات المفتاحية | |
# هذا تمثيل مؤقت للوظيفة | |
# قائمة بالكلمات المفتاحية المحتملة في مجال المناقصات | |
potential_keywords = [ | |
"مناقصة", "عقد", "توريد", "تنفيذ", "مشروع", "ميزانية", "مدة", "غرامة", | |
"جودة", "مواصفات", "شروط", "تسليم", "ضمان", "كفالة", "دفعات", "مستحقات", | |
"محتوى محلي", "توطين", "متطلبات", "مخاطر", "تكاليف", "سعر", "عمالة" | |
] | |
# اختيار كلمات مفتاحية عشوائية من النص | |
words = text.split() | |
selected_keywords = [] | |
for keyword in potential_keywords: | |
if keyword in words and len(selected_keywords) < top_n: | |
count = words.count(keyword) | |
selected_keywords.append({ | |
"keyword": keyword, | |
"count": count, | |
"importance": round(count / len(words) * 10, 2) | |
}) | |
# ترتيب الكلمات المفتاحية حسب الأهمية | |
selected_keywords = sorted(selected_keywords, key=lambda x: x["importance"], reverse=True) | |
return selected_keywords | |
class VectorDB: | |
""" | |
فئة للتعامل مع قاعدة بيانات المتجهات لدعم عمليات RAG | |
""" | |
def __init__(self, db_path: str = "vector_db"): | |
""" | |
تهيئة قاعدة بيانات المتجهات | |
المعاملات: | |
---------- | |
db_path : str, optional | |
مسار قاعدة بيانات المتجهات (افتراضي: "vector_db") | |
""" | |
self.db_path = db_path | |
# في التطبيق الفعلي، يتم تحميل أو إنشاء قاعدة بيانات المتجهات | |
# هذا تمثيل مؤقت للوظيفة | |
# قاعدة بيانات مؤقتة للأغراض التوضيحية | |
self.sample_db = [ | |
{ | |
"text": "تعتبر نسبة المحتوى المحلي من أهم العوامل في تقييم المناقصات، حيث يجب أن تكون 40% على الأقل للمشاريع الإنشائية و30% للمشاريع التقنية وفقاً لمتطلبات هيئة المحتوى المحلي والمشتريات الحكومية.", | |
"vector": np.random.rand(384) # تمثيل عشوائي للمتجه | |
}, | |
{ | |
"text": "يعد تحليل المخاطر في سلسلة الإمداد جزءاً أساسياً من تقييم المناقصات، خاصةً في ظل تقلبات الأسعار العالمية وتأثيرها على توفر المواد.", | |
"vector": np.random.rand(384) | |
}, | |
{ | |
"text": "من أفضل الممارسات في إدارة المناقصات تقسيم المتطلبات إلى فئات واضحة (فنية، إدارية، مالية) مع تحديد الأولويات والمعايير القابلة للقياس.", | |
"vector": np.random.rand(384) | |
}, | |
{ | |
"text": "وفقاً لنظام المنافسات والمشتريات الحكومية، يجب تضمين بند التوطين ونسبة المحتوى المحلي في جميع المناقصات الحكومية، مع منح أفضلية للعروض ذات النسب الأعلى.", | |
"vector": np.random.rand(384) | |
}, | |
{ | |
"text": "من التحديات الشائعة في تنفيذ المشاريع الإنشائية: تأخر توريد المواد، ونقص العمالة الماهرة، وتغيير نطاق العمل، والتأخير في اعتماد المخططات.", | |
"vector": np.random.rand(384) | |
} | |
] | |
def retrieve_similar_content(self, query: str, top_k: int = 3) -> List[str]: | |
""" | |
استرجاع المحتوى المشابه للاستعلام من قاعدة البيانات | |
المعاملات: | |
---------- | |
query : str | |
الاستعلام المراد البحث عن محتوى مشابه له | |
top_k : int, optional | |
عدد النتائج المراد استرجاعها (افتراضي: 3) | |
المخرجات: | |
-------- | |
List[str] | |
قائمة بالمحتوى المشابه للاستعلام | |
""" | |
# في التطبيق الفعلي، يتم تحويل الاستعلام إلى متجه والبحث في قاعدة البيانات | |
# هذا تمثيل مؤقت للوظيفة | |
# اختيار محتوى عشوائي من قاعدة البيانات | |
import random | |
# تحقق بسيط من وجود كلمات مشتركة بين الاستعلام والمحتوى | |
query_words = set(query.lower().split()) | |
matching_content = [] | |
for item in self.sample_db: | |
content_words = set(item["text"].lower().split()) | |
common_words = query_words.intersection(content_words) | |
if common_words: | |
matching_content.append(item["text"]) | |
# إذا لم يتم العثور على تطابق، إرجاع عناصر عشوائية | |
if not matching_content and self.sample_db: | |
return random.sample([item["text"] for item in self.sample_db], min(top_k, len(self.sample_db))) | |
# إرجاع أفضل النتائج (أو كل النتائج إذا كان عددها أقل من top_k) | |
return matching_content[:top_k] |