microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
samples/migration-bot

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

core/src/Microsoft.Teams.Bot.Apps/Schema/Entities/CitationEntity.cs

385lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json.Serialization;
5
6namespace Microsoft.Teams.Bot.Apps.Schema.Entities;
7
8/// <summary>
9/// Extension methods for Activity to handle citations and AI-generated content.
10/// </summary>
11public static class ActivityCitationExtensions
12{
13 /// <summary>
14 /// Adds a citation to the activity. Creates or updates the root message entity
15 /// with the specified citation claim.
16 /// </summary>
17 /// <param name="activity">The activity to add the citation to. Cannot be null.</param>
18 /// <param name="position">The position of the citation in the message text.</param>
19 /// <param name="appearance">The citation appearance information.</param>
20 /// <returns>The created CitationEntity that was added to the activity.</returns>
21 public static CitationEntity AddCitation(this TeamsActivity activity, int position, CitationAppearance appearance)
22 {
23 ArgumentNullException.ThrowIfNull(activity);
24 ArgumentNullException.ThrowIfNull(appearance);
25
26 activity.Entities ??= [];
27 OMessageEntity messageEntity = GetOrCreateRootMessageEntity(activity);
28 CitationEntity citationEntity = new(messageEntity);
29 citationEntity.Citation ??= [];
30 citationEntity.Citation.Add(new CitationClaim()
31 {
32 Position = position,
33 Appearance = appearance.ToDocument()
34 });
35
36 activity.Entities.Remove(messageEntity);
37 activity.Entities.Add(citationEntity);
38 activity.Rebase();
39 return citationEntity;
40 }
41
42 /// <summary>
43 /// Adds the AI-generated content label to the activity's root message entity.
44 /// This method is idempotent — calling it multiple times has the same effect as calling it once.
45 /// </summary>
46 /// <param name="activity">The activity to mark as AI-generated. Cannot be null.</param>
47 /// <returns>The OMessageEntity with the AI-generated label applied.</returns>
48 public static OMessageEntity AddAIGenerated(this TeamsActivity activity)
49 {
50 ArgumentNullException.ThrowIfNull(activity);
51
52 OMessageEntity messageEntity = GetOrCreateRootMessageEntity(activity);
53 messageEntity.AdditionalType ??= [];
54
55 if (!messageEntity.AdditionalType.Contains("AIGeneratedContent"))
56 {
57 messageEntity.AdditionalType.Add("AIGeneratedContent");
58 }
59
60 activity.Rebase();
61 return messageEntity;
62 }
63
64 /// <summary>
65 /// Enables the feedback loop (thumbs up/down) on the activity's channel data.
66 /// </summary>
67 /// <param name="activity">The activity to enable feedback on. Cannot be null.</param>
68 /// <param name="value">Whether to enable feedback. Defaults to true.</param>
69 /// <returns>The activity for chaining.</returns>
70 public static TeamsActivity AddFeedback(this TeamsActivity activity, bool value = true)
71 {
72 ArgumentNullException.ThrowIfNull(activity);
73
74 activity.ChannelData ??= new TeamsChannelData();
75 activity.ChannelData.FeedbackLoopEnabled = value;
76 return activity;
77 }
78
79 // Gets or creates the single root-level OMessageEntity on the activity.
80 private static OMessageEntity GetOrCreateRootMessageEntity(TeamsActivity activity)
81 {
82 activity.Entities ??= [];
83
84 OMessageEntity? messageEntity = activity.Entities.FirstOrDefault(
85 e => e.Type == "https://schema.org/Message" && e.OType == "Message"
86 ) as OMessageEntity;
87
88 if (messageEntity is null)
89 {
90 messageEntity = new OMessageEntity();
91 activity.Entities.Add(messageEntity);
92 }
93
94 return messageEntity;
95 }
96}
97
98/// <summary>
99/// Citation entity representing a message with citation claims.
100/// </summary>
101public class CitationEntity : OMessageEntity
102{
103 /// <summary>
104 /// Creates a new instance of <see cref="CitationEntity"/>.
105 /// </summary>
106 public CitationEntity() : base()
107 {
108 }
109
110 /// <summary>
111 /// Creates a new instance of <see cref="CitationEntity"/> by copying data from an existing message entity.
112 /// </summary>
113 /// <param name="entity">The message entity to copy from. Cannot be null.</param>
114 public CitationEntity(OMessageEntity entity) : base()
115 {
116 ArgumentNullException.ThrowIfNull(entity);
117 OType = entity.OType;
118 OContext = entity.OContext;
119 Type = entity.Type;
120 AdditionalType = entity.AdditionalType != null
121 ? new List<string>(entity.AdditionalType)
122 : null;
123 if (entity is CitationEntity citationEntity)
124 {
125 Citation = citationEntity.Citation != null
126 ? new List<CitationClaim>(citationEntity.Citation)
127 : null;
128 }
129 }
130
131 /// <summary>
132 /// Gets or sets the list of citation claims.
133 /// </summary>
134 [JsonPropertyName("citation")]
135 public IList<CitationClaim>? Citation
136 {
137 get => base.Properties.TryGetValue("citation", out object? value) ? value as IList<CitationClaim> : null;
138 set => base.Properties["citation"] = value;
139 }
140}
141
142/// <summary>
143/// Represents a citation claim with a position and appearance document.
144/// </summary>
145public class CitationClaim
146{
147 /// <summary>
148 /// Gets or sets the schema.org type. Always "Claim".
149 /// </summary>
150 [JsonPropertyName("@type")]
151 public string Type { get; set; } = "Claim";
152
153 /// <summary>
154 /// Gets or sets the position of the citation in the message text.
155 /// </summary>
156 [JsonPropertyName("position")]
157 public required int Position { get; set; }
158
159 /// <summary>
160 /// Gets or sets the appearance document describing the cited source.
161 /// </summary>
162 [JsonPropertyName("appearance")]
163 public required CitationAppearanceDocument Appearance { get; set; }
164}
165
166/// <summary>
167/// Represents the appearance of a cited document.
168/// </summary>
169public class CitationAppearanceDocument
170{
171 /// <summary>
172 /// Gets or sets the schema.org type. Always "DigitalDocument".
173 /// </summary>
174 [JsonPropertyName("@type")]
175 public string Type { get; set; } = "DigitalDocument";
176
177 /// <summary>
178 /// Gets or sets the name of the document (max length 80).
179 /// </summary>
180 [JsonPropertyName("name")]
181 public required string Name { get; set; }
182
183 /// <summary>
184 /// Gets or sets a stringified adaptive card with additional information about the citation.
185 /// </summary>
186 [JsonPropertyName("text")]
187 public string? Text { get; set; }
188
189 /// <summary>
190 /// Gets or sets the URL of the document.
191 /// </summary>
192 [JsonPropertyName("url")]
193 public Uri? Url { get; set; }
194
195 /// <summary>
196 /// Gets or sets the extract of the referenced content (max length 160).
197 /// </summary>
198 [JsonPropertyName("abstract")]
199 public required string Abstract { get; set; }
200
201 /// <summary>
202 /// Gets or sets the encoding format of the text. See <see cref="EncodingFormats"/> for known values.
203 /// </summary>
204 [JsonPropertyName("encodingFormat")]
205 public string? EncodingFormat { get; set; }
206
207 /// <summary>
208 /// Gets or sets the citation icon information.
209 /// </summary>
210 [JsonPropertyName("image")]
211 public CitationImageObject? Image { get; set; }
212
213 /// <summary>
214 /// Gets or sets the keywords (max length 3, max keyword length 28).
215 /// </summary>
216 [JsonPropertyName("keywords")]
217 public IList<string>? Keywords { get; set; }
218
219 /// <summary>
220 /// Gets or sets the sensitivity usage information for the citation.
221 /// </summary>
222 [JsonPropertyName("usageInfo")]
223 public SensitiveUsageEntity? UsageInfo { get; set; }
224}
225
226/// <summary>
227/// Represents an image object used for citation icons.
228/// </summary>
229public class CitationImageObject
230{
231 /// <summary>
232 /// Gets or sets the schema.org type. Always "ImageObject".
233 /// </summary>
234 [JsonPropertyName("@type")]
235 public string Type { get; set; } = "ImageObject";
236
237 /// <summary>
238 /// Gets or sets the icon name. See <see cref="CitationIcon"/> for known values.
239 /// </summary>
240 [JsonPropertyName("name")]
241 public required string Name { get; set; }
242}
243
244/// <summary>
245/// Known citation icon names.
246/// </summary>
247public static class CitationIcon
248{
249 /// <summary>Microsoft Word icon.</summary>
250 public const string MicrosoftWord = "Microsoft Word";
251
252 /// <summary>Microsoft Excel icon.</summary>
253 public const string MicrosoftExcel = "Microsoft Excel";
254
255 /// <summary>Microsoft PowerPoint icon.</summary>
256 public const string MicrosoftPowerPoint = "Microsoft PowerPoint";
257
258 /// <summary>Microsoft OneNote icon.</summary>
259 public const string MicrosoftOneNote = "Microsoft OneNote";
260
261 /// <summary>Microsoft SharePoint icon.</summary>
262 public const string MicrosoftSharePoint = "Microsoft SharePoint";
263
264 /// <summary>Microsoft Visio icon.</summary>
265 public const string MicrosoftVisio = "Microsoft Visio";
266
267 /// <summary>Microsoft Loop icon.</summary>
268 public const string MicrosoftLoop = "Microsoft Loop";
269
270 /// <summary>Microsoft Whiteboard icon.</summary>
271 public const string MicrosoftWhiteboard = "Microsoft Whiteboard";
272
273 /// <summary>Adobe Illustrator icon.</summary>
274 public const string AdobeIllustrator = "Adobe Illustrator";
275
276 /// <summary>Adobe Photoshop icon.</summary>
277 public const string AdobePhotoshop = "Adobe Photoshop";
278
279 /// <summary>Adobe InDesign icon.</summary>
280 public const string AdobeInDesign = "Adobe InDesign";
281
282 /// <summary>Adobe Flash icon.</summary>
283 public const string AdobeFlash = "Adobe Flash";
284
285 /// <summary>Sketch icon.</summary>
286 public const string Sketch = "Sketch";
287
288 /// <summary>Source code icon.</summary>
289 public const string SourceCode = "Source Code";
290
291 /// <summary>Image icon.</summary>
292 public const string Image = "Image";
293
294 /// <summary>GIF icon.</summary>
295 public const string Gif = "GIF";
296
297 /// <summary>Video icon.</summary>
298 public const string Video = "Video";
299
300 /// <summary>Sound icon.</summary>
301 public const string Sound = "Sound";
302
303 /// <summary>ZIP icon.</summary>
304 public const string Zip = "ZIP";
305
306 /// <summary>Text icon.</summary>
307 public const string Text = "Text";
308
309 /// <summary>PDF icon.</summary>
310 public const string Pdf = "PDF";
311}
312
313/// <summary>
314/// Known encoding format MIME types for citation documents.
315/// </summary>
316public static class EncodingFormats
317{
318 /// <summary>Adaptive card encoding format.</summary>
319 public const string AdaptiveCard = "application/vnd.microsoft.card.adaptive";
320}
321
322/// <summary>
323/// Helper class for building citation appearance documents.
324/// </summary>
325public class CitationAppearance
326{
327 /// <summary>
328 /// Gets or sets the name of the document (max length 80).
329 /// </summary>
330 public required string Name { get; set; }
331
332 /// <summary>
333 /// Gets or sets a stringified adaptive card with additional information.
334 /// </summary>
335 public string? Text { get; set; }
336
337 /// <summary>
338 /// Gets or sets the URL of the document.
339 /// </summary>
340 public Uri? Url { get; set; }
341
342 /// <summary>
343 /// Gets or sets the extract of the referenced content (max length 160).
344 /// </summary>
345 public required string Abstract { get; set; }
346
347 /// <summary>
348 /// Gets or sets the encoding format of the text. See <see cref="EncodingFormats"/> for known values.
349 /// </summary>
350 public string? EncodingFormat { get; set; }
351
352 /// <summary>
353 /// Gets or sets the citation icon name. See <see cref="CitationIcon"/> for known values.
354 /// </summary>
355 public string? Icon { get; set; }
356
357 /// <summary>
358 /// Gets or sets the keywords (max length 3, max keyword length 28).
359 /// </summary>
360 public IList<string>? Keywords { get; set; }
361
362 /// <summary>
363 /// Gets or sets the sensitivity usage information.
364 /// </summary>
365 public SensitiveUsageEntity? UsageInfo { get; set; }
366
367 /// <summary>
368 /// Converts this appearance to a <see cref="CitationAppearanceDocument"/>.
369 /// </summary>
370 /// <returns>The appearance document.</returns>
371 public CitationAppearanceDocument ToDocument()
372 {
373 return new()
374 {
375 Name = Name,
376 Text = Text,
377 Url = Url,
378 Abstract = Abstract,
379 EncodingFormat = EncodingFormat,
380 Image = Icon is null ? null : new CitationImageObject() { Name = Icon },
381 Keywords = Keywords,
382 UsageInfo = UsageInfo
383 };
384 }
385}
386