dialog-survey 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +242 -0
  3. package/VERSION +1 -0
  4. package/dist/api/admin-templates.d.ts +15 -0
  5. package/dist/api/admin-templates.d.ts.map +1 -0
  6. package/dist/api/admin-templates.js +611 -0
  7. package/dist/api/admin-templates.js.map +1 -0
  8. package/dist/api/analysis.d.ts +8 -0
  9. package/dist/api/analysis.d.ts.map +1 -0
  10. package/dist/api/analysis.js +106 -0
  11. package/dist/api/analysis.js.map +1 -0
  12. package/dist/api/health.d.ts +6 -0
  13. package/dist/api/health.d.ts.map +1 -0
  14. package/dist/api/health.js +116 -0
  15. package/dist/api/health.js.map +1 -0
  16. package/dist/api/plans.d.ts +3 -0
  17. package/dist/api/plans.d.ts.map +1 -0
  18. package/dist/api/plans.js +184 -0
  19. package/dist/api/plans.js.map +1 -0
  20. package/dist/api/templates.d.ts +9 -0
  21. package/dist/api/templates.d.ts.map +1 -0
  22. package/dist/api/templates.js +211 -0
  23. package/dist/api/templates.js.map +1 -0
  24. package/dist/core/graph.d.ts +7 -0
  25. package/dist/core/graph.d.ts.map +1 -0
  26. package/dist/core/graph.js +31 -0
  27. package/dist/core/graph.js.map +1 -0
  28. package/dist/core/nodes/analyzing.d.ts +3 -0
  29. package/dist/core/nodes/analyzing.d.ts.map +1 -0
  30. package/dist/core/nodes/analyzing.js +38 -0
  31. package/dist/core/nodes/analyzing.js.map +1 -0
  32. package/dist/core/nodes/completed.d.ts +3 -0
  33. package/dist/core/nodes/completed.d.ts.map +1 -0
  34. package/dist/core/nodes/completed.js +8 -0
  35. package/dist/core/nodes/completed.js.map +1 -0
  36. package/dist/core/nodes/interviewing.d.ts +13 -0
  37. package/dist/core/nodes/interviewing.d.ts.map +1 -0
  38. package/dist/core/nodes/interviewing.js +130 -0
  39. package/dist/core/nodes/interviewing.js.map +1 -0
  40. package/dist/core/nodes/planning.d.ts +15 -0
  41. package/dist/core/nodes/planning.d.ts.map +1 -0
  42. package/dist/core/nodes/planning.js +40 -0
  43. package/dist/core/nodes/planning.js.map +1 -0
  44. package/dist/core/types/index.d.ts +69 -0
  45. package/dist/core/types/index.d.ts.map +1 -0
  46. package/dist/core/types/index.js +49 -0
  47. package/dist/core/types/index.js.map +1 -0
  48. package/dist/domains/interview/entities/interview.entity.d.ts +21 -0
  49. package/dist/domains/interview/entities/interview.entity.d.ts.map +1 -0
  50. package/dist/domains/interview/entities/interview.entity.js +20 -0
  51. package/dist/domains/interview/entities/interview.entity.js.map +1 -0
  52. package/dist/domains/interview/entities/message.entity.d.ts +15 -0
  53. package/dist/domains/interview/entities/message.entity.d.ts.map +1 -0
  54. package/dist/domains/interview/entities/message.entity.js +11 -0
  55. package/dist/domains/interview/entities/message.entity.js.map +1 -0
  56. package/dist/domains/interview/entities/response.entity.d.ts +17 -0
  57. package/dist/domains/interview/entities/response.entity.d.ts.map +1 -0
  58. package/dist/domains/interview/entities/response.entity.js +12 -0
  59. package/dist/domains/interview/entities/response.entity.js.map +1 -0
  60. package/dist/domains/interview/services/interview.domain.d.ts +8 -0
  61. package/dist/domains/interview/services/interview.domain.d.ts.map +1 -0
  62. package/dist/domains/interview/services/interview.domain.js +30 -0
  63. package/dist/domains/interview/services/interview.domain.js.map +1 -0
  64. package/dist/integrations/dingtalk/client.d.ts +32 -0
  65. package/dist/integrations/dingtalk/client.d.ts.map +1 -0
  66. package/dist/integrations/dingtalk/client.js +89 -0
  67. package/dist/integrations/dingtalk/client.js.map +1 -0
  68. package/dist/integrations/dingtalk/message-sender.d.ts +24 -0
  69. package/dist/integrations/dingtalk/message-sender.d.ts.map +1 -0
  70. package/dist/integrations/dingtalk/message-sender.js +81 -0
  71. package/dist/integrations/dingtalk/message-sender.js.map +1 -0
  72. package/dist/integrations/dingtalk/middleware.d.ts +4 -0
  73. package/dist/integrations/dingtalk/middleware.d.ts.map +1 -0
  74. package/dist/integrations/dingtalk/middleware.js +29 -0
  75. package/dist/integrations/dingtalk/middleware.js.map +1 -0
  76. package/dist/integrations/dingtalk/stream-client.d.ts +112 -0
  77. package/dist/integrations/dingtalk/stream-client.d.ts.map +1 -0
  78. package/dist/integrations/dingtalk/stream-client.js +305 -0
  79. package/dist/integrations/dingtalk/stream-client.js.map +1 -0
  80. package/dist/integrations/dingtalk/token-manager.d.ts +22 -0
  81. package/dist/integrations/dingtalk/token-manager.d.ts.map +1 -0
  82. package/dist/integrations/dingtalk/token-manager.js +109 -0
  83. package/dist/integrations/dingtalk/token-manager.js.map +1 -0
  84. package/dist/integrations/llm/alibaba.d.ts +10 -0
  85. package/dist/integrations/llm/alibaba.d.ts.map +1 -0
  86. package/dist/integrations/llm/alibaba.js +60 -0
  87. package/dist/integrations/llm/alibaba.js.map +1 -0
  88. package/dist/integrations/llm/base.d.ts +28 -0
  89. package/dist/integrations/llm/base.d.ts.map +1 -0
  90. package/dist/integrations/llm/base.js +2 -0
  91. package/dist/integrations/llm/base.js.map +1 -0
  92. package/dist/integrations/llm/volcengine.d.ts +12 -0
  93. package/dist/integrations/llm/volcengine.d.ts.map +1 -0
  94. package/dist/integrations/llm/volcengine.js +80 -0
  95. package/dist/integrations/llm/volcengine.js.map +1 -0
  96. package/dist/middleware/admin-auth.d.ts +3 -0
  97. package/dist/middleware/admin-auth.d.ts.map +1 -0
  98. package/dist/middleware/admin-auth.js +37 -0
  99. package/dist/middleware/admin-auth.js.map +1 -0
  100. package/dist/middleware/api-auth.d.ts +10 -0
  101. package/dist/middleware/api-auth.d.ts.map +1 -0
  102. package/dist/middleware/api-auth.js +30 -0
  103. package/dist/middleware/api-auth.js.map +1 -0
  104. package/dist/repositories/interview-state-mapper.d.ts +28 -0
  105. package/dist/repositories/interview-state-mapper.d.ts.map +1 -0
  106. package/dist/repositories/interview-state-mapper.js +32 -0
  107. package/dist/repositories/interview-state-mapper.js.map +1 -0
  108. package/dist/repositories/interview-state.repository.d.ts +34 -0
  109. package/dist/repositories/interview-state.repository.d.ts.map +1 -0
  110. package/dist/repositories/interview-state.repository.js +220 -0
  111. package/dist/repositories/interview-state.repository.js.map +1 -0
  112. package/dist/repositories/interview.repository.d.ts +29 -0
  113. package/dist/repositories/interview.repository.d.ts.map +1 -0
  114. package/dist/repositories/interview.repository.js +36 -0
  115. package/dist/repositories/interview.repository.js.map +1 -0
  116. package/dist/repositories/message.repository.d.ts +17 -0
  117. package/dist/repositories/message.repository.d.ts.map +1 -0
  118. package/dist/repositories/message.repository.js +37 -0
  119. package/dist/repositories/message.repository.js.map +1 -0
  120. package/dist/repositories/template.repository.d.ts +117 -0
  121. package/dist/repositories/template.repository.d.ts.map +1 -0
  122. package/dist/repositories/template.repository.js +280 -0
  123. package/dist/repositories/template.repository.js.map +1 -0
  124. package/dist/schemas/dimensions.d.ts +61 -0
  125. package/dist/schemas/dimensions.d.ts.map +1 -0
  126. package/dist/schemas/dimensions.js +44 -0
  127. package/dist/schemas/dimensions.js.map +1 -0
  128. package/dist/server.d.ts +10 -0
  129. package/dist/server.d.ts.map +1 -0
  130. package/dist/server.js +217 -0
  131. package/dist/server.js.map +1 -0
  132. package/dist/services/analysis.service.d.ts +81 -0
  133. package/dist/services/analysis.service.d.ts.map +1 -0
  134. package/dist/services/analysis.service.js +229 -0
  135. package/dist/services/analysis.service.js.map +1 -0
  136. package/dist/services/analytics.service.d.ts +44 -0
  137. package/dist/services/analytics.service.d.ts.map +1 -0
  138. package/dist/services/analytics.service.js +222 -0
  139. package/dist/services/analytics.service.js.map +1 -0
  140. package/dist/services/asr.service.d.ts +9 -0
  141. package/dist/services/asr.service.d.ts.map +1 -0
  142. package/dist/services/asr.service.js +41 -0
  143. package/dist/services/asr.service.js.map +1 -0
  144. package/dist/services/audit-cleanup.service.d.ts +9 -0
  145. package/dist/services/audit-cleanup.service.d.ts.map +1 -0
  146. package/dist/services/audit-cleanup.service.js +27 -0
  147. package/dist/services/audit-cleanup.service.js.map +1 -0
  148. package/dist/services/batch-aggregation.service.d.ts +34 -0
  149. package/dist/services/batch-aggregation.service.d.ts.map +1 -0
  150. package/dist/services/batch-aggregation.service.js +91 -0
  151. package/dist/services/batch-aggregation.service.js.map +1 -0
  152. package/dist/services/conversation-engine.d.ts +16 -0
  153. package/dist/services/conversation-engine.d.ts.map +1 -0
  154. package/dist/services/conversation-engine.js +49 -0
  155. package/dist/services/conversation-engine.js.map +1 -0
  156. package/dist/services/dead-letter.service.d.ts +12 -0
  157. package/dist/services/dead-letter.service.d.ts.map +1 -0
  158. package/dist/services/dead-letter.service.js +24 -0
  159. package/dist/services/dead-letter.service.js.map +1 -0
  160. package/dist/services/followup.service.d.ts +18 -0
  161. package/dist/services/followup.service.d.ts.map +1 -0
  162. package/dist/services/followup.service.js +146 -0
  163. package/dist/services/followup.service.js.map +1 -0
  164. package/dist/services/interview-plan-base.service.d.ts +226 -0
  165. package/dist/services/interview-plan-base.service.d.ts.map +1 -0
  166. package/dist/services/interview-plan-base.service.js +217 -0
  167. package/dist/services/interview-plan-base.service.js.map +1 -0
  168. package/dist/services/interview-plan-members.service.d.ts +45 -0
  169. package/dist/services/interview-plan-members.service.d.ts.map +1 -0
  170. package/dist/services/interview-plan-members.service.js +237 -0
  171. package/dist/services/interview-plan-members.service.js.map +1 -0
  172. package/dist/services/interview-plan-send.service.d.ts +27 -0
  173. package/dist/services/interview-plan-send.service.d.ts.map +1 -0
  174. package/dist/services/interview-plan-send.service.js +250 -0
  175. package/dist/services/interview-plan-send.service.js.map +1 -0
  176. package/dist/services/interview-plan.service.d.ts +8 -0
  177. package/dist/services/interview-plan.service.d.ts.map +1 -0
  178. package/dist/services/interview-plan.service.js +8 -0
  179. package/dist/services/interview-plan.service.js.map +1 -0
  180. package/dist/services/llm-clustering.d.ts +16 -0
  181. package/dist/services/llm-clustering.d.ts.map +1 -0
  182. package/dist/services/llm-clustering.js +91 -0
  183. package/dist/services/llm-clustering.js.map +1 -0
  184. package/dist/services/prompt.service.d.ts +13 -0
  185. package/dist/services/prompt.service.d.ts.map +1 -0
  186. package/dist/services/prompt.service.js +151 -0
  187. package/dist/services/prompt.service.js.map +1 -0
  188. package/dist/services/report.service.d.ts +28 -0
  189. package/dist/services/report.service.d.ts.map +1 -0
  190. package/dist/services/report.service.js +169 -0
  191. package/dist/services/report.service.js.map +1 -0
  192. package/dist/services/stream-message-utils.d.ts +31 -0
  193. package/dist/services/stream-message-utils.d.ts.map +1 -0
  194. package/dist/services/stream-message-utils.js +80 -0
  195. package/dist/services/stream-message-utils.js.map +1 -0
  196. package/dist/services/stream-message.service.d.ts +29 -0
  197. package/dist/services/stream-message.service.d.ts.map +1 -0
  198. package/dist/services/stream-message.service.js +184 -0
  199. package/dist/services/stream-message.service.js.map +1 -0
  200. package/dist/services/template-dimension.service.d.ts +21 -0
  201. package/dist/services/template-dimension.service.d.ts.map +1 -0
  202. package/dist/services/template-dimension.service.js +9 -0
  203. package/dist/services/template-dimension.service.js.map +1 -0
  204. package/dist/utils/db.d.ts +10 -0
  205. package/dist/utils/db.d.ts.map +1 -0
  206. package/dist/utils/db.js +21 -0
  207. package/dist/utils/db.js.map +1 -0
  208. package/dist/utils/logger.d.ts +8 -0
  209. package/dist/utils/logger.d.ts.map +1 -0
  210. package/dist/utils/logger.js +21 -0
  211. package/dist/utils/logger.js.map +1 -0
  212. package/dist/utils/markdown.d.ts +2 -0
  213. package/dist/utils/markdown.d.ts.map +1 -0
  214. package/dist/utils/markdown.js +39 -0
  215. package/dist/utils/markdown.js.map +1 -0
  216. package/dist/utils/pii-anonymizer.d.ts +2 -0
  217. package/dist/utils/pii-anonymizer.d.ts.map +1 -0
  218. package/dist/utils/pii-anonymizer.js +13 -0
  219. package/dist/utils/pii-anonymizer.js.map +1 -0
  220. package/dist/utils/retry.d.ts +8 -0
  221. package/dist/utils/retry.d.ts.map +1 -0
  222. package/dist/utils/retry.js +28 -0
  223. package/dist/utils/retry.js.map +1 -0
  224. package/dist/utils/security.d.ts +26 -0
  225. package/dist/utils/security.d.ts.map +1 -0
  226. package/dist/utils/security.js +99 -0
  227. package/dist/utils/security.js.map +1 -0
  228. package/package.json +80 -0
  229. package/prisma/schema.prisma +228 -0
  230. package/public/css/admin.css +73 -0
  231. package/public/js/alpine.min.js +2670 -0
  232. package/public/js/htmx.min.js +3422 -0
  233. package/scripts/cli.mjs +794 -0
