break if i not in seen_indices:

← العودة
Blog Post

عنوان المحادثة: break if i not in seen_indices: ...

التاريخ: 05.01.2026

التصنيف: 📊 البيانات وتحليل البيانات

إجمالي الرسائل: 7 | ياسر: 0 | M: 7

المحادثة الكاملة - 05.01.2026
M
break if i not in seen_indices: selected_cars.append(valid_cars[i]) seen_indices.add(i) selected_cars.sort(key=lambda x: x.get("_calculated_price", 0), reverse=True) valid_cars = selected_cars for car in valid_cars: self._cars_cache[car.get("id")] = car self._cars_cache[car.get("name", "").lower()] = car return valid_cars except Exception as e: print(f"Error fetching cars: {e}") return [] def find_car_by_name(self, name: str) -> Optional[Dict]: """البحث عن سيارة بالاسم""" name_lower = name.lower() for key, car in self._cars_cache.items(): if isinstance(key, str) and name_lower in key: return car if isinstance(car, dict): car_name = car.get("name", "").lower() if name_lower in car_name or car_name in name_lower: return car return None async def get_available_cars_context(self, budget_min: float = None, budget_max: float = None) -> str: """جلب السيارات المتاحة كـ context""" try: cars = await self.get_available_cars_with_images(budget_min, budget_max) if not cars: return "لا توجد سيارات متاحة حالياً في هذا النطاق السعري. جرب ميزانية أعلى." cars_text = f"السيارات المتاحة ({len(cars)} سيارة):\n" cars_text += "⚠️ هام: لا تكتب قائمة السيارات بنفسك! قل فقط 'إليك السيارات المتاحة' والنظام سيعرضها.\n\n" for i, car in enumerate(cars[:6], 1): name = car.get("name", "سيارة") price = car.get("_calculated_price") if price: price_formatted = f"{int(price):,}" else: price_formatted = "غير محدد" car_id = car.get("id") cars_text += f"{i}. {name} - {price_formatted} ريال (ID: {car_id})\n" return cars_text except Exception as e: return f"خطأ في جلب السيارات: {str(e)}" async def get_cities_context(self) -> str: """جلب المدن كـ context""" try: cities = await aldaman_client.get_cities() cities_text = "المدن المتاحة: " city_names = [c.get("name_ar") or c.get("name", "") for c in cities[:15]] cities_text += "، ".join(city_names) return cities_text except Exception: return "المدن: الرياض، جدة، الدمام، مكة، المدينة" async def chat( self, user_message: str, conversation_history: List[Dict[str, str]], collected_data: Dict[str, Any] ) -> Dict[str, Any]: """معالجة رسالة المستخدم عبر مرحلتين (توليد ثم تدقيق) مع إعادة محاولة ذكية.""" try: context_parts: List[str] = [] cars_data: List[Dict[str, Any]] = [] if collected_data: context_parts.append(f"البيانات المجمعة حتى الآن: {json.dumps(collected_data, ensure_ascii=False)}") user_wants_images = any(word in user_message.lower() for word in ["صور", "صورة", "وريني", "شوفني", "أشوف", "ابي اشوف"]) budget_min = None budget_max = None budget_data = collected_data.get("budget") if isinstance(budget_data, dict): budget_min = budget_data.get("min") budget_max = budget_data.get("max") elif isinstance(budget_data, (int, float)): budget_max = float(budget_data) if not budget_max: arabic_budget = collected_data.get("الميزانية", "") if arabic_budget: budget_max = self._extract_budget_from_text(str(arabic_budget)) if not budget_max: budget_max = self._extract_budget_from_text(user_message)
05.01.2026 17:02
M
selected_car_from_message = None if self._cars_cache and not collected_data.get("selected_car"): for key, car in self._cars_cache.items(): if isinstance(car, dict): car_name = car.get("name", "") if car_name and (car_name in user_message or user_message in car_name): selected_car_from_message = car break if budget_min or budget_max or user_wants_images or collected_data.get("selected_car"): cars_data = await self.get_available_cars_with_images( budget_min=budget_min, budget_max=budget_max ) cars_context = await self.get_available_cars_context( budget_min=budget_min, budget_max=budget_max ) context_parts.append(cars_context) if collected_data.get("selected_car") and not collected_data.get("city"): cities_context = await self.get_cities_context() context_parts.append(cities_context) retry_notes = None last_candidate = None def build_primary_messages(attempt: int, notes: Optional[str]) -> List[Dict[str, str]]: messages: List[Dict[str, str]] = [{"role": "system", "content": SYSTEM_PROMPT}] if notes: messages.append({"role": "system", "content": f"ملاحظات إعادة المحاولة #{attempt}: {notes}"}) if last_candidate and notes: messages.append({"role": "system", "content": f"الرد السابق لم يكن كافياً: {last_candidate.get('message', '')}"}) if context_parts: messages.append({"role": "system", "content": "معلومات إضافية:\n" + "\n".join(context_parts)}) messages.extend(conversation_history[-10:]) messages.append({"role": "user", "content": user_message}) return messages for attempt in range(1, MAX_RECURSIVE_ATTEMPTS + 1): messages = build_primary_messages(attempt, retry_notes) primary_raw = await self._call_json_chat(messages) candidate = self._build_candidate_payload( result=primary_raw, user_wants_images=user_wants_images, cars_data=cars_data, selected_car_from_message=selected_car_from_message ) last_candidate = candidate try: validation = await self._validate_candidate_response( user_message=user_message, collected_data=collected_data, candidate_response=candidate, attempt_index=attempt, retry_notes=retry_notes ) except Exception as val_err: validation = {"decision": "pass", "reason": f"تخطي التدقيق بسبب: {val_err}"} improved_message = validation.get("improved_message") if improved_message: candidate["message"] = improved_message if validation.get("decision", "pass") == "pass": candidate["success"] = True return candidate retry_notes = validation.get("retry_instructions") or validation.get("reason") or "الرد غير كافٍ." fallback_message = (last_candidate or {}).get("message") or "عذراً، لم أتمكن من الوصول لرد نهائي بالبيانات المتاحة." if retry_notes: fallback_message += f"\n\n(ملاحظة: {retry_notes}. لن أختلق بيانات.)"
05.01.2026 17:02
M
break if i not in seen_indices: selected_cars.append(valid_cars[i]) seen_indices.add(i) selected_cars.sort(key=lambda x: x.get("_calculated_price", 0), reverse=True) valid_cars = selected_cars for car in valid_cars: self._cars_cache[car.get("id")] = car self._cars_cache[car.get("name", "").lower()] = car return valid_cars except Exception as e: print(f"Error fetching cars: {e}") return [] def find_car_by_name(self, name: str) -> Optional[Dict]: """البحث عن سيارة بالاسم""" name_lower = name.lower() for key, car in self._cars_cache.items(): if isinstance(key, str) and name_lower in key: return car if isinstance(car, dict): car_name = car.get("name", "").lower() if name_lower in car_name or car_name in name_lower: return car return None async def get_available_cars_context(self, budget_min: float = None, budget_max: float = None) -> str: """جلب السيارات المتاحة كـ context""" try: cars = await self.get_available_cars_with_images(budget_min, budget_max) if not cars: return "لا توجد سيارات متاحة حالياً في هذا النطاق السعري. جرب ميزانية أعلى." cars_text = f"السيارات المتاحة ({len(cars)} سيارة):\n" cars_text += "⚠️ هام: لا تكتب قائمة السيارات بنفسك! قل فقط 'إليك السيارات المتاحة' والنظام سيعرضها.\n\n" for i, car in enumerate(cars[:6], 1): name = car.get("name", "سيارة") price = car.get("_calculated_price") if price: price_formatted = f"{int(price):,}" else: price_formatted = "غير محدد" car_id = car.get("id") cars_text += f"{i}. {name} - {price_formatted} ريال (ID: {car_id})\n" return cars_text except Exception as e: return f"خطأ في جلب السيارات: {str(e)}" async def get_cities_context(self) -> str: """جلب المدن كـ context""" try: cities = await aldaman_client.get_cities() cities_text = "المدن المتاحة: " city_names = [c.get("name_ar") or c.get("name", "") for c in cities[:15]] cities_text += "، ".join(city_names) return cities_text except Exception: return "المدن: الرياض، جدة، الدمام، مكة، المدينة" async def chat( self, user_message: str, conversation_history: List[Dict[str, str]], collected_data: Dict[str, Any] ) -> Dict[str, Any]: """معالجة رسالة المستخدم عبر مرحلتين (توليد ثم تدقيق) مع إعادة محاولة ذكية.""" try: context_parts: List[str] = [] cars_data: List[Dict[str, Any]] = [] if collected_data: context_parts.append(f"البيانات المجمعة حتى الآن: {json.dumps(collected_data, ensure_ascii=False)}") user_wants_images = any(word in user_message.lower() for word in ["صور", "صورة", "وريني", "شوفني", "أشوف", "ابي اشوف"]) budget_min = None budget_max = None budget_data = collected_data.get("budget") if isinstance(budget_data, dict): budget_min = budget_data.get("min") budget_max = budget_data.get("max") elif isinstance(budget_data, (int, float)): budget_max = float(budget_data) if not budget_max: arabic_budget = collected_data.get("الميزانية", "") if arabic_budget: budget_max = self._extract_budget_from_text(str(arabic_budget)) if not budget_max: budget_max = self._extract_budget_from_text(user_message)
05.01.2026 17:02
M
selected_car_from_message = None if self._cars_cache and not collected_data.get("selected_car"): for key, car in self._cars_cache.items(): if isinstance(car, dict): car_name = car.get("name", "") if car_name and (car_name in user_message or user_message in car_name): selected_car_from_message = car break if budget_min or budget_max or user_wants_images or collected_data.get("selected_car"): cars_data = await self.get_available_cars_with_images( budget_min=budget_min, budget_max=budget_max ) cars_context = await self.get_available_cars_context( budget_min=budget_min, budget_max=budget_max ) context_parts.append(cars_context) if collected_data.get("selected_car") and not collected_data.get("city"): cities_context = await self.get_cities_context() context_parts.append(cities_context) retry_notes = None last_candidate = None def build_primary_messages(attempt: int, notes: Optional[str]) -> List[Dict[str, str]]: messages: List[Dict[str, str]] = [{"role": "system", "content": SYSTEM_PROMPT}] if notes: messages.append({"role": "system", "content": f"ملاحظات إعادة المحاولة #{attempt}: {notes}"}) if last_candidate and notes: messages.append({"role": "system", "content": f"الرد السابق لم يكن كافياً: {last_candidate.get('message', '')}"}) if context_parts: messages.append({"role": "system", "content": "معلومات إضافية:\n" + "\n".join(context_parts)}) messages.extend(conversation_history[-10:]) messages.append({"role": "user", "content": user_message}) return messages for attempt in range(1, MAX_RECURSIVE_ATTEMPTS + 1): messages = build_primary_messages(attempt, retry_notes) primary_raw = await self._call_json_chat(messages) candidate = self._build_candidate_payload( result=primary_raw, user_wants_images=user_wants_images, cars_data=cars_data, selected_car_from_message=selected_car_from_message ) last_candidate = candidate try: validation = await self._validate_candidate_response( user_message=user_message, collected_data=collected_data, candidate_response=candidate, attempt_index=attempt, retry_notes=retry_notes ) except Exception as val_err: validation = {"decision": "pass", "reason": f"تخطي التدقيق بسبب: {val_err}"} improved_message = validation.get("improved_message") if improved_message: candidate["message"] = improved_message if validation.get("decision", "pass") == "pass": candidate["success"] = True return candidate retry_notes = validation.get("retry_instructions") or validation.get("reason") or "الرد غير كافٍ." fallback_message = (last_candidate or {}).get("message") or "عذراً، لم أتمكن من الوصول لرد نهائي بالبيانات المتاحة." if retry_notes: fallback_message += f"\n\n(ملاحظة: {retry_notes}. لن أختلق بيانات.)"
05.01.2026 17:02
M
break if i not in seen_indices: selected_cars.append(valid_cars[i]) seen_indices.add(i) selected_cars.sort(key=lambda x: x.get("_calculated_price", 0), reverse=True) valid_cars = selected_cars for car in valid_cars: self._cars_cache[car.get("id")] = car self._cars_cache[car.get("name", "").lower()] = car return valid_cars except Exception as e: print(f"Error fetching cars: {e}") return [] def find_car_by_name(self, name: str) -> Optional[Dict]: """البحث عن سيارة بالاسم""" name_lower = name.lower() for key, car in self._cars_cache.items(): if isinstance(key, str) and name_lower in key: return car if isinstance(car, dict): car_name = car.get("name", "").lower() if name_lower in car_name or car_name in name_lower: return car return None async def get_available_cars_context(self, budget_min: float = None, budget_max: float = None) -> str: """جلب السيارات المتاحة كـ context""" try: cars = await self.get_available_cars_with_images(budget_min, budget_max) if not cars: return "لا توجد سيارات متاحة حالياً في هذا النطاق السعري. جرب ميزانية أعلى." cars_text = f"السيارات المتاحة ({len(cars)} سيارة):\n" cars_text += "⚠️ هام: لا تكتب قائمة السيارات بنفسك! قل فقط 'إليك السيارات المتاحة' والنظام سيعرضها.\n\n" for i, car in enumerate(cars[:6], 1): name = car.get("name", "سيارة") price = car.get("_calculated_price") if price: price_formatted = f"{int(price):,}" else: price_formatted = "غير محدد" car_id = car.get("id") cars_text += f"{i}. {name} - {price_formatted} ريال (ID: {car_id})\n" return cars_text except Exception as e: return f"خطأ في جلب السيارات: {str(e)}" async def get_cities_context(self) -> str: """جلب المدن كـ context""" try: cities = await aldaman_client.get_cities() cities_text = "المدن المتاحة: " city_names = [c.get("name_ar") or c.get("name", "") for c in cities[:15]] cities_text += "، ".join(city_names) return cities_text except Exception: return "المدن: الرياض، جدة، الدمام، مكة، المدينة" async def chat( self, user_message: str, conversation_history: List[Dict[str, str]], collected_data: Dict[str, Any] ) -> Dict[str, Any]: """معالجة رسالة المستخدم عبر مرحلتين (توليد ثم تدقيق) مع إعادة محاولة ذكية.""" try: context_parts: List[str] = [] cars_data: List[Dict[str, Any]] = [] if collected_data: context_parts.append(f"البيانات المجمعة حتى الآن: {json.dumps(collected_data, ensure_ascii=False)}") user_wants_images = any(word in user_message.lower() for word in ["صور", "صورة", "وريني", "شوفني", "أشوف", "ابي اشوف"]) budget_min = None budget_max = None budget_data = collected_data.get("budget") if isinstance(budget_data, dict): budget_min = budget_data.get("min") budget_max = budget_data.get("max") elif isinstance(budget_data, (int, float)): budget_max = float(budget_data) if not budget_max: arabic_budget = collected_data.get("الميزانية", "") if arabic_budget: budget_max = self._extract_budget_from_text(str(arabic_budget)) if not budget_max: budget_max = self._extract_budget_from_text(user_message)
05.01.2026 17:02
M
selected_car_from_message = None if self._cars_cache and not collected_data.get("selected_car"): for key, car in self._cars_cache.items(): if isinstance(car, dict): car_name = car.get("name", "") if car_name and (car_name in user_message or user_message in car_name): selected_car_from_message = car break if budget_min or budget_max or user_wants_images or collected_data.get("selected_car"): cars_data = await self.get_available_cars_with_images( budget_min=budget_min, budget_max=budget_max ) cars_context = await self.get_available_cars_context( budget_min=budget_min, budget_max=budget_max ) context_parts.append(cars_context) if collected_data.get("selected_car") and not collected_data.get("city"): cities_context = await self.get_cities_context() context_parts.append(cities_context) retry_notes = None last_candidate = None def build_primary_messages(attempt: int, notes: Optional[str]) -> List[Dict[str, str]]: messages: List[Dict[str, str]] = [{"role": "system", "content": SYSTEM_PROMPT}] if notes: messages.append({"role": "system", "content": f"ملاحظات إعادة المحاولة #{attempt}: {notes}"}) if last_candidate and notes: messages.append({"role": "system", "content": f"الرد السابق لم يكن كافياً: {last_candidate.get('message', '')}"}) if context_parts: messages.append({"role": "system", "content": "معلومات إضافية:\n" + "\n".join(context_parts)}) messages.extend(conversation_history[-10:]) messages.append({"role": "user", "content": user_message}) return messages for attempt in range(1, MAX_RECURSIVE_ATTEMPTS + 1): messages = build_primary_messages(attempt, retry_notes) primary_raw = await self._call_json_chat(messages) candidate = self._build_candidate_payload( result=primary_raw, user_wants_images=user_wants_images, cars_data=cars_data, selected_car_from_message=selected_car_from_message ) last_candidate = candidate try: validation = await self._validate_candidate_response( user_message=user_message, collected_data=collected_data, candidate_response=candidate, attempt_index=attempt, retry_notes=retry_notes ) except Exception as val_err: validation = {"decision": "pass", "reason": f"تخطي التدقيق بسبب: {val_err}"} improved_message = validation.get("improved_message") if improved_message: candidate["message"] = improved_message if validation.get("decision", "pass") == "pass": candidate["success"] = True return candidate retry_notes = validation.get("retry_instructions") or validation.get("reason") or "الرد غير كافٍ." fallback_message = (last_candidate or {}).get("message") or "عذراً، لم أتمكن من الوصول لرد نهائي بالبيانات المتاحة." if retry_notes: fallback_message += f"\n\n(ملاحظة: {retry_notes}. لن أختلق بيانات.)"
05.01.2026 17:02
M
- النظام يعمل على مرحلتين: (1) توليد رد مبدئي يقرر بين رسالة ودية أو إجراء وظيفي (show_cars، options، collected_field...). (2) تمرير الرد لمدقق مستقل يتأكد من الوضوح، جمع الحقول، وعدم اختلاق معلومات؛ يعيد pass أو retry مع تعليمات تحسين. راجع المنطق في ai_chat.py. - في حال retry يُعاد التوليد مع ملاحظات المدقق وأي محاولات سابقة، بحد أقصى 3 محاولات. إذا فشلت كلها، نرسل أفضل رد متاح بدون اختلاق بيانات. - تنسيق الخرج دائماً JSON: message، collected_field/value، next_step، is_complete، show_cars، options. لا تترك options فارغة عند الأسئلة عن اللون/المدينة/البنك/المصدر، بل وفّر أزرار جاهزة كما في الإرشادات. - لا اختلاق سيارات أو أسعار؛ استخدم السيارات المتاحة فقط. عند الميزانية فعّل show_cars؛ عند اختيار سيارة اسأل عن اللون؛ عند الإنهاء ضع is_complete: true وشكر ودود. - المدقق مهيأ بنص عربي واضح لضمان الودّ وعدم تكرار الأسئلة، مع تصحيح النص في ai_chat.py.
05.01.2026 17:06
← العودة إلى الرئيسية