0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CSVをアップロードするだけで売上を予測するAI(FastAPI + Prophet + React)

0
Posted at

はじめに
「売上データは管理しているけど、将来の予測ができない」という飲食店・EC・小売店向けに、売上予測AIサービス SalesCast ができました。
https://salescast.vercel.app
CSVをアップロード、またはExcelからコピペするだけでAIが将来の売上を予測してくれます。無料・登録不要です。
この記事では技術的な実装の工夫などを紹介します

また僕自身もプログラミングは学んでいますが、経験が浅いので今回はAIを活用して開発しています。
(サイトのデザインからもClaudeの風を感じるかもしれません)
フィードバックや改善要望もお待ちしております

技術スタック
レイヤー    技術
バックエンド  FastAPI + Prophet
フロントエンド React + Vite + Recharts
デプロイ    Render(バックエンド)+ Vercel(フロントエンド)

  1. CSVの列名を自動検出する
    ユーザーによってCSVの列名はバラバラです(「日付」「date」「売上」「sales」など)。毎回列名を指定させるのはUXが悪いので、自動検出する仕組みです

python
def _detect_date_column(df: pd.DataFrame) -> str:
for col in df.columns:
try:
pd.to_datetime(df[col])
return col
except Exception:
continue
raise ValueError("日付列が見つかりませんでした")

  1. ExcelからのコピペをそのままCSVに変換する
    Excelからコピーしたデータはタブorカンマ区切りで貼り付けられます。これをそのままAPIに投げられるよう、フロントエンドで正規化しています。

javascript
function pasteTextToFile(text) {
const normalized = text
.trim()
.split("\n")
.map((line) => line.trim().replace(/\t+/g, ","))
.join("\n");
const hasHeader = /[a-zA-Zぁ-ん一-龯]/.test(normalized.split("\n")[0]);
const csv = hasHeader ? normalized : "date,sales\n" + normalized;
return new File([csv], "pasted_data.csv", { type: "text/csv" });
}

  1. ユーザーデータをオプトイン+匿名化で学習に活用
    ユーザーが同意した場合のみデータを保存して精度向上に使います。その際、以下の匿名化を行っています。

日付を±180日ランダムシフト(実際の時期を特定不能に)
売上を0〜1に正規化(絶対的な売上規模を特定不能に)
ランダムなUUIDで保存(ユーザーと紐付けない)

python
def _anonymize(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
offset_days = random.randint(-180, 180)
df["ds"] = df["ds"] + timedelta(days=offset_days)
y_min, y_max = df["y"].min(), df["y"].max()
if y_max > y_min:
df["y"] = (df["y"] - y_min) / (y_max - y_min)
return df

  1. セキュリティ対策
    個人開発でも最低限のセキュリティは必要です。以下を実装しました。

ファイルサイズ制限:5MB以上のファイルはエラー
レートリミット:同一IPから1分間に10回まで(slowapiを使用)
CSVフォーマット検証:拡張子だけでなく中身もチェック

python
limiter = Limiter(key_func=get_remote_address, default_limits=["10/minute"])

@app.post("/predict")
@limiter.limit("10/minute")
async def predict(request: Request, ...):
if len(content) > MAX_FILE_SIZE: # 5MB
raise HTTPException(status_code=400, detail="ファイルサイズは5MB以下にしてください")

今後の予定

Google Sheets連携
商品別・店舗別の複数指標予測
モデル精度の改善(匿名化データの活用)

おわりに
フィードバックや改善要望があればコメントください
サービス:https://salescast.vercel.app
GitHub:https://github.com/Mecharhythm/salescast
#Python #React #機械学習 #個人開発 #FastAPI #Prophet

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?