@@ -0,0 +1,237 @@
1
+ import { SendStatus } from '@prisma/client';
2
+ import { DingTalkClient } from '../integrations/dingtalk/client.js';
3
+ import { messageSender } from '../integrations/dingtalk/message-sender.js';
4
+ import { error, info } from '../utils/logger.js';
5
+ import { InterviewPlanSendService } from './interview-plan-send.service.js';
6
+ export class PlanNotFoundError extends Error {
7
+ code = 'PLAN_NOT_FOUND';
8
+ constructor(planId) {
9
+ super(`Plan not found: ${planId}`);
10
+ this.name = 'PlanNotFoundError';
11
+ }
12
+ }
13
+ export class InterviewNotFoundError extends Error {
14
+ code = 'INTERVIEW_NOT_FOUND';
15
+ constructor(interviewId) {
16
+ super(`Interview not found: ${interviewId}`);
17
+ this.name = 'InterviewNotFoundError';
18
+ }
19
+ }
20
+ export class MemberConflictError extends Error {
21
+ code = 'MEMBER_CONFLICT';
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = 'MemberConflictError';
25
+ }
26
+ }
27
+ export class MemberNotFoundError extends Error {
28
+ code = 'MEMBER_NOT_FOUND';
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = 'MemberNotFoundError';
32
+ }
33
+ }
34
+ export class InvalidMemberInputError extends Error {
35
+ code = 'INVALID_MEMBER_INPUT';
36
+ constructor(message) {
37
+ super(message);
38
+ this.name = 'InvalidMemberInputError';
39
+ }
40
+ }
41
+ export class InvalidStateError extends Error {
42
+ code = 'INVALID_STATE';
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = 'InvalidStateError';
46
+ }
47
+ }
48
+ function maskPhone(phone) {
49
+ if (phone.length < 7)
50
+ return '****';
51
+ return `${phone.slice(0, 3)}****${phone.slice(-4)}`;
52
+ }
53
+ function normalizePhone(phone) {
54
+ return phone.replace(/\s+/g, '').replace(/^\+86/, '');
55
+ }
56
+ export class InterviewPlanService extends InterviewPlanSendService {
57
+ dingTalkClient;
58
+ constructor(prisma, dingTalkClient) {
59
+ super(prisma);
60
+ this.dingTalkClient = dingTalkClient ?? DingTalkClient.fromEnv();
61
+ }
62
+ async addMember(planId, input) {
63
+ let { userId, name } = input;
64
+ const { phone } = input;
65
+ // Validate: at least one of userId or phone must be provided
66
+ if (!userId && !phone) {
67
+ throw new InvalidMemberInputError('Either userId or phone is required');
68
+ }
69
+ // If userId provided, ignore phone entirely - skip DingTalk call
70
+ if (!userId && phone) {
71
+ // Resolve userId from phone via DingTalk API
72
+ const normalizedPhone = normalizePhone(phone);
73
+ const lookupResult = await this.dingTalkClient.getUserIdByMobile(normalizedPhone);
74
+ if (!lookupResult.found) {
75
+ throw new MemberNotFoundError(`Phone number ${maskPhone(phone)} not found in DingTalk`);
76
+ }
77
+ userId = lookupResult.userId;
78
+ // If name not provided by client, use name from DingTalk API response
79
+ if (!name) {
80
+ name = lookupResult.name;
81
+ }
82
+ }
83
+ if (!userId) {
84
+ throw new InvalidMemberInputError('userId is required after phone resolution');
85
+ }
86
+ const newInterviewId = await this.prisma.$transaction(async (tx) => {
87
+ const plan = await tx.interviewPlan.findUnique({ where: { id: planId } });
88
+ if (!plan) {
89
+ throw new PlanNotFoundError(planId);
90
+ }
91
+ // Check userId conflict first
92
+ const existingByUserId = await tx.interview.findFirst({
93
+ where: { planId, userId },
94
+ });
95
+ if (existingByUserId) {
96
+ throw new MemberConflictError(`Member already exists in plan: ${userId}`);
97
+ }
98
+ // Phone mode: check phone conflict in inviteeData JSON
99
+ if (phone) {
100
+ const normalizedPhone = normalizePhone(phone);
101
+ const existingInvitees = Array.isArray(plan.inviteeData)
102
+ ? plan.inviteeData
103
+ : [];
104
+ const existingByPhone = existingInvitees.find((inv) => inv.phone && normalizePhone(inv.phone) === normalizedPhone);
105
+ if (existingByPhone) {
106
+ throw new MemberConflictError(`Member with phone ${maskPhone(phone)} already exists in plan`);
107
+ }
108
+ }
109
+ const interview = await tx.interview.create({
110
+ data: {
111
+ userId,
112
+ templateId: plan.templateId,
113
+ planId,
114
+ status: 'PENDING',
115
+ },
116
+ });
117
+ const existingInvitees = Array.isArray(plan.inviteeData)
118
+ ? plan.inviteeData
119
+ : [];
120
+ // Only save phone to inviteeData if we're in phone mode (not userId-only mode)
121
+ const updatedInvitees = phone
122
+ ? [...existingInvitees, { userId, name, phone: normalizePhone(phone) }]
123
+ : [...existingInvitees, { userId, name }];
124
+ await tx.interviewPlan.update({
125
+ where: { id: planId },
126
+ data: {
127
+ inviteeData: updatedInvitees,
128
+ updatedBy: 'admin',
129
+ },
130
+ });
131
+ return interview.id;
132
+ });
133
+ info('Member added to plan', { planId, userId, interviewId: newInterviewId });
134
+ return { interviewId: newInterviewId };
135
+ }
136
+ async removeMember(planId, interviewId) {
137
+ await this.prisma.$transaction(async (tx) => {
138
+ const interview = await tx.interview.findUnique({ where: { id: interviewId } });
139
+ if (!interview) {
140
+ throw new InterviewNotFoundError(interviewId);
141
+ }
142
+ if (interview.planId !== planId) {
143
+ throw new InvalidStateError(`Interview does not belong to plan: ${interviewId}`);
144
+ }
145
+ if (interview.status === 'COMPLETED') {
146
+ throw new InvalidStateError(`Cannot remove completed interview: ${interviewId}`);
147
+ }
148
+ const plan = await tx.interviewPlan.findUnique({ where: { id: planId } });
149
+ if (!plan) {
150
+ throw new PlanNotFoundError(planId);
151
+ }
152
+ const wasCounted = interview.sendStatus === SendStatus.SENT || interview.sendStatus === SendStatus.FAILED;
153
+ const wasFailed = interview.sendStatus === SendStatus.FAILED;
154
+ await tx.interview.delete({ where: { id: interviewId } });
155
+ const existingInvitees = Array.isArray(plan.inviteeData)
156
+ ? plan.inviteeData
157
+ : [];
158
+ const updatedInvitees = existingInvitees.filter((inv) => inv.userId !== interview.userId);
159
+ const planUpdate = {
160
+ inviteeData: updatedInvitees,
161
+ updatedBy: 'admin',
162
+ };
163
+ if (wasCounted) {
164
+ planUpdate.sentCount = { decrement: 1 };
165
+ }
166
+ if (wasFailed) {
167
+ planUpdate.failedCount = { decrement: 1 };
168
+ }
169
+ await tx.interviewPlan.update({
170
+ where: { id: planId },
171
+ data: planUpdate,
172
+ });
173
+ info('Member removed from plan', {
174
+ planId,
175
+ interviewId,
176
+ userId: interview.userId,
177
+ wasCounted,
178
+ wasFailed,
179
+ });
180
+ });
181
+ }
182
+ async sendReminder(planId, interviewId) {
183
+ const plan = await this.prisma.interviewPlan.findUnique({ where: { id: planId } });
184
+ if (!plan) {
185
+ throw new PlanNotFoundError(planId);
186
+ }
187
+ let targets;
188
+ if (interviewId) {
189
+ const interview = await this.prisma.interview.findUnique({ where: { id: interviewId } });
190
+ if (!interview || interview.planId !== planId) {
191
+ throw new InterviewNotFoundError(interviewId);
192
+ }
193
+ if (interview.status === 'COMPLETED' || interview.status === 'CANCELLED') {
194
+ return { reminded: 0, failed: 0 };
195
+ }
196
+ targets = [{ id: interview.id, userId: interview.userId }];
197
+ }
198
+ else {
199
+ targets = await this.prisma.interview.findMany({
200
+ where: {
201
+ planId,
202
+ status: { notIn: ['COMPLETED', 'CANCELLED'] },
203
+ },
204
+ select: { id: true, userId: true },
205
+ });
206
+ }
207
+ if (targets.length === 0) {
208
+ return { reminded: 0, failed: 0 };
209
+ }
210
+ const message = `【访谈提醒】您参与的访谈 "${plan.name}" 尚未完成,请抽空回复访谈邀约消息继续完成。`;
211
+ const concurrency = 10;
212
+ let reminded = 0;
213
+ let failed = 0;
214
+ for (let i = 0; i < targets.length; i += concurrency) {
215
+ const batch = targets.slice(i, i + concurrency);
216
+ const results = await Promise.allSettled(batch.map((target) => messageSender.sendTextMessage([target.userId], message)));
217
+ for (let j = 0; j < results.length; j++) {
218
+ const result = results[j];
219
+ if (result.status === 'fulfilled') {
220
+ reminded++;
221
+ }
222
+ else {
223
+ failed++;
224
+ const errMsg = result.reason instanceof Error ? result.reason.message : 'send failed';
225
+ error('Reminder send failed', {
226
+ planId,
227
+ userId: batch[j].userId,
228
+ error: errMsg,
229
+ });
230
+ }
231
+ }
232
+ }
233
+ info('Reminders sent', { planId, reminded, failed });
234
+ return { reminded, failed };
235
+ }
236
+ }
237
+ //# sourceMappingURL=interview-plan-members.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview-plan-members.service.js","sourceRoot":"","sources":["../../src/services/interview-plan-members.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { PlanStatus } from '@prisma/client';
2
+ import { InterviewPlanServiceBase } from './interview-plan-base.service.js';
3
+ import type { CreateAndPublishInput, ImportResult, InviteeData } from './interview-plan-base.service.js';
4
+ export declare class InterviewPlanSendService extends InterviewPlanServiceBase {
5
+ importInvitees(planId: string, invitees: InviteeData[]): Promise<ImportResult>;
6
+ sendInvitations(planId: string): Promise<{
7
+ sent: number;
8
+ failed: number;
9
+ }>;
10
+ resendToInterview(planId: string, interviewId: string): Promise<{
11
+ success: boolean;
12
+ error?: string;
13
+ }>;
14
+ private sendInvitation;
15
+ updatePlanStatus(planId: string, status: PlanStatus): Promise<void>;
16
+ pausePlan(planId: string): Promise<void>;
17
+ resumePlan(planId: string): Promise<void>;
18
+ cancelPlan(planId: string): Promise<void>;
19
+ createAndPublish(input: CreateAndPublishInput): Promise<{
20
+ planId: string;
21
+ imported: number;
22
+ sent: number;
23
+ failed: number;
24
+ errors: string[];
25
+ }>;
26
+ }
27
+ //# sourceMappingURL=interview-plan-send.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview-plan-send.service.d.ts","sourceRoot":"","sources":["../../src/services/interview-plan-send.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,gBAAgB,CAAC;AAGhE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EACV,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACZ,MAAM,kCAAkC,CAAC;AAG1C,qBAAa,wBAAyB,SAAQ,wBAAwB;IAC9D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAyC9E,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAmF1E,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;YA+ElC,cAAc;IAWtB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC;QAC5D,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;CAgCH"}
@@ -0,0 +1,250 @@
1
+ import { PlanStatus, SendStatus } from '@prisma/client';
2
+ import { messageSender } from '../integrations/dingtalk/message-sender.js';
3
+ import { error, info, warn } from '../utils/logger.js';
4
+ import { InterviewPlanServiceBase } from './interview-plan-base.service.js';
5
+ import { parseInviteeText } from './interview-plan-base.service.js';
6
+ export class InterviewPlanSendService extends InterviewPlanServiceBase {
7
+ async importInvitees(planId, invitees) {
8
+ const result = { success: 0, failed: 0, errors: [] };
9
+ const plan = await this.prisma.interviewPlan.findUnique({ where: { id: planId } });
10
+ if (!plan)
11
+ throw new Error(`Plan not found: ${planId}`);
12
+ const existingUserIds = new Set((await this.prisma.interview.findMany({ where: { planId }, select: { userId: true } })).map((i) => i.userId));
13
+ const uniqueInvitees = new Map();
14
+ for (const inv of invitees)
15
+ uniqueInvitees.set(inv.userId, inv);
16
+ const interviews = [];
17
+ for (const invitee of uniqueInvitees.values()) {
18
+ if (existingUserIds.has(invitee.userId)) {
19
+ result.failed++;
20
+ result.errors.push(`User ${invitee.userId} already exists in plan`);
21
+ continue;
22
+ }
23
+ interviews.push({
24
+ userId: invitee.userId,
25
+ templateId: plan.templateId,
26
+ planId: planId,
27
+ status: 'PENDING',
28
+ });
29
+ }
30
+ if (interviews.length > 0) {
31
+ await this.prisma.interview.createMany({ data: interviews });
32
+ result.success = interviews.length;
33
+ }
34
+ await this.prisma.interviewPlan.update({
35
+ where: { id: planId },
36
+ data: {
37
+ inviteeData: Array.from(uniqueInvitees.values()),
38
+ status: PlanStatus.READY,
39
+ updatedBy: 'admin',
40
+ },
41
+ });
42
+ info('Invitees imported', { planId, success: result.success, failed: result.failed });
43
+ return result;
44
+ }
45
+ async sendInvitations(planId) {
46
+ const plan = await this.prisma.interviewPlan.findUnique({
47
+ where: { id: planId },
48
+ include: {
49
+ template: { select: { content: true } },
50
+ interviews: {
51
+ where: { status: 'PENDING' },
52
+ },
53
+ },
54
+ });
55
+ if (!plan) {
56
+ throw new Error(`Plan not found: ${planId}`);
57
+ }
58
+ let invitationPrompt = '';
59
+ if (plan.template?.content) {
60
+ try {
61
+ const content = JSON.parse(plan.template.content);
62
+ invitationPrompt = content.invitationPrompt || '';
63
+ }
64
+ catch (err) {
65
+ warn('Failed to parse template content', {
66
+ templateId: plan.templateId,
67
+ error: err instanceof Error ? err.message : String(err),
68
+ });
69
+ }
70
+ }
71
+ let sent = 0;
72
+ let failed = 0;
73
+ for (const interview of plan.interviews) {
74
+ try {
75
+ await this.sendInvitation(interview.userId, plan.name, invitationPrompt);
76
+ sent++;
77
+ await this.prisma.interview.update({
78
+ where: { id: interview.id },
79
+ data: { sendStatus: SendStatus.SENT, sentAt: new Date() },
80
+ });
81
+ }
82
+ catch (err) {
83
+ failed++;
84
+ const errorMsg = err instanceof Error ? err.message : String(err);
85
+ error('Failed to send invitation', {
86
+ planId,
87
+ userId: interview.userId,
88
+ error: errorMsg,
89
+ });
90
+ await this.prisma.interview.update({
91
+ where: { id: interview.id },
92
+ data: { sendStatus: SendStatus.FAILED, sendError: errorMsg },
93
+ });
94
+ }
95
+ }
96
+ let planSendStatus;
97
+ if (failed > 0 && sent > 0) {
98
+ planSendStatus = SendStatus.SENT;
99
+ }
100
+ else if (failed > 0 && sent === 0) {
101
+ planSendStatus = SendStatus.FAILED;
102
+ }
103
+ else if (failed === 0 && sent > 0) {
104
+ planSendStatus = SendStatus.SENT;
105
+ }
106
+ const planUpdateData = {
107
+ status: PlanStatus.RUNNING,
108
+ sentCount: { increment: sent },
109
+ failedCount: { increment: failed },
110
+ startedAt: plan.startedAt || new Date(),
111
+ updatedBy: 'admin',
112
+ };
113
+ if (planSendStatus !== undefined) {
114
+ planUpdateData.sendStatus = planSendStatus;
115
+ }
116
+ await this.prisma.interviewPlan.update({
117
+ where: { id: planId },
118
+ data: planUpdateData,
119
+ });
120
+ info('Invitations sent', { planId, sent, failed });
121
+ return { sent, failed };
122
+ }
123
+ async resendToInterview(planId, interviewId) {
124
+ const interview = await this.prisma.interview.findUnique({
125
+ where: { id: interviewId },
126
+ select: {
127
+ id: true,
128
+ userId: true,
129
+ sendStatus: true,
130
+ plan: { select: { id: true, name: true, templateId: true } },
131
+ },
132
+ });
133
+ if (!interview) {
134
+ return { success: false, error: `Interview not found: ${interviewId}` };
135
+ }
136
+ if (interview.plan?.id !== planId) {
137
+ return {
138
+ success: false,
139
+ error: `Interview ${interviewId} does not belong to plan ${planId}`,
140
+ };
141
+ }
142
+ const template = await this.prisma.template.findUnique({
143
+ where: { id: interview.plan.templateId },
144
+ select: { content: true },
145
+ });
146
+ let invitationPrompt = '';
147
+ if (template?.content) {
148
+ try {
149
+ const content = JSON.parse(template.content);
150
+ invitationPrompt = content.invitationPrompt || '';
151
+ }
152
+ catch (err) {
153
+ warn('Failed to parse template content', {
154
+ templateId: interview.plan.templateId,
155
+ error: err instanceof Error ? err.message : String(err),
156
+ });
157
+ }
158
+ }
159
+ const wasAlreadyCounted = interview.sendStatus === SendStatus.SENT || interview.sendStatus === SendStatus.FAILED;
160
+ try {
161
+ await this.sendInvitation(interview.userId, interview.plan.name, invitationPrompt);
162
+ await this.prisma.interview.update({
163
+ where: { id: interviewId },
164
+ data: { sendStatus: SendStatus.SENT, sentAt: new Date(), sendError: null },
165
+ });
166
+ if (!wasAlreadyCounted) {
167
+ await this.prisma.interviewPlan.update({
168
+ where: { id: planId },
169
+ data: { sentCount: { increment: 1 } },
170
+ });
171
+ }
172
+ info('Resent invitation', { planId, interviewId, userId: interview.userId });
173
+ return { success: true };
174
+ }
175
+ catch (err) {
176
+ const errorMsg = err instanceof Error ? err.message : String(err);
177
+ await this.prisma.interview.update({
178
+ where: { id: interviewId },
179
+ data: { sendStatus: SendStatus.FAILED, sendError: errorMsg },
180
+ });
181
+ if (!wasAlreadyCounted) {
182
+ await this.prisma.interviewPlan.update({
183
+ where: { id: planId },
184
+ data: { failedCount: { increment: 1 } },
185
+ });
186
+ }
187
+ error('Failed to resend invitation', {
188
+ planId,
189
+ interviewId,
190
+ userId: interview.userId,
191
+ error: errorMsg,
192
+ });
193
+ return { success: false, error: errorMsg };
194
+ }
195
+ }
196
+ async sendInvitation(userId, planName, invitationPrompt) {
197
+ const message = invitationPrompt
198
+ ? `${invitationPrompt}\n\n(来自「${planName}」访谈。请直接在钉钉中回复 OpenClaw小钉 任意消息即可开始访谈。)`
199
+ : `您被邀请参与「${planName}」访谈。请直接在钉钉中回复 OpenClaw小钉 任意消息(如"你好"或"开始")即可开始访谈。`;
200
+ await messageSender.sendTextMessage([userId], message);
201
+ }
202
+ async updatePlanStatus(planId, status) {
203
+ const updateData = { status, updatedBy: 'admin' };
204
+ if (status === PlanStatus.COMPLETED) {
205
+ updateData.completedAt = new Date();
206
+ }
207
+ await this.prisma.interviewPlan.update({
208
+ where: { id: planId },
209
+ data: updateData,
210
+ });
211
+ }
212
+ async pausePlan(planId) {
213
+ await this.updatePlanStatus(planId, PlanStatus.PAUSED);
214
+ }
215
+ async resumePlan(planId) {
216
+ await this.updatePlanStatus(planId, PlanStatus.RUNNING);
217
+ }
218
+ async cancelPlan(planId) {
219
+ await this.updatePlanStatus(planId, PlanStatus.CANCELLED);
220
+ }
221
+ async createAndPublish(input) {
222
+ const planId = await this.createPlan({
223
+ name: input.name,
224
+ description: input.description,
225
+ templateId: input.templateId,
226
+ targetDate: input.targetDate ? new Date(input.targetDate) : undefined,
227
+ schedule: input.schedule,
228
+ });
229
+ const invitees = parseInviteeText(input.invitees);
230
+ if (invitees.length === 0) {
231
+ return { planId, imported: 0, sent: 0, failed: 0, errors: ['未提供有效的受访人员'] };
232
+ }
233
+ const importResult = await this.importInvitees(planId, invitees);
234
+ let sent = 0;
235
+ let failed = 0;
236
+ if (input.publish === true) {
237
+ const sendResult = await this.sendInvitations(planId);
238
+ sent = sendResult.sent;
239
+ failed = sendResult.failed;
240
+ }
241
+ return {
242
+ planId,
243
+ imported: importResult.success,
244
+ sent,
245
+ failed,
246
+ errors: importResult.errors,
247
+ };
248
+ }
249
+ }
250
+ //# sourceMappingURL=interview-plan-send.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview-plan-send.service.js","sourceRoot":"","sources":["../../src/services/interview-plan-send.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { parseInviteeText } from './interview-plan-base.service.js';
2
+ export type { CreatePlanInput, CreateAndPublishInput, InviteeData, ImportResult, } from './interview-plan-base.service.js';
3
+ export { InterviewPlanServiceBase } from './interview-plan-base.service.js';
4
+ export { InterviewPlanSendService } from './interview-plan-send.service.js';
5
+ export { InterviewPlanService } from './interview-plan-members.service.js';
6
+ export { PlanNotFoundError, InterviewNotFoundError, MemberConflictError, MemberNotFoundError, InvalidMemberInputError, InvalidStateError, } from './interview-plan-members.service.js';
7
+ export type { AddMemberInput } from './interview-plan-members.service.js';
8
+ //# sourceMappingURL=interview-plan.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview-plan.service.d.ts","sourceRoot":"","sources":["../../src/services/interview-plan.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,YAAY,GACb,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAE3E,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,qCAAqC,CAAC;AAE7C,YAAY,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Barrel file: re-exports from split modules for backwards compatibility.
2
+ // All existing imports from './interview-plan.service.js' continue to work.
3
+ export { parseInviteeText } from './interview-plan-base.service.js';
4
+ export { InterviewPlanServiceBase } from './interview-plan-base.service.js';
5
+ export { InterviewPlanSendService } from './interview-plan-send.service.js';
6
+ export { InterviewPlanService } from './interview-plan-members.service.js';
7
+ export { PlanNotFoundError, InterviewNotFoundError, MemberConflictError, MemberNotFoundError, InvalidMemberInputError, InvalidStateError, } from './interview-plan-members.service.js';
8
+ //# sourceMappingURL=interview-plan.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview-plan.service.js","sourceRoot":"","sources":["../../src/services/interview-plan.service.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAE5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAOpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAE3E,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type LLMService } from '../integrations/llm/base.js';
2
+ export interface SubTheme {
3
+ subTopicName: string;
4
+ mentionCount: number;
5
+ overallSentiment: string;
6
+ representativeQuotes: string[];
7
+ }
8
+ export interface EmergentIssue {
9
+ name: string;
10
+ mentionCount: number;
11
+ urgency: 'high' | 'medium' | 'low';
12
+ representativeQuotes: string[];
13
+ }
14
+ export declare function clusterDimensionQuotes(quotes: string[], dimension: string, llm: LLMService): Promise<SubTheme[]>;
15
+ export declare function discoverEmergentIssues(allEmergents: string[], llm: LLMService): Promise<EmergentIssue[]>;
16
+ //# sourceMappingURL=llm-clustering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-clustering.d.ts","sourceRoot":"","sources":["../../src/services/llm-clustering.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EAAE,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,QAAQ,EAAE,CAAC,CA6BrB;AAED,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EAAE,EACtB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,aAAa,EAAE,CAAC,CA6B1B"}