John6666 commited on
Commit
bc33bde
·
verified ·
1 Parent(s): df82c19

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +9 -8
  2. app.py +178 -153
  3. requirements.txt +1 -2
README.md CHANGED
@@ -1,14 +1,15 @@
1
  ---
2
- title: Anycoder 1404a139
3
- emoji:
4
- colorFrom: purple
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 6.0.2
8
  app_file: app.py
9
  pinned: false
10
- tags:
11
- - anycoder
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
1
  ---
2
+ title: Anycoder
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: purple
6
  sdk: gradio
 
7
  app_file: app.py
8
  pinned: false
9
+ python_version: "3.10"
 
10
  ---
11
 
12
+ ## Setup
13
+
14
+ 1. Add a Space secret named `GEMINI_API_KEY`.
15
+ 2. (Optional) Set `GEMINI_MODEL` to override the default model (`gemini-2.0-flash`).
app.py CHANGED
@@ -1,175 +1,200 @@
1
  import os
 
 
 
2
  import gradio as gr
3
- import google.generativeai as genai
4
- from PIL import Image
5
- import typing
6
 
 
7
  # Configuration
8
- MODEL_ID = "gemini-2.0-flash-exp"
 
9
 
10
- def generate_content(
11
- prompt: str,
12
- image1: str | None,
13
- image2: str | None,
14
- image3: str | None,
15
- api_key: str
16
- ) -> tuple[str | None, str | None]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  """
18
- Generates content using Google Gemini 2.0 Flash.
19
- Handles both text-to-image/image-editing and text responses.
20
  """
21
- if not api_key:
22
- raise gr.Error("Please enter your Google API Key to continue.")
23
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  try:
25
- genai.configure(api_key=api_key)
26
- model = genai.GenerativeModel(MODEL_ID)
27
-
28
- # Prepare content parts
29
- parts = [prompt]
30
-
31
- # Add images if they exist
32
- images = [image1, image2, image3]
33
- for img_path in images:
34
- if img_path:
35
- # Upload file if necessary or read directly
36
- parts.append(Image.open(img_path))
37
-
38
- # Generate content
39
- response = model.generate_content(parts)
40
-
41
- # Resolve response
42
- response.resolve()
43
-
44
- # Check for image in response
45
- image_output = None
46
- text_output = None
47
-
48
- if response.candidates:
49
- for part in response.candidates[0].content.parts:
50
- if part.inline_data:
51
- # Save the generated image to a temporary file to display it
52
- image_data = part.inline_data.data
53
- import tempfile
54
- temp_dir = tempfile.gettempdir()
55
- # Create a unique filename
56
- filename = os.path.join(temp_dir, f"gemini_output_{os.urandom(4).hex()}.png")
57
- with open(filename, "wb") as f:
58
- f.write(image_data)
59
- image_output = filename
60
- elif part.text:
61
- text_output = part.text
62
-
63
- if image_output:
64
- return image_output, text_output or "Image generated successfully!"
65
- elif text_output:
66
- return None, text_output
67
- else:
68
- return None, "No content generated. Try a different prompt."
69
 
 
70
  except Exception as e:
71
- raise gr.Error(f"Error generating content: {str(e)}")
72
 
73
- # Gradio 6 Application
 
 
 
74
  with gr.Blocks() as demo:
75
-
76
- # Header
77
- gr.HTML("""
78
- <div style="text-align: center; margin-bottom: 20px;">
79
- <h1>✨ Gemini 2.0 Flash Studio</h1>
80
- <p>Next-Gen Image Generation & Editing powered by Google DeepMind</p>
81
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #007bff; text-decoration: none; font-weight: bold;">Built with anycoder</a>
82
- </div>
83
- """)
84
-
85
- # API Key Section
86
- gr.Markdown("### 🔑 Configuration")
87
  with gr.Row():
88
- api_key_input = gr.Textbox(
89
- label="Google API Key",
90
- type="password",
91
- placeholder="Enter your 'gemini-2.0-flash-exp' API Key here...",
92
- scale=4
93
  )
94
-
95
- gr.Markdown("### 🎨 Inputs")
96
-
97
- # Image Inputs (3 Blank Spots)
98
  with gr.Row():
99
- img_input_1 = gr.Image(
100
- label="Image 1 (Drag & Drop)",
101
- type="filepath",
102
- sources=["upload", "clipboard"],
103
- height=300
104
- )
105
- img_input_2 = gr.Image(
106
- label="Image 2 (Drag & Drop)",
107
- type="filepath",
108
- sources=["upload", "clipboard"],
109
- height=300
110
- )
111
- img_input_3 = gr.Image(
112
- label="Image 3 (Drag & Drop)",
113
- type="filepath",
114
- sources=["upload", "clipboard"],
115
- height=300
116
- )
117
 
