Spaces:
Running
Running
############################################## | |
# 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() |