JuanjoSG5 commited on
Commit
100ea5d
·
1 Parent(s): e0b4034

feat: finally the gradio interface works

Browse files
Files changed (1) hide show
  1. gradio_interface/app.py +124 -33
gradio_interface/app.py CHANGED
@@ -7,6 +7,7 @@ from dotenv import load_dotenv
7
  import requests
8
  import socket
9
  import logging
 
10
 
11
  from langchain_openai import ChatOpenAI
12
  from langchain_core.messages import HumanMessage, AIMessage
@@ -35,6 +36,37 @@ def test_connectivity(url="https://openrouter.helicone.ai/api/v1"):
35
  if not test_connectivity():
36
  logger.warning("No network to OpenRouter; responses may fail.")
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  # Initialize LLM with streaming and retry logic
39
  def init_llm():
40
  if not test_connectivity():
@@ -50,57 +82,116 @@ def init_llm():
50
  },
51
  )
52
 
53
- llm = init_llm()
 
 
 
 
 
54
 
55
  # Helpers
56
  def encode_image_to_base64(pil_image):
57
  buffer = BytesIO()
58
  pil_image.save(buffer, format="PNG")
59
- return f"data:image/png;base64,{base64.b64encode(buffer.getvalue()).decode()}"
60
 
61
  # Core logic
62
  def generate_response(message, chat_history, image):
63
- messages = [HumanMessage(content="You are an expert image analysis assistant. Answer succinctly.")]
 
64
  for msg in chat_history:
65
  role = msg.get('role')
66
  content = msg.get('content')
67
  if role == 'user':
68
- messages.append(HumanMessage(content=content))
69
  else:
70
- messages.append(AIMessage(content=content))
71
 
72
- encoded = encode_image_to_base64(image)
 
73
 
74
- # Create a properly formatted multimodal content list
75
- multimodal_content = [
76
- {"type": "text", "text": message},
77
- {"type": "image_url", "image_url": {"url": encoded}}
78
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- # Append a single HumanMessage with the multimodal content
81
- messages.append(HumanMessage(content=multimodal_content))
82
 
83
  try:
84
- stream_iter = llm.stream(messages)
85
- if stream_iter is None:
86
- raise RuntimeError("Received no stream iterator from LLM.")
87
- partial = ""
88
- for chunk in stream_iter:
89
- if chunk is None:
90
- logger.warning("Received None chunk from stream, skipping.")
91
- continue
92
- content = getattr(chunk, 'content', None)
93
- if content is None:
94
- logger.warning(f"Chunk without content: {chunk}")
95
- continue
96
- partial += content
97
- yield partial
98
- except AssertionError as e:
99
- logger.error(f"AssertionError in stream: {e}")
100
- yield "⚠️ No response del modelo. Por favor reintenta."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  except Exception as e:
102
- logger.exception("Unexpected error during streaming response.")
103
- yield "⚠️ Error al generar respuesta. Intenta más tarde."
 
 
 
104
 
105
  # Gradio interface
106
  def process_message(message, chat_history, image):
@@ -130,4 +221,4 @@ with gr.Blocks() as demo:
130
  msg.submit(process_message, [msg, chatbot, image_input], [msg, chatbot])
131
  image_input.change(lambda img: f"Tamaño: {img.size}" if img else "Sin imagen.", [image_input], [info])
132
 
133
- demo.launch()
 
7
  import requests
8
  import socket
9
  import logging
10
+ import json
11
 
12
  from langchain_openai import ChatOpenAI
13
  from langchain_core.messages import HumanMessage, AIMessage
 
36
  if not test_connectivity():
37
  logger.warning("No network to OpenRouter; responses may fail.")
38
 
39
+ # Helper to make direct API calls to OpenRouter when LangChain fails
40
+ def direct_api_call(messages, api_key, base_url):
41
+ headers = {
42
+ "Content-Type": "application/json",
43
+ "Authorization": f"Bearer {api_key}",
44
+ "HTTP-Referer": "https://your-app-domain.com", # Add your domain
45
+ "X-Title": "Image Analysis App"
46
+ }
47
+
48
+ if getenv("HELICONE_API_KEY"):
49
+ headers["Helicone-Auth"] = f"Bearer {getenv('HELICONE_API_KEY')}"
50
+
51
+ payload = {
52
+ "model": "google/gemini-flash-1.5",
53
+ "messages": messages,
54
+ "stream": False,
55
+ }
56
+
57
+ try:
58
+ response = requests.post(
59
+ f"{base_url}/chat/completions",
60
+ headers=headers,
61
+ json=payload,
62
+ timeout=30
63
+ )
64
+ response.raise_for_status()
65
+ return response.json()["choices"][0]["message"]["content"]
66
+ except Exception as e:
67
+ logger.error(f"Direct API call failed: {e}")
68
+ return f"Error: {str(e)}"
69
+
70
  # Initialize LLM with streaming and retry logic
71
  def init_llm():
72
  if not test_connectivity():
 
82
  },
