Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page templating prototype #87

Merged
merged 29 commits into from
May 24, 2024
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c375ef6
note some todos
stoerr May 16, 2024
f741ebb
untested implementation of ai templating
stoerr May 17, 2024
499aaaf
implement AITemplating{Service,Servlet}
stoerr May 17, 2024
bbc5454
starting templating GUI
stoerr May 17, 2024
52e3ea9
first version of templating
stoerr May 17, 2024
b56c5fd
various fixes
stoerr May 17, 2024
05b1a7d
some fixes
stoerr May 17, 2024
5401ca6
some fixes
stoerr May 17, 2024
184f0d1
update texts
stoerr May 18, 2024
26749d2
refactoring
stoerr May 21, 2024
82c2bff
enable richtext for prompts, some fixes
stoerr May 21, 2024
693aff3
Gson: disable HTML escaping to make it easier for ChatGPT
stoerr May 21, 2024
d30c999
fixes and improvements of the prompting
stoerr May 21, 2024
33d4465
add templating for AEM; extend bin/aigenerate
stoerr May 21, 2024
767b1df
fixes
stoerr May 23, 2024
7d11eca
massively improve the prompting
stoerr May 23, 2024
c0a603b
templating works, but not reliable enough with gpt-3.5-turbo
stoerr May 23, 2024
4891ba3
restructure templating request with separated normal text instead of …
stoerr May 23, 2024
9820256
Refactor AITemplatingServiceImpl to handle end-of-page command and re…
stoerr May 23, 2024
8eac4be
fixes
stoerr May 23, 2024
814b301
replace gpt-4-turbo with newer and less expensive gpt-4o
stoerr May 23, 2024
f4ac2cb
use high intelligence model gpt-4o for templating service
stoerr May 23, 2024
a6332d4
update spec
stoerr May 23, 2024
3890837
make it possible add background information as text
stoerr May 23, 2024
fb3c3f6
continuing documentation
stoerr May 23, 2024
8ca6666
introduce URL blacklisting and whitelisting for markdown determinatio…
stoerr May 24, 2024
ceb2d5c
Update configuration overview
stoerr May 24, 2024
43deb9f
initial documentation
stoerr May 24, 2024
f1bcfb3
some fixes
stoerr May 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -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
@@ -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
@@ -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
@@ -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?

Original file line number Diff line number Diff line change
@@ -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.
@@ -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.
Original file line number Diff line number Diff line change
@@ -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;

/**
@@ -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 {
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>
@@ -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>
Dismissed Show dismissed Hide dismissed
<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
@@ -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>
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
@@ -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 {
@@ -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);
}
@@ -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;
}

/**
@@ -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.
*
@@ -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) {
Loading
Loading