uploadService.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { apiClient } from './apiClient';
  2. import { IndexingConfig } from '../types';
  3. // web/services/uploadService.ts
  4. export const uploadService = {
  5. async uploadFile(file: File, authToken: string): Promise<any> {
  6. const formData = new FormData();
  7. formData.append('file', file);
  8. const response = await apiClient.request('/upload', {
  9. method: 'POST',
  10. body: formData,
  11. });
  12. if (!response.ok) {
  13. const errorData = await response.json();
  14. throw new Error(errorData.message || 'fileUploadFailed');
  15. }
  16. return response.json();
  17. },
  18. async uploadFileWithConfig(file: File, config: IndexingConfig, authToken: string): Promise<any> {
  19. const formData = new FormData();
  20. formData.append('file', file);
  21. formData.append('chunkSize', config.chunkSize.toString());
  22. formData.append('chunkOverlap', config.chunkOverlap.toString());
  23. formData.append('embeddingModelId', config.embeddingModelId);
  24. if (config.mode) {
  25. formData.append('mode', config.mode);
  26. }
  27. // 分類を追加(指定されている場合)
  28. if (config.groupIds && config.groupIds.length > 0) {
  29. formData.append('groupIds', JSON.stringify(config.groupIds));
  30. }
  31. const response = await apiClient.request('/upload', {
  32. method: 'POST',
  33. body: formData,
  34. });
  35. if (!response.ok) {
  36. const errorData = await response.json();
  37. throw new Error(errorData.message || 'fileUploadFailed');
  38. }
  39. return response.json();
  40. },
  41. async uploadText(content: string, title: string, config: IndexingConfig, authToken: string): Promise<any> {
  42. const { data } = await apiClient.post('/upload/text', {
  43. content,
  44. title,
  45. chunkSize: config.chunkSize.toString(),
  46. chunkOverlap: config.chunkOverlap.toString(),
  47. embeddingModelId: config.embeddingModelId,
  48. mode: config.mode
  49. });
  50. return data;
  51. },
  52. async recommendMode(file: File): Promise<any> {
  53. if (!file || !file.name) {
  54. return {
  55. recommendedMode: 'fast',
  56. reason: 'invalidFile',
  57. warnings: ['incompleteFileInfo'],
  58. };
  59. }
  60. const ext = file.name.toLowerCase().split('.').pop();
  61. const sizeMB = file.size / (1024 * 1024);
  62. const preciseFormats = ['pdf', 'doc', 'docx', 'ppt', 'pptx'];
  63. const supportedFormats = [...preciseFormats, 'xls', 'xlsx', 'txt', 'md', 'html', 'json', 'csv'];
  64. if (!supportedFormats.includes(ext || '')) {
  65. return {
  66. recommendedMode: 'fast',
  67. reason: `unsupportedFileFormat`,
  68. reasonArgs: [ext],
  69. warnings: ['willUseFastMode'],
  70. };
  71. }
  72. if (!preciseFormats.includes(ext || '')) {
  73. return {
  74. recommendedMode: 'fast',
  75. reason: `formatNoPrecise`,
  76. reasonArgs: [ext],
  77. warnings: ['willUseFastMode'],
  78. };
  79. }
  80. if (sizeMB < 5) {
  81. return {
  82. recommendedMode: 'fast',
  83. reason: 'smallFileFastOk',
  84. estimatedCost: 0,
  85. estimatedTime: sizeMB * 2,
  86. warnings: [],
  87. };
  88. }
  89. if (sizeMB < 50) {
  90. return {
  91. recommendedMode: 'precise',
  92. reason: 'mixedContentPreciseRecommended',
  93. estimatedCost: Math.max(0.01, sizeMB * 0.01),
  94. estimatedTime: sizeMB * 8,
  95. warnings: ['willIncurApiCost'],
  96. };
  97. }
  98. return {
  99. recommendedMode: 'precise',
  100. reason: 'largeFilePreciseRecommended',
  101. estimatedCost: sizeMB * 0.015,
  102. estimatedTime: sizeMB * 12,
  103. warnings: ['longProcessingTime', 'highApiCost', 'considerFileSplitting'],
  104. };
  105. },
  106. };