1 import { isBrave, isFirefox, isSafari } from '@proton/shared/lib/helpers/browser';
10 export type GpuAssessmentResult =
11 | 'ok' // seems like WebGPU should work
12 | 'noWebGpu' // we cannot load WebGPU
13 | 'noWebGpuFirefox' // we cannot load WebGPU and we specifically know it's because the user uses Firefox
14 | 'noWebGpuSafari' // we cannot load WebGPU and we specifically know it's because the user uses Safari
15 | 'insufficientRam' // total ram can't hold the model in memory, and swapping would give terrible perfs
16 | 'macPreM1' // Mac detected, but it seems to be an older Intel CPU that cannot run LLMs
17 | 'noShaderF16' // this GPU is lacking newer features that are required for LLM text generation
18 | 'noShaderF16Brave' // in some cases Brave won't report shader-f16 despite the hardware supporting it
19 | 'maxBufferSizeTooLow'; // this GPU is likely underpowered
22 const isBlacklisted = (specs: HardwareSpecs, adapter: any): GpuAssessmentResult | null => {
23 // Returns null if not blacklisted, else returns a reason why it was blacklisted
25 // Check FP16 support.
26 // Some graphics cards like GTX 1060 have enough RAM (6GB) but lack FP16 support, so we must blacklist them.
27 if (!adapter.features.has('shader-f16')) {
28 console.error("Feature 'shader-f16' is not supported by this GPU adapter, but is required to run the LLM.");
31 "It looks like you're running Brave. In some cases, Brave may not expose the 'shader-f16' feature. " +
32 'Consider trying in another Chromium browser.'
34 return 'noShaderF16Brave';
40 // Unlike what the name says, 'MacIntel' appears for both older Intel CPUs and newer Apple CPUs (M1 and later).
41 let isMac = specs.platform === 'MacIntel';
43 // The following criterion on maxBufferSize was chosen not because of the impact on the LLM, but because
44 // based on hardware data analysis on a bunch of machines, it was a good differentiator of pre- vs post-M1.
45 const macPostM1 = adapter.limits.maxBufferSize >= 4294967292;
47 console.error('Mac with Intel chips are not sufficiently powerful for LLM text generation.');
51 // We lack sufficient data to distinguish Windows/Linux machines that have decent hardware, but we've seen at
52 // least one Windows configuration where the maxBufferSize was < 4294967292 yet the LLM was working well.
53 // I'm putting this criterion for now, but it's likely inexact and will have to evolve over time.
54 const maxBufferSizeTooLow = adapter.limits.maxBufferSize < 2147483644;
55 if (maxBufferSizeTooLow) {
56 console.error(`maxBufferSize = ${adapter.limits.maxBufferSize} could be too low to run the LLM`);
57 return 'maxBufferSizeTooLow';
64 export const checkHardwareForAssistant = async (): Promise<GpuAssessmentResult> => {
65 const canvas = document.createElement('canvas');
68 let webGlRenderer: string | undefined;
69 let webGlVendor: string | undefined;
71 const gl = canvas.getContext('webgl');
73 return 'noWebGpu'; // no WebGL really, but it doesn't change the conclusion
75 webGlRenderer = gl.getParameter(gl.RENDERER);
76 webGlVendor = gl.getParameter(gl.VENDOR);
78 const specs: HardwareSpecs = {
79 platform: navigator.platform,
81 deviceMemory: navigator.deviceMemory || null,
82 webGlRenderer: webGlRenderer || '',
83 webGlVendor: webGlVendor || '',
86 // Test if there's enough memory
87 // ...except for Brave, which under-reports the device memory
88 // https://github.com/brave/brave-browser/issues/1157
90 if (specs.deviceMemory !== null && specs.deviceMemory < 8) {
91 console.error('This machine reports RAM under 8GB which may be too low to run the LLM.');
92 return 'insufficientRam';
96 // Test if we can load webgpu
98 const navigator = globalThis.navigator as any;
100 const adapter: any | undefined = await navigator.gpu?.requestAdapter();
102 console.error('WebGPU is not available.');
104 return 'noWebGpuFirefox';
105 } else if (isSafari()) {
106 return 'noWebGpuSafari';
111 // Test if system is not blacklisted
112 const reason = isBlacklisted(specs, adapter);
119 return 'noWebGpuFirefox';
120 } else if (isSafari()) {
121 return 'noWebGpuSafari';