import os import streamlit as st from openai import OpenAI from dotenv import load_dotenv from reportlab.pdfgen import canvas import base64 from token_optimizer import optimize_prompt # ------------------------ # 🔑 تنظیم کلاینت OpenAI-compatible (Hugging Face) # ------------------------ load_dotenv() client = OpenAI( base_url=os.getenv("OPENROUTER_BASE_URL"), api_key=os.getenv("OPENROUTER_API_KEY") ) # ------------------------ # 🎨 استایل اختیاری # ------------------------ with open("src/theme.css") as f: st.markdown(f"", unsafe_allow_html=True) # ------------------------ # Page setup # ------------------------ st.set_page_config(page_title="AI Article Writer", page_icon="🧠", layout="centered") st.title("🧠 AI Article Writer") st.subheader("تولید مقاله حرفه‌ای با هوش مصنوعی") st.divider() # ------------------------ # Inputs # ------------------------ topic = st.text_input("موضوع مقاله:",key="topic_input", placeholder="مثلاً تاثیر هوش مصنوعی بر آموزش...") tone = st.selectbox("لحن مقاله:", ["علمی", "غیررسمی", "تخصصی", "داستانی", "تحلیلی", "احساسی", "طنزآمیز ", "ژورنالیستی"], key="tone_select") language = st.selectbox("زبان مقاله:", ["فارسی", "انگلیسی"], key="lang_select") length = st.select_slider("طول مقاله(پاراگراف):", options=list(range(1,11)), value=3, key="length_slider") # 1 to 10 scale keywords = st.text_input("کلمات کلیدی (اختیاری):",key="keywords_input", placeholder="مثلاً آموزش، فناوری، هوش مصنوعی...") references_num = st.number_input("تعداد منابع مورد استفاده (اختیاری):", 0, 5, 1, key="ref_num") references_condition = st.text_input("شرایط منابع (اختیاری):",key="ref_cond", placeholder="مثلاً منابع معتبر و به‌روز...") st.divider() # ------------------------ # Model selection # ------------------------ model_options = { "🦾 مدل بزرگ، مناسب تولید محتوای باکیفیت و خلاقانه (Meta-Llama Maverick)": "meta-llama/llama-4-maverick:free", "✍️ مدل 24B، مناسب مقاله‌نویسی و متن‌های طولانی با انسجام بالا (Mistral-Small 3.2)": "mistralai/mistral-small-3.2-24b-instruct:free", "🚀 مدل خیلی بزرگ، مناسب کارهای سنگین، تحلیل عمیق و تولید محتوای حرفه‌ای (Hermes 405B)": "nousresearch/hermes-3-llama-3.1-405b:free", "⚡ سریع و سبک، مناسب متن‌نویسی روزمره و پاسخ‌های کوتاه (DeepHermes 8B)": "nousresearch/deephermes-3-llama-3-8b-preview:free", # "nvidia/nemotron-nano-12b-v2-vl:free":"nvidia/nemotron-nano-12b-v2-vl:free", # "minimax/minimax-m2:free":"minimax/minimax-m2:free", } selected_label = st.selectbox("مدل مورد استفاده:", list(model_options.keys()), key="model_label_select") model_name = model_options[selected_label] # ------------------------ # Advanced settings # ------------------------ with st.expander("⚙️ تنظیمات پیشرفته (برای کاربران حرفه‌ای)", expanded=False): st.caption("در صورت نیاز می‌توانید تنظیمات مدل را تغییر دهید:") temperature = st.slider("میزان خلاقیت مدل (Temperature)", 0.1, 1.0, 0.3) max_tokens = st.slider("حداکثر تعداد توکن خروجی", 200, 2000, 800) st.divider() # ------------------------ # Generate button # ------------------------ if st.button("✍️ تولید مقاله"): if not topic.strip(): st.warning("لطفاً موضوع مقاله را وارد کنید 🌱") else: with st.spinner("در حال تولید مقاله..."): prompt = f""" You are an expert human writer and researcher. With'{references_condition}' on your mind, and using '{references_num}' credible sources if needed, Write a high-quality, well-researched article in '{language}' with a '{tone}' tone about the topic: '{topic}'. Requirements: - Follow SEO principles and naturally include these keywords if relevant: '{keywords}' - Structure: 1️⃣ A compelling title 2️⃣ An engaging introduction with a hook 3️⃣ Multiple well-organized paragraphs with clear subheaders 4️⃣ Examples, recent insights, or credible statistics when useful 5️⃣ A strong conclusion with a key takeaway - Style: - Human-like, smooth, and conversational writing (not robotic) - No hallucinated facts — ensure clarity and accuracy - Avoid repetition and filler content - Maintain logical flow and readability Length: - Write a '{length}' paragraph article. References: - If '{references_num}' > 0, include '{references_num}' credible sources or references at the end. Make the content professional, coherent, informative, and enjoyable to read. """ # بهینه‌سازی پرامپت قبل از ارسال به مدل prompt = optimize_prompt(prompt) try: response = client.chat.completions.create( model=model_name, messages=[ {"role": "system", "content": "You are a professional article writer."}, {"role": "user", "content": prompt} ], temperature=temperature, max_tokens=max_tokens ) article_text = response.choices[0].message.content st.success("✅ مقاله تولید شد:") st.text_area("📄 متن مقاله:", value=article_text, height=400) # ✅ دکمه دانلود TXT b64 = base64.b64encode(article_text.encode()).decode() href = f'📥 دانلود نسخه متنی' st.markdown(href, unsafe_allow_html=True) # ✅ دکمه دانلود PDF # ✅ ذخیره مقاله تولیدشده در حافظه موقت Session if "articles_session" not in st.session_state: st.session_state.articles_session = [] st.session_state.articles_session.append({ "topic": st.session_state.get("topic_input", topic), "tone": st.session_state.get("tone_select", tone), "language": st.session_state.get("lang_select", language), "length": st.session_state.get("length_slider", length), "keywords": st.session_state.get("keywords_input", keywords), "references_num": st.session_state.get("ref_num", references_num), "references_condition": st.session_state.get("ref_cond", references_condition), "model_label": st.session_state.get("model_label_select", selected_label), "content": article_text, }) st.info(f"📌 مقاله ذخیره شد — تعداد {len(st.session_state.articles_session)} مورد") except Exception as e: st.error(f"⚠️ خطا در فراخوانی مدل: {e}") # 🗂️ نمایش نتایج قبلی (موقت) if st.session_state.get("articles_session"): st.subheader("🗂️ نتایج قبلی (تا زمان بسته شدن صفحه)") for i, item in enumerate(st.session_state.articles_session): with st.expander(f"📄 مقاله {i+1}: {item['topic']}"): st.markdown(f"**موضوع:** {item['topic']}") st.markdown(f"**لحن:** {item['tone']}") st.markdown(f"**زبان:** {item['language']}") st.markdown(f"**طول مقاله:** {item['length']} پاراگراف") st.markdown(f"**کلمات کلیدی:** {item['keywords']}") st.markdown(f"**تعداد منابع:** {item['references_num']}") st.markdown(f"**شرایط منابع:** {item['references_condition']}") st.markdown(f"**مدل استفاده شده:** {item['model_label']}") st.markdown("---") st.write(item["content"]) # 🧭 اجرا: # streamlit run src/article_writer.py