Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
cca9edc9
Unverified
Commit
cca9edc9
authored
Jan 12, 2024
by
takatost
Committed by
GitHub
Jan 12, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: ollama support (#2003)
parent
5e75f702
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1369 additions
and
13 deletions
+1369
-13
generate_task_pipeline.py
api/core/app_runner/generate_task_pipeline.py
+26
-3
_position.yaml
api/core/model_runtime/model_providers/_position.yaml
+1
-0
localai.yaml
api/core/model_runtime/model_providers/localai/localai.yaml
+2
-2
__init__.py
api/core/model_runtime/model_providers/ollama/__init__.py
+0
-0
icon_l_en.svg
...odel_runtime/model_providers/ollama/_assets/icon_l_en.svg
+15
-0
icon_s_en.svg
...odel_runtime/model_providers/ollama/_assets/icon_s_en.svg
+15
-0
__init__.py
...core/model_runtime/model_providers/ollama/llm/__init__.py
+0
-0
llm.py
api/core/model_runtime/model_providers/ollama/llm/llm.py
+615
-0
ollama.py
api/core/model_runtime/model_providers/ollama/ollama.py
+17
-0
ollama.yaml
api/core/model_runtime/model_providers/ollama/ollama.yaml
+98
-0
__init__.py
...runtime/model_providers/ollama/text_embedding/__init__.py
+0
-0
text_embedding.py
...e/model_providers/ollama/text_embedding/text_embedding.py
+221
-0
llm.py
..._runtime/model_providers/openai_api_compatible/llm/llm.py
+1
-0
openai_api_compatible.yaml
...roviders/openai_api_compatible/openai_api_compatible.yaml
+2
-2
openllm.yaml
api/core/model_runtime/model_providers/openllm/openllm.yaml
+2
-2
xinference.yaml
.../model_runtime/model_providers/xinference/xinference.yaml
+2
-2
prompt_transform.py
api/core/prompt/prompt_transform.py
+18
-2
.env.example
api/tests/integration_tests/.env.example
+3
-0
__init__.py
api/tests/integration_tests/model_runtime/ollama/__init__.py
+0
-0
test_llm.py
api/tests/integration_tests/model_runtime/ollama/test_llm.py
+260
-0
test_text_embedding.py
...gration_tests/model_runtime/ollama/test_text_embedding.py
+71
-0
No files found.
api/core/app_runner/generate_task_pipeline.py
View file @
cca9edc9
...
...
@@ -459,10 +459,33 @@ class GenerateTaskPipeline:
"files"
:
files
})
else
:
prompts
.
append
({
prompt_message
=
prompt_messages
[
0
]
text
=
''
files
=
[]
if
isinstance
(
prompt_message
.
content
,
list
):
for
content
in
prompt_message
.
content
:
if
content
.
type
==
PromptMessageContentType
.
TEXT
:
content
=
cast
(
TextPromptMessageContent
,
content
)
text
+=
content
.
data
else
:
content
=
cast
(
ImagePromptMessageContent
,
content
)
files
.
append
({
"type"
:
'image'
,
"data"
:
content
.
data
[:
10
]
+
'...[TRUNCATED]...'
+
content
.
data
[
-
10
:],
"detail"
:
content
.
detail
.
value
})
else
:
text
=
prompt_message
.
content
params
=
{
"role"
:
'user'
,
"text"
:
prompt_messages
[
0
]
.
content
})
"text"
:
text
,
}
if
files
:
params
[
'files'
]
=
files
prompts
.
append
(
params
)
return
prompts
...
...
api/core/model_runtime/model_providers/_position.yaml
View file @
cca9edc9
...
...
@@ -6,6 +6,7 @@
-
huggingface_hub
-
cohere
-
togetherai
-
ollama
-
zhipuai
-
baichuan
-
spark
...
...
api/core/model_runtime/model_providers/localai/localai.yaml
View file @
cca9edc9
...
...
@@ -54,5 +54,5 @@ model_credential_schema:
type
:
text-input
required
:
true
placeholder
:
zh_Hans
:
在此输入LocalAI的服务器地址,如 http
s://example.com/xxx
en_US
:
Enter the url of your LocalAI,
for example https://example.com/xxx
zh_Hans
:
在此输入LocalAI的服务器地址,如 http
://192.168.1.100:8080
en_US
:
Enter the url of your LocalAI,
e.g. http://192.168.1.100:8080
api/core/model_runtime/model_providers/ollama/__init__.py
0 → 100644
View file @
cca9edc9
api/core/model_runtime/model_providers/ollama/_assets/icon_l_en.svg
0 → 100644
View file @
cca9edc9
<svg
width=
"82"
height=
"24"
viewBox=
"0 0 82 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<rect
x=
"1"
width=
"16.9688"
height=
"24"
fill=
"url(#pattern0)"
/>
<path
d=
"M71.4453 14.552C71.4453 13.6667 71.6266 12.8827 71.9893 12.2C72.3626 11.5174 72.864 10.9894 73.4933 10.616C74.1333 10.232 74.8373 10.04 75.6053 10.04C76.2986 10.04 76.9013 10.1787 77.4133 10.456C77.936 10.7227 78.352 11.0587 78.6613 11.464V10.184H80.5013V19H78.6613V17.688C78.352 18.104 77.9306 18.4507 77.3973 18.728C76.864 19.0054 76.256 19.144 75.5733 19.144C74.816 19.144 74.1226 18.952 73.4933 18.568C72.864 18.1734 72.3626 17.6294 71.9893 16.936C71.6266 16.232 71.4453 15.4374 71.4453 14.552ZM78.6613 14.584C78.6613 13.976 78.5333 13.448 78.2773 13C78.032 12.552 77.7066 12.2107 77.3013 11.976C76.896 11.7414 76.4586 11.624 75.9893 11.624C75.52 11.624 75.0826 11.7414 74.6773 11.976C74.272 12.2 73.9413 12.536 73.6853 12.984C73.44 13.4214 73.3173 13.944 73.3173 14.552C73.3173 15.16 73.44 15.6934 73.6853 16.152C73.9413 16.6107 74.272 16.9627 74.6773 17.208C75.0933 17.4427 75.5306 17.56 75.9893 17.56C76.4586 17.56 76.896 17.4427 77.3013 17.208C77.7066 16.9734 78.032 16.632 78.2773 16.184C78.5333 15.7254 78.6613 15.192 78.6613 14.584Z"
fill=
"black"
/>
<path
d=
"M66.42 10.04C67.1134 10.04 67.732 10.184 68.276 10.472C68.8307 10.76 69.2627 11.1867 69.572 11.752C69.892 12.3174 70.052 13 70.052 13.8V19H68.244V14.072C68.244 13.2827 68.0467 12.68 67.652 12.264C67.2574 11.8374 66.7187 11.624 66.036 11.624C65.3534 11.624 64.8094 11.8374 64.404 12.264C64.0094 12.68 63.812 13.2827 63.812 14.072V19H62.004V14.072C62.004 13.2827 61.8067 12.68 61.412 12.264C61.0174 11.8374 60.4787 11.624 59.796 11.624C59.1134 11.624 58.5694 11.8374 58.164 12.264C57.7694 12.68 57.572 13.2827 57.572 14.072V19H55.748V10.184H57.572V11.192C57.8707 10.8294 58.2494 10.5467 58.708 10.344C59.1667 10.1414 59.6574 10.04 60.18 10.04C60.884 10.04 61.5134 10.1894 62.068 10.488C62.6227 10.7867 63.0494 11.2187 63.348 11.784C63.6147 11.2507 64.0307 10.8294 64.596 10.52C65.1614 10.2 65.7694 10.04 66.42 10.04Z"
fill=
"black"
/>
<path
d=
"M44.6152 14.552C44.6152 13.6667 44.7966 12.8827 45.1592 12.2C45.5326 11.5174 46.0339 10.9894 46.6632 10.616C47.3032 10.232 48.0072 10.04 48.7752 10.04C49.4686 10.04 50.0712 10.1787 50.5832 10.456C51.1059 10.7227 51.5219 11.0587 51.8312 11.464V10.184H53.6712V19H51.8312V17.688C51.5219 18.104 51.1006 18.4507 50.5672 18.728C50.0339 19.0054 49.4259 19.144 48.7432 19.144C47.9859 19.144 47.2926 18.952 46.6632 18.568C46.0339 18.1734 45.5326 17.6294 45.1592 16.936C44.7966 16.232 44.6152 15.4374 44.6152 14.552ZM51.8312 14.584C51.8312 13.976 51.7032 13.448 51.4472 13C51.2019 12.552 50.8766 12.2107 50.4712 11.976C50.0659 11.7414 49.6286 11.624 49.1592 11.624C48.6899 11.624 48.2526 11.7414 47.8472 11.976C47.4419 12.2 47.1112 12.536 46.8552 12.984C46.6099 13.4214 46.4872 13.944 46.4872 14.552C46.4872 15.16 46.6099 15.6934 46.8552 16.152C47.1112 16.6107 47.4419 16.9627 47.8472 17.208C48.2632 17.4427 48.7006 17.56 49.1592 17.56C49.6286 17.56 50.0659 17.4427 50.4712 17.208C50.8766 16.9734 51.2019 16.632 51.4472 16.184C51.7032 15.7254 51.8312 15.192 51.8312 14.584Z"
fill=
"black"
/>
<path
d=
"M43.1502 7.16016V19.0002H41.3262V7.16016H43.1502Z"
fill=
"black"
/>
<path
d=
"M39.2498 7.16016V19.0002H37.4258V7.16016H39.2498Z"
fill=
"black"
/>
<path
d=
"M30.2718 19.1123C29.2371 19.1123 28.2825 18.8723 27.4078 18.3923C26.5438 17.9017 25.8558 17.2243 25.3438 16.3603C24.8425 15.4857 24.5918 14.5043 24.5918 13.4163C24.5918 12.3283 24.8425 11.3523 25.3438 10.4883C25.8558 9.62433 26.5438 8.95233 27.4078 8.47233C28.2825 7.98166 29.2371 7.73633 30.2718 7.73633C31.3171 7.73633 32.2718 7.98166 33.1358 8.47233C34.0105 8.95233 34.6985 9.62433 35.1998 10.4883C35.7011 11.3523 35.9518 12.3283 35.9518 13.4163C35.9518 14.5043 35.7011 15.4857 35.1998 16.3603C34.6985 17.2243 34.0105 17.9017 33.1358 18.3923C32.2718 18.8723 31.3171 19.1123 30.2718 19.1123ZM30.2718 17.5283C31.0078 17.5283 31.6638 17.363 32.2398 17.0323C32.8158 16.691 33.2638 16.211 33.5838 15.5923C33.9145 14.963 34.0798 14.2377 34.0798 13.4163C34.0798 12.595 33.9145 11.875 33.5838 11.2563C33.2638 10.6377 32.8158 10.163 32.2398 9.83233C31.6638 9.50166 31.0078 9.33633 30.2718 9.33633C29.5358 9.33633 28.8798 9.50166 28.3038 9.83233C27.7278 10.163 27.2745 10.6377 26.9438 11.2563C26.6238 11.875 26.4638 12.595 26.4638 13.4163C26.4638 14.2377 26.6238 14.963 26.9438 15.5923C27.2745 16.211 27.7278 16.691 28.3038 17.0323C28.8798 17.363 29.5358 17.5283 30.2718 17.5283Z"
fill=
"black"
/>
<defs>
<pattern
id=
"pattern0"
patternContentUnits=
"objectBoundingBox"
width=
"1"
height=
"1"
>
<use
xlink:href=
"#image0_16324_59298"
transform=
"scale(0.00552486 0.00390625)"
/>
</pattern>
<image
id=
"image0_16324_59298"
width=
"181"
height=
"256"
xlink:href=
"data:image/png;base64,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"
/>
</defs>
</svg>
api/core/model_runtime/model_providers/ollama/_assets/icon_s_en.svg
0 → 100644
View file @
cca9edc9
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<g
clip-path=
"url(#clip0_16325_59237)"
>
<rect
width=
"24"
height=
"24"
rx=
"5"
fill=
"white"
/>
<rect
x=
"3.5"
width=
"17"
height=
"24"
fill=
"url(#pattern0)"
/>
</g>
<defs>
<pattern
id=
"pattern0"
patternContentUnits=
"objectBoundingBox"
width=
"1"
height=
"1"
>
<use
xlink:href=
"#image0_16325_59237"
transform=
"matrix(0.00552486 0 0 0.00391344 0 -0.00092081)"
/>
</pattern>
<clipPath
id=
"clip0_16325_59237"
>
<rect
width=
"24"
height=
"24"
fill=
"white"
/>
</clipPath>
<image
id=
"image0_16325_59237"
width=
"181"
height=
"256"
xlink:href=
"data:image/png;base64,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"
/>
</defs>
</svg>
api/core/model_runtime/model_providers/ollama/llm/__init__.py
0 → 100644
View file @
cca9edc9
api/core/model_runtime/model_providers/ollama/llm/llm.py
0 → 100644
View file @
cca9edc9
import
json
import
logging
import
re
from
decimal
import
Decimal
from
typing
import
Optional
,
Generator
,
Union
,
List
,
cast
from
urllib.parse
import
urljoin
import
requests
from
core.model_runtime.entities.message_entities
import
PromptMessageTool
,
PromptMessage
,
AssistantPromptMessage
,
\
UserPromptMessage
,
PromptMessageContentType
,
ImagePromptMessageContent
,
\
TextPromptMessageContent
,
SystemPromptMessage
from
core.model_runtime.entities.model_entities
import
I18nObject
,
ModelType
,
\
PriceConfig
,
AIModelEntity
,
FetchFrom
,
ModelPropertyKey
,
ParameterRule
,
ParameterType
,
DefaultParameterName
,
\
ModelFeature
from
core.model_runtime.entities.llm_entities
import
LLMMode
,
LLMResult
,
\
LLMResultChunk
,
LLMResultChunkDelta
from
core.model_runtime.errors.invoke
import
InvokeError
,
InvokeAuthorizationError
,
InvokeBadRequestError
,
\
InvokeRateLimitError
,
InvokeServerUnavailableError
,
InvokeConnectionError
from
core.model_runtime.errors.validate
import
CredentialsValidateFailedError
from
core.model_runtime.model_providers.__base.large_language_model
import
LargeLanguageModel
logger
=
logging
.
getLogger
(
__name__
)
class
OllamaLargeLanguageModel
(
LargeLanguageModel
):
"""
Model class for Ollama large language model.
"""
def
_invoke
(
self
,
model
:
str
,
credentials
:
dict
,
prompt_messages
:
list
[
PromptMessage
],
model_parameters
:
dict
,
tools
:
Optional
[
list
[
PromptMessageTool
]]
=
None
,
stop
:
Optional
[
List
[
str
]]
=
None
,
stream
:
bool
=
True
,
user
:
Optional
[
str
]
=
None
)
\
->
Union
[
LLMResult
,
Generator
]:
"""
Invoke large language model
:param model: model name
:param credentials: model credentials
:param prompt_messages: prompt messages
:param model_parameters: model parameters
:param tools: tools for tool calling
:param stop: stop words
:param stream: is stream response
:param user: unique user id
:return: full response or stream response chunk generator result
"""
return
self
.
_generate
(
model
=
model
,
credentials
=
credentials
,
prompt_messages
=
prompt_messages
,
model_parameters
=
model_parameters
,
stop
=
stop
,
stream
=
stream
,
user
=
user
)
def
get_num_tokens
(
self
,
model
:
str
,
credentials
:
dict
,
prompt_messages
:
list
[
PromptMessage
],
tools
:
Optional
[
list
[
PromptMessageTool
]]
=
None
)
->
int
:
"""
Get number of tokens for given prompt messages
:param model: model name
:param credentials: model credentials
:param prompt_messages: prompt messages
:param tools: tools for tool calling
:return:
"""
# get model mode
model_mode
=
self
.
get_model_mode
(
model
,
credentials
)
if
model_mode
==
LLMMode
.
CHAT
:
# chat model
return
self
.
_num_tokens_from_messages
(
prompt_messages
)
else
:
first_prompt_message
=
prompt_messages
[
0
]
if
isinstance
(
first_prompt_message
.
content
,
str
):
text
=
first_prompt_message
.
content
else
:
text
=
''
for
message_content
in
first_prompt_message
.
content
:
if
message_content
.
type
==
PromptMessageContentType
.
TEXT
:
message_content
=
cast
(
TextPromptMessageContent
,
message_content
)
text
=
message_content
.
data
break
return
self
.
_get_num_tokens_by_gpt2
(
text
)
def
validate_credentials
(
self
,
model
:
str
,
credentials
:
dict
)
->
None
:
"""
Validate model credentials
:param model: model name
:param credentials: model credentials
:return:
"""
try
:
self
.
_generate
(
model
=
model
,
credentials
=
credentials
,
prompt_messages
=
[
UserPromptMessage
(
content
=
"ping"
)],
model_parameters
=
{
'num_predict'
:
5
},
stream
=
False
)
except
InvokeError
as
ex
:
raise
CredentialsValidateFailedError
(
f
'An error occurred during credentials validation: {ex.description}'
)
except
Exception
as
ex
:
raise
CredentialsValidateFailedError
(
f
'An error occurred during credentials validation: {str(ex)}'
)
def
_generate
(
self
,
model
:
str
,
credentials
:
dict
,
prompt_messages
:
list
[
PromptMessage
],
model_parameters
:
dict
,
stop
:
Optional
[
List
[
str
]]
=
None
,
stream
:
bool
=
True
,
user
:
Optional
[
str
]
=
None
)
->
Union
[
LLMResult
,
Generator
]:
"""
Invoke llm completion model
:param model: model name
:param credentials: credentials
:param prompt_messages: prompt messages
:param model_parameters: model parameters
:param stop: stop words
:param stream: is stream response
:param user: unique user id
:return: full response or stream response chunk generator result
"""
headers
=
{
'Content-Type'
:
'application/json'
}
endpoint_url
=
credentials
[
'base_url'
]
if
not
endpoint_url
.
endswith
(
'/'
):
endpoint_url
+=
'/'
# prepare the payload for a simple ping to the model
data
=
{
'model'
:
model
,
'stream'
:
stream
}
if
'format'
in
model_parameters
:
data
[
'format'
]
=
model_parameters
[
'format'
]
del
model_parameters
[
'format'
]
data
[
'options'
]
=
model_parameters
or
{}
if
stop
:
data
[
'stop'
]
=
"
\n
"
.
join
(
stop
)
completion_type
=
LLMMode
.
value_of
(
credentials
[
'mode'
])
if
completion_type
is
LLMMode
.
CHAT
:
endpoint_url
=
urljoin
(
endpoint_url
,
'api/chat'
)
data
[
'messages'
]
=
[
self
.
_convert_prompt_message_to_dict
(
m
)
for
m
in
prompt_messages
]
else
:
endpoint_url
=
urljoin
(
endpoint_url
,
'api/generate'
)
first_prompt_message
=
prompt_messages
[
0
]
if
isinstance
(
first_prompt_message
,
UserPromptMessage
):
first_prompt_message
=
cast
(
UserPromptMessage
,
first_prompt_message
)
if
isinstance
(
first_prompt_message
.
content
,
str
):
data
[
'prompt'
]
=
first_prompt_message
.
content
else
:
text
=
''
images
=
[]
for
message_content
in
first_prompt_message
.
content
:
if
message_content
.
type
==
PromptMessageContentType
.
TEXT
:
message_content
=
cast
(
TextPromptMessageContent
,
message_content
)
text
=
message_content
.
data
elif
message_content
.
type
==
PromptMessageContentType
.
IMAGE
:
message_content
=
cast
(
ImagePromptMessageContent
,
message_content
)
image_data
=
re
.
sub
(
r'^data:image\/[a-zA-Z]+;base64,'
,
''
,
message_content
.
data
)
images
.
append
(
image_data
)
data
[
'prompt'
]
=
text
data
[
'images'
]
=
images
# send a post request to validate the credentials
response
=
requests
.
post
(
endpoint_url
,
headers
=
headers
,
json
=
data
,
timeout
=
(
10
,
60
),
stream
=
stream
)
response
.
encoding
=
"utf-8"
if
response
.
status_code
!=
200
:
raise
InvokeError
(
f
"API request failed with status code {response.status_code}: {response.text}"
)
if
stream
:
return
self
.
_handle_generate_stream_response
(
model
,
credentials
,
completion_type
,
response
,
prompt_messages
)
return
self
.
_handle_generate_response
(
model
,
credentials
,
completion_type
,
response
,
prompt_messages
)
def
_handle_generate_response
(
self
,
model
:
str
,
credentials
:
dict
,
completion_type
:
LLMMode
,
response
:
requests
.
Response
,
prompt_messages
:
list
[
PromptMessage
])
->
LLMResult
:
"""
Handle llm completion response
:param model: model name
:param credentials: model credentials
:param completion_type: completion type
:param response: response
:param prompt_messages: prompt messages
:return: llm result
"""
response_json
=
response
.
json
()
if
completion_type
is
LLMMode
.
CHAT
:
message
=
response_json
.
get
(
'message'
,
{})
response_content
=
message
.
get
(
'content'
,
''
)
else
:
response_content
=
response_json
[
'response'
]
assistant_message
=
AssistantPromptMessage
(
content
=
response_content
)
if
'prompt_eval_count'
in
response_json
and
'eval_count'
in
response_json
:
# transform usage
prompt_tokens
=
response_json
[
"prompt_eval_count"
]
completion_tokens
=
response_json
[
"eval_count"
]
else
:
# calculate num tokens
prompt_tokens
=
self
.
_get_num_tokens_by_gpt2
(
prompt_messages
[
0
]
.
content
)
completion_tokens
=
self
.
_get_num_tokens_by_gpt2
(
assistant_message
.
content
)
# transform usage
usage
=
self
.
_calc_response_usage
(
model
,
credentials
,
prompt_tokens
,
completion_tokens
)
# transform response
result
=
LLMResult
(
model
=
response_json
[
"model"
],
prompt_messages
=
prompt_messages
,
message
=
assistant_message
,
usage
=
usage
,
)
return
result
def
_handle_generate_stream_response
(
self
,
model
:
str
,
credentials
:
dict
,
completion_type
:
LLMMode
,
response
:
requests
.
Response
,
prompt_messages
:
list
[
PromptMessage
])
->
Generator
:
"""
Handle llm completion stream response
:param model: model name
:param credentials: model credentials
:param completion_type: completion type
:param response: response
:param prompt_messages: prompt messages
:return: llm response chunk generator result
"""
full_text
=
''
chunk_index
=
0
def
create_final_llm_result_chunk
(
index
:
int
,
message
:
AssistantPromptMessage
,
finish_reason
:
str
)
\
->
LLMResultChunk
:
# calculate num tokens
prompt_tokens
=
self
.
_get_num_tokens_by_gpt2
(
prompt_messages
[
0
]
.
content
)
completion_tokens
=
self
.
_get_num_tokens_by_gpt2
(
full_text
)
# transform usage
usage
=
self
.
_calc_response_usage
(
model
,
credentials
,
prompt_tokens
,
completion_tokens
)
return
LLMResultChunk
(
model
=
model
,
prompt_messages
=
prompt_messages
,
delta
=
LLMResultChunkDelta
(
index
=
index
,
message
=
message
,
finish_reason
=
finish_reason
,
usage
=
usage
)
)
for
chunk
in
response
.
iter_lines
(
decode_unicode
=
True
,
delimiter
=
'
\n
'
):
if
not
chunk
:
continue
try
:
chunk_json
=
json
.
loads
(
chunk
)
# stream ended
except
json
.
JSONDecodeError
as
e
:
yield
create_final_llm_result_chunk
(
index
=
chunk_index
,
message
=
AssistantPromptMessage
(
content
=
""
),
finish_reason
=
"Non-JSON encountered."
)
chunk_index
+=
1
break
if
completion_type
is
LLMMode
.
CHAT
:
if
not
chunk_json
:
continue
if
'message'
not
in
chunk_json
:
text
=
''
else
:
text
=
chunk_json
.
get
(
'message'
)
.
get
(
'content'
,
''
)
else
:
if
not
chunk_json
:
continue
# transform assistant message to prompt message
text
=
chunk_json
[
'response'
]
assistant_prompt_message
=
AssistantPromptMessage
(
content
=
text
)
full_text
+=
text
if
chunk_json
[
'done'
]:
# calculate num tokens
if
'prompt_eval_count'
in
chunk_json
and
'eval_count'
in
chunk_json
:
# transform usage
prompt_tokens
=
chunk_json
[
"prompt_eval_count"
]
completion_tokens
=
chunk_json
[
"eval_count"
]
else
:
# calculate num tokens
prompt_tokens
=
self
.
_get_num_tokens_by_gpt2
(
prompt_messages
[
0
]
.
content
)
completion_tokens
=
self
.
_get_num_tokens_by_gpt2
(
full_text
)
# transform usage
usage
=
self
.
_calc_response_usage
(
model
,
credentials
,
prompt_tokens
,
completion_tokens
)
yield
LLMResultChunk
(
model
=
chunk_json
[
'model'
],
prompt_messages
=
prompt_messages
,
delta
=
LLMResultChunkDelta
(
index
=
chunk_index
,
message
=
assistant_prompt_message
,
finish_reason
=
'stop'
,
usage
=
usage
)
)
else
:
yield
LLMResultChunk
(
model
=
chunk_json
[
'model'
],
prompt_messages
=
prompt_messages
,
delta
=
LLMResultChunkDelta
(
index
=
chunk_index
,
message
=
assistant_prompt_message
,
)
)
chunk_index
+=
1
def
_convert_prompt_message_to_dict
(
self
,
message
:
PromptMessage
)
->
dict
:
"""
Convert PromptMessage to dict for Ollama API
"""
if
isinstance
(
message
,
UserPromptMessage
):
message
=
cast
(
UserPromptMessage
,
message
)
if
isinstance
(
message
.
content
,
str
):
message_dict
=
{
"role"
:
"user"
,
"content"
:
message
.
content
}
else
:
text
=
''
images
=
[]
for
message_content
in
message
.
content
:
if
message_content
.
type
==
PromptMessageContentType
.
TEXT
:
message_content
=
cast
(
TextPromptMessageContent
,
message_content
)
text
=
message_content
.
data
elif
message_content
.
type
==
PromptMessageContentType
.
IMAGE
:
message_content
=
cast
(
ImagePromptMessageContent
,
message_content
)
image_data
=
re
.
sub
(
r'^data:image\/[a-zA-Z]+;base64,'
,
''
,
message_content
.
data
)
images
.
append
(
image_data
)
message_dict
=
{
"role"
:
"user"
,
"content"
:
text
,
"images"
:
images
}
elif
isinstance
(
message
,
AssistantPromptMessage
):
message
=
cast
(
AssistantPromptMessage
,
message
)
message_dict
=
{
"role"
:
"assistant"
,
"content"
:
message
.
content
}
elif
isinstance
(
message
,
SystemPromptMessage
):
message
=
cast
(
SystemPromptMessage
,
message
)
message_dict
=
{
"role"
:
"system"
,
"content"
:
message
.
content
}
else
:
raise
ValueError
(
f
"Got unknown type {message}"
)
return
message_dict
def
_num_tokens_from_messages
(
self
,
messages
:
List
[
PromptMessage
])
->
int
:
"""
Calculate num tokens.
:param messages: messages
"""
num_tokens
=
0
messages_dict
=
[
self
.
_convert_prompt_message_to_dict
(
m
)
for
m
in
messages
]
for
message
in
messages_dict
:
for
key
,
value
in
message
.
items
():
num_tokens
+=
self
.
_get_num_tokens_by_gpt2
(
str
(
key
))
num_tokens
+=
self
.
_get_num_tokens_by_gpt2
(
str
(
value
))
return
num_tokens
def
get_customizable_model_schema
(
self
,
model
:
str
,
credentials
:
dict
)
->
AIModelEntity
:
"""
Get customizable model schema.
:param model: model name
:param credentials: credentials
:return: model schema
"""
extras
=
{}
if
'vision_support'
in
credentials
and
credentials
[
'vision_support'
]
==
'true'
:
extras
[
'features'
]
=
[
ModelFeature
.
VISION
]
entity
=
AIModelEntity
(
model
=
model
,
label
=
I18nObject
(
zh_Hans
=
model
,
en_US
=
model
),
model_type
=
ModelType
.
LLM
,
fetch_from
=
FetchFrom
.
CUSTOMIZABLE_MODEL
,
model_properties
=
{
ModelPropertyKey
.
MODE
:
credentials
.
get
(
'mode'
),
ModelPropertyKey
.
CONTEXT_SIZE
:
int
(
credentials
.
get
(
'context_size'
,
4096
)),
},
parameter_rules
=
[
ParameterRule
(
name
=
DefaultParameterName
.
TEMPERATURE
.
value
,
use_template
=
DefaultParameterName
.
TEMPERATURE
.
value
,
label
=
I18nObject
(
en_US
=
"Temperature"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"The temperature of the model. "
"Increasing the temperature will make the model answer "
"more creatively. (Default: 0.8)"
),
default
=
0.8
,
min
=
0
,
max
=
2
),
ParameterRule
(
name
=
DefaultParameterName
.
TOP_P
.
value
,
use_template
=
DefaultParameterName
.
TOP_P
.
value
,
label
=
I18nObject
(
en_US
=
"Top P"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"Works together with top-k. A higher value (e.g., 0.95) will lead to "
"more diverse text, while a lower value (e.g., 0.5) will generate more "
"focused and conservative text. (Default: 0.9)"
),
default
=
0.9
,
min
=
0
,
max
=
1
),
ParameterRule
(
name
=
"top_k"
,
label
=
I18nObject
(
en_US
=
"Top K"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Reduces the probability of generating nonsense. "
"A higher value (e.g. 100) will give more diverse answers, "
"while a lower value (e.g. 10) will be more conservative. (Default: 40)"
),
default
=
40
,
min
=
1
,
max
=
100
),
ParameterRule
(
name
=
'repeat_penalty'
,
label
=
I18nObject
(
en_US
=
"Repeat Penalty"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"Sets how strongly to penalize repetitions. "
"A higher value (e.g., 1.5) will penalize repetitions more strongly, "
"while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1)"
),
default
=
1.1
,
min
=-
2
,
max
=
2
),
ParameterRule
(
name
=
'num_predict'
,
use_template
=
'max_tokens'
,
label
=
I18nObject
(
en_US
=
"Num Predict"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Maximum number of tokens to predict when generating text. "
"(Default: 128, -1 = infinite generation, -2 = fill context)"
),
default
=
128
,
min
=-
2
,
max
=
int
(
credentials
.
get
(
'max_tokens'
,
4096
)),
),
ParameterRule
(
name
=
'mirostat'
,
label
=
I18nObject
(
en_US
=
"Mirostat sampling"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Enable Mirostat sampling for controlling perplexity. "
"(default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0)"
),
default
=
0
,
min
=
0
,
max
=
2
),
ParameterRule
(
name
=
'mirostat_eta'
,
label
=
I18nObject
(
en_US
=
"Mirostat Eta"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"Influences how quickly the algorithm responds to feedback from "
"the generated text. A lower learning rate will result in slower adjustments, "
"while a higher learning rate will make the algorithm more responsive. "
"(Default: 0.1)"
),
default
=
0.1
,
precision
=
1
),
ParameterRule
(
name
=
'mirostat_tau'
,
label
=
I18nObject
(
en_US
=
"Mirostat Tau"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"Controls the balance between coherence and diversity of the output. "
"A lower value will result in more focused and coherent text. (Default: 5.0)"
),
default
=
5.0
,
precision
=
1
),
ParameterRule
(
name
=
'num_ctx'
,
label
=
I18nObject
(
en_US
=
"Size of context window"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Sets the size of the context window used to generate the next token. "
"(Default: 2048)"
),
default
=
2048
,
min
=
1
),
ParameterRule
(
name
=
'num_gpu'
,
label
=
I18nObject
(
en_US
=
"Num GPU"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"The number of layers to send to the GPU(s). "
"On macOS it defaults to 1 to enable metal support, 0 to disable."
),
default
=
1
,
min
=
0
,
max
=
1
),
ParameterRule
(
name
=
'num_thread'
,
label
=
I18nObject
(
en_US
=
"Num Thread"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Sets the number of threads to use during computation. "
"By default, Ollama will detect this for optimal performance. "
"It is recommended to set this value to the number of physical CPU cores "
"your system has (as opposed to the logical number of cores)."
),
min
=
1
,
),
ParameterRule
(
name
=
'repeat_last_n'
,
label
=
I18nObject
(
en_US
=
"Repeat last N"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Sets how far back for the model to look back to prevent repetition. "
"(Default: 64, 0 = disabled, -1 = num_ctx)"
),
default
=
64
,
min
=-
1
),
ParameterRule
(
name
=
'tfs_z'
,
label
=
I18nObject
(
en_US
=
"TFS Z"
),
type
=
ParameterType
.
FLOAT
,
help
=
I18nObject
(
en_US
=
"Tail free sampling is used to reduce the impact of less probable tokens "
"from the output. A higher value (e.g., 2.0) will reduce the impact more, "
"while a value of 1.0 disables this setting. (default: 1)"
),
default
=
1
,
precision
=
1
),
ParameterRule
(
name
=
'seed'
,
label
=
I18nObject
(
en_US
=
"Seed"
),
type
=
ParameterType
.
INT
,
help
=
I18nObject
(
en_US
=
"Sets the random number seed to use for generation. Setting this to "
"a specific number will make the model generate the same text for "
"the same prompt. (Default: 0)"
),
default
=
0
),
ParameterRule
(
name
=
'format'
,
label
=
I18nObject
(
en_US
=
"Format"
),
type
=
ParameterType
.
STRING
,
help
=
I18nObject
(
en_US
=
"the format to return a response in."
" Currently the only accepted value is json."
),
options
=
[
'json'
],
)
],
pricing
=
PriceConfig
(
input
=
Decimal
(
credentials
.
get
(
'input_price'
,
0
)),
output
=
Decimal
(
credentials
.
get
(
'output_price'
,
0
)),
unit
=
Decimal
(
credentials
.
get
(
'unit'
,
0
)),
currency
=
credentials
.
get
(
'currency'
,
"USD"
)
),
**
extras
)
return
entity
@
property
def
_invoke_error_mapping
(
self
)
->
dict
[
type
[
InvokeError
],
list
[
type
[
Exception
]]]:
"""
Map model invoke error to unified error
The key is the error type thrown to the caller
The value is the error type thrown by the model,
which needs to be converted into a unified error type for the caller.
:return: Invoke error mapping
"""
return
{
InvokeAuthorizationError
:
[
requests
.
exceptions
.
InvalidHeader
,
# Missing or Invalid API Key
],
InvokeBadRequestError
:
[
requests
.
exceptions
.
HTTPError
,
# Invalid Endpoint URL or model name
requests
.
exceptions
.
InvalidURL
,
# Misconfigured request or other API error
],
InvokeRateLimitError
:
[
requests
.
exceptions
.
RetryError
# Too many requests sent in a short period of time
],
InvokeServerUnavailableError
:
[
requests
.
exceptions
.
ConnectionError
,
# Engine Overloaded
requests
.
exceptions
.
HTTPError
# Server Error
],
InvokeConnectionError
:
[
requests
.
exceptions
.
ConnectTimeout
,
# Timeout
requests
.
exceptions
.
ReadTimeout
# Timeout
]
}
api/core/model_runtime/model_providers/ollama/ollama.py
0 → 100644
View file @
cca9edc9
import
logging
from
core.model_runtime.model_providers.__base.model_provider
import
ModelProvider
logger
=
logging
.
getLogger
(
__name__
)
class
OpenAIProvider
(
ModelProvider
):
def
validate_provider_credentials
(
self
,
credentials
:
dict
)
->
None
:
"""
Validate provider credentials
if validate failed, raise exception
:param credentials: provider credentials, credentials form defined in `provider_credential_schema`.
"""
pass
api/core/model_runtime/model_providers/ollama/ollama.yaml
0 → 100644
View file @
cca9edc9
provider
:
ollama
label
:
en_US
:
Ollama
icon_large
:
en_US
:
icon_l_en.svg
icon_small
:
en_US
:
icon_s_en.svg
background
:
"
#F9FAFB"
help
:
title
:
en_US
:
How to integrate with Ollama
zh_Hans
:
如何集成 Ollama
url
:
en_US
:
https://docs.dify.ai/advanced/model-configuration/ollama
supported_model_types
:
-
llm
-
text-embedding
configurate_methods
:
-
customizable-model
model_credential_schema
:
model
:
label
:
en_US
:
Model Name
zh_Hans
:
模型名称
placeholder
:
en_US
:
Enter your model name
zh_Hans
:
输入模型名称
credential_form_schemas
:
-
variable
:
base_url
label
:
zh_Hans
:
基础 URL
en_US
:
Base URL
type
:
text-input
required
:
true
placeholder
:
zh_Hans
:
Ollama server 的基础 URL,例如 http://192.168.1.100:11434
en_US
:
Base url of Ollama server, e.g. http://192.168.1.100:11434
-
variable
:
mode
show_on
:
-
variable
:
__model_type
value
:
llm
label
:
zh_Hans
:
模型类型
en_US
:
Completion mode
type
:
select
required
:
true
default
:
chat
placeholder
:
zh_Hans
:
选择对话类型
en_US
:
Select completion mode
options
:
-
value
:
completion
label
:
en_US
:
Completion
zh_Hans
:
补全
-
value
:
chat
label
:
en_US
:
Chat
zh_Hans
:
对话
-
variable
:
context_size
label
:
zh_Hans
:
模型上下文长度
en_US
:
Model context size
required
:
true
type
:
text-input
default
:
'
4096'
placeholder
:
zh_Hans
:
在此输入您的模型上下文长度
en_US
:
Enter your Model context size
-
variable
:
max_tokens
label
:
zh_Hans
:
最大 token 上限
en_US
:
Upper bound for max tokens
show_on
:
-
variable
:
__model_type
value
:
llm
default
:
'
4096'
type
:
text-input
required
:
true
-
variable
:
vision_support
label
:
zh_Hans
:
是否支持 Vision
en_US
:
Vision support
show_on
:
-
variable
:
__model_type
value
:
llm
default
:
'
false'
type
:
radio
required
:
false
options
:
-
value
:
'
true'
label
:
en_US
:
Yes
zh_Hans
:
是
-
value
:
'
false'
label
:
en_US
:
No
zh_Hans
:
否
api/core/model_runtime/model_providers/ollama/text_embedding/__init__.py
0 → 100644
View file @
cca9edc9
api/core/model_runtime/model_providers/ollama/text_embedding/text_embedding.py
0 → 100644
View file @
cca9edc9
import
logging
import
time
from
decimal
import
Decimal
from
typing
import
Optional
from
urllib.parse
import
urljoin
import
requests
import
json
import
numpy
as
np
from
core.model_runtime.entities.common_entities
import
I18nObject
from
core.model_runtime.entities.model_entities
import
PriceType
,
ModelPropertyKey
,
ModelType
,
AIModelEntity
,
FetchFrom
,
\
PriceConfig
from
core.model_runtime.entities.text_embedding_entities
import
TextEmbeddingResult
,
EmbeddingUsage
from
core.model_runtime.errors.invoke
import
InvokeError
,
InvokeAuthorizationError
,
InvokeBadRequestError
,
\
InvokeRateLimitError
,
InvokeServerUnavailableError
,
InvokeConnectionError
from
core.model_runtime.errors.validate
import
CredentialsValidateFailedError
from
core.model_runtime.model_providers.__base.text_embedding_model
import
TextEmbeddingModel
logger
=
logging
.
getLogger
(
__name__
)
class
OllamaEmbeddingModel
(
TextEmbeddingModel
):
"""
Model class for an Ollama text embedding model.
"""
def
_invoke
(
self
,
model
:
str
,
credentials
:
dict
,
texts
:
list
[
str
],
user
:
Optional
[
str
]
=
None
)
\
->
TextEmbeddingResult
:
"""
Invoke text embedding model
:param model: model name
:param credentials: model credentials
:param texts: texts to embed
:param user: unique user id
:return: embeddings result
"""
# Prepare headers and payload for the request
headers
=
{
'Content-Type'
:
'application/json'
}
endpoint_url
=
credentials
.
get
(
'base_url'
)
if
not
endpoint_url
.
endswith
(
'/'
):
endpoint_url
+=
'/'
endpoint_url
=
urljoin
(
endpoint_url
,
'api/embeddings'
)
# get model properties
context_size
=
self
.
_get_context_size
(
model
,
credentials
)
inputs
=
[]
used_tokens
=
0
for
i
,
text
in
enumerate
(
texts
):
# Here token count is only an approximation based on the GPT2 tokenizer
num_tokens
=
self
.
_get_num_tokens_by_gpt2
(
text
)
if
num_tokens
>=
context_size
:
cutoff
=
int
(
len
(
text
)
*
(
np
.
floor
(
context_size
/
num_tokens
)))
# if num tokens is larger than context length, only use the start
inputs
.
append
(
text
[
0
:
cutoff
])
else
:
inputs
.
append
(
text
)
batched_embeddings
=
[]
for
text
in
inputs
:
# Prepare the payload for the request
payload
=
{
'prompt'
:
text
,
'model'
:
model
,
}
# Make the request to the OpenAI API
response
=
requests
.
post
(
endpoint_url
,
headers
=
headers
,
data
=
json
.
dumps
(
payload
),
timeout
=
(
10
,
300
)
)
response
.
raise_for_status
()
# Raise an exception for HTTP errors
response_data
=
response
.
json
()
# Extract embeddings and used tokens from the response
embeddings
=
response_data
[
'embedding'
]
embedding_used_tokens
=
self
.
get_num_tokens
(
model
,
credentials
,
[
text
])
used_tokens
+=
embedding_used_tokens
batched_embeddings
.
append
(
embeddings
)
# calc usage
usage
=
self
.
_calc_response_usage
(
model
=
model
,
credentials
=
credentials
,
tokens
=
used_tokens
)
return
TextEmbeddingResult
(
embeddings
=
batched_embeddings
,
usage
=
usage
,
model
=
model
)
def
get_num_tokens
(
self
,
model
:
str
,
credentials
:
dict
,
texts
:
list
[
str
])
->
int
:
"""
Approximate number of tokens for given messages using GPT2 tokenizer
:param model: model name
:param credentials: model credentials
:param texts: texts to embed
:return:
"""
return
sum
(
self
.
_get_num_tokens_by_gpt2
(
text
)
for
text
in
texts
)
def
validate_credentials
(
self
,
model
:
str
,
credentials
:
dict
)
->
None
:
"""
Validate model credentials
:param model: model name
:param credentials: model credentials
:return:
"""
try
:
self
.
_invoke
(
model
=
model
,
credentials
=
credentials
,
texts
=
[
'ping'
]
)
except
InvokeError
as
ex
:
raise
CredentialsValidateFailedError
(
f
'An error occurred during credentials validation: {ex.description}'
)
except
Exception
as
ex
:
raise
CredentialsValidateFailedError
(
f
'An error occurred during credentials validation: {str(ex)}'
)
def
get_customizable_model_schema
(
self
,
model
:
str
,
credentials
:
dict
)
->
AIModelEntity
:
"""
generate custom model entities from credentials
"""
entity
=
AIModelEntity
(
model
=
model
,
label
=
I18nObject
(
en_US
=
model
),
model_type
=
ModelType
.
TEXT_EMBEDDING
,
fetch_from
=
FetchFrom
.
CUSTOMIZABLE_MODEL
,
model_properties
=
{
ModelPropertyKey
.
CONTEXT_SIZE
:
int
(
credentials
.
get
(
'context_size'
)),
ModelPropertyKey
.
MAX_CHUNKS
:
1
,
},
parameter_rules
=
[],
pricing
=
PriceConfig
(
input
=
Decimal
(
credentials
.
get
(
'input_price'
,
0
)),
unit
=
Decimal
(
credentials
.
get
(
'unit'
,
0
)),
currency
=
credentials
.
get
(
'currency'
,
"USD"
)
)
)
return
entity
def
_calc_response_usage
(
self
,
model
:
str
,
credentials
:
dict
,
tokens
:
int
)
->
EmbeddingUsage
:
"""
Calculate response usage
:param model: model name
:param credentials: model credentials
:param tokens: input tokens
:return: usage
"""
# get input price info
input_price_info
=
self
.
get_price
(
model
=
model
,
credentials
=
credentials
,
price_type
=
PriceType
.
INPUT
,
tokens
=
tokens
)
# transform usage
usage
=
EmbeddingUsage
(
tokens
=
tokens
,
total_tokens
=
tokens
,
unit_price
=
input_price_info
.
unit_price
,
price_unit
=
input_price_info
.
unit
,
total_price
=
input_price_info
.
total_amount
,
currency
=
input_price_info
.
currency
,
latency
=
time
.
perf_counter
()
-
self
.
started_at
)
return
usage
@
property
def
_invoke_error_mapping
(
self
)
->
dict
[
type
[
InvokeError
],
list
[
type
[
Exception
]]]:
"""
Map model invoke error to unified error
The key is the error type thrown to the caller
The value is the error type thrown by the model,
which needs to be converted into a unified error type for the caller.
:return: Invoke error mapping
"""
return
{
InvokeAuthorizationError
:
[
requests
.
exceptions
.
InvalidHeader
,
# Missing or Invalid API Key
],
InvokeBadRequestError
:
[
requests
.
exceptions
.
HTTPError
,
# Invalid Endpoint URL or model name
requests
.
exceptions
.
InvalidURL
,
# Misconfigured request or other API error
],
InvokeRateLimitError
:
[
requests
.
exceptions
.
RetryError
# Too many requests sent in a short period of time
],
InvokeServerUnavailableError
:
[
requests
.
exceptions
.
ConnectionError
,
# Engine Overloaded
requests
.
exceptions
.
HTTPError
# Server Error
],
InvokeConnectionError
:
[
requests
.
exceptions
.
ConnectTimeout
,
# Timeout
requests
.
exceptions
.
ReadTimeout
# Timeout
]
}
api/core/model_runtime/model_providers/openai_api_compatible/llm/llm.py
View file @
cca9edc9
...
...
@@ -360,6 +360,7 @@ class OAIAPICompatLargeLanguageModel(_CommonOAI_API_Compat, LargeLanguageModel):
message
=
AssistantPromptMessage
(
content
=
""
),
finish_reason
=
"Non-JSON encountered."
)
break
if
not
chunk_json
or
len
(
chunk_json
[
'choices'
])
==
0
:
continue
...
...
api/core/model_runtime/model_providers/openai_api_compatible/openai_api_compatible.yaml
View file @
cca9edc9
...
...
@@ -33,8 +33,8 @@ model_credential_schema:
type
:
text-input
required
:
true
placeholder
:
zh_Hans
:
Base URL, eg. https://api.openai.com/v1
en_US
:
Base URL, eg. https://api.openai.com/v1
zh_Hans
:
Base URL, e
.
g. https://api.openai.com/v1
en_US
:
Base URL, e
.
g. https://api.openai.com/v1
-
variable
:
mode
show_on
:
-
variable
:
__model_type
...
...
api/core/model_runtime/model_providers/openllm/openllm.yaml
View file @
cca9edc9
...
...
@@ -33,5 +33,5 @@ model_credential_schema:
type
:
text-input
required
:
true
placeholder
:
zh_Hans
:
在此输入OpenLLM的服务器地址,如 http
s://example.com/xxx
en_US
:
Enter the url of your OpenLLM,
for example https://example.com/xxx
zh_Hans
:
在此输入OpenLLM的服务器地址,如 http
://192.168.1.100:3000
en_US
:
Enter the url of your OpenLLM,
e.g. http://192.168.1.100:3000
api/core/model_runtime/model_providers/xinference/xinference.yaml
View file @
cca9edc9
...
...
@@ -34,8 +34,8 @@ model_credential_schema:
type
:
secret-input
required
:
true
placeholder
:
zh_Hans
:
在此输入Xinference的服务器地址,如 http
s://example.com/xxx
en_US
:
Enter the url of your Xinference,
for example https://example.com/xxx
zh_Hans
:
在此输入Xinference的服务器地址,如 http
://192.168.1.100:9997
en_US
:
Enter the url of your Xinference,
e.g. http://192.168.1.100:9997
-
variable
:
model_uid
label
:
zh_Hans
:
模型UID
...
...
api/core/prompt/prompt_transform.py
View file @
cca9edc9
...
...
@@ -121,6 +121,7 @@ class PromptTransform:
prompt_template_entity
=
prompt_template_entity
,
inputs
=
inputs
,
query
=
query
,
files
=
files
,
context
=
context
,
memory
=
memory
,
model_config
=
model_config
...
...
@@ -343,7 +344,14 @@ class PromptTransform:
prompt_message
=
UserPromptMessage
(
content
=
prompt_message_contents
)
else
:
prompt_message
=
UserPromptMessage
(
content
=
prompt
)
if
files
:
prompt_message_contents
=
[
TextPromptMessageContent
(
data
=
prompt
)]
for
file
in
files
:
prompt_message_contents
.
append
(
file
.
prompt_message_content
)
prompt_message
=
UserPromptMessage
(
content
=
prompt_message_contents
)
else
:
prompt_message
=
UserPromptMessage
(
content
=
prompt
)
return
[
prompt_message
]
...
...
@@ -434,6 +442,7 @@ class PromptTransform:
prompt_template_entity
:
PromptTemplateEntity
,
inputs
:
dict
,
query
:
str
,
files
:
List
[
FileObj
],
context
:
Optional
[
str
],
memory
:
Optional
[
TokenBufferMemory
],
model_config
:
ModelConfigEntity
)
->
List
[
PromptMessage
]:
...
...
@@ -461,7 +470,14 @@ class PromptTransform:
prompt
=
self
.
_format_prompt
(
prompt_template
,
prompt_inputs
)
prompt_messages
.
append
(
UserPromptMessage
(
content
=
prompt
))
if
files
:
prompt_message_contents
=
[
TextPromptMessageContent
(
data
=
prompt
)]
for
file
in
files
:
prompt_message_contents
.
append
(
file
.
prompt_message_content
)
prompt_messages
.
append
(
UserPromptMessage
(
content
=
prompt_message_contents
))
else
:
prompt_messages
.
append
(
UserPromptMessage
(
content
=
prompt
))
return
prompt_messages
...
...
api/tests/integration_tests/.env.example
View file @
cca9edc9
...
...
@@ -62,5 +62,8 @@ COHERE_API_KEY=
# Jina Credentials
JINA_API_KEY=
# Ollama Credentials
OLLAMA_BASE_URL=
# Mock Switch
MOCK_SWITCH=false
\ No newline at end of file
api/tests/integration_tests/model_runtime/ollama/__init__.py
0 → 100644
View file @
cca9edc9
api/tests/integration_tests/model_runtime/ollama/test_llm.py
0 → 100644
View file @
cca9edc9
import
os
from
typing
import
Generator
import
pytest
from
core.model_runtime.entities.message_entities
import
AssistantPromptMessage
,
UserPromptMessage
,
\
SystemPromptMessage
,
TextPromptMessageContent
,
ImagePromptMessageContent
from
core.model_runtime.entities.llm_entities
import
LLMResult
,
LLMResultChunkDelta
,
\
LLMResultChunk
from
core.model_runtime.errors.validate
import
CredentialsValidateFailedError
from
core.model_runtime.model_providers.ollama.llm.llm
import
OllamaLargeLanguageModel
def
test_validate_credentials
():
model
=
OllamaLargeLanguageModel
()
with
pytest
.
raises
(
CredentialsValidateFailedError
):
model
.
validate_credentials
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
'http://localhost:21434'
,
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
}
)
model
.
validate_credentials
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
}
)
def
test_invoke_model
():
model
=
OllamaLargeLanguageModel
()
response
=
model
.
invoke
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
UserPromptMessage
(
content
=
'Who are you?'
)
],
model_parameters
=
{
'temperature'
:
1.0
,
'top_k'
:
2
,
'top_p'
:
0.5
,
'num_predict'
:
10
},
stop
=
[
'How'
],
stream
=
False
)
assert
isinstance
(
response
,
LLMResult
)
assert
len
(
response
.
message
.
content
)
>
0
def
test_invoke_stream_model
():
model
=
OllamaLargeLanguageModel
()
response
=
model
.
invoke
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
SystemPromptMessage
(
content
=
'You are a helpful AI assistant.'
,
),
UserPromptMessage
(
content
=
'Who are you?'
)
],
model_parameters
=
{
'temperature'
:
1.0
,
'top_k'
:
2
,
'top_p'
:
0.5
,
'num_predict'
:
10
},
stop
=
[
'How'
],
stream
=
True
)
assert
isinstance
(
response
,
Generator
)
for
chunk
in
response
:
assert
isinstance
(
chunk
,
LLMResultChunk
)
assert
isinstance
(
chunk
.
delta
,
LLMResultChunkDelta
)
assert
isinstance
(
chunk
.
delta
.
message
,
AssistantPromptMessage
)
def
test_invoke_completion_model
():
model
=
OllamaLargeLanguageModel
()
response
=
model
.
invoke
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'completion'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
UserPromptMessage
(
content
=
'Who are you?'
)
],
model_parameters
=
{
'temperature'
:
1.0
,
'top_k'
:
2
,
'top_p'
:
0.5
,
'num_predict'
:
10
},
stop
=
[
'How'
],
stream
=
False
)
assert
isinstance
(
response
,
LLMResult
)
assert
len
(
response
.
message
.
content
)
>
0
def
test_invoke_stream_completion_model
():
model
=
OllamaLargeLanguageModel
()
response
=
model
.
invoke
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'completion'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
SystemPromptMessage
(
content
=
'You are a helpful AI assistant.'
,
),
UserPromptMessage
(
content
=
'Who are you?'
)
],
model_parameters
=
{
'temperature'
:
1.0
,
'top_k'
:
2
,
'top_p'
:
0.5
,
'num_predict'
:
10
},
stop
=
[
'How'
],
stream
=
True
)
assert
isinstance
(
response
,
Generator
)
for
chunk
in
response
:
assert
isinstance
(
chunk
,
LLMResultChunk
)
assert
isinstance
(
chunk
.
delta
,
LLMResultChunkDelta
)
assert
isinstance
(
chunk
.
delta
.
message
,
AssistantPromptMessage
)
def
test_invoke_completion_model_with_vision
():
model
=
OllamaLargeLanguageModel
()
result
=
model
.
invoke
(
model
=
'llava'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'completion'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
UserPromptMessage
(
content
=
[
TextPromptMessageContent
(
data
=
'What is this in this picture?'
,
),
ImagePromptMessageContent
(
data
=
'data:image/png;base64,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'
)
]
)
],
model_parameters
=
{
'temperature'
:
0.1
,
'num_predict'
:
100
},
stream
=
False
,
)
assert
isinstance
(
result
,
LLMResult
)
assert
len
(
result
.
message
.
content
)
>
0
def
test_invoke_chat_model_with_vision
():
model
=
OllamaLargeLanguageModel
()
result
=
model
.
invoke
(
model
=
'llava'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
UserPromptMessage
(
content
=
[
TextPromptMessageContent
(
data
=
'What is this in this picture?'
,
),
ImagePromptMessageContent
(
data
=
'data:image/png;base64,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'
)
]
)
],
model_parameters
=
{
'temperature'
:
0.1
,
'num_predict'
:
100
},
stream
=
False
,
)
assert
isinstance
(
result
,
LLMResult
)
assert
len
(
result
.
message
.
content
)
>
0
def
test_get_num_tokens
():
model
=
OllamaLargeLanguageModel
()
num_tokens
=
model
.
get_num_tokens
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
2048
,
'max_tokens'
:
2048
,
},
prompt_messages
=
[
UserPromptMessage
(
content
=
'Hello World!'
)
]
)
assert
isinstance
(
num_tokens
,
int
)
assert
num_tokens
==
6
api/tests/integration_tests/model_runtime/ollama/test_text_embedding.py
0 → 100644
View file @
cca9edc9
import
os
import
pytest
from
core.model_runtime.entities.text_embedding_entities
import
TextEmbeddingResult
from
core.model_runtime.errors.validate
import
CredentialsValidateFailedError
from
core.model_runtime.model_providers.ollama.text_embedding.text_embedding
import
OllamaEmbeddingModel
def
test_validate_credentials
():
model
=
OllamaEmbeddingModel
()
with
pytest
.
raises
(
CredentialsValidateFailedError
):
model
.
validate_credentials
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
'http://localhost:21434'
,
'mode'
:
'chat'
,
'context_size'
:
4096
,
}
)
model
.
validate_credentials
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
4096
,
}
)
def
test_invoke_model
():
model
=
OllamaEmbeddingModel
()
result
=
model
.
invoke
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
4096
,
},
texts
=
[
"hello"
,
"world"
],
user
=
"abc-123"
)
assert
isinstance
(
result
,
TextEmbeddingResult
)
assert
len
(
result
.
embeddings
)
==
2
assert
result
.
usage
.
total_tokens
==
2
def
test_get_num_tokens
():
model
=
OllamaEmbeddingModel
()
num_tokens
=
model
.
get_num_tokens
(
model
=
'mistral:text'
,
credentials
=
{
'base_url'
:
os
.
environ
.
get
(
'OLLAMA_BASE_URL'
),
'mode'
:
'chat'
,
'context_size'
:
4096
,
},
texts
=
[
"hello"
,
"world"
]
)
assert
num_tokens
==
2
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment