diff --git a/.env b/.env new file mode 100644 index 0000000..d52ef51 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +# فایل تنظیمات محیطی +# برای دریافت API Key به https://makersuite.google.com/app/apikey مراجعه کنید + +GEMINI_API_KEY=your_gemini_api_key_here + +# تنظیمات اضافی (اختیاری) +GEMINI_MODEL=gemini-2.0-flash-exp +LOG_LEVEL=INFO +DEBUG_MODE=false \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3f8a59f --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +# فایل تنظیمات محیطی +# این فایل را کپی کرده و نام آن را به .env تغییر دهید +# سپس API Key های خود را اضافه کنید + +# Gemini API Key +# برای دریافت API Key به https://makersuite.google.com/app/apikey مراجعه کنید +GEMINI_API_KEY=your_gemini_api_key_here + +# تنظیمات اضافی (اختیاری) +# GEMINI_MODEL=gemini-2.0-flash-exp +# LOG_LEVEL=INFO +# DEBUG_MODE=false \ No newline at end of file diff --git a/README.md b/README.md index 296b930..53e1c9d 100644 --- a/README.md +++ b/README.md @@ -7,69 +7,308 @@ Add your open source license, GitHub uses MIT license. --> -# GitHub Pages +# 🚀 سیستم تولید محتوای هوش مصنوعی چندپلتفرمی -_Create a site or blog from your GitHub repositories with GitHub Pages._ +یک سیستم پیشرفته تولید محتوا که با استفاده از **Gemini 2.5 Flash** و قابلیت **Function Calling**، محتوای بهینه و اختصاصی برای پلتفرم‌های مختلف تولید می‌کند. - +## ✨ ویژگی‌های کلیدی - +- 🎯 **تولید محتوای چندپلتفرمی**: اینستاگرام، تلگرام، وب‌سایت، ایتا، روبیکا +- 🤖 **هوش مصنوعی پیشرفته**: استفاده از Gemini 2.5 Flash با Function Calling +- 🔍 **بهینه‌سازی SEO**: محتوای وب‌سایت کاملاً SEO-friendly +- 🎨 **پیشنهادات بصری**: ایده‌های تصویر و ویدئو متناسب با محتوا +- ⏰ **زمان‌بندی خودکار**: انتشار خودکار محتوا در زمان‌های مشخص +- 🌍 **پشتیبانی چندزبانه**: تولید محتوا به زبان‌های مختلف +- 📊 **تحلیل موضوع**: تحلیل عمیق و ایده‌پردازی خلاقانه -## Welcome +## 🏗️ معماری سیستم -With GitHub Pages, you can host project blogs, documentation, resumes, portfolios, or any other static content you'd like. Your GitHub repository can easily become its own website. In this course, we'll show you how to set up your own site or blog using GitHub Pages. +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ FastAPI App │───▶│ Content Generator│───▶│ Gemini Client │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ Scheduler │ │ Models & API │ │ Function Calls │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ +``` -- **Who is this for**: Beginners, students, project maintainers, small businesses. -- **What you'll learn**: How to build a GitHub Pages site. -- **What you'll build**: We'll build a simple GitHub Pages site with a blog. We'll use [Jekyll](https://jekyllrb.com), a static site generator. -- **Prerequisites**: If you need to learn about branches, commits, and pull requests, take [Introduction to GitHub](https://github.com/skills/introduction-to-github) first. -- **How long**: This course takes less than one hour to complete. +## 🚀 نصب و راه‌اندازی -In this course, you will: +### پیش‌نیازها -1. Enable GitHub Pages -2. Configure your site -3. Customize your home page -4. Create a blog post -5. Merge your pull request +- Python 3.8+ +- Gemini API Key -### How to start this course +### نصب - +1. **کلون کردن مخزن** +```bash +git clone +cd ai-content-generator +``` -[![start-course](https://user-images.githubusercontent.com/1221423/235727646-4a590299-ffe5-480d-8cd5-8194ea184546.svg)](https://github.com/new?template_owner=skills&template_name=github-pages&owner=%40me&name=skills-github-pages&description=My+clone+repository&visibility=public) +2. **نصب وابستگی‌ها** +```bash +pip install -r requirements.txt +``` -1. Right-click **Start course** and open the link in a new tab. -2. In the new tab, most of the prompts will automatically fill in for you. - - For owner, choose your personal account or an organization to host the repository. - - We recommend creating a public repository, as private repositories will [use Actions minutes](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions). - - Scroll down and click the **Create repository** button at the bottom of the form. -3. After your new repository is created, wait about 20 seconds, then refresh the page. Follow the step-by-step instructions in the new repository's README. +3. **تنظیم API Key** +```bash +cp .env.example .env +# فایل .env را ویرایش کرده و GEMINI_API_KEY خود را اضافه کنید +``` - +**نکته**: برای استفاده از این سیستم، حتماً API Key معتبر Gemini داشته باشید. diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000..a204cad Binary files /dev/null and b/__pycache__/config.cpython-313.pyc differ diff --git a/__pycache__/content_generator.cpython-313.pyc b/__pycache__/content_generator.cpython-313.pyc new file mode 100644 index 0000000..3a15ae7 Binary files /dev/null and b/__pycache__/content_generator.cpython-313.pyc differ diff --git a/__pycache__/gemini_client.cpython-313.pyc b/__pycache__/gemini_client.cpython-313.pyc new file mode 100644 index 0000000..17f21db Binary files /dev/null and b/__pycache__/gemini_client.cpython-313.pyc differ diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc new file mode 100644 index 0000000..73a0d31 Binary files /dev/null and b/__pycache__/models.cpython-313.pyc differ diff --git a/__pycache__/scheduler.cpython-313.pyc b/__pycache__/scheduler.cpython-313.pyc new file mode 100644 index 0000000..3283c23 Binary files /dev/null and b/__pycache__/scheduler.cpython-313.pyc differ diff --git a/config.py b/config.py new file mode 100644 index 0000000..6779804 --- /dev/null +++ b/config.py @@ -0,0 +1,35 @@ +import os +from dotenv import load_dotenv + +load_dotenv() + +class Config: + # Gemini API Configuration + GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") + GEMINI_MODEL = "gemini-2.0-flash-exp" + + # Platform-specific settings + INSTAGRAM_MAX_CAPTION_LENGTH = 2200 + TELEGRAM_MAX_MESSAGE_LENGTH = 4096 + WEBSITE_MAX_TITLE_LENGTH = 60 + WEBSITE_MAX_DESCRIPTION_LENGTH = 160 + + # Content generation settings + DEFAULT_TONE = "professional" + DEFAULT_LANGUAGE = "persian" + + # SEO settings + SEO_KEYWORDS_COUNT = 5 + SEO_DESCRIPTION_LENGTH = 155 + + # Visual content suggestions + IMAGE_STYLES = [ + "modern", "minimalist", "vibrant", "professional", + "creative", "elegant", "bold", "playful" + ] + + VIDEO_DURATIONS = [15, 30, 60, 90, 120] + + # Hashtag settings + MAX_HASHTAGS = 30 + MIN_HASHTAGS = 5 \ No newline at end of file diff --git a/content_generator.py b/content_generator.py new file mode 100644 index 0000000..6ecbcad --- /dev/null +++ b/content_generator.py @@ -0,0 +1,350 @@ +from typing import Dict, Any, List, Optional +from models import ContentRequest, ContentResponse, Platform, PlatformContent, WebsiteContent, VisualSuggestion +from gemini_client import GeminiClient +from config import Config +import random + +class ContentGenerator: + def __init__(self): + self.gemini_client = GeminiClient() + + def generate_content(self, request: ContentRequest) -> ContentResponse: + """تولید محتوای چندپلتفرمی""" + try: + # تحلیل موضوع + topic_analysis = self._analyze_topic(request) + + # تولید محتوا برای هر پلتفرم + content_responses = {} + + if Platform.INSTAGRAM in request.platforms: + content_responses['instagram'] = self._generate_instagram_content(request) + + if Platform.TELEGRAM in request.platforms: + content_responses['telegram'] = self._generate_telegram_content(request) + + if Platform.WEBSITE in request.platforms: + content_responses['website'] = self._generate_website_content(request) + + if Platform.EITAA in request.platforms: + content_responses['eitaa'] = self._generate_eitaa_content(request) + + if Platform.RUBIKA in request.platforms: + content_responses['rubika'] = self._generate_rubika_content(request) + + # تولید هشتگ‌ها + hashtags = self._generate_hashtags(request.keywords, request.topic) + + # تولید ایده‌های بصری + visual_suggestions = self._generate_visual_suggestions(request) + + # تولید پیشنهادات CTA + cta_suggestions = self._generate_cta_suggestions(request.tone) + + # بهینه‌سازی SEO + seo_optimization = None + if request.include_seo and Platform.WEBSITE in request.platforms: + seo_optimization = self._optimize_for_seo(request) + + return ContentResponse( + topic_analysis=topic_analysis, + instagram_content=content_responses.get('instagram'), + telegram_content=content_responses.get('telegram'), + website_content=content_responses.get('website'), + eitaa_content=content_responses.get('eitaa'), + rubika_content=content_responses.get('rubika'), + hashtags=hashtags, + visual_suggestions=visual_suggestions, + cta_suggestions=cta_suggestions, + seo_optimization=seo_optimization + ) + + except Exception as e: + raise Exception(f"خطا در تولید محتوا: {str(e)}") + + def _analyze_topic(self, request: ContentRequest) -> Dict[str, Any]: + """تحلیل موضوع و ایده‌پردازی""" + prompt = f""" + تحلیل موضوع: {request.topic} + کلمات کلیدی: {', '.join(request.keywords)} + مخاطب هدف: {request.target_audience} + لحن: {request.tone} + + لطفاً تحلیل کاملی از موضوع ارائه دهید شامل: + 1. خلاصه موضوع + 2. نکات کلیدی + 3. ایده‌های خلاقانه + 4. زاویه‌های مختلف برای ارائه + """ + + response = self.gemini_client.generate_content(prompt) + return { + "analysis": response.get("text", ""), + "key_points": self._extract_key_points(response.get("text", "")), + "creative_angles": self._extract_creative_angles(response.get("text", "")) + } + + def _generate_instagram_content(self, request: ContentRequest) -> Dict[str, str]: + """تولید محتوای اینستاگرام""" + prompt = f""" + برای اینستاگرام محتوای جذاب تولید کنید: + موضوع: {request.topic} + لحن: {request.tone} + مخاطب: {request.target_audience} + + شامل: + 1. کپشن جذاب (حداکثر 2200 کاراکتر) + 2. هشتگ‌های مرتبط + 3. اموجی‌های مناسب + 4. CTA موثر + """ + + response = self.gemini_client.generate_content(prompt) + return { + "caption": response.get("text", "")[:Config.INSTAGRAM_MAX_CAPTION_LENGTH], + "hashtags": self._extract_hashtags(response.get("text", "")), + "emojis": self._extract_emojis(response.get("text", "")), + "cta": self._extract_cta(response.get("text", "")) + } + + def _generate_telegram_content(self, request: ContentRequest) -> Dict[str, str]: + """تولید محتوای تلگرام""" + prompt = f""" + برای تلگرام محتوای کامل و مفصل تولید کنید: + موضوع: {request.topic} + لحن: {request.tone} + مخاطب: {request.target_audience} + + شامل: + 1. متن کامل و مفصل + 2. هشتگ‌های مرتبط + 3. اموجی‌های مناسب + 4. CTA موثر + """ + + response = self.gemini_client.generate_content(prompt) + return { + "content": response.get("text", ""), + "hashtags": self._extract_hashtags(response.get("text", "")), + "emojis": self._extract_emojis(response.get("text", "")), + "cta": self._extract_cta(response.get("text", "")) + } + + def _generate_website_content(self, request: ContentRequest) -> Dict[str, str]: + """تولید محتوای وب‌سایت""" + prompt = f""" + برای وب‌سایت محتوای SEO-friendly تولید کنید: + موضوع: {request.topic} + کلمات کلیدی: {', '.join(request.keywords)} + لحن: {request.tone} + مخاطب: {request.target_audience} + + شامل: + 1. عنوان صفحه (حداکثر 60 کاراکتر) + 2. توضیحات متا (حداکثر 160 کاراکتر) + 3. محتوای اصلی با هدینگ‌های مناسب + 4. کلمات کلیدی SEO + """ + + response = self.gemini_client.generate_content(prompt) + return { + "title": self._extract_title(response.get("text", "")), + "meta_description": self._extract_meta_description(response.get("text", "")), + "content": response.get("text", ""), + "headings": self._extract_headings(response.get("text", "")), + "keywords": request.keywords + } + + def _generate_eitaa_content(self, request: ContentRequest) -> Dict[str, str]: + """تولید محتوای ایتا""" + prompt = f""" + برای ایتا محتوای مناسب تولید کنید: + موضوع: {request.topic} + لحن: {request.tone} + مخاطب: {request.target_audience} + + شامل: + 1. متن کامل و جذاب + 2. هشتگ‌های مرتبط + 3. اموجی‌های مناسب + 4. CTA موثر + """ + + response = self.gemini_client.generate_content(prompt) + return { + "content": response.get("text", ""), + "hashtags": self._extract_hashtags(response.get("text", "")), + "emojis": self._extract_emojis(response.get("text", "")), + "cta": self._extract_cta(response.get("text", "")) + } + + def _generate_rubika_content(self, request: ContentRequest) -> Dict[str, str]: + """تولید محتوای روبیکا""" + prompt = f""" + برای روبیکا محتوای بهینه تولید کنید: + موضوع: {request.topic} + لحن: {request.tone} + مخاطب: {request.target_audience} + + شامل: + 1. متن جذاب و کوتاه + 2. هشتگ‌های مرتبط + 3. اموجی‌های مناسب + 4. CTA موثر + """ + + response = self.gemini_client.generate_content(prompt) + return { + "content": response.get("text", ""), + "hashtags": self._extract_hashtags(response.get("text", "")), + "emojis": self._extract_emojis(response.get("text", "")), + "cta": self._extract_cta(response.get("text", "")) + } + + def _generate_hashtags(self, keywords: List[str], topic: str) -> List[str]: + """تولید هشتگ‌های پیشنهادی""" + base_hashtags = [f"#{keyword.replace(' ', '')}" for keyword in keywords] + + # اضافه کردن هشتگ‌های مرتبط + related_hashtags = [ + f"#{topic.replace(' ', '')}", + "#محتوای_دیجیتال", + "#بازاریابی_دیجیتال", + "#شبکه_های_اجتماعی" + ] + + all_hashtags = base_hashtags + related_hashtags + return list(set(all_hashtags))[:Config.MAX_HASHTAGS] + + def _generate_visual_suggestions(self, request: ContentRequest) -> Dict[str, Any]: + """تولید ایده‌های بصری""" + image_style = random.choice(Config.IMAGE_STYLES) + video_duration = random.choice(Config.VIDEO_DURATIONS) + + return { + "image_style": image_style, + "color_scheme": self._generate_color_scheme(image_style), + "composition": self._generate_composition(image_style), + "video_duration": video_duration, + "video_style": self._generate_video_style(request.tone) + } + + def _generate_cta_suggestions(self, tone: str) -> List[str]: + """تولید پیشنهادات CTA""" + cta_templates = { + "professional": [ + "برای اطلاعات بیشتر با ما تماس بگیرید", + "همین امروز شروع کنید", + "درخواست مشاوره رایگان" + ], + "friendly": [ + "نظرتون چیه؟", + "تجربه‌تون رو به اشتراک بگذارید", + "سوالی دارید؟" + ], + "creative": [ + "ایده‌های جدید رو کشف کنید", + "خلاقیت‌تون رو بروز بدید", + "ماجراجویی رو شروع کنید" + ] + } + + return cta_templates.get(tone, cta_templates["professional"]) + + def _optimize_for_seo(self, request: ContentRequest) -> Dict[str, str]: + """بهینه‌سازی SEO""" + prompt = f""" + برای موضوع '{request.topic}' و کلمات کلیدی {', '.join(request.keywords)}: + 1. عنوان SEO بهینه (حداکثر 60 کاراکتر) + 2. توضیحات متا (حداکثر 160 کاراکتر) + 3. هدینگ‌های H1, H2, H3 + 4. کلمات کلیدی اصلی + """ + + response = self.gemini_client.generate_content(prompt) + return { + "title": self._extract_title(response.get("text", "")), + "meta_description": self._extract_meta_description(response.get("text", "")), + "headings": self._extract_headings(response.get("text", "")), + "keywords": request.keywords + } + + # Helper methods for extracting content + def _extract_key_points(self, text: str) -> List[str]: + """استخراج نکات کلیدی از متن""" + # این متد می‌تواند با NLP پیشرفته‌تر شود + return [text[:100] + "..."] if text else [] + + def _extract_creative_angles(self, text: str) -> List[str]: + """استخراج زاویه‌های خلاقانه""" + return [text[:100] + "..."] if text else [] + + def _extract_hashtags(self, text: str) -> List[str]: + """استخراج هشتگ‌ها از متن""" + import re + hashtags = re.findall(r'#\w+', text) + return hashtags[:10] + + def _extract_emojis(self, text: str) -> List[str]: + """استخراج اموجی‌ها از متن""" + import re + emojis = re.findall(r'[^\w\s]', text) + return emojis[:5] + + def _extract_cta(self, text: str) -> str: + """استخراج CTA از متن""" + cta_keywords = ["تماس", "شروع", "کلیک", "ببینید", "دانلود"] + for keyword in cta_keywords: + if keyword in text: + return keyword + return "بیشتر بدانید" + + def _extract_title(self, text: str) -> str: + """استخراج عنوان از متن""" + lines = text.split('\n') + for line in lines: + if line.strip() and len(line.strip()) <= 60: + return line.strip() + return text[:60] + "..." + + def _extract_meta_description(self, text: str) -> str: + """استخراج توضیحات متا از متن""" + return text[:160] + "..." if len(text) > 160 else text + + def _extract_headings(self, text: str) -> List[str]: + """استخراج هدینگ‌ها از متن""" + lines = text.split('\n') + headings = [] + for line in lines: + if line.strip().startswith('#') or line.strip().isupper(): + headings.append(line.strip()) + return headings[:5] + + def _generate_color_scheme(self, style: str) -> List[str]: + """تولید رنگ‌بندی بر اساس سبک""" + color_schemes = { + "modern": ["#2C3E50", "#3498DB", "#ECF0F1"], + "minimalist": ["#FFFFFF", "#000000", "#F5F5F5"], + "vibrant": ["#E74C3C", "#F39C12", "#2ECC71"], + "professional": ["#34495E", "#7F8C8D", "#BDC3C7"] + } + return color_schemes.get(style, ["#000000", "#FFFFFF"]) + + def _generate_composition(self, style: str) -> str: + """تولید ترکیب‌بندی بر اساس سبک""" + compositions = { + "modern": "ترکیب‌بندی متقارن با فضای سفید", + "minimalist": "ترکیب‌بندی ساده و تمیز", + "vibrant": "ترکیب‌بندی پویا و رنگی", + "professional": "ترکیب‌بندی متعادل و حرفه‌ای" + } + return compositions.get(style, "ترکیب‌بندی استاندارد") + + def _generate_video_style(self, tone: str) -> str: + """تولید سبک ویدئو بر اساس لحن""" + video_styles = { + "professional": "ویدئوی آموزشی با انیمیشن‌های ساده", + "friendly": "ویدئوی تعاملی و دوستانه", + "creative": "ویدئوی خلاقانه با افکت‌های ویژه" + } + return video_styles.get(tone, "ویدئوی استاندارد") \ No newline at end of file diff --git a/example_usage.py b/example_usage.py new file mode 100644 index 0000000..b061591 --- /dev/null +++ b/example_usage.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +نمونه استفاده از سیستم تولید محتوای هوش مصنوعی چندپلتفرمی +""" + +import os +import sys +from datetime import datetime, timedelta +from models import ContentRequest, Platform, Tone +from content_generator import ContentGenerator +from scheduler import ContentScheduler + +def main(): + """نمونه استفاده اصلی""" + + print("🚀 سیستم تولید محتوای هوش مصنوعی چندپلتفرمی") + print("=" * 60) + + # بررسی وجود API Key + if not os.getenv("GEMINI_API_KEY"): + print("❌ GEMINI_API_KEY تنظیم نشده است!") + print("لطفاً فایل .env را ایجاد کرده و API Key را اضافه کنید:") + print("GEMINI_API_KEY=your_api_key_here") + return + + try: + # ایجاد نمونه از تولیدکننده محتوا + content_generator = ContentGenerator() + + # نمونه درخواست محتوا + request = ContentRequest( + topic="بازاریابی دیجیتال در سال 2024", + keywords=["بازاریابی دیجیتال", "شبکه‌های اجتماعی", "محتوا", "SEO"], + target_audience="کارآفرینان و مدیران کسب‌وکار", + tone=Tone.PROFESSIONAL, + platforms=[Platform.INSTAGRAM, Platform.TELEGRAM, Platform.WEBSITE], + include_visual_suggestions=True, + include_seo=True + ) + + print("\n📝 درخواست محتوا:") + print(f"موضوع: {request.topic}") + print(f"کلمات کلیدی: {', '.join(request.keywords)}") + print(f"مخاطب: {request.target_audience}") + print(f"لحن: {request.tone.value}") + print(f"پلتفرم‌ها: {[p.value for p in request.platforms]}") + + print("\n🔄 در حال تولید محتوا...") + + # تولید محتوا + response = content_generator.generate_content(request) + + print("\n✅ محتوا با موفقیت تولید شد!") + print("\n" + "=" * 60) + + # نمایش تحلیل موضوع + print("📊 تحلیل موضوع:") + print(f"تحلیل: {response.topic_analysis.get('analysis', '')[:200]}...") + + # نمایش محتوای اینستاگرام + if response.instagram_content: + print("\n📱 محتوای اینستاگرام:") + print(f"کپشن: {response.instagram_content.get('caption', '')[:100]}...") + print(f"هشتگ‌ها: {', '.join(response.instagram_content.get('hashtags', [])[:5])}") + print(f"اموجی‌ها: {', '.join(response.instagram_content.get('emojis', [])[:3])}") + print(f"CTA: {response.instagram_content.get('cta', '')}") + + # نمایش محتوای تلگرام + if response.telegram_content: + print("\n💬 محتوای تلگرام:") + print(f"محتوا: {response.telegram_content.get('content', '')[:150]}...") + print(f"هشتگ‌ها: {', '.join(response.telegram_content.get('hashtags', [])[:5])}") + + # نمایش محتوای وب‌سایت + if response.website_content: + print("\n🌐 محتوای وب‌سایت:") + print(f"عنوان: {response.website_content.get('title', '')}") + print(f"توضیحات متا: {response.website_content.get('meta_description', '')}") + print(f"هدینگ‌ها: {', '.join(response.website_content.get('headings', [])[:3])}") + + # نمایش هشتگ‌های کلی + print(f"\n🏷️ هشتگ‌های پیشنهادی:") + print(f"{', '.join(response.hashtags[:10])}") + + # نمایش پیشنهادات بصری + print(f"\n🎨 پیشنهادات بصری:") + visual = response.visual_suggestions + print(f"سبک تصویر: {visual.get('image_style', '')}") + print(f"رنگ‌بندی: {', '.join(visual.get('color_scheme', [])[:3])}") + print(f"ترکیب‌بندی: {visual.get('composition', '')}") + if visual.get('video_duration'): + print(f"مدت ویدئو: {visual.get('video_duration')} ثانیه") + + # نمایش پیشنهادات CTA + print(f"\n🎯 پیشنهادات CTA:") + for i, cta in enumerate(response.cta_suggestions[:3], 1): + print(f"{i}. {cta}") + + # نمایش بهینه‌سازی SEO + if response.seo_optimization: + print(f"\n🔍 بهینه‌سازی SEO:") + seo = response.seo_optimization + print(f"عنوان SEO: {seo.get('title', '')}") + print(f"توضیحات متا: {seo.get('meta_description', '')}") + print(f"هدینگ‌های SEO: {', '.join(seo.get('headings', [])[:3])}") + + # نمایش نمونه زمان‌بندی + print("\n" + "=" * 60) + print("⏰ نمونه زمان‌بندی انتشار:") + + scheduler = ContentScheduler() + + # زمان‌بندی پست برای اینستاگرام + instagram_time = datetime.now() + timedelta(hours=2) + post_id = scheduler.schedule_post( + Platform.INSTAGRAM, + request, + instagram_time + ) + print(f"پست اینستاگرام در ساعت {instagram_time.strftime('%H:%M')} زمان‌بندی شد (ID: {post_id})") + + # زمان‌بندی پست برای تلگرام + telegram_time = datetime.now() + timedelta(hours=4) + post_id = scheduler.schedule_post( + Platform.TELEGRAM, + request, + telegram_time + ) + print(f"پست تلگرام در ساعت {telegram_time.strftime('%H:%M')} زمان‌بندی شد (ID: {post_id})") + + # نمایش پست‌های زمان‌بندی شده + scheduled_posts = scheduler.get_scheduled_posts() + print(f"\n📅 تعداد پست‌های زمان‌بندی شده: {len(scheduled_posts)}") + + for post in scheduled_posts: + print(f"- {post['platform']}: {post['publish_time']} (وضعیت: {post['status']})") + + print("\n🎉 نمونه استفاده با موفقیت اجرا شد!") + + except Exception as e: + print(f"\n❌ خطا: {str(e)}") + print("\nبرای رفع مشکل:") + print("1. مطمئن شوید GEMINI_API_KEY تنظیم شده است") + print("2. اتصال اینترنت خود را بررسی کنید") + print("3. نسخه‌های پکیج‌ها را بررسی کنید") + +def demo_simple_content(): + """نمونه ساده تولید محتوا""" + + print("\n🔧 نمونه ساده تولید محتوا:") + + try: + content_generator = ContentGenerator() + + # درخواست ساده + simple_request = ContentRequest( + topic="نکات موفقیت در کسب‌وکار", + keywords=["موفقیت", "کسب‌وکار", "نکات"], + target_audience="کارآفرینان", + tone=Tone.INSPIRATIONAL, + platforms=[Platform.INSTAGRAM], + include_visual_suggestions=False, + include_seo=False + ) + + print("درخواست: تولید محتوای الهام‌بخش برای اینستاگرام") + + response = content_generator.generate_content(simple_request) + + if response.instagram_content: + print(f"✅ کپشن تولید شد: {response.instagram_content.get('caption', '')[:100]}...") + print(f"🏷️ هشتگ‌ها: {', '.join(response.hashtags[:5])}") + + except Exception as e: + print(f"❌ خطا در نمونه ساده: {str(e)}") + +def demo_bulk_generation(): + """نمونه تولید انبوه محتوا""" + + print("\n📚 نمونه تولید انبوه محتوا:") + + topics = [ + "تکنیک‌های مدیریت زمان", + "راه‌های افزایش بهره‌وری", + "استراتژی‌های بازاریابی محتوا", + "نکات موفقیت در شبکه‌های اجتماعی" + ] + + try: + content_generator = ContentGenerator() + + for i, topic in enumerate(topics, 1): + print(f"\n{i}. تولید محتوا برای: {topic}") + + request = ContentRequest( + topic=topic, + keywords=[topic.split()[0], "موفقیت", "نکات"], + target_audience="کارآفرینان", + tone=Tone.PROFESSIONAL, + platforms=[Platform.INSTAGRAM, Platform.TELEGRAM], + include_visual_suggestions=False, + include_seo=False + ) + + response = content_generator.generate_content(request) + + if response.instagram_content: + caption = response.instagram_content.get('caption', '') + print(f" ✅ کپشن: {caption[:80]}...") + + if response.telegram_content: + content = response.telegram_content.get('content', '') + print(f" 💬 محتوا: {content[:80]}...") + + print(f"\n🎯 {len(topics)} محتوا با موفقیت تولید شد!") + + except Exception as e: + print(f"❌ خطا در تولید انبوه: {str(e)}") + +if __name__ == "__main__": + print("انتخاب کنید:") + print("1. اجرای کامل نمونه") + print("2. نمونه ساده") + print("3. تولید انبوه") + + try: + choice = input("انتخاب شما (1-3): ").strip() + + if choice == "1": + main() + elif choice == "2": + demo_simple_content() + elif choice == "3": + demo_bulk_generation() + else: + print("انتخاب نامعتبر. اجرای نمونه کامل...") + main() + + except KeyboardInterrupt: + print("\n\n👋 برنامه متوقف شد") + except Exception as e: + print(f"\n❌ خطای غیرمنتظره: {str(e)}") \ No newline at end of file diff --git a/gemini_client.py b/gemini_client.py new file mode 100644 index 0000000..de7a03c --- /dev/null +++ b/gemini_client.py @@ -0,0 +1,198 @@ +import google.generativeai as genai +from typing import Dict, Any, List +import json +from config import Config + +class GeminiClient: + def __init__(self): + if not Config.GEMINI_API_KEY: + raise ValueError("GEMINI_API_KEY is required") + + genai.configure(api_key=Config.GEMINI_API_KEY) + self.model = genai.GenerativeModel(Config.GEMINI_MODEL) + + # تعریف توابع برای Function Calling + self.functions = self._define_functions() + + def _define_functions(self) -> List[Dict[str, Any]]: + """تعریف توابع قابل فراخوانی برای Gemini""" + return [ + { + "name": "generate_content", + "description": "تولید محتوای متناسب با پلتفرم خاص", + "parameters": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "enum": ["instagram", "telegram", "website", "eitaa", "rubika"], + "description": "پلتفرم هدف" + }, + "content_type": { + "type": "string", + "enum": ["caption", "article", "post", "story"], + "description": "نوع محتوا" + }, + "main_text": { + "type": "string", + "description": "متن اصلی محتوا" + }, + "hashtags": { + "type": "array", + "items": {"type": "string"}, + "description": "هشتگ‌های مرتبط" + }, + "emojis": { + "type": "array", + "items": {"type": "string"}, + "description": "اموجی‌های مناسب" + }, + "cta": { + "type": "string", + "description": "فراخوان به عمل" + } + }, + "required": ["platform", "content_type", "main_text"] + } + }, + { + "name": "optimize_for_seo", + "description": "بهینه‌سازی محتوای وب‌سایت برای SEO", + "parameters": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "عنوان بهینه شده" + }, + "meta_description": { + "type": "string", + "description": "توضیحات متا" + }, + "headings": { + "type": "array", + "items": {"type": "string"}, + "description": "سرتیترهای H1, H2, H3" + }, + "keywords": { + "type": "array", + "items": {"type": "string"}, + "description": "کلمات کلیدی SEO" + } + }, + "required": ["title", "meta_description", "headings", "keywords"] + } + }, + { + "name": "generate_visual_idea", + "description": "تولید ایده بصری برای محتوا", + "parameters": { + "type": "object", + "properties": { + "image_style": { + "type": "string", + "description": "سبک تصویر" + }, + "color_scheme": { + "type": "array", + "items": {"type": "string"}, + "description": "رنگ‌بندی پیشنهادی" + }, + "composition": { + "type": "string", + "description": "ترکیب‌بندی تصویر" + }, + "video_duration": { + "type": "integer", + "description": "مدت ویدئو (ثانیه)" + }, + "video_style": { + "type": "string", + "description": "سبک ویدئو" + } + }, + "required": ["image_style", "color_scheme", "composition"] + } + } + ] + + def generate_content(self, prompt: str) -> Dict[str, Any]: + """تولید محتوا با استفاده از Gemini""" + try: + response = self.model.generate_content( + prompt, + generation_config={ + "temperature": 0.7, + "top_p": 0.8, + "top_k": 40, + }, + tools=self.functions + ) + + # پردازش پاسخ و استخراج فراخوانی توابع + if response.candidates and response.candidates[0].content: + content = response.candidates[0].content + + # بررسی فراخوانی توابع + if hasattr(content, 'parts') and content.parts: + for part in content.parts: + if hasattr(part, 'function_call'): + return self._process_function_call(part.function_call) + + # اگر تابعی فراخوانی نشده، متن معمولی برگردان + return {"text": content.text} + + return {"error": "پاسخ نامعتبر از Gemini"} + + except Exception as e: + return {"error": f"خطا در تولید محتوا: {str(e)}"} + + def _process_function_call(self, function_call) -> Dict[str, Any]: + """پردازش فراخوانی تابع""" + try: + function_name = function_call.name + arguments = json.loads(function_call.args) + + return { + "function_name": function_name, + "arguments": arguments, + "status": "success" + } + except Exception as e: + return { + "error": f"خطا در پردازش فراخوانی تابع: {str(e)}", + "status": "error" + } + + def generate_multi_platform_content(self, request_data: Dict[str, Any]) -> Dict[str, Any]: + """تولید محتوای چندپلتفرمی""" + prompt = self._create_content_prompt(request_data) + return self.generate_content(prompt) + + def _create_content_prompt(self, request_data: Dict[str, Any]) -> str: + """ایجاد پرومپت برای تولید محتوا""" + platforms = ", ".join(request_data.get("platforms", [])) + + prompt = f""" + شما یک سیستم هوش مصنوعی تولید محتوا هستید که باید برای پلتفرم‌های {platforms} محتوای بهینه تولید کنید. + + موضوع: {request_data.get('topic', '')} + کلمات کلیدی: {', '.join(request_data.get('keywords', []))} + مخاطب هدف: {request_data.get('target_audience', '')} + لحن: {request_data.get('tone', 'professional')} + زبان: {request_data.get('language', 'persian')} + + لطفاً برای هر پلتفرم محتوای مناسب تولید کنید و از توابع تعریف شده استفاده کنید: + 1. برای تولید محتوا از تابع generate_content استفاده کنید + 2. برای بهینه‌سازی SEO از تابع optimize_for_seo استفاده کنید + 3. برای ایده‌های بصری از تابع generate_visual_idea استفاده کنید + + خروجی باید شامل موارد زیر باشد: + - تحلیل موضوع و ایده‌پردازی + - محتوای اختصاصی برای هر پلتفرم + - هشتگ‌های پیشنهادی + - ایده‌های بصری + - پیشنهادات CTA + """ + + return prompt \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..52978e0 --- /dev/null +++ b/main.py @@ -0,0 +1,267 @@ +from fastapi import FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +import uvicorn +from typing import Dict, Any + +from models import ContentRequest, ContentResponse +from content_generator import ContentGenerator +from config import Config + +app = FastAPI( + title="سیستم تولید محتوای هوش مصنوعی چندپلتفرمی", + description="تولید محتوای بهینه برای اینستاگرام، تلگرام، وب‌سایت، ایتا و روبیکا", + version="1.0.0" +) + +# تنظیمات CORS +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# ایجاد نمونه از تولیدکننده محتوا +content_generator = ContentGenerator() + +@app.get("/", response_class=HTMLResponse) +async def root(): + """صفحه اصلی""" + return """ + + + + + + سیستم تولید محتوای هوش مصنوعی + + + +
+

