@midscene/visualizer 0.26.2 → 0.26.3-beta-20250813021342.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/blank_polyfill.mjs +2 -0
- package/dist/es/component/blackboard.css +12 -5
- package/dist/es/component/blackboard.mjs +266 -0
- package/dist/es/component/color.mjs +35 -0
- package/dist/es/component/describer.css +9 -5
- package/dist/es/component/describer.mjs +128 -0
- package/dist/es/component/env-config.mjs +112 -0
- package/dist/es/component/github-star.css +1 -0
- package/dist/es/component/github-star.mjs +20 -0
- package/dist/es/component/logo.css +5 -3
- package/dist/es/component/logo.mjs +20 -0
- package/dist/es/component/misc.mjs +54 -0
- package/dist/es/component/pixi-loader.mjs +16 -0
- package/dist/es/component/player.css +88 -70
- package/dist/es/component/player.mjs +628 -0
- package/dist/es/component/playground/ConfigSelector.mjs +53 -0
- package/dist/es/component/playground/ContextPreview.mjs +39 -0
- package/dist/es/component/playground/HistorySelector.mjs +193 -0
- package/dist/es/component/playground/PlaygroundResult.mjs +60 -0
- package/dist/es/component/playground/PromptInput.mjs +225 -0
- package/dist/es/component/playground/ServiceModeControl.mjs +100 -0
- package/dist/es/component/playground/index.css +140 -98
- package/dist/es/component/playground/playground-constants.mjs +45 -0
- package/dist/es/component/playground/playground-utils.mjs +89 -0
- package/dist/es/component/playground/useServerValid.mjs +27 -0
- package/dist/es/component/playground/useStaticPageAgent.mjs +12 -0
- package/dist/es/component/replay-scripts.mjs +271 -0
- package/dist/es/component/shiny-text.css +33 -22
- package/dist/es/component/shiny-text.mjs +15 -0
- package/dist/es/component/store/history.mjs +55 -0
- package/dist/es/component/store/store.mjs +128 -0
- package/dist/es/icons/close.mjs +19 -0
- package/dist/es/icons/history.mjs +30 -0
- package/dist/es/icons/magnifying-glass.mjs +39 -0
- package/dist/es/icons/setting.mjs +20 -0
- package/dist/es/index.mjs +21 -0
- package/dist/es/init.mjs +10 -0
- package/dist/es/{utils.js → utils.mjs} +51 -75
- package/dist/lib/blank_polyfill.js +34 -38
- package/dist/lib/component/blackboard.css +12 -5
- package/dist/lib/component/blackboard.js +293 -306
- package/dist/lib/component/color.js +64 -74
- package/dist/lib/component/describer.css +9 -5
- package/dist/lib/component/describer.js +158 -198
- package/dist/lib/component/env-config.js +142 -147
- package/dist/lib/component/github-star.css +1 -0
- package/dist/lib/component/github-star.js +51 -62
- package/dist/lib/component/logo.css +5 -3
- package/dist/lib/component/logo.js +53 -56
- package/dist/lib/component/misc.js +85 -84
- package/dist/lib/component/pixi-loader.js +49 -80
- package/dist/lib/component/player.css +88 -70
- package/dist/lib/component/player.js +627 -738
- package/dist/lib/component/playground/ConfigSelector.js +91 -92
- package/dist/lib/component/playground/ContextPreview.js +80 -72
- package/dist/lib/component/playground/HistorySelector.js +234 -197
- package/dist/lib/component/playground/PlaygroundResult.js +100 -103
- package/dist/lib/component/playground/PromptInput.js +250 -237
- package/dist/lib/component/playground/ServiceModeControl.js +124 -124
- package/dist/lib/component/playground/index.css +140 -98
- package/dist/lib/component/playground/playground-constants.js +97 -73
- package/dist/lib/component/playground/playground-types.js +17 -31
- package/dist/lib/component/playground/playground-utils.js +140 -168
- package/dist/lib/component/playground/useServerValid.js +55 -86
- package/dist/lib/component/playground/useStaticPageAgent.js +45 -51
- package/dist/lib/component/replay-scripts.js +291 -373
- package/dist/lib/component/shiny-text.css +33 -22
- package/dist/lib/component/shiny-text.js +46 -57
- package/dist/lib/component/store/history.js +58 -64
- package/dist/lib/component/store/store.js +132 -128
- package/dist/lib/icons/close.js +53 -0
- package/dist/lib/icons/history.js +64 -0
- package/dist/lib/icons/magnifying-glass.js +73 -0
- package/dist/lib/icons/setting.js +54 -0
- package/dist/lib/index.js +158 -124
- package/dist/lib/init.js +39 -46
- package/dist/lib/utils.js +105 -109
- package/dist/types/blank_polyfill.d.ts +2 -2
- package/dist/types/component/playground/ConfigSelector.d.ts +1 -0
- package/dist/types/component/playground/ContextPreview.d.ts +1 -0
- package/dist/types/component/playground/HistorySelector.d.ts +1 -0
- package/dist/types/component/playground/PlaygroundResult.d.ts +1 -0
- package/dist/types/component/playground/PromptInput.d.ts +1 -0
- package/dist/types/component/playground/ServiceModeControl.d.ts +1 -0
- package/package.json +16 -18
- package/dist/es/assets/close.909351c0.svg +0 -4
- package/dist/es/assets/history.164a4eab.svg +0 -4
- package/dist/es/assets/magnifying-glass.9498e70e.svg +0 -12
- package/dist/es/assets/setting.80ab7285.svg +0 -11
- package/dist/es/blank_polyfill.js +0 -10
- package/dist/es/component/blackboard.js +0 -286
- package/dist/es/component/color.js +0 -49
- package/dist/es/component/describer.js +0 -173
- package/dist/es/component/env-config.js +0 -117
- package/dist/es/component/github-star.js +0 -31
- package/dist/es/component/logo.js +0 -25
- package/dist/es/component/misc.js +0 -63
- package/dist/es/component/pixi-loader.js +0 -51
- package/dist/es/component/player.js +0 -746
- package/dist/es/component/playground/ConfigSelector.js +0 -64
- package/dist/es/component/playground/ContextPreview.js +0 -42
- package/dist/es/component/playground/HistorySelector.js +0 -168
- package/dist/es/component/playground/PlaygroundResult.js +0 -73
- package/dist/es/component/playground/PromptInput.js +0 -212
- package/dist/es/component/playground/ServiceModeControl.js +0 -100
- package/dist/es/component/playground/playground-constants.js +0 -39
- package/dist/es/component/playground/playground-types.js +0 -6
- package/dist/es/component/playground/playground-utils.js +0 -141
- package/dist/es/component/playground/useServerValid.js +0 -58
- package/dist/es/component/playground/useStaticPageAgent.js +0 -20
- package/dist/es/component/replay-scripts.js +0 -361
- package/dist/es/component/shiny-text.js +0 -30
- package/dist/es/component/store/history.js +0 -34
- package/dist/es/component/store/store.js +0 -99
- package/dist/es/index.js +0 -79
- package/dist/es/init.js +0 -17
- package/dist/index.css +0 -595
- package/dist/index.js +0 -1
- package/dist/lib/assets/close.909351c0.svg +0 -4
- package/dist/lib/assets/history.164a4eab.svg +0 -4
- package/dist/lib/assets/magnifying-glass.9498e70e.svg +0 -12
- package/dist/lib/assets/setting.80ab7285.svg +0 -11
- package/dist/lib/component/common.css +0 -0
- /package/dist/es/component/{common.css → playground/playground-types.mjs} +0 -0
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
.blackboard .footer {
|
|
2
2
|
color: #aaa;
|
|
3
3
|
}
|
|
4
|
+
|
|
4
5
|
.blackboard ul {
|
|
5
|
-
padding-left:
|
|
6
|
+
padding-left: 0;
|
|
6
7
|
}
|
|
8
|
+
|
|
7
9
|
.blackboard li {
|
|
8
10
|
list-style: none;
|
|
9
11
|
}
|
|
12
|
+
|
|
10
13
|
.blackboard .bottom-tip {
|
|
11
14
|
height: 30px;
|
|
12
15
|
}
|
|
16
|
+
|
|
13
17
|
.blackboard .bottom-tip-item {
|
|
14
|
-
|
|
15
|
-
color: #AAA;
|
|
18
|
+
color: #aaa;
|
|
16
19
|
text-overflow: ellipsis;
|
|
17
20
|
word-wrap: break-word;
|
|
21
|
+
max-width: 500px;
|
|
18
22
|
}
|
|
23
|
+
|
|
19
24
|
.blackboard-filter {
|
|
20
25
|
margin: 10px 0;
|
|
21
26
|
}
|
|
27
|
+
|
|
22
28
|
.blackboard-main-content canvas {
|
|
23
|
-
width: 100%;
|
|
24
|
-
border: 1px solid #888;
|
|
25
29
|
box-sizing: border-box;
|
|
30
|
+
border: 1px solid #888;
|
|
31
|
+
width: 100%;
|
|
26
32
|
}
|
|
33
|
+
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import "pixi.js/unsafe-eval";
|
|
4
|
+
import { Checkbox } from "antd";
|
|
5
|
+
import { Application, Container, Graphics, Rectangle, Sprite, Text, Texture } from "pixi.js";
|
|
6
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { colorForName, highlightColorForType } from "./color.mjs";
|
|
8
|
+
import "./blackboard.css";
|
|
9
|
+
import { treeToList } from "@midscene/shared/extractor";
|
|
10
|
+
import { DropShadowFilter } from "pixi-filters";
|
|
11
|
+
import { useBlackboardPreference } from "./store/store.mjs";
|
|
12
|
+
const itemFillAlpha = 0.4;
|
|
13
|
+
const highlightAlpha = 0.4;
|
|
14
|
+
const pointRadius = 10;
|
|
15
|
+
const pointMarkForItem = (point, type)=>{
|
|
16
|
+
const [x, y] = point;
|
|
17
|
+
const themeColor = highlightColorForType('element');
|
|
18
|
+
const graphics = new Graphics();
|
|
19
|
+
graphics.beginFill(themeColor, itemFillAlpha);
|
|
20
|
+
graphics.drawCircle(x, y, pointRadius);
|
|
21
|
+
graphics.endFill();
|
|
22
|
+
return graphics;
|
|
23
|
+
};
|
|
24
|
+
const rectMarkForItem = (rect, name, type)=>{
|
|
25
|
+
const { left, top, width, height } = rect;
|
|
26
|
+
let themeColor;
|
|
27
|
+
themeColor = 'element' === type ? colorForName(name) : 'searchArea' === type ? highlightColorForType('searchArea') : highlightColorForType('element');
|
|
28
|
+
const alpha = 'highlight' === type ? highlightAlpha : itemFillAlpha;
|
|
29
|
+
const graphics = new Graphics();
|
|
30
|
+
graphics.beginFill(themeColor, alpha);
|
|
31
|
+
graphics.lineStyle(1, themeColor, 1);
|
|
32
|
+
graphics.drawRect(left, top, width, height);
|
|
33
|
+
graphics.endFill();
|
|
34
|
+
const dropShadowFilter = new DropShadowFilter({
|
|
35
|
+
blur: 2,
|
|
36
|
+
quality: 3,
|
|
37
|
+
alpha: 0.4,
|
|
38
|
+
offset: {
|
|
39
|
+
x: 4,
|
|
40
|
+
y: 4
|
|
41
|
+
},
|
|
42
|
+
color: 0x333333
|
|
43
|
+
});
|
|
44
|
+
graphics.filters = [
|
|
45
|
+
dropShadowFilter
|
|
46
|
+
];
|
|
47
|
+
const nameFontSize = 18;
|
|
48
|
+
if (!name) return [
|
|
49
|
+
graphics
|
|
50
|
+
];
|
|
51
|
+
const texts = new Text(name, {
|
|
52
|
+
fontSize: nameFontSize,
|
|
53
|
+
fill: 0x0
|
|
54
|
+
});
|
|
55
|
+
texts.x = left;
|
|
56
|
+
texts.y = Math.max(top - (nameFontSize + 4), 0);
|
|
57
|
+
return [
|
|
58
|
+
graphics,
|
|
59
|
+
texts
|
|
60
|
+
];
|
|
61
|
+
};
|
|
62
|
+
const Blackboard = (props)=>{
|
|
63
|
+
const highlightElements = props.highlightElements || [];
|
|
64
|
+
const highlightIds = highlightElements.map((e)=>e.id);
|
|
65
|
+
const highlightRect = props.highlightRect;
|
|
66
|
+
const highlightPoints = props.highlightPoints;
|
|
67
|
+
const context = props.uiContext;
|
|
68
|
+
const { size, screenshotBase64 } = context;
|
|
69
|
+
const screenWidth = size.width;
|
|
70
|
+
const screenHeight = size.height;
|
|
71
|
+
const domRef = useRef(null);
|
|
72
|
+
const app = useMemo(()=>new Application(), []);
|
|
73
|
+
const [appInitialed, setAppInitialed] = useState(false);
|
|
74
|
+
const highlightContainer = useMemo(()=>new Container(), []);
|
|
75
|
+
const elementMarkContainer = useMemo(()=>new Container(), []);
|
|
76
|
+
const [hoverElement, setHoverElement] = useState(null);
|
|
77
|
+
const pixiBgRef = useRef(void 0);
|
|
78
|
+
const { markerVisible, setMarkerVisible, elementsVisible, setTextsVisible } = useBlackboardPreference();
|
|
79
|
+
useEffect(()=>{
|
|
80
|
+
Promise.resolve((async ()=>{
|
|
81
|
+
if (!domRef.current || !screenWidth) return;
|
|
82
|
+
await app.init({
|
|
83
|
+
width: screenWidth,
|
|
84
|
+
height: screenHeight,
|
|
85
|
+
background: 0xffffff
|
|
86
|
+
});
|
|
87
|
+
const canvasEl = domRef.current;
|
|
88
|
+
domRef.current.appendChild(app.canvas);
|
|
89
|
+
const { clientWidth } = domRef.current.parentElement;
|
|
90
|
+
const targetHeight = 0.6 * window.innerHeight;
|
|
91
|
+
const viewportRatio = clientWidth / targetHeight;
|
|
92
|
+
if (screenWidth / screenHeight <= viewportRatio) {
|
|
93
|
+
const ratio = targetHeight / screenHeight;
|
|
94
|
+
canvasEl.style.width = `${Math.floor(screenWidth * ratio)}px`;
|
|
95
|
+
canvasEl.style.height = `${Math.floor(screenHeight * ratio)}px`;
|
|
96
|
+
}
|
|
97
|
+
app.stage.addChild(highlightContainer);
|
|
98
|
+
app.stage.addChild(elementMarkContainer);
|
|
99
|
+
setAppInitialed(true);
|
|
100
|
+
})());
|
|
101
|
+
return ()=>{
|
|
102
|
+
console.log('will destroy');
|
|
103
|
+
try {
|
|
104
|
+
app.destroy(true, {
|
|
105
|
+
children: true,
|
|
106
|
+
texture: true
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
console.warn('destroy failed', e);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}, [
|
|
113
|
+
app,
|
|
114
|
+
screenWidth,
|
|
115
|
+
screenHeight
|
|
116
|
+
]);
|
|
117
|
+
useEffect(()=>{
|
|
118
|
+
if (!appInitialed) return;
|
|
119
|
+
app.stage.eventMode = 'static';
|
|
120
|
+
app.stage.hitArea = new Rectangle(0, 0, screenWidth, screenHeight);
|
|
121
|
+
const clickHandler = (event)=>{
|
|
122
|
+
var _props_onCanvasClick;
|
|
123
|
+
console.log('pixi click', event);
|
|
124
|
+
const { x, y } = event.data.global;
|
|
125
|
+
null == (_props_onCanvasClick = props.onCanvasClick) || _props_onCanvasClick.call(props, [
|
|
126
|
+
Math.round(x),
|
|
127
|
+
Math.round(y)
|
|
128
|
+
]);
|
|
129
|
+
};
|
|
130
|
+
app.stage.on('click', clickHandler);
|
|
131
|
+
return ()=>{
|
|
132
|
+
var _app_stage;
|
|
133
|
+
null == app || null == (_app_stage = app.stage) || _app_stage.off('click');
|
|
134
|
+
};
|
|
135
|
+
}, [
|
|
136
|
+
appInitialed,
|
|
137
|
+
props.onCanvasClick,
|
|
138
|
+
screenWidth,
|
|
139
|
+
screenHeight
|
|
140
|
+
]);
|
|
141
|
+
useEffect(()=>{
|
|
142
|
+
if (!appInitialed) return;
|
|
143
|
+
const img = new Image();
|
|
144
|
+
img.onload = ()=>{
|
|
145
|
+
if (!app.stage) return;
|
|
146
|
+
const screenshotTexture = Texture.from(img);
|
|
147
|
+
const backgroundSprite = new Sprite(screenshotTexture);
|
|
148
|
+
backgroundSprite.x = 0;
|
|
149
|
+
backgroundSprite.y = 0;
|
|
150
|
+
backgroundSprite.width = screenWidth;
|
|
151
|
+
backgroundSprite.height = screenHeight;
|
|
152
|
+
backgroundSprite.eventMode = 'passive';
|
|
153
|
+
app.stage.addChildAt(backgroundSprite, 0);
|
|
154
|
+
pixiBgRef.current = backgroundSprite;
|
|
155
|
+
};
|
|
156
|
+
img.onerror = (e)=>{
|
|
157
|
+
console.error('load screenshot failed', e);
|
|
158
|
+
};
|
|
159
|
+
img.src = screenshotBase64;
|
|
160
|
+
}, [
|
|
161
|
+
app.stage,
|
|
162
|
+
appInitialed,
|
|
163
|
+
screenWidth,
|
|
164
|
+
screenHeight
|
|
165
|
+
]);
|
|
166
|
+
const { highlightElementRects } = useMemo(()=>{
|
|
167
|
+
const highlightElementRects = [];
|
|
168
|
+
highlightContainer.removeChildren();
|
|
169
|
+
elementMarkContainer.removeChildren();
|
|
170
|
+
highlightContainer.eventMode = 'passive';
|
|
171
|
+
elementMarkContainer.eventMode = 'passive';
|
|
172
|
+
if (highlightRect) {
|
|
173
|
+
const [graphics] = rectMarkForItem(highlightRect, 'Search Area', 'searchArea');
|
|
174
|
+
highlightContainer.addChild(graphics);
|
|
175
|
+
}
|
|
176
|
+
if (highlightElements.length) highlightElements.forEach((element)=>{
|
|
177
|
+
const { rect, content, id } = element;
|
|
178
|
+
const [graphics] = rectMarkForItem(rect, content, 'highlight');
|
|
179
|
+
highlightContainer.addChild(graphics);
|
|
180
|
+
});
|
|
181
|
+
if (null == highlightPoints ? void 0 : highlightPoints.length) highlightPoints.forEach((point)=>{
|
|
182
|
+
const graphics = pointMarkForItem(point, 'highlightPoint');
|
|
183
|
+
highlightContainer.addChild(graphics);
|
|
184
|
+
});
|
|
185
|
+
const elements = treeToList(context.tree);
|
|
186
|
+
elements.forEach((element)=>{
|
|
187
|
+
const { rect, content, id } = element;
|
|
188
|
+
const ifHighlight = highlightIds.includes(id) || (null == hoverElement ? void 0 : hoverElement.id) === id;
|
|
189
|
+
if (ifHighlight) return;
|
|
190
|
+
const [graphics] = rectMarkForItem(rect, content, 'element');
|
|
191
|
+
elementMarkContainer.addChild(graphics);
|
|
192
|
+
});
|
|
193
|
+
elementMarkContainer.visible = elementsVisible;
|
|
194
|
+
return {
|
|
195
|
+
highlightElementRects
|
|
196
|
+
};
|
|
197
|
+
}, [
|
|
198
|
+
app,
|
|
199
|
+
appInitialed,
|
|
200
|
+
highlightElements,
|
|
201
|
+
context.tree,
|
|
202
|
+
hoverElement,
|
|
203
|
+
highlightRect,
|
|
204
|
+
highlightPoints
|
|
205
|
+
]);
|
|
206
|
+
const onSetElementsVisible = (e)=>{
|
|
207
|
+
setTextsVisible(e.target.checked);
|
|
208
|
+
elementMarkContainer.visible = e.target.checked;
|
|
209
|
+
};
|
|
210
|
+
let bottomTipA = null;
|
|
211
|
+
if (1 === highlightElementRects.length) bottomTipA = /*#__PURE__*/ jsx("div", {
|
|
212
|
+
className: "bottom-tip",
|
|
213
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
214
|
+
className: "bottom-tip-item",
|
|
215
|
+
children: [
|
|
216
|
+
"Element: ",
|
|
217
|
+
JSON.stringify(highlightElementRects[0])
|
|
218
|
+
]
|
|
219
|
+
})
|
|
220
|
+
});
|
|
221
|
+
else if (highlightElementRects.length > 1) bottomTipA = /*#__PURE__*/ jsx("div", {
|
|
222
|
+
className: "bottom-tip",
|
|
223
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
224
|
+
className: "bottom-tip-item",
|
|
225
|
+
children: [
|
|
226
|
+
"Element: ",
|
|
227
|
+
JSON.stringify(highlightElementRects)
|
|
228
|
+
]
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
232
|
+
className: "blackboard",
|
|
233
|
+
children: [
|
|
234
|
+
/*#__PURE__*/ jsx("div", {
|
|
235
|
+
className: "blackboard-main-content",
|
|
236
|
+
style: {
|
|
237
|
+
width: '100%'
|
|
238
|
+
},
|
|
239
|
+
ref: domRef
|
|
240
|
+
}),
|
|
241
|
+
/*#__PURE__*/ jsx("div", {
|
|
242
|
+
className: "blackboard-filter",
|
|
243
|
+
style: {
|
|
244
|
+
display: props.hideController ? 'none' : 'block'
|
|
245
|
+
},
|
|
246
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
247
|
+
className: "overlay-control",
|
|
248
|
+
children: /*#__PURE__*/ jsx(Checkbox, {
|
|
249
|
+
checked: elementsVisible,
|
|
250
|
+
onChange: onSetElementsVisible,
|
|
251
|
+
children: "Elements"
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
}),
|
|
255
|
+
/*#__PURE__*/ jsx("div", {
|
|
256
|
+
className: "bottom-tip",
|
|
257
|
+
style: {
|
|
258
|
+
display: props.hideController ? 'none' : 'block'
|
|
259
|
+
},
|
|
260
|
+
children: bottomTipA
|
|
261
|
+
})
|
|
262
|
+
]
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
const blackboard = Blackboard;
|
|
266
|
+
export { Blackboard, blackboard as default, pointMarkForItem, rectMarkForItem };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const elementColor = [
|
|
2
|
+
'#01204E'
|
|
3
|
+
];
|
|
4
|
+
const highlightColorForSearchArea = '#028391';
|
|
5
|
+
const highlightColorForElement = '#fd5907';
|
|
6
|
+
function djb2Hash(str) {
|
|
7
|
+
if (!str) str = 'unnamed';
|
|
8
|
+
let hash = 5381;
|
|
9
|
+
for(let i = 0; i < str.length; i++)hash = (hash << 5) + hash + str.charCodeAt(i);
|
|
10
|
+
return hash >>> 0;
|
|
11
|
+
}
|
|
12
|
+
function colorForName(name) {
|
|
13
|
+
const hashNumber = djb2Hash(name);
|
|
14
|
+
return elementColor[hashNumber % elementColor.length];
|
|
15
|
+
}
|
|
16
|
+
function highlightColorForType(type) {
|
|
17
|
+
if ('searchArea' === type) return highlightColorForSearchArea;
|
|
18
|
+
return highlightColorForElement;
|
|
19
|
+
}
|
|
20
|
+
function globalThemeConfig() {
|
|
21
|
+
return {
|
|
22
|
+
token: {
|
|
23
|
+
colorPrimary: '#2B83FF'
|
|
24
|
+
},
|
|
25
|
+
components: {
|
|
26
|
+
Layout: {
|
|
27
|
+
headerHeight: 60,
|
|
28
|
+
headerPadding: '0 30px',
|
|
29
|
+
headerBg: '#FFF',
|
|
30
|
+
bodyBg: '#FFF'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export { colorForName, globalThemeConfig, highlightColorForType };
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
.image-describer {
|
|
2
2
|
position: relative;
|
|
3
3
|
}
|
|
4
|
+
|
|
4
5
|
.image-describer .describe-text {
|
|
5
6
|
box-sizing: border-box;
|
|
6
|
-
|
|
7
|
+
color: #fff;
|
|
7
8
|
background: #000;
|
|
8
9
|
width: 100%;
|
|
9
10
|
height: 30px;
|
|
10
|
-
left: 0;
|
|
11
|
-
bottom: 0;
|
|
12
|
-
color: #FFF;
|
|
13
|
-
font-size: 12px;
|
|
14
11
|
padding: 10px;
|
|
12
|
+
font-size: 12px;
|
|
13
|
+
position: absolute;
|
|
14
|
+
bottom: 0;
|
|
15
|
+
left: 0;
|
|
15
16
|
}
|
|
17
|
+
|
|
16
18
|
.image-describer .describe-text.success {
|
|
17
19
|
background: #047704;
|
|
18
20
|
}
|
|
21
|
+
|
|
19
22
|
.image-describer .describe-text.error {
|
|
20
23
|
background: #870707;
|
|
21
24
|
}
|
|
25
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useStaticPageAgent } from "./playground/useStaticPageAgent.mjs";
|
|
5
|
+
import "./describer.css";
|
|
6
|
+
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
|
|
7
|
+
import { Blackboard } from "./blackboard.mjs";
|
|
8
|
+
import { PlaygroundResultView } from "./playground/PlaygroundResult.mjs";
|
|
9
|
+
const Describer = (props)=>{
|
|
10
|
+
var _result_verifyResult;
|
|
11
|
+
const { uiContext } = props;
|
|
12
|
+
const image = uiContext.screenshotBase64;
|
|
13
|
+
const canvasRef = useRef(null);
|
|
14
|
+
const [highlightPoints, setHighlightPoints] = useState([]);
|
|
15
|
+
const [highlightRect, setHighlightRect] = useState();
|
|
16
|
+
const [error, setError] = useState();
|
|
17
|
+
const [loading, setLoading] = useState(false);
|
|
18
|
+
const [result, setResult] = useState();
|
|
19
|
+
const agent = useStaticPageAgent(uiContext);
|
|
20
|
+
useEffect(()=>{
|
|
21
|
+
const canvas = canvasRef.current;
|
|
22
|
+
if (!canvas || !image) return;
|
|
23
|
+
const ctx = canvas.getContext('2d');
|
|
24
|
+
if (!ctx) return;
|
|
25
|
+
const img = new Image();
|
|
26
|
+
img.onload = ()=>{
|
|
27
|
+
canvas.width = img.width;
|
|
28
|
+
canvas.height = img.height;
|
|
29
|
+
ctx.drawImage(img, 0, 0);
|
|
30
|
+
};
|
|
31
|
+
img.src = image;
|
|
32
|
+
}, [
|
|
33
|
+
image
|
|
34
|
+
]);
|
|
35
|
+
const handleClick = async (position)=>{
|
|
36
|
+
if (!agent) return void console.error('agent is not initialized');
|
|
37
|
+
setLoading(true);
|
|
38
|
+
setError(void 0);
|
|
39
|
+
setResult(void 0);
|
|
40
|
+
setHighlightPoints([]);
|
|
41
|
+
setHighlightRect(void 0);
|
|
42
|
+
try {
|
|
43
|
+
var _result_verifyResult;
|
|
44
|
+
const userLocation = [
|
|
45
|
+
position[0],
|
|
46
|
+
position[1]
|
|
47
|
+
];
|
|
48
|
+
setHighlightPoints([
|
|
49
|
+
userLocation
|
|
50
|
+
]);
|
|
51
|
+
const result = await (null == agent ? void 0 : agent.describeElementAtPoint(userLocation));
|
|
52
|
+
console.log('describe result', result);
|
|
53
|
+
setResult(result);
|
|
54
|
+
if (null == (_result_verifyResult = result.verifyResult) ? void 0 : _result_verifyResult.rect) setHighlightRect(result.verifyResult.rect);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
setError(error.message);
|
|
57
|
+
} finally{
|
|
58
|
+
setLoading(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
let resultText = '';
|
|
62
|
+
if (error) resultText = error;
|
|
63
|
+
else if (!result || (null == (_result_verifyResult = result.verifyResult) ? void 0 : _result_verifyResult.pass)) {
|
|
64
|
+
if (result) resultText = result.deepThink ? `Deep think: ${result.prompt}` : result.prompt;
|
|
65
|
+
else if (loading) resultText = 'Loading...';
|
|
66
|
+
} else resultText = `Locate failed with prompt: ${result.prompt}`;
|
|
67
|
+
return /*#__PURE__*/ jsx("div", {
|
|
68
|
+
className: "image-describer",
|
|
69
|
+
children: /*#__PURE__*/ jsxs(PanelGroup, {
|
|
70
|
+
autoSaveId: "describer-layout",
|
|
71
|
+
direction: "horizontal",
|
|
72
|
+
children: [
|
|
73
|
+
/*#__PURE__*/ jsx(Panel, {
|
|
74
|
+
defaultSize: 32,
|
|
75
|
+
maxSize: 60,
|
|
76
|
+
minSize: 20,
|
|
77
|
+
style: {
|
|
78
|
+
paddingRight: '24px'
|
|
79
|
+
},
|
|
80
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
81
|
+
className: "form-part context-panel",
|
|
82
|
+
children: [
|
|
83
|
+
/*#__PURE__*/ jsx("h3", {
|
|
84
|
+
children: "Screenshot"
|
|
85
|
+
}),
|
|
86
|
+
/*#__PURE__*/ jsx("div", {
|
|
87
|
+
className: "form-sub-title",
|
|
88
|
+
children: "Click on the screenshot, Midscene will help you describe the element at the clicked point."
|
|
89
|
+
}),
|
|
90
|
+
/*#__PURE__*/ jsx(Blackboard, {
|
|
91
|
+
uiContext: {
|
|
92
|
+
...uiContext,
|
|
93
|
+
tree: {
|
|
94
|
+
node: null,
|
|
95
|
+
children: []
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
highlightPoints: highlightPoints,
|
|
99
|
+
highlightRect: highlightRect,
|
|
100
|
+
onCanvasClick: handleClick,
|
|
101
|
+
hideController: true
|
|
102
|
+
})
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
}),
|
|
106
|
+
/*#__PURE__*/ jsx(PanelResizeHandle, {
|
|
107
|
+
className: "panel-resize-handle"
|
|
108
|
+
}),
|
|
109
|
+
/*#__PURE__*/ jsx(Panel, {
|
|
110
|
+
children: /*#__PURE__*/ jsx(PlaygroundResultView, {
|
|
111
|
+
result: {
|
|
112
|
+
result: resultText,
|
|
113
|
+
error: error || null
|
|
114
|
+
},
|
|
115
|
+
loading: loading,
|
|
116
|
+
serverValid: true,
|
|
117
|
+
serviceMode: 'In-Browser',
|
|
118
|
+
replayScriptsInfo: null,
|
|
119
|
+
replayCounter: 0,
|
|
120
|
+
loadingProgressText: ''
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
]
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
const describer = Describer;
|
|
128
|
+
export { Describer, describer as default };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { SettingOutlined } from "@ant-design/icons";
|
|
3
|
+
import { Input, Modal, Tooltip } from "antd";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import { useEnvConfig } from "./store/store.mjs";
|
|
6
|
+
function EnvConfig(param) {
|
|
7
|
+
let { showTooltipWhenEmpty = true, showModelName = true, tooltipPlacement = 'bottom', mode = 'icon' } = param;
|
|
8
|
+
const { config, configString, loadConfig, syncFromStorage } = useEnvConfig();
|
|
9
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
10
|
+
const [tempConfigString, setTempConfigString] = useState(configString);
|
|
11
|
+
const midsceneModelName = config.MIDSCENE_MODEL_NAME;
|
|
12
|
+
const componentRef = useRef(null);
|
|
13
|
+
const showModal = (e)=>{
|
|
14
|
+
syncFromStorage();
|
|
15
|
+
setIsModalOpen(true);
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
e.stopPropagation();
|
|
18
|
+
};
|
|
19
|
+
const handleOk = ()=>{
|
|
20
|
+
setIsModalOpen(false);
|
|
21
|
+
loadConfig(tempConfigString);
|
|
22
|
+
};
|
|
23
|
+
const handleCancel = ()=>{
|
|
24
|
+
setIsModalOpen(false);
|
|
25
|
+
};
|
|
26
|
+
useEffect(()=>{
|
|
27
|
+
if (isModalOpen) setTempConfigString(configString);
|
|
28
|
+
}, [
|
|
29
|
+
isModalOpen,
|
|
30
|
+
configString
|
|
31
|
+
]);
|
|
32
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
33
|
+
style: {
|
|
34
|
+
display: 'flex',
|
|
35
|
+
justifyContent: 'flex-end',
|
|
36
|
+
gap: '10px',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
height: '100%',
|
|
39
|
+
minHeight: '32px'
|
|
40
|
+
},
|
|
41
|
+
ref: componentRef,
|
|
42
|
+
children: [
|
|
43
|
+
showModelName ? midsceneModelName : null,
|
|
44
|
+
/*#__PURE__*/ jsx(Tooltip, {
|
|
45
|
+
title: "Please set up your environment variables before using.",
|
|
46
|
+
placement: tooltipPlacement,
|
|
47
|
+
align: {
|
|
48
|
+
offset: [
|
|
49
|
+
-10,
|
|
50
|
+
5
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
getPopupContainer: ()=>componentRef.current,
|
|
54
|
+
open: isModalOpen ? false : showTooltipWhenEmpty ? 0 === Object.keys(config).length : void 0,
|
|
55
|
+
children: 'icon' === mode ? /*#__PURE__*/ jsx(SettingOutlined, {
|
|
56
|
+
onClick: showModal
|
|
57
|
+
}) : /*#__PURE__*/ jsx("span", {
|
|
58
|
+
onClick: showModal,
|
|
59
|
+
style: {
|
|
60
|
+
color: '#006AFF',
|
|
61
|
+
cursor: 'pointer'
|
|
62
|
+
},
|
|
63
|
+
children: "set up"
|
|
64
|
+
})
|
|
65
|
+
}),
|
|
66
|
+
/*#__PURE__*/ jsxs(Modal, {
|
|
67
|
+
title: "Model Env Config",
|
|
68
|
+
open: isModalOpen,
|
|
69
|
+
onOk: handleOk,
|
|
70
|
+
onCancel: handleCancel,
|
|
71
|
+
okText: "Save",
|
|
72
|
+
style: {
|
|
73
|
+
width: '800px',
|
|
74
|
+
height: '100%',
|
|
75
|
+
marginTop: '10%'
|
|
76
|
+
},
|
|
77
|
+
destroyOnClose: true,
|
|
78
|
+
maskClosable: true,
|
|
79
|
+
centered: true,
|
|
80
|
+
children: [
|
|
81
|
+
/*#__PURE__*/ jsx(Input.TextArea, {
|
|
82
|
+
rows: 7,
|
|
83
|
+
placeholder: 'OPENAI_API_KEY=sk-...\nMIDSCENE_MODEL_NAME=gpt-4o-2024-08-06\n...',
|
|
84
|
+
value: tempConfigString,
|
|
85
|
+
onChange: (e)=>setTempConfigString(e.target.value),
|
|
86
|
+
style: {
|
|
87
|
+
whiteSpace: 'nowrap',
|
|
88
|
+
wordWrap: 'break-word'
|
|
89
|
+
}
|
|
90
|
+
}),
|
|
91
|
+
/*#__PURE__*/ jsxs("div", {
|
|
92
|
+
children: [
|
|
93
|
+
/*#__PURE__*/ jsx("p", {
|
|
94
|
+
children: "The format is KEY=VALUE and separated by new lines."
|
|
95
|
+
}),
|
|
96
|
+
/*#__PURE__*/ jsxs("p", {
|
|
97
|
+
children: [
|
|
98
|
+
"These data will be saved ",
|
|
99
|
+
/*#__PURE__*/ jsx("strong", {
|
|
100
|
+
children: "locally in your browser"
|
|
101
|
+
}),
|
|
102
|
+
"."
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
})
|
|
107
|
+
]
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
export { EnvConfig };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import "./github-star.css";
|
|
3
|
+
const GithubStar = ()=>/*#__PURE__*/ jsx("a", {
|
|
4
|
+
href: "https://github.com/web-infra-dev/midscene",
|
|
5
|
+
target: "_blank",
|
|
6
|
+
rel: "noreferrer",
|
|
7
|
+
style: {
|
|
8
|
+
display: 'flex',
|
|
9
|
+
alignItems: 'center'
|
|
10
|
+
},
|
|
11
|
+
children: /*#__PURE__*/ jsx("img", {
|
|
12
|
+
className: "github-star",
|
|
13
|
+
src: "https://img.shields.io/github/stars/web-infra-dev/midscene?style=social",
|
|
14
|
+
alt: "Github star",
|
|
15
|
+
style: {
|
|
16
|
+
display: 'block'
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
export { GithubStar };
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
.logo img {
|
|
2
|
-
height: 30px;
|
|
3
|
-
line-height: 30px;
|
|
4
2
|
vertical-align: baseline;
|
|
3
|
+
height: 30px;
|
|
5
4
|
vertical-align: -webkit-baseline-middle;
|
|
5
|
+
line-height: 30px;
|
|
6
6
|
}
|
|
7
|
+
|
|
7
8
|
.logo-with-star-wrapper {
|
|
8
|
-
display: flex;
|
|
9
9
|
flex-direction: row;
|
|
10
10
|
justify-content: space-between;
|
|
11
|
+
display: flex;
|
|
11
12
|
}
|
|
13
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import "./logo.css";
|
|
3
|
+
const LogoUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png';
|
|
4
|
+
const Logo = (param)=>{
|
|
5
|
+
let { hideLogo = false } = param;
|
|
6
|
+
if (hideLogo) return null;
|
|
7
|
+
return /*#__PURE__*/ jsx("div", {
|
|
8
|
+
className: "logo",
|
|
9
|
+
children: /*#__PURE__*/ jsx("a", {
|
|
10
|
+
href: "https://midscenejs.com/",
|
|
11
|
+
target: "_blank",
|
|
12
|
+
rel: "noreferrer",
|
|
13
|
+
children: /*#__PURE__*/ jsx("img", {
|
|
14
|
+
alt: "Midscene_logo",
|
|
15
|
+
src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/vhaeh7vhabf/Midscene.png"
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
export { Logo, LogoUrl };
|