2
2
using azure_project_generator . models ;
3
3
using Microsoft . Extensions . Logging ;
4
4
using OpenAI . Embeddings ;
5
+ using OpenAI . Chat ;
6
+ using System . Text . Json ;
7
+ using Microsoft . AspNetCore . Mvc ;
8
+ using Newtonsoft . Json ;
9
+ using Newtonsoft . Json . Linq ;
5
10
6
11
namespace azure_project_generator . services
7
12
{
8
13
public class ContentGenerationService
9
14
{
10
15
private readonly ILogger < ContentGenerationService > _logger ;
11
16
private readonly EmbeddingClient _embeddingClient ;
12
-
13
- public ContentGenerationService ( ILogger < ContentGenerationService > logger , EmbeddingClient embeddingClient )
17
+ private readonly ChatClient _completionsClient ;
18
+ public ContentGenerationService ( ILogger < ContentGenerationService > logger , EmbeddingClient embeddingClient , ChatClient completionsClient )
14
19
{
15
20
_logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
16
21
_embeddingClient = embeddingClient ?? throw new ArgumentNullException ( nameof ( embeddingClient ) ) ;
22
+ _completionsClient = completionsClient ?? throw new ArgumentNullException ( nameof ( completionsClient ) ) ;
23
+
17
24
}
18
25
19
26
public string GenerateCertServiceContextSentence ( CertificationService data ) =>
20
27
$ "The { data . CertificationCode } { data . CertificationName } certification includes the skill of { data . SkillName } . Within this skill, there is a focus on the topic of { data . TopicName } , particularly through the use of the service { data . ServiceName } .";
21
28
22
- public string GenerateCertDataContextSentence ( Certification certificationDocument )
23
- {
24
- var certificationName = certificationDocument . CertificationName ;
25
- var certificationCode = certificationDocument . CertificationCode ;
26
-
27
- var skills = certificationDocument . SkillsMeasured . Select ( s => s . Name ) . ToList ( ) ;
28
- var topicsWithServices = certificationDocument . SkillsMeasured
29
- . SelectMany ( s => s . Topics )
30
- . Select ( t => $ "{ t . TopicName } (using { string . Join ( ", " , t . Services ) } )") . ToList ( ) ;
31
-
32
- string skillNames = string . Join ( ", " , skills ) ;
33
- string topicDetails = string . Join ( "; " , topicsWithServices ) ;
34
-
35
- string prompt = $ "Generate a project idea that aligns with the { certificationCode } certification, " +
36
- $ "which covers skills such as { skillNames } . The project should focus on topics like { topicDetails } , " +
37
- $ "addressing real-world scenarios related to { certificationName } .";
38
-
39
- return prompt ;
40
-
41
- }
42
29
43
30
public async Task < float [ ] > GenerateEmbeddingsAsync ( string content )
44
31
{
@@ -60,5 +47,83 @@ public async Task<float[]> GenerateEmbeddingsAsync(string content)
60
47
throw ;
61
48
}
62
49
}
50
+
51
+ public async Task < string > GenerateProjectIdeaAsync ( string skills , string services )
52
+ {
53
+ string userPrompt = $@ "You are an expert cloud architect.
54
+ Please generate a detailed project idea for a beginner-friendly weekend cloud solution
55
+ based on the following Azure certification skills: { skills } .
56
+ The project should utilize the following services: { services } .
57
+ The project should be small in scale, achievable over a weekend, and have a fun, creative name. Suitable for beginners. Cheap to run.
58
+ The response must be formatted as valid JSON and include only the following fields:
59
+ {{
60
+ ""projectName"": ""A fun and creative project name"",
61
+ ""description"": ""A brief, engaging description of the project, highlighting its purpose and main features."",
62
+ ""learningGoals"": [""Goal 1"", ""Goal 2"", ""Goal 3""],
63
+ ""steps"": [
64
+ ""Step 1: Description of the first step"",
65
+ ""Step 2: Description of the second step"",
66
+ ""Step 3: Description of the third step"",
67
+ ""Step 4: Description of the fourth step"",
68
+ ""Step 5: Description of the fifth step""
69
+ ]
70
+ }}
71
+ Ensure that the project idea is practical, aligned with beginner-level skills, and leverages best practices in Azure architecture." ;
72
+
73
+ try
74
+ {
75
+ _logger . LogInformation ( "Generating project idea..." ) ;
76
+ ChatCompletion completion = await _completionsClient . CompleteChatAsync ( new ChatMessage [ ]
77
+ {
78
+ new SystemChatMessage ( "You are a technical assistant specialized in generating beginner-friendly cloud project ideas. Provide the response in JSON format only, without any additional text." ) ,
79
+ new UserChatMessage ( userPrompt )
80
+ } ) ;
81
+
82
+ string projectIdeaContent = completion . Content [ 0 ] . Text ;
83
+
84
+ if ( string . IsNullOrWhiteSpace ( projectIdeaContent ) )
85
+ {
86
+ _logger . LogWarning ( "The response from the AI model was empty or null." ) ;
87
+ throw new Exception ( "Failed to generate project idea." ) ;
88
+ }
89
+
90
+ string cleanedJsonContent = projectIdeaContent
91
+ . Replace ( "```json" , string . Empty )
92
+ . Replace ( "```" , string . Empty )
93
+ . Replace ( "json\n " , string . Empty )
94
+ . Trim ( ) ;
95
+
96
+ JObject jsonObject = JObject . Parse ( cleanedJsonContent ) ;
97
+
98
+ // Validate that all required fields are present
99
+ string [ ] requiredFields = { "projectName" , "description" , "learningGoals" , "steps" } ;
100
+ foreach ( var field in requiredFields )
101
+ {
102
+ if ( ! jsonObject . ContainsKey ( field ) )
103
+ {
104
+ _logger . LogWarning ( $ "Generated JSON is missing required field: { field } ") ;
105
+ throw new System . Text . Json . JsonException ( $ "Generated project idea is missing required field: { field } ") ;
106
+
107
+ }
108
+ }
109
+
110
+ return jsonObject . ToString ( ) ;
111
+ }
112
+ catch ( System . Text . Json . JsonException ex )
113
+ {
114
+ _logger . LogError ( ex , "Error parsing JSON response" ) ;
115
+ throw ;
116
+ }
117
+ catch ( RequestFailedException ex )
118
+ {
119
+ _logger . LogError ( ex , "Azure OpenAI API request failed" ) ;
120
+ throw ;
121
+ }
122
+ catch ( Exception ex )
123
+ {
124
+ _logger . LogError ( ex , "Error generating project idea" ) ;
125
+ throw ;
126
+ }
127
+ }
63
128
}
64
129
}
0 commit comments