118
- # Prompt Input
119
- prompt_input = gr.Textbox(
120
- label="✍️ Prompt",
121
- placeholder="Describe the image you want to generate or how you want to edit the uploaded images...",
122
  lines=3,
123
- show_copy_button=True
124
  )
125
-
126
- # Action Button
127
- generate_btn = gr.Button("✨ Generate", variant="primary", size="lg")
128
-
129
- gr.Markdown("### 🖼️ Output")
130
-
131
- # Output Section
132
- with gr.Row():
133
- with gr.Column():
134
- output_image = gr.Image(label="Generated Image", type="filepath", height=400)
135
- with gr.Column():
136
- output_text = gr.Textbox(label="Response / Description", lines=10)
137
-
138
- # Examples
139
- gr.Examples(
140
- examples=[
141
- ["Generate a futuristic cyberpunk city with neon lights", None, None, None],
142
- ["Edit this image to make it look like a painting", "https://gradio-builds.s3.amazonaws.com/assets/cheetah-003.jpg", None, None],
143
- ["Combine these two concepts into a logo", None, None, None], # Placeholder for logic
144
- ],
145
- inputs=[prompt_input, img_input_1, img_input_2, img_input_3],
146
  )
147
 
148
- # Event Listener
149
- generate_btn.click(
150
- fn=generate_content,
151
- inputs=[prompt_input, img_input_1, img_input_2, img_input_3, api_key_input],
152
- outputs=[output_image, output_text],
153
- api_visibility="public"
 
 
154
  )
155
 
156
- # Gradio 6 Launch Configuration
157
- # Note: theme, css, and footer_links are now in launch()
158
- demo.launch(
159
- theme=gr.themes.Soft(
160
- primary_hue="indigo",
161
- secondary_hue="cyan",
162
- neutral_hue="slate",
163
- font=gr.themes.GoogleFont("Inter"),
164
- text_size="lg",
165
- spacing_size="lg",
166
- radius_size="md"
167
- ).set(
168
- button_primary_background_fill="*primary_500",
169
- button_primary_background_fill_hover="*primary_600",
170
- button_primary_text_color="white",
171
- block_border_width="0px",
172
- block_shadow="*shadow_drop_lg"
173
- ),
174
- footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}]
175
- )
 
1
  import os
2
+ import mimetypes
3
+ from typing import Iterable, List, Optional, Tuple, Union
4
+
5
  import gradio as gr
6
+ from google import genai
7
+ from google.genai import types
8
+
9
 
10
+ # -----------------------------
11
  # Configuration
12
+ # -----------------------------
13
+ DEFAULT_MODEL = os.getenv("GEMINI_MODEL", "gemini-2.0-flash")
14
 
15
+ # Common Gemini models (edit as needed)
16
+ MODEL_CHOICES = [
17
+ "gemini-2.0-flash",
18
+ "gemini-2.5-flash",
19
+ "gemini-2.5-pro",
20
+ "gemini-3-flash-preview",
21
+ "gemini-3-pro-preview",
22
+ ]
23
+
24
+ DEFAULT_SYSTEM_INSTRUCTION = (
25
+ "You are a coding assistant. "
26
+ "When the user asks for code, output complete, runnable code. "
27
+ "Prefer simple, readable implementations and include brief comments where helpful."
28
+ )
29
+
30
+
31
+ # -----------------------------
32
+ # Client helper
33
+ # -----------------------------
34
+ _client: Optional[genai.Client] = None
35
+
36
+
37
+ def _get_api_key() -> Optional[str]:
38
+ # HF Spaces secrets often use GEMINI_API_KEY; keep a few fallbacks.
39
+ return (
40
+ os.getenv("GEMINI_API_KEY")
41
+ or os.getenv("GOOGLE_API_KEY")
42
+ or os.getenv("GOOGLE_GENAI_API_KEY")
43
+ )
44
+
45
+
46
+ def get_client() -> genai.Client:
47
+ global _client
48
+ if _client is None:
49
+ api_key = _get_api_key()
50
+ if not api_key:
51
+ raise RuntimeError(
52
+ "Missing API key. Set GEMINI_API_KEY in your Hugging Face Space secrets."
53
+ )
54
+ _client = genai.Client(api_key=api_key)
55
+ return _client
56
+
57
+
58
+ # -----------------------------
59
+ # Input helpers
60
+ # -----------------------------
61
+ def _coerce_filepath(item: object) -> Optional[str]:
62
+ """
63
+ Gradio file inputs can arrive as:
64
+ - str paths (type='filepath')
65
+ - dict-like objects with a 'path' key
66
+ - objects with a 'path' attribute
67
+ """
68
+ if item is None:
69
+ return None
70
+ if isinstance(item, str):
71
+ return item
72
+ if isinstance(item, dict) and "path" in item:
73
+ return item["path"]
74
+ path_attr = getattr(item, "path", None)
75
+ if isinstance(path_attr, str):
76
+ return path_attr
77
+ return None
78
+
79
+
80
+ def _guess_mime_type(path: str) -> str:
81
+ mime, _ = mimetypes.guess_type(path)
82
+ return mime or "application/octet-stream"
83
+
84
+
85
+ def build_contents(prompt: str, file_items: Optional[Iterable[object]]) -> List[object]:
86
  """
87
+ Build the `contents` list for client.models.generate_content().
88
+ Per Google docs, you can pass a list mixing strings and types.Part objects.
89
  """
