Преглед изворни кода

Add editable AI prompt settings

master
Nano пре 6 дана
родитељ
комит
c2c3e263c4
9 измењених фајлова са 243 додато и 21 уклоњено
  1. +38
    -12
      app/controllers/AdminController.asp
  2. +3
    -2
      app/controllers/CommentsController.asp
  3. +15
    -4
      app/controllers/PostsController.asp
  4. +25
    -0
      app/views/Admin/ai-prompt.asp
  5. +8
    -0
      app/views/Admin/index.asp
  6. +134
    -1
      core/helpers.asp
  7. +13
    -0
      core/router.wsc
  8. +4
    -2
      public/Default.asp
  9. +3
    -0
      public/web.config

+ 38
- 12
app/controllers/AdminController.asp Прегледај датотеку

@@ -58,6 +58,43 @@ Class AdminController_Class
<%
End Sub

'---------------------------------------------------------------
' Action: AIPrompt
'---------------------------------------------------------------
Public Sub AIPrompt()
m_title = "AI Prompt Settings"
Dim promptTemplate : promptTemplate = GetGenerationPromptTemplate()
%>
<!--#include file="../views/Admin/ai-prompt.asp" -->
<%
End Sub

'---------------------------------------------------------------
' Action: UpdateAIPrompt
'---------------------------------------------------------------
Public Sub UpdateAIPrompt()
Dim promptTemplate : promptTemplate = Trim(Request.Form("PromptTemplate"))
If Len(promptTemplate) = 0 Then
Flash().AddError "Prompt template cannot be empty."
Response.Redirect "/admin/ai-prompt"
Exit Sub
End If

On Error Resume Next
UpdateAppSetting "AbacusGenerationPrompt", promptTemplate
If Err.Number <> 0 Then
Flash().AddError "Unable to save prompt template: " & Err.Description
Err.Clear
On Error GoTo 0
Response.Redirect "/admin/ai-prompt"
Exit Sub
End If
On Error GoTo 0

Flash().Success = "AI prompt template saved."
Response.Redirect "/admin/ai-prompt"
End Sub

'---------------------------------------------------------------
' Action: PublishPost
'---------------------------------------------------------------
@@ -166,10 +203,7 @@ Class AdminController_Class
Dim systemPrompt, userPrompt, payload, responseText, parsed, choices, choice, message, content, contentJson
systemPrompt = "You write clear, engaging blog post content for a classic ASP blog. Return only valid JSON with two keys: summary and body. Summary must be 1 to 2 sentences. Body must be 3 to 5 short paragraphs separated by blank lines. Do not use markdown fences, bullets, or code blocks."

userPrompt = "Create blog content for this post title: " & SafeText(post.Title) & vbCrLf & _
"Existing summary: " & SafeText(post.Summary) & vbCrLf & _
"Existing body: " & SafeText(post.Body) & vbCrLf & _
"Keep the title unchanged. Make the content readable and helpful for a general audience."
userPrompt = BuildGenerationPrompt(post)

