File size: 5,806 Bytes
700b1d7
 
85139d2
c01a950
6fb9e78
c0bb1cd
 
6ffb5a2
6fb9e78
 
 
 
 
 
baaab55
c139e5d
6fb9e78
700b1d7
 
 
c01a950
85139d2
4f29568
3f11bbc
baaab55
6fb9e78
3f11bbc
6fb9e78
3f11bbc
4f29568
 
 
 
baaab55
4f29568
 
 
 
 
 
 
 
 
 
 
 
 
6fb9e78
85139d2
baaab55
6fb9e78
 
 
 
 
a291ed6
 
 
 
6fb9e78
 
 
 
 
 
 
c3bfb7c
baaab55
 
 
85139d2
baaab55
7916fee
 
 
 
 
 
 
c0bb1cd
85139d2
 
 
 
7916fee
85139d2
 
7916fee
85139d2
 
 
 
 
 
 
 
 
 
c0bb1cd
7916fee
 
 
 
 
 
 
 
baaab55
 
 
 
7011453
baaab55
 
85139d2
c0bb1cd
85139d2
 
c0bb1cd
85139d2
c0bb1cd
 
85139d2
 
c0bb1cd
85139d2
16cc397
85139d2
700b1d7
85139d2
7011453
 
85139d2
dda26c7
7011453
700b1d7
 
7011453
 
baaab55
 
 
 
 
 
 
 
 
 
 
 
 
 
6fb9e78
baaab55
 
 
 
7011453
6fb9e78
c0bb1cd
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
import discord
from discord import app_commands
from discord.ui import Button, View
import os
import asyncio
import aiohttp
import gradio as gr

# --- Environment Variables & Setup ---
DISCORD_BOT_TOKEN = os.getenv("DISCORD_BOT_TOKEN")
GLIF_API_TOKEN = os.getenv("GLIF_API_TOKEN")
GLIF_API_URL = "https://simple-api.glif.app"

if not DISCORD_BOT_TOKEN or not GLIF_API_TOKEN:
    raise ValueError("Both DISCORD_BOT_TOKEN and GLIF_API_TOKEN must be set.")

# --- Discord Bot Setup ---
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)

# --- Image Generation Function ---
async def generate_image_async(prompt, aspect_ratio):
    payload = {
        "id": "cm3ugmzv2002gnckiosrwk6xi",
        "inputs": [prompt, aspect_ratio],
    }
    headers = {"Authorization": f"Bearer {GLIF_API_TOKEN}"}

    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(
                GLIF_API_URL, json=payload, headers=headers, timeout=15
            ) as response:
                response.raise_for_status()
                response_data = await response.json()
                if "output" in response_data:
                    return response_data["output"]
                elif "error" in response_data:
                    return f"Error: {response_data['error']}"
                else:
                    return "Error: Unexpected response from GLIF API."

        except asyncio.TimeoutError:
            return "Error: GLIF API request timed out."
        except aiohttp.ClientError as e:
            return f"API request failed: {e}"

# --- Discord Command: /generate ---
@tree.command(name="generate", description="Generates an image based on a text prompt")
@app_commands.choices(
    aspect_ratio=[
        app_commands.Choice(name="1:1 (Square)", value="1:1"),
        app_commands.Choice(name="9:16 (Vertical)", value="9:16"),
        app_commands.Choice(name="16:9 (Horizontal)", value="16:9"),
        app_commands.Choice(name="3:4", value="3:4"),
        app_commands.Choice(name="4:3", value="4:3"),
        app_commands.Choice(name="9:21", value="9:21"),
        app_commands.Choice(name="21:9", value="21:9"),
    ]
)
async def generate_command(
    interaction: discord.Interaction,
    prompt: str,
    aspect_ratio: app_commands.Choice[str],
):
    try:
        await interaction.response.defer()

        image_url_or_error = await generate_image_async(prompt, aspect_ratio.value)

        if image_url_or_error.startswith("http"):
            # Download the image
            async with aiohttp.ClientSession() as session:
                async with session.get(image_url_or_error) as resp:
                    if resp.status != 200:
                        return await interaction.followup.send('Could not download file...')
                    image_data = await resp.read()

            # Format the prompt for display with expand/collapse
            formatted_prompt, initial_content, full_content = format_prompt_for_discord(prompt)

            # Create buttons
            async def show_more_callback(interaction):
                await interaction.response.edit_message(content=full_content, view=view)

            async def show_less_callback(interaction):
                await interaction.response.edit_message(content=initial_content, view=view)

            show_more_button = Button(label="Read More", style=discord.ButtonStyle.primary)
            show_more_button.callback = show_more_callback
            show_less_button = Button(label="Hide", style=discord.ButtonStyle.secondary)
            show_less_button.callback = show_less_callback

            view = View()
            if len(prompt) > 256:
                view.add_item(show_more_button)
            view.add_item(show_less_button)

            # Send the image as an attachment
            with io.BytesIO(image_data) as image_file:
                await interaction.followup.send(
                    content=initial_content,
                    file=discord.File(image_file, 'generated_image.png'),
                    view=view
                )

        else:
            await interaction.followup.send(
                f"Sorry, I couldn't generate an image. {image_url_or_error}"
            )
    except Exception as e:
        await interaction.followup.send(f"Error: {str(e)}")

# --- Helper Function: Format Prompt for Discord ---
def format_prompt_for_discord(prompt):
    """Formats the prompt for display in Discord with expand/collapse functionality using buttons."""
    max_length = 256
    if len(prompt) <= max_length:
        return prompt, f"**Prompt:** {prompt}", f"**Prompt:** {prompt}"

    truncated_prompt = prompt[:max_length]
    initial_content = f"**Prompt:** {truncated_prompt}..."
    full_content = f"**Prompt:** {prompt}"

    return prompt, initial_content, full_content

# --- Discord Command: /hello ---
@tree.command(name="hello", description="Says hello!")
async def hello_command(interaction: discord.Interaction):
    await interaction.response.send_message("Hello there!")

# --- Bot Ready Event ---
async def on_ready():
    await tree.sync()
    print("Bot is ready!")

client.event(on_ready)

# --- Gradio Interface ---
def echo_text(text):
    return text

def run_gradio():
    gr.Interface(
        fn=echo_text,
        inputs="text",
        outputs="text",
        live=False,
        title="Minimal Gradio Interface",
    ).launch(server_name="0.0.0.0", server_port=7860, share=False, show_error=True)

# --- Main ---
async def main():
    bot_task = asyncio.create_task(client.start(DISCORD_BOT_TOKEN))
    gradio_task = asyncio.to_thread(run_gradio)

    await asyncio.gather(bot_task, gradio_task)

if __name__ == "__main__":
    asyncio.run(main())