TheFrenchDemos commited on
Commit
bd0320b
·
1 Parent(s): 80a1838

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +20 -196
app.py CHANGED
@@ -1,234 +1,58 @@
1
  # docker build -t reward-simulator .docker run -p 7860:7860 -v $(pwd)/data:/app/data reward-simulator
2
 
 
3
  from PIL import Image
4
  import numpy as np
5
  import io
6
- import faiss
7
-
8
- import requests
9
  import torch
10
 
11
- from request import get_ft, get_topk
12
- ### from flickrapi import FlickrAPI
13
 
14
- from flask import Flask, request, render_template, jsonify, send_from_directory
15
  app = Flask(__name__)
16
 
17
- PRESET_IMAGES = {
18
- 1: "static/1.webp",
19
- 2: "static/2.webp",
20
- 3: "static/3.webp"
21
- }
22
-
23
- # Add Flickr configuration
24
- ### FLICKR_API_KEY = '80ef21a6f7eb0984ea613c316a89ca69'
25
- ### FLICKR_API_SECRET = '4d0e8ce6734f4b3f'
26
- ### flickr = FlickrAPI(FLICKR_API_KEY, FLICKR_API_SECRET, format='parsed-json', store_token=False)
27
-
28
- ### def get_photo_id(url):
29
- ### """Extract photo ID from Flickr URL"""
30
- ### try:
31
- ### return url.split('/')[-1].split('_')[0]
32
- ### except:
33
- ### return None
34
-
35
- ### def get_other_info(url):
36
- ### """Get author information from Flickr"""
37
- ### try:
38
- ### photo_id = get_photo_id(url)
39
- ### if photo_id:
40
- ### photo_info = flickr.photos.getInfo(photo_id=photo_id)
41
- ### license = photo_info['photo']['license']
42
- ### owner = photo_info['photo']['owner']
43
- ### flickr_url = f"https://www.flickr.com/photos/{owner.get('nsid', '')}/{photo_id}"
44
- ### return {
45
- ### 'username': owner.get('username', ''),
46
- ### 'realname': owner.get('realname', ''),
47
- ### 'nsid': owner.get('nsid', ''),
48
- ### 'flickr_url': flickr_url,
49
- ### 'license': license
50
- ### }
51
- ### except:
52
- ### pass
53
- ### return {
54
- ### 'username': 'Unknown',
55
- ### 'realname': 'Unknown',
56
- ### 'nsid': '',
57
- ### 'flickr_url': '',
58
- ### 'license': 'Unknown'
59
- ### }
60
-
61
-
62
- ### def load_model():
63
- ### """Load DINOv2 model once and cache it"""
64
- ### torch.hub.set_dir('static')
65
- ### model = torch.hub.load('facebookresearch/dinov2', 'dinov2_vits14')
66
- ### model.eval()
67
- ### model.to(torch.device('cuda' if torch.cuda.is_available() else 'cpu'))
68
- ### return model
69
-
70
- ### def load_index(index_path):
71
- ### """Load FAISS index once and cache it"""
72
- ### return faiss.read_index(index_path)
73
-
74
- def distance_to_similarity(distances, temp=1e-4):
75
- """Convert distance to similarity"""
76
- for ii in range(len(distances)):
77
- contribs = distances[ii].max() - distances[ii]
78
- contribs = contribs / temp
79
- sum_contribs = np.exp(contribs).sum()
80
- distances[ii] = np.exp(contribs) / sum_contribs
81
- return distances
82
-
83
- import os
84
-
85
- import os
86
- from PIL import Image
87
- import numpy as np
88
-
89
- def calculate_rewards(subscription, num_generations, author_share, ro_share, num_users_k, similarities, num_authors=1800):
90
- """Calculate raw similarity (distance) between two static images"""
91
-
92
- try:
93
- if os.path.exists("static/1.webp") and os.path.exists("static/2.webp"):
94
- image1 = Image.open("static/1.webp")
95
- image2 = Image.open("static/2.webp")
96
- features1 = get_ft(model, image1)
97
- features2 = get_ft(model, image1) # temporaire : remettre image2
98
- euclid = float(np.linalg.norm(features1 - features2))
99
- else:
100
- euclid = 0.0
101
- except Exception as e:
102
- print(f"Erreur lors du chargement des images : {e}")
103
- euclid = 0.0
104
-
105
- rewards = [{
106
- 'raw_similarity': euclid
107
- }]
108
- return rewards
109
-
110
-
111
-
112
- # Global variables for model and index
113
  model = None
114
- index = None
115
- urls = None
116
 
117
- ### def init_model():
118
- ### global model, index, urls
119
- ### model = load_model()
120
- ### index = load_index("data/openimages_index.bin")
121
- ### with open("data/openimages_urls.txt", "r") as f:
122
- ### urls = f.readlines()
 
 
 
 
 
123
 
124
  @app.route('/')
125
  def home():
126
- return render_template('index.html')
127
 
128
  @app.route('/static/<path:filename>')
129
  def serve_static(filename):
130
  return send_from_directory('static', filename)
131
 
