Skip to content

Commit 9d4b2bf

Browse files
committed
feat: enhance image and video handling by supporting URLs and file IDs
1 parent 30494cf commit 9d4b2bf

File tree

6 files changed

+94
-21
lines changed

6 files changed

+94
-21
lines changed

apps/application/flow/step_node/image_to_video_step_node/impl/base_image_to_video_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def execute(self, model_id, prompt, negative_prompt, dialogue_number, dialogue_t
7474
def get_file_base64(self, image_url):
7575
try:
7676
if isinstance(image_url, list):
77-
image_url = image_url[0].get('file_id')
77+
image_url = image_url[0].get('file_id') if 'file_id' in image_url[0] else image_url[0].get('url')
7878
if isinstance(image_url, str) and not image_url.startswith('http'):
7979
file = QuerySet(File).filter(id=image_url).first()
8080
file_bytes = file.get_bytes()

apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,18 @@ def generate_history_human_message_for_details(self, chat_record):
131131
image_list = data['image_list']
132132
if len(image_list) == 0 or data['dialogue_type'] == 'WORKFLOW':
133133
return HumanMessage(content=chat_record.problem_text)
134-
file_id_list = [image.get('file_id') for image in image_list]
134+
135+
file_id_list = []
136+
url_list = []
137+
for image in image_list:
138+
if 'file_id' in image:
139+
file_id_list.append(image.get('file_id'))
140+
elif 'url' in image:
141+
url_list.append(image.get('url'))
135142
return HumanMessage(content=[
136143
{'type': 'text', 'text': data['question']},
137-
*[{'type': 'image_url', 'image_url': {'url': f'./oss/file/{file_id}'}} for file_id in file_id_list]
138-
144+
*[{'type': 'image_url', 'image_url': {'url': f'./oss/file/{file_id}'}} for file_id in file_id_list],
145+
*[{'type': 'image_url', 'image_url': {'url': url}} for url in url_list]
139146
])
140147
return HumanMessage(content=chat_record.problem_text)
141148

@@ -155,13 +162,22 @@ def generate_history_human_message(self, chat_record):
155162
image_list = data['image_list']
156163
if len(image_list) == 0 or data['dialogue_type'] == 'WORKFLOW':
157164
return HumanMessage(content=chat_record.problem_text)
158-
image_base64_list = [file_id_to_base64(image.get('file_id')) for image in image_list]
165+
file_id_list = []
166+
url_list = []
167+
for image in image_list:
168+
if 'file_id' in image:
169+
file_id_list.append(image.get('file_id'))
170+
elif 'url' in image:
171+
url_list.append(image.get('url'))
172+
image_base64_list = [file_id_to_base64(file_id) for file_id in file_id_list]
173+
159174
return HumanMessage(
160175
content=[
161176
{'type': 'text', 'text': data['question']},
162177
*[{'type': 'image_url',
163178
'image_url': {'url': f'data:image/{base64_image[1]};base64,{base64_image[0]}'}} for
164-
base64_image in image_base64_list]
179+
base64_image in image_base64_list],
180+
*[{'type': 'image_url', 'image_url': url} for url in url_list]
165181
])
166182
return HumanMessage(content=chat_record.problem_text)
167183

@@ -177,13 +193,17 @@ def _process_images(self, image):
177193
images.append({'type': 'image_url', 'image_url': {'url': image}})
178194
elif image is not None and len(image) > 0:
179195
for img in image:
180-
file_id = img['file_id']
181-
file = QuerySet(File).filter(id=file_id).first()
182-
image_bytes = file.get_bytes()
183-
base64_image = base64.b64encode(image_bytes).decode("utf-8")
184-
image_format = what(None, image_bytes)
185-
images.append(
186-
{'type': 'image_url', 'image_url': {'url': f'data:image/{image_format};base64,{base64_image}'}})
196+
if 'file_id' in img:
197+
file_id = img['file_id']
198+
file = QuerySet(File).filter(id=file_id).first()
199+
image_bytes = file.get_bytes()
200+
base64_image = base64.b64encode(image_bytes).decode("utf-8")
201+
image_format = what(None, image_bytes)
202+
images.append(
203+
{'type': 'image_url', 'image_url': {'url': f'data:image/{image_format};base64,{base64_image}'}})
204+
elif 'url' in img and img['url'].startswith('http'):
205+
images.append(
206+
{'type': 'image_url', 'image_url': {'url': img["url"]}})
187207
return images
188208

189209
def generate_message_list(self, image_model, system: str, prompt: str, history_message, image):

