Skip to content

Commit

Permalink
Page templating prototype (#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
stoerr authored May 24, 2024
2 parents 86cc7ba + f1bcfb3 commit a9cd8de
Show file tree
Hide file tree
Showing 64 changed files with 1,555 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ target
.linklint
.lycheecache
build.log
.aigenpipeline
.aigenpipeline*
3 changes: 1 addition & 2 deletions NextSteps.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@

- Choose tags from existing tags, AEM like?
- Page assistant in preview: can also process selected text!
- Site specific or global templates for prompts.
- Global configuration for prompts: e.g. glossary, important terms, background information.
- Bug: translation in all properties component - fill german value and translate to english.
- Check Error handling. (e.g. connection error.)
- Unclear: content generation from text in non-default language?
- better mode of shortening texts if required text length is small.

## Possible improvements later
Expand Down Expand Up @@ -70,3 +68,4 @@
- DONE: API key in site configuration? Tenant configuration?
- DONE: AEM announcement and installation and usage description
- DONE: Update Pages content creation dialog with separate content field like AEM
- DONE: Site specific or global templates for prompts.
4 changes: 3 additions & 1 deletion TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

Offer parent container as content creation dialog source
Document using Claude, Gemini, https://octo.ai/product/text-generation/ , local
Bug: no content creation dialog in new component
Problems in Composum version:
- when using assistant on creation dialog, and then opening it again, it should have the same settings as when creating (?)
- last 20 prompts not yet implemented

Image description from URL?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.composum.ai.backend.base.service.chat.GPTChatCompletionService;
import com.composum.ai.backend.slingbase.ApproximateMarkdownService;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* Servlet that reads the content selectors from a JSON file, adds links in the content and provides that to the dialog.
Expand All @@ -39,7 +40,7 @@
})
public class AemContentCreationSelectorsServlet extends SlingSafeMethodsServlet {

private final Gson gson = new Gson();
private final Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();

/**
* JCR path to a JSON with the basic content selectors supported by the dialog.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.composum.ai.backend.slingbase.AIConfigurationService;
import com.day.cq.wcm.api.WCMException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;

/**
Expand Down Expand Up @@ -61,7 +62,7 @@ public class AutoTranslateWorkflowProcess implements WorkflowProcess {
@Reference
protected AIConfigurationService configurationService;

protected final Gson gson = new Gson();
protected final Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();

@Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) throws WorkflowException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<!-- AIGenPromptStart(foobar)
Just copy.
AIGenCommand(foobar)
-m copy
../../../../../../../../../composum/package/src/main/content/jcr_root/libs/composum/pages/options/ai/prototype/prototype.html
AIGenPromptEnd(foobar) -->
<!DOCTYPE html>
<html lang="en">
<head>
Expand All @@ -10,29 +16,43 @@
padding-top: 20px;
background-color: #f0f8ff; /* Light blue background */
}

.container {
max-width: 800px;
}

a {
color: #007bff; /* Bootstrap primary blue */
}

a:hover {
color: #0056b3; /* Darker blue on hover */
}
</style>
</head>
<body>
<div class="container">
<h1>AI Search Prototypes Index</h1>
<p>This page serves as an index for AI search prototype applications developed as part of the Composum platform integration.</p>
<ul class="list-unstyled">
<li><a href="prototype/embedsearch.html">AI Assisted Search</a> - Explore the AI Assisted Search prototype, which leverages embedding orders and query parameters to enhance search results.</li>
<li><a href="prototype/rag.html">Retrieval Augmented Generation (RAG) Search</a> - Discover the RAG Search prototype, utilizing advanced AI to generate responses based on the retrieval of relevant documents.</li>
</ul>
</div>
<div class="container">
<h1>AI Search Prototypes Index</h1>
<p>This page serves as an index for AI search prototype applications developed as part of the Composum platform
integration.</p>
<ul class="list-unstyled">
<li><a href="prototype/embedsearch.html">AI Assisted Search</a> - Explore the AI Assisted Search prototype,
which leverages embedding orders and query parameters to enhance search results.
</li>
<li><a href="prototype/rag.html">Retrieval Augmented Generation (RAG) Search</a> - Discover the RAG Search
prototype, utilizing advanced AI to generate responses based on the retrieval of relevant documents.
</li>
<li><a href="prototype/templating.html">AI Templating</a> - Experiment to create whole pages with various
prompts backed by an URL source for information.
</li>
</ul>
</div>

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>


