TahaFawzyElshrif commited on
Commit
32a7233
·
1 Parent(s): 1327b4d

uploaded files

Browse files
.gitignore ADDED
File without changes
Dockerfile ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ ENV PYTHONDONTWRITEBYTECODE=1
4
+ ENV PYTHONUNBUFFERED=1
5
+
6
+ WORKDIR /app
7
+
8
+ COPY requirements.txt ./
9
+ RUN pip install --no-cache-dir --upgrade pip && \
10
+ pip install --no-cache-dir -r requirements.txt
11
+
12
+ COPY . .
13
+
14
+ CMD ["python", "Server.py"]
Server.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_huggingface import HuggingFaceEndpoint,ChatHuggingFace
2
+ from langchain_core.messages import HumanMessage,SystemMessage
3
+ import os
4
+ import pandas as pd
5
+ from agent.agent_graph.graph import compiled_graph
6
+ from agent.rag.rag import rag_text_chooser
7
+ import sys
8
+ import os
9
+ from agent.agent_graph.StateTasks import Available_Tasks
10
+ from agent.tools.PDF import PDF_generator_Node
11
+ from agent.tools.email import EMAIL_sender_Node
12
+ from agent.agent_graph.Graph_Nodes import get_llm_answer
13
+ from agent.llm.prompts import NODES_Prompts
14
+ import dotenv
15
+
16
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
17
+ dotenv.load_dotenv("/content/drive/MyDrive/study/Projects/keys.env")
18
+ def get_response(prompt,memory,hf_key,state,user_email,user_name):
19
+ # Setting up models
20
+ os.environ["HF_TOKEN"] = hf_key
21
+ llm_gpt = HuggingFaceEndpoint(
22
+ repo_id="openai/gpt-oss-20b",#"deepseek-ai/DeepSeek-V3.2-Exp",#"openai/gpt-oss-20b",
23
+ task='conversational',
24
+ provider="auto",
25
+ max_new_tokens=2048
26
+ )
27
+ llm_gpt = ChatHuggingFace(llm=llm_gpt)
28
+
29
+ rag_model = rag_text_chooser(os.path.join(os.path.dirname(__file__), 'agent' ,'rag', 'rag.xlsx'))
30
+
31
+ # update state
32
+ state["question"] = prompt
33
+ state["memory"] = memory
34
+ state["llm"] = llm_gpt
35
+ state["rag_model"] = rag_model
36
+
37
+ call = compiled_graph.invoke(state)
38
+
39
+ save_send_email(call,user_email,user_name)
40
+ os.environ["HF_TOKEN"] = "" # to prevent keep it in env for other calls and for security
41
+
42
+ return call
43
+
44
+ def save_send_email(call,user_email,user_name):
45
+ if ("all_ok" in call.keys()):
46
+ if (call['all_ok']== True):
47
+ if (call['question_type'] in [Available_Tasks.LAPTOP_CHOOSE.value ,
48
+ Available_Tasks.QUESTION.value ,
49
+ Available_Tasks.ROADMAP.value]):
50
+ email_txt = get_llm_answer(model_llm=call['llm'],messages=[HumanMessage(content=("اسم الزميل لتستخدمه هو : "+ user_name +"/n/n")+ NODES_Prompts.Email_text.value + call['question'] + str(call['memory']) + call['question_type'] + call['answer'])])
51
+ title = get_llm_answer(model_llm=call['llm'],messages=[HumanMessage(content=NODES_Prompts.Email_title.value + call['question'] + str(call['memory']) + call['question_type']+ call['answer'])])
52
+
53
+ import tempfile
54
+ path_pdf = ''
55
+ with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
56
+ path_pdf = tmp_file.name
57
+ # هنا تكتب الكود اللي بيولد الملف
58
+ print("PDF path:", path_pdf)
59
+
60
+ # بعد ما تخلص من الملف ممكن تحذفه
61
+ # import os
62
+ # os.remove(path_pdf)
63
+
64
+
65
+ #path_pdf ="/content/drive/MyDrive/study/Projects/CodeBuddyAI/tmp.pdf"
66
+ PDF_generator_Node(call['answer'],title,path_pdf)
67
+ EMAIL_sender_Node(user_email,email_txt,title,path_pdf)
68
+ import os
69
+ os.remove(path_pdf)
70
+ print("Done")
71
+
72
+
73
+
__pycache__/Server.cpython-312.pyc ADDED
Binary file (4.28 kB). View file
 
