@mathrunet/masamune_firebase_workflow_marketing 3.8.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 (146) hide show
  1. package/CHANGELOG.md +361 -0
  2. package/LICENSE +21 -0
  3. package/README.md +70 -0
  4. package/assets/fonts/NotoSans-Bold.ttf +1439 -0
  5. package/assets/fonts/NotoSans-Regular.ttf +1439 -0
  6. package/assets/fonts/NotoSans.ttf +0 -0
  7. package/assets/fonts/NotoSansJP-Bold.ttf +0 -0
  8. package/assets/fonts/NotoSansJP-Regular.ttf +0 -0
  9. package/assets/fonts/NotoSansKR-Bold.ttf +1439 -0
  10. package/assets/fonts/NotoSansKR-Regular.ttf +1439 -0
  11. package/assets/fonts/NotoSansKR.ttf +0 -0
  12. package/assets/fonts/NotoSansSC-Bold.ttf +1439 -0
  13. package/assets/fonts/NotoSansSC-Regular.ttf +1439 -0
  14. package/assets/fonts/NotoSansSC.ttf +0 -0
  15. package/dist/clients/app_store_client.d.ts +54 -0
  16. package/dist/clients/app_store_client.js +280 -0
  17. package/dist/clients/app_store_client.js.map +1 -0
  18. package/dist/clients/firebase_analytics_client.d.ts +67 -0
  19. package/dist/clients/firebase_analytics_client.js +411 -0
  20. package/dist/clients/firebase_analytics_client.js.map +1 -0
  21. package/dist/clients/github_content_client.d.ts +83 -0
  22. package/dist/clients/github_content_client.js +443 -0
  23. package/dist/clients/github_content_client.js.map +1 -0
  24. package/dist/clients/google_play_client.d.ts +49 -0
  25. package/dist/clients/google_play_client.js +275 -0
  26. package/dist/clients/google_play_client.js.map +1 -0
  27. package/dist/functions/analyze_github_init.d.ts +37 -0
  28. package/dist/functions/analyze_github_init.js +299 -0
  29. package/dist/functions/analyze_github_init.js.map +1 -0
  30. package/dist/functions/analyze_github_process.d.ts +25 -0
  31. package/dist/functions/analyze_github_process.js +268 -0
  32. package/dist/functions/analyze_github_process.js.map +1 -0
  33. package/dist/functions/analyze_github_summary.d.ts +32 -0
  34. package/dist/functions/analyze_github_summary.js +270 -0
  35. package/dist/functions/analyze_github_summary.js.map +1 -0
  36. package/dist/functions/analyze_market_research.d.ts +40 -0
  37. package/dist/functions/analyze_market_research.js +346 -0
  38. package/dist/functions/analyze_market_research.js.map +1 -0
  39. package/dist/functions/analyze_marketing_data.d.ts +96 -0
  40. package/dist/functions/analyze_marketing_data.js +990 -0
  41. package/dist/functions/analyze_marketing_data.js.map +1 -0
  42. package/dist/functions/collect_from_app_store.d.ts +25 -0
  43. package/dist/functions/collect_from_app_store.js +148 -0
  44. package/dist/functions/collect_from_app_store.js.map +1 -0
  45. package/dist/functions/collect_from_firebase_analytics.d.ts +25 -0
  46. package/dist/functions/collect_from_firebase_analytics.js +142 -0
  47. package/dist/functions/collect_from_firebase_analytics.js.map +1 -0
  48. package/dist/functions/collect_from_google_play_console.d.ts +25 -0
  49. package/dist/functions/collect_from_google_play_console.js +142 -0
  50. package/dist/functions/collect_from_google_play_console.js.map +1 -0
  51. package/dist/functions/generate_marketing_markdown.d.ts +89 -0
  52. package/dist/functions/generate_marketing_markdown.js +653 -0
  53. package/dist/functions/generate_marketing_markdown.js.map +1 -0
  54. package/dist/functions/generate_marketing_pdf.d.ts +25 -0
  55. package/dist/functions/generate_marketing_pdf.js +175 -0
  56. package/dist/functions/generate_marketing_pdf.js.map +1 -0
  57. package/dist/functions/research_market.d.ts +56 -0
  58. package/dist/functions/research_market.js +434 -0
  59. package/dist/functions/research_market.js.map +1 -0
  60. package/dist/functions.d.ts +571 -0
  61. package/dist/functions.js +648 -0
  62. package/dist/functions.js.map +1 -0
  63. package/dist/index.d.ts +13 -0
  64. package/dist/index.js +30 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/locales/de_DE.d.ts +5 -0
  67. package/dist/locales/de_DE.js +111 -0
  68. package/dist/locales/de_DE.js.map +1 -0
  69. package/dist/locales/en.d.ts +5 -0
  70. package/dist/locales/en.js +111 -0
  71. package/dist/locales/en.js.map +1 -0
  72. package/dist/locales/es_ES.d.ts +5 -0
  73. package/dist/locales/es_ES.js +111 -0
  74. package/dist/locales/es_ES.js.map +1 -0
  75. package/dist/locales/fr_FR.d.ts +5 -0
  76. package/dist/locales/fr_FR.js +111 -0
  77. package/dist/locales/fr_FR.js.map +1 -0
  78. package/dist/locales/id_ID.d.ts +5 -0
  79. package/dist/locales/id_ID.js +111 -0
  80. package/dist/locales/id_ID.js.map +1 -0
  81. package/dist/locales/index.d.ts +59 -0
  82. package/dist/locales/index.js +155 -0
  83. package/dist/locales/index.js.map +1 -0
  84. package/dist/locales/ja.d.ts +5 -0
  85. package/dist/locales/ja.js +111 -0
  86. package/dist/locales/ja.js.map +1 -0
  87. package/dist/locales/ko_KR.d.ts +5 -0
  88. package/dist/locales/ko_KR.js +111 -0
  89. package/dist/locales/ko_KR.js.map +1 -0
  90. package/dist/locales/pt_PT.d.ts +5 -0
  91. package/dist/locales/pt_PT.js +111 -0
  92. package/dist/locales/pt_PT.js.map +1 -0
  93. package/dist/locales/ru_RU.d.ts +5 -0
  94. package/dist/locales/ru_RU.js +111 -0
  95. package/dist/locales/ru_RU.js.map +1 -0
  96. package/dist/locales/types.d.ts +105 -0
  97. package/dist/locales/types.js +8 -0
  98. package/dist/locales/types.js.map +1 -0
  99. package/dist/locales/zh_CN.d.ts +5 -0
  100. package/dist/locales/zh_CN.js +111 -0
  101. package/dist/locales/zh_CN.js.map +1 -0
  102. package/dist/models/app_store_data.d.ts +87 -0
  103. package/dist/models/app_store_data.js +8 -0
  104. package/dist/models/app_store_data.js.map +1 -0
  105. package/dist/models/chart_data.d.ts +104 -0
  106. package/dist/models/chart_data.js +8 -0
  107. package/dist/models/chart_data.js.map +1 -0
  108. package/dist/models/common.d.ts +42 -0
  109. package/dist/models/common.js +8 -0
  110. package/dist/models/common.js.map +1 -0
  111. package/dist/models/firebase_analytics_data.d.ts +134 -0
  112. package/dist/models/firebase_analytics_data.js +8 -0
  113. package/dist/models/firebase_analytics_data.js.map +1 -0
  114. package/dist/models/github_analysis_data.d.ts +266 -0
  115. package/dist/models/github_analysis_data.js +101 -0
  116. package/dist/models/github_analysis_data.js.map +1 -0
  117. package/dist/models/google_play_data.d.ts +115 -0
  118. package/dist/models/google_play_data.js +8 -0
  119. package/dist/models/google_play_data.js.map +1 -0
  120. package/dist/models/index.d.ts +14 -0
  121. package/dist/models/index.js +36 -0
  122. package/dist/models/index.js.map +1 -0
  123. package/dist/models/market_research_data.d.ts +259 -0
  124. package/dist/models/market_research_data.js +8 -0
  125. package/dist/models/market_research_data.js.map +1 -0
  126. package/dist/models/marketing_analysis_data.d.ts +200 -0
  127. package/dist/models/marketing_analysis_data.js +8 -0
  128. package/dist/models/marketing_analysis_data.js.map +1 -0
  129. package/dist/models/pdf_data.d.ts +112 -0
  130. package/dist/models/pdf_data.js +8 -0
  131. package/dist/models/pdf_data.js.map +1 -0
  132. package/dist/services/chart_service.d.ts +54 -0
  133. package/dist/services/chart_service.js +436 -0
  134. package/dist/services/chart_service.js.map +1 -0
  135. package/dist/services/github_analysis_service.d.ts +73 -0
  136. package/dist/services/github_analysis_service.js +488 -0
  137. package/dist/services/github_analysis_service.js.map +1 -0
  138. package/dist/services/pdf_service.d.ts +112 -0
  139. package/dist/services/pdf_service.js +1397 -0
  140. package/dist/services/pdf_service.js.map +1 -0
  141. package/dist/utils/github_analysis_storage.d.ts +88 -0
  142. package/dist/utils/github_analysis_storage.js +154 -0
  143. package/dist/utils/github_analysis_storage.js.map +1 -0
  144. package/package.json +64 -0
  145. package/scripts/cleanup_test_data.ts +304 -0
  146. package/scripts/list_test_data.ts +85 -0
