CORVO-AI commited on
Commit
7696d99
·
verified ·
1 Parent(s): 1265aa2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -40
app.py CHANGED
@@ -3,7 +3,7 @@ import base64
3
  import requests
4
  from pathlib import Path
5
  from typing import Optional, List, Dict, Any
6
- from flask import Flask, request, jsonify
7
 
8
  app = Flask(__name__)
9
 
@@ -24,12 +24,6 @@ def encode_image_to_base64_from_url(image_url: str, timeout: int = 30) -> str:
24
  return base64.b64encode(resp.content).decode("utf-8")
25
 
26
  def normalize_messages_to_prompt(messages: List[Dict[str, str]]) -> str:
27
- # Convert structured chat history into a single prompt string
28
- # Expected roles: system, user, assistant
29
- # Output example:
30
- # System: ...
31
- # User: ...
32
- # Assistant: ...
33
  lines = []
34
  for msg in messages:
35
  role = str(msg.get("role", "")).strip().lower()
@@ -43,25 +37,20 @@ def normalize_messages_to_prompt(messages: List[Dict[str, str]]) -> str:
43
  else:
44
  prefix = "User"
45
  lines.append(f"{prefix}: {content}")
46
- # Optionally add a final cue for the assistant to respond
47
  return "\n".join(lines).strip()
48
 
49
  def extract_output(obj: dict) -> str:
50
- # Try common shapes:
51
- # 1) { data: { outputs: [ { output: "..." } ] } }
52
  try:
53
  out = obj["data"]["outputs"][0]["output"]
54
  if isinstance(out, str):
55
  return out
56
  except Exception:
57
  pass
58
- # 2) Flat { "output": "..." }
59
  if isinstance(obj, dict) and isinstance(obj.get("output"), str):
60
  return obj["output"]
61
- # Fallback: empty
62
  return ""
63
 
