FE_Test / server /routes /gradio-proxy.ts
GitHub Actions
Deploy from GitHub Actions [test] - 2025-10-31 10:18:25
5f2aab6
import { checkUrlRequestSchema } from '@/schema/gradio-proxy/check-url';
import { excelRequestSchema } from '@/schema/gradio-proxy/excel';
import { poxRequestSchema } from '@/schema/gradio-proxy/pox';
import { proposalCnRequestSchema } from '@/schema/gradio-proxy/proposal-cn';
import { proposalFvRequestSchema } from '@/schema/gradio-proxy/proposal-fv';
import { proposalIntentRequestSchema } from '@/schema/gradio-proxy/proposal-intent';
import { proposalPredictionRequestSchema } from '@/schema/gradio-proxy/proposal-prediction';
import { refreshMomentRequestSchema } from '@/schema/gradio-proxy/refresh-moment';
import { scoreStep3RequestSchema } from '@/schema/gradio-proxy/score-step3';
import { summaryRequestSchema } from '@/schema/gradio-proxy/summary';
import { themeByMomentRequestSchema } from '@/schema/gradio-proxy/theme-by-moment';
import { visScoreRequestSchema } from '@/schema/gradio-proxy/vis-score';
import { AppError } from '@/lib/errors';
import { getDummyData } from '@/server/utils/dummy-data';
import {
getCheckUrl,
getExcel,
getPox,
getProposalCn,
getProposalFv,
getProposalIntent,
getProposalPrediction,
getRefreshMoment,
getScoreStep3,
getSummary,
getThemeByMoment,
getVisScore,
} from '@/services/gradio';
import { zValidator } from '@hono/zod-validator';
import { Hono } from 'hono';
/**
* Gradio APIエラーを統一的に処理するヘルパー関数
*/
function handleGradioError(error: unknown): { statusCode: number; message: string } {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof AppError) {
errorMessage = error.message;
statusCode = error.statusCode || 500;
} else if (error instanceof Error) {
errorMessage = error.message;
// タイムアウトエラー
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
if ('statusCode' in error && typeof error.statusCode === 'number') {
statusCode = error.statusCode;
}
}
return { statusCode, message: errorMessage };
}
export const gradioProxyRoute = new Hono()
// check_url API (POST /check-url)
.post('/check-url', zValidator('json', checkUrlRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_check_url.json');
return c.json(dummyData);
} catch (error) {
console.error('[CHECK_URL API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getCheckUrl(
{
ownUrl: request.ownUrl,
urlText: request.urlText,
ownImage: request.ownImage,
ownImageName: request.ownImageName,
},
request.userEmail || null,
request.userIdentifier,
);
// エラーレスポンスチェック
if (result && typeof result === 'object' && 'status' in result && result.status === 'error') {
return c.json(result, 400);
}
return c.json(result);
} catch (error) {
console.error('[CHECK_URL API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
})
// score_step3 API (POST /score-step3)
.post(
'/score-step3',
zValidator('json', scoreStep3RequestSchema, (result, c) => {
if (!result.success) {
console.error('[SCORE_STEP3 API] Validation error:', JSON.stringify(result.error.issues, null, 2));
return c.json(
{
status: 'error',
message: `リクエストのバリデーションに失敗しました: ${result.error.issues.map((i) => i.message).join(', ')}`,
},
400,
);
}
}),
async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_score.json');
return c.json(dummyData);
} catch (error) {
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getScoreStep3(
{
tempImages: request.tempImages,
fvInfos: request.fvInfos,
cnInfo: request.cnInfo,
commonDict: request.commonDict,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[SCORE_STEP3 API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
},
)
// vis_score API (POST /vis-score)
.post('/vis-score', zValidator('json', visScoreRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_vis_score.json');
return c.json(dummyData);
} catch (error) {
console.error('[VIS_SCORE API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getVisScore(
{
commonDict: request.commonDict,
scoreDict: request.scoreDict,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[VIS_SCORE API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
})
// summary API (POST /summary)
.post('/summary', zValidator('json', summaryRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_summary.json');
return c.json(dummyData);
} catch (error) {
console.error('[SUMMARY API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getSummary(
{
commonDict: request.commonDict,
scoreDict: request.scoreDict,
score_total: request.score_total,
url_category_scores: request.url_category_scores,
own_category_score: request.own_category_score,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[SUMMARY API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
})
// pox API (POST /pox)
.post('/pox', zValidator('json', poxRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_pox.json');
return c.json(dummyData);
} catch (error) {
console.error('[POX API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getPox(
{
commonDict: request.commonDict,
scoreDict: request.scoreDict,
score_total: request.score_total,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[POX API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
})
// excel API (POST /excel)
.post('/excel', zValidator('json', excelRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_excel.json');
return c.json(dummyData);
} catch (error) {
console.error('[EXCEL API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getExcel(
{
ownUrl: request.ownUrl,
urlText: request.urlText,
commonDict: request.commonDict,
scoreDict: request.scoreDict,
summary: request.summary,
swot: request.swot,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[EXCEL API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
})
// theme_by_moment API (POST /theme-by-moment)
.post(
'/theme-by-moment',
zValidator('json', themeByMomentRequestSchema, (result, c) => {
if (!result.success) {
console.error('[THEME_BY_MOMENT API] Validation failed:', result.error.issues);
return c.json({ success: false, error: result.error.issues }, 400);
}
}),
async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_theme_by_moment.json');
return c.json(dummyData);
} catch (error) {
console.error('[THEME_BY_MOMENT API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getThemeByMoment(
{
commonDict: request.commonDict || {},
scoreDict: request.scoreDict || {},
swot: request.swot || {},
strategies: request.strategies || {},
moments: request.moments || [],
fv_infos: request.fv_infos ?? undefined,
own_theme: request.own_theme || '',
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof Error) {
errorMessage = error.message;
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
}
return c.json(
{
status: 'error',
message: errorMessage,
},
statusCode as 400 | 408 | 500,
);
}
},
)
// proposal_fv API (POST /proposal-fv)
.post('/proposal-fv', zValidator('json', proposalFvRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_proposal_fv.json');
return c.json(dummyData);
} catch (error) {
console.error('[PROPOSAL_FV API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getProposalFv(
{
strategy_x_moment: request.strategy_x_moment,
commonDict: request.commonDict,
fv_infos: request.fv_infos,
strategies: request.strategies,
cnall_json: request.cnall_json,
url_category_scores: request.url_category_scores,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof Error) {
errorMessage = error.message;
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
}
return c.json(
{
status: 'error',
message: errorMessage,
},
statusCode as 400 | 408 | 500,
);
}
})
// proposal_cn API (POST /proposal-cn)
.post('/proposal-cn', zValidator('json', proposalCnRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_proposal_cn.json');
return c.json(dummyData);
} catch (error) {
console.error('[PROPOSAL_CN API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getProposalCn(
{
strategy_x_moment: request.strategy_x_moment,
commonDict: request.commonDict,
cnall_json: request.cnall_json,
strategies: request.strategies,
fv_infos: request.fv_infos,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof Error) {
errorMessage = error.message;
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
}
return c.json(
{
status: 'error',
message: errorMessage,
},
statusCode as 400 | 408 | 500,
);
}
})
// proposal_prediction API (POST /proposal-prediction)
.post('/proposal-prediction', zValidator('json', proposalPredictionRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_proposal_prediction.json');
return c.json(dummyData);
} catch (error) {
console.error('[PROPOSAL_PREDICTION API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getProposalPrediction(
{
proposal_fv: request.proposal_fv,
proposal_cn: request.proposal_cn,
commonDict: request.commonDict,
fv_infos: request.fv_infos,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof Error) {
errorMessage = error.message;
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
}
return c.json(
{
status: 'error',
message: errorMessage,
},
statusCode as 400 | 408 | 500,
);
}
})
// proposal_intent API (POST /proposal-intent)
.post('/proposal-intent', zValidator('json', proposalIntentRequestSchema), async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_proposal_intent.json');
return c.json(dummyData);
} catch (error) {
console.error('[PROPOSAL_INTENT API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getProposalIntent(
{
proposal_fv: request.proposal_fv,
proposal_cn: request.proposal_cn,
commonDict: request.commonDict,
swot: request.swot,
q_summary: request.q_summary,
strategy_x_moment: request.strategy_x_moment,
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
let errorMessage = '不明なエラーが発生しました。';
let statusCode = 500;
if (error instanceof Error) {
errorMessage = error.message;
if (error.message.includes('タイムアウト') || error.message.includes('timeout')) {
errorMessage = 'タイムアウトが発生しました。もう一度やり直してください。';
statusCode = 408;
}
}
return c.json(
{
status: 'error',
message: errorMessage,
},
statusCode as 400 | 408 | 500,
);
}
})
// refresh_moment API (POST /refresh-moment)
.post(
'/refresh-moment',
zValidator('json', refreshMomentRequestSchema, (result, c) => {
if (!result.success) {
console.error('[REFRESH_MOMENT API] Validation failed:', result.error.issues);
return c.json({ success: false, error: result.error.issues }, 400);
}
}),
async (c) => {
try {
const request = c.req.valid('json');
// ダミーモード時はJSONファイルを返す
if (request.dummyMode) {
try {
const dummyData = getDummyData('get_refresh_moment.json');
return c.json(dummyData);
} catch (error) {
console.error('[REFRESH_MOMENT API] Dummy data loading failed:', error);
return c.json(
{
status: 'error',
message: error instanceof Error ? error.message : 'ダミーデータの読み込みに失敗しました。',
},
404,
);
}
}
// 通常モード時はGradio APIを呼び出し
const result = await getRefreshMoment(
{
commonDict: request.commonDict || {},
scoreDict: request.scoreDict || {},
swot: request.swot || {},
},
request.userEmail || null,
request.userIdentifier,
);
return c.json(result);
} catch (error) {
console.error('[REFRESH_MOMENT API] Error:', error);
const { statusCode, message } = handleGradioError(error);
return c.json(
{
status: 'error',
message,
},
statusCode as 400 | 408 | 500,
);
}
},
);