Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
christogreeff committed Mar 24, 2024
1 parent 3c88657 commit e88bc63
Show file tree
Hide file tree
Showing 36 changed files with 1,845 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################

.vs
**/bin
**/obj
**/Safetensors.Inspector.UX/Properties/Resources.Designer.cs
**/Safetensors.Inspector.UX/Properties/Resources.resx
**/Safetensors.Inspector.UX/Properties/Settings.Designer.cs
**/Safetensors.Inspector.UX/Properties/Settings.settings
**/Safetensors.Inspector.UX/Properties/PublishProfiles/FolderProfile.pubxml.user
**/publish/*
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Safetensors Inspector
=====================

Safetensors Inspector is a tool that I created to learn the file structures and workings of
safetensors files.

## Important

At present, the following safetensors are supported:

* LoRA
* Metadata

## Examples

### Reading a single file

![](https://github.com/christogreeff/safetensors-inspector/blob/main/documentation/example01.gif)

### Reading a folder full of files

![](https://github.com/christogreeff/safetensors-inspector/blob/main/documentation/example02.gif)

## Releases

See [latest](https://github.com/christogreeff/safetensors-inspector/releases/tag/latest) releases.

## Tools

Additional tooling is (or will be) available in the **tools/** directory.

## Documentation

The offline documentation is (or will be) available in the **documentation/** directory.

## License

Safetensors Inspetor codebase is GPL-3.0 licensed. Please refer to the LICENSE file for detailed information.

## Contributing

Please do.
Binary file added documentation/example01.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/example02.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions publish.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
$signTool="C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe"
$certFolder = "C:\temp\cert\CodeSign\"
$cert = "$($certFolder)kd.pfx"
$pass = Get-Content "$($certFolder)kd.pass"
$exe = ".\publish\Safetensors.Inspector.UX.exe"
$md5 = ".\publish\Safetensors.Inspector.UX.md5"

Remove-Item ".\publish\*" -Recurse -Force

dotnet publish ".\solution\Safetensors.Inspector.sln" /p:PublishProfile=FolderProfile -v q

Remove-Item ".\publish\*.config" -Force

& $signTool sign /tr http://timestamp.digicert.com /f $cert /p $pass /td SHA256 /fd SHA256 $exe
(Get-FileHash $exe -Algorithm MD5).Hash > $md5
42 changes: 42 additions & 0 deletions solution/Safetensors.Core/Helpers/IntHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace Safetensors.Core
{
/// <summary>
/// Int Helper
/// </summary>
public static class IntHelper
{
/// <summary>
/// Size suffixes for file sizes
/// </summary>
private static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

/// <summary>
/// Size suffix for file sizes
/// </summary>
public static string SizeSuffix(this long value, int decimalPlaces = 1)
{
if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); }
if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }

// mag is 0 for bytes, 1 for KB, 2, for MB, etc.
int mag = (int)Math.Log(value, 1024);

// 1L << (mag * 10) == 2 ^ (10 * mag)
// [i.e. the number of bytes in the unit corresponding to mag]
decimal adjustedSize = (decimal)value / (1L << (mag * 10));

// make adjustment when the value is large enough that
// it would round up to 1000 or more
if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
{
mag += 1;
adjustedSize /= 1024;
}

return string.Format("{0:n" + decimalPlaces + "} {1}",
adjustedSize,
SizeSuffixes[mag]);
}
}
}
15 changes: 15 additions & 0 deletions solution/Safetensors.Core/Interfaces/IConfigurationReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Safetensors.Core
{
/// <summary>
/// Safetensor configuration reader interface
/// </summary>
public interface IConfigurationReader
{
/// <summary>
/// Load metadata property configuration
/// </summary>
/// <returns>List of Safetensor metadata properties</returns>

Task<IList<SafetensorsMetadataProperty>?> LoadMetadataPropertyConfigAsync();
}
}
9 changes: 9 additions & 0 deletions solution/Safetensors.Core/Interfaces/ISafetensorsFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Safetensors.Core
{
public interface ISafetensorsFile
{
string Header { get; }
ISafetensorsMetadata Metadata { get; }
string Path { get; }
}
}
10 changes: 10 additions & 0 deletions solution/Safetensors.Core/Interfaces/ISafetensorsMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

namespace Safetensors.Core
{
public interface ISafetensorsMetadata
{
string Description { get; set; }
List<ISafetensorsMetadataProperty> Properties { get; set; }
string PropertyName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Text.Json.Nodes;

namespace Safetensors.Core
{
public interface ISafetensorsMetadataProperty
{
string Description { get; set; }
string? MetadataType { get; set; }
string PropertyName { get; set; }
string Value { get; set; }
JsonNode? ValueEx { get; }
}
}
20 changes: 20 additions & 0 deletions solution/Safetensors.Core/Interfaces/ISafetensorsReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Safetensors.Core
{
/// <summary>
/// Safeensor reader interface
/// </summary>
public interface ISafetensorsReader
{
/// <summary>
/// Initialize the Safetenso reader
/// </summary>
Task InitializeAsync();

/// <summary>
/// Async read of .safetensor file
/// </summary>
/// <param name="path">File path of the .safetensor file</param>
/// <returns>SafetensorFile object</returns>
Task<ISafetensorsFile?> ReadAsync(string path);
}
}
28 changes: 28 additions & 0 deletions solution/Safetensors.Core/Models/Safetensor/SafetensorsFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Safetensors.Core
{
/// <summary>
/// Safetensor file
/// </summary>
/// <remarks>
/// https://huggingface.co/docs/safetensors/en/metadata_parsing
/// https://cran.r-project.org/web/packages/safetensors/safetensors.pdf
/// https://civitai.com/articles/827/safetensors-inspector-google-colab
/// </remarks>
public class SafetensorsFile(string path, string header) : ISafetensorsFile
{
/// <summary>
/// Safetensor file location
/// </summary>
public string Path { get; private set; } = path;

/// <summary>
/// Safetensor raw metadata
/// </summary>
public string Header { get; private set; } = header;

/// <summary>
/// Safetensor metadata
/// </summary>
public ISafetensorsMetadata Metadata { get; private set; } = new SafetensorsMetadata();
}
}
23 changes: 23 additions & 0 deletions solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Safetensors.Core
{
/// <summary>
/// Safetensor metadata
/// </summary>
public class SafetensorsMetadata : ISafetensorsMetadata
{
/// <summary>
/// Default __metadata__ property name
/// </summary>
public string PropertyName { get; set; } = "__metadata__";

/// <summary>
/// Safetensor metadata description
/// </summary>
public string Description { get; set; } = string.Empty;

/// <summary>
/// Safeensor metadata properties
/// </summary>
public List<ISafetensorsMetadataProperty> Properties { get; set; } = [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Text.Json.Nodes;

namespace Safetensors.Core
{
/// <summary>
/// Safeensor metadata property
/// </summary>
public class SafetensorsMetadataProperty : ISafetensorsMetadataProperty
{
/// <summary>
/// Safeensor metadata property name
/// </summary>
public string PropertyName { get; set; } = string.Empty;

/// <summary>
/// Safetenso metadata property description
/// </summary>
public string Description { get; set; } = string.Empty;

/// <summary>
/// Safeensor metadata property value
/// </summary>
public string Value { get; set; } = string.Empty;

/// <summary>
/// Safeensor metadata property value extended
/// </summary>
public JsonNode? ValueEx
{
get
{
return Convert.ToString(MetadataType)?.ToLower() switch
{
"tagfrequency" or
"datasetdirs" => ParseJson(),
_ => null,
};
}
}

/// <summary>
/// Safeensor metadata property type
/// </summary>
public string? MetadataType { get; set; } = string.Empty;

/// <summary>
/// Try parse Json
/// </summary>
/// <returns></returns>
private JsonNode? ParseJson()
{
if (!string.IsNullOrEmpty(Value))
{
var node = JsonNode.Parse(Value);

return node;
}

return null;
}
}
}
10 changes: 10 additions & 0 deletions solution/Safetensors.Core/Safetensors.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DebugType>none</DebugType>
</PropertyGroup>

</Project>
3 changes: 3 additions & 0 deletions solution/Safetensors.Inspector.UX/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions solution/Safetensors.Inspector.UX/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Safetensor.Inspector.UX
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new formSafetensors());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\Publish</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>
Loading

0 comments on commit e88bc63

Please sign in to comment.