James040 commited on
Commit
9ce3351
·
verified ·
1 Parent(s): 175f63d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -0
app.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import re
5
+
6
+ LLAMA_URL = "http://localhost:8080/v1/chat/completions"
7
+
8
+ SYSTEM_PROMPT = """You are PromptForge, an AI that converts simple user statements into highly detailed JSON prompts for AI image and video generation.
9
+
10
+ You MUST always respond with valid JSON only. No explanation, no extra text — just pure JSON.
11
+
12
+ For IMAGE prompts, use this exact structure:
13
+ {
14
+ "type": "image",
15
+ "prompt": "ultra-detailed visual description here",
16
+ "negative_prompt": "what to avoid",
17
+ "style": "e.g. photorealistic / anime / oil painting / cinematic",
18
+ "aspect_ratio": "e.g. 16:9 / 1:1 / 9:16",
19
+ "lighting": "e.g. golden hour / dramatic studio / soft diffused",
20
+ "camera": "e.g. wide angle / macro / aerial / 35mm portrait",
21
+ "mood": "e.g. mysterious / joyful / melancholic",
22
+ "quality_tags": ["8k", "ultra detailed", "award winning", "masterpiece"],
23
+ "color_palette": "e.g. warm earth tones / neon cyberpunk / pastel",
24
+ "additional_details": "any extra context"
25
+ }
26
+
27
+ For VIDEO prompts, use this exact structure:
28
+ {
29
+ "type": "video",
30
+ "prompt": "ultra-detailed scene description",
31
+ "negative_prompt": "what to avoid",
32
+ "style": "e.g. cinematic / animation / documentary",
33
+ "aspect_ratio": "e.g. 16:9 / 9:16",
34
+ "duration_seconds": 5,
35
+ "fps": 24,
36
+ "motion": "e.g. slow zoom in / pan left / dolly shot / static",
37
+ "camera_movement": "e.g. handheld shaky / smooth gimbal / aerial drone",
38
+ "lighting": "e.g. natural daylight / neon lights / candlelit",
39
+ "mood": "e.g. tense / peaceful / epic",
40
+ "scene_transition": "e.g. fade in / cut / dissolve",
41
+ "audio_suggestion": "e.g. ambient rain / dramatic orchestral / none",
42
+ "quality_tags": ["cinematic 4k", "smooth motion", "color graded"],
43
+ "additional_details": "any extra context"
44
+ }
45
+
46
+ Always generate BOTH an image prompt AND a video prompt for every user input, combined into a single JSON object like this:
47
+ {
48
+ "image": { ...image prompt object... },
49
+ "video": { ...video prompt object... }
50
+ }
51
+
52
+ Be creative, specific, and detailed. Expand on the user's simple statement richly."""
53
+
54
+
55
+ def generate_prompts(user_input: str, history: list):
56
+ if not user_input.strip():
57
+ return history, history, ""
58
+
59
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
60
+ for h in history:
61
+ messages.append({"role": "user", "content": h[0]})
62
+ messages.append({"role": "assistant", "content": h[1]})
63
+ messages.append({"role": "user", "content": user_input})
64
+
65
+ try:
66
+ response = requests.post(
67
+ LLAMA_URL,
68
+ json={
69
+ "model": "local",
70
+ "messages": messages,
71
+ "max_tokens": 1200,
72
+ "temperature": 0.7,
73
+ "stream": False,
74
+ },
75
+ timeout=120,
76
+ )
77
+ raw = response.json()["choices"][0]["message"]["content"].strip()
78
+
79
+ # Try to extract JSON from response
80
+ json_match = re.search(r'\{[\s\S]*\}', raw)
81
+ if json_match:
82
+ parsed = json.loads(json_match.group())
83
+ formatted = json.dumps(parsed, indent=2)
84
+ display = f"```json\n{formatted}\n```"
85
+ else:
86
+ display = raw
87
+
88
+ new_history = history + [(user_input, display)]
89
+ return new_history, new_history, ""
90
+
91
+ except Exception as e:
92
+ err = f"⚠️ Error: {str(e)}\n\nMake sure the llama.cpp server is running on port 8080."
93
+ new_history = history + [(user_input, err)]
94
+ return new_history, new_history, ""
95
+
96
+
97
+ def clear_history():
98
+ return [], [], ""
99
+
100
+
101
+ CSS = """
102
+ @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=DM+Sans:wght@300;400;600&display=swap');
103
+
104
+ body, .gradio-container {
105
+ background: #0a0a0f !important;
106
+ color: #e8e8f0 !important;
107
+ font-family: 'DM Sans', sans-serif !important;
108
+ }
109
+
110
+ .gradio-container {
111
+ max-width: 900px !important;
112
+ margin: 0 auto !important;
113
+ }
114
+
115
+ h1 {
116
+ font-family: 'Space Mono', monospace !important;
117
+ font-size: 1.8rem !important;
118
+ color: #a78bfa !important;
119
+ text-align: center;
120
+ letter-spacing: -1px;
121
+ margin-bottom: 4px !important;
122
+ }
123
+
124
+ .subtitle {
125
+ text-align: center;
126
+ color: #6b6b8a;
127
+ font-size: 0.85rem;
128
+ margin-bottom: 24px;
129
+ font-family: 'Space Mono', monospace;
130
+ }
131
+
132
+ .chatbot .message {
133
+ font-family: 'Space Mono', monospace !important;
134
+ font-size: 0.78rem !important;
135
+ }
136
+
137
+ .chatbot .user {
138
+ background: #1a1a2e !important;
139
+ border: 1px solid #2d2d4e !important;
140
+ border-radius: 8px !important;
141
+ }
142
+
143
+ .chatbot .bot {
144
+ background: #0d1117 !important;
145
+ border: 1px solid #7c3aed44 !important;
146
+ border-radius: 8px !important;
147
+ color: #c4b5fd !important;
148
+ }
149
+
150
+ textarea, input {
151
+ background: #111120 !important;
152
+ border: 1px solid #2d2d4e !important;
153
+ color: #e8e8f0 !important;
154
+ border-radius: 8px !important;
155
+ font-family: 'DM Sans', sans-serif !important;
156
+ }
157
+
158
+ button.primary {
159
+ background: linear-gradient(135deg, #7c3aed, #a855f7) !important;
160
+ border: none !important;
161
+ border-radius: 8px !important;
162
+ color: white !important;
163
+ font-family: 'Space Mono', monospace !important;
164
+ font-weight: 700 !important;
165
+ letter-spacing: 1px !important;
166
+ }
167
+
168
+ button.secondary {
169
+ background: #1a1a2e !important;
170
+ border: 1px solid #2d2d4e !important;
171
+ color: #6b6b8a !important;
172
+ border-radius: 8px !important;
173
+ }
174
+
175
+ .examples-table td {
176
+ background: #111120 !important;
177
+ border: 1px solid #2d2d4e !important;
178
+ color: #a78bfa !important;
179
+ font-family: 'Space Mono', monospace !important;
180
+ font-size: 0.75rem !important;
181
+ }
182
+ """
183
+
184
+ with gr.Blocks(css=CSS, title="PromptForge") as demo:
185
+ gr.HTML("""
186
+ <h1>⚡ PromptForge</h1>
187
+ <p class="subtitle">simple words → detailed JSON image & video prompts</p>
188
+ """)
189
+
190
+ chatbot = gr.Chatbot(
191
+ label="",
192
+ height=480,
193
+ show_label=False,
194
+ render_markdown=True,
195
+ bubble_full_width=False,
196
+ )
197
+
198
+ state = gr.State([])
199
+
200
+ with gr.Row():
201
+ txt = gr.Textbox(
202
+ placeholder="Describe a scene, mood, or idea... e.g. 'a samurai in rainy Tokyo at night'",
203
+ show_label=False,
204
+ scale=5,
205
+ lines=1,
206
+ )
207
+ btn = gr.Button("FORGE →", variant="primary", scale=1)
208
+ clr = gr.Button("Clear", variant="secondary", scale=1)
209
+
210
+ gr.Examples(
211
+ examples=[
212
+ ["a lone astronaut on a red alien desert at sunset"],
213
+ ["a cozy Japanese cafe interior in winter morning"],
214
+ ["an ancient dragon flying over a burning medieval city"],
215
+ ["a neon-lit cyberpunk street market in heavy rain"],
216
+ ["a peaceful mountain lake reflection at golden hour"],
217
+ ],
218
+ inputs=txt,
219
+ label="Try these →",
220
+ )
221
+
222
+ btn.click(generate_prompts, [txt, state], [chatbot, state, txt])
223
+ txt.submit(generate_prompts, [txt, state], [chatbot, state, txt])
224
+ clr.click(clear_history, [], [chatbot, state, txt])
225
+
226
+ demo.launch(server_name="0.0.0.0", server_port=7860)