XopoIII commited on
Commit
8decc2b
Β·
verified Β·
1 Parent(s): 01140c9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +261 -0
app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py - PyIQA Image Quality Assessment API for Horsh
2
+ import gradio as gr
3
+ import pyiqa
4
+ import torch
5
+ from PIL import Image
6
+ import requests
7
+ from io import BytesIO
8
+ import os
9
+
10
+ # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ модСль ΠΏΡ€ΠΈ стартС
11
+ print("πŸš€ Loading ARNIQA model...")
12
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
13
+ metric = pyiqa.create_metric('arniqa', device=device)
14
+ print(f"βœ… Model loaded on {device}")
15
+
16
+ def assess_image_quality(image):
17
+ """
18
+ ΠžΡ†Π΅Π½ΠΈΡ‚ΡŒ качСство изобраТСния
19
+ Args:
20
+ image: PIL Image
21
+ Returns:
22
+ dict: {'quality': 0.75, 'score': 75, 'status': 'approved'}
23
+ """
24
+ try:
25
+ # Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ
26
+ temp_path = '/tmp/temp_image.jpg'
27
+ image.save(temp_path)
28
+
29
+ # ΠžΡ†Π΅Π½ΠΈΡ‚ΡŒ качСство (50-200ms)
30
+ with torch.no_grad():
31
+ score = metric(temp_path).item()
32
+
33
+ quality = score / 100.0 # ΠΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ 0-1
34
+ status = 'approved' if quality >= 0.3 else 'rejected'
35
+
36
+ return {
37
+ 'quality': round(quality, 3),
38
+ 'score': round(score, 2),
39
+ 'status': status,
40
+ 'threshold': 0.3,
41
+ 'model': 'ARNIQA (WACV 2024)',
42
+ 'device': str(device)
43
+ }
44
+
45
+ except Exception as e:
46
+ return {
47
+ 'error': str(e),
48
+ 'quality': 0.0,
49
+ 'score': 0.0,
50
+ 'status': 'error'
51
+ }
52
+
53
+ def assess_from_url(url):
54
+ """ΠžΡ†Π΅Π½ΠΈΡ‚ΡŒ ΠΏΠΎ URL"""
55
+ try:
56
+ if not url or not url.startswith('http'):
57
+ return {'error': 'Invalid URL. Must start with http:// or https://'}
58
+
59
+ response = requests.get(url, timeout=15)
60
+ response.raise_for_status()
61
+
62
+ img = Image.open(BytesIO(response.content))
63
+
64
+ # ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π² RGB Ссли Π½ΡƒΠΆΠ½ΠΎ
65
+ if img.mode != 'RGB':
66
+ img = img.convert('RGB')
67
+
68
+ return assess_image_quality(img)
69
+ except Exception as e:
70
+ return {
71
+ 'error': f'Failed to load image: {str(e)}',
72
+ 'quality': 0.0,
73
+ 'score': 0.0,
74
+ 'status': 'error'
75
+ }
76
+
77
+ # Gradio Interface
78
+ with gr.Blocks(
79
+ title="PyIQA Image Quality Assessment API",
80
+ theme=gr.themes.Soft()
81
+ ) as demo:
82
+
83
+ gr.Markdown("""
84
+ # πŸ“Έ Image Quality Assessment API
85
+
86
+ **Powered by ARNIQA** (WACV 2024) - State-of-the-art no-reference quality assessment
87
+
88
+ This API is used by [Horsh](https://hor.sh) photo-sharing app for automatic quality control.
89
+ """)
90
+
91
+ with gr.Tab("πŸ–ΌοΈ Upload Image"):
92
+ with gr.Row():
93
+ with gr.Column():
94
+ image_input = gr.Image(type="pil", label="Upload Image")
95
+ upload_btn = gr.Button("Assess Quality", variant="primary", size="lg")
96
+
97
+ gr.Markdown("""
98
+ **Threshold:** Quality score β‰₯ 0.3 = Approved
99
+ **Model:** ARNIQA (Learning Distortion Manifold)
100
+ **Speed:** ~50-200ms per image
101
+ """)
102
+
103
+ with gr.Column():
104
+ upload_output = gr.JSON(label="Quality Assessment Result")
105
+
106
+ upload_btn.click(
107
+ fn=assess_image_quality,
108
+ inputs=image_input,
109
+ outputs=upload_output
110
+ )
111
+
112
+ with gr.Tab("πŸ”— Image URL"):
113
+ with gr.Row():
114
+ with gr.Column():
115
+ url_input = gr.Textbox(
116
+ label="Image URL",
117
+ placeholder="https://example.com/photo.jpg",
118
+ lines=1
119
+ )
120
+ url_btn = gr.Button("Assess Quality", variant="primary", size="lg")
121
+
122
+ gr.Markdown("""
123
+ **Example URLs:**
124
+ - https://picsum.photos/800/600
125
+ - https://images.unsplash.com/photo-1506905925346-21bda4d32df4
126
+ """)
127
+
128
+ with gr.Column():
129
+ url_output = gr.JSON(label="Quality Assessment Result")
130
+
131
+ url_btn.click(
132
+ fn=assess_from_url,
133
+ inputs=url_input,
134
+ outputs=url_output
135
+ )
136
+
137
+ with gr.Tab("πŸ“š API Documentation"):
138
+ gr.Markdown("""
139
+ ## REST API Usage
140
+
141
+ This Space exposes a REST API for programmatic access.
142
+
143
+ ### Python (gradio_client)
144
+
145
+ ```python
146
+ from gradio_client import Client
147
+
148
+ client = Client("YOUR_USERNAME/pyiqa-api")
149
+
150
+ # Assess from URL
151
+ result = client.predict(
152
+ "https://example.com/photo.jpg",
153
+ api_name="/assess_from_url"
154
+ )
155
+ print(result['quality']) # 0.756
156
+ ```
157
+
158
+ ### Python (requests)
159
+
160
+ ```python
161
+ import requests
162
+ import json
163
+
164
+ url = "https://YOUR_USERNAME-pyiqa-api.hf.space/api/predict"
165
+
166
+ response = requests.post(url, json={
167
+ "data": ["https://example.com/photo.jpg"]
168
+ })
169
+
170
+ result = response.json()
171
+ quality = result['data'][0]['quality']
172
+ print(f"Quality: {quality}")
173
+ ```
174
+
175
+ ### Flutter/Dart
176
+
177
+ ```dart
178
+ import 'package:http/http.dart' as http;
179
+ import 'dart:convert';
180
+
181
+ Future<double> assessQuality(String imageUrl) async {
182
+ final response = await http.post(
183
+ Uri.parse('https://YOUR_USERNAME-pyiqa-api.hf.space/api/predict'),
184
+ headers: {'Content-Type': 'application/json'},
185
+ body: jsonEncode({'data': [imageUrl]}),
186
+ );
187
+
188
+ if (response.statusCode == 200) {
189
+ final result = jsonDecode(response.body);
190
+ return result['data'][0]['quality'];
191
+ }
192
+ throw Exception('Failed to assess quality');
193
+ }
194
+ ```
195
+
196
+ ### cURL
197
+
198
+ ```bash
199
+ curl -X POST https://YOUR_USERNAME-pyiqa-api.hf.space/api/predict \\
200
+ -H "Content-Type: application/json" \\
201
+ -d '{"data": ["https://example.com/photo.jpg"]}'
202
+ ```
203
+
204
+ ### JavaScript/TypeScript
205
+
206
+ ```javascript
207
+ const response = await fetch('https://YOUR_USERNAME-pyiqa-api.hf.space/api/predict', {
208
+ method: 'POST',
209
+ headers: { 'Content-Type': 'application/json' },
210
+ body: JSON.stringify({ data: ['https://example.com/photo.jpg'] })
211
+ });
212
+
213
+ const result = await response.json();
214
+ const quality = result.data[0].quality;
215
+ console.log('Quality:', quality);
216
+ ```
217
+
218
+ ## Response Format
219
+
220
+ ```json
221
+ {
222
+ "quality": 0.756,
223
+ "score": 75.6,
224
+ "status": "approved",
225
+ "threshold": 0.3,
226
+ "model": "ARNIQA (WACV 2024)",
227
+ "device": "cpu"
228
+ }
229
+ ```
230
+
231
+ ## Rate Limiting
232
+
233
+ - Free tier: No hard limits, but please be reasonable
234
+ - If you need high volume (>10k requests/day), contact us
235
+
236
+ ## Model Information
237
+
238
+ - **Paper:** [ARNIQA: Learning Distortion Manifold for Image Quality Assessment](https://arxiv.org/abs/2310.14918)
239
+ - **Conference:** WACV 2024 (Oral)
240
+ - **Code:** [miccunifi/ARNIQA](https://github.com/miccunifi/ARNIQA)
241
+ - **PyIQA:** [chaofengc/IQA-PyTorch](https://github.com/chaofengc/IQA-PyTorch)
242
+
243
+ ## About Horsh
244
+
245
+ This API powers quality control for [Horsh](https://hor.sh) - a photo-sharing app with AI-powered moderation.
246
+ """)
247
+
248
+ gr.Markdown("""
249
+ ---
250
+ **Note:** This is a public API. Please use responsibly. For production use, consider running your own instance.
251
+
252
+ **License:** Apache-2.0 | **Model:** ARNIQA (WACV 2024) | **Built with:** PyIQA + Gradio
253
+ """)
254
+
255
+ # Π—Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ
256
+ if __name__ == "__main__":
257
+ demo.launch(
258
+ server_name="0.0.0.0",
259
+ server_port=7860,
260
+ share=False
261
+ )