0Pricing
AI Agents · درس

بناء خط أنابيب لأتمتة تطبيقات متعددة

ربط Gmail ← Slack ← Google Sheets عبر استدعاءات الأدوات التي يديرها الوكيل.

بناء خط أنابيب لأتمتة تطبيقات متعددة درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.

خط أنابيب التطبيقات المتعددة

يربط خط أنابيب التطبيقات المتعددة عدة خدمات في سير عمل آلي واحد. في هذا الدرس سنبني: بريد إلكتروني جديد في Gmail ← يقرأ الوكيل البريد ويستخرج بنود العمل ← ينشئ بطاقة في Trello ← يرسل إشعارًا إلى Slack.

بنية خط الأنابيب

يتكوّن خط الأنابيب من أربع مراحل:

  • التشغيل: يكتشف إشعار الدفع من Gmail أو الاستطلاع بريدًا إلكترونيًا جديدًا
  • الاستخراج: يقرأ LLM البريد الإلكتروني ويستخرج بنود العمل
  • الإنشاء: تنشئ Trello API بطاقةً لكل بند عمل
  • الإشعار: تنشر Slack API رسالةً تلخيصية

كل مرحلة دالة مستقلة ذات مدخلات ومخرجات واضحة.

from dataclasses import dataclass, field
from typing import List

@dataclass
class Email:
    id: str
    sender: str
    subject: str
    body: str

@dataclass
class ActionItem:
    title: str
    description: str
    due_date: str = None

@dataclass
class PipelineResult:
    email_id: str
    action_items: List[ActionItem] = field(default_factory=list)
    trello_card_ids: List[str] = field(default_factory=list)
    slack_message_ts: str = None
    error: str = None

if __name__ == '__main__':
    email = Email(id='e1', sender='alice@example.com', subject='Project update', body='See attached.')
    result = PipelineResult(email_id=email.id, action_items=[ActionItem(title='Review attachment', description='Check the doc')])
    print(f'Pipeline result for {result.email_id}: {len(result.action_items)} action item(s)')
    print(' -', result.action_items[0].title)

المرحلة 1: قراءة رسائل البريد الإلكتروني

استخدم Gmail API لجلب رسائل البريد الإلكتروني الجديدة. تتولى مكتبة google-api-python-client المصادقة واستدعاءات API. نستطلع الرسائل التي لم تُشاهد بعد.

from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
import base64

def get_gmail_service(token_path='token.json'):
    creds = Credentials.from_authorized_user_file(token_path)
    return build('gmail', 'v1', credentials=creds)

def fetch_unread_emails(service, max_results=10):
    results = service.users().messages().list(
        userId='me',
        q='is:unread',
        maxResults=max_results
    ).execute()
    messages = results.get('messages', [])
    emails = []
    for msg in messages:
        detail = service.users().messages().get(
            userId='me', id=msg['id'], format='full'
        ).execute()
        headers = {h['name']: h['value'] for h in detail['payload']['headers']}
        emails.append(Email(
            id=msg['id'],
            sender=headers.get('From', ''),
            subject=headers.get('Subject', ''),
            body=extract_body(detail)
        ))
    return emails

def extract_body(message_detail):
    payload = message_detail.get('payload', {})
    if 'data' in payload.get('body', {}):
        return base64.urlsafe_b64decode(payload['body']['data']).decode('utf-8')
    return ''

المرحلة 2: استخراج بنود العمل

مرّر محتوى البريد الإلكتروني إلى LLM واطلب منه استخراج بنود العمل بتنسيق JSON منظّم. استخدم response_format للحصول على مخرجات JSON موثوقة.

import openai
import json

client = openai.OpenAI(api_key='sk-...')

def extract_action_items(email: 'Email') -> list:
    prompt = (
        'Extract all action items from this email. '
        'Return JSON array with objects having fields: '
        'title (string), description (string), due_date (string or null).\n\n'
        f'From: {email.sender}\n'
        f'Subject: {email.subject}\n'
        f'Body:\n{email.body}'
    )
    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    result = json.loads(response.choices[0].message.content)
    items = result.get('action_items', [])
    return [
        ActionItem(
            title=item['title'],
            description=item.get('description', ''),
            due_date=item.get('due_date')
        )
        for item in items
    ]

المرحلة 3: إنشاء بطاقات Trello

تنشئ Trello REST API بطاقات باستخدام طلب POST بسيط. ستحتاج إلى مفتاح API والرمز المميز ومعرّف القائمة التي ينبغي إنشاء البطاقات فيها.

import httpx

TRELLO_API_KEY = 'your-trello-api-key'
TRELLO_TOKEN = 'your-trello-token'
TRELLO_LIST_ID = 'your-list-id'

def create_trello_card(action_item: 'ActionItem') -> str:
    url = 'https://api.trello.com/1/cards'
    params = {
        'key': TRELLO_API_KEY,
        'token': TRELLO_TOKEN
    }
    data = {
        'name': action_item.title,
        'desc': action_item.description,
        'idList': TRELLO_LIST_ID,
        'due': action_item.due_date
    }
    response = httpx.post(url, params=params, json=data)
    response.raise_for_status()
    card = response.json()
    return card['id']

