File size: 9,098 Bytes
1e6c6f2
 
 
bef3741
1e6c6f2
bef3741
ceffbde
bef3741
1e6c6f2
bef3741
64322bd
 
1e6c6f2
64322bd
1e6c6f2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64322bd
1e6c6f2
64322bd
ceffbde
1e6c6f2
ceffbde
 
 
 
1e6c6f2
 
 
 
 
 
 
 
 
 
ceffbde
 
1e6c6f2
ceffbde
1e6c6f2
 
ceffbde
1e6c6f2
 
 
ceffbde
1e6c6f2
 
 
 
 
ceffbde
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e6c6f2
ceffbde
 
1e6c6f2
ceffbde
 
 
 
 
1e6c6f2
bef3741
64322bd
bef3741
64322bd
1e6c6f2
 
 
 
 
 
 
 
 
 
 
64322bd
 
ceffbde
 
64322bd
1e6c6f2
64322bd
1e6c6f2
64322bd
1e6c6f2
 
64322bd
 
1e6c6f2
64322bd
1e6c6f2
 
 
 
 
 
64322bd
ceffbde
64322bd
1e6c6f2
64322bd
1e6c6f2
64322bd
 
1e6c6f2
ceffbde
 
64322bd
1e6c6f2
ceffbde
 
 
 
 
 
64322bd
bef3741
64322bd
bef3741
64322bd
1e6c6f2
64322bd
ceffbde
 
64322bd
 
bef3741
64322bd
 
ceffbde
0f91f56
ceffbde
64322bd
 
ceffbde
64322bd
1e6c6f2
64322bd
1e6c6f2
64322bd
 
 
1e6c6f2
64322bd
1e6c6f2
64322bd
ceffbde
64322bd
 
1e6c6f2
64322bd
1e6c6f2
64322bd
1e6c6f2
64322bd
1e6c6f2
64322bd
bef3741
 
 
 
 
64322bd
14b159d
64322bd
1e6c6f2
 
ceffbde
64322bd
0f91f56
64322bd
1e6c6f2
 
 
 
 
64322bd
 
1e6c6f2
64322bd
1e6c6f2
 
64322bd
1e6c6f2
 
 
64322bd
 
 
 
 
ceffbde
1e6c6f2
64322bd
ceffbde
1e6c6f2
 
64322bd
 
1e6c6f2
 
 
 
 
 
 
05bf4a2
1e6c6f2
64322bd
1e6c6f2
 
64322bd
1e6c6f2
 
64322bd
1e6c6f2
 
64322bd
 
 
 
 
1e6c6f2
bef3741
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
##############################################
# app.py
##############################################
import os
import json
import gradio as gr
import requests

# 新版 openai>=1.0.0
from openai import OpenAI

##############################################################################
# 1. 从外部文件中加载 Furry 物种数据 + Gender 细节文本
##############################################################################

# 读取 Furry 物种分类的 JSON 文件
# 假设文件名为 furry_species.json,结构示例:
# {
#   "CANIDS": ["Dogs", "Wolves", "Foxes"],
#   "FELINES": ["Lions", "Tigers", "Cheetahs"],
#   ...
# }
try:
    with open("furry_species.json", "r", encoding="utf-8") as fs_file:
        furry_map = json.load(fs_file)
except:
    furry_map = {}  # 若文件不存在或出错,可给个空dict备用

def flatten_furry_species(map_data):
    """
    将 {分类: [物种列表]} 展开为 ["分类 - 物种"] 形式的扁平列表
    """
    result = []
    for category, species_list in map_data.items():
        for sp in species_list:
            result.append(f"{category} - {sp}")
    return sorted(result)

ALL_FURRY_SPECIES = flatten_furry_species(furry_map)

# 读取 Gender 细节长文本 (记忆库)
try:
    with open("gender_details.txt", "r", encoding="utf-8") as gd_file:
        GENDER_DETAILS_TEXT = gd_file.read()
except:
    GENDER_DETAILS_TEXT = (
        "Gender conversion rules are missing. Please provide gender_details.txt."
    )

##############################################################################
# 2. 核心函数:根据选择调用 GPT 或 DeepSeek
##############################################################################