83
  )
84
 
85
+ # Try to initialize LLM but handle failures gracefully
86
+ try:
87
+ llm = init_llm()
88
+ except Exception as e:
89
+ logger.error(f"Failed to initialize LLM: {e}")
90
+ llm = None
91
 
92
  # Helpers
93
  def encode_image_to_base64(pil_image):
94
  buffer = BytesIO()
95
  pil_image.save(buffer, format="PNG")
96
+ return base64.b64encode(buffer.getvalue()).decode()
97
 
98
  # Core logic
99
  def generate_response(message, chat_history, image):
100
+ # Convert chat history to standard format
101
+ formatted_history = []
102
  for msg in chat_history:
103
  role = msg.get('role')
104
  content = msg.get('content')
105
  if role == 'user':
106
+ formatted_history.append({"role": "user", "content": content})
107
  else:
108
+ formatted_history.append({"role": "assistant", "content": content})
109
 
110
+ # Prepare system message
111
+ system_msg = {"role": "system", "content": "You are an expert image analysis assistant. Answer succinctly."}
112
 
113
+ # Prepare the latest message with image if provided
114
+ if image:
115
+ base64_image = encode_image_to_base64(image)
116
+
117
+ # Format for direct API call (OpenRouter/OpenAI format)
118
+ api_messages = [system_msg] + formatted_history + [{
119
+ "role": "user",
120
+ "content": [
121
+ {"type": "text", "text": message},
122
+ {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
123
+ ]
124
+ }]
125
+
126
+ # For LangChain format
127
+ content_for_langchain = [
128
+ {"type": "text", "text": message},
129
+ {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
130
+ ]
131
+ else:
132
+ api_messages = [system_msg] + formatted_history + [{"role": "user", "content": message}]
133
+ content_for_langchain = message
134
+
135
+ # Build LangChain messages
136
+ lc_messages = [HumanMessage(content="You are an expert image analysis assistant. Answer succinctly.")]
137
+ for msg in chat_history:
138
+ role = msg.get('role')
139
+ content = msg.get('content')
140
+ if role == 'user':
141
+ lc_messages.append(HumanMessage(content=content))
142
+ else:
143
+ lc_messages.append(AIMessage(content=content))
144
 
145
+ lc_messages.append(HumanMessage(content=content_for_langchain))
 
146
 
147
  try:
148
+ # First try with LangChain
149
+ if llm:
150
+ try:
151
+ # Try streaming first
152
+ try:
153
+ stream_iter = llm.stream(lc_messages)
154
+ partial = ""
155
+ for chunk in stream_iter:
156
+ if chunk is None:
157
+ continue
158
+ content = getattr(chunk, 'content', None)
159
+ if content is None:
160
+ continue
161
+ partial += content
162
+ yield partial
163
+
164
+ # If we got this far, streaming worked
165
+ return
166
+ except Exception as e:
167
+ logger.warning(f"Streaming failed: {e}. Falling back to non-streaming mode")
168
+
169
+ # Try non-streaming
170
+ try:
171
+ response = llm.invoke(lc_messages)
172
+ yield response.content
173
+ return
174
+ except Exception as e:
175
+ logger.warning(f"Non-streaming LangChain invoke failed: {e}")
176
+ raise e
177
+ except Exception as e:
178
+ logger.warning(f"LangChain approach failed: {e}. Trying direct API call")
179
+
180
+ # Fallback to direct API call
181
+ logger.info("Using direct API call as fallback")
182
+ response_text = direct_api_call(
183
+ api_messages,
184
+ getenv("OPENROUTER_API_KEY"),
185
+ getenv("OPENROUTER_BASE_URL")
186
+ )
187
+ yield response_text
188
+
189
  except Exception as e:
190
+ import traceback
191
+ error_trace = traceback.format_exc()
192
+ logger.exception(f"All approaches failed during response generation: {e}")
193
+ logger.error(f"Full traceback: {error_trace}")
194
+ yield f"⚠️ Error al generar respuesta: {str(e)}. Intenta más tarde."
195
 
196
  # Gradio interface
197
  def process_message(message, chat_history, image):
 
221
  msg.submit(process_message, [msg, chatbot, image_input], [msg, chatbot])
222
  image_input.change(lambda img: f"Tamaño: {img.size}" if img else "Sin imagen.", [image_input], [info])
223
 
224
+ demo.launch()