Add CV structure analysis groundwork
This commit is contained in:
@@ -37,6 +37,8 @@ public sealed class ProfileCvController : ControllerBase
|
||||
}
|
||||
|
||||
public sealed record RewriteSectionRequest(string SectionName, string? Style, string? TargetRole);
|
||||
public sealed record ParseCvRequest(string? Text);
|
||||
public sealed record ParsedCvSectionDto(string Name, string Content, int WordCount);
|
||||
|
||||
[HttpPost("upload")]
|
||||
[RequestSizeLimit(MaxFileSizeBytes)]
|
||||
@@ -146,6 +148,22 @@ public sealed class ProfileCvController : ControllerBase
|
||||
return Ok(new { sectionName, style, targetRole, text = rewritten.Trim() });
|
||||
}
|
||||
|
||||
[HttpPost("parse")]
|
||||
public async Task<ActionResult<object>> Parse([FromBody] ParseCvRequest? request)
|
||||
{
|
||||
var user = await _users.GetUserAsync(User);
|
||||
if (user is null) return Unauthorized();
|
||||
|
||||
var source = string.IsNullOrWhiteSpace(request?.Text) ? user.ProfileCvText : request!.Text;
|
||||
if (string.IsNullOrWhiteSpace(source)) return BadRequest("Add or import CV text before parsing sections.");
|
||||
|
||||
var sections = ParseSections(source)
|
||||
.Select(section => new ParsedCvSectionDto(section.Name, section.Content, CountWords(section.Content)))
|
||||
.ToList();
|
||||
|
||||
return Ok(new { sections, totalWords = CountWords(source) });
|
||||
}
|
||||
|
||||
[HttpPost("improve")]
|
||||
public async Task<IActionResult> Improve()
|
||||
{
|
||||
@@ -174,6 +192,80 @@ public sealed class ProfileCvController : ControllerBase
|
||||
return Ok(new { improved = true, characters = user.ProfileCvText.Length, text = user.ProfileCvText });
|
||||
}
|
||||
|
||||
private static int CountWords(string? text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text)) return 0;
|
||||
return text.Trim().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries).Length;
|
||||
}
|
||||
|
||||
private static List<(string Name, string Content)> ParseSections(string source)
|
||||
{
|
||||
var lines = source.Replace("\r\n", "\n").Split('\n');
|
||||
var aliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["professional summary"] = "Professional Summary",
|
||||
["summary"] = "Professional Summary",
|
||||
["profile"] = "Professional Summary",
|
||||
["core skills"] = "Core Skills",
|
||||
["skills"] = "Core Skills",
|
||||
["technical skills"] = "Core Skills",
|
||||
["experience"] = "Experience Highlights",
|
||||
["experience highlights"] = "Experience Highlights",
|
||||
["work experience"] = "Experience Highlights",
|
||||
["selected achievements"] = "Selected Achievements",
|
||||
["achievements"] = "Selected Achievements",
|
||||
["projects"] = "Projects",
|
||||
["education"] = "Education",
|
||||
["certifications"] = "Certifications",
|
||||
["certificates"] = "Certifications",
|
||||
};
|
||||
|
||||
var sections = new List<(string Name, List<string> Lines)>();
|
||||
var currentName = "General";
|
||||
var currentLines = new List<string>();
|
||||
|
||||
void Flush()
|
||||
{
|
||||
var content = string.Join("\n", currentLines).Trim();
|
||||
if (!string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
sections.Add((currentName, new List<string>(currentLines)));
|
||||
}
|
||||
currentLines.Clear();
|
||||
}
|
||||
|
||||
foreach (var raw in lines)
|
||||
{
|
||||
var line = raw.Trim();
|
||||
var normalized = line.TrimEnd(':').Trim();
|
||||
var looksLikeHeading = normalized.Length > 0
|
||||
&& normalized.Length <= 40
|
||||
&& !normalized.Contains('.')
|
||||
&& aliases.ContainsKey(normalized.ToLowerInvariant());
|
||||
|
||||
if (looksLikeHeading)
|
||||
{
|
||||
Flush();
|
||||
currentName = aliases[normalized.ToLowerInvariant()];
|
||||
continue;
|
||||
}
|
||||
|
||||
currentLines.Add(raw);
|
||||
}
|
||||
|
||||
Flush();
|
||||
|
||||
if (sections.Count == 0)
|
||||
{
|
||||
return new List<(string Name, string Content)> { ("General", source.Trim()) };
|
||||
}
|
||||
|
||||
return sections
|
||||
.Select(section => (section.Name, string.Join("\n", section.Lines).Trim()))
|
||||
.Where(section => !string.IsNullOrWhiteSpace(section.Item2))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static async Task<string> ExtractTextAsync(IFormFile file, string extension)
|
||||
{
|
||||
if (string.Equals(extension, ".txt", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".md", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
Reference in New Issue
Block a user