payload = "{""model"":""" & JsonEscape(modelName) & """,""messages"":[{""role"":""system"",""content"":""" & JsonEscape(systemPrompt) & """},{""role"":""user"",""content"":""" & JsonEscape(userPrompt) & """}],""temperature"":0.7}"

@@ -235,14 +269,6 @@ Class AdminController_Class
End If
End Function

Private Function SafeText(ByVal value)
If IsNull(value) Or IsEmpty(value) Then
SafeText = ""
Else
SafeText = CStr(value)
End If
End Function

End Class

Dim AdminController_Class__Singleton


+ 3
- 2
app/controllers/CommentsController.asp Прегледај датотеку

@@ -53,7 +53,7 @@ Class CommentsController_Class

Dim slug : slug = ResolvePostSlug(comment.PostID)
If Len(slug) > 0 Then
Response.Redirect "/posts/" & Server.URLEncode(slug)
Response.Redirect PostUrl(slug)
Else
Response.Redirect "/posts"
End If
@@ -82,12 +82,13 @@ Class CommentsController_Class
Private Function ResolvePostSlug(ByVal postID)
Dim slug : slug = Trim(Request.Form("Slug"))
If Len(slug) = 0 Then slug = Trim(Request.Form("PostSlug"))
slug = NormalizeSlug(slug)

If Len(slug) = 0 And CLng(postID) > 0 Then
Dim post
On Error Resume Next
Set post = PostsRepository().FindByID(postID)
If Err.Number = 0 Then slug = CStr(post.Slug)
If Err.Number = 0 Then slug = NormalizeSlug(post.Slug)
Err.Clear
On Error GoTo 0
End If


+ 15
- 4
app/controllers/PostsController.asp Прегледај датотеку

@@ -45,12 +45,19 @@ Class PostsController_Class
<%
End Sub
'---------------------------------------------------------------
' Action: Show
'---------------------------------------------------------------
'---------------------------------------------------------------
' Action: Show
'---------------------------------------------------------------
Public Sub Show(ByVal slug)
Dim requestedSlug : requestedSlug = Trim(CStr(slug))
Dim canonicalSlug : canonicalSlug = NormalizeSlug(requestedSlug)

Dim matches
Set matches = PostsRepository().Find(Array("Slug", slug, "IsPublished", 1), Empty)
Set matches = PostsRepository().Find(Array("Slug", requestedSlug, "IsPublished", 1), Empty)

If matches.Count = 0 And canonicalSlug <> requestedSlug Then
Set matches = PostsRepository().Find(Array("Slug", canonicalSlug, "IsPublished", 1), Empty)
End If

If matches.Count = 0 Then
Response.Status = "404 Not Found"
@@ -63,6 +70,10 @@ Class PostsController_Class
Dim post
Set post = matches.Front()

If Len(canonicalSlug) > 0 And canonicalSlug <> requestedSlug Then
Response.Redirect PostUrl(canonicalSlug)
End If

Dim comments
Set comments = CommentsRepository().Find(Array("PostID", post.PostID, "IsApproved", 1), "CreatedDate")
%>


+ 25
- 0
app/views/Admin/ai-prompt.asp Прегледај датотеку

@@ -0,0 +1,25 @@
<div class="row">
<div class="col-lg-10 col-xl-8">
<div class="card shadow-sm">
<div class="card-body">
<h1 class="h3 mb-2">AI Prompt Settings</h1>
<p class="text-muted mb-4">Edit the template used when generating AI post content.</p>

<form method="post" action="<%= AdminAIPromptUpdateUrl() %>">
<div class="mb-3">
<label class="form-label" for="PromptTemplate">Prompt Template</label>
<textarea class="form-control" id="PromptTemplate" name="PromptTemplate" rows="14" spellcheck="false"><%= H(promptTemplate) %></textarea>
<div class="form-text">
Placeholders: <code>{TITLE}</code>, <code>{SUMMARY}</code>, <code>{BODY}</code>
</div>
</div>

<div class="d-flex flex-wrap gap-2">
<button class="btn btn-primary" type="submit">Save Prompt</button>
<a class="btn btn-outline-secondary" href="<%= AdminUrl() %>">Cancel</a>
</div>
</form>
</div>
</div>
</div>
</div>

+ 8
- 0
app/views/Admin/index.asp Прегледај датотеку

@@ -22,4 +22,12 @@
</div>
</a>
</div>
<div class="col-md-6">
<a class="card shadow-sm text-decoration-none h-100" href="<%= AdminUrl() %>/ai-prompt">
<div class="card-body">
<h2 class="h5 mb-1">AI Prompt</h2>
<p class="text-muted mb-0">Edit the prompt used to generate AI post content.</p>
</div>
</a>
</div>
</div>

+ 134
- 1
core/helpers.asp Прегледај датотеку

@@ -95,6 +95,76 @@ Public Function GetSecureSetting(key, envName)
GetSecureSetting = ""
End Function

Public Function GetGenerationPromptTemplate()
Dim prompt
prompt = Trim(CStr(GetAppSetting("AbacusGenerationPrompt")))

If Len(prompt) = 0 Or LCase(prompt) = "nothing" Then
prompt = "You write clear, engaging blog post content for a classic ASP blog. Return only valid JSON with two keys: summary and body. Summary must be 1 to 2 sentences. Body must be 3 to 5 short paragraphs separated by blank lines. Do not use markdown fences, bullets, or code blocks." & vbCrLf & vbCrLf & _
"Create blog content for this post title: {TITLE}" & vbCrLf & _
"Existing summary: {SUMMARY}" & vbCrLf & _
"Existing body: {BODY}" & vbCrLf & _
"Keep the title unchanged. Make the content readable and helpful for a general audience."
End If

GetGenerationPromptTemplate = prompt
End Function

Public Function BuildGenerationPrompt(ByRef post)
Dim template
template = GetGenerationPromptTemplate()
template = Replace(template, "{TITLE}", SafePromptText(post.Title))
template = Replace(template, "{SUMMARY}", SafePromptText(post.Summary))
template = Replace(template, "{BODY}", SafePromptText(post.Body))
BuildGenerationPrompt = template
End Function

Public Function SafePromptText(ByVal value)
If IsNull(value) Or IsEmpty(value) Then
SafePromptText = ""
Else
SafePromptText = CStr(value)
End If
End Function

Public Function UpdateAppSetting(key, value)
Dim xml, nodes, node, appSettings, found
Set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = False
xml.preserveWhiteSpace = True
xml.Load Server.MapPath("web.config")

If xml.parseError.errorCode <> 0 Then
Err.Raise 1, "UpdateAppSetting", "Unable to load web.config: " & xml.parseError.reason
End If

Set nodes = xml.selectNodes("//appSettings/add[@key='" & key & "']")
found = False
If Not (nodes Is Nothing) Then
If nodes.Length > 0 Then
Set node = nodes.Item(0)
node.setAttribute "value", value
found = True
End If
End If

If Not found Then
Set appSettings = xml.selectSingleNode("//appSettings")
If appSettings Is Nothing Then
Err.Raise 1, "UpdateAppSetting", "<appSettings> section not found in web.config."
End If

Set node = xml.createElement("add")
node.setAttribute "key", key
node.setAttribute "value", value
appSettings.appendChild node
End If

xml.Save Server.MapPath("web.config")
Application.Contents.Remove("AppSetting_" & key)
UpdateAppSetting = True
End Function

Public Sub ShowServerVariables
Dim varName, htmlTable
htmlTable = "<table border='1' cellspacing='0' cellpadding='5'>"
@@ -183,6 +253,31 @@ Function TrimQueryParams(rawPath)
End If
End Function

Function DecodeUrlPath(ByVal rawPath)
Dim current, previous
current = Trim(CStr(rawPath))

On Error Resume Next
Do
previous = current
current = Server.URLDecode(current)
If Err.Number <> 0 Then
Err.Clear
current = previous
Exit Do
End If
Loop While current <> previous
On Error GoTo 0

current = Replace(current, "%252D", "-")
current = Replace(current, "%252d", "-")
current = Replace(current, "%2D", "-")
current = Replace(current, "%2d", "-")
current = Replace(current, "%25", "%")

DecodeUrlPath = current
End Function

Sub Destroy(o)
if isobject(o) then
if not o is nothing then
@@ -252,7 +347,7 @@ Function CategoryDeleteUrl(ByVal categoryId)
End Function

Function PostUrl(ByVal slug)
PostUrl = "/posts/" & Server.URLEncode(CStr(slug))
PostUrl = "/posts/" & Server.URLEncode(NormalizeSlug(slug))
End Function

Function PostsUrl()
@@ -287,6 +382,14 @@ Function AdminPostAIUrl(ByVal postId)
AdminPostAIUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/ai"
End Function

Function AdminAIPromptUrl()
AdminAIPromptUrl = "/admin/ai-prompt"
End Function

Function AdminAIPromptUpdateUrl()
AdminAIPromptUpdateUrl = "/admin/ai-prompt"
End Function

Function AdminUrl()
AdminUrl = "/admin"
End Function
@@ -295,6 +398,36 @@ Function CommentsUrl()
CommentsUrl = "/comments"
End Function

Function NormalizeSlug(ByVal slug)
Dim current, previous
current = Trim(CStr(slug))

If Len(current) = 0 Then
NormalizeSlug = ""
Exit Function
End If

On Error Resume Next
Do
previous = current
current = Server.URLDecode(current)
If Err.Number <> 0 Then
Err.Clear
current = previous
Exit Do
End If
Loop While current <> previous
On Error GoTo 0

current = Replace(current, "%252D", "-")
current = Replace(current, "%252d", "-")
current = Replace(current, "%2D", "-")
current = Replace(current, "%2d", "-")
current = Replace(current, "%25", "%")

NormalizeSlug = current
End Function


'=======================================================================================================================
' Adapted from Tolerable library


+ 13
- 0
core/router.wsc Прегледај датотеку

@@ -165,6 +165,19 @@ Private Function NormalizePath(path)
cleaned = Left(cleaned, Len(cleaned) - 1)
Loop

On Error Resume Next
Do
Dim decoded
decoded = Server.URLDecode(cleaned)
If Err.Number <> 0 Then
Err.Clear
Exit Do
End If
If decoded = cleaned Then Exit Do
cleaned = LCase(decoded)
Loop
On Error GoTo 0

NormalizePath = cleaned
End Function



+ 4
- 2
public/Default.asp Прегледај датотеку

@@ -33,11 +33,13 @@
router.AddRoute "GET", "/admin", "AdminController", "Index"
router.AddRoute "GET", "/admin/posts", "AdminController", "Posts"
router.AddRoute "GET", "/admin/categories", "AdminController", "Categories"
router.AddRoute "GET", "/admin/ai-prompt", "AdminController", "AIPrompt"
router.AddRoute "POST", "/admin/ai-prompt", "AdminController", "UpdateAIPrompt"
router.AddRoute "POST", "/admin/posts/{id}/publish", "AdminController", "PublishPost"
router.AddRoute "POST", "/admin/posts/{id}/unpublish", "AdminController", "UnpublishPost"
router.AddRoute "POST", "/admin/posts/{id}/ai", "AdminController", "GenerateAIContent"

' Dispatch the request (resolves route and executes controller action)
MVC.DispatchRequest Request.ServerVariables("REQUEST_METHOD"), _
TrimQueryParams(Request.ServerVariables("HTTP_X_ORIGINAL_URL"))
MVC.DispatchRequest Request.ServerVariables("REQUEST_METHOD"), _
TrimQueryParams(DecodeUrlPath(Request.ServerVariables("HTTP_X_ORIGINAL_URL")))
%>

+ 3
- 0
public/web.config Прегледај датотеку

@@ -48,6 +48,9 @@

<!-- Model name to send to the Abacus RouteLLM API -->
<add key="AbacusModel" value="route-llm" />

<!-- Editable prompt template used to generate AI post content -->
<add key="AbacusGenerationPrompt" value="You write clear, engaging blog post content for a classic ASP blog. Return only valid JSON with two keys: summary and body. Summary must be 1 to 2 sentences. Body must be 3 to 5 short paragraphs separated by blank lines. Do not use markdown fences, bullets, or code blocks.&#10;&#10;Create blog content for this post title: {TITLE}&#10;Existing summary: {SUMMARY}&#10;Existing body: {BODY}&#10;Keep the title unchanged. Make the content readable and helpful for a general audience." />
</appSettings>

<system.webServer>


Loading…
Откажи
Сачувај

Powered by TurnKey Linux.