64
- def call_roboflow_playground(image_b64: str, prompt: str, model: str = DEFAULT_MODEL, timeout: int = 60) -> Dict[str, Any]:
65
  payload = {
66
  "inputs": {
67
  "image": {"type": "base64", "value": image_b64},
@@ -84,60 +73,66 @@ def call_roboflow_playground(image_b64: str, prompt: str, model: str = DEFAULT_M
84
  @app.route("/infer", methods=["POST"])
85
  def infer():
86
  try:
87
- data = request.get_json(force=True, silent=False) or {}
88
 
89
- # Image sources: image_base64, image_url, or image_path (optional local)
90
  image_b64 = (data.get("image_base64") or "").strip()
91
  image_url = (data.get("image_url") or "").strip()
92
  image_path = (data.get("image_path") or "").strip()
93
 
94
  if not image_b64:
95
  if image_url:
96
- try:
97
- image_b64 = encode_image_to_base64_from_url(image_url)
98
- except Exception as e:
99
- return jsonify({"error": f"Failed to fetch/encode image_url: {str(e)}"}), 400
100
  elif image_path:
101
- try:
102
- image_b64 = encode_image_to_base64_from_path(image_path)
103
- except Exception as e:
104
- return jsonify({"error": f"Failed to read/encode image_path: {str(e)}"}), 400
105
  else:
106
- return jsonify({"error": "Provide one of: image_base64, image_url, or image_path"}), 400
107
 
108
- # Messages to prompt
109
  messages = data.get("messages", [])
110
- if not isinstance(messages, list) or not all(isinstance(m, dict) for m in messages):
111
- return jsonify({"error": "messages must be a list of {role, content}"}), 400
112
 
113
  prompt = normalize_messages_to_prompt(messages)
114
  if not prompt:
115
- return jsonify({"error": "messages is empty or has no valid content"}), 400
116
 
117
- # Model (optional override)
118
  model = (data.get("model") or DEFAULT_MODEL).strip() or DEFAULT_MODEL
119
 
120
- # Call external API
121
- raw_response = call_roboflow_playground(image_b64=image_b64, prompt=prompt, model=model)
122
 
123
- # Extract simplified output
124
- output_text = extract_output(raw_response)
125
 
126
- return jsonify({
127
- "output": output_text,
128
- "raw_response": raw_response
129
- }), 200
130
 
131
  except requests.HTTPError as e:
132
  status = getattr(e.response, "status_code", 502)
133
  text = getattr(e.response, "text", "")
134
- return jsonify({"error": "HTTP error from upstream", "status": status, "response_text": text}), 502
135
  except Exception as e:
136
- return jsonify({"error": str(e)}), 500
137
 
138
  def main():
139
- # Run Flask on port 7860
140
  app.run(host="0.0.0.0", port=7860, debug=False)
141
 
142
  if __name__ == "__main__":
143
  main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import requests
4
  from pathlib import Path
5
  from typing import Optional, List, Dict, Any
6
+ from flask import Flask, request, Response
7
 
8
  app = Flask(__name__)
9
 
 
24
  return base64.b64encode(resp.content).decode("utf-8")
25
 
26
  def normalize_messages_to_prompt(messages: List[Dict[str, str]]) -> str:
 
 
 
 
 
 
27
  lines = []
28
  for msg in messages:
29
  role = str(msg.get("role", "")).strip().lower()
 
37
  else:
38
  prefix = "User"
39
  lines.append(f"{prefix}: {content}")
 
40
  return "\n".join(lines).strip()
41
 
42
  def extract_output(obj: dict) -> str:
 
 
43
  try:
44
  out = obj["data"]["outputs"][0]["output"]
45
  if isinstance(out, str):
46
  return out
47
  except Exception:
48
  pass
 
49
  if isinstance(obj, dict) and isinstance(obj.get("output"), str):
50
  return obj["output"]
 
51
  return ""
52
 
53
+ def call_roboflow_playground(image_b64: str, prompt: str, model: str = DEFAULT_MODEL, timeout: int = 60) -> dict:
54
  payload = {
55
  "inputs": {
56
  "image": {"type": "base64", "value": image_b64},
 
73
  @app.route("/infer", methods=["POST"])
74
  def infer():
75
  try:
76
+ data = request.get_json(force=True) or {}
77
 
78
+ # Image input
79
  image_b64 = (data.get("image_base64") or "").strip()
80
  image_url = (data.get("image_url") or "").strip()
81
  image_path = (data.get("image_path") or "").strip()
82
 
83
  if not image_b64:
84
  if image_url:
85
+ image_b64 = encode_image_to_base64_from_url(image_url)
 
 
 
86
  elif image_path:
87
+ image_b64 = encode_image_to_base64_from_path(image_path)
 
 
 
88
  else:
89
+ return Response("Missing image. Provide image_base64, image_url, or image_path.", status=400)
90
 
91
+ # Messages -> prompt
92
  messages = data.get("messages", [])
93
+ if not isinstance(messages, list):
94
+ return Response("messages must be a list of {role, content}.", status=400)
95
 
96
  prompt = normalize_messages_to_prompt(messages)
97
  if not prompt:
98
+ return Response("messages is empty or has no content.", status=400)
99
 
 
100
  model = (data.get("model") or DEFAULT_MODEL).strip() or DEFAULT_MODEL
101
 
102
+ upstream = call_roboflow_playground(image_b64=image_b64, prompt=prompt, model=model)
103
+ output_text = extract_output(upstream).strip()
104
 
105
+ if not output_text:
106
+ return Response("No output from model.", status=502)
107
 
108
+ # Return only the AI response as plain text
109
+ return Response(output_text, mimetype="text/plain", status=200)
 
 
110
 
111
  except requests.HTTPError as e:
112
  status = getattr(e.response, "status_code", 502)
113
  text = getattr(e.response, "text", "")
114
+ return Response(f"Upstream HTTP error ({status}): {text}", status=502)
115
  except Exception as e:
116
+ return Response(str(e), status=500)
117
 
118
  def main():
 
119
  app.run(host="0.0.0.0", port=7860, debug=False)
120
 
121
  if __name__ == "__main__":
122
  main()
123
+
124
+ Client test (super simple):
125
+ import requests
126
+ API_URL = "https://corvo-ai-xx-mistral.hf.space/infer"
127
+
128
+ payload = {
129
+ "image_url": "https://images.unsplash.com/photo-1518791841217-8f162f1e1131",
130
+ "messages": [
131
+ {"role": "system", "content": "You are a helpful vision assistant."},
132
+ {"role": "user", "content": "What do you see in this image?"}
133
+ ]
134
+ }
135
+
136
+ r = requests.post(API_URL, json=payload, timeout=60)
137
+ print(r.status_code)
138
+ print(r.text)