Not convinced yet?
— Plamen Mushkov (@plamen_9) February 12, 2024
Give my little POC a try - built in a single day, using the best Low-code tool - Oracle APEX (#orclAPEX) with some REST API calls to my local machine.
Now, explaining memes to you, using the latest version of LLaVA multi-modal LLM, run locally using Ollama ✨… pic.twitter.com/atvTzVpMCg
ubuntu@mywhisper2:~$ curl -fsSL https://ollama.com/install.sh | sh
>>> Downloading ollama...
######################################################################## 100.0%######################################################################### 100.0%
>>> Installing ollama to /usr/local/bin...
>>> Creating ollama user...
>>> Adding ollama user to render group...
>>> Adding current user to ollama group...
>>> Creating ollama systemd service...
>>> Enabling and starting ollama service...
Created symlink /etc/systemd/system/default.target.wants/ollama.service → /etc/systemd/system/ollama.service.
>>> The Ollama API is now available at 0.0.0.0:11434.
>>> Install complete. Run "ollama" from the command line.
WARNING: No NVIDIA GPU detected. Ollama will run in CPU-only mode.
ubuntu@mywhisper2:~$
ubuntu@mywhisper2:~$ ollama run codellama
pulling manifest
pulling 3a43f93b78ec... 100% ▕████████████████▏ 3.8 GB
pulling 8c17c2ebb0ea... 100% ▕████████████████▏ 7.0 KB
pulling 590d74a5569b... 100% ▕████████████████▏ 4.8 KB
pulling 2e0493f67d0c... 100% ▕████████████████▏ 59 B
pulling 7f6a57943a88... 100% ▕████████████████▏ 120 B
pulling 316526ac7323... 100% ▕████████████████▏ 529 B
verifying sha256 digest
writing manifest
removing any unused layers
success
>>> /?
Available Commands:
/set Set session variables
/show Show model information
/load <model> Load a session or model
/save <model> Save your current session
/bye Exit
/?, /help Help for a command
/? shortcuts Help for keyboard shortcuts
Use """ to begin a multi-line message.
>>> /bye
ubuntu@mywhisper2:~$
ubuntu@mywhisper2:~$ sudo firewall-cmd --add-port=11434/tcp
You're performing an operation over default zone ('public'),
but your connections/interfaces are in zone 'docker' (see --get-active-zones)
You most likely need to use --zone=docker option.
success
ubuntu@mywhisper2:~$
ubuntu@mywhisper2:~$ sudo firewall-cmd --runtime-to-permanent
success
ubuntu@mywhisper2:~$
proxy_pass http://localhost:11434/;
以上の変更を行なった後にNginxを再起動すると、Ollamaを呼び出せる状態になります。
declare | |
l_request json_object_t; | |
l_request_clob clob; | |
l_response clob; | |
l_generated_message clob; | |
e_call_api_failed exception; | |
/* 改行ごとにJSONを読む際に使用する */ | |
l_pos integer; | |
l_offset integer; | |
l_amount integer; | |
l_line varchar2(32767); | |
l_json json_object_t; | |
l_is_done boolean; | |
begin | |
/* | |
* OllamaのGenerate a completionを呼び出す。 | |
* https://github.com/ollama/ollama/blob/main/docs/api.md | |
*/ | |
l_request := json_object_t(); | |
l_request.put('model', :P1_MODEL); | |
l_request.put('prompt', :P1_MESSAGE); | |
l_request_clob := l_request.to_clob(); | |
/* | |
* REST APIの呼び出し。Always FreeのAmpere A1インスタンスは遅いので | |
* p_transfer_timeoutの設定は必須。 | |
*/ | |
apex_web_service.clear_request_headers(); | |
apex_web_service.set_request_headers('Content-Type', 'application/json', p_reset => false); | |
l_response := apex_web_service.make_rest_request( | |
p_url => :G_ENDPOINT | |
,p_http_method => 'POST' | |
,p_body => l_request_clob | |
,p_transfer_timeout => :G_TRANSFER_TIMEOUT | |
); | |
if apex_web_service.g_status_code <> 200 then | |
raise e_call_api_failed; | |
end if; | |
/* | |
* 出力はデフォルトでストリーミングで、APEXの場合、Ollamaが分割で返しているレスポンスが | |
* ひとつのレスポンスとして返される。そのため、レスポンスを改行ごとに分割して、それぞれを | |
* JSONとして解釈する必要がある。 | |
*/ | |
l_generated_message := ''; | |
l_offset := 1; | |
while true | |
loop | |
/* | |
* LFの位置を探す。 | |
* 返される位置はoffsetからの相対位置ではなく、CLOBの中での絶対位置が返される。 | |
*/ | |
l_pos := dbms_lob.instr( | |
lob_loc => l_response | |
,pattern => CHR(10) | |
,offset => l_offset | |
); | |
/* LFがなければ終了 */ | |
exit when ( l_pos = 0 ); | |
l_amount := l_pos - l_offset; | |
/* 1行取り出す */ | |
l_line := dbms_lob.substr( | |
lob_loc => l_response | |
,amount => l_amount | |
,offset => l_offset | |
); | |
l_json := json_object_t(l_line); | |
l_generated_message := l_generated_message || l_json.get_string('response'); | |
l_is_done := l_json.get_boolean('done'); | |
if l_is_done then | |
/* context以外をSTATSとして印刷 */ | |
l_json.remove('context'); | |
:P1_STATS := l_json.to_string(); | |
end if; | |
/* 次の行を取り出す */ | |
l_offset := l_pos + 1; | |
end loop; | |
:P1_RESPONSE := l_generated_message; | |
end; |