<!-- AIGenVersion(49dfba8f, prototype.html-0caedaea, prototype.html-49dfba8f) -->
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ <h2>Answer questions with RAG (retrieval augmented generation)</h2>
</div>
<div class="mb-3">
<label for="limitField" class="form-label">Maximum number of pages to be searched and ranked:</label>
<input type="number" class="form-control" id="limitField" name="limit" value="10">
<input type="number" class="form-control" id="limitField" name="limit" value="20">
<small class="form-text text-muted">Set the maximum number of pages to search and rank
(default is 10).</small>
(default is 20).</small>
</div>
<div class="mb-3">
<label for="limitRagTextsField" class="form-label">Maximum number of pages for AI to answer:</label>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
sling:resourceType="composum-ai/prototype/templating"
jcr:title="AI templating exploration app"
jcr:description="Expore AITemplatingServlet services at e.g. http://localhost:4502/apps/composum-ai/prototype/templating.html"
jcr:primaryType="sling:Folder"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!-- AIGenPromptStart(foobar)
Just copy.
AIGenCommand(foobar)
-m copy
../../../../../../../../../../composum/package/src/main/content/jcr_root/libs/composum/pages/options/ai/prototype/templating/templating.html
AIGenPromptEnd(foobar) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create a page from a template with AI</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body {
background-color: #cfe2f3;
}
.container {
background-color: #b3d7f7;
padding: 20px;
border-radius: 10px;
margin-top: 20px;
}
.btn-primary {
background-color: #5eadff;
border-color: #5eadff;
}
.btn-primary:hover {
background-color: #3ca9ff;
border-color: #3ca9ff;
}
</style>
</head>
<body>
<div class="container">
<h1>Create a page from a template with AI</h1>
<p>This single page application allows you to generate a complete text for a page by replacing prompts with AI-generated content. The page structure contains various components with prompts marked by special placeholders, such as 'PROMPTFIELD: ' for individual prompts and 'PROMPTFIELD#ID: ' for referenced prompts. Additionally, URLs can be included using 'SOURCEURL(https://example.com/)'. The application interacts with the AITemplatingServlet to process the page template.</p>

<form id="templatingForm">
<div class="form-group">
<label for="resourcePath">Resource Path:</label>
<input type="text" class="form-control" id="resourcePath" name="resourcePath" required>
<small class="form-text text-muted">Enter the path of the resource to process.</small>
</div>
<div class="form-group">
<label for="additionalPrompt">Additional Prompt:</label>
<textarea class="form-control" id="additionalPrompt" name="additionalPrompt" rows="3"></textarea>
<small class="form-text text-muted">Optionally, provide an additional prompt for the AI.</small>
</div>
<div class="form-group">
<label for="additionalUrls">Additional URL:</label>
<input type="url" class="form-control" id="additionalUrls" name="additionalUrls">
<small class="form-text text-muted">Enter a URL for context.</small>
</div>
<div class="form-group">
<label for="backgroundInformation">Background Information:</label>
<textarea class="form-control" id="backgroundInformation" name="backgroundInformation" rows="3"></textarea>
<small class="form-text text-muted">Optionally, provide additional background information for the AI.</small>
</div>
<button type="submit" class="btn btn-primary" id="replacePromptsBtn">Replace Prompts</button>
<button type="submit" class="btn btn-primary" id="resetPromptsBtn">Reset to Prompts</button>
</form>

