Aleksmorshen commited on
Commit
c8373b5
·
verified ·
1 Parent(s): 33d7857

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +635 -64
app.py CHANGED
@@ -1,75 +1,646 @@
1
- import gradio as gr
2
- import google.generativeai as genai
3
- from PIL import Image
4
  import io
 
 
 
 
5
  import numpy as np
6
 
7
- def generate_content(api_key, image_data, language):
8
- genai.configure(api_key=api_key)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- # Convert uploaded image data into a PIL image
11
- if image_data is None:
12
- return "Пожалуйста, загрузите изображение!"
13
- image = Image.fromarray(np.uint8(image_data)).convert('RGB')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # Base prompt
16
  base_prompt = "Напиши большой и красивый, содержательный рекламный пост минимум на 1000 символов со смайликами и 25 тематических хэштегов с ключевыми словами разных вариантов, чтобы мои клиенты могли найти меня в поиске Instagram, Google и т.д. по ключевым словам. Пост пиши исключительно под товар, который на фото, без адресов и номеров телефона."
17
 
18
- # Modify prompt based on selected language
19
  if language == "Русский":
20
- final_prompt = f"{base_prompt} Пиши на русском языке."
21
  elif language == "Кыргызский":
22
- final_prompt = f"{base_prompt} Пиши на кыргызском языке."
23
  elif language == "Казахский":
24
- final_prompt = f"{base_prompt} Пиши на казахском языке."
25
  elif language == "Узбекский":
26
- final_prompt = f"{base_prompt} Пиши на узбекском языке."
27
- else:
28
- final_prompt = base_prompt # Default to Russian if no language selected
29
-
30
- # Initialize the model
31
- model = genai.GenerativeModel('learnlm-2.0-flash-experimental')
32
-
33
- # Generate content with the image and prompt
34
- response = model.generate_content([final_prompt, image])
35
- response.resolve()
36
- return response.text
37
-
38
- # Gradio interface
39
- with gr.Blocks(title="EVA - Генератор рекламных постов") as app:
40
- gr.Markdown("# EVA - Загрузи изображение, выбери язык и получи красивый рекламный пост!")
41
-
42
- # API Key input
43
- api_key_input = gr.Textbox(
44
- label="API Key",
45
- type="password",
46
- value="AIzaSyArKidc4o0MwbaCFKStlb2q2AwNg6Pnqns",
47
- placeholder="Введите ваш API Key",
48
- lines=1
49
- )
50
-
51
- # Language selection
52
- language_input = gr.Radio(
53
- choices=["Русский", "Кыргызский", "Казахский", "Узбекский"],
54
- label="Выберите язык поста",
55
- value="Русский" # Default value
56
- )
57
-
58
- # Image input
59
- image_input = gr.Image(label="Загрузить изображение")
60
-
61
- # Generate button
62
- generate_button = gr.Button("Пуск")
63
-
64
- # Output
65
- output = gr.Markdown(label="Результат")
66
-
67
- # Button click event
68
- generate_button.click(
69
- fn=generate_content,
70
- inputs=[api_key_input, image_input, language_input],
71
- outputs=output
72
- )
73
-
74
- # Launch the app
75
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
 
 
2
  import io
3
+ import base64
4
+ from flask import Flask, request, jsonify, Response
5
+ from PIL import Image
6
+ import google.generativeai as genai
7
  import numpy as np
8
 
