File size: 6,599 Bytes
fa3a9d9
48be6c1
fa3a9d9
728ca87
48be6c1
fa3a9d9
 
 
8375d1e
1b427e5
e05be61
 
 
 
 
 
fa3a9d9
 
 
 
e05be61
fa3a9d9
e05be61
 
fa3a9d9
 
 
 
 
 
 
 
48be6c1
fa3a9d9
 
991b62f
fa3a9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8019839
8375d1e
 
 
 
fa3a9d9
 
 
 
 
 
 
e05be61
 
fa3a9d9
 
 
8375d1e
fa3a9d9
8375d1e
fa3a9d9
 
 
 
 
 
 
8375d1e
fa3a9d9
8375d1e
fa3a9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e05be61
 
fa3a9d9
 
 
 
8375d1e
fa3a9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8375d1e
daf9c31
fa3a9d9
8019839
fa3a9d9
 
d7622b9
fa3a9d9
8375d1e
 
daf9c31
8375d1e
97fad18
 
48be6c1
 
 
66b8e5f
97fad18
 
fa3a9d9
97fad18
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import os
import atexit
import weaviate
import requests
import gradio as gr
from weaviate.classes.init import Auth
from weaviate.classes.query import Rerank
from transformers import AutoTokenizer, pipeline, AutoModelForSeq2SeqLM
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast

# ====== تحميل الإعدادات من البيئة ======
WEAVIATE_CLUSTER_URL = os.environ.get("weaviate_rest")
WEAVIATE_API_KEY = os.environ.get("weaviate_api_key")
COHERE_API_KEY = os.environ.get("cohere_api_key")
PERPLEXITY_API_KEY = os.environ.get("perplexity_api_key")
PERPLEXITY_END_POINT = os.environ.get("perplexity_end_point")

# ========== إعداد الاتصال مع Weaviate ==========
def connect_to_db():
    headers = {
        "X-Cohere-Api-Key": COHERE_API_KEY
    }
    weaviate_url = WEAVIATE_CLUSTER_URL
    weaviate_api_key = WEAVIATE_API_KEY

    client = weaviate.connect_to_weaviate_cloud(
        cluster_url=weaviate_url,
        auth_credentials=Auth.api_key(weaviate_api_key),
        headers=headers
    )
    return client


# ========== تحميل الموديلات ==========
model_checkpoint = "EN3IMI/RouterAraBERT"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
classifier = pipeline("sentiment-analysis", model=model_checkpoint)


# ========== دوال البحث ==========
def search_for_faq(user_query, client):
    collection = client.collections.use("FAQ")
    response = collection.query.hybrid(
        query=user_query,
        limit=10,
        alpha=0.40,
        rerank=Rerank(prop="content", query=user_query),
    )
    queries = [f"{user_query} [SEP] {obj.properties['content']}" for obj in response.objects[:2]]
    return queries, response.objects[:3]

def search_for_laws(user_query, client):
    collection = client.collections.use("Laws")
    response = collection.query.hybrid(
        query=user_query,
        limit=10,
        alpha=0.40,
        rerank=Rerank(prop="text", query=user_query),
    )
    return response.objects[:3]

# ========== دوال القرار ==========
def router_decision(queries):
    results = classifier(queries)
    labels = [res['label'] for res in results]
    numeric_labels = [1 if label == 'LABEL_1' else 0 for label in labels]
    return any(numeric_labels)

# ========== LLM responses ==========
def llm_response_faq(query, docs):
  chunks = []
  for i in docs:
    chunks.append(i.properties["content"])

  API_KEY = PERPLEXITY_API_KEY
  ENDPOINT = PERPLEXITY_END_POINT

  system_prompt = """
  You are an intelligent assistant specialized in the Jordanian Land and Survey Department. Your task is to provide answers strictly based on the context provided from FAQ files.

  Guidelines:

  1. Use only the information available in the provided files. Do not hallucinate or invent any information.
  2. If the provided context does not contain a relevant answer to the user's question, respond with: "I do not know the answer."
  3. Correct any spelling or typographical errors present in the extracted text from the files.
  4. Provide brief clarifications or explanations only when necessary to make the answer clear, but do not add new facts.
  5. Do not modify the facts or data from the files; respect the sensitivity of the information.
  6. Focus only on questions related to Jordanian land, survey, and administrative data.
  7. Answer in the language of the user's question. Most questions will be in Arabic, so prioritize answering in Arabic when possible.

  Instructions for answering:

  - First, identify the most relevant FAQ entry based on the user's question.
  - Then, provide the answer exactly as it appears in the file, fixing only spelling mistakes and minor formatting issues.
  - AVOID PROVIDIND INORMATION NOT PRESENT IN THE CONTEXT.
  - Always maintain accuracy and reliability.
  - If you don't know the answer tell the user that you don't know in Arabic
  """


  messages = [
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": "Context:\n" + "\n".join(chunks) + "\n\nQuestion:\n" + query}
  ]

  data = {
    "model": "sonar-pro",
    "messages": messages,
    "max_tokens": 250,
    "temperature": 0.5
  }

  resp = requests.post(ENDPOINT, headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}, json=data)
  responsed = resp.json()
  return responsed['choices'][0]['message']['content']


def llm_response_laws(query, docs):
    chunks = []
    for i in docs:
        chunks.append(i.properties["text"])

    API_KEY = PERPLEXITY_API_KEY
    ENDPOINT = PERPLEXITY_END_POINT

    system_prompt = """
    You are an intelligent assistant specialized in Jordanian laws and legislation.
    Your task is to provide answers strictly based on the context provided from the legal documents.

    Guidelines:
    1. Use only the information available in the provided files. Do not hallucinate.
    2. If the provided context does not contain a relevant answer, respond in Arabic with: "لا أعلم الجواب".
    3. Correct minor spelling/formatting mistakes if needed.
    4. Provide answers in Arabic when possible.
    5. Be accurate and concise.
    """

    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": "Context:\n" + "\n".join(chunks) + "\n\nQuestion:\n" + query}
    ]

    data = {
        "model": "sonar-pro",
        "messages": messages,
        "max_tokens": 300,
        "temperature": 0.5
    }

    resp = requests.post(
        ENDPOINT,
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json=data
    )
    responsed = resp.json()
    return responsed['choices'][0]['message']['content']


# ========== النظام الرئيسي ==========
def rag_system(user_input):
    client = connect_to_db()
    queries, faq_docs = search_for_faq(user_input, client)
    use_laws = router_decision(queries)

    if use_laws:
        answer = llm_response_faq(user_input, faq_docs)
    else:
        law_docs = search_for_laws(user_input, client)
        answer = llm_response_laws(user_input, law_docs)
        client.close()
    return answer
"""
@atexit.register
def close_client():
    try:
        client.close()
    except:
        pass"""

# ========== واجهة Gradio ==========
with gr.Blocks() as demo:
    gr.Markdown("## 🤖 AILS RAG System")
    inp = gr.Textbox(label="اكتب سؤالك")
    out = gr.Textbox(label="الإجابة")
    btn = gr.Button("إرسال")
    btn.click(rag_system, inp, out)

if __name__ == "__main__":
    demo.launch()