agent/agent_graph/Graph_Nodes.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import TypedDict, List, Dict, Any, Optional
3
+ from langgraph.graph import StateGraph, START, END
4
+ from agent.agent_graph.StateTasks import *
5
+ from agent.llm.prompts import *
6
+ from typing import get_type_hints
7
+ import json
8
+ from langchain_core.messages import HumanMessage,SystemMessage
9
+ from agent.agent_graph.Graph_Utils import get_egp_to_usd
10
+ from agent.rag.rag import *
11
+
12
+ def answer_question(state:ProblemState):
13
+ print("Answering...")
14
+ question = state["question"]
15
+
16
+
17
+ if state["question_type"] == Available_Tasks.LAPTOP_CHOOSE.value:
18
+ guide_prompt = Tasks_prompts.LAPTOP_THINK.value
19
+ elif state["question_type"] == Available_Tasks.ROADMAP.value:
20
+ guide_prompt = Tasks_prompts.ROADMAP.value
21
+ elif ("node_output_article" in state.keys()):
22
+ guide_prompt = Tasks_prompts.ROADMAP.value +"<source>" + state["node_output_article"] +"</source>"
23
+
24
+ else:
25
+ guide_prompt = Tasks_prompts.RAG.value
26
+
27
+
28
+ answer_prompt = ((guide_prompt + "طلب المستخدم:\n" + question + "\nاهم معلومات المستخدم لاستخدامها ف الدلالة (بالنسبة للسعر هو نفس السعر لكن بالدولار فدائما ركز على السعر بالدولار\n)"+ str(state) + Route_prompts.FINALIZER_PROMPT.value))
29
+
30
+ print("ANSWER-PROMPT",answer_prompt)
31
+
32
+ state["answer"] = get_llm_answer(model_llm=state["llm"],messages=state["memory"] + [HumanMessage(content=(guide_prompt + "طلب المستخدم:\n" + question + "\nاهم معلومات المستخدم لاستخدامها ف الدلالة (بالنسبة للسعر هو نفس السعر لكن بالدولار فدائما ركز على السعر بالدولار\n)"+ str(state) + Route_prompts.FINALIZER_PROMPT.value))])
33
+
34
+ print("Answer ",state["answer"])
35
+ print("STATE ",state)
36
+ print("----------------------------")
37
+ return state
38
+
39
+
40
+ def update_context(state:ProblemState):
41
+ # Control what keys can be modified to preven hullicination
42
+ keys = get_type_hints(ProblemState).keys()
43
+ keys_modifiable = [] # keep it inside the function to make sure append to it not affected by other calls
44
+
45
+ _is_rag=False
46
+ _rag_text_if_exist = ""
47
+
48
+ for i in list(keys):
49
+
50
+ # 1️⃣ استبعاد المفاتيح غير القابلة للتعديل نهائيًا
51
+ if i in ["question", "answer", "node_output_article", "memory"]:
52
+ continue
53
+
54
+ # 2️⃣ منع تعديل question_type بعد بداية الشات
55
+ # - question_type يُسمح به فقط في أول الشات
56
+ # - لو موجود بالفعل في state → يبقى الشات بدأ → ممنوع التعديل
57
+ # if exist question in data rag skip it
58
+
59
+ if i == "question_type":
60
+ if "question_type" in state.keys():
61
+ continue
62
+
63
+ rag_text = state["rag_model"].get_relevant_question(state["question"])
64
+
65
+ if bool(rag_text):
66
+ _is_rag = True
67
+ _rag_text_if_exist = rag_text # store text to prevent calling twice
68
+ continue
69
+
70
+ # 3️⃣ أي key وصل هنا يبقى مسموح للـ LLM يرجّعه
71
+ keys_modifiable.append(i)
72
+
73
+ # Make the prompt
74
+ prompt_llm_new_info = Route_prompts.Context_UPDATOR.value + "\n <KEYS> \n" +str(keys_modifiable) +"\n </KEYS> <Text>"+state["question"]+"</Text>"
75
+
76
+ print("UPDATE - PROMPT",prompt_llm_new_info)
77
+
78
+
79
+ llm_new_info = get_llm_answer(model_llm=state["llm"],messages = [HumanMessage(prompt_llm_new_info)])
80
+ print("ANSWER ", llm_new_info)
81
+
82
+
83
+ # Save and Process the returned json to prevent hallucination
84
+ try:
85
+ llm_new_info = json.loads(llm_new_info)
86
+ for key in llm_new_info.keys():
87
+ if key in keys_modifiable:
88
+ state[key] = llm_new_info[key]
89
+
90
+ # check if rag
91
+ if _is_rag:
92
+ state["question_type"] = Available_Tasks.QUESTION.value
93
+ state["node_output_article"] = _rag_text_if_exist
94
+
95
+ # Check if all_ok can be answered now
96
+ last_question = state.get("answer", "")
97
+ check_finalized_prompt = (
98
+ "عندك ده اخر سوال واجابة"+
99
+ last_question +
100
+ state["question"] +
101
+ "هل معنى ذلك ان المستخدم اكد على الفهم الصحيح؟" +
102
+ "رجع فقط BOOL (True/False)"
103
+ )
104
+
105
+ print("UPDATE 2 - PROMPT ",check_finalized_prompt)
106
+ check_finalized = get_llm_answer(model_llm=state["llm"], messages = [HumanMessage(
107
+ check_finalized_prompt
108
+ )])
109
+ print("ANSWER ", check_finalized)
110
+ state['all_ok'] = check_finalized.strip().lower() == "true" # If wrong parsed it's false
111
+ print("Context updated")
112
+
113
+
114
+
115
+ except Exception as e:
116
+ print("Context was not updated due to error : ",e)
117
+
118
+ print("STATE ",state)
119
+ print("----------------------------")
120
+
121
+ return state
122
+
123
+
124
+
125
+ def convertPriceToDollar(state:ProblemState):
126
+ print("Converting price to dollar...")
127
+ if "price" in state.keys():
128
+ state["price"] = get_egp_to_usd(state["price"])
129
+ print("STATE ",state)
130
+ print("----------------------------")
131
+
132
+ return state
133
+
134
+ def step(state:ProblemState):
135
+ next_topic = None
136
+
137
+ if "question_type" not in state.keys():
138
+ next_topic = "question_type"
139
+
140
+
141
+ else:
142
+ for i in task_steps[state.get("question_type")]:
143
+ if i not in state.keys():
144
+ next_topic = i
145
+ print("Next topic ",next_topic)
146
+ break
147
+ # Only after finishing the to do list of the question type we can ask for all_ok to confirm
148
+ if (not next_topic) and ("all_ok" not in state.keys() or (state["all_ok"]==False)) and "question_type" in state.keys():
149
+
150
+ next_topic = "all_ok"
151
+ print("Next topic ",next_topic)
152
+
153
+
154
+
155
+ step_prompt = (System_prompts.STATE_DESCRIBE.value + f"<order>{next_topic} </order> <state>{state}</state>" + Route_prompts.FINALIZER_PROMPT_STEP.value)
156
+ print("STEP PROMPT",step_prompt)
157
+ state['answer'] = get_llm_answer(model_llm=state["llm"],messages = [HumanMessage(step_prompt)])
158
+ print("ANSWER ", state['answer'])
159
+ print("STATE ",state)
160
+ print("----------------------------")
161
+
162
+ return state
163
+
164
+ def search_knowledgebase(state:ProblemState):
165
+ """
166
+ Search the vector database for relevant contexts.
167
+ """
168
+ # fetch top 3 relevant docs
169
+ state["node_output_article"] = state["rag_model"].get_relevant_question(state["question"])
170
+
171
+ return state
172
+
173
+ def get_llm_answer(model_llm=None,messages=[HumanMessage(content="hi")]):
174
+ return model_llm.invoke(messages).content
agent/agent_graph/Graph_Routes.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent.agent_graph.StateTasks import *
2
+
3
+ def is_question_clear(state:ProblemState): # not check type , only check to do list
4
+ is_clear = True # as used with and later
5
+
6
+ is_clear = is_clear and ("question" in state.keys())
7
+
8
+ is_clear = is_clear and ("question_type" in state.keys()) and (state.get("question_type") in task_steps.keys())
9
+
10
+ if "question_type" in state.keys():
11
+ for step in task_steps[state.get("question_type")]:
12
+
13
+ is_clear = is_clear and (step in state.keys())
14
+
15
+ is_clear = is_clear and (state["all_ok"]==True)
16
+
17
+ return is_clear
18
+
19
+
agent/agent_graph/Graph_Utils.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ USD_url = "https://open.er-api.com/v6/latest/EGP"
3
+
4
+ def get_egp_to_usd(egp_amount):
5
+
6
+ try:
7
+ response = requests.get(USD_url, timeout=8)
8
+ response.raise_for_status() # raise error for bad status
9
+ data = response.json()
10
+
11
+ if data.get("result") != "success":
12
+ print("API error:", data)
13
+ return None
14
+
15
+ rate = data["rates"]["USD"]
16
+ usd_amount = egp_amount * rate
17
+
18
+ return usd_amount
19
+
20
+ except Exception as e:
21
+ print("Error:", e)
22
+ return None
23
+
24
+
25
+ get_egp_to_usd(1)
agent/agent_graph/StateTasks.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import TypedDict, List, Dict, Any, Optional
3
+ from enum import Enum
4
+
5
+ # 1) Core Tasks
6
+ class Available_Tasks(Enum):
7
+ LAPTOP_CHOOSE = "LAPTOP_CHOOSE"
8
+ QUESTION = "QUESTION" # EAG of well known
9
+ ROADMAP = "ROADMAP"
10
+ PROGRAMMING = "PROGRAMMING"
11
+ GENERAL = "GENERAL" # last option with notice
12
+ HELLO = "HELLO" # this is to generally detect hello , but in use update_context prompt control to not classify it as core type
13
+
14
+ # 2) Task Steps
15
+ task_steps = {
16
+ Available_Tasks.GENERAL.value : [],
17
+ Available_Tasks.LAPTOP_CHOOSE.value : ["price","usage","other_concern"],
18
+ Available_Tasks.QUESTION.value : [],
19
+ Available_Tasks.PROGRAMMING.value : [],
20
+ Available_Tasks.ROADMAP.value : ["career","level","experience","skills"],
21
+ Available_Tasks.HELLO.value : []
22
+ }
23
+
24
+ # 3) Tasks State
25
+ class ProblemState(TypedDict):
26
+ # main
27
+ question: str
28
+ answer: Optional[str]
29
+ node_output_article : Optional[str]
30
+ memory: List[Dict[str, Any]] # filled by list of Human/Sytem messages ... as in gui
31
+
32
+ # to do lists
33
+ # same as defined in task_Steps
34
+ question_type : Optional[str] # --> must be of Available_Tasks values
35
+ price : Optional[str]
36
+ usage : Optional[str]
37
+ other_concern : Optional[str]
38
+ career : Optional[str]
39
+ level : Optional[str]
40
+ experience : Optional[List[str]]
41
+ skills : Optional[List[str]]
42
+ all_ok : Optional[bool]
43
+
44
+ # Models
45
+ llm: Optional[Any]
46
+ rag_model: Optional[Any]
47
+
48
+
49
+
agent/agent_graph/__pycache__/Finalize_Nodes.cpython-312.pyc ADDED
Binary file (2.6 kB). View file
 
