import gradio as gr import requests import os import json from datetime import datetime import re from pathlib import Path import uuid # === CONFIG === STORAGE_DIR = Path("journal_data") STORAGE_DIR.mkdir(exist_ok=True) HISTORY_FILE = STORAGE_DIR / "history.json" API_KEY = os.getenv("GROQ_API_KEY") API_URL = "https://api.groq.com/openai/v1/chat/completions" MODEL = "gemma2-9b-it" # === MEMORY: Load history === def load_history(): if HISTORY_FILE.exists(): try: with open(HISTORY_FILE, 'r', encoding='utf-8') as f: return json.load(f) except: pass return [] def save_history(history): with open(HISTORY_FILE, 'w', encoding='utf-8') as f: json.dump(history[-100:], f, indent=2, ensure_ascii=False) # Simpen 100 terakhir chat_history = load_history() current_session = str(uuid.uuid4()) # === Smart Summary Generator === def generate_summary(messages): if not messages: return "User baru mulai ngobrol." user_msgs = [m for m in messages if m['role'] == 'user'] topics = [m['topic'] for m in user_msgs[-5:]] main_topic = max(set(topics), key=topics.count) if topics else "general" # Emosi kasar pos = sum(1 for m in user_msgs[-3:] if any(w in m['content'].lower() for w in ['senang', 'semangat', 'baik'])) neg = sum(1 for m in user_msgs[-3:] if any(w in m['content'].lower() for w in ['capek', 'sedih', 'gagal'])) mood = "positif" if pos > neg else "negatif" if neg > pos else "netral" # Gaya bicara style = "kasual" if any('gue' in m['content'].lower() or 'anjir' in m['content'].lower() for m in user_msgs[-2:]) else "formal" return f""" Topik utama: {main_topic} Mood: {mood} Gaya: {style} Catatan: Validasi emosi dulu, hindari klise, akhiri dengan pertanyaan terbuka. """.strip() # === Deteksi Gaya Khusus (Tom Schreiter, dll) === def detect_style_instruction(content): content = content.lower() if "gaya schreiter" in content: return "Tom Schreiter: pendek, ngena, Mini-Stories, empati, efektif." if "gaya henneke" in content: return "Henneke Duistermaat: hangat, relatable, humor halus." if "gaya ogilvy" in content: return "David Ogilvy: elegan, persuasive, storytelling memikat." if "gaya halbert" in content: return "Gary Halbert: bold, direct, seperti surat penjualan." if "gaya rohn" in content: return "Jim Rohn: inspiratif, penuh wisdom." if "gaya lao tzu" in content: return "Lao Tzu: filosofis, minimalis, tenang." return "santai, cerdas, kayak ngobrol sama world-class mentor." # === Kirim ke Groq + Context Ringan === def groq_respond(message, topic): if not message.strip(): return "❌ Isi pesannya dulu.", "" if not API_KEY: return "❌ GROQ_API_KEY belum diset.", "" global chat_history, current_session # Simpan user message user_msg = { "role": "user", "content": message.strip(), "topic": topic, "timestamp": datetime.now().isoformat(), "session_id": current_session } chat_history.append(user_msg) # Buat context: system + summary + 2 terakhir summary = generate_summary(chat_history) style_instruction = detect_style_instruction(message) recent = chat_history[-2:] # Cuma 2 terakhir messages = [ { "role": "system", "content": f"""Kamu adalah Deepseek-Mentor. Prinsip: 1. Validasi emosi dulu sebelum solusi. 2. Hindari jawaban generik — tanya balik yang mendalam. 3. Sesuaikan gaya: {style_instruction} 4. Akhiri dengan pertanyaan terbuka yang mengajak bertindak. 5. Jangan jadi motivator klise. Jadi teman yang kompeten. [MEMORY] {summary} """.strip() } ] + [{"role": m["role"], "content": m["content"]} for m in recent] try: resp = requests.post( API_URL, headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}, json={ "model": MODEL, "messages": messages, "max_tokens": 1024, "temperature": 0.9, "top_p": 0.95, "presence_penalty": 0.8, "frequency_penalty": 0.7 }, timeout=30 ) resp.raise_for_status() ai_msg = resp.json()["choices"][0]["message"]["content"] # Simpan response chat_history.append({ "role": "assistant", "content": ai_msg, "topic": topic, "timestamp": datetime.now().isoformat(), "session_id": current_session }) save_history(chat_history) return ai_msg, "" except Exception as e: return f"❌ Error: {str(e)}", "" # === Gradio UI === with gr.Blocks(title="🧠 AI Journal Paling Keren Sedunia", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🧠 AI Journal Paling Keren Sedunia") gr.Markdown("Minimalis. Pintar. Nyambung. Input token < 300, tapi tetap kayak ngobrol beneran.") with gr.Tab("💬 Chat"): response = gr.Textbox(label="🤖 AI", lines=10, interactive=False, show_copy_button=True) user_input = gr.Textbox(label="✍️ Kamu", placeholder="Apa yang kamu rasakan sekarang?", lines=3) topic_input = gr.Textbox(label="🏷️ Topik", value="journal", placeholder="e.g., produktivitas, hubungan") send_btn = gr.Button("🚀 Kirim") with gr.Tab("📚 Riwayat"): history_display = gr.Textbox(label="Riwayat", lines=15, interactive=False, show_copy_button=True) refresh_btn = gr.Button("🔄 Muat Ulang") with gr.Tab("📊 Ringkasan"): summary_display = gr.Textbox(label="Insight", lines=10, interactive=False) gen_summary_btn = gr.Button("🔮 Buat Ringkasan") # Actions send_btn.click(groq_respond, [user_input, topic_input], [response, user_input]) refresh_btn.click(lambda: "\n\n".join(f"[{m['timestamp'][:10]}] {m['role']}: {m['content']}" for m in chat_history[-20:]), None, history_display) gen_summary_btn.click(lambda: generate_summary(chat_history), None, summary_display) # Jalanin if __name__ == "__main__": demo.launch()