Skip to content

Commit 98e5e05

Browse files
authored
Add an API endpoint to retrieve all builds for all engines (#826)
1 parent 129467e commit 98e5e05

14 files changed

Lines changed: 1011 additions & 416 deletions

File tree

src/Serval/src/Serval.Client/Client.g.cs

Lines changed: 513 additions & 239 deletions
Large diffs are not rendered by default.

src/Serval/src/Serval.Translation/Configuration/IMongoDataAccessConfiguratorExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ await c.UpdateManyAsync(
3030
"translation.builds",
3131
init: static async c =>
3232
{
33+
await c.Indexes.CreateOrUpdateAsync(
34+
new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.Owner))
35+
);
3336
await c.Indexes.CreateOrUpdateAsync(
3437
new CreateIndexModel<Build>(Builders<Build>.IndexKeys.Ascending(b => b.EngineRef))
3538
);
@@ -49,6 +52,15 @@ await c.UpdateManyAsync(
4952
),
5053
new BsonDocument("$rename", new BsonDocument("percentCompleted", "progress"))
5154
);
55+
// migrate by duplicating the owner field from build
56+
await c.Aggregate()
57+
.Match(Builders<Build>.Filter.Exists(b => b.Owner, false))
58+
.Lookup("translation.engines", "engineRef", "_id", "engine")
59+
.Unwind("engine", new AggregateUnwindOptions<BsonDocument> { PreserveNullAndEmptyArrays = true })
60+
.AppendStage<BsonDocument>(new BsonDocument("$set", new BsonDocument("owner", "$engine.owner")))
61+
.AppendStage<BsonDocument>(new BsonDocument("$unset", "engine"))
62+
.Merge(c, new MergeStageOptions<Build> { WhenMatched = MergeStageWhenMatched.Replace })
63+
.ToListAsync();
5264
}
5365
);
5466
configurator.AddRepository<Pretranslation>(
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
namespace Serval.Translation.Controllers;
2+
3+
[ApiVersion(1.0)]
4+
[Route("api/v{version:apiVersion}/translation/builds")]
5+
[OpenApiTag("Translation Engines")]
6+
public class TranslationBuildsController(
7+
IAuthorizationService authService,
8+
IBuildService buildService,
9+
IUrlService urlService
10+
) : TranslationControllerBase(authService, urlService)
11+
{
12+
private readonly IBuildService _buildService = buildService;
13+
14+
/// <summary>
15+
/// Get all builds for your translation engines that are created after the specified date.
16+
/// </summary>
17+
/// <param name="createdAfter">The date and time in UTC that the builds were created after (optional).</param>
18+
/// <param name="cancellationToken"></param>
19+
/// <response code="200">The engines</response>
20+
/// <response code="401">The client is not authenticated.</response>
21+
/// <response code="403">The authenticated client cannot perform the operation.</response>
22+
/// <response code="503">A necessary service is currently unavailable. Check `/health` for more details.</response>
23+
[Authorize(Scopes.ReadTranslationEngines)]
24+
[HttpGet]
25+
[ProducesResponseType(StatusCodes.Status200OK)]
26+
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
27+
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
28+
[ProducesResponseType(typeof(void), StatusCodes.Status503ServiceUnavailable)]
29+
public async Task<IEnumerable<TranslationBuildDto>> GetAllBuildsCreatedAfterAsync(
30+
[FromQuery(Name = "created-after")] DateTime? createdAfter,
31+
CancellationToken cancellationToken
32+
)
33+
{
34+
if (createdAfter is null)
35+
{
36+
return (await _buildService.GetAllAsync(Owner, cancellationToken)).Select(Map);
37+
}
38+
else
39+
{
40+
return (await _buildService.GetAllCreatedAfterAsync(Owner, createdAfter, cancellationToken)).Select(Map);
41+
}
42+
}
43+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
namespace Serval.Translation.Controllers;
2+
3+
#pragma warning disable CS0612 // Type or member is obsolete
4+
5+
public abstract class TranslationControllerBase(IAuthorizationService authService, IUrlService urlService)
6+
: ServalControllerBase(authService)
7+
{
8+
private readonly IUrlService _urlService = urlService;
9+
10+
protected TranslationBuildDto Map(Build source) =>
11+
new TranslationBuildDto
12+
{
13+
Id = source.Id,
14+
Url = _urlService.GetUrl(Endpoints.GetTranslationBuild, new { id = source.EngineRef, buildId = source.Id }),
15+
Revision = source.Revision,
16+
Name = source.Name,
17+
Engine = new ResourceLinkDto
18+
{
19+
Id = source.EngineRef,
20+
Url = _urlService.GetUrl(Endpoints.GetTranslationEngine, new { id = source.EngineRef })
21+
},
22+
TrainOn = source.TrainOn?.Select(s => Map(source.EngineRef, s)).ToList(),
23+
Pretranslate = source.Pretranslate?.Select(s => Map(source.EngineRef, s)).ToList(),
24+
Step = source.Step,
25+
PercentCompleted = source.Progress,
26+
Progress = source.Progress,
27+
Message = source.Message,
28+
QueueDepth = source.QueueDepth,
29+
State = source.State,
30+
DateFinished = source.DateFinished,
31+
Options = source.Options,
32+
DeploymentVersion = source.DeploymentVersion,
33+
ExecutionData = Map(source.ExecutionData),
34+
Phases = source.Phases?.Select(Map).ToList(),
35+
Analysis = source.Analysis?.Select(Map).ToList(),
36+
};
37+
38+
private PretranslateCorpusDto Map(string engineId, PretranslateCorpus source) =>
39+
new PretranslateCorpusDto
40+
{
41+
Corpus =
42+
source.CorpusRef != null
43+
? new ResourceLinkDto
44+
{
45+
Id = source.CorpusRef,
46+
Url = _urlService.GetUrl(
47+
Endpoints.GetTranslationCorpus,
48+
new { id = engineId, corpusId = source.CorpusRef }
49+
)
50+
}
51+
: null,
52+
TextIds = source.TextIds,
53+
ScriptureRange = source.ScriptureRange,
54+
ParallelCorpus =
55+
source.ParallelCorpusRef != null
56+
? new ResourceLinkDto
57+
{
58+
Id = source.ParallelCorpusRef,
59+
Url = _urlService.GetUrl(
60+
Endpoints.GetParallelTranslationCorpus,
61+
new { id = engineId, parallelCorpusId = source.ParallelCorpusRef }
62+
)
63+
}
64+
: null,
65+
SourceFilters = source.SourceFilters?.Select(Map).ToList()
66+
};
67+
68+
private TrainingCorpusDto Map(string engineId, TrainingCorpus source) =>
69+
new TrainingCorpusDto
70+
{
71+
Corpus =
72+
source.CorpusRef != null
73+
? new ResourceLinkDto
74+
{
75+
Id = source.CorpusRef,
76+
Url = _urlService.GetUrl(
77+
Endpoints.GetTranslationCorpus,
78+
new { id = engineId, corpusId = source.CorpusRef }
79+
)
80+
}
81+
: null,
82+
TextIds = source.TextIds,
83+
ScriptureRange = source.ScriptureRange,
84+
ParallelCorpus =
85+
source.ParallelCorpusRef != null
86+
? new ResourceLinkDto
87+
{
88+
Id = source.ParallelCorpusRef,
89+
Url = _urlService.GetUrl(
90+
Endpoints.GetParallelTranslationCorpus,
91+
new { id = engineId, parallelCorpusId = source.ParallelCorpusRef }
92+
)
93+
}
94+
: null,
95+
SourceFilters = source.SourceFilters?.Select(Map).ToList(),
96+
TargetFilters = source.TargetFilters?.Select(Map).ToList()
97+
};
98+
99+
private ParallelCorpusFilterDto Map(ParallelCorpusFilter source) =>
100+
new ParallelCorpusFilterDto
101+
{
102+
Corpus = new ResourceLinkDto
103+
{
104+
Id = source.CorpusRef,
105+
Url = _urlService.GetUrl(Endpoints.GetCorpus, new { id = source.CorpusRef })
106+
},
107+
TextIds = source.TextIds,
108+
ScriptureRange = source.ScriptureRange
109+
};
110+
111+
private static PhaseDto Map(BuildPhase source) =>
112+
new PhaseDto
113+
{
114+
Stage = (PhaseStage)source.Stage,
115+
Step = source.Step,
116+
StepCount = source.StepCount
117+
};
118+
119+
private static ParallelCorpusAnalysisDto Map(ParallelCorpusAnalysis source) =>
120+
new ParallelCorpusAnalysisDto
121+
{
122+
ParallelCorpusRef = source.ParallelCorpusRef,
123+
TargetQuoteConvention = source.TargetQuoteConvention,
124+
SourceQuoteConvention = "ignore",
125+
CanDenormalizeQuotes = source.TargetQuoteConvention != ""
126+
};
127+
128+
private static ExecutionDataDto Map(ExecutionData source) =>
129+
new ExecutionDataDto
130+
{
131+
TrainCount = source.TrainCount ?? 0,
132+
PretranslateCount = source.PretranslateCount ?? 0,
133+
Warnings = source.Warnings ?? [],
134+
EngineSourceLanguageTag = source.EngineSourceLanguageTag,
135+
EngineTargetLanguageTag = source.EngineTargetLanguageTag,
136+
ResolvedSourceLanguage = source.ResolvedSourceLanguage,
137+
ResolvedTargetLanguage = source.ResolvedTargetLanguage,
138+
};
139+
}
140+
141+
#pragma warning restore CS0612 // Type or member is obsolete

0 commit comments

Comments
 (0)