<div class="mt-4"><pre style="white-space: pre-wrap;" id="resultDiv"></pre></div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script>
$(document).ready(function() {
var formData = JSON.parse(localStorage.getItem('composum-ai-prototype-templating')) || {};
$('#resourcePath').val(formData.resourcePath || '');
$('#additionalPrompt').val(formData.additionalPrompt || '');
$('#additionalUrls').val(formData.additionalUrls || '');
$('#backgroundInformation').val(formData.backgroundInformation || '');

$('#templatingForm').submit(function(event) {
event.preventDefault();
var method = event.originalEvent.submitter.id === 'replacePromptsBtn' ? 'replacePromptsInResource' : 'resetToPrompts';
var formData = {
resourcePath: $('#resourcePath').val(),
additionalPrompt: $('#additionalPrompt').val(),
additionalUrls: $('#additionalUrls').val(),
backgroundInformation: $('#backgroundInformation').val()
};
localStorage.setItem('composum-ai-prototype-templating', JSON.stringify(formData));

$('#replacePromptsBtn, #resetPromptsBtn').prop('disabled', true);
$('#resultDiv').text('Contacting the AI ...');
$.post('/bin/cpm/ai/experimental/templating.' + method + '.json', formData)
.done(function(data) {
$('#resultDiv').text(JSON.stringify(data, null, 2));
})
.fail(function(jqXHR, textStatus, errorThrown) {
$('#resultDiv').text('Error: ' + errorThrown);
})
.always(function() {
$('#replacePromptsBtn, #resetPromptsBtn').prop('disabled', false);
});
});
});
</script>
</body>
</html>

<!-- -->


<!-- AIGenVersion(794dd7c5, templating.html-0caedaea, templating.html-20fd7529) -->
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ public enum AnswerType {
/**
* Real HTML or, more likely, richtext as simplified HTML.
*/
HTML
HTML,
/**
* JSON is not yet supported by all models, so a bit dangerous.
*/
JSON
}

public enum Mode {
Expand All @@ -44,6 +48,8 @@ public enum Mode {

private final Mode mode;

private final Boolean highIntelligenceNeeded;

public GPTConfiguration(@Nullable String apiKey, @Nullable String organizationId, @Nullable AnswerType answerType) {
this(apiKey, organizationId, answerType, null);
}
Expand All @@ -53,11 +59,16 @@ public GPTConfiguration(@Nullable String apiKey, @Nullable String organizationId
}

public GPTConfiguration(@Nullable String apiKey, @Nullable String organizationId, @Nullable AnswerType answerType, @Nullable String additionalInstructions, @Nullable Mode mode) {
this(apiKey, organizationId, answerType, additionalInstructions, mode, null);
}

public GPTConfiguration(@Nullable String apiKey, @Nullable String organizationId, @Nullable AnswerType answerType, @Nullable String additionalInstructions, @Nullable Mode mode, @Nullable Boolean highIntelligenceNeeded) {
this.apiKey = apiKey;
this.answerType = answerType;
this.organizationId = organizationId;
this.additionalInstructions = additionalInstructions;
this.mode = mode;
this.highIntelligenceNeeded = highIntelligenceNeeded;
}

/**
Expand Down Expand Up @@ -96,6 +107,11 @@ public Mode getMode() {
return mode;
}

/** Uses the slower and more expensive high intelligence model - use sparingly for more challenging tasks. */
public Boolean isHighIntelligenceNeeded() {
return highIntelligenceNeeded;
}

/**
* Creates a configuration that joins the values.
*
Expand Down Expand Up @@ -154,13 +170,22 @@ public String toString() {
if (additionalInstructions != null) {
sb.append(", additionalInstructions='").append(additionalInstructions).append('\'');
}
if (mode != null) {
sb.append(", mode=").append(mode);
}
if (highIntelligenceNeeded != null) {
sb.append(", highIntelligenceNeeded=").append(highIntelligenceNeeded);
}
return sb.append('}').toString();
}

public static final GPTConfiguration MARKDOWN = new GPTConfiguration(null, null, AnswerType.MARKDOWN);
public static final GPTConfiguration HTML = new GPTConfiguration(null, null, AnswerType.HTML);
public static final GPTConfiguration JSON = new GPTConfiguration(null, null, AnswerType.JSON);
public static final GPTConfiguration CHAT = new GPTConfiguration(null, null, null, null, Mode.CHAT);
public static final GPTConfiguration GENERATE = new GPTConfiguration(null, null, null, null, Mode.GENERATE);
/** Requests slower and more expensive "high intelligence" model - use sparingly. */
public static final GPTConfiguration HIGH_INTELLIGENCE = new GPTConfiguration(null, null, null, null, null, true);

@Override
public boolean equals(Object o) {
Expand Down
Loading

0 comments on commit a9cd8de

Please sign in to comment.