def generate_description_with_tags(prompt, gender_option, furry_species, api_mode, api_key):
    """
    1) 构造 tags(包含 gender/furry/base_prompt)。
    2) 调用 GPT 或 DeepSeek,带上记忆库信息 (GENDER_DETAILS_TEXT) 作为系统提示。
    3) 返回 (tags + 自然语言描述) 的输出形式。
    """

    if not api_key:
        return "Error: No API Key provided."

    # 组装 tags
    tags = {}
    if gender_option == "Trans_to_Male":
        tags["gender"] = "male"
    elif gender_option == "Trans_to_Female":
        tags["gender"] = "female"
    elif gender_option == "Trans_to_Mannequin":
        tags["gender"] = "genderless"
    elif gender_option == "Trans_to_Intersex":
        tags["gender"] = "intersex"
    elif gender_option == "Trans_to_Furry":
        tags["gender"] = "furry"
        tags["furry_species"] = furry_species or "unknown"

    tags["base_prompt"] = prompt

    # 确定 base_url + model
    if api_mode == "GPT":
        base_url = None
        model_name = "gpt-3.5-turbo"  # or "gpt-4", "gpt-4o", etc.
    else:
        # DeepSeek
        base_url = "https://api.deepseek.com"
        model_name = "deepseek-chat"

    # 创建 OpenAI Client
    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])

    # 准备对话消息:把 gender_details 放在系统提示中,以便 AI 参考
    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 obey the following gender transformation & furry rules:\n\n"
        f"{GENDER_DETAILS_TEXT}\n\n"
        "After forming your final description, return it in no more than five sentences. Thank you!"
    )

    try:
        response = client.chat.completions.create(
            model=model_name,
            messages=[
                {"role": "system", "content": system_prompt},
                {
                    "role": "user",
                    "content": (
                        f"Here are the tags:\n{tags_str}\n"
                        f"Please generate a vivid, imaginative scene description."
                    ),
                },
            ],
        )
        description = response.choices[0].message.content.strip()

        # 输出形式:(tags + 自然语言描述)
        output_text = f"=== Tags ===\n{tags_str}\n\n=== Description ===\n{description}"
        return output_text

    except Exception as e:
        return f"{api_mode} generation failed. Error: {e}"

def translate_text(text, translate_language, api_mode, api_key):
    """
    仅做一次简单翻译。若不需要翻译可以省去。也可用系统提示让 AI 翻译。
    """
    if not api_key:
        return "Error: No API Key provided."
    if not text.strip():
        return ""

    # GPT vs DeepSeek
    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 professional translator. Translate the following text to {translate_language}:"
    try:
        resp = client.chat.completions.create(
            model=model_name,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user",   "content": text},
            ]
        )
        return resp.choices[0].message.content.strip()
    except Exception as e:
        return f"{api_mode} translation failed. Error: {e}"

##############################################################################
# 3. Gradio 界面
##############################################################################
def build_interface():
    with gr.Blocks() as demo:
        gr.Markdown("## Prompt Transformer (GPT / DeepSeek) - (tags + 自然语言描述)")

        with gr.Row():
            with gr.Column():
                # 选择 API
                api_mode = gr.Radio(
                    label="选择API (GPT or DeepSeek)",
                    choices=["GPT", "DeepSeek"],
                    value="GPT",
                )
                api_key = gr.Textbox(
                    label="API密钥 (API Key)",
                    type="password",
                    placeholder="在此输入 GPT / DeepSeek 的API Key"
                )
                # 性别 / Furry
                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",
                )
                furry_species = gr.Dropdown(
                    label="Furry 物种选择",
                    choices=ALL_FURRY_SPECIES,
                    value=None,
                    visible=False
                )

                def show_furry_species(choice):
                    return gr.update(visible=(choice == "Trans_to_Furry"))

                gender_option.change(show_furry_species, inputs=[gender_option], outputs=[furry_species])

            with gr.Column():
                user_prompt = gr.Textbox(
                    label="提示词 (Prompt)",
                    lines=4,
                    placeholder="示例:一位穿着蓝色长裙的少女,坐在海边..."
                )
                output_tags_and_desc = gr.Textbox(
                    label="(tags + 自然语言描述)",
                    lines=10
                )

        with gr.Row():
            translate_language = gr.Dropdown(
                label="翻译语言 (Translation Language)",
                choices=["English", "Chinese", "Japanese", "French", "German", "Spanish"],
                value="English"
            )
            translate_output = gr.Textbox(
                label="翻译结果",
                lines=10
            )

        # 点击生成 -> 同时调用生成描述 & 翻译
        def on_generate(prompt, gender, f_species, mode, key, lang):
            # 1. 生成 (tags + 自然语言描述)
            result_text = generate_description_with_tags(prompt, gender, f_species, mode, key)
            # 2. 翻译
            translated = translate_text(result_text, lang, mode, key)
            return result_text, translated

        user_prompt.submit(
            fn=on_generate,
            inputs=[user_prompt, gender_option, furry_species, api_mode, api_key, translate_language],
            outputs=[output_tags_and_desc, translate_output]
        )
        generate_btn = gr.Button("生成 / Generate")
        generate_btn.click(
            fn=on_generate,
            inputs=[user_prompt, gender_option, furry_species, api_mode, api_key, translate_language],
            outputs=[output_tags_and_desc, translate_output]
        )

    return demo

if __name__ == "__main__":
    demo = build_interface()
    demo.launch()