Skip to content

Commit 3f49a87

Browse files
wly-115liutongxuan
authored andcommitted
feat: support image url input for vlm.
1 parent d5cc2a9 commit 3f49a87

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed

xllm/api_service/chat_service_impl.cpp

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ void MMChatServiceImpl::process_async(std::shared_ptr<MMChatCall> call) {
647647
std::vector<Message> messages;
648648
MMInput mm_inputs;
649649

650-
MMInputHelper helper;
650+
static MMInputHelper helper;
651651
if (!helper.trans(req_messages, messages, mm_inputs.items_)) {
652652
call->finish_with_error(StatusCode::INVALID_ARGUMENT,
653653
"inputs argument is invalid.");

xllm/core/framework/request/CMakeLists.txt

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ cc_library(
4545
absl::time
4646
proto::xllm_proto
4747
torch
48+
${OpenCV_LIBS}
4849
)
4950

xllm/core/framework/request/mm_input_helper.cpp

100644100755
Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ limitations under the License.
1515

1616
#include "mm_input_helper.h"
1717

18+
#include <brpc/channel.h>
19+
#include <brpc/controller.h>
20+
#include <bthread/rwlock.h>
21+
#include <glog/logging.h>
22+
1823
#include <opencv2/opencv.hpp>
1924

2025
#include "butil/base64.h"
@@ -41,6 +46,91 @@ class OpenCVImageDecoder {
4146
}
4247
};
4348

49+
class FileDownloadHelper {
50+
public:
51+
FileDownloadHelper() {}
52+
~FileDownloadHelper() {}
53+
std::string parse_url(const std::string& url) {
54+
size_t scheme_end = url.find("://");
55+
if (scheme_end == std::string::npos) {
56+
LOG(ERROR)
57+
<< "Error: Invalid URL, missing protocol (http:// or https://)";
58+
}
59+
size_t host_start = scheme_end + 3;
60+
size_t path_pos = url.find('/', host_start);
61+
if (path_pos == std::string::npos) {
62+
LOG(ERROR) << "Error: No path in URL";
63+
}
64+
return url.substr(host_start, path_pos - host_start);
65+
}
66+
67+
std::shared_ptr<brpc::Channel> get_channel(const std::string& host) {
68+
{
69+
bthread::RWLockRdGuard rd_guard(instance_channel_map_mutex_);
70+
auto it = channels_.find(host);
71+
if (it != channels_.end()) {
72+
return it->second;
73+
}
74+
}
75+
bthread::RWLockWrGuard wr_guard(instance_channel_map_mutex_);
76+
auto it = channels_.find(host);
77+
if (it != channels_.end()) {
78+
return it->second;
79+
}
80+
81+
brpc::ChannelOptions option;
82+
option.protocol = brpc::PROTOCOL_HTTP;
83+
option.connection_type = brpc::CONNECTION_TYPE_POOLED;
84+
option.max_retry = 3;
85+
auto channel = std::make_shared<brpc::Channel>();
86+
if (channel->Init(host.c_str(), &option) != 0) {
87+
LOG(ERROR) << "fail to init channel for " << host;
88+
return nullptr;
89+
}
90+
channels_[host] = channel;
91+
return channel;
92+
}
93+
94+
bool download_data(const std::string& host,
95+
const std::string& url,
96+
std::string& data) {
97+
brpc::Controller cntl;
98+
cntl.http_request().uri() = url;
99+
cntl.set_timeout_ms(2000);
100+
auto channel = get_channel(host);
101+
if (!channel) {
102+
LOG(ERROR) << "Channel is null";
103+
return false;
104+
}
105+
channel->CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr);
106+
if (cntl.Failed()) {
107+
LOG(ERROR) << "Request failed: " << cntl.ErrorText();
108+
return false;
109+
}
110+
111+
if (cntl.http_response().status_code() != 200) {
112+
LOG(ERROR) << "HTTP error: " << cntl.http_response().status_code();
113+
return false;
114+
}
115+
116+
const butil::IOBuf& io = cntl.response_attachment();
117+
data = io.to_string();
118+
return true;
119+
}
120+
121+
bool fetch_data(const std::string& url, std::string& data) {
122+
// parse url
123+
std::string host = parse_url(url);
124+
// fetch data
125+
return download_data(host, url, data);
126+
}
127+
128+
private:
129+
bthread::RWLock instance_channel_map_mutex_;
130+
inline static std::unordered_map<std::string, std::shared_ptr<brpc::Channel>>
131+
channels_;
132+
};
133+
44134
class Handler {
45135
public:
46136
bool process(const proto::MMInputData& msg, MMInputItem& input) {
@@ -74,13 +164,19 @@ class Handler {
74164
}
75165

76166
bool load_from_http(const std::string& url, std::string& data) {
77-
return false;
167+
return helper_.fetch_data(url, data);
78168
}
169+
170+
std::string dataurl_prefix_{"data:image"};
171+
std::string httpurl_prefix_{"http"};
172+
173+
private:
174+
FileDownloadHelper helper_;
79175
};
80176

81177
class ImageHandler : public Handler {
82178
public:
83-
ImageHandler() : dataurl_prefix_("data:image") {}
179+
ImageHandler() {}
84180

85181
virtual bool load(const proto::MMInputData& msg, MMInputItem& input) {
86182
input.clear();
@@ -93,18 +189,18 @@ class ImageHandler : public Handler {
93189

94190
input.type_ = MMType::IMAGE;
95191
return this->load_from_dataurl(url, input.raw_data_);
96-
} else {
97-
return false;
192+
} else if (url.compare(0, httpurl_prefix_.size(), httpurl_prefix_) ==
193+
0) { // http url
194+
195+
input.type_ = MMType::IMAGE;
196+
return this->load_from_http(url, input.raw_data_);
98197
}
99198
}
100199

101200
virtual bool decode(MMInputItem& input) {
102201
OpenCVImageDecoder decoder;
103202
return decoder.decode(input.raw_data_, input.decode_data_);
104203
}
105-
106-
private:
107-
const std::string dataurl_prefix_;
108204
};
109205

110206
class MMHandlerSet {
@@ -128,7 +224,7 @@ class MMHandlerSet {
128224
}
129225

130226
private:
131-
std::unordered_map<std::string, std::unique_ptr<Handler> > handlers_;
227+
std::unordered_map<std::string, std::unique_ptr<Handler>> handlers_;
132228
};
133229

134230
MMInputHelper::MMInputHelper() {

0 commit comments

Comments
 (0)