agent/agent_graph/__pycache__/Graph_Nodes.cpython-312.pyc ADDED
Binary file (7.46 kB). View file
 
agent/agent_graph/__pycache__/Graph_Routes.cpython-312.pyc ADDED
Binary file (943 Bytes). View file
 
agent/agent_graph/__pycache__/Graph_Utils.cpython-312.pyc ADDED
Binary file (1.01 kB). View file
 
agent/agent_graph/__pycache__/StateTasks.cpython-312.pyc ADDED
Binary file (1.92 kB). View file
 
agent/agent_graph/__pycache__/graph.cpython-312.pyc ADDED
Binary file (1.09 kB). View file
 
agent/agent_graph/graph.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from IPython.display import Image, display
2
+ from langgraph.graph import StateGraph, START, END
3
+ from agent.agent_graph.Graph_Nodes import *
4
+ from agent.agent_graph.Graph_Routes import *
5
+
6
+ problem_graph = StateGraph(ProblemState)
7
+
8
+ # Add nodes
9
+ problem_graph.add_node("answer_question",answer_question)
10
+ problem_graph.add_node("update_context",update_context)
11
+ problem_graph.add_node("convertPriceToDollar",convertPriceToDollar)
12
+ problem_graph.add_node("step",step)
13
+
14
+
15
+ # Routes
16
+ problem_graph.add_conditional_edges(
17
+ "update_context",
18
+ is_question_clear,
19
+ {
20
+ True: "convertPriceToDollar",
21
+ False: "step"
22
+ }
23
+ )
24
+
25
+
26
+ # Edges
27
+ problem_graph.add_edge(START,"update_context")
28
+ problem_graph.add_edge("convertPriceToDollar","answer_question")
29
+
30
+ # Finalize
31
+ compiled_graph = problem_graph.compile()
32
+ #display(Image(compiled_graph.get_graph().draw_mermaid_png()))
agent/llm/__pycache__/prompts.cpython-312.pyc ADDED
Binary file (20.9 kB). View file
 