def create_trello_cards_for_items(action_items: list) -> list:
    card_ids = []
    for item in action_items:
        card_id = create_trello_card(item)
        print(f'Created Trello card: {item.title} (ID: {card_id})')
        card_ids.append(card_id)
    return card_ids

المرحلة 4: إرسال إشعار Slack

استخدم Slack SDK لإرسال رسالة تلخيصية منسّقة إلى قناة. ينبغي أن تلخّص الرسالة بوضوح بنود العمل التي استُخرجت وأُنشئت.

from slack_sdk import WebClient

slack_client = WebClient(token='xoxb-your-slack-bot-token')

def send_slack_summary(email: 'Email', action_items: list, card_ids: list, channel: str = '#automation'):
    if not action_items:
        return None
    
    items_text = '\n'.join([
        f'  - {item.title}'
        for item in action_items
    ])
    
    message = (
        f'*New email processed from {email.sender}*\n'
        f'*Subject:* {email.subject}\n\n'
        f'*Action items extracted ({len(action_items)}):*\n'
        f'{items_text}\n\n'
        f'Trello cards created: {len(card_ids)}'
    )
    response = slack_client.chat_postMessage(
        channel=channel,
        text=message,
        mrkdwn=True
    )
    return response['ts']

معالجة الأخطاء في كل مرحلة

لا يكون خط الأنابيب متينًا إلا بقدر متانة معالجة أخطائه. يمكن أن تفشل كل مرحلة بشكل مستقل. غلّف كل استدعاء، وسجّل الخطأ، وحدد ما إذا كان ينبغي متابعة خط الأنابيب أو إيقافه.

import logging

logger = logging.getLogger('pipeline')

def run_pipeline_stage(stage_name, fn, *args, **kwargs):
    try:
        result = fn(*args, **kwargs)
        logger.info(f'Stage {stage_name}: success')
        return result, None
    except Exception as e:
        logger.error(f'Stage {stage_name}: FAILED - {e}')
        return None, str(e)

def process_email_pipeline(email):
    # Stage 2: Extract
    action_items, err = run_pipeline_stage('extract', extract_action_items, email)
    if err:
        return PipelineResult(email_id=email.id, error=f'Extract failed: {err}')
    if not action_items:
        logger.info(f'No action items found in email {email.id}')
        return PipelineResult(email_id=email.id, action_items=[])
    
    # Stage 3: Trello
    card_ids, err = run_pipeline_stage('trello', create_trello_cards_for_items, action_items)
    if err:
        card_ids = []  # Continue even if Trello fails
    
    # Stage 4: Slack
    ts, err = run_pipeline_stage('slack', send_slack_summary, email, action_items, card_ids or [])
    
    return PipelineResult(
        email_id=email.id,
        action_items=action_items,
        trello_card_ids=card_ids or [],
        slack_message_ts=ts
    )

التسجيل المنظّم لخطوط الأنابيب

استخدم التسجيل المنظّم حتى تتمكن من الاستعلام عن سجل تنفيذ خط الأنابيب. سجّل بدء خط الأنابيب واكتمال كل مرحلة والنتيجة النهائية ككائنات JSON.

import logging
import json
from datetime import datetime

class PipelineLogger:
    def __init__(self, pipeline_name):
        self.pipeline_name = pipeline_name
        self.logger = logging.getLogger(pipeline_name)
        self.run_id = None
        self.start_time = None
    
    def start(self, email_id):
        self.run_id = f'{email_id}_{int(datetime.now().timestamp())}'
        self.start_time = datetime.now()
        self.logger.info(json.dumps({
            'event': 'pipeline_start',
            'run_id': self.run_id,
            'email_id': email_id
        }))
    
    def stage_done(self, stage, result_summary):
        self.logger.info(json.dumps({
            'event': 'stage_complete',
            'run_id': self.run_id,
            'stage': stage,
            'result': result_summary
        }))
    
    def finish(self, success, details):
        duration = (datetime.now() - self.start_time).total_seconds()
        self.logger.info(json.dumps({
            'event': 'pipeline_finish',
            'run_id': self.run_id,
            'success': success,
            'duration_seconds': duration,
            'details': details
        }))

if __name__ == '__main__':
    import sys
    logging.basicConfig(level=logging.INFO, format='%(message)s', stream=sys.stdout)
    pl = PipelineLogger('demo_pipeline')
    pl.start('email_123')
    pl.stage_done('extract', {'items_found': 3})
    pl.finish(True, {'action_items': 2})

المشغّل الرئيسي لخط الأنابيب

يربط المشغّل الرئيسي جميع المكوّنات معًا. فهو يتحقّق من وجود رسائل بريد إلكتروني جديدة، ويعالج كل رسالة عبر خط الأنابيب، ثم يضع علامة «مقروءة» عليها لتجنّب معالجتها مرة أخرى.

import time

def mark_as_read(gmail_service, email_id):
    gmail_service.users().messages().modify(
        userId='me',
        id=email_id,
        body={'removeLabelIds': ['UNREAD']}
    ).execute()

