11import { type ReadableBoxedValues } from "svelte-toolbelt" ;
2- import { lazyPromise } from "$lib/util" ;
2+ import { getExtensionForLanguage , lazyPromise } from "$lib/util" ;
3+ import type { BundledLanguage , SpecialLanguage } from "shiki" ;
34
45export interface FileSystemEntry {
56 fileName : string ;
@@ -132,6 +133,8 @@ function filesToDirectory(files: FileList): DirectoryEntry {
132133 return ret ;
133134}
134135
136+ export type FileType = SpecialLanguage | BundledLanguage | "auto" ;
137+
135138export type FileInputMode = "file" | "url" | "text" ;
136139
137140export type MultimodalFileInputValueMetadata = {
@@ -144,21 +147,26 @@ export type MultimodalFileInputProps = {
144147
145148 label ?: string | undefined ;
146149 required ?: boolean | undefined ;
150+ fileTypeOverride ?: boolean | undefined ;
147151} ;
148152
149153export type MultimodalFileInputStateProps = {
150154 state : MultimodalFileInputState | undefined ;
151155} & ReadableBoxedValues < {
152156 label : string ;
153157 required : boolean ;
158+ fileTypeOverride : boolean ;
154159} > ;
155160
156161export class MultimodalFileInputState {
157162 private readonly opts : MultimodalFileInputStateProps ;
158163 mode : FileInputMode = $state ( "file" ) ;
159164 text : string = $state ( "" ) ;
165+ textType : FileType = $state ( "plaintext" ) ;
160166 file : File | undefined = $state ( undefined ) ;
167+ fileType : FileType = $state ( "auto" ) ;
161168 url : string = $state ( "" ) ;
169+ urlType : FileType = $state ( "auto" ) ;
162170 private urlResolver = $derived . by ( ( ) => {
163171 const url = this . url ;
164172 return lazyPromise ( async ( ) => {
@@ -185,22 +193,56 @@ export class MultimodalFileInputState {
185193 if ( this . opts . state ) {
186194 this . mode = this . opts . state . mode ;
187195 this . text = this . opts . state . text ;
196+ this . textType = this . opts . state . textType ;
188197 this . file = this . opts . state . file ;
198+ this . fileType = this . opts . state . fileType ;
189199 this . url = this . opts . state . url ;
200+ this . urlType = this . opts . state . urlType ;
190201 this . urlResolver = this . opts . state . urlResolver ;
191202 }
192203 }
193204
205+ getFileType ( ) : FileType {
206+ if ( this . mode === "file" ) {
207+ return this . fileType ;
208+ } else if ( this . mode === "url" ) {
209+ return this . urlType ;
210+ } else if ( this . mode === "text" ) {
211+ return this . textType ;
212+ }
213+ throw new Error ( "Invalid mode" ) ;
214+ }
215+
216+ setFileType ( fileType : FileType ) {
217+ if ( this . mode === "file" ) {
218+ this . fileType = fileType ;
219+ } else if ( this . mode === "url" ) {
220+ this . urlType = fileType ;
221+ } else if ( this . mode === "text" ) {
222+ this . textType = fileType ;
223+ } else {
224+ throw new Error ( "Invalid mode" ) ;
225+ }
226+ }
227+
228+ private getExtensionOrBlank ( ) {
229+ const fileType = this . getFileType ( ) ;
230+ if ( fileType === "auto" ) {
231+ return "" ;
232+ }
233+ return getExtensionForLanguage ( fileType ) ;
234+ }
235+
194236 get metadata ( ) : MultimodalFileInputValueMetadata | null {
195237 const mode = this . mode ;
196238 const label = this . opts . label . current ;
197239 if ( mode === "file" && this . file !== undefined ) {
198240 const file = this . file ;
199- return { type : "file" , name : file . name } ;
241+ return { type : "file" , name : ` ${ file . name } ${ this . getExtensionOrBlank ( ) } ` } ;
200242 } else if ( mode === "url" && this . url !== "" ) {
201- return { type : "url" , name : this . url } ;
243+ return { type : "url" , name : ` ${ this . url } ${ this . getExtensionOrBlank ( ) } ` } ;
202244 } else if ( mode === "text" && this . text !== "" ) {
203- return { type : "text" , name : `${ label } (Text Input) ` } ;
245+ return { type : "text" , name : `${ label } ${ this . getExtensionOrBlank ( ) } ` } ;
204246 } else {
205247 return null ;
206248 }
@@ -228,20 +270,29 @@ export class MultimodalFileInputState {
228270 swapState ( other : MultimodalFileInputState ) {
229271 const mode = this . mode ;
230272 const text = this . text ;
273+ const textType = this . textType ;
231274 const file = this . file ;
275+ const fileType = this . fileType ;
232276 const url = this . url ;
277+ const urlType = this . urlType ;
233278 const urlResolver = this . urlResolver ;
234279
235280 this . mode = other . mode ;
236281 this . text = other . text ;
282+ this . textType = other . textType ;
237283 this . file = other . file ;
284+ this . fileType = other . fileType ;
238285 this . url = other . url ;
286+ this . urlType = other . urlType ;
239287 this . urlResolver = other . urlResolver ;
240288
241289 other . mode = mode ;
242290 other . text = text ;
291+ other . textType = textType ;
243292 other . file = file ;
293+ other . fileType = fileType ;
244294 other . url = url ;
295+ other . urlType = urlType ;
245296 other . urlResolver = urlResolver ;
246297 }
247298}
0 commit comments