apps/application/flow/step_node/video_understand_step_node/impl/base_video_understand_node.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,17 @@ def generate_history_human_message_for_details(self, chat_record):
131131
# 增加对 None 和空列表的检查
132132
if not video_list or len(video_list) == 0 or data['dialogue_type'] == 'WORKFLOW':
133133
return HumanMessage(content=chat_record.problem_text)
134-
file_id_list = [video.get('file_id') for video in video_list]
134+
file_id_list = []
135+
url_list = []
136+
for image in video_list:
137+
if 'file_id' in image:
138+
file_id_list.append(image.get('file_id'))
139+
elif 'url' in image:
140+
url_list.append(image.get('url'))
135141
return HumanMessage(content=[
136142
{'type': 'text', 'text': data['question']},
137-
*[{'type': 'video_url', 'video_url': {'url': f'./oss/file/{file_id}'}} for file_id in file_id_list]
138-
143+
*[{'type': 'video_url', 'video_url': {'url': f'./oss/file/{file_id}'}} for file_id in file_id_list],
144+
*[{'type': 'video_url', 'video_url': {'url': url}} for url in url_list],
139145
])
140146
return HumanMessage(content=chat_record.problem_text)
141147

@@ -155,6 +161,13 @@ def generate_history_human_message(self, chat_record, video_model):
155161
video_list = data['video_list']
156162
if len(video_list) == 0 or data['dialogue_type'] == 'WORKFLOW':
157163
return HumanMessage(content=chat_record.problem_text)
164+
file_id_list = []
165+
url_list = []
166+
for image in video_list:
167+
if 'file_id' in image:
168+
file_id_list.append(image.get('file_id'))
169+
elif 'url' in image:
170+
url_list.append(image.get('url'))
158171
video_base64_list = [file_id_to_base64(video.get('file_id'), video_model) for video in video_list]
159172
return HumanMessage(
160173
content=[
@@ -174,11 +187,15 @@ def _process_videos(self, image, video_model):
174187
videos.append({'type': 'video_url', 'video_url': {'url': image}})
175188
elif image is not None and len(image) > 0:
176189
for img in image:
177-
file_id = img['file_id']
178-
file = QuerySet(File).filter(id=file_id).first()
179-
url = video_model.upload_file_and_get_url(file.get_bytes(), file.file_name)
180-
videos.append(
181-
{'type': 'video_url', 'video_url': {'url': url}})
190+
if 'file_id' in img:
191+
file_id = img['file_id']
192+
file = QuerySet(File).filter(id=file_id).first()
193+
url = video_model.upload_file_and_get_url(file.get_bytes(), file.file_name)
194+
videos.append(
195+
{'type': 'video_url', 'video_url': {'url': url}})
196+
elif 'url' in img and img['url'].startswith('http'):
197+
videos.append(
198+
{'type': 'video_url', 'video_url': {'url': img['url']}})
182199
return videos
183200

184201
def generate_message_list(self, video_model, system: str, prompt: str, history_message, video):

apps/oss/retrieval_urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@
1717
views.FileRetrievalView.as_view()),
1818
re_path(rf'oss/file/(?P<file_id>[\w-]+)/?$',
1919
views.FileRetrievalView.as_view()),
20+
re_path(rf'^/oss/get_url/(?P<url>[\w-]+)?$',
21+
views.GetUrlView.as_view()),
2022

2123
]

apps/oss/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66

77
urlpatterns = [
88
path('oss/file', views.FileView.as_view()),
9+
path('oss/get_url', views.GetUrlView.as_view()),
910
]

apps/oss/views/file.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# coding=utf-8
2+
import base64
3+
4+
import requests
25
from django.utils.translation import gettext_lazy as _
36
from drf_spectacular.utils import extend_schema
47
from rest_framework.parsers import MultiPartParser
@@ -66,3 +69,33 @@ class Operate(APIView):
6669
@log(menu='file', operate='Delete file')
6770
def delete(self, request: Request, file_id: str):
6871
return result.success(FileSerializer.Operate(data={'id': file_id}).delete())
72+
73+
74+
class GetUrlView(APIView):
75+
authentication_classes = [TokenAuth]
76+
77+
@extend_schema(
78+
methods=['GET'],
79+
summary=_('Get url'),
80+
description=_('Get url'),
81+
operation_id=_('Get url'), # type: ignore
82+
tags=[_('Chat')] # type: ignore
83+
)
84+
def get(self, request: Request):
85+
url = request.query_params.get('url')
86+
response = requests.get(url)
87+
# 返回状态码 响应内容大小 响应的contenttype 还有字节流
88+
content_type = response.headers.get('Content-Type', '')
89+
# 根据内容类型决定如何处理
90+
if 'text' in content_type or 'json' in content_type:
91+
content = response.text
92+
else:
93+
# 二进制内容使用Base64编码
94+
content = base64.b64encode(response.content).decode('utf-8')
95+
96+
return result.success({
97+
'status_code': response.status_code,
98+
'Content-Length': response.headers.get('Content-Length', 0),
99+
'Content-Type': content_type,
100+
'content': content,
101+
})

0 commit comments

Comments
 (0)