Loading
Loading
In this project you'll apply everything you've learned in the course to build a complete AI assistant that runs in the terminal. The assistant supports: long conversations, file analysis, web search (via MCP), and memory between sessions.
Smart Assistant
├── 💬 Multi-turn conversation with Streaming
├── 📁 File analysis (PDF, Code, Text)
├── 🔍 Web search (via Brave MCP)
├── 🧠 Memory between sessions
└── 🎨 Beautiful terminal UI
smart-assistant/
├── main.py # Entry point
├── assistant.py # Assistant logic
├── memory.py # Memory system
├── tools.py # Assistant tools
├── ui.py # User interface
├── .env # Environment variables
└── requirements.txt # Requirements
pip install anthropic rich python-dotenv pypdf2
In this course, you went through everything a professional needs to use Claude effectively:
| Lesson | What You Learned | |--------|---------| | 1. Claude.ai | Projects, Artifacts, subscription plans | | 2. Professional Framework | CRAFT, Chain-of-Thought, XML Tags | | 3. Projects | Permanent System Prompts, knowledge files | | 4. Claude Code | CLI, CLAUDE.md, shortcuts | | 5. MCP | Integration protocol, ready-to-use servers | | 6. Claude API | SDK, Streaming, Vision, Tool Use | | 7. Project | A real app combining all skills |
# smart-assistant/assistant.py
# المساعد الذكي الكامل — يجمع كل مهارات الدورة
import os
import json
import anthropic
from pathlib import Path
from datetime import datetime
from typing import Optional
import base64
# ──────────────────────────────────────
# نظام الذاكرة
# ──────────────────────────────────────
MEMORY_FILE = Path("memory.json")
def load_memory() -> dict:
if MEMORY_FILE.exists():
return json.loads(MEMORY_FILE.read_text(encoding="utf-8"))
return {"messages": [], "facts": [], "created_at": datetime.now().isoformat()}
def save_memory(memory: dict) -> None:
max_msgs = int(os.getenv("MEMORY_MAX_MESSAGES", "50"))
if len(memory["messages"]) > max_msgs:
# احتفظ بأهم الرسائل (الأولى 5 + آخر max-5)
memory["messages"] = memory["messages"][:5] + memory["messages"][-(max_msgs-5):]
MEMORY_FILE.write_text(
json.dumps(memory, ensure_ascii=False, indent=2),
encoding="utf-8"
)
# ──────────────────────────────────────
# تحليل الملفات
# ──────────────────────────────────────
def read_file_content(file_path: str) -> tuple[str, str]:
"""
يقرأ الملف ويُرجع (المحتوى, نوع الملف).
يدعم: .txt .py .ts .js .md .pdf
"""
path = Path(file_path)
suffix = path.suffix.lower()
if suffix == ".pdf":
try:
import PyPDF2
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
text = "
".join(
page.extract_text() or "" for page in reader.pages
)
return text[:20000], "pdf" # حد 20K حرف
except ImportError:
return "خطأ: مكتبة PyPDF2 غير مثبتة (pip install pypdf2)", "error"
elif suffix in (".png", ".jpg", ".jpeg", ".webp", ".gif"):
# صور — ترجع base64 للـ Vision API
with open(path, "rb") as f:
data = base64.standard_b64encode(f.read()).decode()
media_type = f"image/{suffix[1:].replace('jpg', 'jpeg')}"
return data, f"image:{media_type}"
else:
# ملفات نصية
try:
return path.read_text(encoding="utf-8")[:20000], "text"
except UnicodeDecodeError:
return path.read_text(encoding="latin-1")[:20000], "text"
# ──────────────────────────────────────
# المساعد الرئيسي
# ──────────────────────────────────────
class SmartAssistant:
def __init__(self):
self.client = anthropic.Anthropic()
self.name = os.getenv("ASSISTANT_NAME", "المساعد الذكي")
self.memory = load_memory()
self.model = "claude-opus-4-8"
self.system_prompt = f"""أنت {self.name} — مساعد AI ذكي ومخصص.
قدراتك:
- محادثة طبيعية وذكية بالعربية والإنجليزية
- تحليل الملفات (كود، PDF، نصوص)
- تحليل الصور وشرح محتواها
- تذكّر المحادثات السابقة
أسلوبك:
- ودود، واضح، موجز
- استخدم أمثلة عملية
- اعترف بعدم المعرفة بدلاً من التخمين
- عند الكود، استخدم code blocks دائماً
التاريخ الحالي: {datetime.now().strftime('%Y-%m-%d')}"""
def build_messages(self, new_message: dict) -> list[dict]:
"""بناء قائمة الرسائل مع السياق التاريخي"""
return self.memory["messages"] + [new_message]
def chat(self, user_input: str, file_path: Optional[str] = None) -> str:
"""إرسال رسالة والحصول على رد مع streaming"""
# بناء محتوى الرسالة
if file_path:
content, file_type = read_file_content(file_path)
if file_type.startswith("image:"):
media_type = file_type.split(":")[1]
message_content = [
{
"type": "image",
"source": {"type": "base64", "media_type": media_type, "data": content}
},
{"type": "text", "text": user_input}
]
else:
message_content = f"{user_input}
<file name='{Path(file_path).name}'>
{content}
</file>"
else:
message_content = user_input
new_message = {"role": "user", "content": message_content}
messages = self.build_messages(new_message)
# Streaming response
full_response = ""
print(f"
{self.name}: ", end="", flush=True)
with self.client.messages.stream(
model=self.model,
max_tokens=2048,
system=self.system_prompt,
messages=messages
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
full_response += text
print() # سطر جديد
# حفظ في الذاكرة (نص فقط للـ user إذا كان content قائمة)
user_text = user_input if file_path else str(message_content)
self.memory["messages"].append({"role": "user", "content": user_text})
self.memory["messages"].append({"role": "assistant", "content": full_response})
save_memory(self.memory)
return full_response
def clear_memory(self):
"""مسح ذاكرة المحادثة"""
self.memory["messages"] = []
save_memory(self.memory)
print("✅ تم مسح الذاكرة")
# ──────────────────────────────────────
# تشغيل المساعد
# ──────────────────────────────────────
def main():
from dotenv import load_dotenv
load_dotenv()
assistant = SmartAssistant()
print("=" * 55)
print(f"🤖 {assistant.name} — مساعد AI الكامل")
print("=" * 55)
print("الأوامر:")
print(" /ملف <مسار> — تحليل ملف")
print(" /مسح — مسح الذاكرة")
print(" /خروج — الخروج")
print("-" * 55)
if assistant.memory["messages"]:
print(f"💾 تم تحميل {len(assistant.memory['messages'])} رسالة من الذاكرة")
while True:
user_input = input("
أنت: ").strip()
if not user_input:
continue
if user_input in ["/خروج", "/exit"]:
print("
👋 إلى اللقاء!")
break
if user_input == "/مسح":
assistant.clear_memory()
continue
if user_input.startswith("/ملف "):
file_path = user_input[5:].strip()
if not Path(file_path).exists():
print(f"❌ الملف غير موجود: {file_path}")
continue
question = input("سؤالك عن الملف: ").strip() or "حلّل هذا الملف"
assistant.chat(question, file_path=file_path)
continue
assistant.chat(user_input)
if __name__ == "__main__":
main()