jandan138 commited on
Commit
ed21695
·
verified ·
1 Parent(s): a5eb7ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +327 -83
app.py CHANGED
@@ -1,98 +1,342 @@
 
1
  import gradio as gr
2
  import requests
3
- import time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- def check_url_status():
6
- """检查目标URL的状态"""
7
- target_url = "http://123.57.187.96:55005/"
 
 
 
 
 
 
 
 
 
 
 
 
8
  try:
9
- response = requests.get(target_url, timeout=10)
10
- return f"✅ URL状态: {response.status_code} - 可访问"
 
 
 
11
  except Exception as e:
12
- return f" URL错误: {str(e)}"
13
-
14
- def create_webpage_display():
15
- """创建显示指定网页的HTML内容"""
16
- # 添加调试信息
17
- debug_info = f"调试时间: {time.strftime('%Y-%m-%d %H:%M:%S')}<br>"
18
- debug_info += f"目标URL: http://123.57.187.96:55005/<br>"
19
- debug_info += f"{check_url_status()}<br><br>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- iframe_html = f'''
22
- <div style="border: 2px solid #ccc; padding: 10px; margin: 10px 0;">
23
- <h3>调试信息:</h3>
24
- <p>{debug_info}</p>
 
 
 
25
 
26
- <h3>方式1: 直接链接</h3>
27
- <p><a href="http://123.57.187.96:55005/" target="_blank" style="font-size: 18px; color: blue;">🔗 点击这里直接访问网站</a></p>
 
 
 
 
 
 
 
 
 
28
 
29
- <h3>方式2: iframe嵌入</h3>
30
- <div style="width: 100%; height: 600px; border: 1px solid #999;">
31
- <iframe src="http://123.57.187.96:55005/"
32
- width="100%"
33
- height="100%"
34
- frameborder="1"
35
- allowfullscreen
36
- sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
37
- onerror="console.log('iframe加载失败')"
38
- onload="console.log('iframe加载成功')">
39
- <p style="color: red; font-size: 16px;">
40
- ⚠️ iframe无法显示内容。可能原因:<br>
41
- 1. 目标网站不允许被嵌入<br>
42
- 2. 跨域安全策略限制<br>
43
- 3. HTTPS/HTTP混合内容问题<br>
44
- <a href="http://123.57.187.96:55005/" target="_blank">请点击这里直接访问</a>
45
- </p>
46
- </iframe>
47
- </div>
48
 