9
+ app = Flask(__name__)
10
+
11
+ API_KEY_INTERNAL = "AIzaSyArKidc4o0MwbaCFKStlb2q2AwNg6Pnqns" # Hardcoded API Key
12
+
13
+ html_template = """
14
+ <!DOCTYPE html>
15
+ <html lang="ru">
16
+ <head>
17
+ <meta charset="UTF-8">
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
19
+ <title>EVA - Генератор постов</title>
20
+ <style>
21
+ :root {
22
+ --system-gray-100-light: #f2f2f7;
23
+ --system-gray-75-light: #f8f8fa;
24
+ --system-gray-50-light: #ffffff;
25
+ --system-gray-dark-100-light: #000000;
26
+ --system-gray-dark-75-light: #1c1c1e;
27
+ --system-gray-dark-50-light: #3a3a3c;
28
+ --system-gray-light-75-light: #8e8e93;
29
+ --system-gray-light-50-light: #aeaeb2;
30
+ --system-blue-light: #007aff;
31
+ --system-blue-light-hover: #005ecf;
32
+ --system-red-light: #ff3b30;
33
+ --system-separator-light: rgba(60, 60, 67, 0.29);
34
+ --system-separator-opaque-light: #d1d1d6;
35
+
36
+ --system-gray-100-dark: #1c1c1e;
37
+ --system-gray-75-dark: #2c2c2e;
38
+ --system-gray-50-dark: #000000;
39
+ --system-gray-dark-100-dark: #ffffff;
40
+ --system-gray-dark-75-dark: #f2f2f7;
41
+ --system-gray-dark-50-dark: #e5e5ea;
42
+ --system-gray-light-75-dark: #8e8e93;
43
+ --system-gray-light-50-dark: #636366;
44
+ --system-blue-dark: #0a84ff;
45
+ --system-blue-dark-hover: #3b9eff;
46
+ --system-red-dark: #ff453a;
47
+ --system-separator-dark: rgba(84, 84, 88, 0.65);
48
+ --system-separator-opaque-dark: #38383a;
49
+ }
50
+
51
+ @media (prefers-color-scheme: dark) {
52
+ :root {
53
+ --bg-color: var(--system-gray-50-dark);
54
+ --content-bg: var(--system-gray-100-dark);
55
+ --text-color: var(--system-gray-dark-100-dark);
56
+ --secondary-text-color: var(--system-gray-light-75-dark);
57
+ --tertiary-text-color: var(--system-gray-light-50-dark);
58
+ --border-color: var(--system-separator-dark);
59
+ --border-color-opaque: var(--system-separator-opaque-dark);
60
+ --input-bg: var(--system-gray-75-dark);
61
+ --primary-color: var(--system-blue-dark);
62
+ --primary-color-hover: var(--system-blue-dark-hover);
63
+ --error-color: var(--system-red-dark);
64
+ }
65
+ }
66
+
67
+ @media (prefers-color-scheme: light) {
68
+ :root {
69
+ --bg-color: var(--system-gray-100-light);
70
+ --content-bg: var(--system-gray-50-light);
71
+ --text-color: var(--system-gray-dark-100-light);
72
+ --secondary-text-color: var(--system-gray-light-75-light);
73
+ --tertiary-text-color: var(--system-gray-light-50-light);
74
+ --border-color: var(--system-separator-light);
75
+ --border-color-opaque: var(--system-separator-opaque-light);
76
+ --input-bg: var(--system-gray-75-light);
77
+ --primary-color: var(--system-blue-light);
78
+ --primary-color-hover: var(--system-blue-light-hover);
79
+ --error-color: var(--system-red-light);
80
+ }
81
+ }
82
+
83
+ html {
84
+ height: -webkit-fill-available;
85
+ }
86
+
87
+ body {
88
+ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
89
+ margin: 0;
90
+ padding: 20px env(safe-area-inset-top) 20px env(safe-area-inset-bottom);
91
+ background-color: var(--bg-color);
92
+ color: var(--text-color);
93
+ display: flex;
94
+ justify-content: center;
95
+ align-items: flex-start;
96
+ min-height: 100vh;
97
+ min-height: -webkit-fill-available;
98
+ line-height: 1.45;
99
+ -webkit-font-smoothing: antialiased;
100
+ -moz-osx-font-smoothing: grayscale;
101
+ }
102
+
103
+ .container {
104
+ background-color: var(--content-bg);
105
+ padding: 25px 30px 30px 30px;
106
+ border-radius: 24px;
107
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0,0,0,0.05);
108
+ max-width: 580px;
109
+ width: calc(100% - 40px);
110
+ box-sizing: border-box;
111
+ margin-top: 30px;
112
+ }
113
+
114
+ h1 {
115
+ font-size: 32px;
116
+ font-weight: 700;
117
+ text-align: center;
118
+ margin-bottom: 8px;
119
+ color: var(--text-color);
120
+ letter-spacing: -0.5px;
121
+ }
122
+
123
+ p.subtitle {
124
+ font-size: 17px;
125
+ color: var(--secondary-text-color);
126
+ text-align: center;
127
+ margin-bottom: 35px;
128
+ font-weight: 400;
129
+ }
130
+
131
+ .form-group {
132
+ margin-bottom: 28px;
133
+ }
134
+
135
+ label.input-label {
136
+ display: block;
137
+ font-weight: 500;
138
+ margin-bottom: 10px;
139
+ font-size: 15px;
140
+ color: var(--secondary-text-color);
141
+ padding-left: 5px;
142
+ }
143
+
144
+ input[type="file"] {
145
+ width: 100%;
146
+ padding: 14px 18px;
147
+ border: 1px solid var(--border-color-opaque);
148
+ border-radius: 12px;
149
+ font-size: 16px;
150
+ background-color: var(--input-bg);
151
+ color: var(--text-color);
152
+ box-sizing: border-box;
153
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
154
+ cursor: pointer;
155
+ font-family: inherit;
156
+ }
157
+
158
+ input[type="file"]:focus {
159
+ border-color: var(--primary-color);
160
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 25%, transparent);
161
+ outline: none;
162
+ }
163
+
164
+ input[type="file"]::file-selector-button {
165
+ font-weight: 500;
166
+ color: var(--primary-color);
167
+ background-color: transparent;
168
+ border: none;
169
+ padding: 0;
170
+ margin-right: 12px;
171
+ cursor: pointer;
172
+ font-size: 16px;
173
+ }
174
+
175
+ .language-options {
176
+ display: flex;
177
+ flex-wrap: wrap;
178
+ gap: 10px;
179
+ margin-top: 5px;
180
+ }
181
+
182
+ .language-options label {
183
+ display: flex;
184
+ align-items: center;
185
+ background-color: var(--input-bg);
186
+ padding: 10px 18px;
187
+ border-radius: 25px;
188
+ cursor: pointer;
189
+ transition: background-color 0.2s ease, color 0.2s ease, transform 0.1s ease;
190
+ font-weight: 500;
191
+ font-size: 14px;
192
+ color: var(--tertiary-text-color);
193
+ border: 1px solid transparent;
194
+ user-select: none;
195
+ }
196
+
197
+ .language-options input[type="radio"] {
198
+ display: none;
199
+ }
200
+
201
+ .language-options input[type="radio"]:checked + label {
202
+ background-color: var(--primary-color);
203
+ color: white;
204
+ font-weight: 600;
205
+ border-color: transparent;
206
+ }
207
+
208
+ .language-options label:hover {
209
+ background-color: color-mix(in srgb, var(--input-bg) 85%, var(--secondary-text-color));
210
+ }
211
+
212
+ .language-options input[type="radio"]:checked + label:hover {
213
+ background-color: var(--primary-color-hover);
214
+ }
215
+
216
+ .language-options label:active {
217
+ transform: scale(0.96);
218
+ }
219
+
220
+
221
+ button#generate-button {
222
+ width: 100%;
223
+ padding: 16px;
224
+ background-color: var(--primary-color);
225
+ color: white;
226
+ border: none;
227
+ border-radius: 12px;
228
+ font-size: 17px;
229
+ font-weight: 600;
230
+ cursor: pointer;
231
+ transition: background-color 0.2s ease, transform 0.1s ease;
232
+ margin-top: 15px;
233
+ }
234
+
235
+ button#generate-button:hover {
236
+ background-color: var(--primary-color-hover);
237
+ }
238
+
239
+ button#generate-button:active {
240
+ transform: scale(0.98);
241
+ }
242
+
243
+ button#generate-button:disabled {
244
+ background-color: var(--tertiary-text-color);
245
+ cursor: not-allowed;
246
+ }
247
+
248
+ .output-section {
249
+ margin-top: 35px;
250
+ }
251
+
252
+ .output-header {
253
+ display: flex;
254
+ justify-content: space-between;
255
+ align-items: center;
256
+ margin-bottom: 10px;
257
+ }
258
+
259
+ label#output-label {
260
+ font-weight: 500;
261
+ font-size: 15px;
262
+ color: var(--secondary-text-color);
263
+ padding-left: 5px;
264
+ }
265
+
266
+ button#copy-button {
267
+ background-color: transparent;
268
+ border: none;
269
+ color: var(--primary-color);
270
+ font-size: 14px;
271
+ font-weight: 500;
272
+ cursor: pointer;
273
+ padding: 5px 8px;
274
+ border-radius: 6px;
275
+ transition: background-color 0.2s ease, color 0.2s ease;
276
+ display: none;
277
+ }
278
+
279
+ button#copy-button:hover {
280
+ background-color: color-mix(in srgb, var(--primary-color) 15%, transparent);
281
+ }
282
+
283
+ button#copy-button:active {
284
+ background-color: color-mix(in srgb, var(--primary-color) 25%, transparent);
285
+ }
286
+
287
+ button#copy-button.copied {
288
+ color: #34c759; /* System Green */
289
+ }
290
+ @media (prefers-color-scheme: dark) {
291
+ button#copy-button.copied {
292
+ color: #30d158; /* System Green Dark */
293
+ }
294
+ }
295
+
296
+
297
+ #output-container {
298
+ background-color: var(--input-bg);
299
+ padding: 18px 20px;
300
+ border-radius: 12px;
301
+ min-height: 120px;
302
+ border: 1px solid var(--border-color);
303
+ white-space: pre-wrap;
304
+ word-wrap: break-word;
305
+ font-size: 15px;
306
+ color: var(--text-color);
307
+ line-height: 1.5;
308
+ transition: border-color 0.2s ease, background-color 0.2s ease;
309
+ }
310
+
311
+ #output-container.loading::before {
312
+ content: "Генерация...";
313
+ display: block;
314
+ text-align: center;
315
+ font-style: italic;
316
+ color: var(--secondary-text-color);
317
+ animation: fadePulse 1.8s infinite ease-in-out;
318
+ padding-top: 30px;
319
+ }
320
+
321
+ #output-container.error {
322
+ color: var(--error-color);
323
+ font-weight: 500;
324
+ border-color: color-mix(in srgb, var(--error-color) 50%, transparent);
325
+ background-color: color-mix(in srgb, var(--error-color) 10%, var(--input-bg));
326
+ }
327
+
328
+ #image-preview-container {
329
+ margin-top: 15px;
330
+ text-align: center;
331
+ }
332
+
333
+ #image-preview {
334
+ max-width: 100%;
335
+ max-height: 220px;
336
+ border-radius: 12px;
337
+ margin-top: 10px;
338
+ border: 1px solid var(--border-color-opaque);
339
+ display: none;
340
+ background-color: var(--input-bg); /* Placeholder bg */
341
+ }
342
+
343
+ @keyframes fadePulse {
344
+ 0%, 100% { opacity: 0.6; }
345
+ 50% { opacity: 1; }
346
+ }
347
+
348
+ @media (max-width: 620px) {
349
+ body {
350
+ padding: 15px env(safe-area-inset-top) 15px env(safe-area-inset-bottom);
351
+ align-items: flex-start;
352
+ }
353
+ .container {
354
+ padding: 20px 20px 25px 20px;
355
+ margin-top: 15px;
356
+ border-radius: 20px;
357
+ width: calc(100% - 30px);
358
+ }
359
+ h1 {
360
+ font-size: 28px;
361
+ }
362
+ p.subtitle {
363
+ font-size: 16px;
364
+ margin-bottom: 25px;
365
+ }
366
+ .form-group {
367
+ margin-bottom: 22px;
368
+ }
369
+ input[type="file"] {
370
+ padding: 12px 15px;
371
+ }
372
+ input[type="file"]::file-selector-button {
373
+ font-size: 15px;
374
+ margin-right: 10px;
375
+ }
376
+ .language-options {
377
+ gap: 8px;
378
+ justify-content: space-evenly;
379
+ }
380
+ .language-options label {
381
+ padding: 9px 16px;
382
+ font-size: 13px;
383
+ }
384
+ button#generate-button {
385
+ padding: 15px;
386
+ font-size: 16px;
387
+ }
388
+ #output-container {
389
+ padding: 15px 18px;
390
+ font-size: 14px;
391
+ min-height: 100px;
392
+ }
393
+ .output-section {
394
+ margin-top: 30px;
395
+ }
396
+ }
397
 
398
+ </style>
399
+ </head>
400
+ <body>
401
+ <div class="container">
402
+ <h1>EVA</h1>
403
+ <p class="subtitle">Генератор рекламных постов</p>
404
+
405
+ <form id="generate-form">
406
+
407
+ <div class="form-group">
408
+ <label class="input-label">Выберите язык поста</label>
409
+ <div class="language-options">
410
+ <input type="radio" id="lang-ru" name="language" value="Русский" checked>
411
+ <label for="lang-ru">Русский</label>
412
+
413
+ <input type="radio" id="lang-kg" name="language" value="Кыргызский">
414
+ <label for="lang-kg">Кыргызский</label>
415
+
416
+ <input type="radio" id="lang-kz" name="language" value="Казахский">
417
+ <label for="lang-kz">Казахский</label>
418
+
419
+ <input type="radio" id="lang-uz" name="language" value="Узбекский">
420
+ <label for="lang-uz">Узбекский</label>
421
+ </div>
422
+ </div>
423
+
424
+ <div class="form-group">
425
+ <label for="image-upload" class="input-label">Загрузить изображение</label>
426
+ <input type="file" id="image-upload" name="image" accept="image/*" required>
427
+ <div id="image-preview-container">
428
+ <img id="image-preview" src="#" alt="Предпросмотр изображения"/>
429
+ </div>
430
+ </div>
431
+
432
+ <button type="submit" id="generate-button">Пуск</button>
433
+ </form>
434
+
435
+ <div class="output-section">
436
+ <div class="output-header">
437
+ <label id="output-label">Результат</label>
438
+ <button id="copy-button">Копировать</button>
439
+ </div>
440
+ <div id="output-container" aria-live="polite">
441
+ </div>
442
+ </div>
443
+ </div>
444
+
445
+ <script>
446
+ const form = document.getElementById('generate-form');
447
+ const imageInput = document.getElementById('image-upload');
448
+ const imagePreview = document.getElementById('image-preview');
449
+ const outputContainer = document.getElementById('output-container');
450
+ const generateButton = document.getElementById('generate-button');
451
+ const imagePreviewContainer = document.getElementById('image-preview-container');
452
+ const copyButton = document.getElementById('copy-button');
453
+
454
+ imageInput.addEventListener('change', function(event) {
455
+ const file = event.target.files[0];
456
+ if (file && file.type.startsWith('image/')) {
457
+ const reader = new FileReader();
458
+ reader.onload = function(e) {
459
+ imagePreview.src = e.target.result;
460
+ imagePreview.style.display = 'block';
461
+ }
462
+ reader.readAsDataURL(file);
463
+ } else {
464
+ imagePreview.src = '#';
465
+ imagePreview.style.display = 'none';
466
+ }
467
+ });
468
+
469
+ form.addEventListener('submit', async (event) => {
470
+ event.preventDefault();
471
+
472
+ if (!imageInput.files || imageInput.files.length === 0) {
473
+ showError("Пожалуйста, загрузите изображение.");
474
+ return;
475
+ }
476
+
477
+ const formData = new FormData(form);
478
+
479
+ generateButton.disabled = true;
480
+ generateButton.textContent = 'Генерация...';
481
+ outputContainer.innerHTML = '';
482
+ outputContainer.classList.add('loading');
483
+ outputContainer.classList.remove('error');
484
+ copyButton.style.display = 'none';
485
+ copyButton.textContent = 'Копировать';
486
+ copyButton.classList.remove('copied');
487
+
488
+
489
+ try {
490
+ const response = await fetch('/generate', {
491
+ method: 'POST',
492
+ body: formData
493
+ });
494
+
495
+ const result = await response.json();
496
+
497
+ if (!response.ok) {
498
+ throw new Error(result.error || `Ошибка сервера: ${response.status}`);
499
+ }
500
+
501
+ outputContainer.textContent = result.text;
502
+ if (result.text && result.text.trim().length > 0) {
503
+ copyButton.style.display = 'block';
504
+ } else {
505
+ copyButton.style.display = 'none';
506
+ }
507
+
508
+
509
+ } catch (error) {
510
+ console.error("Fetch Error:", error);
511
+ showError(`Ошибка: ${error.message}`);
512
+ copyButton.style.display = 'none';
513
+ } finally {
514
+ generateButton.disabled = false;
515
+ generateButton.textContent = 'Пуск';
516
+ outputContainer.classList.remove('loading');
517
+ }
518
+ });
519
+
520
+ copyButton.addEventListener('click', () => {
521
+ const textToCopy = outputContainer.textContent;
522
+ if (!textToCopy) return;
523
+
524
+ navigator.clipboard.writeText(textToCopy).then(() => {
525
+ copyButton.textContent = 'Скопировано!';
526
+ copyButton.classList.add('copied');
527
+ setTimeout(() => {
528
+ copyButton.textContent = 'Копировать';
529
+ copyButton.classList.remove('copied');
530
+ }, 1500);
531
+ }).catch(err => {
532
+ console.error('Ошибка копирования: ', err);
533
+ copyButton.textContent = 'Ошибка';
534
+ setTimeout(() => {
535
+ copyButton.textContent = 'Копировать';
536
+ }, 1500);
537
+ });
538
+ });
539
+
540
+ function showError(message) {
541
+ outputContainer.textContent = message;
542
+ outputContainer.classList.add('error');
543
+ outputContainer.classList.remove('loading');
544
+ copyButton.style.display = 'none';
545
+ }
546
+
547
+ </script>
548
+ </body>
549
+ </html>
550
+ """
551
+
552
+ def generate_ai_content(image_data, language):
553
+ try:
554
+ genai.configure(api_key=API_KEY_INTERNAL)
555
+ except Exception as e:
556
+ print(f"Error configuring GenAI: {e}")
557
+ raise ValueError(f"Не удалось настроить Google AI. Проблема с конфигурацией. Ошибка: {e}")
558
+
559
+ try:
560
+ if not image_data:
561
+ raise ValueError("Файл изображения не найден.")
562
+
563
+ image_stream = io.BytesIO(image_data)
564
+ image = Image.open(image_stream).convert('RGB')
565
+
566
+ except Exception as e:
567
+ print(f"Error processing image: {e}")
568
+ raise ValueError(f"Не удалось обработать изображение. Убедитесь, что это действительный файл изображения. Ошибка: {e}")
569
 
 
570
  base_prompt = "Напиши большой и красивый, содержательный рекламный пост минимум на 1000 символов со смайликами и 25 тематических хэштегов с ключевыми словами разных вариантов, чтобы мои клиенты могли найти меня в поиске Instagram, Google и т.д. по ключевым словам. Пост пиши исключительно под товар, который на фото, без адресов и номеров телефона."
