使用Files API
上一节介绍了通过 URL 或 base64 直接提交图片。这种方式简单直接,但有两个限制:图片需在 48 MiB 的请求体限制内,且每次请求都要重新提交图片数据。如果需要在多个请求中复用同一张图片,或者图片较大,使用 Files API 会更合适——只需上传一次,之后通过 file_id 引用即可,推荐在以下场景使用:
Files API
目前仅支持图片格式:JPEG、PNG、GIF、WebP。格式由文件实际内容判断,而非文件名。
DeepSeek关于Files API的官方地址:
https://api-docs.deepseek.com/zh-cn/guides/files_api
基于这个API,我们完全可以设计一个文件上传、列表、删除、AI分析理解的图片管理系统。
目前 DeepSeek 的 Files API 仅支持图片格式。如果未来扩展到 PDF、Word
等文档格式(据传已在路径中),本节介绍的上传、引用、管理流程仍然适用,只需调整文件过滤器和处理逻辑即可。
上传文件
在命令窗口执行:
'''Async
Dim
imgPath
As
String
=
"C:\test\test.jpg"
'本地图片文件
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
hc
As
New
HttpClient("https://api.deepseek.com/files")
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
'设置密钥
' 设置表单参数
hc.FormData.Add("purpose",
"user_data")
hc.Files.Add("file",
imgPath)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode = 200
Then
Dim
jo
As
JObject = JsonConvert.DeserializeObject(res)
Dim
fileid
As
String
= jo("id")
'获取文件ID
Output.Show(jo.ToString())
Else
MessageBoxA.Show("文件上传失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
End
If
得到的结果类似:
{
"id":"file-api-d3dfd5cb-1b9f-48fc-94b7-b9fe3314f401",
"object":"file",
"bytes":215000,
"created_at":1791707212,
"filename":"test.jpg",
"purpose":"user_data"
}
其中id字段是需要记录下来的,接下来我们就可以在其他代码中通过这个id访问上传好的文件,例如:
Dim
caller
As
New
LLMCaller("https://api.deepseek.com/chat/completions",
"deepseek-flash",
"sk-a734b83536da45e9aedc3e42605bfb3a")
Dim
msgArray
As
New
JArray()
'添加用户问题
msgArray.Add(
New
JObject
From
{
{"type",
"text"},
{"text",
"这张图片里有什么?"}
})
'通过id引用我们之前上传的图片文件
msgArray.Add(New
JObject
From
{
{"type",
"file"},
{"file_id",
"file-api-d3dfd5cb-1b9f-48fc-94b7-b9fe3314f401"}
})
caller.UserMessage = msgArray
If
caller.GetResult()
Then
MessageBoxA.Show(caller.Result)
Else
MessageBoxA.Show(caller.Error)
End
If
当然你也可以将两段代码合在一起:
'''Async
Dim
imgPath
As
String
=
"C:\test\test.jpg"
'本地图片文件
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
hc
As
New
HttpClient("https://api.deepseek.com/files")
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
'设置密钥
' 设置表单参数
hc.FormData.Add("purpose",
"user_data")
hc.Files.Add("file",
imgPath)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode = 200
Then
Dim
jo
As
JObject = JsonConvert.DeserializeObject(res)
Dim
fileid
As
String
= jo("id")
'获取文件ID
Dim
caller
As
New
LLMCaller("https://api.deepseek.com/chat/completions",
"deepseek-flash",
apiKey)
Dim
msgArray
As
New
JArray()
'添加用户问题
msgArray.Add(
New
JObject
From
{
{"type",
"text"},
{"text",
"这张图片里有什么?"}
})
'通过id引用我们之前上传的图片文件
msgArray.Add(New
JObject
From
{
{"type",
"file"},
{"file_id",
fileid}
})
caller.UserMessage = msgArray
If
caller.GetResult()
Then
MessageBoxA.Show(caller.Result)
Else
MessageBoxA.Show(caller.Error)
End
If
Else
MessageBoxA.Show("文件上传失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
End
If
设置文件有效期
上传的文件默认长期有效,你可以在上传文件的时候设置一个有效期,有效期到了之后,服务器会自动删除该文件。
例如:
'''Async
Dim
imgPath
As
String
=
"C:\test\test.jpg"
'本地图片文件
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
hc
As
New
HttpClient("https://api.deepseek.com/files")
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
'设置密钥
' 设置表单参数
hc.FormData.Add("purpose",
"user_data")
hc.FormData.Add("expires_after[anchor]",
"created_at")
'
锚点:创建时间
hc.FormData.Add("expires_after[seconds]",
"604800")
'
有效期604800秒,也就是7
天
hc.Files.Add("file",
imgPath)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode = 200
Then
Dim
jo
As
JObject = JsonConvert.DeserializeObject(res)
Dim
fileid
As
String
= jo("id")
'获取文件ID
Output.Show(jo.ToString())
Else
MessageBoxA.Show("文件上传失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
End
If
普通用户可以忽略接下来的内容,以下三个操作(查询指定文件、删除指定文件、查询所有文件)主要用于文件管理和清理,在常规的图片理解场景中并不需要。
查询指定文件
参考代码:
'''Async
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
fileId
As
String
=
"file-api-5a55e104-0737-4478-a0f6-1990d4bf6890"
'请替换为要查询的文件ID
Dim
url
As
String
=
"https://api.deepseek.com/files/"
& fileId
Dim
hc
As
New
HttpClient(url)
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode = 200
Then
Dim
file
As
JObject = JsonConvert.DeserializeObject(res)
Dim
fileName
As
String
= file("filename").ToString()
Dim
fileBytes
As
Long
= file("bytes").ToObject(Of
Long)()
Dim
createdAt
As
Long
= file("created_at").ToObject(Of
Long)()
Dim
createdTime
As
DateTime = DateTimeOffset.FromUnixTimeSeconds(createdAt).LocalDateTime
Dim
purpose
As
String
= file("purpose").ToString()
Dim
sb
As
New
StringBuilder()
sb.AppendLine("文件名:"
& fileName)
sb.AppendLine("文件ID:"
& file("id").ToString())
sb.AppendLine("大小:"
& Math.Round(fileBytes / 1024, 1) &
" KB")
sb.AppendLine("用途:"
& purpose)
sb.AppendLine("上传时间:"
& createdTime.ToString("yyyy-MM-dd
HH:mm:ss"))
'
如果设置了过期时间,会返回
expires_at 字段
If
file("expires_at")
IsNot
Nothing
AndAlso
file("expires_at").Type
<> JTokenType.Null
Then
Dim
expiresAt
As
Long
= file("expires_at").ToObject(Of
Long)()
Dim
expireTime
As
DateTime = DateTimeOffset.FromUnixTimeSeconds(expiresAt).LocalDateTime
sb.AppendLine("过期时间:"
& expireTime.ToString("yyyy-MM-dd
HH:mm:ss"))
Else
sb.AppendLine("过期时间:永久有效")
End
If
MessageBoxA.Show(sb.ToString())
Else
MessageBoxA.Show("查询文件失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
End
If
删除指定文件
参考代码:
'''Async
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
fileId
As
String
=
"file-api-5a55e104-0737-4478-a0f6-1990d4bf6890"
'请替换为要删除的文件ID
Dim
url
As
String
=
"https://api.deepseek.com/files/"
& fileId
Dim
hc
As
New
HttpClient(url)
hc.Method =
"DELETE"
'
明确指定请求方式为
DELETE
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode = 200
Then
Dim
jo
As
JObject = JsonConvert.DeserializeObject(res)
Dim
deleted
As
Boolean
= jo("deleted").ToObject(Of
Boolean)()
If
deleted
Then
MessageBoxA.Show("文件删除成功:"
& vbCrLf &
"文件ID:"
& jo("id").ToString())
Else
MessageBoxA.Show("文件删除失败,API
返回
deleted = false。")
End
If
Else
MessageBoxA.Show("删除文件失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
End
If
查询所有文件
参考代码:
'''Async
Dim
apiKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'请替换为自己的密钥
Dim
limit
As
Integer
= 200
'
每页返回200个文件,1~1000,默认1000
Dim
Order
As
String
=
"desc"
'
排序方式:asc(按创建时间升序)或
desc(降序)
Dim
purpose
As
String
=
"user_data"
'
仅支持
user_data
' ---- 1.
分页获取所有文件
----
Dim
allFiles
As
New
JArray()
Dim
afterId
As
String
=
""
Dim
hasMore
As
Boolean
=
True
While
hasMore
'
构造请求URL
Dim
url
As
String
=
"https://api.deepseek.com/files"
&
"?limit="
& limit &
"&order="
&
Order
&
"&purpose="
& purpose
If
afterId <>
""
Then
url &=
"&after="
& afterId
End
If
Dim
hc
As
New
HttpClient(url)
hc.SkipError =
True
hc.Headers.Add("Authorization",
"Bearer "
& apiKey)
Dim
res
As
String
=
Await
hc.GetDataAsync()
If
hc.StatusCode <> 200
Then
MessageBoxA.Show("获取文件列表失败:"
& vbCrLf &
"状态码:"
& hc.StatusCode & vbCrLf &
"状态描述:"
& hc.StatusDescription)
Return
""
End
If
Dim
jo
As
JObject = JsonConvert.DeserializeObject(res)
Dim
pageFiles
As
JArray = jo("data")
'
将当前页的文件添加到总列表
For
Each
file
As
JObject
In
pageFiles
allFiles.Add(file)
Next
'
检查是否还有更多
hasMore = jo("has_more").ToObject(Of
Boolean)()
If
hasMore
Then
afterId = jo("last_id").ToString()
End
If
End
While
' ---- 2.
格式化显示所有文件信息
----
If
allFiles.Count = 0
Then
MessageBoxA.Show("没有已上传的文件。")
Else
Dim
sb
As
New
StringBuilder()
sb.AppendLine("共
"
& allFiles.Count &
"
个文件:")
sb.AppendLine()
For
Each
file
As
JObject
In
allFiles
Dim
fileId
As
String
= file("id").ToString()
Dim
fileName
As
String
= file("filename").ToString()
Dim
fileBytes
As
Long
= file("bytes").ToObject(Of
Long)()
Dim
createdAt
As
Long
= file("created_at").ToObject(Of
Long)()
Dim
createdTime
As
DateTime = DateTimeOffset.FromUnixTimeSeconds(createdAt).LocalDateTime
sb.AppendLine("文件名:"
& fileName)
sb.AppendLine("
文件ID:"
& fileId)
sb.AppendLine("
大小:"
& Math.Round(fileBytes / 1024, 1) &
" KB")
sb.AppendLine("
上传时间:"
& createdTime.ToString("yyyy-MM-dd
HH:mm:ss"))
'
如果设置了过期时间,会返回
expires_at 字段
If
file("expires_at")
IsNot
Nothing
AndAlso
file("expires_at").Type
<> JTokenType.Null
Then
Dim
expiresAt
As
Long
= file("expires_at").ToObject(Of
Long)()
Dim
expireTime
As
DateTime = DateTimeOffset.FromUnixTimeSeconds(expiresAt).LocalDateTime
sb.AppendLine("
过期时间:"
& expireTime.ToString("yyyy-MM-dd
HH:mm:ss"))
Else
sb.AppendLine("
过期时间:永久有效")
End
If
sb.AppendLine()
Next
Output.Show(sb.ToString())
End
If