49
- <h3>方式3: 网站预览信息</h3>
50
- <div style="background: #f5f5f5; padding: 10px; border-radius: 5px;">
51
- <p>如果iframe无法显示,这通常是因为:</p>
52
- <ul>
53
- <li>目标网站设置了 X-Frame-Options 禁止被嵌入</li>
54
- <li>CSP (Content Security Policy) 限制</li>
55
- <li>HTTPS页面无法嵌入HTTP内容</li>
56
- </ul>
57
- </div>
58
- </div>
59
- '''
60
- return iframe_html
61
-
62
- # 创建 Gradio 界面
63
- with gr.Blocks(title="网页显示器", css=".gradio-container {padding: 0px !important}") as demo:
64
- gr.Markdown("# 网页内容显示")
65
- gr.Markdown("以下是来自 http://123.57.187.96:55005/ 的网页内容:")
66
-
67
- # 显示网页内容
68
- webpage_html = gr.HTML(value=create_webpage_display())
69
 
70
- # 添加刷新按钮
71
- refresh_btn = gr.Button("🔄 刷新页面", variant="primary")
72
- refresh_btn.click(fn=create_webpage_display, outputs=webpage_html)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
- # 添加获取网页源码的功能
75
- def get_webpage_content():
76
- try:
77
- response = requests.get("http://123.57.187.96:55005/", timeout=10)
78
- content = response.text
79
- # 简单处理HTML内容,移除可能的脚本
80
- import re
81
- content = re.sub(r'<script.*?</script>', '', content, flags=re.DOTALL)
82
- return f"<div style='border: 1px solid #ccc; padding: 10px; max-height: 500px; overflow-y: auto;'><h3>网页源码内容:</h3><pre>{content[:2000]}{'...' if len(content) > 2000 else ''}</pre></div>"
83
- except Exception as e:
84
- return f"<p style='color: red;'>获取网页内容失败: {str(e)}</p>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
- gr.Markdown("---")
87
- gr.Markdown("### 备用方案:直接获取网页内容")
88
- content_btn = gr.Button("📄 获取网页源码", variant="secondary")
89
- content_output = gr.HTML()
90
- content_btn.click(fn=get_webpage_content, outputs=content_output)
 
 
 
 
 
 
 
 
91
 
92
  # 启动应用
93
  if __name__ == "__main__":
94
- demo.launch(
95
- server_name="0.0.0.0", # 允许外部访问
96
- server_port=7860, # Hugging Face Spaces 默认端口
97
- share=False # 在 HF Spaces 上不需要 share
98
- )
 
1
+
2
  import gradio as gr
3
  import requests
4
+ # import json
5
+ import os
6
+ from typing import Optional
7
+ import numpy as np
8
+ import cv2
9
+ from PIL import Image
10
+
11
+ # 后端API配置(可配置化)
12
+ BACKEND_URL = os.getenv("BACKEND_URL", "http://your-backend-server:5000")
13
+ API_ENDPOINTS = {
14
+ "submit_task": f"{BACKEND_URL}/api/v1/submit",
15
+ "query_status": f"{BACKEND_URL}/api/v1/status",
16
+ "get_result": f"{BACKEND_URL}/api/v1/result"
17
+ }
18
+
19
+ # 全局缓存原始图像
20
+ #ORIGINAL_IMAGE = cv2.imread("scene.png")
21
+ ORIGINAL_IMAGE = np.array(Image.open("scene.png").convert("RGB"))
22
+ if ORIGINAL_IMAGE is None:
23
+ raise RuntimeError("❌ 无法加载 scene.png,请确保图片文件与 app.py 同目录,并命名正确。")
24
+
25
+
26
+ # 模拟场景配置
27
+ SCENE_CONFIGS = {
28
+ "default_desk": {
29
+ "description": "标准实验桌",
30
+ "objects": ["番茄酱", "盐瓶", "餐刀", "杯子"]
31
+ },
32
+ "cluttered_desk": {
33
+ "description": "杂乱桌面场景",
34
+ "objects": ["书本", "笔", "手机", "水杯", "零食袋"]
35
+ },
36
+ "industrial_table": {
37
+ "description": "工业工作台",
38
+ "objects": ["扳手", "螺丝", "电路板", "润滑剂"]
39
+ }
40
+ }
41
+
42
+ # 可用模型列表
43
+ MODEL_CHOICES = [
44
+ "GRManipulation-v1.0",
45
+ "GR00T-N1",
46
+ "GR00T-1.5",
47
+ "Pi0",
48
+ "DP+CLIP",
49
+ "AcT+CLIP"
50
+ ]
51
+
52
+ def image_to_position(image: np.ndarray, evt: gr.SelectData) -> tuple[np.ndarray, str]:
53
+ h, w = image.shape[:2]
54
+ px, py = evt.index # 点击位置 (x, y)
55
+
56
+ # 坐标转换
57
+ x = (px / w) * 2 - 1
58
+ y = -((py / h) * 2 - 1)
59
+ z = 0.1
60
+ coord_str = f"{x:.2f}, {y:.2f}, {z:.2f}"
61
+
62
+ # 使用原始图像绘制新图(保证每次只有一个点)
63
+ marked = ORIGINAL_IMAGE.copy()
64
+ cv2.circle(marked, center=(px, py), radius=8, color=(255, 0, 0), thickness=-1)
65
+
66
+ return marked, coord_str
67
+
68
+
69
+ def submit_to_backend(
70
+ scene: str,
71
+ prompt: str,
72
+ start_position: str,
73
+ max_steps: int = 100,
74
+ visualize: bool = True
75
+ ) -> dict:
76
+ """
77
+ 提交任务到后端API
78
+ """
79
+ payload = {
80
+ "scene_config": scene,
81
+ "prompt": prompt,
82
+ "start_position": start_position,
83
+ "params": {
84
+ "max_steps": max_steps,
85
+ "visualize": visualize
86
+ },
87
+ "metadata": {
88
+ "submit_from": "gradio_ui"
89
+ }
90
+ }
91
 
92
+
93
+ try:
94
+ response = requests.post(
95
+ API_ENDPOINTS["submit_task"],
96
+ json=payload,
97
+ timeout=10
98
+ )
99
+ return response.json()
100
+ except Exception as e:
101
+ return {"status": "error", "message": str(e)}
102
+
103
+ def get_task_status(task_id: str) -> dict:
104
+ """
105
+ 查询任务状态
106
+ """
107
  try:
108
+ response = requests.get(
109
+ f"{API_ENDPOINTS['query_status']}/{task_id}",
110
+ timeout=5
111
+ )
112
+ return response.json()
113
  except Exception as e:
114
+ return {"status": "error", "message": str(e)}
115
+
116
+ def get_task_result(task_id: str) -> Optional[dict]:
117
+ """
118
+ 获取任务结果
119
+ """
120
+ try:
121
+ response = requests.get(
122
+ f"{API_ENDPOINTS['get_result']}/{task_id}",
123
+ timeout=5
124
+ )
125
+ return response.json()
126
+ except Exception as e:
127
+ print(f"Error fetching result: {e}")
128
+ return None
129
+
130
+ def run_simulation(
131
+ scene: str,
132
+ prompt: str,
133
+ model: str,
134
+ progress=gr.Progress()
135
+ ) -> dict:
136
+ """
137
+ 运行仿真的主函数
138
+ """
139
+ # 提交任务到后端
140
+ progress(0.1, desc="提交任务到后端...")
141
+ submission = submit_to_backend(scene, prompt, model)
142
+
143
+ if submission.get("status") != "success":
144
+ raise gr.Error(f"提交失败: {submission.get('message', '未知错误')}")
145
 
146
+ task_id = submission["task_id"]
147
+ progress(0.3, desc="任务已提交,等待执行...")
148
+
149
+ # 轮询任务状态
150
+ max_checks = 20
151
+ for i in range(max_checks):
152
+ status = get_task_status(task_id)
153
 
154
+ if status.get("status") == "completed":
155
+ progress(0.9, desc="获取结果...")
156
+ result = get_task_result(task_id)
157
+ if result:
158
+ return {
159
+ "video": result.get("video_path"),
160
+ "metrics": result.get("metrics"),
161
+ "log": result.get("log")
162
+ }
163
+ else:
164
+ raise gr.Error("获取结果失败")
165
 
166
+ elif status.get("status") == "failed":
167
+ raise gr.Error(f"任务执行失败: {status.get('message')}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ progress(0.3 + 0.6 * (i/max_checks), desc=f"任务执行中...({status.get('progress', 0)}%)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ raise gr.Error("任务执行超时")
172
+
173
+ # 自定义CSS样式
174
+ custom_css = """
175
+ #simulation-panel {
176
+ border-radius: 8px;
177
+ padding: 20px;
178
+ background: #f9f9f9;
179
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
180
+ }
181
+ #result-panel {
182
+ border-radius: 8px;
183
+ padding: 20px;
184
+ background: #f0f8ff;
185
+ }
186
+ .dark #simulation-panel { background: #2a2a2a; }
187
+ .dark #result-panel { background: #1a2a3a; }
188
+ /* 强力隐藏图像组件底部工具栏 */
189
+ .gr-image .absolute.bottom-0,
190
+ .gr-image .flex.justify-between.items-center.px-2.pb-2 {
191
+ display: none !important;
192
+ }
193
+ """
194
+
195
+ with gr.Blocks(title="机器人导航仿真系统", css=custom_css) as demo:
196
+ # 标题和描述
197
+ gr.Markdown("""
198
+ # 🧭 GRNavigation 机器人导航仿真平台
199
+ ### 基于 GRNavigation 框架的多场景路径规划与自主导航训练
200
+ """)
201
 
202
+ with gr.Row():
203
+ # 左侧控制面板
204
+ with gr.Column(elem_id="simulation-panel"):
205
+ gr.Markdown("### 仿真任务配置")
206
+
207
+ # 场景选择
208
+ scene_dropdown = gr.Dropdown(
209
+ label="选择导航环境",
210
+ choices=list(SCENE_CONFIGS.keys()),
211
+ value="default_desk",
212
+ interactive=True
213
+ )
214
+
215
+ def update_scene_desc(scene):
216
+ config = SCENE_CONFIGS.get(scene, {})
217
+ desc = config.get("description", "无描述")
218
+ objects = "、".join(config.get("objects", []))
219
+ return f"**{desc}** \n包含物体: {objects}"
220
+
221
+
222
+ # 场景描述预览
223
+ scene_description = gr.Markdown("")
224
+
225
+ # 动态更新场景描述(函数不变)
226
+
227
+ # 操作指令输入
228
+ prompt_input = gr.Textbox(
229
+ label="导航指令(自然语言)",
230
+ placeholder="例如:'从桌角出发,穿过障碍物,前往水杯位置'",
231
+ lines=2,
232
+ max_lines=4
233
+ )
234
+
235
+ # 起始坐标输入
236
+ start_pos_input = gr.Textbox(
237
+ label="起始位置坐标 (x, y, z)",
238
+ placeholder="例如:0.0, 0.0, 0.2",
239
+ lines=1
240
+ )
241
+
242
+
243
+ # 高级参数
244
+ with gr.Accordion("高级设置", open=False):
245
+ max_steps = gr.Slider(
246
+ minimum=50,
247
+ maximum=500,
248
+ value=100,
249
+ step=10,
250
+ label="最大导航步数"
251
+ )
252
+ visualize = gr.Checkbox(
253
+ value=True,
254
+ label="显示可视化界面(Isaac Sim)"
255
+ )
256
+
257
+ # 提交按钮
258
+ submit_btn = gr.Button("开始导航仿真", variant="primary")
259
+
260
+ # 右侧结果面板
261
+ with gr.Column(elem_id="result-panel"):
262
+ gr.Markdown("### 仿真结果预览")
263
+
264
+ # 视频输出
265
+ video_output = gr.Video(
266
+ label="导航过程回放",
267
+ interactive=False,
268
+ format="mp4"
269
+ )
270
+
271
+ # 场景俯视图图像(点击获取起点)
272
+ scene_image = gr.Image(
273
+ value="/scene.png", # 占位图路径
274
+ label="点击选择起点位置(场景俯视图)",
275
+ type="numpy", # 获取坐标
276
+ interactive=True,
277
+ height=300,
278
+ show_share_button=False # ✅ 关闭底部按钮(上传、拍照、复制)
279
+ )
280
+
281
+ # ✅ 添加“刷新场景图像”按钮
282
+ def reload_scene_image():
283
+ new_image = np.array(Image.open("scene.png").convert("RGB"))
284
+ global ORIGINAL_IMAGE
285
+ ORIGINAL_IMAGE = new_image
286
+ return new_image
287
+
288
+ refresh_btn = gr.Button("🔁 刷新场景图像")
289
+ refresh_btn.click(fn=reload_scene_image, outputs=scene_image)
290
+
291
+
292
+ # 指标展示
293
+ metrics_output = gr.JSON(
294
+ label="导航性能指标",
295
+ visible=False
296
+ )
297
+
298
+ # 日志输出
299
+ log_output = gr.Textbox(
300
+ label="任务执行日志",
301
+ visible=False,
302
+ lines=10,
303
+ max_lines=20
304
+ )
305
+
306
+ # 示例任务
307
+ gr.Examples(
308
+ examples=[
309
+ ["default_desk", "从桌角出发,前往番茄酱附近", "0.0, 0.0, 0.1"],
310
+ ["cluttered_desk", "从水杯出发,移动到手机旁", "1.0, -0.5, 0.0"],
311
+ ["industrial_table", "避开扳手,从台边移动到润滑剂", "0.5, 0.2, 0.0"]
312
+ ],
313
+ inputs=[scene_dropdown, prompt_input, start_pos_input],
314
+ label="导航任务示例"
315
+ )
316
+
317
+
318
+ # 提交处理逻辑
319
+ submit_btn.click(
320
+ fn=run_simulation,
321
+ inputs=[scene_dropdown, prompt_input, start_pos_input],
322
+ outputs=[video_output, metrics_output, log_output],
323
+ api_name="run_simulation"
324
+ )
325
 
326
+ # 初始场景文字描述
327
+ demo.load(
328
+ fn=lambda: (update_scene_desc("default_desk"), reload_scene_image()),
329
+ outputs=[scene_description, scene_image]
330
+ )
331
+
332
+ # ✅ 添加点击图片 → 自动设置起始位置
333
+ scene_image.select(
334
+ fn=image_to_position,
335
+ inputs=[scene_image],
336
+ outputs=[scene_image, start_pos_input]
337
+ )
338
+
339
 
340
  # 启动应用
341
  if __name__ == "__main__":
342
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=True, debug=True)