agent/llm/prompts.py ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+ from agent.agent_graph.StateTasks import Available_Tasks
3
+
4
+ class System_prompts(Enum):
5
+ STATE_DESCRIBE = """
6
+ بيانات الحالة (state) مقسمة كالآتي:
7
+
8
+ 1. البيانات الأساسية
9
+
10
+ question: str → هذا هو السؤال الذي أدخله المستخدم.
11
+
12
+ answer: Optional[str] → هذا الحقل مخصص لإجابتك، لكن لا تكتب فيه مباشرة، كود آخر سيملأه لاحقًا.
13
+
14
+ node_output_article: Optional[str] → هذا النص يُستخدم لإرسال معلومات إلى نود آخر، مثل نص سيتم إرساله عبر البريد، فقط عند الحاجة.
15
+
16
+ memory: List[Dict[str, Any]] → سجل المحادثة السابقة (الرسائل من المستخدم والنظام)، لا تملأه، كود آخر سيستخدمه.
17
+
18
+ 2. قائمة المهام (To-Do / Question Type)
19
+
20
+ question_type: Optional[str] → يحدد نوع السؤال، ويجب أن يكون أحد القيم التالية من Enum Available_Tasks:
21
+
22
+ LAPTOP_CHOOSE → أي سؤال عن لابتوب أو كمبيوتر أو جهاز شغل.
23
+
24
+ ROADMAP → لو السؤال عن خارطة تعلم أو مسار دراسة (رودماب).
25
+
26
+ QUESTION → أسئلة مشهورة أو RAG.
27
+
28
+ PROGRAMMING → أي سؤال تقني أو برمجة دقيق.
29
+
30
+ GENERAL → أي سؤال آخر.
31
+
32
+ 3. بيانات خاصة بالسؤال عن لابتوب
33
+
34
+ price: Optional[str] → الميزانية بالدولار.
35
+
36
+ usage: Optional[str] →
37
+ → الغرض الأساسي اللي الجهاز معمول عشانه
38
+ → الحاجة اللي لو الجهاز مش هيشغلها كويس يبقى فاشل
39
+ → اختر حاجة واحدة فقط
40
+ "تعرفها ازاى؟ لو قال "استخدامى الاساسى
41
+
42
+ other_concern: Optional[str] →
43
+ → أي استخدام إضافي أو ثانوي
44
+ → حاجات "لطيفة لو موجودة" بس مش سبب الشراء الأساسي
45
+ → ممكن يكون أكتر من حاجة
46
+ "تعرفها ازاى؟ لو قال "استخدام اخر
47
+
48
+ 4. بيانات خاصة بالسؤال عن رودماب
49
+
50
+ career: Optional[str] → المجال الذي يود المستخدم العمل فيه.
51
+ → المجال أو الوظيفة اللي عايز يشتغل فيها
52
+ → اسم مجال واحد واضح
53
+ → "عايز أبقى إيه؟"
54
+
55
+
56
+ level: Optional[str] → مستواه الحالي (مبتدئ، متوسط، متقدم).
57
+ → مستواه الحالي في المجال ده
58
+ → قيمة واحدة فقط: مبتدئ / متوسط / متقدم
59
+ → إحساس عام مش تفاصيل
60
+
61
+
62
+ experience: Optional[List[str]] → خبراته السابقة.
63
+ → حاجات اشتغل عليها قبل كده فعلًا
64
+ → مشاريع، شغل، دراسة عملية
65
+ → إجابة سؤال: "عملت إيه قبل كده؟"
66
+
67
+
68
+
69
+ skills: Optional[List[str]] → المهارات التي يمتلكها.
70
+ → مهارات أو أدوات بيعرف يستخدمها
71
+ → لغات، تقنيات، فريموركس
72
+ → إجابة سؤال: "بتعرف تعمل بإيه؟"
73
+
74
+
75
+ 5. بيانات عامة
76
+
77
+ all_ok: Optional[bool] → للتأكد من صحة التحليل؛ ستسأل المستخدم "هل هذه المعلومات صحيحة؟" ويجيب بنعم أو لا.
78
+ """
79
+ SYSTEM_PROMPT = """
80
+ انت نظام CodeBuddy نظام مخصص للمبرمجين الجداد
81
+ تجب عن الاسئلة المشهورة كمبتدا وتصنع خرائط roadmaps وترشح لابتوب وغيره
82
+
83
+ - يجب ان تكون ودودا
84
+ - فكر قبل الاجابة
85
+ - اذا كنت غير متاكد ف الاجابة لديك الحرية ان تقول
86
+ "بص هو غالبا ......على اساس ان ...سبب .. ممكن تحاول تدور فيها اكتر او هتوضح مع الخبرة"
87
+ -حاول بردوا تفهم شعور الطالب لو مرتبك تكون تقوله بالراحة كدة ولو حزين قله فاهمك يخويك متزعلش ....
88
+ - اذا اعطيتك خيارات لارجاع منها اياك ابدا ابدا ان تخرج عنها او ترجع قيمة فارغة بل فكر واختار الاقرب حسب المعنى
89
+ - مش لازم تطول وتزود كتير خليك مركز
90
+ - - لا تتوقف قبل إكمال الفكرة
91
+
92
+
93
+
94
+ ستستلم معلومات ال state كالاتى:
95
+
96
+ """ + STATE_DESCRIBE
97
+
98
+ class Tasks_prompts(Enum):
99
+
100
+ ROADMAP = f"""
101
+ أنت الآن دورك مستشار تعلم ودود. مهمتك مساعدة الشخص على وضع **خطة تعلم شخصية منظمة** بناءً على معلوماته:
102
+
103
+ - career: المجال أو الوظيفة اللي عايز يشتغل فيها
104
+ - level: مستواه الحالي أو كم سنة شغال
105
+ - experience: خبراته العملية الحالية
106
+ - skills: المهارات اللي عنده
107
+
108
+ مطلوب منك:
109
+ 1) تبني له خطة منظمة خطوة بخطوة
110
+ 2) تشمل تأسيس قوي للمبادئ الأساسية
111
+ 3) تخليه يواكب العصر والتقنيات الحديثة
112
+ 4) شرحها بطريقة بسيطة ومريحة، بحيث ميتعقدش أو يحس بالضغط
113
+ 5) تخليه يطلع مشروع أو نتيجة قريبة ممكن يعملها، حتى لو بسيطة، لو أمكن
114
+
115
+ قواعد أثناء الكتابة:
116
+ - ركز على **الأساسيات أولاً ثم التدرج للمستوى المتقدم**
117
+ - قدم أمثلة عملية بسيطة، بدون غرق في تفاصيل دقيقة جداً
118
+ - وضّح أدوات أو موارد ممكن تساعده، سواء أونلاين أو برامج بسيطة
119
+ - أخيراً، شجّعه على البدء الآن:
120
+ > "خد خطوة دلوقتي، والباقي هييجي مع الوقت، وكلنا بنحتار الأول، المهم تبدأ."
121
+
122
+ """
123
+
124
+ RAG = f"""
125
+ انت المصدر الاخير للمعلومات. لا تستخدم أي معلومة غير موجودة في <source>.
126
+ إذا لم يكن هناك إجابة واضحة في <source>، أجب: "لا تتوفر معلومات كافية".
127
+ صغ الرد بأسلوب ودود ومرتب، لا تضف أمثلة أو أرقام من خبرتك الشخصية.
128
+ إذا كان المصدر يشير إلى موقع فقط، فاشرح للمستخدم أن البيانات يمكن الاطلاع عليها في هذا الموقع.
129
+ استعمل مصدر المعلومات الاتى
130
+ """
131
+ LAPTOP_THINK = f"""
132
+ أنت الآن في دور مستشار تقني ودود.
133
+ مهمتك مساعدة المستخدم يفكّر إزاي يختار لابتوب، وليس ماذا يشتري.
134
+ ممنوع تمامًا ذكر أي اسم جهاز أو موديل أو شركة.
135
+
136
+ ====================
137
+ قواعد صارمة قبل الإجابة
138
+ ====================
139
+
140
+ 1) لا افتراض:
141
+ ممنوع افتراض وجود مواصفات غير منطقية للسعر.
142
+ لو المواصفة غير متاحة اقتصاديًا → صرّح بأنها غير ممكنة.
143
+
144
+ 2) السعر هو الحاكم:
145
+ إذا تعارض الاستخدام مع السعر → السعر يكسب.
146
+ ممنوع رفع المواصفات لإرضاء الاستخدام.
147
+
148
+ 3) لا دقة زائفة:
149
+ ❌ ممنوع الجداول
150
+ ❌ ممنوع ذكر أجيال حديثة مع أسعار رخيصة
151
+ ❌ ممنوع ذكر كروت شاشة قوية أو حديثة إلا إذا السعر يسمح منطقيًا
152
+
153
+ 4) نبرة الإجابة:
154
+ لا تتحدث بثقة مطلقة.
155
+ استخدم دائمًا:
156
+ "في الغالب"
157
+ "المتوقع"
158
+ "المنطقي في الرينج ده"
159
+ لو في شك → قل إنه حد أدنى أو توقع، وليس ضمانًا.
160
+
161
+ 5) حجم الإجابة:
162
+ لو السؤال بسيط → الإجابة لا تتجاوز 8–10 سطور.
163
+ ممنوع التقارير الطويلة.
164
+
165
+ ====================
166
+ الخطوة 1: تحديد الاستخدام (الأهم)
167
+ ====================
168
+
169
+ ابدأ دائمًا بتحديد الاستخدام الأساسي فقط.
170
+ ❌ ممنوع شرح كل الاستخدامات
171
+ ❌ ممنوع فتح أقسام لم يُسأل عنها
172
+ ✅ مسموح فقط ذكر نوع المعالج / الجيل / الرام / التخزين / الكارت بشكل عام
173
+ ✅لو في تعارض بين السعر والمواصفات، وضّح التعارض بدل ما تحاول تلفّق حل.
174
+ ردودك تكون خطوط عريضة بدون تشعب.
175
+
176
+ خريطة الاستخدام → المتطلبات العامة:
177
+
178
+ - دراسة فقط:
179
+ → أي جهاز حديث نسبيًا ينفع
180
+
181
+ - برمجة ويب / موبايل:
182
+ → Core i3 أو i5 قديم نسبيًا
183
+ → التركيز على RAM و SSD
184
+
185
+ - ألعاب:
186
+ → التركيز على كارت الشاشة
187
+ → لو السعر قليل جدًا، صرّح أن الأداء سيكون محدود جدًا
188
+ → لو الألعاب اهتمام جانبي: سطر تحذيري واحد فقط بدون ذكر كروت أو VRAM
189
+
190
+ - مونتاج / جرافيكس:
191
+ → كارت مخصص للمونتاج + بروسيسور أقوى نسبيًا
192
+
193
+ - ذكاء اصطناعي:
194
+ → الكارت + البروسيسور أهم شيء
195
+ → أفضل أداء ممكن داخل الفئة السعرية فقط
196
+
197
+ - استخدام غير محدد:
198
+ → جهاز متوازن داخل الفئة السعرية
199
+
200
+ أساسيات في كل الحالات:
201
+ - SSD
202
+ - RAM لا تقل عن 8GB
203
+ - Windows 10/11 أو Linux حديث أو macOS
204
+
205
+ ====================
206
+ الخطوة 2: تقريب المواصفات
207
+ ====================
208
+
209
+ قرّب المواصفات الواقعية فقط.
210
+ اذكر "أفضل ما يمكن استهدافه" داخل نفس الفئة السعرية في 2025.
211
+ ممنوع ذكر مواصفات تعلم أنها نادرة أو غير متاحة في هذا السعر.
212
+
213
+ ====================
214
+ الخطوة 3: البرامج
215
+ ====================
216
+
217
+ لو المستخدم ذكر برنامج:
218
+ قل له يرجع للموقع الرسمي ويشوف المتطلبات.
219
+ اذكر أمثلة أسماء فقط بدون شرح:
220
+ Android Studio – Blender – AutoCAD
221
+
222
+ ====================
223
+ الخطوة 4: Other Concern
224
+ ====================
225
+
226
+ لخّص أي احتياج إضافي في سطر واحد.
227
+ لو خارج نطاق السعر → صرّح بذلك بوضوح.
228
+
229
+ ====================
230
+ الخطوة 5: السعر
231
+ ====================
232
+
233
+ - قيّم السعر: رخيص / متوسط / غالي (حسب 2025)
234
+ - لو بالجنيه: حوّله تقديريًا للدولار
235
+ - قل: "أعلى مواصفات منطقية في الرينج ده غالبًا هي…"
236
+
237
+ لو السعر غير كافٍ:
238
+ صرّح بذلك بوضوح.
239
+ اقترح بدائل أونلاين مناسبة فقط للاستخدام الأساسي:
240
+ Google Colab – Firebase – Android IDX – VS Code Web
241
+
242
+ ====================
243
+ الخطوة 6: الخاتمة
244
+ ====================
245
+
246
+ أكّد أن التعلم والتفكير أهم من قوة اللابتوب.
247
+ شجّع المستخدم يبدأ دلوقتي.
248
+
249
+ ====================
250
+ اكتب الإجابة الآن بأسلوب ودود وبسيط.
251
+ أنهِي الرد بجملة واضحة ولا تتوقف في منتصف جملة.
252
+
253
+ """
254
+
255
+
256
+
257
+ GENERAL_QUESTION = f"""
258
+ انت المصدر الاخير للمعلومات
259
+ فقله فيما معناه ان لا تتوفر اجابة والاجابة مصدرها اجتهاد وقد تكون غير محدثة
260
+ -ثم اجب
261
+ """
262
+
263
+ class Route_prompts(Enum):
264
+ Context_UPDATOR = """
265
+ ساعطيك نصا ف <text>
266
+ المطلوب حلل النص ورجع المعلومات ال فيه بصورة dictionary json
267
+ - only onlys dict no other words like "json"...
268
+ - keys of the json to be returned must be only from <Keys> only not </keys>
269
+ - يعنى ال مطلوب منك ببساطة حلل ال ف text لو ف معلومة من اللمرفقين ف keys
270
+ موجود ف النص ام لا
271
+ ❗ بخصوص المفتاح all_ok:
272
+ - لا تحاول تخمينه أو استنتاجه بأي شكل.
273
+ - لا تُرجِع all_ok إلا إذا صرّح المستخدم صراحة أنه موافق / تمام / كده تمام / مفهوم / كله واضح.
274
+ - إذا لم يوجد تأكيد صريح من المستخدم → لا تُرجِع all_ok نهائيًا.
275
+ - إذا قال المستخدم "لا معنديش استخدامات تانية" او ذكر اى كلمة استخدام فرعى فحدث other_concern
276
+ ولا تضعها في usage
277
+ - اياك اياك ابدا ان ترجع فى question_type
278
+ اى شى غير موجود فى
279
+ """+str([i.value for i in Available_Tasks if i.name!="QUESTION"])+"""}
280
+ ex
281
+ → ارجع {"other_concern": "لا يوجد"}
282
+ ❗ ممنوع الدمج أو التعميم:
283
+ - لا تدمج مجالات.
284
+ - لا تفترض نية المستخدم.
285
+ - لا تكمّل الناقص من عندك.
286
+
287
+
288
+ 1-USER: عاوز لابتوب ف رينج 5000
289
+ System: {"price":5000,"question_type":"LAPTOP_CHOOSE"}
290
+
291
+ 2- USER: عاوز اتعلم برمجة موبايل
292
+ System: {"question_type":"ROADMAP","career":"برمجة موبايل"}
293
+
294
+ 3- USER :مشعارف
295
+ System: {}
296
+
297
+ 4- USER: معاى نص مليون جنيه
298
+ System: {"price":1000000}
299
+ 5- USER : السلام عليكم اى الاخبار
300
+ System: {}
301
+ """
302
+
303
+
304
+ FINALIZER_PROMPT = """
305
+ صوغ الكل��م ف صيغة ودودة ومرتبه كانك بتشرح مش بتتكلم
306
+ الآن اكتب الإجابة النهائية للمستخدم. أنهِي الرد بجملة واضحة ولا تتوقف ابدا في منتصف جملة.
307
+ """
308
+
309
+ FINALIZER_PROMPT_STEP = """
310
+ أنت في خطوة الـ Finalizer.
311
+ مهمتك سؤال واحد فقط بناءً على قيمة <order>، ولا شيء غيره.
312
+
313
+ قواعد صارمة:
314
+ 1) اسأل سؤال واحد فقط متعلق بـ <order>.
315
+ 2) لا تضف أي معلومات أو نصائح أو استنتاجات.
316
+ 3) لا تنتقل لمرحلة التأكيد (all_ok) إلا إذا كانت بياناتها مكتملة.
317
+ 4) لا تسأل "هل هذه المعلومات صحيحة" إلا إذا كان <order> == all_ok.
318
+ 5 ) لو الإدخال تحية أو كلام عام، لا تذهب إلى all_ok.
319
+ رد التحية اولا ثم اساله عاوز اى
320
+ اياك تشرح التحية
321
+ 6) قدم ملخصًا واضحًا لما فهمته في جملة واحدة
322
+ (من معطى ال <state> قدم ملخص اى ال فهمته مطلوب اذا فقط وجد معلومات)
323
+ - يجب الا تكون غبيا اذا فقط السوال هو تحية فرد التحية مطولش
324
+ ومتقولش فهمت انك بتحيي
325
+ 7)اى حاجة غير is_ok وضحها بظبط بطريقة بسيطة ومثال
326
+ كما ف الامثلة
327
+
328
+ 8)يجب ان:
329
+ - توضيح بسيط للمقصود
330
+ - مثال واحد أو أكثر
331
+ حتى لو كان السؤال مباشر.
332
+
333
+
334
+ ❗ تحذير:
335
+ يُمنع منعًا باتًا سؤال أي شيء غير <order>.
336
+ حتى لو كانت معلومة ناقصة أو مذكورة سابقًا.
337
+
338
+
339
+
340
+ النبرة المطلوبة:
341
+ - ودودة وبسيطة.
342
+ - كأنك زميل بتتكلم، مش بوت.
343
+ - بدون كلمات رسمية زي "بالرجاء".
344
+ وبردود مشجعة
345
+ ومودبة مش كلمة عاوز
346
+
347
+ التصرف حسب <order>:
348
+ - إذا <order> == usage:
349
+ اسأل: "طيب استخدامك الأساسي إيه؟"
350
+ - إذا <order> == price:
351
+ اسأل: "طيب بادجتك كام تقريبًا؟"
352
+ - إذا <order> == all_ok:
353
+ قدم ملخصًا واضحًا لما فهمته في جملة واحدة،
354
+ ثم اسأل: "هل فهمي كده صح؟"
355
+
356
+
357
+ مثال:
358
+ <order>usage</order>
359
+ الرد: طيب استخدامك الأساسي إيه؟
360
+ اقصد اهم استخدام → الحاجة اللي لو الجهاز مش هيشغلها كويس يبقى فاشل
361
+
362
+ مثال:
363
+ <order>other_concern </order>
364
+ الرد : عندك اى استخدام تانى؟
365
+ → حاجات "لطيفة لو موجودة" بس مش سبب الشراء الأساسي
366
+
367
+ مثال:
368
+ <order>price</order>
369
+ الرد: طيب بادجتك كام تقريبًا؟
370
+ نطاق السعر ال تقدر تدفعه
371
+ (ادخل رقم واحد للمتوسط)
372
+
373
+
374
+ مثال:
375
+ <order>all_ok</order>
376
+ الرد: تمام، فهمت إنك عايز لابتوب بسعر X لاستخدام Y، هل فهمي كده صح؟
377
+
378
+
379
+ """
380
+
381
+ class NODES_Prompts(Enum):
382
+ Email_text = """
383
+ سأعطيك نصًا يحتوي على محادثة كاملة،
384
+ وفي النهاية توجد الإجابة أو النتيجة النهائية.
385
+
386
+ لا تهتم بالتفاصيل الدقيقة داخل الحوار.
387
+ المطلوب هو فهم السياق العام فقط.
388
+
389
+ اكتب ملخصًا قصيرًا مناسبًا ليكون نص بريد إلكتروني
390
+ مرسل إلى زميل عمل، يوضح خلاصة ما تم الاتفاق عليه.
391
+
392
+ يجب أن يكون الأسلوب مهنيًا وبسيطًا.
393
+ يمكنك الإشارة إلى أن التفاصيل موجودة في الملف إذا احتاجها.
394
+
395
+ المطلوب:
396
+ - إخراج نص الإيميل فقط. بالعامية المصرى
397
+ - بدون أي مقدمات أو شروحات إضافية.
398
+ """
399
+
400
+ Email_title = """
401
+ سأعطيك نصًا يحتوي على محادثة كاملة،
402
+ وفي النهاية توجد الإجابة أو النتيجة النهائية.
403
+
404
+ لا تهتم بالتفاصيل.
405
+ المطلوب هو فهم موضوع المحادثة فقط.
406
+
407
+ اكتب عنوانًا قصيرًا وواضحًا يلخص موضوع المحادثة
408
+ كما لو كان عنوان بريد إلكتروني.
409
+
410
+ المطلوب:
411
+ - إخراج العنوان فقط.
412
+ - بدون أي نص إضافي.
413
+ """
agent/rag/__pycache__/rag.cpython-312.pyc ADDED
Binary file (2.46 kB). View file
 
