mirror of
				https://github.com/severian-dev/sucker.severian.dev.git
				synced 2025-10-28 04:35:45 +00:00 
			
		
		
		
	chore: 1.7
This commit is contained in:
		| @@ -4,6 +4,7 @@ Check package.json for commands, I can't be bothered. | ||||
|  | ||||
| ### Changelog | ||||
|  | ||||
| - 1.7: Handling for nested XML character tags | ||||
| - 1.6: First message formatting, copy button for first message and other fields | ||||
| - 1.5: {{user}} substitution for user persona name | ||||
| - 1.4: Mooth just keeps finding bugs, damn. | ||||
|   | ||||
| @@ -40,49 +40,118 @@ interface PersonaMatch { | ||||
|  | ||||
| function findTagsBetween(content: string, startMarker: string): PersonaMatch[] { | ||||
|   const startMarkerTag = `<${startMarker}>`; | ||||
|    | ||||
|  | ||||
|   const startIdx = content.indexOf(startMarkerTag); | ||||
|   if (startIdx === -1) return []; | ||||
|    | ||||
|  | ||||
|   const scenarioIdx = content.indexOf("<scenario>"); | ||||
|   const exampleIdx = content.indexOf("<example_dialogs>"); | ||||
|    | ||||
|  | ||||
|   let endIdx = content.length; | ||||
|   if (scenarioIdx !== -1) endIdx = Math.min(endIdx, scenarioIdx); | ||||
|   if (exampleIdx !== -1) endIdx = Math.min(endIdx, exampleIdx); | ||||
|    | ||||
|  | ||||
|   const section = content.slice(startIdx, endIdx); | ||||
|   const matches: PersonaMatch[] = []; | ||||
|    | ||||
|   const tagPattern = /<([^/>\s][^>]*)>([\s\S]*?)<\/\1>/g; | ||||
|   let match; | ||||
|    | ||||
|   try { | ||||
|     while ((match = tagPattern.exec(section)) !== null) { | ||||
|       // Skip the system tag | ||||
|       if (match[1] !== startMarker) { | ||||
|         matches.push({ | ||||
|           tag: match[1].trim(), | ||||
|           content: match[2].trim() | ||||
|         }); | ||||
|  | ||||
|   let position = 0; | ||||
|  | ||||
|   while (position < section.length) { | ||||
|     const tagStart = section.indexOf("<", position); | ||||
|     if (tagStart === -1) break; | ||||
|  | ||||
|     const tagNameEnd = section.indexOf(">", tagStart); | ||||
|     if (tagNameEnd === -1) break; | ||||
|  | ||||
|     const tagName = section.substring(tagStart + 1, tagNameEnd).trim(); | ||||
|  | ||||
|     if (tagName.startsWith("/") || tagName === startMarker) { | ||||
|       position = tagNameEnd + 1; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     const openTag = `<${tagName}>`; | ||||
|     const closeTag = `</${tagName}>`; | ||||
|  | ||||
|     let openTagPos = tagStart; | ||||
|     let closeTagPos = -1; | ||||
|     let tagCount = 1; | ||||
|     let searchPos = tagNameEnd + 1; | ||||
|  | ||||
|     while (searchPos < section.length && tagCount > 0) { | ||||
|       const nextOpen = section.indexOf(openTag, searchPos); | ||||
|       const nextClose = section.indexOf(closeTag, searchPos); | ||||
|  | ||||
|       if (nextClose === -1) break; | ||||
|  | ||||
|       if (nextOpen !== -1 && nextOpen < nextClose) { | ||||
|         tagCount++; | ||||
|         searchPos = nextOpen + openTag.length; | ||||
|       } else { | ||||
|         tagCount--; | ||||
|         searchPos = nextClose + closeTag.length; | ||||
|  | ||||
|         if (tagCount === 0) { | ||||
|           closeTagPos = nextClose; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } catch (error) { | ||||
|     console.error("Error during regex execution:", error); | ||||
|  | ||||
|     if (closeTagPos !== -1) { | ||||
|       const tagContent = section.substring(tagNameEnd + 1, closeTagPos); | ||||
|  | ||||
|       matches.push({ | ||||
|         tag: tagName, | ||||
|         content: tagContent.trim(), | ||||
|       }); | ||||
|  | ||||
|       position = closeTagPos + closeTag.length; | ||||
|     } else { | ||||
|       position = tagNameEnd + 1; | ||||
|     } | ||||
|   } | ||||
|    | ||||
|  | ||||
|   return matches; | ||||
| } | ||||
|  | ||||
| function extractBetweenTags(content: string, tag: string): string { | ||||
|   const startTag = `<${tag}>`; | ||||
|   const endTag = `</${tag}>`; | ||||
|  | ||||
|   const startIndex = content.indexOf(startTag); | ||||
|   if (startIndex === -1) return ""; | ||||
|    | ||||
|   const endIndex = content.indexOf(endTag, startIndex); | ||||
|  | ||||
|   // Handle nested tags by counting opening and closing tags | ||||
|   let openTagCount = 1; | ||||
|   let position = startIndex + startTag.length; | ||||
|   let endIndex = -1; | ||||
|  | ||||
|   while (position < content.length && openTagCount > 0) { | ||||
|     const nextOpenTag = content.indexOf(startTag, position); | ||||
|     const nextCloseTag = content.indexOf(endTag, position); | ||||
|  | ||||
|     // No more closing tags found | ||||
|     if (nextCloseTag === -1) break; | ||||
|  | ||||
|     // Found another opening tag before the next closing tag | ||||
|     if (nextOpenTag !== -1 && nextOpenTag < nextCloseTag) { | ||||
|       openTagCount++; | ||||
|       position = nextOpenTag + startTag.length; | ||||
|     } | ||||
|     // Found a closing tag | ||||
|     else { | ||||
|       openTagCount--; | ||||
|       position = nextCloseTag + endTag.length; | ||||
|       // If we've found the matching closing tag for our initial opening tag | ||||
|       if (openTagCount === 0) { | ||||
|         endIndex = nextCloseTag; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (endIndex === -1) return ""; | ||||
|    | ||||
|  | ||||
|   return content.slice(startIndex + startTag.length, endIndex).trim(); | ||||
| } | ||||
|  | ||||
| @@ -96,7 +165,7 @@ function extractCardData(messages: Message[]): CardData { | ||||
|  | ||||
|   // Find all persona tags between system and the first optional tag (scenario or example_dialogs) | ||||
|   const personas = findTagsBetween(content0, "system"); | ||||
|    | ||||
|  | ||||
|   const userPersona = personas[personas.length - 2]; | ||||
|   const charPersona = personas[personas.length - 1]; | ||||
|   const charName = charPersona?.tag || ""; | ||||
| @@ -117,7 +186,11 @@ function extractCardData(messages: Message[]): CardData { | ||||
|     if (field !== "name") { | ||||
|       const val = cardData[field as keyof CardData]; | ||||
|       if (typeof val === "string") { | ||||
|         cardData[field as keyof CardData] = safeReplace(val, userName, "{{user}}"); | ||||
|         cardData[field as keyof CardData] = safeReplace( | ||||
|           val, | ||||
|           userName, | ||||
|           "{{user}}" | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -127,7 +200,11 @@ function extractCardData(messages: Message[]): CardData { | ||||
|     if (field !== "name") { | ||||
|       const val = cardData[field as keyof CardData]; | ||||
|       if (typeof val === "string") { | ||||
|         cardData[field as keyof CardData] = safeReplace(val, charName, "{{char}}"); | ||||
|         cardData[field as keyof CardData] = safeReplace( | ||||
|           val, | ||||
|           charName, | ||||
|           "{{char}}" | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -191,10 +191,9 @@ export default function Home() { | ||||
|       <div className="container mx-auto px-4 py-8"> | ||||
|         <div className="flex justify-between items-center mb-4"> | ||||
|           <div> | ||||
|             <h1 className="text-3xl font-bold">Sucker v1.6</h1> | ||||
|             <h1 className="text-3xl font-bold">Sucker v1.7</h1> | ||||
|             <p className="text-sm text-muted-foreground"> | ||||
|               Wherein Myscell's Not-Unreasonable, Yet Still Annoying, | ||||
|               Request is Delivered with a Heavy Sigh | ||||
|               Handles nested XML character tags now, let me know how it goes. | ||||
|             </p> | ||||
|           </div> | ||||
|           <Button | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Severian
					Severian