muhammadhabibna's picture
refactor: remove toggle features, LLM always gives full unified analysis
986780f
Raw
History Blame Contribute Delete
4.86 kB
import os
import pandas as pd
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from langchain_openai import ChatOpenAI
from langchain_experimental.agents import create_pandas_dataframe_agent
app = FastAPI(title="BiteSight Analytics API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, replace with your Vercel URL
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Load data on startup
DATA_FILE = "data_client.csv"
try:
df = pd.read_csv(DATA_FILE)
print(f"Successfully loaded {DATA_FILE} with {len(df)} rows.")
except Exception as e:
print(f"Warning: Could not load {DATA_FILE}: {e}")
df = pd.DataFrame() # Fallback empty dataframe
class ChatRequest(BaseModel):
question: str
@app.post("/chat")
async def chat(request: ChatRequest):
try:
if df.empty:
return {"answer": "Error: Data source is unavailable on the server."}
akashml_api_key = os.environ.get("AKASHML_API_KEY")
if not akashml_api_key:
return {"answer": "Error: AKASHML_API_KEY environment variable tidak diset di Hugging Face Space Anda."}
# Initialize AkashML LLM via ChatOpenAI (OpenAI-compatible)
llm = ChatOpenAI(
openai_api_key=akashml_api_key,
openai_api_base="https://api.akashml.com/v1",
model_name="MiniMaxAI/MiniMax-M2.5",
temperature=0.2,
max_tokens=8192
)
system_message = (
"You are a world-class F&B Executive Business Consultant and Data Scientist "
"with 20+ years of experience advising top restaurant chains and retail F&B brands. "
"You have deep expertise in sales analytics, consumer behavior, operational efficiency, and growth strategy.\n\n"
"RESPONSE STYLE:\n"
"- If the user sends a general greeting, respond warmly and naturally in Indonesian.\n"
"- If the user asks a business/data question, give a THOROUGH, INSIGHTFUL, and EXECUTIVE-LEVEL analysis. "
"Do NOT give shallow or overly brief answers. Go deep. Uncover layers of insight.\n"
"- ALWAYS include: key data facts WITH specific numbers, analytical commentary explaining the 'why', "
"patterns/anomalies/trends, business implications, AND concrete actionable recommendations.\n"
"- Structure your response FREELY using rich Markdown: use headers (##, ###), bold text, "
"bullet lists, and comparison tables when helpful. DO NOT use any rigid fixed template.\n"
"- ALWAYS respond in fluent, professional INDONESIAN.\n\n"
"PANDAS DATA ENGINE RULES (CRITICAL):\n"
"- A pandas DataFrame named `df` with ALL rows of client transaction data is ALREADY LOADED.\n"
"- ALWAYS run actual pandas operations to get real numbers. NEVER estimate or fabricate data.\n"
"- DO NOT recreate the dataframe using StringIO or hardcoded text. Use `df` directly.\n"
"- Run MULTIPLE pandas queries if needed to build a complete picture "
"(e.g., value_counts, groupby, mean, corr, describe, resample, etc.).\n"
"- Cross-reference multiple dimensions when relevant (e.g., payment method vs. branch vs. time of day).\n\n"
"DATA PRESENTATION RULES:\n"
"- ALWAYS state specific numbers, percentages, and timeframes. Vague statements are not acceptable.\n"
"- Currency is US Dollars ($). ALWAYS format as $XX.XX. NEVER use 'Rp' or 'Rupiah'.\n"
"- Do NOT explain the dataset schema or mention row counts unless explicitly asked.\n"
"- When comparing metrics, provide both absolute numbers AND percentages for clarity.\n"
)
agent = create_pandas_dataframe_agent(
llm,
df,
agent_type="tool-calling",
allow_dangerous_code=True,
handle_parsing_errors=True,
verbose=True,
prefix=system_message
)
response = agent.invoke({"input": request.question})
return {"answer": response.get("output", "No output generated.")}
except Exception as e:
error_msg = str(e)
if "Could not parse" in error_msg:
extracted = error_msg.split("Could not parse")[-1].replace("LLM output:", "").strip(" `'\"")
return {"answer": extracted}
return {"answer": f"Terjadi kendala saat memproses instruksi. Jika Anda sekadar menyapa, halo juga! Jika ini pertanyaan data, format Model mungkin tidak sesuai.\n\n**Log Server:** `{error_msg}`"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860) # Hugging Face Spaces typical port