@@ -0,0 +1,990 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnalyzeMarketingData = void 0;
4
+ const masamune_firebase_workflow_1 = require("@mathrunet/masamune_firebase_workflow");
5
+ const genai_1 = require("@google/genai");
6
+ const locales_1 = require("../locales");
7
+ /**
8
+ * A function for analyzing marketing data using AI (Gemini).
9
+ *
10
+ * AIを使用してマーケティングデータを解析するためのFunction。
11
+ */
12
+ class AnalyzeMarketingData extends masamune_firebase_workflow_1.WorkflowProcessFunctionBase {
13
+ /**
14
+ * The ID of the function.
15
+ *
16
+ * 関数のID。
17
+ */
18
+ id = "analyze_marketing_data";
19
+ /**
20
+ * Translations for the current locale.
21
+ */
22
+ translations = (0, locales_1.getTranslations)("en");
23
+ /**
24
+ * The process of the function.
25
+ *
26
+ * @param context
27
+ * The context of the function.
28
+ *
29
+ * @returns
30
+ * The action of the function.
31
+ */
32
+ async process(context) {
33
+ const action = context.action;
34
+ const task = context.task;
35
+ // 1. task.results から各データを取得
36
+ const googlePlayConsole = task.results?.googlePlayConsole;
37
+ const appStore = task.results?.appStore;
38
+ const firebaseAnalytics = task.results?.firebaseAnalytics;
39
+ const githubRepository = task.results?.githubRepository;
40
+ // 市場調査データを取得(あれば)
41
+ const marketResearchData = task.results?.marketResearchData;
42
+ const marketResearch = task.results?.marketResearch;
43
+ // 市場調査データが有効かどうかをチェック
44
+ const hasValidMarketResearchData = marketResearchData && !("error" in marketResearchData);
45
+ const hasValidMarketResearch = marketResearch && !("error" in marketResearch);
46
+ // 2. いずれのデータも無ければ空データを返却
47
+ if (!googlePlayConsole && !appStore && !firebaseAnalytics) {
48
+ console.log("AnalyzeMarketingData: No marketing data found in task.results");
49
+ return {
50
+ ...action,
51
+ results: {
52
+ marketingAnalytics: {},
53
+ }
54
+ };
55
+ }
56
+ // 3. 環境変数からプロジェクト情報を取得
57
+ const projectId = process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCP_PROJECT_ID;
58
+ const region = process.env.GCLOUD_REGION || "us-central1";
59
+ const modelName = process.env.GEMINI_MODEL || "gemini-2.5-flash";
60
+ const inputPrice = process.env.MODEL_INPUT_PRICE || 0.0000003;
61
+ const outputPrice = process.env.MODEL_OUTPUT_PRICE || 0.0000025;
62
+ if (!projectId) {
63
+ console.error("AnalyzeMarketingData: No GCP project ID found");
64
+ return {
65
+ ...action,
66
+ results: {
67
+ marketingAnalytics: {
68
+ error: "No GCP project ID configured",
69
+ },
70
+ }
71
+ };
72
+ }
73
+ try {
74
+ // 4. Localeを取得して翻訳を初期化
75
+ const locale = typeof action.locale === "object"
76
+ ? action.locale["@language"]
77
+ : action.locale;
78
+ this.translations = (0, locales_1.getTranslations)(locale);
79
+ // 5. GoogleGenAI を初期化(VertexAI モード)
80
+ const genai = new genai_1.GoogleGenAI({
81
+ vertexai: true,
82
+ project: projectId,
83
+ location: region,
84
+ });
85
+ const combinedData = {
86
+ googlePlayConsole,
87
+ appStore,
88
+ firebaseAnalytics,
89
+ githubRepository,
90
+ marketResearchData: hasValidMarketResearchData ? marketResearchData : undefined,
91
+ marketResearch: hasValidMarketResearch ? marketResearch : undefined,
92
+ };
93
+ // 市場調査データが統合されるかどうかのフラグ(Firestoreはundefinedを許可しないため、必ずbooleanにする)
94
+ const marketDataIntegrated = !!(hasValidMarketResearchData || hasValidMarketResearch);
95
+ // レビューデータを抽出
96
+ const reviews = [
97
+ ...(googlePlayConsole?.recentReviews || []),
98
+ ...(appStore?.recentReviews || []),
99
+ ];
100
+ // 価格を数値に変換(環境変数は文字列の可能性があるため)
101
+ const inputPriceNum = Number(inputPrice);
102
+ const outputPriceNum = Number(outputPrice);
103
+ // 5. 各解析を並列実行
104
+ const [overallResult, suggestionsResult, trendResult, reviewResult, githubImprovementsResult, competitivePositioningResult, marketOpportunityResult,] = await Promise.all([
105
+ this.generateOverallAnalysis(genai, combinedData, modelName),
106
+ this.generateImprovementSuggestions(genai, combinedData, modelName),
107
+ this.generateTrendAnalysis(genai, combinedData, modelName),
108
+ reviews.length > 0
109
+ ? this.analyzeReviews(genai, reviews, modelName)
110
+ : Promise.resolve({
111
+ data: {
112
+ sentiment: { positive: 0, neutral: 0, negative: 0 },
113
+ commonThemes: [],
114
+ actionableInsights: [],
115
+ },
116
+ inputTokens: 0,
117
+ outputTokens: 0,
118
+ }),
119
+ // GitHub改善提案(GitHubデータがある場合のみ)
120
+ githubRepository && !("error" in githubRepository)
121
+ ? this.generateGitHubImprovements(genai, combinedData, modelName)
122
+ : Promise.resolve(null),
123
+ // 競合ポジショニング分析(市場調査データがある場合のみ)
124
+ marketDataIntegrated
125
+ ? this.generateCompetitivePositioning(genai, combinedData, modelName)
126
+ : Promise.resolve(null),
127
+ // 市場機会優先度分析(市場調査データがある場合のみ)
128
+ marketDataIntegrated
129
+ ? this.generateMarketOpportunityPriority(genai, combinedData, modelName)
130
+ : Promise.resolve(null),
131
+ ]);
132
+ // 6. トークン使用量を集計してコストを計算
133
+ const totalInputTokens = overallResult.inputTokens +
134
+ suggestionsResult.inputTokens +
135
+ trendResult.inputTokens +
136
+ reviewResult.inputTokens +
137
+ (githubImprovementsResult?.inputTokens ?? 0) +
138
+ (competitivePositioningResult?.inputTokens ?? 0) +
139
+ (marketOpportunityResult?.inputTokens ?? 0);
140
+ const totalOutputTokens = overallResult.outputTokens +
141
+ suggestionsResult.outputTokens +
142
+ trendResult.outputTokens +
143
+ reviewResult.outputTokens +
144
+ (githubImprovementsResult?.outputTokens ?? 0) +
145
+ (competitivePositioningResult?.outputTokens ?? 0) +
146
+ (marketOpportunityResult?.outputTokens ?? 0);
147
+ // コスト計算(1トークンあたりのドル × トークン数)
148
+ const aiCost = totalInputTokens * inputPriceNum + totalOutputTokens * outputPriceNum;
149
+ // 7. 結果を marketingAnalytics キーで返却
150
+ return {
151
+ ...action,
152
+ usage: (action.usage ?? 0) + aiCost,
153
+ results: {
154
+ marketingAnalytics: {
155
+ overallAnalysis: overallResult.data,
156
+ improvementSuggestions: suggestionsResult.data,
157
+ trendAnalysis: trendResult.data,
158
+ reviewAnalysis: reviewResult.data,
159
+ // 市場調査データがある場合のみ追加
160
+ ...(competitivePositioningResult?.data ? { competitivePositioning: competitivePositioningResult.data } : {}),
161
+ ...(marketOpportunityResult?.data ? { marketOpportunityPriority: marketOpportunityResult.data } : {}),
162
+ marketDataIntegrated,
163
+ generatedAt: new Date().toISOString(),
164
+ },
165
+ // GitHub改善提案(GitHubデータがある場合のみ)
166
+ ...(githubImprovementsResult?.data ? { githubImprovements: githubImprovementsResult.data } : {}),
167
+ }
168
+ };
169
+ }
170
+ catch (error) {
171
+ console.error("AnalyzeMarketingData: Failed to analyze data", error);
172
+ return {
173
+ ...action,
174
+ results: {
175
+ marketingAnalytics: {
176
+ error: error.message,
177
+ },
178
+ }
179
+ };
180
+ }
181
+ }
182
+ /**
183
+ * Generate overall analysis from marketing data.
184
+ */
185
+ async generateOverallAnalysis(genai, data, modelName) {
186
+ try {
187
+ const prompt = this.buildOverallAnalysisPrompt(data);
188
+ const response = await genai.models.generateContent({
189
+ model: modelName,
190
+ contents: prompt,
191
+ config: {
192
+ responseMimeType: "application/json",
193
+ responseSchema: {
194
+ type: genai_1.Type.OBJECT,
195
+ properties: {
196
+ summary: { type: genai_1.Type.STRING },
197
+ highlights: {
198
+ type: genai_1.Type.ARRAY,
199
+ items: { type: genai_1.Type.STRING },
200
+ },
201
+ concerns: {
202
+ type: genai_1.Type.ARRAY,
203
+ items: { type: genai_1.Type.STRING },
204
+ },
205
+ keyMetrics: {
206
+ type: genai_1.Type.ARRAY,
207
+ items: {
208
+ type: genai_1.Type.OBJECT,
209
+ properties: {
210
+ metric: { type: genai_1.Type.STRING },
211
+ value: { type: genai_1.Type.STRING },
212
+ trend: { type: genai_1.Type.STRING },
213
+ },
214
+ },
215
+ },
216
+ },
217
+ required: ["summary", "highlights", "concerns", "keyMetrics"],
218
+ },
219
+ },
220
+ });
221
+ const text = response.text;
222
+ if (!text) {
223
+ throw new Error("No response from AI model");
224
+ }
225
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
226
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
227
+ return {
228
+ data: JSON.parse(text),
229
+ inputTokens,
230
+ outputTokens,
231
+ };
232
+ }
233
+ catch (err) {
234
+ console.error("Failed to generate overall analysis:", err.message);
235
+ return {
236
+ data: {
237
+ summary: "",
238
+ highlights: [],
239
+ concerns: [],
240
+ keyMetrics: [],
241
+ },
242
+ inputTokens: 0,
243
+ outputTokens: 0,
244
+ };
245
+ }
246
+ }
247
+ /**
248
+ * Generate improvement suggestions.
249
+ */
250
+ async generateImprovementSuggestions(genai, data, modelName) {
251
+ try {
252
+ const prompt = this.buildImprovementSuggestionsPrompt(data);
253
+ const response = await genai.models.generateContent({
254
+ model: modelName,
255
+ contents: prompt,
256
+ config: {
257
+ responseMimeType: "application/json",
258
+ responseSchema: {
259
+ type: genai_1.Type.ARRAY,
260
+ items: {
261
+ type: genai_1.Type.OBJECT,
262
+ properties: {
263
+ title: { type: genai_1.Type.STRING },
264
+ description: { type: genai_1.Type.STRING },
265
+ priority: { type: genai_1.Type.STRING },
266
+ category: { type: genai_1.Type.STRING },
267
+ expectedImpact: { type: genai_1.Type.STRING },
268
+ },
269
+ required: ["title", "description", "priority", "category"],
270
+ },
271
+ },
272
+ },
273
+ });
274
+ const text = response.text;
275
+ if (!text) {
276
+ throw new Error("No response from AI model");
277
+ }
278
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
279
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
280
+ return {
281
+ data: JSON.parse(text),
282
+ inputTokens,
283
+ outputTokens,
284
+ };
285
+ }
286
+ catch (err) {
287
+ console.error("Failed to generate improvement suggestions:", err.message);
288
+ return {
289
+ data: [],
290
+ inputTokens: 0,
291
+ outputTokens: 0,
292
+ };
293
+ }
294
+ }
295
+ /**
296
+ * Generate trend analysis.
297
+ */
298
+ async generateTrendAnalysis(genai, data, modelName) {
299
+ try {
300
+ const prompt = this.buildTrendAnalysisPrompt(data);
301
+ const response = await genai.models.generateContent({
302
+ model: modelName,
303
+ contents: prompt,
304
+ config: {
305
+ responseMimeType: "application/json",
306
+ responseSchema: {
307
+ type: genai_1.Type.OBJECT,
308
+ properties: {
309
+ userGrowthTrend: { type: genai_1.Type.STRING },
310
+ engagementTrend: { type: genai_1.Type.STRING },
311
+ ratingTrend: { type: genai_1.Type.STRING },
312
+ predictions: {
313
+ type: genai_1.Type.ARRAY,
314
+ items: { type: genai_1.Type.STRING },
315
+ },
316
+ },
317
+ required: ["userGrowthTrend", "engagementTrend", "ratingTrend", "predictions"],
318
+ },
319
+ },
320
+ });
321
+ const text = response.text;
322
+ if (!text) {
323
+ throw new Error("No response from AI model");
324
+ }
325
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
326
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
327
+ return {
328
+ data: JSON.parse(text),
329
+ inputTokens,
330
+ outputTokens,
331
+ };
332
+ }
333
+ catch (err) {
334
+ console.error("Failed to generate trend analysis:", err.message);
335
+ return {
336
+ data: {
337
+ userGrowthTrend: "",
338
+ engagementTrend: "",
339
+ ratingTrend: "",
340
+ predictions: [],
341
+ },
342
+ inputTokens: 0,
343
+ outputTokens: 0,
344
+ };
345
+ }
346
+ }
347
+ /**
348
+ * Analyze reviews and extract insights.
349
+ */
350
+ async analyzeReviews(genai, reviews, modelName) {
351
+ try {
352
+ const prompt = this.buildReviewAnalysisPrompt(reviews);
353
+ const response = await genai.models.generateContent({
354
+ model: modelName,
355
+ contents: prompt,
356
+ config: {
357
+ responseMimeType: "application/json",
358
+ responseSchema: {
359
+ type: genai_1.Type.OBJECT,
360
+ properties: {
361
+ sentiment: {
362
+ type: genai_1.Type.OBJECT,
363
+ properties: {
364
+ positive: { type: genai_1.Type.NUMBER },
365
+ neutral: { type: genai_1.Type.NUMBER },
366
+ negative: { type: genai_1.Type.NUMBER },
367
+ },
368
+ },
369
+ commonThemes: {
370
+ type: genai_1.Type.ARRAY,
371
+ items: { type: genai_1.Type.STRING },
372
+ },
373
+ actionableInsights: {
374
+ type: genai_1.Type.ARRAY,
375
+ items: { type: genai_1.Type.STRING },
376
+ },
377
+ },
378
+ required: ["sentiment", "commonThemes", "actionableInsights"],
379
+ },
380
+ },
381
+ });
382
+ const text = response.text;
383
+ if (!text) {
384
+ throw new Error("No response from AI model");
385
+ }
386
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
387
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
388
+ return {
389
+ data: JSON.parse(text),
390
+ inputTokens,
391
+ outputTokens,
392
+ };
393
+ }
394
+ catch (err) {
395
+ console.error("Failed to analyze reviews:", err.message);
396
+ return {
397
+ data: {
398
+ sentiment: { positive: 0, neutral: 0, negative: 0 },
399
+ commonThemes: [],
400
+ actionableInsights: [],
401
+ },
402
+ inputTokens: 0,
403
+ outputTokens: 0,
404
+ };
405
+ }
406
+ }
407
+ /**
408
+ * Build prompt for overall analysis.
409
+ */
410
+ buildOverallAnalysisPrompt(data) {
411
+ // 市場調査データのセクションを構築
412
+ let marketResearchSection = "";
413
+ if (data.marketResearchData || data.marketResearch) {
414
+ marketResearchSection = `
415
+ ## 市場調査データ
416
+ ${data.marketResearchData ? `
417
+ ### 市場ポテンシャル
418
+ ${JSON.stringify(data.marketResearchData.marketPotential, null, 2)}
419
+
420
+ ### 競合分析
421
+ ${JSON.stringify(data.marketResearchData.competitorAnalysis, null, 2)}
422
+ ` : ""}
423
+ ${data.marketResearch ? `
424
+ ### 需要予測
425
+ ${JSON.stringify(data.marketResearch.demandForecast, null, 2)}
426
+
427
+ ### キーインサイト
428
+ ${JSON.stringify(data.marketResearch.keyInsights, null, 2)}
429
+ ` : ""}
430
+ `;
431
+ }
432
+ return `You are an expert app marketing analyst. Analyze the following marketing data and provide a comprehensive overview.
433
+
434
+ ## Marketing Data
435
+
436
+ ### Google Play Data
437
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "Not available"}
438
+
439
+ ### App Store Data
440
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "Not available"}
441
+
442
+ ### Firebase Analytics Data
443
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "Not available"}
444
+ ${marketResearchSection}
445
+ ## Instructions
446
+ 1. Write a concise summary (2-3 paragraphs) analyzing the overall app performance
447
+ 2. List 3-5 key highlights (positive points)
448
+ 3. List 2-4 concerns or areas needing attention
449
+ 4. Identify 4-6 key metrics with their values and trends (up/down/stable)
450
+ ${data.marketResearchData || data.marketResearch ? "5. Integrate market research insights into your analysis, considering market potential and competitive landscape" : ""}
451
+
452
+ ${this.translations.respondInLanguage}`;
453
+ }
454
+ /**
455
+ * Build prompt for improvement suggestions.
456
+ */
457
+ buildImprovementSuggestionsPrompt(data) {
458
+ // 市場調査データのセクションを構築
459
+ let marketResearchSection = "";
460
+ if (data.marketResearchData || data.marketResearch) {
461
+ marketResearchSection = `
462
+ ## 市場調査データ
463
+ ${data.marketResearchData ? `
464
+ ### ビジネス機会
465
+ ${JSON.stringify(data.marketResearchData.businessOpportunities, null, 2)}
466
+
467
+ ### 差別化機会
468
+ ${JSON.stringify(data.marketResearchData.competitorAnalysis.differentiationOpportunities, null, 2)}
469
+
470
+ ### 市場ギャップ
471
+ ${JSON.stringify(data.marketResearchData.competitorAnalysis.marketGaps, null, 2)}
472
+ ` : ""}
473
+ ${data.marketResearch ? `
474
+ ### 収益向上施策(市場調査ベース)
475
+ ${JSON.stringify(data.marketResearch.revenueStrategies, null, 2)}
476
+
477
+ ### 流入向上施策(市場調査ベース)
478
+ ${JSON.stringify(data.marketResearch.trafficStrategies, null, 2)}
479
+ ` : ""}
480
+ `;
481
+ }
482
+ return `You are an expert app marketing strategist. Based on the following marketing data, provide actionable improvement suggestions.
483
+
484
+ ## Marketing Data
485
+
486
+ ### Google Play Data
487
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "Not available"}
488
+
489
+ ### App Store Data
490
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "Not available"}
491
+
492
+ ### Firebase Analytics Data
493
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "Not available"}
494
+ ${marketResearchSection}
495
+ ## Instructions
496
+ Provide 5-8 specific, actionable improvement suggestions. For each suggestion:
497
+ 1. title: Brief title (under 50 characters)
498
+ 2. description: Detailed explanation with specific steps (100-200 characters)
499
+ 3. priority: "high", "medium", or "low"
500
+ 4. category: One of "user_acquisition", "retention", "engagement", "monetization", "quality", "development"
501
+ 5. expectedImpact: Expected outcome if implemented
502
+ ${data.marketResearchData || data.marketResearch ? `
503
+ Important: Consider the market research data when making recommendations:
504
+ - Prioritize suggestions that address identified market gaps
505
+ - Leverage business opportunities and differentiation points
506
+ - Align with revenue and traffic strategies from market research
507
+ ` : ""}
508
+ Focus on data-driven recommendations. ${this.translations.respondInLanguage}`;
509
+ }
510
+ /**
511
+ * Build prompt for trend analysis.
512
+ */
513
+ buildTrendAnalysisPrompt(data) {
514
+ // 市場調査データのセクションを構築
515
+ let marketResearchSection = "";
516
+ if (data.marketResearchData || data.marketResearch) {
517
+ marketResearchSection = `
518
+ ## 市場調査データ
519
+ ${data.marketResearch ? `
520
+ ### 需要予測
521
+ ${JSON.stringify(data.marketResearch.demandForecast, null, 2)}
522
+
523
+ ### 市場全体トレンド
524
+ ${data.marketResearch.demandForecast.overallTrend}
525
+ ` : ""}
526
+ ${data.marketResearchData ? `
527
+ ### 市場ドライバー
528
+ ${JSON.stringify(data.marketResearchData.marketPotential.marketDrivers, null, 2)}
529
+
530
+ ### 市場ポテンシャル概要
531
+ ${data.marketResearchData.marketPotential.summary}
532
+ ` : ""}
533
+ `;
534
+ }
535
+ return `You are an expert data analyst specializing in mobile app trends. Analyze the following marketing data and provide trend insights.
536
+
537
+ ## Marketing Data
538
+
539
+ ### Google Play Data
540
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "Not available"}
541
+
542
+ ### App Store Data
543
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "Not available"}
544
+
545
+ ### Firebase Analytics Data
546
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "Not available"}
547
+ ${marketResearchSection}
548
+ ## Instructions
549
+ Analyze trends and provide:
550
+ 1. userGrowthTrend: Analysis of user acquisition and growth patterns (2-3 sentences)
551
+ 2. engagementTrend: Analysis of user engagement metrics (2-3 sentences)
552
+ 3. ratingTrend: Analysis of app ratings and user satisfaction (2-3 sentences)
553
+ 4. predictions: 3-5 predictions for the next period based on current trends
554
+ ${data.marketResearchData || data.marketResearch ? "5. Consider market demand forecasts and market drivers when making predictions" : ""}
555
+
556
+ ${this.translations.respondInLanguage}`;
557
+ }
558
+ /**
559
+ * Build prompt for review analysis.
560
+ */
561
+ buildReviewAnalysisPrompt(reviews) {
562
+ const reviewsText = reviews
563
+ .slice(0, 50) // Limit to 50 reviews to avoid token limits
564
+ .map((r) => `Rating: ${r.rating}/5\nText: ${r.text}\n---`)
565
+ .join("\n");
566
+ return `You are an expert in user feedback analysis. Analyze the following app reviews and extract insights.
567
+
568
+ ## Reviews
569
+ ${reviewsText}
570
+
571
+ ## Instructions
572
+ Analyze the reviews and provide:
573
+ 1. sentiment: Percentage breakdown of positive, neutral, and negative reviews (must sum to 100)
574
+ 2. commonThemes: List 3-6 recurring themes or topics mentioned by users
575
+ 3. actionableInsights: List 3-5 specific, actionable insights based on the feedback
576
+
577
+ ${this.translations.respondInLanguage}`;
578
+ }
579
+ /**
580
+ * Generate GitHub-aware improvement suggestions.
581
+ *
582
+ * GitHubリポジトリ分析に基づく改善提案を生成。
583
+ */
584
+ async generateGitHubImprovements(genai, data, modelName) {
585
+ try {
586
+ const prompt = this.buildGitHubImprovementsPrompt(data);
587
+ const response = await genai.models.generateContent({
588
+ model: modelName,
589
+ contents: prompt,
590
+ config: {
591
+ responseMimeType: "application/json",
592
+ responseSchema: {
593
+ type: genai_1.Type.OBJECT,
594
+ properties: {
595
+ improvementSummary: { type: genai_1.Type.STRING },
596
+ improvements: {
597
+ type: genai_1.Type.ARRAY,
598
+ items: {
599
+ type: genai_1.Type.OBJECT,
600
+ properties: {
601
+ title: { type: genai_1.Type.STRING },
602
+ description: { type: genai_1.Type.STRING },
603
+ priority: { type: genai_1.Type.STRING },
604
+ category: { type: genai_1.Type.STRING },
605
+ expectedImpact: { type: genai_1.Type.STRING },
606
+ relatedFeature: { type: genai_1.Type.STRING },
607
+ codeReferences: {
608
+ type: genai_1.Type.ARRAY,
609
+ items: {
610
+ type: genai_1.Type.OBJECT,
611
+ properties: {
612
+ filePath: { type: genai_1.Type.STRING },
613
+ currentFunctionality: { type: genai_1.Type.STRING },
614
+ proposedChange: { type: genai_1.Type.STRING },
615
+ modificationType: { type: genai_1.Type.STRING },
616
+ },
617
+ required: ["filePath", "currentFunctionality", "proposedChange", "modificationType"],
618
+ },
619
+ },
620
+ },
621
+ required: ["title", "description", "priority", "category", "expectedImpact", "codeReferences"],
622
+ },
623
+ },
624
+ },
625
+ required: ["improvementSummary", "improvements"],
626
+ },
627
+ },
628
+ });
629
+ const text = response.text;
630
+ if (!text) {
631
+ throw new Error("No response from AI model");
632
+ }
633
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
634
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
635
+ const parsed = JSON.parse(text);
636
+ const githubRepo = data.githubRepository;
637
+ return {
638
+ data: {
639
+ repository: githubRepo.repository,
640
+ framework: githubRepo.framework,
641
+ improvements: parsed.improvements,
642
+ improvementSummary: parsed.improvementSummary,
643
+ generatedAt: new Date().toISOString(),
644
+ },
645
+ inputTokens,
646
+ outputTokens,
647
+ };
648
+ }
649
+ catch (err) {
650
+ console.error("Failed to generate GitHub improvements:", err.message);
651
+ return {
652
+ data: {
653
+ repository: data.githubRepository?.repository ?? "",
654
+ framework: data.githubRepository?.framework ?? "",
655
+ improvements: [],
656
+ improvementSummary: "",
657
+ generatedAt: new Date().toISOString(),
658
+ },
659
+ inputTokens: 0,
660
+ outputTokens: 0,
661
+ };
662
+ }
663
+ }
664
+ /**
665
+ * Build prompt for GitHub-aware improvements.
666
+ *
667
+ * GitHub対応改善提案用のプロンプトを生成。
668
+ */
669
+ buildGitHubImprovementsPrompt(data) {
670
+ const github = data.githubRepository;
671
+ // フィーチャーをテキストに変換(最大15件に制限)
672
+ const featuresText = github.features
673
+ .slice(0, 15)
674
+ .map((f) => `### ${f.name}\n${f.description}\nFiles: ${f.relatedFiles.join(", ")}`)
675
+ .join("\n\n");
676
+ // 全てのファイルパスを収集
677
+ const allFilePaths = github.features
678
+ .slice(0, 15)
679
+ .flatMap((f) => f.relatedFiles)
680
+ .filter((v, i, a) => a.indexOf(v) === i) // 重複排除
681
+ .join("\n- ");
682
+ return `あなたはアプリ開発とマーケティング戦略の専門家です。以下のマーケティングデータとコードベース分析に基づいて、具体的なコード改善提案を行ってください。
683
+
684
+ ## アプリケーション情報
685
+ - Repository: ${github.repository}
686
+ - Framework: ${github.framework}
687
+ - Platforms: ${github.platforms.join(", ")}
688
+
689
+ ## アプリケーション概要
690
+ ${github.overview}
691
+
692
+ ## アーキテクチャ
693
+ ${github.architecture}
694
+
695
+ ## 機能とファイル
696
+ ${featuresText}
697
+
698
+ ## 利用可能なファイルパス
699
+ 以下のファイルパスのみをcodeReferencesで使用してください:
700
+ - ${allFilePaths}
701
+
702
+ ## マーケティングデータ
703
+
704
+ ### Google Play Console
705
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "データなし"}
706
+
707
+ ### App Store
708
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "データなし"}
709
+
710
+ ### Firebase Analytics
711
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "データなし"}
712
+
713
+ ## 指示
714
+ マーケティングデータとコードベース分析に基づいて、5-8個の具体的な改善提案を行ってください。
715
+
716
+ 各提案には必ず以下を含めてください:
717
+ 1. **title**: 簡潔なタイトル(50文字以内)
718
+ 2. **description**: 詳細な説明(100-200文字)
719
+ 3. **priority**: "high", "medium", "low" のいずれか
720
+ 4. **category**: "user_acquisition", "retention", "engagement", "monetization", "quality", "development" のいずれか
721
+ 5. **expectedImpact**: 期待される効果(具体的な数値目標があれば含める)
722
+ 6. **relatedFeature**: 上記の機能名から関連するものを選択
723
+ 7. **codeReferences**: 具体的なファイル修正の配列
724
+ - **filePath**: 上記「利用可能なファイルパス」から選択した実際のパス
725
+ - **currentFunctionality**: 現在のファイル/機能の説明
726
+ - **proposedChange**: 提案する具体的な変更内容
727
+ - **modificationType**: "add"(新規追加), "modify"(修正), "refactor"(リファクタリング), "optimize"(最適化)のいずれか
728
+
729
+ Important:
730
+ - codeReferences filePath must be selected from the "Available File Paths" list above
731
+ - Focus on code changes that improve marketing metrics (user acquisition, retention, engagement, monetization)
732
+ - Each improvement suggestion should be specific and actionable
733
+
734
+ ${this.translations.respondInLanguage}`;
735
+ }
736
+ /**
737
+ * Generate competitive positioning analysis.
738
+ *
739
+ * 競合ポジショニング分析を生成。
740
+ */
741
+ async generateCompetitivePositioning(genai, data, modelName) {
742
+ try {
743
+ const prompt = this.buildCompetitivePositioningPrompt(data);
744
+ const response = await genai.models.generateContent({
745
+ model: modelName,
746
+ contents: prompt,
747
+ config: {
748
+ responseMimeType: "application/json",
749
+ responseSchema: {
750
+ type: genai_1.Type.OBJECT,
751
+ properties: {
752
+ marketPosition: { type: genai_1.Type.STRING },
753
+ competitorComparison: {
754
+ type: genai_1.Type.ARRAY,
755
+ items: {
756
+ type: genai_1.Type.OBJECT,
757
+ properties: {
758
+ competitor: { type: genai_1.Type.STRING },
759
+ ourStrengths: {
760
+ type: genai_1.Type.ARRAY,
761
+ items: { type: genai_1.Type.STRING },
762
+ },
763
+ ourWeaknesses: {
764
+ type: genai_1.Type.ARRAY,
765
+ items: { type: genai_1.Type.STRING },
766
+ },
767
+ battleStrategy: { type: genai_1.Type.STRING },
768
+ },
769
+ required: ["competitor", "ourStrengths", "ourWeaknesses", "battleStrategy"],
770
+ },
771
+ },
772
+ differentiationStrategy: { type: genai_1.Type.STRING },
773
+ quickWins: {
774
+ type: genai_1.Type.ARRAY,
775
+ items: { type: genai_1.Type.STRING },
776
+ },
777
+ },
778
+ required: ["marketPosition", "competitorComparison", "differentiationStrategy", "quickWins"],
779
+ },
780
+ },
781
+ });
782
+ const text = response.text;
783
+ if (!text) {
784
+ throw new Error("No response from AI model");
785
+ }
786
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
787
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
788
+ return {
789
+ data: JSON.parse(text),
790
+ inputTokens,
791
+ outputTokens,
792
+ };
793
+ }
794
+ catch (err) {
795
+ console.error("Failed to generate competitive positioning:", err.message);
796
+ return {
797
+ data: {
798
+ marketPosition: "",
799
+ competitorComparison: [],
800
+ differentiationStrategy: "",
801
+ quickWins: [],
802
+ },
803
+ inputTokens: 0,
804
+ outputTokens: 0,
805
+ };
806
+ }
807
+ }
808
+ /**
809
+ * Build prompt for competitive positioning analysis.
810
+ *
811
+ * 競合ポジショニング分析用のプロンプトを生成。
812
+ */
813
+ buildCompetitivePositioningPrompt(data) {
814
+ const competitors = data.marketResearchData?.competitorAnalysis.competitors || [];
815
+ const competitorsList = competitors
816
+ .map((c) => `- ${c.name}: ${c.description}\n 強み: ${c.strengths.join(", ")}\n 弱み: ${c.weaknesses.join(", ")}`)
817
+ .join("\n");
818
+ return `あなたは競合分析の専門家です。以下のアプリパフォーマンスデータと市場調査の競合データに基づいて、競合ポジショニング分析を行ってください。
819
+
820
+ ## 当アプリのパフォーマンスデータ
821
+
822
+ ### Google Play Console
823
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "データなし"}
824
+
825
+ ### App Store
826
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "データなし"}
827
+
828
+ ### Firebase Analytics
829
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "データなし"}
830
+
831
+ ## 市場調査:競合情報
832
+ ${competitorsList || "競合データなし"}
833
+
834
+ ## 市場ランドスケープ
835
+ ${data.marketResearchData?.competitorAnalysis.marketLandscape || "情報なし"}
836
+
837
+ ## 差別化機会
838
+ ${JSON.stringify(data.marketResearchData?.competitorAnalysis.differentiationOpportunities || [], null, 2)}
839
+
840
+ ## 分析指示
841
+ 以下の観点で分析してください:
842
+
843
+ 1. **marketPosition**: 現在の市場での位置づけ(2-3文)
844
+ - 市場シェアの推定
845
+ - 競合との相対的な強さ
846
+
847
+ 2. **competitorComparison**: 各競合との比較(3-5社)
848
+ - **competitor**: 競合名
849
+ - **ourStrengths**: 当アプリの優位点(2-4点)
850
+ - **ourWeaknesses**: 当アプリの劣位点(2-4点)
851
+ - **battleStrategy**: この競合に対する具体的な対抗戦略(1-2文)
852
+
853
+ 3. **differentiationStrategy**: 総合的な差別化戦略(3-4文)
854
+ - 複数の競合に対して有効な差別化ポイント
855
+
856
+ 4. **quickWins**: Quick-win differentiation tactics (3-5 points)
857
+ - Things that can be executed in 1-2 weeks
858
+
859
+ ${this.translations.respondInLanguage}`;
860
+ }
861
+ /**
862
+ * Generate market opportunity priority analysis.
863
+ *
864
+ * 市場機会優先度分析を生成。
865
+ */
866
+ async generateMarketOpportunityPriority(genai, data, modelName) {
867
+ try {
868
+ const prompt = this.buildMarketOpportunityPriorityPrompt(data);
869
+ const response = await genai.models.generateContent({
870
+ model: modelName,
871
+ contents: prompt,
872
+ config: {
873
+ responseMimeType: "application/json",
874
+ responseSchema: {
875
+ type: genai_1.Type.OBJECT,
876
+ properties: {
877
+ prioritizedOpportunities: {
878
+ type: genai_1.Type.ARRAY,
879
+ items: {
880
+ type: genai_1.Type.OBJECT,
881
+ properties: {
882
+ opportunity: { type: genai_1.Type.STRING },
883
+ fitScore: {
884
+ type: genai_1.Type.STRING,
885
+ enum: ["excellent", "good", "moderate", "poor"],
886
+ },
887
+ fitReason: { type: genai_1.Type.STRING },
888
+ requiredChanges: {
889
+ type: genai_1.Type.ARRAY,
890
+ items: { type: genai_1.Type.STRING },
891
+ },
892
+ estimatedEffort: {
893
+ type: genai_1.Type.STRING,
894
+ enum: ["low", "medium", "high"],
895
+ },
896
+ recommendedAction: { type: genai_1.Type.STRING },
897
+ },
898
+ required: ["opportunity", "fitScore", "fitReason", "requiredChanges", "estimatedEffort", "recommendedAction"],
899
+ },
900
+ },
901
+ strategicRecommendation: { type: genai_1.Type.STRING },
902
+ },
903
+ required: ["prioritizedOpportunities", "strategicRecommendation"],
904
+ },
905
+ },
906
+ });
907
+ const text = response.text;
908
+ if (!text) {
909
+ throw new Error("No response from AI model");
910
+ }
911
+ const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
912
+ const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
913
+ return {
914
+ data: JSON.parse(text),
915
+ inputTokens,
916
+ outputTokens,
917
+ };
918
+ }
919
+ catch (err) {
920
+ console.error("Failed to generate market opportunity priority:", err.message);
921
+ return {
922
+ data: {
923
+ prioritizedOpportunities: [],
924
+ strategicRecommendation: "",
925
+ },
926
+ inputTokens: 0,
927
+ outputTokens: 0,
928
+ };
929
+ }
930
+ }
931
+ /**
932
+ * Build prompt for market opportunity priority analysis.
933
+ *
934
+ * 市場機会優先度分析用のプロンプトを生成。
935
+ */
936
+ buildMarketOpportunityPriorityPrompt(data) {
937
+ const opportunities = data.marketResearchData?.businessOpportunities || [];
938
+ const opportunitiesList = opportunities
939
+ .map((o) => `- **${o.title}** (${o.type}, インパクト: ${o.potentialImpact}, 時間枠: ${o.timeframe})\n ${o.description}\n 要件: ${o.requirements.join(", ")}\n リスク: ${o.risks.join(", ")}`)
940
+ .join("\n\n");
941
+ const marketGaps = data.marketResearchData?.competitorAnalysis.marketGaps || [];
942
+ return `あなたは戦略コンサルタントです。以下のアプリパフォーマンスデータと市場機会データに基づいて、機会の優先順位付けを行ってください。
943
+
944
+ ## 当アプリのパフォーマンスデータ
945
+
946
+ ### Google Play Console
947
+ ${data.googlePlayConsole ? JSON.stringify(data.googlePlayConsole, null, 2) : "データなし"}
948
+
949
+ ### App Store
950
+ ${data.appStore ? JSON.stringify(data.appStore, null, 2) : "データなし"}
951
+
952
+ ### Firebase Analytics
953
+ ${data.firebaseAnalytics ? JSON.stringify(data.firebaseAnalytics, null, 2) : "データなし"}
954
+
955
+ ## 市場調査:ビジネス機会
956
+ ${opportunitiesList || "機会データなし"}
957
+
958
+ ## 市場調査:市場ギャップ
959
+ ${JSON.stringify(marketGaps, null, 2)}
960
+
961
+ ## 需要予測サマリー
962
+ ${data.marketResearch?.demandForecast.summary || "情報なし"}
963
+
964
+ ## 分析指示
965
+ 各ビジネス機会と市場ギャップを、当アプリの現状と照らし合わせて優先順位付けしてください。
966
+
967
+ 1. **prioritizedOpportunities**: 優先順位付けされた機会リスト(5-8件)
968
+ - **opportunity**: 機会名(市場調査データから)
969
+ - **fitScore**: 当アプリとの適合度
970
+ - "excellent": 既存機能・リソースで即座に対応可能
971
+ - "good": 小規模な追加開発で対応可能
972
+ - "moderate": 中規模の開発・投資が必要
973
+ - "poor": 大規模な方向転換が必要
974
+ - **fitReason**: 適合度の理由(1-2文)
975
+ - **requiredChanges**: 必要な変更・施策(2-4点)
976
+ - **estimatedEffort**: 実装工数の見積もり(low/medium/high)
977
+ - **recommendedAction**: 推奨アクション(1文)
978
+
979
+ 2. **strategicRecommendation**: Strategic recommendations (3-4 sentences)
980
+ - Priority opportunities to pursue
981
+ - Resource allocation proposals
982
+
983
+ ${this.translations.respondInLanguage}`;
984
+ }
985
+ }
986
+ exports.AnalyzeMarketingData = AnalyzeMarketingData;
987
+ module.exports = (regions, options, data) => new AnalyzeMarketingData(options).build(regions);
988
+ // Export class for testing
989
+ module.exports.AnalyzeMarketingData = AnalyzeMarketingData;
990
+ //# sourceMappingURL=analyze_marketing_data.js.map