Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateDictionaryAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public override TemplateDataAccessor Index(TemplateDataAccessor index)
return Property(index.ToString());
}

public override bool HasProperty(string name)
{
return _dictionary.ContainsKey(name);
}

public override TemplateDataAccessor Property(string key)
{
if (_dictionary.TryGetValue(key, out var accessor))
Expand Down
5 changes: 5 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateObjectAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public TemplateObjectAccessor(object target, DataAccessorCreationOptions options
return accessors;
}

public override bool HasProperty(string name)
{
return _propertyAccessors.ContainsKey(name);
}

public override TemplateDataAccessor Property(string key)
{
if (_propertyAccessors.TryGetValue(key, out var accessor))
Expand Down
7 changes: 1 addition & 6 deletions src/LLTSharp/ITemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@ namespace LLTSharp
/// <summary>
/// Interface for a template that can be used to generate contents.
/// </summary>
public interface ITemplate
public interface ITemplate : IMetadataProvider
{
/// <summary>
/// Gets the metadata associated with this template.
/// </summary>
public IMetadataCollection Metadata { get; }

/// <summary>
/// Renders the template with the given context.
/// </summary>
Expand Down
6 changes: 4 additions & 2 deletions src/LLTSharp/ITemplateParser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using LLTSharp.Metadata;
using System;
using System.Collections.Generic;
using System.Text;

Expand All @@ -13,7 +14,8 @@ public interface ITemplateParser
/// Parses a prompt template string into a <see cref="ITemplate"/> objects.
/// </summary>
/// <param name="templateString">The prompt template string to parse.</param>
/// <param name="metadataFactories">Optional metadata factories to use for parsing.</param>
/// <returns>A collection of <see cref="ITemplate"/> objects representing the parsed templates.</returns>
IEnumerable<ITemplate> Parse(string templateString);
IEnumerable<ITemplate> Parse(string templateString, IEnumerable<MetadataFactory>? metadataFactories = null);
}
}
48 changes: 17 additions & 31 deletions src/LLTSharp/LLTParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class LLTParser : ITemplateParser
private class LLTParsingContext
{
public TemplateLibrary LocalLibrary { get; set; }
public IEnumerable<MetadataFactory> MetadataFactories { get; set; }
}

private static readonly Parser _parser;
Expand Down Expand Up @@ -697,30 +698,23 @@ private static void DeclareMainRules(ParserBuilder builder)
.Rule("constant_object")
.Transform(v =>
{
var ctx = v.GetParsingParameter<LLTParsingContext>();
var factories = ctx.MetadataFactories;

var obj = v.GetValue<TemplateDictionaryAccessor>(2);
var metadata = new List<IMetadata>();
var additionalMetadata = new AdditionalMetadata();

foreach (var pair in obj.Dictionary)
{
switch (pair.Key)
{
case "lang":
metadata.Add(new LanguageMetadata(new Locale.LanguageCode(pair.Value.ToString())));
break;
case "model":
metadata.Add(new TargetModelMetadata(pair.Value.ToString()));
break;
case "model_family":
metadata.Add(new TargetModelFamilyMetadata(pair.Value.ToString()));
IMetadata? result = null;
foreach (var factory in factories)
if (factory.TryCreateMetadata(pair.Key, pair.Value, out result))
break;
case "version":
metadata.Add(new VersionMetadata((int)((double)pair.Value.GetValue())));
break;
default:
additionalMetadata.Set(pair.Key, pair.Value.GetValue());
break;
}
if (result != null)
metadata.Add(result);
else
additionalMetadata.Set(pair.Key, pair.Value.GetValue());
}

if (additionalMetadata.Count > 0)
Expand Down Expand Up @@ -770,21 +764,13 @@ static LLTParser()
_parser = builder.Build();
}

public ParsedRuleResultBase ParseAST(string templateString)
public IEnumerable<ITemplate> Parse(string templateString, IEnumerable<MetadataFactory>? metadataFactories = null)
{
var ctx = new LLTParsingContext { LocalLibrary = new TemplateLibrary() };
return _parser.Parse(templateString, ctx);
}

public ParsedRuleResultBase ParseOptimizedAST(string templateString)
{
var ctx = new LLTParsingContext { LocalLibrary = new TemplateLibrary() };
return _parser.Parse(templateString, ctx).Optimized(ParseTreeOptimization.Default);
}

public IEnumerable<ITemplate> Parse(string templateString)
{
var ctx = new LLTParsingContext { LocalLibrary = new TemplateLibrary() };
var ctx = new LLTParsingContext
{
LocalLibrary = new TemplateLibrary(),
MetadataFactories = metadataFactories?.ToList() ?? Enumerable.Empty<MetadataFactory>()
};
return _parser.Parse(templateString, ctx).GetValue<IEnumerable<ITemplate>>();
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/LLTSharp/LLTSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<PropertyGroup>
<PackageId>LLTSharp</PackageId>
<Version>1.2.2</Version>
<Version>1.2.3</Version>
<Authors>Roman K.</Authors>
<Company>RomeCore</Company>
<Product>LLTSharp</Product>
Expand Down
71 changes: 71 additions & 0 deletions src/LLTSharp/Locale/HierarchicalLanguageFallbackScheme.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace LLTSharp.Locale
{
/// <summary>
/// Provides a hierarchical language fallback scheme that walks up the language tag hierarchy (e.g., en-US → en)
/// and then tries any available sibling variant of the same language root before falling back to a default or the first available language.
/// </summary>
public class HierarchicalLanguageFallbackScheme : ILanguageFallbackScheme
{
// Да, да, это нейрослоп

private readonly LanguageCode? _defaultLanguage;

/// <summary>
/// Creates a new instance of the scheme.
/// </summary>
/// <param name="defaultLanguage">
/// Optional default language code to be used if the target language and none of its linguistic relatives are available.
/// If <see langword="null"/>, the first available language from the collection will be returned as a last resort.
/// </param>
public HierarchicalLanguageFallbackScheme(LanguageCode? defaultLanguage = null)
{
_defaultLanguage = defaultLanguage;
}

public LanguageCode GetFallbackLanguage(LanguageCode targetLanguage, IEnumerable<LanguageCode> availableLanguages)
{
if (availableLanguages == null)
throw new ArgumentNullException(nameof(availableLanguages));

// Materialise to a list to avoid multiple enumeration.
List<LanguageCode> availableList = availableLanguages as List<LanguageCode> ?? availableLanguages.ToList();

if (availableList.Count == 0)
throw new ArgumentException("Available languages collection is empty.", nameof(availableLanguages));

// 1. Exact match is already the best choice.
if (availableList.Any(l => l == targetLanguage))
return targetLanguage;

// 2. Walk up the parent chain: e.g., zh-Hans-CN → zh-Hans → zh
LanguageCode current = targetLanguage;
while (true)
{
LanguageCode parent = current.GetSuperLanguage();
if (parent == current)
break;

if (availableList.Any(l => l == parent))
return parent;

current = parent;
}

// 3. Look for any sibling belonging to the same root language (e.g., fr-FR when fr-CA was requested)
var sibling = availableList.FirstOrDefault(l => l.IsSubLanguageOf(current));
if (sibling.FullCode != null)
return sibling;

// 4. Fall back to the explicitly configured default language (if available).
if (_defaultLanguage.HasValue && availableList.Any(l => l == _defaultLanguage.Value))
return _defaultLanguage.Value;

// 5. Ultimate fallback – return the first language from the available set.
return availableList[0];
}
}
}
2 changes: 1 addition & 1 deletion src/LLTSharp/Locale/MajorLanguageFallbackScheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public LanguageCode GetFallbackLanguage(LanguageCode targetLanguage, IEnumerable
var hashSet = new HashSet<LanguageCode>(availableLanguages);
hashSet.IntersectWith(LanguageGroup.MajorWorldLanguages);

if (hashSet.Any())
if (hashSet.Count > 0)
return hashSet.First();

return availableLanguages.First();
Expand Down
21 changes: 21 additions & 0 deletions src/LLTSharp/Metadata/Factories/LanguageMetadataFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using LLTSharp.Metadata.Types;
using System;
using System.Collections.Generic;
using System.Text;

namespace LLTSharp.Metadata.Factories
{
public class LanguageMetadataFactory : MetadataFactory
{
public override bool TryCreateMetadata(string key, TemplateDataAccessor value, out IMetadata metadata)
{
if (key == "lang")
{
metadata = new LanguageMetadata(value.ToString());
return true;
}
metadata = null;
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using LLTSharp.Metadata.Types;

namespace LLTSharp.Metadata.Factories
{
public class TargetModelFamilyMetadataFactory : MetadataFactory
{
public override bool TryCreateMetadata(string key, TemplateDataAccessor value, out IMetadata metadata)
{
if (key == "model_family")
{
metadata = new TargetModelFamilyMetadata(value.ToString());
return true;
}
metadata = null;
return false;
}
}
}
18 changes: 18 additions & 0 deletions src/LLTSharp/Metadata/Factories/TargetModelMetadataFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using LLTSharp.Metadata.Types;

namespace LLTSharp.Metadata.Factories
{
public class TargetModelMetadataFactory : MetadataFactory
{
public override bool TryCreateMetadata(string key, TemplateDataAccessor value, out IMetadata metadata)
{
if (key == "model")
{
metadata = new TargetModelMetadata(value.ToString());
return true;
}
metadata = null;
return false;
}
}
}
19 changes: 19 additions & 0 deletions src/LLTSharp/Metadata/Factories/VersionMetadataFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using LLTSharp.Metadata.Types;
using System;

namespace LLTSharp.Metadata.Factories
{
public class VersionMetadataFactory : MetadataFactory
{
public override bool TryCreateMetadata(string key, TemplateDataAccessor value, out IMetadata metadata)
{
if (key == "version")
{
metadata = new VersionMetadata(Version.Parse(value.ToString()));
return true;
}
metadata = null;
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
using System.Linq;
using System.Text;
using LLTSharp.Locale;
using LLTSharp.Metadata.Types;

namespace LLTSharp.Metadata
namespace LLTSharp.Metadata.FallbackSchemes
{
/// <summary>
/// A fallback scheme for handling language metadata when no specific information is available.
Expand Down
18 changes: 18 additions & 0 deletions src/LLTSharp/Metadata/MetadataFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace LLTSharp.Metadata
{
public abstract class MetadataFactory
{
/// <summary>
/// Tries to create a new instance of <see cref="IMetadata"/> based on the provided key and value.
/// </summary>
/// <param name="key">The key associated with the metadata.</param>
/// <param name="value">The value associated with the metadata.</param>
/// <param name="metadata">When this method returns, contains the newly created instance of <see cref="IMetadata"/> if successful; otherwise, null. This parameter is passed uninitialized.</param>
/// <returns>true if a new instance of <see cref="IMetadata"/> was created successfully; otherwise, false.</returns>
public abstract bool TryCreateMetadata(string key, TemplateDataAccessor value, out IMetadata metadata);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
using System.Collections.Generic;
using System.Text;
using LLTSharp.Locale;
using LLTSharp.Metadata;

namespace LLTSharp.Metadata
namespace LLTSharp.Metadata.Types
{
/// <summary>
/// The metadata for language-related information.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using LLTSharp.Metadata;

namespace LLTSharp.Metadata
namespace LLTSharp.Metadata.Types
{
/// <summary>
/// The metadata for target model family-related information.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using LLTSharp.Metadata;

namespace LLTSharp.Metadata
namespace LLTSharp.Metadata.Types
{
/// <summary>
/// The metadata for target model-related information.
Expand Down
Loading
Loading