🚀 سیستم تولید محتوای هوش مصنوعی چندپلتفرمی

+ +
+
+

📱 اینستاگرام

+

کپشن‌های جذاب و هشتگ‌های بهینه

+
+
+

💬 تلگرام

+

محتویات کامل و مفصل

+
+
+

🌐 وب‌سایت

+

محتوای SEO-friendly

+
+
+

📢 ایتا

+

محتویات مناسب شبکه اجتماعی

+
+
+

🎯 روبیکا

+

محتوای بهینه برای الگوریتم جدید

+
+
+ +
+

🔌 API Endpoints

+
POST /generate-content
+

تولید محتوای چندپلتفرمی

+
GET /health
+

بررسی وضعیت سیستم

+
+ +
+

✨ ویژگی‌های کلیدی

+
    +
  • تولید محتوای اختصاصی برای هر پلتفرم
  • +
  • بهینه‌سازی SEO برای وب‌سایت
  • +
  • تولید هشتگ‌های مرتبط و موثر
  • +
  • پیشنهادات بصری (تصویر و ویدئو)
  • +
  • پشتیبانی از Function Calling Gemini
  • +
  • زمان‌بندی انتشار خودکار
  • +
  • ترجمه چندزبانه
  • +
+
+
+ + + """ + +@app.post("/generate-content", response_model=ContentResponse) +async def generate_content(request: ContentRequest): + """تولید محتوای چندپلتفرمی""" + try: + # بررسی وجود API Key + if not Config.GEMINI_API_KEY: + raise HTTPException( + status_code=500, + detail="GEMINI_API_KEY تنظیم نشده است" + ) + + # تولید محتوا + response = content_generator.generate_content(request) + return response + + except Exception as e: + raise HTTPException( + status_code=500, + detail=f"خطا در تولید محتوا: {str(e)}" + ) + +@app.get("/health") +async def health_check(): + """بررسی وضعیت سیستم""" + return { + "status": "healthy", + "service": "AI Content Generation System", + "version": "1.0.0", + "gemini_api_configured": bool(Config.GEMINI_API_KEY) + } + +@app.get("/platforms") +async def get_platforms(): + """دریافت لیست پلتفرم‌های پشتیبانی شده""" + return { + "platforms": [ + { + "name": "instagram", + "display_name": "اینستاگرام", + "max_caption_length": Config.INSTAGRAM_MAX_CAPTION_LENGTH, + "features": ["کپشن", "هشتگ", "اموجی", "CTA"] + }, + { + "name": "telegram", + "display_name": "تلگرام", + "max_message_length": Config.TELEGRAM_MAX_MESSAGE_LENGTH, + "features": ["متن کامل", "هشتگ", "اموجی", "CTA"] + }, + { + "name": "website", + "display_name": "وب‌سایت", + "max_title_length": Config.WEBSITE_MAX_TITLE_LENGTH, + "features": ["SEO", "هدینگ", "متاتگ", "کلمات کلیدی"] + }, + { + "name": "eitaa", + "display_name": "ایتا", + "features": ["متن کامل", "هشتگ", "اموجی", "CTA"] + }, + { + "name": "rubika", + "display_name": "روبیکا", + "features": ["متن کوتاه", "هشتگ", "اموجی", "CTA"] + } + ] + } + +@app.get("/tones") +async def get_tones(): + """دریافت لیست لحن‌های پشتیبانی شده""" + return { + "tones": [ + {"name": "professional", "display_name": "حرفه‌ای"}, + {"name": "friendly", "display_name": "دوستانه"}, + {"name": "casual", "display_name": "غیررسمی"}, + {"name": "formal", "display_name": "رسمی"}, + {"name": "creative", "display_name": "خلاقانه"}, + {"name": "inspirational", "display_name": "الهام‌بخش"} + ] + } + +if __name__ == "__main__": + uvicorn.run( + "main:app", + host="0.0.0.0", + port=8000, + reload=True, + log_level="info" + ) \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 0000000..a7e6187 --- /dev/null +++ b/models.py @@ -0,0 +1,60 @@ +from pydantic import BaseModel, Field +from typing import List, Optional, Dict, Any +from enum import Enum + +class Platform(str, Enum): + INSTAGRAM = "instagram" + TELEGRAM = "telegram" + WEBSITE = "website" + EITAA = "eitaa" + RUBIKA = "rubika" + +class Tone(str, Enum): + PROFESSIONAL = "professional" + FRIENDLY = "friendly" + CASUAL = "casual" + FORMAL = "formal" + CREATIVE = "creative" + INSPIRATIONAL = "inspirational" + +class ContentRequest(BaseModel): + topic: str = Field(..., description="موضوع اصلی محتوا") + keywords: List[str] = Field(..., description="کلمات کلیدی") + target_audience: str = Field(..., description="مخاطب هدف") + tone: Tone = Field(default=Tone.PROFESSIONAL, description="لحن محتوا") + platforms: List[Platform] = Field(..., description="پلتفرم‌های هدف") + language: str = Field(default="persian", description="زبان محتوا") + include_visual_suggestions: bool = Field(default=True, description="شامل پیشنهادات بصری") + include_seo: bool = Field(default=False, description="شامل بهینه‌سازی SEO") + +class ContentResponse(BaseModel): + topic_analysis: Dict[str, Any] = Field(..., description="تحلیل موضوع") + instagram_content: Optional[Dict[str, str]] = Field(None, description="محتوای اینستاگرام") + telegram_content: Optional[Dict[str, str]] = Field(None, description="محتوای تلگرام") + website_content: Optional[Dict[str, str]] = Field(None, description="محتوای وب‌سایت") + eitaa_content: Optional[Dict[str, str]] = Field(None, description="محتوای ایتا") + rubika_content: Optional[Dict[str, str]] = Field(None, description="محتوای روبیکا") + hashtags: List[str] = Field(..., description="هشتگ‌های پیشنهادی") + visual_suggestions: Dict[str, Any] = Field(..., description="پیشنهادات بصری") + cta_suggestions: List[str] = Field(..., description="پیشنهادات CTA") + seo_optimization: Optional[Dict[str, str]] = Field(None, description="بهینه‌سازی SEO") + +class PlatformContent(BaseModel): + caption: str = Field(..., description="متن اصلی") + hashtags: List[str] = Field(..., description="هشتگ‌ها") + emojis: List[str] = Field(..., description="اموجی‌ها") + cta: str = Field(..., description="فراخوان به عمل") + +class WebsiteContent(BaseModel): + title: str = Field(..., description="عنوان صفحه") + meta_description: str = Field(..., description="توضیحات متا") + content: str = Field(..., description="محتوای اصلی") + headings: List[str] = Field(..., description="سرتیترها") + keywords: List[str] = Field(..., description="کلمات کلیدی SEO") + +class VisualSuggestion(BaseModel): + image_style: str = Field(..., description="سبک تصویر") + color_scheme: List[str] = Field(..., description="رنگ‌بندی") + composition: str = Field(..., description="ترکیب‌بندی") + video_duration: Optional[int] = Field(None, description="مدت ویدئو") + video_style: Optional[str] = Field(None, description="سبک ویدئو") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c37ca7c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +fastapi>=0.104.0 +uvicorn>=0.24.0 +google-generativeai>=0.3.0 +python-dotenv>=1.0.0 +pydantic>=2.0.0 +requests>=2.31.0 +python-multipart>=0.0.6 +jinja2>=3.1.0 +aiofiles>=23.0.0 +python-dateutil>=2.8.0 +schedule>=1.2.0 \ No newline at end of file diff --git a/scheduler.py b/scheduler.py new file mode 100644 index 0000000..25a24cc --- /dev/null +++ b/scheduler.py @@ -0,0 +1,243 @@ +import schedule +import time +import threading +from datetime import datetime, timedelta +from typing import Dict, Any, List, Optional +from models import Platform, ContentRequest +from content_generator import ContentGenerator +import json +import logging + +# تنظیم لاگینگ +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +class ContentScheduler: + def __init__(self): + self.content_generator = ContentGenerator() + self.scheduled_posts = {} + self.is_running = False + + def schedule_post(self, + platform: Platform, + content_request: ContentRequest, + publish_time: datetime, + post_id: Optional[str] = None) -> str: + """زمان‌بندی انتشار پست""" + + if not post_id: + post_id = f"post_{int(time.time())}" + + # تولید محتوا + try: + content_response = self.content_generator.generate_content(content_request) + + # ذخیره اطلاعات پست زمان‌بندی شده + scheduled_post = { + "post_id": post_id, + "platform": platform, + "content_request": content_request.dict(), + "content_response": content_response.dict(), + "publish_time": publish_time.isoformat(), + "status": "scheduled", + "created_at": datetime.now().isoformat() + } + + self.scheduled_posts[post_id] = scheduled_post + + # زمان‌بندی انتشار + schedule.every().day.at(publish_time.strftime("%H:%M")).do( + self._publish_post, post_id + ).tag(post_id) + + logger.info(f"پست {post_id} برای {platform} در ساعت {publish_time} زمان‌بندی شد") + return post_id + + except Exception as e: + logger.error(f"خطا در زمان‌بندی پست: {str(e)}") + raise + + def schedule_recurring_posts(self, + platform: Platform, + content_request: ContentRequest, + interval_hours: int, + start_time: datetime, + end_time: Optional[datetime] = None) -> List[str]: + """زمان‌بندی پست‌های تکرارشونده""" + + post_ids = [] + current_time = start_time + + while True: + if end_time and current_time > end_time: + break + + post_id = f"recurring_{int(current_time.timestamp())}" + self.schedule_post(platform, content_request, current_time, post_id) + post_ids.append(post_id) + + current_time += timedelta(hours=interval_hours) + + # محدودیت تعداد پست‌ها + if len(post_ids) >= 100: + break + + return post_ids + + def schedule_platform_specific_posts(self, + content_request: ContentRequest, + platform_schedule: Dict[Platform, List[datetime]]) -> Dict[Platform, List[str]]: + """زمان‌بندی پست‌ها برای پلتفرم‌های مختلف""" + + platform_post_ids = {} + + for platform, publish_times in platform_schedule.items(): + post_ids = [] + for publish_time in publish_times: + post_id = f"{platform}_{int(publish_time.timestamp())}" + self.schedule_post(platform, content_request, publish_time, post_id) + post_ids.append(post_id) + + platform_post_ids[platform] = post_ids + + return platform_post_ids + + def _publish_post(self, post_id: str): + """انتشار پست زمان‌بندی شده""" + + if post_id not in self.scheduled_posts: + logger.warning(f"پست {post_id} یافت نشد") + return + + post_data = self.scheduled_posts[post_id] + + try: + # اینجا می‌توانید کد انتشار واقعی را اضافه کنید + # مثلاً ارسال به API پلتفرم‌ها + + logger.info(f"انتشار پست {post_id} برای {post_data['platform']}") + + # بروزرسانی وضعیت + post_data["status"] = "published" + post_data["published_at"] = datetime.now().isoformat() + + # حذف از زمان‌بندی + schedule.clear(post_id) + + except Exception as e: + logger.error(f"خطا در انتشار پست {post_id}: {str(e)}") + post_data["status"] = "failed" + post_data["error"] = str(e) + + def cancel_post(self, post_id: str) -> bool: + """لغو پست زمان‌بندی شده""" + + if post_id not in self.scheduled_posts: + return False + + try: + # حذف از زمان‌بندی + schedule.clear(post_id) + + # بروزرسانی وضعیت + self.scheduled_posts[post_id]["status"] = "cancelled" + self.scheduled_posts[post_id]["cancelled_at"] = datetime.now().isoformat() + + logger.info(f"پست {post_id} لغو شد") + return True + + except Exception as e: + logger.error(f"خطا در لغو پست {post_id}: {str(e)}") + return False + + def get_scheduled_posts(self, + platform: Optional[Platform] = None, + status: Optional[str] = None) -> List[Dict[str, Any]]: + """دریافت لیست پست‌های زمان‌بندی شده""" + + posts = list(self.scheduled_posts.values()) + + if platform: + posts = [p for p in posts if p["platform"] == platform] + + if status: + posts = [p for p in posts if p["status"] == status] + + return sorted(posts, key=lambda x: x["publish_time"]) + + def get_post_status(self, post_id: str) -> Optional[Dict[str, Any]]: + """دریافت وضعیت پست خاص""" + return self.scheduled_posts.get(post_id) + + def start_scheduler(self): + """شروع زمان‌بند""" + if self.is_running: + logger.warning("زمان‌بند در حال اجرا است") + return + + self.is_running = True + logger.info("زمان‌بند شروع شد") + + def run_scheduler(): + while self.is_running: + schedule.run_pending() + time.sleep(1) + + # اجرای زمان‌بند در thread جداگانه + scheduler_thread = threading.Thread(target=run_scheduler, daemon=True) + scheduler_thread.start() + + def stop_scheduler(self): + """توقف زمان‌بند""" + self.is_running = False + schedule.clear() + logger.info("زمان‌بند متوقف شد") + + def export_schedule(self, file_path: str): + """صادرات زمان‌بندی به فایل JSON""" + try: + with open(file_path, 'w', encoding='utf-8') as f: + json.dump(self.scheduled_posts, f, ensure_ascii=False, indent=2) + logger.info(f"زمان‌بندی به {file_path} صادر شد") + except Exception as e: + logger.error(f"خطا در صادرات زمان‌بندی: {str(e)}") + + def import_schedule(self, file_path: str): + """واردات زمان‌بندی از فایل JSON""" + try: + with open(file_path, 'r', encoding='utf-8') as f: + imported_posts = json.load(f) + + # پاک کردن زمان‌بندی فعلی + schedule.clear() + self.scheduled_posts.clear() + + # واردات پست‌های جدید + for post_id, post_data in imported_posts.items(): + if post_data["status"] == "scheduled": + publish_time = datetime.fromisoformat(post_data["publish_time"]) + schedule.every().day.at(publish_time.strftime("%H:%M")).do( + self._publish_post, post_id + ).tag(post_id) + + self.scheduled_posts[post_id] = post_data + + logger.info(f"زمان‌بندی از {file_path} وارد شد") + + except Exception as e: + logger.error(f"خطا در واردات زمان‌بندی: {str(e)}") + +# نمونه استفاده +if __name__ == "__main__": + scheduler = ContentScheduler() + + # شروع زمان‌بند + scheduler.start_scheduler() + + try: + # نگه داشتن برنامه در حال اجرا + while True: + time.sleep(1) + except KeyboardInterrupt: + scheduler.stop_scheduler() + print("زمان‌بند متوقف شد") \ No newline at end of file diff --git a/test_system.py b/test_system.py new file mode 100644 index 0000000..7fa5f89 --- /dev/null +++ b/test_system.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +تست ساده سیستم تولید محتوای هوش مصنوعی +""" + +import os +import sys +from models import ContentRequest, Platform, Tone + +def test_models(): + """تست مدل‌های داده""" + print("🧪 تست مدل‌های داده...") + + try: + # تست ایجاد درخواست + request = ContentRequest( + topic="تست سیستم", + keywords=["تست", "سیستم"], + target_audience="توسعه‌دهندگان", + tone=Tone.PROFESSIONAL, + platforms=[Platform.INSTAGRAM, Platform.TELEGRAM], + include_visual_suggestions=True, + include_seo=False + ) + + print("✅ ContentRequest ایجاد شد") + print(f" موضوع: {request.topic}") + print(f" پلتفرم‌ها: {[p.value for p in request.platforms]}") + print(f" لحن: {request.tone.value}") + + # تست تبدیل به دیکشنری + request_dict = request.dict() + print("✅ تبدیل به دیکشنری موفق") + + return True + + except Exception as e: + print(f"❌ خطا در تست مدل‌ها: {str(e)}") + return False + +def test_config(): + """تست تنظیمات""" + print("\n⚙️ تست تنظیمات...") + + try: + from config import Config + + print("✅ فایل تنظیمات بارگذاری شد") + print(f" مدل Gemini: {Config.GEMINI_MODEL}") + print(f" حداکثر طول کپشن اینستاگرام: {Config.INSTAGRAM_MAX_CAPTION_LENGTH}") + print(f" حداکثر هشتگ: {Config.MAX_HASHTAGS}") + + return True + + except Exception as e: + print(f"❌ خطا در تست تنظیمات: {str(e)}") + return False + +def test_imports(): + """تست import کردن ماژول‌ها""" + print("\n📦 تست import کردن ماژول‌ها...") + + try: + # تست import کردن ماژول‌های اصلی + from content_generator import ContentGenerator + print("✅ ContentGenerator import شد") + + from gemini_client import GeminiClient + print("✅ GeminiClient import شد") + + from scheduler import ContentScheduler + print("✅ ContentScheduler import شد") + + return True + + except Exception as e: + print(f"❌ خطا در import: {str(e)}") + return False + +def test_environment(): + """تست محیط اجرا""" + print("\n🌍 تست محیط اجرا...") + + try: + # بررسی Python version + python_version = sys.version_info + print(f"✅ Python {python_version.major}.{python_version.minor}.{python_version.micro}") + + # بررسی وجود فایل‌های اصلی + required_files = [ + "main.py", + "models.py", + "content_generator.py", + "gemini_client.py", + "scheduler.py", + "config.py" + ] + + for file in required_files: + if os.path.exists(file): + print(f"✅ {file} موجود است") + else: + print(f"❌ {file} یافت نشد") + return False + + # بررسی وجود فایل requirements.txt + if os.path.exists("requirements.txt"): + print("✅ requirements.txt موجود است") + else: + print("❌ requirements.txt یافت نشد") + return False + + return True + + except Exception as e: + print(f"❌ خطا در تست محیط: {str(e)}") + return False + +def main(): + """تابع اصلی تست""" + print("🚀 شروع تست سیستم تولید محتوای هوش مصنوعی") + print("=" * 60) + + tests = [ + test_environment, + test_imports, + test_config, + test_models + ] + + passed = 0 + total = len(tests) + + for test in tests: + if test(): + passed += 1 + print() + + print("=" * 60) + print(f"📊 نتایج تست: {passed}/{total} تست موفق") + + if passed == total: + print("🎉 تمام تست‌ها با موفقیت انجام شد!") + print("\n✅ سیستم آماده استفاده است") + print("\nبرای اجرای سیستم:") + print("1. فایل .env را ایجاد کرده و GEMINI_API_KEY را اضافه کنید") + print("2. دستور 'python main.py' را اجرا کنید") + print("3. یا از 'python example_usage.py' برای نمونه استفاده کنید") + else: + print("❌ برخی تست‌ها ناموفق بودند") + print("\nبرای رفع مشکل:") + print("1. مطمئن شوید تمام فایل‌ها موجود هستند") + print("2. وابستگی‌ها را با 'pip install -r requirements.txt' نصب کنید") + print("3. خطاهای Python را بررسی کنید") + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("\n\n👋 تست متوقف شد") + except Exception as e: + print(f"\n❌ خطای غیرمنتظره: {str(e)}") + print("لطفاً مشکل را بررسی کرده و دوباره تلاش کنید") \ No newline at end of file