The dotAI feature makes available a viewtool that surfaces a number of AI operations. Through calls to methods of $ai
, you can incorporate these functions into your Velocity scripts.
Basic Viewtool Generation Tools
The AI Viewtool exposes two important content generation methods:
$ai.generateText(prompt)
$ai.generateImage(prompt)
Both may take as their prompt argument either a string or a map — such as a content object. Both methods return a JSON object, though their respective schemata differ.
The object returned by text generation operations assumes the following form, with the content
property of each object in the choices
array containing the requested output:
{
"id":"chatcmpl-8rKTdjmfNyD1iEKw5qGD98qc14CW7",
"object":"chat.completion",
"created":1707720789,
"model":"gpt-3.5-turbo-16k-0613",
"choices":[
{
"index":0,
"message":{
"role":"assistant",
"content":"Hello! Wishing you a wonderful day filled with joy and success."
},
"logprobs":null,
"finish_reason":"stop"
}
...
],
"usage":{
"prompt_tokens":45,
"completion_tokens":14,
"total_tokens":59
},
"system_fingerprint":null
}
In contrast, image-generation calls return an object with just five properties; the url
property contains the direct link to the file output.
{
"revised_prompt":"Create a meticulous line drawing showcasing a perfectly symmetrical circle neatly inscribed within a geometric square. The lines should be crisp, clear, and simple, evoking a serene sense of symmetry and balance. Please maintain the monochromatic tonality to highlight the geometric simplicity of the drawing.",
"url":"https://example.url/circle_20240212_065752.png?query=param&others=whynot",
"originalPrompt":"Produce a line drawing of a circle inscribed in a square.",
"tempFileName":"circle_20240212_065752.png",
"response":"temp_a89ea3aabc"
}
Viewtool Searches
$ai.search
is a sub-tool of the AI Viewtool, with two methods of its own:
$ai.search.query(query, index)
$ai.search.related(content, index)
Searches using query()
may include query
arguments that consist of a string, or a map object. The latter should specify multiple parameters manually.
Example of a query by string:
## Run a semantic query
#set($results = $ai.search.query("Where can I find the Best beaches?", "blogIndex"))
total: $results.count
limit: $results.limit
offset: $results.offset
threshold: $results.threshold
$results.query
#foreach($result in $results.dotCMSResults)
$result.title
#foreach($m in $result.matches)
- $m.distance : $m.extractedText
#end
#end
Query by map:
## A semantic query using a Map of Parameters
#set($query = {})
$!query.put("query", "Where can I find the Best beaches?")
$!query.put("contentType", "Blog")
$!query.put("indexName", "blogIndex")
$!query.put("limit", "100")
$!query.put("offset", "0")
## $!query.put("host", "SYSTEM_HOST")
## $!query.put("language", "1")
## $!query.put("fieldVar", "content")
#set($results = $ai.search.query($query ))
total: $results.count
limit: $results.limit
offset: $results.offset
threshold: $results.threshold
$results.query
#foreach($result in $results.dotCMSResults)
$result.title
#foreach($m in $result.matches)
- $m.distance : $m.extractedText
#end
#end
The second method of the AI Search tool is related(content, index)
, which takes a map, such as — but not limited to — a full contentlet as its first argument:
## Finding related Content
#set($content = $dotcontent.find("48ec3192-5f04-466b-b7cd-7134f3ea4d67"))
## send in a contentlet to find related content in the index "blog"
#set($relatedContent = $ai.search.related($content, "blogIndex"))
#foreach($result in $relatedContent.dotCMSResults)
$result.title : $result.inode
#foreach($m in $result.matches)
- $m.distance : $m.extractedText
#end
#end
In any of the above cases, the returned JSON object will use the following “completion” structure, albeit slightly truncated:
{
"timeToEmbeddings":"860ms",
"total":5,
"query":"What's the best place to vacation?",
"threshold":0.25,
"dotCMSResults":[
{
<content object properties>,
"matches":[
{
"distance":0.21085739135742188,
"extractedText":"<text excerpt>..."
},
...
]
},
...
],
"operator":"<=>",
"offset":0,
"limit":50,
"count":3
}
Viewtool Embeddings
The AI Viewtool has an embeddings
sub-tool containing three methods that perform operations relevant to embeddings — which, to reiterate, are vector calculations that assist in performing semantic indexing.
Method | Description |
---|---|
$ai.embeddings.countTokens(prompt) | Takes a string argument; returns an integer reflecting how many tokens the string argument would represent. |
$ai.embeddings.generateEmbeddings(prompt) | Takes a string argument; returns an array of floating-point numbers representing the embeddings of the provided string. |
$ai.embeddings.getIndexCount() or $ai.embeddings.indexCount | Returns a map containing a list of indexes (see below for example). |
Each entry in the object returned by indexCount
contains several statistics, in the following fashion:
{
blogIndex={
contentTypes=Blog,
tokensPerChunk=306,
tokenTotal=2146,
fragments=7,
contents=3
},
...
}
Viewtool Completions
The completions
sub-tool provides three methods that make use of “chat”-style functionality.
Method | Description |
---|---|
$ai.completions.getConfig() or $ai.completions.config | Returns a map reflecting the current set of prompt configurations (see below). |
$ai.completions.summarize(prompt, [index]) | Accepts a string prompt and an index, using the default index if the latter is not specified. More than a simple list of results, as with a search.query() , summarize also attempts to provide a short explanation based on the results collected. |
$ai.completions.raw(prompt) | Accepts either a map, a JSON object, or a string representing a JSON object. Returns a JSON object containing a chat response. |
Here is an example of the map returned by the config
method:
{
com.dotcms.ai.completion.model=gpt-3.5-turbo-16k,
com.dotcms.ai.completion.role.prompt=You are a helpful assistant with a descriptive writing style.,
com.dotcms.ai.completion.text.prompt=Answer this question\n\"$!{prompt}?\"\n\nby using only the information in the following text:\n"""\n$!{supportingContent} \n"""\n
}
And an example of the summarize()
method in action:
#set($summary = $ai.completions.summarize("Where can I find the Best beaches?", "blogIndex"))
model: $summary.openAiResponse.model
prompt: $summary.openAiResponse.usage.prompt_tokens
tokens: $summary.openAiResponse.usage.total_tokens
$summary.openAiResponse.choices.get(0).message.content
…returns an object as $summary
resembling the following:
{
"timeToEmbeddings":"67ms",
"total":2,
"query":"Where can I find the Best beaches?",
"threshold":0.25,
"dotCMSResults":[
{
<content object properties>,
"matches":[
{
"distance":0.2304542511701584,
"extractedText":"<excerpt>..."
},
...
]
}
],
"operator":"<=>",
"offset":0,
"limit":50,
"count":1,
"openAiResponse":{
"id":"chatcmpl-8rPgXQi1SpHgq4F6dJ2kH7WHMuwh5",
"object":"chat.completion",
"created":1707740809,
"model":"gpt-3.5-turbo-16k-0613",
"choices":[
{
"index":0,
"message":{
"role":"assistant",
"content":"Based on the given text, Costa Rica is known for its beautiful beaches and is a great destination for beach lovers. The Pacific coast of Costa Rica in particular offers some of the best surfing spots in the world. Whether you are a seasoned surfer or a beginner, you will find a beach that suits your skill level perfectly. Additionally, there are also opportunities for wildlife viewing along the coast, where you can observe various species of birds, monkeys, and other wildlife. So, if you are looking for the best beaches, Costa Rica's Pacific coast is a must-visit destination."
},
"logprobs":null,
"finish_reason":"stop"
}
],
"usage":{
"prompt_tokens":680,
"completion_tokens":116,
"total_tokens":796
},
"system_fingerprint":null
}
}
Finally, the raw
chat might be used in the following fashion with a string prompt:
#set($prompt = '{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "You are a chatbot providing travel advice to people who visit a travel website; provide an enticing description of the beaches of Costa Rica"
}
]
}')
#set($chat = $ai.completions.raw($prompt))
Or, for a map as prompt:
#set($prompt = {})
$!prompt.put("model", "gpt-3.5-turbo")
#set($messages =[])
#set($message ={})
$!message.put("role", "user")
$!message.put("content", "You are a chatbot providing travel advice to people who visit a travel website; provide an enticing description of the beaches of Costa Rica")
$messages.add($message)
$prompt.put("messages", $messages)
#set($chat = $ai.completions.raw($prompt))
It returns its response in the following format:
{
"id":"chatcmpl-8rQ1ZIXIHXEjDiOeKuSyCeuqEVdlH",
"object":"chat.completion",
"created":1707742113,
"model":"gpt-3.5-turbo-0613",
"choices":[
{
"index":0,
"message":{
"role":"assistant",
"content":"Welcome to the tropical paradise of Costa Rica, a dream destination for beach lovers! Get ready to immerse yourself in a world of breathtaking beauty where pristine sandy shores meet crystal-clear turquoise waters. \n\nCosta Rica boasts an incredible 800 miles of coastline, offering an array of picturesque beaches to suit every traveler's taste..."
},
"logprobs":null,
"finish_reason":"stop"
}
],
"usage":{
"prompt_tokens":33,
"completion_tokens":432,
"total_tokens":465
},
"system_fingerprint":null
}