Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit d22d5ad

Browse files
committed
Add support for getting base64 encoded uploads
1 parent 39a0ef7 commit d22d5ad

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

lib/personas/tool_runner.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ def framework_script
7979
const upload = {
8080
create: _upload_create,
8181
getUrl: _upload_get_url,
82+
getBase64: function(id, maxPixels) {
83+
return _upload_get_base64(id, maxPixels);
84+
}
8285
}
8386
8487
const chain = {
@@ -604,6 +607,42 @@ def attach_discourse(mini_racer_context)
604607
end
605608

606609
def attach_upload(mini_racer_context)
610+
mini_racer_context.attach(
611+
"_upload_get_base64",
612+
->(upload_id_or_url, max_pixels) do
613+
in_attached_function do
614+
return nil if upload_id_or_url.blank?
615+
616+
upload = nil
617+
618+
# Handle both upload ID and short URL
619+
if upload_id_or_url.to_s.start_with?("upload://")
620+
# Handle short URL format
621+
sha1 = Upload.sha1_from_short_url(upload_id_or_url)
622+
return nil if sha1.blank?
623+
upload = Upload.find_by(sha1: sha1)
624+
else
625+
# Handle numeric ID
626+
upload_id = upload_id_or_url.to_i
627+
return nil if upload_id <= 0
628+
upload = Upload.find_by(id: upload_id)
629+
end
630+
631+
return nil if upload.nil?
632+
633+
max_pixels = max_pixels&.to_i
634+
max_pixels = nil if max_pixels && max_pixels <= 0
635+
636+
encoded_uploads =
637+
DiscourseAi::Completions::UploadEncoder.encode(
638+
upload_ids: [upload.id],
639+
max_pixels: max_pixels || 10_000_000, # Default to 10M pixels if not specified
640+
)
641+
642+
encoded_uploads.first&.dig(:base64)
643+
end
644+
end,
645+
)
607646
mini_racer_context.attach(
608647
"_upload_get_url",
609648
->(short_url) do

spec/models/ai_tool_spec.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,67 @@ def stub_embeddings
696696
expect(result).to eq([{ "slept" => 1 }, { "slept" => 1 }, { "slept" => 1 }])
697697
end
698698

699+
let(:jpg) { plugin_file_from_fixtures("1x1.jpg") }
700+
701+
describe "upload base64 encoding" do
702+
it "can get base64 data from upload ID and short URL" do
703+
upload = UploadCreator.new(jpg, "1x1.jpg").create_for(Discourse.system_user.id)
704+
705+
# Test with upload ID
706+
script_id = <<~JS
707+
function invoke(params) {
708+
return upload.getBase64(params.upload_id, params.max_pixels);
709+
}
710+
JS
711+
712+
tool = create_tool(script: script_id)
713+
runner =
714+
tool.runner(
715+
{ "upload_id" => upload.id, "max_pixels" => 1_000_000 },
716+
llm: nil,
717+
bot_user: nil,
718+
)
719+
result_id = runner.invoke
720+
721+
expect(result_id).to be_present
722+
expect(result_id).to be_a(String)
723+
expect(result_id.length).to be > 0
724+
725+
# Test with short URL
726+
script_url = <<~JS
727+
function invoke(params) {
728+
return upload.getBase64(params.short_url, params.max_pixels);
729+
}
730+
JS
731+
732+
tool = create_tool(script: script_url)
733+
runner =
734+
tool.runner(
735+
{ "short_url" => upload.short_url, "max_pixels" => 1_000_000 },
736+
llm: nil,
737+
bot_user: nil,
738+
)
739+
result_url = runner.invoke
740+
741+
expect(result_url).to be_present
742+
expect(result_url).to be_a(String)
743+
expect(result_url).to eq(result_id) # Should return same base64 data
744+
745+
# Test with invalid upload ID
746+
script_invalid = <<~JS
747+
function invoke(params) {
748+
return upload.getBase64(99999);
749+
}
750+
JS
751+
752+
tool = create_tool(script: script_invalid)
753+
runner = tool.runner({}, llm: nil, bot_user: nil)
754+
result_invalid = runner.invoke
755+
756+
expect(result_invalid).to be_nil
757+
end
758+
end
759+
699760
describe "upload URL resolution" do
700761
it "can resolve upload short URLs to public URLs" do
701762
upload =

0 commit comments

Comments
 (0)