90
+ contents: List[object] = [prompt]
91
+
92
+ if not file_items:
93
+ return contents
94
+
95
+ for item in file_items:
96
+ path = _coerce_filepath(item)
97
+ if not path:
98
+ continue
99
+
100
+ mime_type = _guess_mime_type(path)
101
+ try:
102
+ with open(path, "rb") as f:
103
+ data = f.read()
104
+ except Exception:
105
+ # If reading fails, skip that file but continue.
106
+ continue
107
+
108
+ # Attach as binary Part
109
+ contents.append(types.Part.from_bytes(data=data, mime_type=mime_type))
110
+
111
+ return contents
112
+
113
+
114
+ # -----------------------------
115
+ # Generation
116
+ # -----------------------------
117
+ def generate(
118
+ prompt: str,
119
+ model: str,
120
+ system_instruction: str,
121
+ temperature: float,
122
+ top_p: float,
123
+ top_k: int,
124
+ max_output_tokens: int,
125
+ files: Optional[List[object]],
126
+ ) -> str:
127
+ prompt = (prompt or "").strip()
128
+ if not prompt:
129
+ return "Error: prompt is empty."
130
+
131
  try:
132
+ client = get_client()
133
+ contents = build_contents(prompt, files)
134
+
135
+ config = types.GenerateContentConfig(
136
+ system_instruction=system_instruction.strip() if system_instruction else None,
137
+ temperature=temperature,
138
+ top_p=top_p,
139
+ top_k=top_k,
140
+ max_output_tokens=int(max_output_tokens),
141
+ )
142
+
143
+ resp = client.models.generate_content(
144
+ model=model or DEFAULT_MODEL,
145
+ contents=contents,
146
+ config=config,
147
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ return resp.text or ""
150
  except Exception as e:
151
+ return f"Error: {type(e).__name__}: {e}"
152
 
153
+
154
+ # -----------------------------
155
+ # UI
156
+ # -----------------------------
157
  with gr.Blocks() as demo:
158
+ gr.Markdown("# Anycoder (Gemini via google-genai)\n\n"
159
+ "This Space uses the **current** Google GenAI Python SDK (`google-genai`).\n"
160
+ "Set `GEMINI_API_KEY` in Space **Settings → Secrets**.")
161
+
 
 
 
 
 
 
 
 
162
  with gr.Row():
163
+ model = gr.Dropdown(
164
+ choices=MODEL_CHOICES,
165
+ value=DEFAULT_MODEL if DEFAULT_MODEL in MODEL_CHOICES else MODEL_CHOICES[0],
166
+ label="Model",
 
167
  )
168
+ temperature = gr.Slider(0.0, 2.0, value=0.2, step=0.05, label="Temperature")
169
+ max_output_tokens = gr.Slider(128, 8192, value=2048, step=64, label="Max output tokens")
170
+
 
171
  with gr.Row():
172
+ top_p = gr.Slider(0.0, 1.0, value=0.95, step=0.01, label="Top-p")
173
+ top_k = gr.Slider(1, 100, value=40, step=1, label="Top-k")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ system_instruction = gr.Textbox(
176
+ label="System instruction (optional)",
177
+ value=DEFAULT_SYSTEM_INSTRUCTION,
 
178
  lines=3,
 
179
  )
180
+
181
+ prompt = gr.Textbox(label="Prompt", lines=8, placeholder="Describe what you want the model to generate...")
182
+
183
+ files = gr.Files(
184
+ label="Optional files (images, audio, etc.)",
185
+ file_count="multiple",
186
+ type="filepath",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  )
188
 
189
+ btn = gr.Button("Generate", variant="primary")
190
+ output = gr.Code(label="Model output", language="markdown")
191
+
192
+ btn.click(
193
+ fn=generate,
194
+ inputs=[prompt, model, system_instruction, temperature, top_p, top_k, max_output_tokens, files],
195
+ outputs=[output],
196
+ api_visibility="public",
197
  )
198
 
199
+ if __name__ == "__main__":
200
+ demo.queue(api_open=False).launch(show_api=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,3 +1,2 @@
1
- Pillow
2
- google
3
  gradio>=6.0.2
 
 
 
 
1
  gradio>=6.0.2
2
+ google-genai