# import gradio as gr # import requests # from datetime import datetime # # URL webhook شما # WEBHOOK_URL = "http://130.185.121.155:5678/webhook/voice-agent" # # ذخیره session_id برای هر کاربر # session_data = {} # def send_message(phone_number, message, history): # """ # ارسال پیام به webhook و دریافت پاسخ # """ # if not phone_number: # history = history or [] # history.append({"role": "assistant", "content": "⚠️ لطفاً ابتدا شماره تلفن خود را وارد کنید!"}) # return history, "" # if not message: # return history, "" # history = history or [] # # اضافه کردن پیام کاربر به تاریخچه # history.append({"role": "user", "content": message}) # # ساخت یا بازیابی session_id # if phone_number not in session_data: # session_data[phone_number] = f"session_{phone_number}_{datetime.now().strftime('%Y%m%d%H%M%S')}" # session_id = session_data[phone_number] # # داده‌های ارسالی # payload = { # "user_message": message, # "context": { # "caller_phone": phone_number, # "session_id": session_id # } # } # headers = { # "Content-Type": "application/json" # } # try: # # ارسال درخواست # response = requests.post(WEBHOOK_URL, json=payload, headers=headers, timeout=30) # if response.status_code == 200: # result = response.json() # bot_response = result.get("response", "پاسخی دریافت نشد") # # اضافه کردن پاسخ ربات به تاریخچه # history.append({"role": "assistant", "content": bot_response}) # # نمایش اطلاعات اضافی اگر موجود باشد # if result.get("order_complete"): # history.append({"role": "assistant", "content": "✅ سفارش شما کامل شد!"}) # return history, "" # else: # history.append({"role": "assistant", "content": f"❌ خطا: {response.status_code}"}) # return history, "" # except requests.exceptions.Timeout: # history.append({"role": "assistant", "content": "⏱️ زمان انتظار تمام شد. لطفاً دوباره تلاش کنید."}) # return history, "" # except requests.exceptions.RequestException as e: # history.append({"role": "assistant", "content": f"❌ خطای اتصال: {str(e)}"}) # return history, "" # def clear_chat(phone_number): # """ # پاک کردن تاریخچه چت # """ # if phone_number in session_data: # del session_data[phone_number] # return None # # رابط Gradio - بدون هیچ پارامتر اضافی # with gr.Blocks() as demo: # gr.Markdown("# 🤖 دستیار هوشمند سفارش") # gr.Markdown("به ربات سفارش‌گیری خوش آمدید! لطفاً شماره تلفن خود را وارد کرده و شروع به چت کنید.") # phone_input = gr.Textbox(label="📱 شماره تلفن", placeholder="مثال: 09123456789") # chatbot = gr.Chatbot(label="گفتگو") # msg_input = gr.Textbox(label="پیام شما", placeholder="پیام خود را بنویسید...") # with gr.Row(): # send_btn = gr.Button("📤 ارسال") # clear_btn = gr.Button("🗑️ پاک کردن چت") # gr.Markdown(""" # ### 💡 نکات: # - ابتدا شماره تلفن خود را وارد کنید # - سفارش خود را به صورت کامل بیان کنید # ### 📋 مثال‌های سفارش: # - "سلام، یک چیزبرگر دوبل و یک نوشابه می‌خوام" # - "آدرسم: تهران، خیابان ولیعصر، پلاک 123" # - "اسمم ادوین هست" # """) # # اتصال رویدادها # send_btn.click( # fn=send_message, # inputs=[phone_input, msg_input, chatbot], # outputs=[chatbot, msg_input] # ) # msg_input.submit( # fn=send_message, # inputs=[phone_input, msg_input, chatbot], # outputs=[chatbot, msg_input] # ) # clear_btn.click( # fn=clear_chat, # inputs=[phone_input], # outputs=[chatbot] # ) # # اجرای برنامه # if __name__ == "__main__": # demo.launch( # server_name="0.0.0.0", # server_port=7860, # share=False # ) """ 🏥 Pharmacy RAG System - Interactive Chat Support Version تعاملی - سوال‌محور - مشاوره‌ای """ import os import json import re from typing import List, Dict, Any, Optional import pandas as pd import numpy as np from dataclasses import dataclass import networkx as nx from collections import defaultdict # Vector DB from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct # OpenRouter import requests # UI import gradio as gr # ============================================================================ # CONFIGURATION # ============================================================================ OPENROUTER_API_KEY = "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" QDRANT_URL = "http://130.185.121.155:6333" COLLECTION_NAME = "pharmacy_products" LLM_MODEL = "openai/gpt-4o-mini" EMBEDDING_MODEL = "openai/text-embedding-3-small" # ============================================================================ # DATA MODELS # ============================================================================ @dataclass class Product: """مدل محصول""" category: str problem_title: str symptoms: str treatment_info: str urls: List[str] product_names: List[str] @dataclass class QueryIntent: """مدل intent شناسایی شده""" intent_type: str extracted_symptoms: List[str] extracted_products: List[str] missing_info: List[str] requires_graph: bool confidence: float # ============================================================================ # OPENROUTER CLIENT # ============================================================================ class OpenRouterClient: """کلاینت OpenRouter برای LLM و Embedding""" def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://openrouter.ai/api/v1" self.headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } def get_embedding(self, text: str) -> List[float]: """دریافت embedding از OpenRouter""" url = f"{self.base_url}/embeddings" payload = { "model": EMBEDDING_MODEL, "input": text } try: response = requests.post(url, headers=self.headers, json=payload, timeout=30) response.raise_for_status() result = response.json() return result['data'][0]['embedding'] except Exception as e: print(f"❌ Embedding Error: {e}") return [0.0] * 1536 def generate(self, messages: List[Dict], temperature: float = 0.7, max_tokens: int = 800) -> str: """تولید متن با LLM - محدودیت طول برای پاسخ‌های کوتاه‌تر""" url = f"{self.base_url}/chat/completions" payload = { "model": LLM_MODEL, "messages": messages, "temperature": temperature, "max_tokens": max_tokens } try: response = requests.post(url, headers=self.headers, json=payload, timeout=60) response.raise_for_status() result = response.json() return result['choices'][0]['message']['content'] except Exception as e: print(f"❌ LLM Error: {e}") return f"خطا در ارتباط با مدل: {str(e)}" # ============================================================================ # VECTOR DATABASE (QDRANT) # ============================================================================ class VectorDB: """مدیریت Qdrant Vector Database""" def __init__(self, url: str, collection_name: str): self.client = QdrantClient(url=url, timeout=60) self.collection_name = collection_name self.fallback_mode = False self.fallback_vectors = [] self.fallback_metadata = [] def create_collection(self, vector_size: int = 1536): """ساخت collection""" try: collections = self.client.get_collections().collections if any(c.name == self.collection_name for c in collections): print(f"✅ Collection '{self.collection_name}' already exists") return self.client.create_collection( collection_name=self.collection_name, vectors_config=VectorParams(size=vector_size, distance=Distance.COSINE) ) print(f"✅ Created collection: {self.collection_name}") except Exception as e: print(f"❌ Error creating collection: {e}") def upsert_points(self, points: List[PointStruct]): """اضافه کردن points به collection""" try: batch_size = 5 total = len(points) failed_batches = 0 for i in range(0, total, batch_size): batch = points[i:i+batch_size] print(f" Uploading batch {i//batch_size + 1}/{(total + batch_size - 1)//batch_size}...") max_retries = 3 batch_failed = True for attempt in range(max_retries): try: self.client.upsert( collection_name=self.collection_name, points=batch, wait=True ) batch_failed = False break except Exception as e: if attempt == max_retries - 1: print(f" ⚠️ Failed batch {i//batch_size + 1}: {e}") failed_batches += 1 for point in batch: self.fallback_vectors.append(point.vector) self.fallback_metadata.append(point.payload) else: print(f" ⚠️ Retry {attempt + 1}/{max_retries}...") import time time.sleep(2) if failed_batches > 0: print(f"⚠️ {failed_batches} batches failed - using in-memory fallback") self.fallback_mode = True print(f"✅ Upserted {len(points)} points (with batching)") except Exception as e: print(f"❌ Error upserting points: {e}") self.fallback_mode = True for point in points: self.fallback_vectors.append(point.vector) self.fallback_metadata.append(point.payload) print(f"⚠️ Switched to in-memory fallback mode") def search(self, query_vector: List[float], limit: int = 5) -> List[Dict]: """جستجوی vector""" if self.fallback_mode and self.fallback_vectors: return self._search_fallback(query_vector, limit) try: from qdrant_client.models import SearchRequest results = self.client.query_points( collection_name=self.collection_name, query=query_vector, limit=limit ) return [ { "id": hit.id, "score": hit.score, "payload": hit.payload } for hit in results.points ] except Exception as e: print(f"❌ Search error: {e}") if self.fallback_vectors: print(f" Using in-memory fallback...") return self._search_fallback(query_vector, limit) return [] def _search_fallback(self, query_vector: List[float], limit: int = 5) -> List[Dict]: """جستجوی fallback با محاسبه cosine similarity""" import numpy as np query_vec = np.array(query_vector) results = [] for i, vec in enumerate(self.fallback_vectors): vec_arr = np.array(vec) similarity = np.dot(query_vec, vec_arr) / (np.linalg.norm(query_vec) * np.linalg.norm(vec_arr)) results.append({ "id": i, "score": float(similarity), "payload": self.fallback_metadata[i] }) results.sort(key=lambda x: x["score"], reverse=True) return results[:limit] # ============================================================================ # KNOWLEDGE GRAPH (NetworkX) # ============================================================================ class KnowledgeGraph: """گراف دانش برای روابط بین مشکلات، اکتیوها و محصولات""" def __init__(self): self.graph = nx.DiGraph() def add_node(self, node_id: str, node_type: str, attributes: Dict): """اضافه کردن node""" self.graph.add_node(node_id, type=node_type, **attributes) def add_edge(self, source: str, target: str, relation: str): """اضافه کردن edge""" self.graph.add_edge(source, target, relation=relation) def find_path(self, start: str, end: str) -> List[str]: """پیدا کردن مسیر بین دو node""" try: return nx.shortest_path(self.graph, start, end) except: return [] def get_neighbors(self, node: str, relation: str = None) -> List[str]: """دریافت همسایگان یک node""" if node not in self.graph: return [] neighbors = [] for _, target, data in self.graph.out_edges(node, data=True): if relation is None or data.get('relation') == relation: neighbors.append(target) return neighbors def multi_hop_query(self, start_nodes: List[str], max_hops: int = 3) -> Dict: """پرس‌وجوی چند مرحله‌ای""" result = defaultdict(list) visited = set() def dfs(node, depth): if depth > max_hops or node in visited: return visited.add(node) node_data = self.graph.nodes.get(node, {}) result[depth].append({ "node": node, "type": node_data.get("type"), "data": node_data }) for neighbor in self.graph.neighbors(node): dfs(neighbor, depth + 1) for start in start_nodes: dfs(start, 0) return dict(result) # ============================================================================ # QUERY UNDERSTANDING AGENT (تغییر اساسی اینجا) # ============================================================================ class QueryUnderstandingAgent: """Agent درک query کاربر - نسخه تعاملی""" def __init__(self, llm: OpenRouterClient): self.llm = llm def analyze_query(self, query: str, conversation_history: List[Dict] = None) -> QueryIntent: """تحلیل query و تشخیص نیاز به اطلاعات بیشتر""" history_context = "" if conversation_history and len(conversation_history) > 1: recent_msgs = conversation_history[-6:] # 6 پیام آخر history_context = "\n\nتاریخچه مکالمه:\n" + "\n".join([ f"{msg['role']}: {msg['content'][:150]}" for msg in recent_msgs ]) prompt = f"""تو یک متخصص تحلیل گفتگوهای مشاوره داروخانه هستی. پیام جدید کاربر: "{query}" {history_context} **وظیفه تو**: تشخیص بده که آیا اطلاعات کافی برای پیشنهاد محصول داریم یا نه. اطلاعات لازم برای پیشنهاد محصول: 1. نوع مشکل (جوش، لک، چربی زیاد، خشکی و...) 2. نوع پوست (چرب، خشک، مختلط، حساس) 3. شدت مشکل (خفیف، متوسط، شدید) 4. محدودیت بودجه (اقتصادی یا نامحدود) خروجی JSON: {{ "intent_type": "needs_clarification" یا "ready_to_recommend", "extracted_symptoms": ["علائم ذکر شده"], "extracted_products": ["محصولات خاص ذکر شده"], "skin_type_mentioned": true/false, "severity_mentioned": true/false, "budget_mentioned": true/false, "missing_info": ["چه اطلاعاتی کم است"], "requires_graph": false, "confidence": 0.0-1.0 }} فقط JSON برگردان، بدون توضیح.""" messages = [{"role": "user", "content": prompt}] response = self.llm.generate(messages, temperature=0.2, max_tokens=400) try: clean_response = response.strip() if "```json" in clean_response: clean_response = clean_response.split("```json")[1].split("```")[0] elif "```" in clean_response: clean_response = clean_response.split("```")[1].split("```")[0] intent_data = json.loads(clean_response.strip()) return QueryIntent( intent_type=intent_data.get("intent_type", "needs_clarification"), extracted_symptoms=intent_data.get("extracted_symptoms", []), extracted_products=intent_data.get("extracted_products", []), missing_info=intent_data.get("missing_info", []), requires_graph=intent_data.get("requires_graph", False), confidence=intent_data.get("confidence", 0.5) ) except Exception as e: print(f"⚠️ Intent parsing error: {e}") return QueryIntent( intent_type="needs_clarification", extracted_symptoms=[], extracted_products=[], missing_info=["نوع پوست", "شدت مشکل"], requires_graph=False, confidence=0.3 ) # ============================================================================ # RETRIEVAL AGENT # ============================================================================ class RetrievalAgent: """Agent بازیابی اطلاعات""" def __init__(self, vector_db: VectorDB, knowledge_graph: KnowledgeGraph, llm: OpenRouterClient): self.vector_db = vector_db self.kg = knowledge_graph self.llm = llm def retrieve(self, query: str, intent: QueryIntent, top_k: int = 3) -> List[Dict]: """بازیابی اطلاعات - فقط top 3 برای پاسخ کوتاه‌تر""" query_vector = self.llm.get_embedding(query) vector_results = self.vector_db.search(query_vector, limit=top_k) if intent.requires_graph and intent.extracted_symptoms: graph_results = self._graph_search(intent.extracted_symptoms) return self._merge_results(vector_results, graph_results) return vector_results def _graph_search(self, symptoms: List[str]) -> List[Dict]: """جستجو در graph""" results = [] for symptom in symptoms: symptom_clean = symptom.lower().strip() related = self.kg.multi_hop_query([symptom_clean], max_hops=2) results.append({"symptom": symptom, "graph_data": related}) return results def _merge_results(self, vector_results: List[Dict], graph_results: List[Dict]) -> List[Dict]: """ترکیب نتایج vector و graph""" merged = vector_results.copy() merged.extend([{"source": "graph", "data": gr} for gr in graph_results]) return merged # ============================================================================ # GRADING AGENT # ============================================================================ class GradingAgent: """Agent ارزیابی کیفیت نتایج""" def __init__(self, llm: OpenRouterClient): self.llm = llm def grade_relevance(self, query: str, retrieved_docs: List[Dict]) -> List[Dict]: """نمره‌دهی به مرتبط بودن documents""" graded_docs = [] for doc in retrieved_docs: score = self._score_document(query, doc) graded_docs.append({ **doc, "relevance_score": score }) graded_docs.sort(key=lambda x: x["relevance_score"], reverse=True) return graded_docs def _score_document(self, query: str, doc: Dict) -> float: """محاسبه نمره relevance""" if "score" in doc: return doc["score"] try: doc_text = str(doc.get("payload", doc))[:500] prompt = f"""این document چقدر به سوال کاربر مرتبط است؟ سوال: {query} Document: {doc_text} فقط یک عدد بین 0.0 تا 1.0 برگردان (مثلا 0.85)""" messages = [{"role": "user", "content": prompt}] response = self.llm.generate(messages, temperature=0.1, max_tokens=10) score = float(re.findall(r'0\.\d+|1\.0', response)[0]) return score except: return 0.5 # ============================================================================ # GENERATION AGENT (تغییر اساسی اینجا) # ============================================================================ class GenerationAgent: """Agent تولید پاسخ - نسخه تعاملی و پرسشگر""" def __init__(self, llm: OpenRouterClient): self.llm = llm def generate_clarification(self, query: str, intent: QueryIntent, conversation_history: List[Dict] = None) -> str: """تولید سوالات برای جمع‌آوری اطلاعات بیشتر""" history_context = "" if conversation_history and len(conversation_history) > 1: history_context = "\n\nمکالمه قبلی:\n" + "\n".join([ f"{msg['role']}: {msg['content'][:100]}" for msg in conversation_history[-4:] ]) missing_info_str = ", ".join(intent.missing_info) if intent.missing_info else "اطلاعات تکمیلی" prompt = f"""تو یک مشاور داروخانه دوستانه و حرفه‌ای هستی که می‌خواهی بهترین محصول رو به مشتری پیشنهاد بدی. پیام مشتری: "{query}" {history_context} اطلاعات ناقص: {missing_info_str} **وظیفه تو**: - یک سوال کوتاه و دوستانه بپرس تا اطلاعات لازم رو جمع کنی - فقط یک سوال در هر پیام (نه لیست سوالات!) - خیلی گرم و صمیمی باش - اگر مشتری قبلا چیزی گفته، بهش اشاره کن مثال‌های خوب: "باشه! یه سوال، پوست شما چرب هست یا خشک؟ 😊" "عالیه! چقدر شدیده این جوش‌ها؟ یعنی زیاده یا فقط گاهی پیش میاد؟" "متوجه شدم! به بودجه محدودیتی دارید یا می‌تونید کمی بیشتر خرج کنید؟" پاسخ کوتاه و دوستانه:""" messages = [{"role": "user", "content": prompt}] response = self.llm.generate(messages, temperature=0.8, max_tokens=150) return response.strip() def generate_recommendation(self, query: str, context_docs: List[Dict], conversation_history: List[Dict] = None) -> str: """تولید پیشنهاد نهایی - کوتاه و مختصر""" context = self._prepare_context(context_docs) history_context = "" if conversation_history and len(conversation_history) > 1: history_context = "\n\nخلاصه مکالمه:\n" + "\n".join([ f"{msg['role']}: {msg['content'][:80]}" for msg in conversation_history[-4:] ]) prompt = f"""تو یک مشاور داروخانه حرفه‌ای هستی. الان وقت پیشنهاد نهایی است! {history_context} سوال نهایی: {query} محصولات موجود: {context} **قوانین مهم**: 1. فقط 1-2 محصول پیشنهاد بده (نه همه!) 2. توضیح خیلی کوتاه بده (2-3 جمله) 3. لینک محصول رو حتما بذار 4. اگر 2 تا پیشنهاد داری، تفاوتشون رو خیلی کوتاه بگو 5. در آخر بپرس: "سوال دیگه‌ای دارید؟" یا "می‌خواید درباره نحوه استفاده بدونید؟" مثال پاسخ خوب: "برای جوش‌های سرسیاه، سرم مارگریت رو پیشنهاد می‌کنم - خیلی قوی و تخصصیه: 🔗 [لینک محصول] اگه بودجه محدودتره، ژل سبوما آردن هم عالیه و ارزون‌تره: 🔗 [لینک محصول] سوال دیگه‌ای دارید؟ 😊" پاسخ (کوتاه و مفید):""" messages = [{"role": "user", "content": prompt}] answer = self.llm.generate(messages, temperature=0.7, max_tokens=400) return answer.strip() def _prepare_context(self, docs: List[Dict]) -> str: """آماده‌سازی context از documents - خلاصه‌تر""" context_parts = [] for i, doc in enumerate(docs[:3], 1): # فقط 3 تای اول payload = doc.get("payload", {}) products_str = ", ".join(payload.get('products', ['نامشخص'])[:2]) # فقط 2 محصول اول url = payload.get('url', payload.get('urls', [''])[0] if payload.get('urls') else '') text = f"""محصول {i}: {products_str} مشکل: {payload.get('problem', 'نامشخص')} لینک: {url} """ context_parts.append(text) return "\n".join(context_parts) # ============================================================================ # MAIN RAG SYSTEM (تغییر در query method) # ============================================================================ class PharmacyRAGSystem: """سیستم RAG کامل داروخانه - نسخه تعاملی""" def __init__(self): print("🚀 Initializing Interactive Pharmacy RAG System...") self.llm = OpenRouterClient(OPENROUTER_API_KEY) self.vector_db = VectorDB(QDRANT_URL, COLLECTION_NAME) self.kg = KnowledgeGraph() self.query_agent = QueryUnderstandingAgent(self.llm) self.retrieval_agent = RetrievalAgent(self.vector_db, self.kg, self.llm) self.grading_agent = GradingAgent(self.llm) self.generation_agent = GenerationAgent(self.llm) print("✅ Interactive System initialized!") def load_data(self, csv_path: str): """بارگذاری داده‌ها از CSV""" print(f"📊 Loading data from {csv_path}...") df = pd.read_excel(csv_path) products = self._parse_dataframe(df) self.vector_db.create_collection() points = [] for i, product in enumerate(products): text = f"{product.problem_title} {product.symptoms} {product.treatment_info}" vector = self.llm.get_embedding(text) point = PointStruct( id=i, vector=vector, payload={ "category": product.category, "problem": product.problem_title, "symptoms": product.symptoms, "treatment": product.treatment_info, "urls": product.urls, "products": product.product_names, "url": product.urls[0] if product.urls else "" } ) points.append(point) self._build_graph_from_product(product, i) self.vector_db.upsert_points(points) print(f"✅ Loaded {len(products)} products!") print(f"✅ Graph has {self.kg.graph.number_of_nodes()} nodes and {self.kg.graph.number_of_edges()} edges") def _parse_dataframe(self, df: pd.DataFrame) -> List[Product]: """تبدیل DataFrame به لیست Product""" products = [] for _, row in df.iterrows(): urls = re.findall(r'https://[^\s]+', str(row['محصولات پیشنهادی درمانی'])) product_names = re.findall(r'(?:سرم|ژل|کرم|فوم|محلول|اسپری|تونر|فلوئید)\s+[^\n]+', str(row['محصولات پیشنهادی درمانی'])) product = Product( category=str(row['دسته بندی کلی مشکل']), problem_title=str(row['عنوان مشکلات']), symptoms=str(row['توضیحات']), treatment_info=str(row['محصولات پیشنهادی درمانی']), urls=urls, product_names=product_names ) products.append(product) return products def _build_graph_from_product(self, product: Product, product_id: int): """ساخت گراف از یک محصول""" problem_id = f"problem_{product_id}" self.kg.add_node(problem_id, "problem", {"name": product.problem_title}) for i, url in enumerate(product.urls): product_node_id = f"product_{product_id}_{i}" product_name = product.product_names[i] if i < len(product.product_names) else f"محصول {i+1}" self.kg.add_node(product_node_id, "product", { "name": product_name, "url": url }) self.kg.add_edge(problem_id, product_node_id, "TREATED_BY") def query(self, user_query: str, conversation_history: List[Dict] = None) -> str: """پردازش query کاربر - با رویکرد تعاملی""" print(f"\n🔍 Processing query: {user_query}") # مرحله 1: فهم query intent = self.query_agent.analyze_query(user_query, conversation_history) print(f" Intent: {intent.intent_type} (confidence: {intent.confidence:.2f})") # **تصمیم‌گیری: سوال بپرس یا پاسخ بده؟** if intent.intent_type == "needs_clarification" and intent.confidence > 0.4: # نیاز به سوال داریم print(f" -> Need more info: {intent.missing_info}") return self.generation_agent.generate_clarification(user_query, intent, conversation_history) # مرحله 2: بازیابی (فقط اگر آماده پیشنهاد هستیم) retrieved_docs = self.retrieval_agent.retrieve(user_query, intent, top_k=3) print(f" Retrieved: {len(retrieved_docs)} documents") # مرحله 3: ارزیابی graded_docs = self.grading_agent.grade_relevance(user_query, retrieved_docs) print(f" Top score: {graded_docs[0]['relevance_score']:.2f}") # مرحله 4: تولید پاسخ نهایی answer = self.generation_agent.generate_recommendation(user_query, graded_docs, conversation_history) return answer # ============================================================================ # GRADIO UI (تغییر برای نگهداری تاریخچه) # ============================================================================ def create_gradio_interface(rag_system: PharmacyRAGSystem): """ساخت رابط کاربری Gradio - با تاریخچه مکالمه""" def chat(message, history): """تابع چت با تاریخچه""" try: # تبدیل history به فرمت مورد نیاز conversation_history = [] for h in history: conversation_history.append({"role": "user", "content": h[0]}) conversation_history.append({"role": "assistant", "content": h[1]}) # اضافه کردن پیام جدید conversation_history.append({"role": "user", "content": message}) # دریافت پاسخ answer = rag_system.query(message, conversation_history) return answer except Exception as e: return f"❌ خطا: {str(e)}" with gr.Blocks(title="🏥 مشاور هوشمند داروخانه") as demo: gr.Markdown(""" # 🏥 مشاور هوشمند داروخانه ### چت پشتیبانی تعاملی - با هوش مصنوعی سلام! من دستیار شما هستم. می‌خوام بهترین محصول رو برای شما پیدا کنم 😊 """) chatbot = gr.ChatInterface( fn=chat, examples=[ "سلام، برای جوش صورتم چیکار کنم؟", "پوستم خیلی چربه", "یه چیز اقتصادی می‌خوام", "میخوام منافذ پوستم کوچیک بشه", ], title="", description="با من چت کنید تا بهترین محصول رو پیدا کنیم!", ) gr.Markdown(""" --- **این سیستم چطور کار می‌کنه؟** 1. 🤔 سوالات شما رو می‌فهمه 2. ❓ سوالات هدفمند می‌پرسه تا بهترین محصول رو پیدا کنه 3. 🎯 فقط 1-2 محصول مناسب پیشنهاد می‌ده (نه همه محصولات!) 4. 💬 مثل یک مشاور واقعی باهاتون صحبت می‌کنه **تکنولوژی:** GPT-4o-mini + Qdrant + NetworkX """) return demo # ============================================================================ # MAIN # ============================================================================ if __name__ == "__main__": rag_system = PharmacyRAGSystem() rag_system.load_data("7590053231020941057_391109923615173.xlsx") demo = create_gradio_interface(rag_system) demo.launch( server_name="0.0.0.0", server_port=7860, share=True, )