132
- DEFAULT_PARAMS = {
133
- 'subscription': 12,
134
- 'num_generations': 60,
135
- 'author_share': 5,
136
- 'ro_share': 10,
137
- 'num_users_k': 500,
138
- 'num_neighbors': 10,
139
- 'num_authors': 2000
140
- }
141
-
142
- @app.route('/select_preset/<int:preset_id>')
143
- def select_preset(preset_id):
144
- if preset_id not in PRESET_IMAGES:
145
- return jsonify({'error': 'Invalid preset ID'}), 400
146
-
147
- try:
148
- image_path = PRESET_IMAGES[preset_id]
149
- image = Image.open(image_path).convert('RGB')
150
-
151
- # Use default parameters for presets
152
- params = DEFAULT_PARAMS.copy()
153
-
154
- # Get features and search
155
- features = get_ft(model, image)
156
- distances, indices = get_topk(index, features, topk=params['num_neighbors'])
157
-
158
- # Collect valid results first
159
- valid_results = []
160
- valid_similarities = []
161
- for i in range(params['num_neighbors']):
162
- image_url = urls[indices[0][i]].strip()
163
- try:
164
- response = requests.head(image_url)
165
- if response.status_code == 200:
166
- valid_results.append({
167
- 'index': i,
168
- 'url': image_url
169
- })
170
- valid_similarities.append(distances[0][i])
171
- except requests.RequestException:
172
- continue
173
-
174
- # Renormalize similarities for valid results
175
- if valid_similarities:
176
- similarities = distance_to_similarity(np.array([valid_similarities]), temp=1e-5)
177
-
178
- # Calculate rewards with renormalized similarities
179
- rewards = calculate_rewards(
180
- params['subscription'],
181
- params['num_generations'],
182
- params['author_share'],
183
- params['ro_share'],
184
- params['num_users_k'],
185
- similarities,
186
- params['num_authors']
187
- )
188
-
189
- # Build final results
190
- results = []
191
- ### for i, result in enumerate(valid_results):
192
- ### other_info = get_other_info(result['url'])
193
- ### results.append({
194
- ### 'image_url': result['url'],
195
- ### 'rewards': rewards[i],
196
- ### 'other': other_info
197
- ### })
198
-
199
- return jsonify({'results': results})
200
-
201
- except Exception as e:
202
- return jsonify({'error': str(e)}), 500
203
-
204
  @app.route('/process', methods=['POST'])
205
  def process_images():
206
  if 'image1' not in request.files or 'image2' not in request.files:
207
  return jsonify({'error': 'Two images must be provided (image1 and image2)'}), 400
208
 
209
  try:
210
- # Charger les deux images
211
- image_file1 = request.files['image1']
212
- image1 = Image.open(io.BytesIO(image_file1.read())).convert('RGB')
213
 
214
- image_file2 = request.files['image2']
215
- image2 = Image.open(io.BytesIO(image_file2.read())).convert('RGB')
216
-
217
- # Extraire les features des deux images
218
  features1 = get_ft(model, image1)
219
  features2 = get_ft(model, image2)
220
 
221
- # Calculer la distance euclidienne entre les deux feature vectors
222
- distance = float(np.linalg.norm(features1 - features2)) # Convertir en float Python natif pour JSON
223
-
224
- # Retourner la distance
225
  return jsonify({'distance': distance})
226
 
227
  except Exception as e:
 
228
  return jsonify({'error': str(e)}), 500
229
 
230
-
231
  if __name__ == '__main__':
232
- ### init_model()
233
  app.run(host='0.0.0.0', port=7860)
234
 
 
1
  # docker build -t reward-simulator .docker run -p 7860:7860 -v $(pwd)/data:/app/data reward-simulator
2
 
3
+ from flask import Flask, request, jsonify, render_template, send_from_directory
4
  from PIL import Image
5
  import numpy as np
6
  import io
 
 
 
7
  import torch
8
 
9
+ from request import get_ft # get_ft(model, image) doit retourner un np.ndarray
 
10
 
 
11
  app = Flask(__name__)
12
 
13
+ # Global model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  model = None
 
 
15
 
16
+ def load_model():
17
+ """Load DINOv2 model"""
18
+ torch.hub.set_dir('static') # Cache local des modèles
19
+ model = torch.hub.load('facebookresearch/dinov2', 'dinov2_vits14')
20
+ model.eval()
21
+ model.to(torch.device('cuda' if torch.cuda.is_available() else 'cpu'))
22
+ return model
23
+
24
+ def init_model():
25
+ global model
26
+ model = load_model()
27
 
28
  @app.route('/')
29
  def home():
30
+ return render_template('index.html') # Si tu as un front-end intégré
31
 
32
  @app.route('/static/<path:filename>')
33
  def serve_static(filename):
34
  return send_from_directory('static', filename)
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  @app.route('/process', methods=['POST'])
37
  def process_images():
38
  if 'image1' not in request.files or 'image2' not in request.files:
39
  return jsonify({'error': 'Two images must be provided (image1 and image2)'}), 400
40
 
41
  try:
42
+ image1 = Image.open(io.BytesIO(request.files['image1'].read())).convert('RGB')
43
+ image2 = Image.open(io.BytesIO(request.files['image2'].read())).convert('RGB')
 
44
 
 
 
 
 
45
  features1 = get_ft(model, image1)
46
  features2 = get_ft(model, image2)
47
 
48
+ distance = float(np.linalg.norm(features1 - features2))
 
 
 
49
  return jsonify({'distance': distance})
50
 
51
  except Exception as e:
52
+ print(f"Erreur back-end: {e}")
53
  return jsonify({'error': str(e)}), 500
54
 
 
55
  if __name__ == '__main__':
56
+ init_model()
57
  app.run(host='0.0.0.0', port=7860)
58