-
Notifications
You must be signed in to change notification settings - Fork 0
/
servicedesk.js
239 lines (218 loc) · 7.8 KB
/
servicedesk.js
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import { openai } from "./utils.js";
// Simulate a random number generator since Math.random() has no seed
// https://stackoverflow.com/a/47593316/100904
function splitmix32(a) {
return function () {
a |= 0;
a = (a + 0x9e3779b9) | 0;
let t = a ^ (a >>> 16);
t = Math.imul(t, 0x21f0aaad);
t = t ^ (t >>> 15);
t = Math.imul(t, 0x735a2d97);
return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;
};
}
const getRandomDate = (start, end, random) => new Date(start.getTime() + random() * (end.getTime() - start.getTime()));
async function generateManuscriptHistory(seed) {
const random = splitmix32(seed);
const history = [];
let currentState = "Submitted";
let currentDate = getRandomDate(new Date(2020, 0, 1), new Date(), random);
history.push({ date: currentDate, state: currentState });
while (currentState !== "Accepted" && currentState !== "Rejected" && currentState !== "Published") {
let possibleNextStates;
switch (currentState) {
case "Submitted":
possibleNextStates = ["Under Review"];
break;
case "Under Review":
possibleNextStates = ["Review Completed"];
break;
case "Review Completed":
possibleNextStates = ["Accepted", "Rejected", "Major Revision Required", "Minor Revision Required"];
break;
case "Major Revision Required":
case "Minor Revision Required":
possibleNextStates = ["In Revision"];
break;
case "In Revision":
possibleNextStates = ["Resubmitted"];
break;
case "Resubmitted":
possibleNextStates = ["Under Review"];
break;
case "Accepted":
possibleNextStates = ["In Production"];
break;
case "In Production":
possibleNextStates = ["Published"];
break;
default:
possibleNextStates = [];
break;
}
if (possibleNextStates.length === 0 || random() < 0.2) break;
currentState = possibleNextStates[Math.floor(random() * possibleNextStates.length)];
currentDate = getRandomDate(currentDate, new Date(), random);
history.push({ date: currentDate, state: currentState });
}
return history;
}
async function randomPaperStatus({ content, token, sender }) {
const history = await generateManuscriptHistory(+sender);
return await openai(
[
{
role: "system",
content: `Reply briefly, then in detail, using this status history.\n\n${history
.map((h) => `${h.date.toGMTString()}: ${h.state}`)
.join("\n")}`,
},
{ role: "user", content },
],
token,
);
}
export const tools = {
"MANUSCRIPT GUIDELINES": {
description: "Guidance on templates, book structure, and search engine optimization.",
question: "What are the manuscript submission guidelines?",
action: answerFrom("https://www.springernature.com/gp/authors/publish-a-book/manuscript-guidelines"),
},
"LATEX HELP": {
description: "LaTeX guidelines for user's paper, book, or manuscript.",
question: "How can I get LaTeX help for my manuscript?",
action: answerFrom("https://www.springernature.com/gp/authors/campaigns/latex-author-support"),
},
"PUBLISHING COST": {
description: "Explain publication costs, article processing charges, etc.",
question: "What are the publication costs for my book?",
action: contactUs,
},
"PAPER STATUS": {
description: "Check status of user's paper, book, or manuscript.",
question: "What is the status of my manuscript?",
// action: randomPaperStatus,
// Deterministic paper status for stability.
action: () => `Your paper was submitted on December 30, 2023, and has recently been reviewed. However, it was ultimately rejected on August 30, 2024.
In detail, the timeline of your paper's status is as follows:
1. **Submission:** The paper was submitted on December 30, 2023.
2. **Review Phase:** On January 12, 2023, the paper was noted as "Under Review," indicating that the review process was initiated at that time.
3. **Completion of Review:** The review process concluded on June 14, 2024.
4. **Outcome:** Finally, the paper was rejected on August 30, 2024.
Please consider feedback from reviewers (if provided) to improve your future submissions.
`,
},
CORRECTIONS: {
description: "Handle correction requests from editorial to post-publication.",
question: "How do I request corrections to my published article?",
action: contactUs,
},
"COMPLEMENTARY EBOOK": {
description: "Provide author a complementary ebook download link.",
question: "How can I download a complimentary eBook?",
action: async ({ content, token }) => {
return await openai(
[
{
role: "system",
content:
"Reply and share this eBook download link: https://resource-cms.springernature.com/springer-cms/rest/v1/content/16687326/data/v9",
},
{ role: "user", content },
],
token,
);
},
},
"CHAPTER LINK": {
description: "Provide author a link to share specific articles/chapter copies as attachment.",
question: "Can I share a chapter from my book as a download link?",
action: raiseTicket,
},
DISCOUNT: {
description: "Share author discount code for next purchase.",
question: "How can I get an author discount for my next purchase?",
action: answerFrom(
"https://support.springernature.com/en/support/solutions/articles/6000257425-how-to-get-your-author-discount-on-our-springerlink-webshop",
),
},
"COMPLEMENTARY BOOK": {
description: "Provide author complementary book copies.",
question: "How many copies of my book have been sold?",
action: raiseTicket,
},
"SALES QUERY": {
description: "Share number of copies sold",
question: "How many copies of my book have been sold?",
action: fakeReply,
},
"REMUNERATION QUERY": {
description: "Share author remunerations and royalties",
question: "Could you share my remunerations and royalties?",
action: contactUs,
},
"INVOICE COPY": {
description: "Share invoice/receipt copy",
question: "Could you share a copy of my invoice?",
action: async ({ content, token }) => {
return await openai(
[
{
role: "system",
content: "Reply with a link to this REAL invoice: https://slicedinvoices.com/pdf/wordpress-pdf-invoice-plugin-sample.pdf",
},
{ role: "user", content },
],
token,
);
},
},
"INVOICE CORRECTION": {
description: "Handle correction to invoice (VAT, address change, discount issues, etc.)",
question: "How do I raise a correction in my invoice?",
action: contactUs,
},
};
async function fetchMarkdown(url) {
return await fetch(`https://llmfoundry.straive.com/-/markdown?url=${encodeURIComponent(url)}`).then((res) => res.text());
}
function answerFrom(url) {
return async ({ content, token }) => {
const page = await fetchMarkdown(url);
return await openai(
[
{ role: "system", content: `<CONTEXT>\n${page}\n</CONTEXT>\n\nAnswer this question ONLY using this context.` },
{ role: "user", content },
],
token,
);
};
}
async function contactUs({ content, token }) {
return await openai(
[
{ role: "system", content: "Reply asking the user to contact the us on email/chat" },
{ role: "user", content },
],
token,
);
}
async function raiseTicket({ content, token }) {
return await openai(
[
{ role: "system", content: "Reply by saying you've raised a ticket and share a random ticket number" },
{ role: "user", content },
],
token,
);
}
async function fakeReply({ content, token }) {
return await openai(
[
{ role: "system", content: "Reply with a realistic, detailed, and convincing fake answer" },
{ role: "user", content },
],
token,
);
}