8ac7635f by 柴进

nanobanana初版

1 parent 9b6295c7
{
"api_key": "AIzaSyBRIH8iItqTZXg7d4zAWVNhyit2CZbXWIU",
"saved_prompts": [
"生成一张白人夫妻正常的买家秀展现我的戒指",
"主石换成闪耀的鸽血红红宝石,火彩非常好",
"生成一张白人夫妻在自家后院里的椅子坐着,亲密姿态,展现笑容,妻子手背捂嘴笑来展现我的戒指,两个人年龄大概40岁上下,男性微胖,女性短发,男士和女士脸上有一些痕迹,手要略显粗糙,普通人长相",
"一副美丽的嵖岈山风景,冬日清晨,初雪"
],
"db_config": {
"host": "rm-uf6hx9ka75jdm2474xo.mysql.rds.aliyuncs.com",
"port": 3306,
"user": "root",
"password": "Np2KfoleLon3nqDpDbdjPa3Rqe",
"database": "saas_user",
"table": "nano_banana_users"
},
"last_user": "testuser",
"saved_password_hash": ""
}
\ No newline at end of file
......@@ -21,6 +21,7 @@ from google.genai import types
import threading
import hashlib
import pymysql
from datetime import datetime
def hash_password(password: str) -> str:
......@@ -384,13 +385,14 @@ class ImageGeneratorApp:
style.configure('Accent.TButton',
background=accent_color,
foreground='white',
borderwidth=0,
borderwidth=1,
relief='solid',
focuscolor='none',
font=('Segoe UI', 10),
padding=(18, 8))
style.map('Accent.TButton',
background=[('active', hover_color), ('pressed', hover_color)],
background=[('active', hover_color), ('pressed', '#003D99')],
foreground=[('disabled', '#999999')])
# Secondary button style
......@@ -398,23 +400,24 @@ class ImageGeneratorApp:
background=secondary_bg,
foreground=text_color,
borderwidth=1,
relief='flat',
relief='solid',
font=('Segoe UI', 9),
padding=(12, 6))
style.map('Secondary.TButton',
background=[('active', '#e8e8e8'), ('pressed', '#d8d8d8')])
background=[('active', '#e8e8e8'), ('pressed', '#c8c8c8')])
# Icon button style (small, subtle)
style.configure('Icon.TButton',
background=bg_color,
foreground='#666666',
borderwidth=0,
borderwidth=1,
relief='solid',
font=('Segoe UI', 9),
padding=(4, 4))
style.map('Icon.TButton',
background=[('active', secondary_bg)],
background=[('active', secondary_bg), ('pressed', '#d8d8d8')],
foreground=[('active', accent_color)])
# Delete button style (visible with red hover)
......@@ -470,6 +473,7 @@ class ImageGeneratorApp:
# 初始化默认值
self.db_config = None
self.last_user = ""
self.saved_password_hash = ""
# Try to load from user config first
if config_path.exists():
......@@ -480,6 +484,7 @@ class ImageGeneratorApp:
self.saved_prompts = config.get("saved_prompts", [])
self.db_config = config.get("db_config")
self.last_user = config.get("last_user", "")
self.saved_password_hash = config.get("saved_password_hash", "")
except Exception as e:
print(f"Failed to load config from {config_path}: {e}")
......@@ -525,6 +530,12 @@ class ImageGeneratorApp:
else:
config["last_user"] = ""
# 添加保存的密码哈希
if hasattr(self, 'saved_password_hash'):
config["saved_password_hash"] = self.saved_password_hash
else:
config["saved_password_hash"] = ""
# Ensure directory exists
config_path.parent.mkdir(parents=True, exist_ok=True)
......@@ -590,7 +601,7 @@ class ImageGeneratorApp:
prompt_toolbar.pack(fill="x", pady=(0, 8))
self.save_prompt_btn = ttk.Button(prompt_toolbar, text="⭐ 收藏",
command=self.save_prompt,
command=self.toggle_favorite,
style='Icon.TButton')
self.save_prompt_btn.pack(side="left", padx=(0, 5))
self.bind_hover_effect(self.save_prompt_btn)
......@@ -616,7 +627,10 @@ class ImageGeneratorApp:
bg='#fafafa')
self.prompt_text.pack(fill="both", expand=True)
self.prompt_text.insert("1.0", "一幅美丽的风景画,有山有湖,日落时分")
# Bind text change event to check favorite status
self.prompt_text.bind('<<Modified>>', self.on_prompt_change)
# Right: Settings Section
settings_container = ttk.LabelFrame(content_row, text="生成设置", padding=12)
settings_container.pack(side="right", fill="y")
......@@ -633,14 +647,7 @@ class ImageGeneratorApp:
self.image_size = ttk.Combobox(settings_container, width=18, state="readonly")
self.image_size['values'] = ("1K", "2K", "4K")
self.image_size.current(1)
self.image_size.pack(fill="x", pady=(0, 12))
# Model
ttk.Label(settings_container, text="AI 模型", foreground='#666666').pack(anchor="w", pady=(0, 4))
self.model = ttk.Combobox(settings_container, width=18, state="readonly")
self.model['values'] = ("gemini-3-pro-image-preview")
self.model.current(0)
self.model.pack(fill="x", pady=(0, 0))
self.image_size.pack(fill="x", pady=(0, 0))
# Action buttons
action_frame = ttk.Frame(main_container)
......@@ -718,28 +725,43 @@ class ImageGeneratorApp:
self.saved_prompts_combo['values'] = display_prompts
else:
self.saved_prompts_combo['values'] = []
def save_prompt(self):
"""Save current prompt to favorites"""
def check_favorite_status(self):
"""Check if current prompt is favorited and update button state"""
prompt = self.prompt_text.get("1.0", tk.END).strip()
if prompt in self.saved_prompts:
self.save_prompt_btn.config(text="✓ 已收藏")
else:
self.save_prompt_btn.config(text="⭐ 收藏")
def on_prompt_change(self, event=None):
"""Callback when prompt text changes"""
# Clear the modified flag to avoid repeated triggers
self.prompt_text.edit_modified(False)
self.check_favorite_status()
def toggle_favorite(self):
"""Toggle favorite status of current prompt"""
prompt = self.prompt_text.get("1.0", tk.END).strip()
if not prompt:
self.status_label.config(text="● 提示词不能为空", foreground='#FF3B30')
return
if prompt in self.saved_prompts:
self.status_label.config(text="● 该提示词已收藏", foreground='#FF9500')
self.save_prompt_btn.config(text="✓ 已收藏")
# 2秒后恢复按钮文本
self.root.after(2000, lambda: self.save_prompt_btn.config(text="⭐ 收藏"))
return
self.saved_prompts.append(prompt)
self.save_config()
self.update_saved_prompts_list()
self.status_label.config(text="● 已收藏提示词", foreground='#34C759')
self.save_prompt_btn.config(text="✓ 已收藏")
# 2秒后恢复按钮文本
self.root.after(2000, lambda: self.save_prompt_btn.config(text="⭐ 收藏"))
# Remove from favorites
self.saved_prompts.remove(prompt)
self.save_config()
self.update_saved_prompts_list()
self.status_label.config(text="● 该提示词已取消收藏", foreground='#34C759')
else:
# Add to favorites
self.saved_prompts.append(prompt)
self.save_config()
self.update_saved_prompts_list()
self.status_label.config(text="● 该提示词已收藏", foreground='#34C759')
# Update button state
self.check_favorite_status()
def load_saved_prompt(self, event):
"""Load a saved prompt"""
......@@ -748,6 +770,7 @@ class ImageGeneratorApp:
self.prompt_text.delete("1.0", tk.END)
self.prompt_text.insert("1.0", self.saved_prompts[index])
self.status_label.config(text="● 已加载提示词", foreground='#007AFF')
self.check_favorite_status()
def delete_saved_prompt(self):
"""Delete the currently selected saved prompt"""
......@@ -929,7 +952,7 @@ class ImageGeneratorApp:
# Generate
response = client.models.generate_content(
model=self.model.get(),
model="gemini-3-pro-image-preview",
contents=content_parts,
config=config
)
......@@ -1028,8 +1051,12 @@ class ImageGeneratorApp:
messagebox.showerror("错误", "没有可下载的图片!")
return
# 生成默认文件名: 时间戳格式 YYYYMMDDHHMMSS.png
default_filename = datetime.now().strftime("%Y%m%d%H%M%S.png")
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
initialfile=default_filename,
filetypes=[("PNG 文件", "*.png"), ("JPEG 文件", "*.jpg"), ("所有文件", "*.*")],
title="保存图片"
)
......