mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-12 22:33:48 +00:00
Carry sources into exported code blocks
This commit is contained in:
4 files changed
+222
-17
No files matched your search
@@ -67,26 +67,65 @@ public static class IContentExtensions
|
||||
return false;
|
||||
}
|
||||
|
||||
var answer = text.Text.Trim();
|
||||
var sources = text.Sources.ToExportMarkdown(keepPageAnchors);
|
||||
if (sources.Length == 0)
|
||||
{
|
||||
markdown = answer;
|
||||
return true;
|
||||
}
|
||||
markdown = AppendSources(text.Text.Trim(), text.Sources.ToExportMarkdown(keepPageAnchors));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (answer.Length == 0)
|
||||
{
|
||||
markdown = sources;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Reads one file out of this content the way it leaves AI Studio, together with the sources
|
||||
/// the answer rests on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A code block saved on its own came out of the same answer, so it rests on the same sources
|
||||
/// and takes them along. How depends on the format. Markdown is what the source list is written
|
||||
/// in, so a Markdown text gets it just as the entire answer does. A web page or a LaTeX document
|
||||
/// gets it as a comment at its end: anything visible would have to be woven into markup the
|
||||
/// model wrote. A fragment has no body to put it in, a page may hide whatever lies outside its
|
||||
/// layout, and one underscore in a title is enough to stop a LaTeX run. A comment breaks
|
||||
/// neither, and whoever opens the file finds it. A table gets no sources at all, since it has
|
||||
/// no column a link list would fit into.
|
||||
///
|
||||
/// Apart from that, the file is what the model wrote, scripts of a web page included. Saving it
|
||||
/// is what the user chose to do; the chat still never renders it.
|
||||
/// </remarks>
|
||||
/// <param name="content">The content the file was found in.</param>
|
||||
/// <param name="file">The file, as PlainFileExport.ExtractFiles read it out of this content.</param>
|
||||
/// <returns>The content of the file to write.</returns>
|
||||
public static string ToExportContent(this IContent content, MessageFile file)
|
||||
{
|
||||
if (file.Format.IsTabular())
|
||||
return file.Content;
|
||||
|
||||
var sources = content.Sources.ToExportMarkdown(file.Format.FollowsPageAnchors());
|
||||
if (file.Format is FileExportFormat.MARKDOWN)
|
||||
return AppendSources(file.Content, sources);
|
||||
|
||||
if (sources.Length is 0 || !file.Format.TryToComment(sources, out var comment))
|
||||
return file.Content;
|
||||
|
||||
return $"{file.Content}{Environment.NewLine}{Environment.NewLine}{comment}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts the source list below a Markdown text.
|
||||
/// </summary>
|
||||
/// <param name="markdown">The Markdown text.</param>
|
||||
/// <param name="sources">The source list as SourceExtensions.ToExportMarkdown writes it, or an
|
||||
/// empty string when there are no sources.</param>
|
||||
/// <returns>The text followed by its sources.</returns>
|
||||
private static string AppendSources(string markdown, string sources)
|
||||
{
|
||||
if (sources.Length == 0)
|
||||
return markdown;
|
||||
|
||||
if (markdown.Length == 0)
|
||||
return sources;
|
||||
|
||||
//
|
||||
// The blank line is not cosmetic: it ends a paragraph, a list, a table, or a block quote, so
|
||||
// that the heading of the source list stands on its own instead of being pulled into the
|
||||
// last block of the answer.
|
||||
//
|
||||
markdown = $"{Markdown.CloseOpenCodeFence(answer)}{Environment.NewLine}{Environment.NewLine}{sources}";
|
||||
return true;
|
||||
return $"{Markdown.CloseOpenCodeFence(markdown)}{Environment.NewLine}{Environment.NewLine}{sources}";
|
||||
}
|
||||
}
|
||||
@@ -241,6 +241,42 @@ public static class FileExportFormatExtensions
|
||||
_ => WITHOUT_BYTE_ORDER_MARK,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a text into a comment of the format: whoever opens the file in an editor reads it,
|
||||
/// while a browser or a LaTeX run skips it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A comment in HTML, and so in Markdown, ends at the first --> it holds, and a browser takes
|
||||
/// --!> for the same; the rest of the text would spill onto the page from there. The title of
|
||||
/// a web page may hold either, so a space goes in before the bracket, which keeps the text
|
||||
/// readable and ends nothing. Every other pair of dashes stays, because a web address may carry
|
||||
/// one, as in the xn-- of a domain with an umlaut. A LaTeX comment has no end to watch for: it
|
||||
/// runs to the end of its line, so every line starts one.
|
||||
/// </remarks>
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="text">The text to put into the comment.</param>
|
||||
/// <param name="comment">The comment, or an empty string when the format has none.</param>
|
||||
/// <returns>True, when the format knows comments.</returns>
|
||||
public static bool TryToComment(this FileExportFormat format, string text, out string comment)
|
||||
{
|
||||
var lines = text.TrimEnd().ReplaceLineEndings("\n").Split('\n');
|
||||
switch (format)
|
||||
{
|
||||
case FileExportFormat.HTML or FileExportFormat.MARKDOWN:
|
||||
var commentText = string.Join(Environment.NewLine, lines).Replace("-->", "-- >").Replace("--!>", "--! >");
|
||||
comment = $"<!--{Environment.NewLine}{commentText}{Environment.NewLine}-->";
|
||||
return true;
|
||||
|
||||
case FileExportFormat.LATEX:
|
||||
comment = string.Join(Environment.NewLine, lines.Select(line => line.Length is 0 ? "%" : $"% {line}"));
|
||||
return true;
|
||||
|
||||
default:
|
||||
comment = string.Empty;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a link into a local file may name the page it points at.
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user