agent/rag/rag.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_text_splitters import CharacterTextSplitter
2
+ from langchain_core.documents import Document # Added import for Document
3
+ from sentence_transformers import SentenceTransformer, util
4
+ import pandas as pd
5
+
6
+ class rag_text_chooser:
7
+ def __init__(self,data_rag):
8
+ self.data_rag = pd.read_excel(data_rag)
9
+
10
+ self.corpus, self.answers = self.get_questions_Answers()
11
+ self.model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')
12
+ self.corpus_embeddings = self.model.encode(self.corpus)
13
+
14
+
15
+
16
+ def get_questions_Answers(self):
17
+
18
+ questions = []
19
+ answers = []
20
+
21
+ for _, row in self.data_rag.iterrows():
22
+ questions.append(row[0])
23
+ answers.append(row[1])
24
+
25
+ return questions, answers
26
+
27
+ def get_relevant_question(self, query):
28
+ # 4) Encode the Arabic query
29
+ query_embedding = self.model.encode(query)
30
+
31
+ # 5) Compute cosine similarity
32
+ cos_scores = util.cos_sim(query_embedding, self.corpus_embeddings)[0]
33
+
34
+ # 6) Rank results
35
+ top_results = cos_scores.argsort(descending=True)
36
+
37
+
38
+ matched_result = None
39
+ for idx in top_results:
40
+ if (cos_scores[idx] < .7): # Mostly not relate to her:
41
+ matched_result = None
42
+ else:
43
+ matched_result = (f"Questions {self.corpus[idx]} \n Answer {self.answers[idx]} \n (score: {cos_scores[idx]:.4f})")
44
+
45
+ break
46
+
47
+ return matched_result
agent/rag/rag.xlsx ADDED
Binary file (10.1 kB). View file
 
