Spaces:
Sleeping
Sleeping
| import type { ProposalCnGradioResponse } from '@/schema/gradio-proxy/proposal-cn'; | |
| import type { ProposalFvGradioResponse } from '@/schema/gradio-proxy/proposal-fv'; | |
| import { proposalFvItemSchema } from '@/schema/gradio-proxy/proposal-fv'; | |
| import type { ProposalIntentGradioResponse } from '@/schema/gradio-proxy/proposal-intent'; | |
| import type { ProposalPredictionGradioResponse } from '@/schema/gradio-proxy/proposal-prediction'; | |
| import type { ThemeByMomentItem, ThemeByMomentStrategy } from '@/schema/gradio-proxy/theme-by-moment'; | |
| import { z } from 'zod'; | |
| import { swotDataSchema } from './pox'; | |
| import { themeExtractionResultSchema } from './theme-extraction'; | |
| // セクション型の定義 | |
| export const sectionTypeSchema = z.enum([ | |
| '問題提起/共感', | |
| 'シミュレーション', | |
| '解決策/ベネフィット提示', | |
| '商品/サービスの特徴', | |
| '商品/サービスの詳細情報', | |
| 'SPオファー/限定特典', | |
| '料金/プラン', | |
| 'ご利用の流れ/ステップ', | |
| '成功事例/ユーザーボイス紹介', | |
| '活用シーン', | |
| 'FAQ/よくある質問', | |
| '競合比較', | |
| '権威訴求', | |
| 'メディア掲載情報', | |
| 'スタッフ・メンバー紹介', | |
| '店舗情報', | |
| 'News/更新情報', | |
| ]); | |
| export type SectionType = z.infer<typeof sectionTypeSchema>; | |
| // FV提案 | |
| export const generateFvHtmlRequestSchema = z | |
| .object({ | |
| tabName: z.string(), | |
| fvData: z | |
| .lazy(() => fvDataSchema) | |
| .optional() | |
| .nullable(), | |
| provider: z.enum(['openai', 'gemini', 'claude']).optional(), | |
| referenceUrl: z.string().optional(), | |
| screenshotUrl: z.string().optional(), | |
| dummyMode: z.boolean().optional(), | |
| swotData: z | |
| .lazy(() => swotDataSchema) | |
| .optional() | |
| .nullable(), | |
| userEmail: z.string().optional(), // ユーザーメールアドレス(エラーログ用) | |
| sourcePage: z.string().optional(), // リクエスト元のページ(APIキー選択用) | |
| forceFallbackMode: z.boolean().optional(), // 強制的にGPT-5文字起こし分析ベースフォールバックモードで動作 | |
| themeData: z.lazy(() => themeExtractionResultSchema).optional(), | |
| }) | |
| .superRefine((data, ctx) => { | |
| // ダミーモードでない場合のみfvDataを必須とする | |
| if (!data.dummyMode && !data.fvData) { | |
| ctx.addIssue({ | |
| code: z.ZodIssueCode.custom, | |
| message: 'fvData is required when not in dummy mode', | |
| path: ['fvData'], | |
| }); | |
| } | |
| }); | |
| export type GenerateFvHtmlRequest = z.infer<typeof generateFvHtmlRequestSchema>; | |
| export const generateFvHtmlResponseSchema = z.object({ | |
| html: z.string(), | |
| css: z.string().optional(), | |
| imageUrl: z.string().optional().nullable(), | |
| pipelineType: z.enum(['full', 'simple', 'text-only']).optional(), | |
| imagePrompt: z.string().optional(), | |
| }); | |
| export type GenerateFvHtmlResponse = z.infer<typeof generateFvHtmlResponseSchema>; | |
| // コンテンツ提案 | |
| // contentSectionSchemaは後で定義されるため、遅延評価を使用 | |
| export const generateContentsHtmlRequestSchema = z.object({ | |
| tabName: z.string(), | |
| cnData: z.lazy(() => z.array(contentSectionSchema)), | |
| provider: z.enum(['openai', 'gemini', 'claude']).optional(), | |
| referenceUrl: z.string().optional(), | |
| screenshotUrl: z.string().optional(), | |
| dummyMode: z.boolean().optional(), | |
| userEmail: z.string().optional(), // ユーザーメールアドレス(エラーログ用) | |
| themeData: z.lazy(() => themeExtractionResultSchema).optional(), | |
| }); | |
| export type GenerateContentsHtmlRequest = z.infer<typeof generateContentsHtmlRequestSchema>; | |
| export const generateContentsHtmlResponseSchema = z.object({ | |
| html: z.string(), | |
| css: z.string().optional(), | |
| imageUrl: z.string().optional().nullable(), | |
| message: z.string().optional(), | |
| batchId: z.string().optional(), // 画像生成バッチID(通常モードのみ) | |
| imageCompleted: z.boolean(), // 画像生成完了フラグ | |
| }); | |
| export type GenerateContentsHtmlResponse = z.infer<typeof generateContentsHtmlResponseSchema>; | |
| // 変換後のFVタブデータ型(コンポーネントが期待する型) | |
| export const fvDataSchema = z.object({ | |
| strategy: z.string(), | |
| need: z.string(), | |
| data: z.object({ | |
| fv: proposalFvItemSchema, | |
| }), | |
| fvCreationIntent: z.string().optional(), | |
| }); | |
| export type FvData = z.infer<typeof fvDataSchema>; | |
| // 変換後のCNタブデータ型(コンポーネントが期待する型) | |
| // 動的なフィールドに対応 | |
| const contentFieldSchema = z.union([ | |
| z.object({ value: z.string() }), | |
| z.object({ | |
| 情報源: z.object({ | |
| 他社: z.string(), | |
| 自社: z.string(), | |
| }), | |
| value: z.string(), | |
| }), | |
| ]); | |
| const contentSubItemSchema = z.record(z.string(), contentFieldSchema); | |
| export const contentSectionSchema = z.object({ | |
| 大区分: sectionTypeSchema, | |
| 中区分: z.string(), | |
| 小区分json: z.array(contentSubItemSchema), | |
| 制作意図: z.string(), | |
| }); | |
| export type ContentSection = z.infer<typeof contentSectionSchema>; | |
| export type ContentSubItem = z.infer<typeof contentSubItemSchema>; | |
| export type ContentField = z.infer<typeof contentFieldSchema>; | |
| // スクリーンショット取得API | |
| export const screenshotRequestSchema = z.object({ | |
| url: z.string().url('有効なURLを入力してください'), | |
| width: z.number().optional().default(512), | |
| height: z.number().optional().default(768), | |
| }); | |
| export type ScreenshotRequest = z.infer<typeof screenshotRequestSchema>; | |
| export const screenshotResponseSchema = z.object({ | |
| success: z.boolean(), | |
| screenshotBase64: z.string(), | |
| mimeType: z.string(), | |
| description: z.string().optional(), | |
| error: z.string().optional(), | |
| }); | |
| export type ScreenshotResponse = z.infer<typeof screenshotResponseSchema>; | |
| // Proposal Tabs API Response Types(TypeScript型定義) | |
| export interface ProposalTabData { | |
| intent: { | |
| // proposalIntentから該当する戦略・ニーズのデータを展開 | |
| FV_intent?: string; | |
| CN_intent?: string; | |
| FV_suggest?: string; | |
| CN_suggest?: string; | |
| // fv_creation_intentを追加 | |
| fv_creation_intent?: string; | |
| // cn_creation_intentを追加 | |
| cn_creation_intent?: Record<string, string>; | |
| // proposalPredictionから該当する戦略・ニーズのデータを展開 | |
| prediction?: number; | |
| // 該当するタブのThemeByMomentItemのみ | |
| strategyXMomentItem?: ThemeByMomentItem; | |
| // 戦略タイプの表示名 | |
| strategy: string; | |
| // 方向性(ThemeByMomentStrategyの2つ目のキー = ニーズ) | |
| direction?: string; | |
| }; | |
| fv: FvData; | |
| cn: ContentSection[]; | |
| } | |
| export type ProposalTabsResponse = Record<string, ProposalTabData>; | |
| // レギュレーションチェック用の生データ型定義 | |
| export interface ProposalRawData { | |
| proposal_fv: ProposalFvGradioResponse; | |
| proposal_cn: ProposalCnGradioResponse; | |
| proposal_intent: ProposalIntentGradioResponse; | |
| proposal_prediction?: ProposalPredictionGradioResponse; // レギュレーション時に必要 | |
| strategy_x_moment?: ThemeByMomentStrategy; // 訴求テーマとstoryG表示用 | |
| } | |
| // useProposalTabsの拡張返り値型定義 | |
| export interface ExtendedProposalTabsResponse { | |
| data: ProposalTabsResponse; | |
| rawData?: ProposalRawData; | |
| } | |