############################################## # app.py ############################################## import os import json import gradio as gr from openai import OpenAI ############################################################################## # 1. 读取外部文件: furry_species.json & gender_rules.json ############################################################################## # 假设 furry_species.json 的结构是多级字典: { "AQUATICS ...": { "Cetaceans": [], ...}, ... } try: with open("furry_species.json", "r", encoding="utf-8") as f: FURRY_DATA = json.load(f) except: FURRY_DATA = {} # gender_rules.json: { "male": "...", "female": "...", "intersex": "...", "genderless": "..." } try: with open("gender_rules.json", "r", encoding="utf-8") as f: GENDER_RULES = json.load(f) except: GENDER_RULES = {} ############################################################################## # 2. 构造多级下拉菜单:先选“主分类”,再选“子分类” ############################################################################## def get_top_categories(furry_data): """获取所有顶级分类 (keys)""" return sorted(list(furry_data.keys())) def get_sub_categories(furry_data, top_category): """ 根据所选 top_category, 返回二级分类列表 furry_data[top_category] -> { "Cetaceans": [...], "FishFurs": [...], ... } """ if top_category in furry_data: return sorted(list(furry_data[top_category].keys())) return [] def get_species_list(furry_data, top_category, sub_category): """ 返回最终物种列表 furry_data[top_category][sub_category] -> list """ if ( top_category in furry_data and sub_category in furry_data[top_category] ): return sorted(furry_data[top_category][sub_category]) return [] ############################################################################## # 3. 调用逻辑:GPT 或 DeepSeek ############################################################################## def generate_tags_and_description(prompt, gender_option, top_cat, sub_cat, species_item, api_mode, api_key): """ 1) 构造 tags: gender, base_prompt, furry_species 2) 读取 gender_rules 并拼入 system prompt 3) 调用 GPT/DeepSeek 4) 输出 (tags + 自然语言描述) """ if not api_key: return "Error: No API Key provided." # 性别 tags = {} if gender_option == "Trans_to_Male": tags["gender"] = "male" rule_text = GENDER_RULES.get("male", "") elif gender_option == "Trans_to_Female": tags["gender"] = "female" rule_text = GENDER_RULES.get("female", "") elif gender_option == "Trans_to_Mannequin": tags["gender"] = "genderless" rule_text = GENDER_RULES.get("genderless", "") elif gender_option == "Trans_to_Intersex": tags["gender"] = "intersex" rule_text = GENDER_RULES.get("intersex", "") else: # Furry tags["gender"] = "furry" rule_text = ( GENDER_RULES.get("male", "") + "\n\n" # 你可以根据自己的业务需求处理 + GENDER_RULES.get("female", "") + "\n\n" + GENDER_RULES.get("intersex", "") + "\n\n" + GENDER_RULES.get("genderless", "") ) # 或者只给一个简要 furry rule # 选定物种 final_species = "unknown" if top_cat and sub_cat and species_item: final_species = f"{top_cat} > {sub_cat} > {species_item}" tags["furry_species"] = final_species # 原始提示词 tags["base_prompt"] = prompt # BaseURL & 模型 if api_mode == "GPT": base_url = None model_name = "gpt-3.5-turbo" else: base_url = "https://api.deepseek.com" model_name = "deepseek-chat" client = OpenAI(api_key=api_key) if base_url: client.base_url = base_url # 将 tags 拼为字符串 tags_str = "\n".join([f"{k}: {v}" for k, v in tags.items() if v]) # system prompt 带上Gender Rules system_prompt = ( "You are a creative assistant that generates detailed and imaginative scene descriptions " "for AI generation prompts. Focus on the details provided, incorporate them into a cohesive narrative, " "and follow these gender/furry rules:\n\n" f"{rule_text}\n\n" "When you respond, do not exceed five sentences. Return your final text in English or relevant language.\n" ) # Chat try: resp = client.chat.completions.create( model=model_name, messages=[ {"role": "system", "content": system_prompt}, { "role": "user", "content": f"Here are the tags:\n{tags_str}\nPlease generate a vivid, imaginative scene description." }, ], ) desc_text = resp.choices[0].message.content.strip() # 输出 (tags + desc) return f"=== Tags ===\n{tags_str}\n\n=== Description ===\n{desc_text}" except Exception as e: return f"{api_mode} generation failed. Error: {e}" def translate_text(content, lang, api_mode, api_key): """ 调用 GPT 或 DeepSeek 做翻译 """ if not api_key: return "Error: No API Key provided." if not content.strip(): return "" if api_mode == "GPT": base_url = None model_name = "gpt-3.5-turbo" else: base_url = "https://api.deepseek.com" model_name = "deepseek-chat" client = OpenAI(api_key=api_key) if base_url: client.base_url = base_url system_prompt = f"You are a translator. Translate the following text to {lang}:" try: resp = client.chat.completions.create( model=model_name, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": content}, ], ) return resp.choices[0].message.content.strip() except Exception as e: return f"{api_mode} translation failed. Error: {e}" ############################################################################## # 4. Gradio 界面 ############################################################################## def build_interface(): with gr.Blocks() as demo: gr.Markdown("## Prompt Furry/Gender Transformer (GPT / DeepSeek)") with gr.Row(): with gr.Column(): api_mode = gr.Radio( label="选择API (GPT or DeepSeek)", choices=["GPT", "DeepSeek"], value="GPT" ) api_key = gr.Textbox( label="API Key", type="password" ) # 性别 gender_option = gr.Radio( label="转换目标", choices=[ "Trans_to_Male", "Trans_to_Female", "Trans_to_Mannequin", "Trans_to_Intersex", "Trans_to_Furry" ], value="Trans_to_Male" ) # 顶级分类 top_cat_dd = gr.Dropdown( label="Furry: 主分类 (Top Category)", choices=get_top_categories(FURRY_DATA), value=None, visible=False ) # 二级分类 sub_cat_dd = gr.Dropdown( label="Furry: 子分类 (Sub-Category)", choices=[], value=None, visible=False ) # 物种 species_dd = gr.Dropdown( label="Furry: 物种 (Species)", choices=[], value=None, visible=False ) # 性别选项变化 -> 显示或隐藏 Furry 下拉 def show_furry_options(chosen): if chosen == "Trans_to_Furry": return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True) else: return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False) gender_option.change( fn=show_furry_options, inputs=[gender_option], outputs=[top_cat_dd, sub_cat_dd, species_dd] ) # 顶级分类 -> 更新子分类 def on_top_cat_select(selected): subs = get_sub_categories(FURRY_DATA, selected) return gr.update(choices=subs, value=None) top_cat_dd.change( fn=on_top_cat_select, inputs=[top_cat_dd], outputs=[sub_cat_dd] ) # 子分类 -> 更新物种 def on_sub_cat_select(top_c, sub_c): sp = get_species_list(FURRY_DATA, top_c, sub_c) return gr.update(choices=sp, value=None) sub_cat_dd.change( fn=on_sub_cat_select, inputs=[top_cat_dd, sub_cat_dd], outputs=[species_dd] ) with gr.Column(): user_prompt = gr.Textbox( label="提示词 (Prompt)", lines=4 ) output_result = gr.Textbox( label="(tags + 自然语言描述)", lines=10 ) with gr.Row(): translate_lang = gr.Dropdown( label="翻译语言", choices=["English", "Chinese", "Japanese", "French", "German", "Spanish"], value="English" ) translate_result = gr.Textbox( label="翻译结果", lines=10 ) ###################################################################### # 生成 ###################################################################### def on_generate(prompt, gender, tc, sc, spc, mode, key, lang): # 1) 生成 tags_desc = generate_tags_and_description(prompt, gender, tc, sc, spc, mode, key) # 2) 翻译 trans_txt = translate_text(tags_desc, lang, mode, key) return tags_desc, trans_txt user_prompt.submit( fn=on_generate, inputs=[user_prompt, gender_option, top_cat_dd, sub_cat_dd, species_dd, api_mode, api_key, translate_lang], outputs=[output_result, translate_result] ) gen_btn = gr.Button("生成 / Generate") gen_btn.click( fn=on_generate, inputs=[user_prompt, gender_option, top_cat_dd, sub_cat_dd, species_dd, api_mode, api_key, translate_lang], outputs=[output_result, translate_result] ) return demo if __name__ == "__main__": demo = build_interface() demo.launch()