-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskAIInteraction.cs
More file actions
184 lines (150 loc) · 5.64 KB
/
Copy pathTaskAIInteraction.cs
File metadata and controls
184 lines (150 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
using GooseShared;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class TaskAIInteraction : GooseTaskInfo
{
private GooseAIConfig _cfg = GooseAIConfig.Load();
private List<object> messageHistory;
public TaskAIInteraction()
{
taskID = "AIInteraction";
shortName = "AI Interaction";
description = "The goose interacts with the user using AI.";
canBePickedRandomly = false;
_cfg = GooseAIConfig.Load(); // << load config first!
messageHistory = new List<object>
{
new { role = "system", content = _cfg.systemPrompt }
};
}
public override GooseTaskData GetNewTaskData(GooseEntity goose)
{
return new TaskAIInteractionData();
}
public override void RunTask(GooseEntity goose)
{
// User tap triggers input prompt + AI response
ShowInputPrompt(goose);
// Start idle chatter task (runs independently)
StartIdleChatter(goose);
}
private void ShowInputPrompt(GooseEntity goose)
{
var pt = new System.Drawing.Point((int)goose.position.x, (int)goose.position.y);
Task.Run(async () =>
{
try
{
string userInput = GooseInputForm.ShowAt(pt, _cfg.bubbleText);
if (string.IsNullOrWhiteSpace(userInput))
return;
string aiResponse = await GetAIResponse(userInput);
string wrapped = WrapText(aiResponse, 50);
var control = new Control();
control.CreateControl();
control.Invoke((MethodInvoker)(() => SpeechBubble.Speak(wrapped)));
}
catch (Exception ex)
{
var control = new Control();
control.CreateControl();
control.Invoke((MethodInvoker)(() =>
SpeechBubble.Speak("AI Error: " + (ex.InnerException?.Message ?? ex.Message))
));
}
});
}
private void StartIdleChatter(GooseEntity goose)
{
Task.Run(async () =>
{
var lastPos = goose.position;
int idleTimeMs = 8000; // 8 seconds idle to start check
int checkInterval = 500;
int elapsed = 0;
Random rand = new Random();
while (true)
{
await Task.Delay(checkInterval);
elapsed += checkInterval;
// Reset idle if goose moved
if (goose.position.x != lastPos.x || goose.position.y != lastPos.y)
{
elapsed = 0;
lastPos = goose.position;
}
// If idle long enough, chance to speak
if (elapsed >= idleTimeMs)
{
if (rand.NextDouble() <= _cfg.chanceToSpeak)
{
string aiPrompt = "Quack!";
string aiResponse = await GetAIResponse(aiPrompt);
string wrapped = WrapText(aiResponse, 50);
var control = new Control();
control.CreateControl();
control.Invoke((MethodInvoker)(() => SpeechBubble.Speak(wrapped)));
elapsed = 0; // reset idle timer after speaking
}
}
}
});
}
private string WrapText(string text, int maxLineLength)
{
var words = text.Split(' ');
var sb = new StringBuilder();
int currentLineLength = 0;
foreach (var word in words)
{
if (currentLineLength + word.Length + 1 > maxLineLength)
{
sb.AppendLine();
currentLineLength = 0;
}
else if (currentLineLength > 0)
{
sb.Append(' ');
currentLineLength++;
}
sb.Append(word);
currentLineLength += word.Length;
}
return sb.ToString();
}
private async Task<string> GetAIResponse(string userInput)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
messageHistory.Add(new { role = "user", content = userInput });
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _cfg.api_key);
var payload = new
{
model = _cfg.model,
messages = messageHistory
};
string jsonRequest = JsonConvert.SerializeObject(payload);
var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(_cfg.endpoint, content);
string json = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new Exception($"HTTP {(int)response.StatusCode}: {json}");
dynamic result = JsonConvert.DeserializeObject(json);
string aiReply = result.choices[0].message.content;
messageHistory.Add(new { role = "assistant", content = aiReply });
return aiReply;
}
}
}
public class TaskAIInteractionData : GooseTaskData
{
// No additional data needed
}