Skip to content

Commit 2fc3b2e

Browse files
committed
Fallback WebGPU adapter selection for zeriyaGPT
1 parent 3eb54d0 commit 2fc3b2e

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

‎apps/betterzeriya/src/routes/sessions/[id]/ai/+page.svelte‎

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,35 @@
5858
let listEl: HTMLDivElement | null = $state(null);
5959
let textareaEl: HTMLTextAreaElement | null = $state(null);
6060
61+
const getWebGPU = () =>
62+
typeof navigator === 'undefined' ? null : ((navigator as Navigator & { gpu?: GPU }).gpu ?? null);
63+
64+
const installWebGPUAdapterFallback = () => {
65+
const gpu = getWebGPU() as (GPU & { __betterzeriyaAdapterFallback?: true }) | null;
66+
if (!gpu || gpu.__betterzeriyaAdapterFallback) return;
67+
68+
const requestAdapter = gpu.requestAdapter.bind(gpu);
69+
try {
70+
Object.defineProperty(gpu, 'requestAdapter', {
71+
configurable: true,
72+
value: async (options?: GPURequestAdapterOptions) => {
73+
const adapter = await requestAdapter(options);
74+
if (adapter || !options?.powerPreference) {
75+
return adapter;
76+
}
77+
return (
78+
(await requestAdapter()) ??
79+
(await requestAdapter({
80+
powerPreference:
81+
options.powerPreference === 'high-performance' ? 'low-power' : 'high-performance'
82+
}))
83+
);
84+
}
85+
});
86+
gpu.__betterzeriyaAdapterFallback = true;
87+
} catch {}
88+
};
89+
6190
const isCloseToBottom = () => {
6291
if (!listEl) return true;
6392
return listEl.scrollHeight - listEl.scrollTop - listEl.clientHeight < 80;
@@ -69,8 +98,17 @@
6998
};
7099
71100
const detectWebGPU = () => {
72-
if (typeof navigator === 'undefined') return false;
73-
return 'gpu' in navigator;
101+
return Boolean(getWebGPU());
102+
};
103+
104+
const verifyWebGPUAdapter = async () => {
105+
const gpu = getWebGPU();
106+
if (!gpu) return false;
107+
const adapter =
108+
(await gpu.requestAdapter({ powerPreference: 'high-performance' })) ??
109+
(await gpu.requestAdapter()) ??
110+
(await gpu.requestAdapter({ powerPreference: 'low-power' }));
111+
return Boolean(adapter);
74112
};
75113
76114
const loadEngine = async () => {
@@ -80,6 +118,7 @@
80118
loadProgress = 0;
81119
loadText = 'モデルを準備しています…';
82120
try {
121+
installWebGPUAdapterFallback();
83122
const { CreateMLCEngine, prebuiltAppConfig } = await import('@mlc-ai/web-llm');
84123
const next = await CreateMLCEngine(selectedModel, {
85124
initProgressCallback: (report: { progress: number; text: string }) => {
@@ -95,7 +134,10 @@
95134
loadText = '準備完了';
96135
} catch (caught) {
97136
engine = null;
98-
error = caught instanceof Error ? caught.message : 'モデル読み込みに失敗しました';
137+
const message = caught instanceof Error ? caught.message : 'モデル読み込みに失敗しました';
138+
error = message.includes('Unable to find a compatible GPU')
139+
? 'WebGPU adapter を取得できませんでした。ブラウザのハードウェアアクセラレーション、GPUドライバ、chrome://gpu の WebGPU 状態を確認してください。'
140+
: message;
99141
} finally {
100142
engineLoading = false;
101143
}
@@ -205,7 +247,16 @@
205247
webgpuSupported = detectWebGPU();
206248
if (!webgpuSupported) {
207249
error = 'このブラウザは WebGPU に未対応です。Chrome / Edge デスクトップ版でお試しください。';
250+
return;
208251
}
252+
installWebGPUAdapterFallback();
253+
void verifyWebGPUAdapter().then((supported) => {
254+
webgpuSupported = supported;
255+
if (!supported) {
256+
error =
257+
'WebGPU adapter を取得できませんでした。ブラウザのハードウェアアクセラレーション、GPUドライバ、chrome://gpu の WebGPU 状態を確認してください。';
258+
}
259+
});
209260
});
210261
</script>
211262

0 commit comments

Comments
 (0)