agent/tools/PDF.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from markdown_pdf import MarkdownPdf, Section
2
+ import os
3
+
4
+ #### For this version the nodes used directly not by graph
5
+
6
+ format_css = """
7
+ body {
8
+ font-family: 'Amiri', 'Arial', sans-serif; /* خط يدعم عربي وانجليزي */
9
+ font-size: 12pt;
10
+ line-height: 1.6;
11
+ direction: rtl; /* لجعل النص من اليمين لليسار */
12
+ margin: 20px;
13
+ }
14
+ h1, h2, h3 {
15
+ color: #2E86C1;
16
+ margin-bottom: 10px;
17
+ }
18
+ table {
19
+ border-collapse: collapse;
20
+ width: 100%;
21
+ margin-bottom: 10px;
22
+ }
23
+ table, th, td {
24
+ border: 1px solid #555;
25
+ padding: 6px;
26
+ }
27
+ th {
28
+ background-color: #f0f0f0;
29
+ }
30
+ """
31
+
32
+ def PDF_generator_Node(text_md,text_title,path_pdf):
33
+ pdf = MarkdownPdf(toc_level=2)
34
+ pdf.add_section(Section("# "+text_title), user_css=format_css)
35
+ pdf.add_section(Section(text_md), user_css=format_css)
36
+ pdf.save(path_pdf)
agent/tools/__pycache__/PDF.cpython-312.pyc ADDED
Binary file (1.24 kB). View file
 