def run_email_pipeline_loop(gmail_service, poll_interval=60):
    pipeline_logger = PipelineLogger('email_pipeline')
    print(f'Pipeline running. Polling every {poll_interval}s')
    
    while True:
        try:
            emails = fetch_unread_emails(gmail_service)
            print(f'Found {len(emails)} unread emails')
            
            for email in emails:
                pipeline_logger.start(email.id)
                result = process_email_pipeline(email)
                
                if result.error:
                    pipeline_logger.finish(False, {'error': result.error})
                else:
                    mark_as_read(gmail_service, email.id)
                    pipeline_logger.finish(True, {
                        'action_items': len(result.action_items),
                        'cards_created': len(result.trello_card_ids)
                    })
        
        except Exception as e:
            print(f'Pipeline loop error: {e}')
        
        time.sleep(poll_interval)

إدارة الإعدادات

احتفظ بجميع بيانات اعتماد API وإعدادات خط الأنابيب في متغيّرات البيئة، وليس في الشيفرة. وحمّلها عند بدء التشغيل، وتحقّق من وجود المفاتيح المطلوبة.

import os
from dotenv import load_dotenv

load_dotenv()

class PipelineConfig:
    def __init__(self):
        self.openai_api_key = os.environ.get('OPENAI_API_KEY', '')
        self.slack_bot_token = os.environ.get('SLACK_BOT_TOKEN', '')
        self.trello_api_key = os.environ.get('TRELLO_API_KEY', '')
        self.trello_token = os.environ.get('TRELLO_TOKEN', '')
        self.trello_list_id = os.environ.get('TRELLO_LIST_ID', '')
        self.slack_channel = os.environ.get('SLACK_CHANNEL', '#automation')
        self.poll_interval = int(os.environ.get('POLL_INTERVAL_SECONDS', '60'))
    
    def validate(self):
        missing = []
        required = [
            ('OPENAI_API_KEY', self.openai_api_key),
            ('SLACK_BOT_TOKEN', self.slack_bot_token),
            ('TRELLO_API_KEY', self.trello_api_key),
            ('TRELLO_TOKEN', self.trello_token),
            ('TRELLO_LIST_ID', self.trello_list_id)
        ]
        for name, value in required:
            if not value:
                missing.append(name)
        if missing:
            raise ValueError(f'Missing required config: {missing}')
        return True

config = PipelineConfig()
config.validate()
print('Config validated successfully')

اختبار خط الأنابيب

اختبر كل مرحلة من مراحل خط الأنابيب بشكل مستقل باستخدام بيانات وهمية قبل إجراء الاختبار الشامل من البداية إلى النهاية. يتيح لك ذلك التحقّق من المنطق دون استهلاك أرصدة API أو إنشاء بطاقات Trello فعلية.

from unittest.mock import MagicMock, patch

def test_extract_action_items_mock():
    mock_response = MagicMock()
    mock_response.choices[0].message.content = '{"action_items": [{"title": "Follow up with vendor", "description": "Call about invoice", "due_date": null}]}'
    
    with patch('openai.OpenAI') as mock_openai:
        mock_client = MagicMock()
        mock_client.chat.completions.create.return_value = mock_response
        mock_openai.return_value = mock_client
        
        test_email = Email(
            id='test123',
            sender='vendor@example.com',
            subject='Invoice Follow-up Needed',
            body='Please follow up with the vendor about the outstanding invoice.'
        )
        # Would call extract_action_items(test_email) with mocked OpenAI
        print('Test email:', test_email.subject)
        print('Mock response parsed successfully')

test_extract_action_items_mock()

اختبار المعرفة: خط أنابيب متعدد التطبيقات

اختبر مدى فهمك لبناء خطوط أنابيب للأتمتة متعددة التطبيقات.

مراجعة خط الأنابيب

لقد بنيت خط أنابيب متكاملًا للأتمتة متعددة التطبيقات: اكتشاف الرسائل في Gmail، والاستخراج المستند إلى LLM، وإنشاء بطاقات Trello، وإرسال إشعارات Slack. وتتمثل مبادئ التصميم الأساسية في فصل المراحل بواجهات واضحة، ومعالجة الأخطاء بفعالية في كل خطوة، وتسجيل الأحداث بطريقة منظمة، وإدارة الإعدادات عبر متغيّرات البيئة.

الأسئلة الشائعة

هل درس «بناء خط أنابيب لأتمتة تطبيقات متعددة» مجاني؟

نعم — نص درس «بناء خط أنابيب لأتمتة تطبيقات متعددة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.

ماذا ستتعلم في «بناء خط أنابيب لأتمتة تطبيقات متعددة»؟

ربط Gmail ← Slack ← Google Sheets عبر استدعاءات الأدوات التي يديرها الوكيل. تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟

لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «بناء خط أنابيب لأتمتة تطبيقات متعددة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟

نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أنماط وكلاء المحفز والإجراء
  2. ربط الوكلاء بـ Webhooks
  3. الوكلاء المجدولون والقائمون على Cron
  4. بناء خط أنابيب لأتمتة تطبيقات متعددة
← العودة إلى AI Agents