1
+ import type { MLCEngine } from "@mlc-ai/web-llm" ;
2
+ import type { LLMProviders , Session } from "~llms" ;
3
+ import type { SettingSchema } from "~options/fragments/llm" ;
4
+
5
+ export default class WebLLM implements LLMProviders {
6
+
7
+ private static readonly DEFAULT_MODEL : string = 'Qwen2-7B-Instruct-q4f32_1-MLC'
8
+
9
+ private readonly model : string
10
+
11
+ constructor ( settings : SettingSchema ) {
12
+ this . model = settings . model || WebLLM . DEFAULT_MODEL
13
+ }
14
+
15
+ cumulative : boolean = true
16
+
17
+ async validate ( progresser ?: ( p : number , t : string ) => void ) : Promise < void > {
18
+ await this . initializeEngine ( progresser )
19
+ }
20
+
21
+ async prompt ( chat : string ) : Promise < string > {
22
+ const session = await this . asSession ( )
23
+ try {
24
+ console . debug ( '[web-llm] prompting: ' , chat )
25
+ return session . prompt ( chat )
26
+ } finally {
27
+ console . debug ( '[web-llm] done' )
28
+ await session [ Symbol . asyncDispose ] ( )
29
+ }
30
+ }
31
+
32
+ async * promptStream ( chat : string ) : AsyncGenerator < string > {
33
+ const session = await this . asSession ( )
34
+ try {
35
+ console . debug ( '[web-llm] prompting stream: ' , chat )
36
+ const res = session . promptStream ( chat )
37
+ for await ( const chunk of res ) {
38
+ yield chunk
39
+ }
40
+ } finally {
41
+ console . debug ( '[web-llm] done' )
42
+ await session [ Symbol . asyncDispose ] ( )
43
+ }
44
+ }
45
+
46
+ async asSession ( ) : Promise < Session < LLMProviders > > {
47
+ const engine = await this . initializeEngine ( )
48
+ return {
49
+ async prompt ( chat : string ) {
50
+ await engine . interruptGenerate ( )
51
+ const c = await engine . completions . create ( {
52
+ prompt : chat ,
53
+ max_tokens : 512 ,
54
+ temperature : 0.2 ,
55
+ } )
56
+ return c . choices [ 0 ] ?. text ?? engine . getMessage ( )
57
+ } ,
58
+ async * promptStream ( chat : string ) : AsyncGenerator < string > {
59
+ await engine . interruptGenerate ( )
60
+ const chunks = await engine . completions . create ( {
61
+ prompt : chat ,
62
+ max_tokens : 512 ,
63
+ temperature : 0.2 ,
64
+ stream : true
65
+ } )
66
+ for await ( const chunk of chunks ) {
67
+ yield chunk . choices [ 0 ] ?. text || "" ;
68
+ if ( chunk . usage ) {
69
+ console . debug ( 'Usage:' , chunk . usage )
70
+ }
71
+ }
72
+ } ,
73
+ [ Symbol . asyncDispose ] : engine . unload
74
+ }
75
+ }
76
+
77
+ private async initializeEngine ( progresser ?: ( p : number , t : string ) => void ) : Promise < MLCEngine > {
78
+ const { CreateMLCEngine } = await import ( '@mlc-ai/web-llm' )
79
+ return CreateMLCEngine ( this . model , {
80
+ initProgressCallback : ( progress ) => {
81
+ progresser ?.( progress . progress , "正在下载AI模型到本地" )
82
+ console . log ( '初始化进度:' , progress )
83
+ }
84
+ } )
85
+ }
86
+
87
+ }
0 commit comments