agent/tools/__pycache__/email.cpython-312.pyc ADDED
Binary file (1.6 kB). View file
 
agent/tools/email.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import smtplib
2
+ from email.message import EmailMessage
3
+ import os
4
+
5
+ #### For this version the nodes used directly not by graph
6
+
7
+
8
+ smtp_server = "smtp.gmail.com" # SMTP is protcol for sending mail, use this server
9
+ smtp_port = 587
10
+ # for large scale / send many message you should use other server
11
+
12
+ def EMAIL_sender_Node(user_email,email_txt,subject,path_pdf):
13
+ APP_email = os.environ["APP_email"]
14
+ APP_password = os.environ["APP_password"]
15
+
16
+ msg = EmailMessage()
17
+ msg["Subject"] = subject
18
+ msg["From"] = APP_email
19
+ msg["To"] = user_email
20
+
21
+ msg.set_content(email_txt)
22
+
23
+ with open(path_pdf, "rb") as f:
24
+ file_data = f.read()
25
+ msg.add_attachment(file_data,
26
+ maintype="application",
27
+ subtype="pdf",
28
+ filename=path_pdf)
29
+
30
+
31
+ with smtplib.SMTP(smtp_server, smtp_port) as server:
32
+ server.ehlo() # know server / get info
33
+ server.starttls() # start the tls (securing protocol)
34
+ server.ehlo()
35
+ server.login(APP_email, APP_password)
36
+ server.send_message(msg)
37
+ print("Email sent!")
38
+
39
+
app.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ import sys
3
+ import os
4
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
5
+ from Server import get_response
6
+ from pydantic import BaseModel
7
+
8
+ # Create app instance
9
+ app = FastAPI()
10
+
11
+ class RequestModel(BaseModel):
12
+ prompt: str
13
+ ht_token : str
14
+ user_email : str
15
+ user_name : str
16
+ memory: list[str]
17
+
18
+
19
+ @app.get("/")
20
+ def read_root():
21
+ return {"message": "Hello From CodeBuddyAI!"}
22
+
23
+
24
+ @app.post("/call/")
25
+ def call(request: RequestModel):
26
+ answer = get_response(request.prompt, request.memory,request.ht_token,request.user_email,request.user_name)
27
+
28
+ return {"answer": answer}
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ langchain-huggingface
2
+ langchain-core
3
+ langchain-text-splitters
4
+ langgraph
5
+ python-dotenv
6
+ pandas
7
+ openpyxl
8
+ sentence-transformers
9
+ requests
10
+ ipython
11
+ fastapi
12
+ uvicorn
13
+ markdown_pdf
14
+ smtplib