571
 
572
+ lang_suffix = ""
573
  if language == "Русский":
574
+ lang_suffix = " Пиши на русском языке."
575
  elif language == "Кыргызский":
576
+ lang_suffix = " Пиши на кыргызском языке."
577
  elif language == "Казахский":
578
+ lang_suffix = " Пиши на казахском языке."
579
  elif language == "Узбекский":
580
+ lang_suffix = " Пиши на узбекском языке."
581
+
582
+ final_prompt = f"{base_prompt}{lang_suffix}"
583
+
584
+ try:
585
+ model = genai.GenerativeModel('learnlm-2.0-flash-experimental')
586
+
587
+ response = model.generate_content([final_prompt, image])
588
+
589
+ if hasattr(response, 'text'):
590
+ return response.text
591
+ else:
592
+ if response.parts:
593
+ return "".join(part.text for part in response.parts if hasattr(part, 'text'))
594
+ else:
595
+ print("Warning: Unexpected response structure:", response)
596
+ response.resolve()
597
+ return response.text
598
+
599
+ except Exception as e:
600
+ print(f"Error generating content with GenAI: {e}")
601
+ if "API key not valid" in str(e):
602
+ raise ValueError("Внутренняя ошибка конфигурации API.")
603
+ elif " Billing account not found" in str(e):
604
+ raise ValueError("Проблема с биллингом аккаунта Google Cloud.")
605
+ elif "Could not find model" in str(e):
606
+ raise ValueError(f"Модель 'gemini-1.5-flash' не найдена или недоступна.")
607
+ elif "resource has been exhausted" in str(e).lower():
608
+ raise ValueError("Квота запросов исчерпана. Попробуйте позже.")
609
+ elif "content has been blocked" in str(e).lower() or (hasattr(response, 'prompt_feedback') and response.prompt_feedback.block_reason):
610
+ reason = response.prompt_feedback.block_reason if hasattr(response, 'prompt_feedback') else "неизвестна"
611
+ raise ValueError(f"Генерация контента заблокирована из-за политики безопасности (причина: {reason}). Попробуйте другое изображение или запрос.")
612
+ else:
613
+ raise ValueError(f"Ошибка при генерации контента: {e}")
614
+
615
+
616
+ @app.route('/')
617
+ def index():
618
+ return Response(html_template, mimetype='text/html')
619
+
620
+ @app.route('/generate', methods=['POST'])
621
+ def handle_generate():
622
+ if 'image' not in request.files:
623
+ return jsonify({"error": "Изображение не найдено в запросе."}), 400
624
+ if 'language' not in request.form:
625
+ return jsonify({"error": "Язык не найден в запросе."}), 400
626
+
627
+ image_file = request.files['image']
628
+ language = request.form['language']
629
+
630
+ image_data = image_file.read()
631
+
632
+ if not image_data:
633
+ return jsonify({"error": "Загруженный файл изображения пуст."}), 400
634
+
635
+ try:
636
+ result_text = generate_ai_content(image_data, language)
637
+ return jsonify({"text": result_text})
638
+ except ValueError as ve:
639
+ return jsonify({"error": str(ve)}), 400
640
+ except Exception as e:
641
+ print(f"Unexpected error during generation: {e}")
642
+ return jsonify({"error": f"Внутренняя ошибка сервера: {e}"}), 500
643
+
644
+
645
+ if __name__ == '__main__':
646
+ app.run(host='0.0.0.0', port=7860, debug=False)