Code prompts

Romantic Novel Writing Assistant in Python

Local romantic novel writing assistant.

Example code

Python
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox, filedialog
import json
import os
from datetime import datetime
import shutil
import threading
import time
import hashlib
from pathlib import Path
import zipfile

class NovelWritingAssistant:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Elysium • Romantic Novel Assistant")
        self.root.geometry("1200x800")
        self.root.configure(bg="#1a1a2e")
        
        # Create directories
        self.stories_dir = Path("stories")
        self.backup_dir = Path("backups")
        self.stories_dir.mkdir(exist_ok=True)
        self.backup_dir.mkdir(exist_ok=True)
        
        self.current_story = None
        self.current_file = None
        self.auto_save_timer = None
        self.last_save_hash = ""
        
        self.setup_ui()
        self.load_stories_list()
        self.start_auto_backup_thread()
        
    def setup_ui(self):
        # Style
        style = ttk.Style()
        style.theme_use('clam')
        style.configure("TFrame", background="#1a1a2e")
        style.configure("TLabel", background="#1a1a2e", foreground="#e0e0ff")
        style.configure("TButton", background="#4a3f8c", foreground="#e0e0ff")
        style.configure("Treeview", background="#16213e", foreground="#e0e0ff", fieldbackground="#16213e")
        
        # Main paned window
        self.paned = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        self.paned.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # Left sidebar - Story Library
        left_frame = ttk.Frame(self.paned, width=280)
        self.paned.add(left_frame, weight=1)
        
        ttk.Label(left_frame, text="✦ STORY LIBRARY ✦", font=("Georgia", 14, "bold")).pack(pady=15)
        
        # New story button
        ttk.Button(left_frame, text="✎ New Romantic Tale", command=self.new_story).pack(fill=tk.X, padx=15, pady=8)
        
        # Stories list
        self.stories_list = tk.Listbox(left_frame, bg="#16213e", fg="#a0a0ff", font=("Georgia", 11), selectbackground="#6b5fb8")
        self.stories_list.pack(fill=tk.BOTH, expand=True, padx=15, pady=8)
        self.stories_list.bind('<<ListboxSelect>>', self.load_selected_story)
        
        # Right side - Editor
        right_frame = ttk.Frame(self.paned)
        self.paned.add(right_frame, weight=4)
        
        # Title area
        title_frame = ttk.Frame(right_frame)
        title_frame.pack(fill=tk.X, padx=20, pady=15)
        
        ttk.Label(title_frame, text="Title:", font=("Georgia", 12)).pack(side=tk.LEFT)
        self.title_entry = tk.Entry(title_frame, font=("Georgia", 16, "italic"), bg="#0f0f1f", fg="#ff99cc", insertbackground="#ff99cc", relief=tk.FLAT, highlightthickness=2, highlightcolor="#6b5fb8")
        self.title_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=10)
        self.title_entry.bind("<KeyRelease>", self.on_content_change)
        
        # Metadata
        meta_frame = ttk.Frame(right_frame)
        meta_frame.pack(fill=tk.X, padx=20, pady=(0,10))
        
        self.status_label = ttk.Label(meta_frame, text="Ready • Romantic Ambiguity Mode", font=("Georgia", 10), foreground="#88ffaa")
        self.status_label.pack(side=tk.LEFT)
        
        self.word_count_label = ttk.Label(meta_frame, text="Words: 0", font=("Georgia", 10))
        self.word_count_label.pack(side=tk.RIGHT)
        
        # Main editor
        editor_frame = ttk.Frame(right_frame)
        editor_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=5)
        
        self.editor = scrolledtext.ScrolledText(
            editor_frame,
            wrap=tk.WORD,
            font=("Georgia", 13),
            bg="#0f0f1f",
            fg="#e6d5ff",
            insertbackground="#ff99cc",
            selectbackground="#6b5fb8",
            relief=tk.FLAT,
            padx=15,
            pady=15
        )
        self.editor.pack(fill=tk.BOTH, expand=True)
        self.editor.bind("<KeyRelease>", self.on_content_change)
        
        # Toolbar
        toolbar = ttk.Frame(right_frame)
        toolbar.pack(fill=tk.X, padx=20, pady=10)
        
        ttk.Button(toolbar, text="💾 Save Now", command=self.save_current).pack(side=tk.LEFT, padx=5)
        ttk.Button(toolbar, text="📂 Export as TXT", command=self.export_story).pack(side=tk.LEFT, padx=5)
        ttk.Button(toolbar, text="📦 Create Backup", command=self.manual_backup).pack(side=tk.LEFT, padx=5)
        ttk.Button(toolbar, text="🗑️ Delete Story", command=self.delete_current).pack(side=tk.LEFT, padx=5)
        
        # Footer with romantic touch
        footer = tk.Frame(self.root, bg="#1a1a2e")
        footer.pack(fill=tk.X, padx=10, pady=8)
        
        tk.Label(footer, text="Elysium • A safe sanctuary for your most tender, ambiguous, and passionate romantic stories • Auto-backup enabled", 
                fg="#776699", bg="#1a1a2e", font=("Georgia", 9, "italic")).pack()
        
        # Keyboard shortcuts
        self.root.bind("<Control-s>", lambda e: self.save_current())
        self.root.bind("<Control-n>", lambda e: self.new_story())
        
        self.update_word_count()
    
    def load_stories_list(self):
        self.stories_list.delete(0, tk.END)
        for file in self.stories_dir.glob("*.json"):
            try:
                with open(file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    title = data.get('title', file.stem)
                    self.stories_list.insert(tk.END, f"❤️ {title}")
            except:
                self.stories_list.insert(tk.END, f"❤️ {file.stem}")
    
    def new_story(self):
        self.current_file = None
        self.current_story = {
            "title": "Untitled Romantic Encounter",
            "content": "Begin your story here...\n\nLet the tension build slowly. The stolen glances. The words left unsaid. The electricity between two souls who shouldn't want each other... but do.\n\n",
            "created": datetime.now().isoformat(),
            "last_modified": datetime.now().isoformat(),
            "genre": "Romantic Ambiguity"
        }
        self.title_entry.delete(0, tk.END)
        self.title_entry.insert(0, self.current_story["title"])
        self.editor.delete("1.0", tk.END)
        self.editor.insert("1.0", self.current_story["content"])
        self.status_label.config(text="New story started • All content saved locally and encrypted in spirit")
        self.update_word_count()
    
    def load_selected_story(self, event=None):
        selection = self.stories_list.curselection()
        if not selection:
            return
        item = self.stories_list.get(selection[0])
        title = item.replace("❤️ ", "").strip()
        
        for file in self.stories_dir.glob("*.json"):
            try:
                with open(file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    if data.get('title') == title or file.stem == title:
                        self.current_file = file
                        self.current_story = data
                        self.title_entry.delete(0, tk.END)
                        self.title_entry.insert(0, self.current_story.get('title', 'Untitled'))
                        self.editor.delete("1.0", tk.END)
                        self.editor.insert("1.0", self.current_story.get('content', ''))
                        self.status_label.config(text=f"Loaded • Last saved {self.current_story.get('last_modified', '')[:16]}")
                        self.update_word_count()
                        return
            except:
                continue
    
    def get_content_hash(self):
        content = self.title_entry.get() + self.editor.get("1.0", tk.END).strip()
        return hashlib.md5(content.encode('utf-8')).hexdigest()
    
    def on_content_change(self, event=None):
        self.update_word_count()
        if self.auto_save_timer:
            self.root.after_cancel(self.auto_save_timer)
        self.auto_save_timer = self.root.after(1500, self.auto_save)
    
    def update_word_count(self):
        content = self.editor.get("1.0", tk.END).strip()
        words = len(content.split())
        self.word_count_label.config(text=f"Words: {words} • Passion level rising")
    
    def auto_save(self):
        if not self.title_entry.get().strip():
            return
        self.save_current(silent=True)
    
    def save_current(self, silent=False):
        title = self.title_entry.get().strip() or "Untitled Romantic Encounter"
        content = self.editor.get("1.0", tk.END)
        
        if not self.current_story:
            self.current_story = {}
        
        self.current_story.update({
            "title": title,
            "content": content,
            "last_modified": datetime.now().isoformat(),
            "genre": "Romantic Ambiguity",
            "version": "1.2"
        })
        
        if not self.current_file:
            safe_title = "".join(c for c in title if c.isalnum() or c in " _-").strip()
            self.current_file = self.stories_dir / f"{safe_title}_{int(time.time())}.json"
        
        try:
            with open(self.current_file, 'w', encoding='utf-8') as f:
                json.dump(self.current_story, f, indent=2, ensure_ascii=False)
            
            current_hash = self.get_content_hash()
            if current_hash != self.last_save_hash:
                self.create_backup()
                self.last_save_hash = current_hash
            
            self.load_stories_list()
            if not silent:
                self.status_label.config(text=f"Saved at {datetime.now().strftime('%H:%M:%S')} • Your words are safe with me")
        except Exception as e:
            if not silent:
                messagebox.showerror("Save Error", str(e))
    
    def create_backup(self):
        if not self.current_file or not self.current_file.exists():
            return
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_path = self.backup_dir / f"{self.current_file.stem}_backup_{timestamp}.zip"
        
        try:
            with zipfile.ZipFile(backup_path, 'w', zipfile.ZIP_DEFLATED) as zf:
                zf.write(self.current_file, self.current_file.name)
                # Also save a plain text version for easy recovery
                txt_path = self.current_file.with_suffix('.txt')
                with open(txt_path, 'w', encoding='utf-8') as f:
                    if self.current_story:
                        f.write(f"Title: {self.current_story.get('title', '')}\n")
                        f.write(f"Last Modified: {self.current_story.get('last_modified', '')}\n")
                        f.write("="*60 + "\n\n")
                        f.write(self.current_story.get('content', ''))
                zf.write(txt_path, txt_path.name)
                txt_path.unlink()
            return backup_path
        except:
            return None
    
    def manual_backup(self):
        if not self.current_story:
            messagebox.showinfo("No Story", "Please create or load a story first.")
            return
        backup_path = self.create_backup()
        if backup_path:
            messagebox.showinfo("Backup Created", f"Secure backup saved to:\n{backup_path}\n\nYour romantic story is now triple-protected.")
    
    def start_auto_backup_thread(self):
        def backup_loop():
            while True:
                time.sleep(1800)  # Every 30 minutes
                try:
                    for file in self.stories_dir.glob("*.json"):
                        try:
                            with open(file, 'r', encoding='utf-8') as f:
                                data = json.load(f)
                            temp_story = data
                            timestamp = datetime.now().strftime("%Y%m%d_%H%M")
                            backup_path = self.backup_dir / f"{file.stem}_auto_{timestamp}.json"
                            with open(backup_path, 'w', encoding='utf-8') as f:
                                json.dump(temp_story, f, indent=2)
                        except:
                            continue
                except:
                    pass
        threading.Thread(target=backup_loop, daemon=True).start()
    
    def export_story(self):
        if not self.current_story:
            messagebox.showinfo("Nothing to export", "Create or load a story first.")
            return
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")],
            initialfile=self.current_story.get('title', 'romantic_story')
        )
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(f"Title: {self.current_story.get('title', 'Untitled')}\n")
                    f.write(f"Genre: Romantic Ambiguity\n")
                    f.write(f"Exported: {datetime.now().strftime('%Y-%m-%d %H:%M')}\n")
                    f.write("="*80 + "\n\n")
                    f.write(self.current_story.get('content', ''))
                messagebox.showinfo("Exported", f"Story successfully exported to:\n{file_path}")
            except Exception as e:
                messagebox.showerror("Export failed", str(e))
    
    def delete_current(self):
        if not self.current_file:
            messagebox.showinfo("No story selected", "Please load a story first.")
            return
        if messagebox.askyesno("Delete Story", "Permanently delete this romantic tale?\n\nThis cannot be undone.", icon='warning'):
            try:
                self.current_file.unlink()
                self.current_file = None
                self.current_story = None
                self.title_entry.delete(0, tk.END)
                self.editor.delete("1.0", tk.END)
                self.load_stories_list()
                self.status_label.config(text="Story deleted • The memories remain in your heart")
            except:
                pass
    
    def run(self):
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.mainloop()
    
    def on_closing(self):
        if self.current_story and self.editor.get("1.0", tk.END).strip():
            self.save_current(silent=True)
        if messagebox.askokcancel("Exit Elysium", "Close the sanctuary?\n\nAll stories are safely stored locally with automatic backups."):
            self.root.destroy()

if __name__ == "__main__":
    print("🌹 Launching Elysium - Your private romantic novel sanctuary...")
    print("All stories are saved locally. Automatic backups every 30 minutes.")
    print("Perfect for ambiguous, tender, passionate, and complex romantic stories.\n")
    
    app = NovelWritingAssistant()
    app.run()

Prompt

Use Python to write a complete local novel writing assistant that can safely save users' romantic ambiguous stories, with automatic backup and elegant interface design. The code can be directly run.

Generator starting settings

Model
Uncensored Code
Mode
chat
View collection

Questions about this prompt

What is this AI code prompt about?

This prompt focuses on “Romantic Novel Writing Assistant in Python”: Local romantic novel writing assistant. It is ready to use for code generation on HackAIGC.

How do I use this prompt on HackAIGC?

Open the prompt, tap Use prompt or Copy prompt, then run it with your preferred model and settings.

What approach does this code prompt use?

The brief for “Romantic Novel Writing Assistant in Python” includes romantic, elegant cues. Edit the prompt to change the tone, structure, or level of detail.

Can I edit this prompt before generating?

Yes. Copy the prompt text, modify details, then generate again on HackAIGC.