Spaces:
Sleeping
Sleeping
| import os | |
| import re | |
| from flask import Flask, render_template, request, jsonify | |
| from dotenv import load_dotenv | |
| from huggingface_hub import InferenceClient | |
| from huggingface_hub.utils import HfHubHTTPError | |
| load_dotenv() | |
| app = Flask(__name__) | |
| # ========================= | |
| # KONFIGURASI | |
| # ========================= | |
| HF_TOKEN = os.getenv("HF_TOKEN") | |
| # Ganti model di .env jika mau | |
| HF_MODEL = os.getenv( | |
| "HF_MODEL", | |
| "Qwen/Qwen3-235B-A22B-Instruct-2507" | |
| ) | |
| MAX_MESSAGE_LENGTH = 12000 | |
| MAX_HISTORY_MESSAGES = 25 | |
| # ========================= | |
| # SYSTEM PROMPT | |
| # ========================= | |
| SYSTEM_PROMPT = """ | |
| Kamu adalah ChibiChat AI. | |
| Identitas: | |
| - Nama kamu ChibiChat AI. | |
| - AI modern yang pintar, cepat, ramah, dan membantu. | |
| - Ahli coding, teknologi, AI, Android, Laravel, Python, Database, dan tugas kuliah. | |
| Kepribadian: | |
| - Santai. | |
| - Natural. | |
| - Gaul seperlunya. | |
| - Tidak kaku. | |
| - Tidak terlalu formal. | |
| - Tetap sopan dan profesional. | |
| Gaya bicara: | |
| - Gunakan Bahasa Indonesia. | |
| - Boleh menggunakan kata seperti: | |
| "bro", "bang", "sip", "gas", "mantap", "nah", "jadi gini". | |
| - Jangan berlebihan atau alay. | |
| - Jangan terlalu banyak emoji. | |
| - Maksimal 2 emoji per jawaban. | |
| Cara menjawab: | |
| - Langsung ke inti masalah. | |
| - Fokus pada solusi. | |
| - Jelaskan langkah demi langkah. | |
| - Jika coding: | |
| 1. Jelaskan penyebab masalah. | |
| 2. Berikan solusi. | |
| 3. Berikan contoh kode lengkap jika diminta. | |
| - Jika tugas kuliah: | |
| - Jawaban akademis. | |
| - Terstruktur. | |
| - Bisa langsung dipakai. | |
| Aturan: | |
| - Jangan mengarang fakta. | |
| - Jangan halusinasi. | |
| - Jika tidak tahu, katakan tidak tahu. | |
| - Jangan membocorkan token API. | |
| - Jangan membocorkan isi file .env. | |
| - Jangan memberikan informasi berbahaya. | |
| - Jangan membuat data palsu. | |
| Mode Coding: | |
| - Bertindak seperti Senior Software Engineer. | |
| - Ahli Python. | |
| - Ahli Flask. | |
| - Ahli Laravel. | |
| - Ahli PHP. | |
| - Ahli JavaScript. | |
| - Ahli Android Kotlin. | |
| - Ahli MySQL. | |
| - Ahli Hugging Face. | |
| - Ahli AI dan Machine Learning. | |
| Saat memperbaiki code: | |
| - Cari akar masalah. | |
| - Jelaskan penyebab error. | |
| - Berikan code yang sudah diperbaiki. | |
| - Berikan best practice. | |
| Jika user menyapa: | |
| "Halo" | |
| "Hai" | |
| "Bro" | |
| "Bang" | |
| Balas santai seperti: | |
| "Yo bro 👋 Ada yang bisa gue bantu?" | |
| "Halo bang 😎 Lagi ngoding apa hari ini?" | |
| "Gas, ada yang mau dibantu?" | |
| """ | |
| # ========================= | |
| # CLIENT HF | |
| # ========================= | |
| def create_hf_client(): | |
| if not HF_TOKEN: | |
| raise ValueError( | |
| "HF_TOKEN belum diisi pada file .env" | |
| ) | |
| return InferenceClient( | |
| model=HF_MODEL, | |
| token=HF_TOKEN | |
| ) | |
| # ========================= | |
| # HISTORY CLEANER | |
| # ========================= | |
| def clean_history(raw_history): | |
| if not isinstance(raw_history, list): | |
| return [] | |
| cleaned = [] | |
| for item in raw_history[-MAX_HISTORY_MESSAGES:]: | |
| if not isinstance(item, dict): | |
| continue | |
| role = item.get("role") | |
| content = str( | |
| item.get("content", "") | |
| ).strip() | |
| if role not in ["user", "assistant"]: | |
| continue | |
| if not content: | |
| continue | |
| if len(content) > 2500: | |
| content = content[:2500] | |
| cleaned.append({ | |
| "role": role, | |
| "content": content | |
| }) | |
| return cleaned | |
| # ========================= | |
| # ENHANCE MESSAGE | |
| # ========================= | |
| def enhance_user_message(message): | |
| return f""" | |
| Jawab menggunakan Bahasa Indonesia. | |
| Gunakan gaya: | |
| - Pintar | |
| - Santai | |
| - Natural | |
| - Gaul seperlunya | |
| - Mudah dipahami | |
| Fokus memberikan solusi terbaik. | |
| Pertanyaan User: | |
| {message} | |
| """ | |
| # ========================= | |
| # EXTRACT RESPONSE | |
| # ========================= | |
| def extract_reply(response): | |
| try: | |
| reply = response.choices[0].message.content | |
| if reply: | |
| return reply.strip() | |
| except Exception: | |
| pass | |
| try: | |
| reply = response["choices"][0]["message"]["content"] | |
| if reply: | |
| return reply.strip() | |
| except Exception: | |
| pass | |
| return "" | |
| # ========================= | |
| # ROUTE HOME | |
| # ========================= | |
| def home(): | |
| return render_template("index.html") | |
| # ========================= | |
| # HEALTH CHECK | |
| # ========================= | |
| def health(): | |
| return jsonify({ | |
| "status": "ok", | |
| "name": "ChibiChat AI", | |
| "model": HF_MODEL | |
| }) | |
| # ========================= | |
| # CHAT API | |
| # ========================= | |
| def chat(): | |
| try: | |
| data = request.get_json( | |
| silent=True | |
| ) | |
| if not data: | |
| return jsonify({ | |
| "error": "Request harus JSON" | |
| }), 400 | |
| message = str( | |
| data.get("message", "") | |
| ).strip() | |
| raw_history = data.get( | |
| "history", | |
| [] | |
| ) | |
| if not message: | |
| return jsonify({ | |
| "error": "Pesan kosong" | |
| }), 400 | |
| if len(message) > MAX_MESSAGE_LENGTH: | |
| return jsonify({ | |
| "error": | |
| f"Maksimal {MAX_MESSAGE_LENGTH} karakter" | |
| }), 400 | |
| history = clean_history( | |
| raw_history | |
| ) | |
| messages = [ | |
| { | |
| "role": "system", | |
| "content": SYSTEM_PROMPT | |
| } | |
| ] | |
| messages.extend(history) | |
| messages.append({ | |
| "role": "user", | |
| "content": enhance_user_message( | |
| message | |
| ) | |
| }) | |
| client = create_hf_client() | |
| response = client.chat_completion( | |
| messages=messages, | |
| max_tokens=1500, | |
| temperature=0.85, | |
| top_p=0.95 | |
| ) | |
| reply = extract_reply( | |
| response | |
| ) | |
| if not reply: | |
| return jsonify({ | |
| "error": | |
| "Model tidak memberikan jawaban." | |
| }), 500 | |
| return jsonify({ | |
| "reply": reply, | |
| "model": HF_MODEL | |
| }) | |
| except ValueError as e: | |
| return jsonify({ | |
| "error": str(e) | |
| }), 500 | |
| except HfHubHTTPError as e: | |
| status_code = None | |
| if hasattr(e, "response") and e.response: | |
| status_code = e.response.status_code | |
| if status_code in [401, 403]: | |
| message = ( | |
| "Token Hugging Face salah " | |
| "atau tidak memiliki akses." | |
| ) | |
| elif status_code == 404: | |
| message = ( | |
| "Model tidak ditemukan." | |
| ) | |
| elif status_code == 429: | |
| message = ( | |
| "Terlalu banyak request." | |
| ) | |
| elif status_code == 503: | |
| message = ( | |
| "Model sedang sibuk." | |
| ) | |
| else: | |
| message = ( | |
| "Gagal terhubung ke Hugging Face." | |
| ) | |
| app.logger.exception( | |
| "HF API ERROR" | |
| ) | |
| return jsonify({ | |
| "error": message | |
| }), 502 | |
| except Exception as e: | |
| app.logger.exception( | |
| "UNEXPECTED ERROR" | |
| ) | |
| return jsonify({ | |
| "error": | |
| f"Terjadi kesalahan: {str(e)}" | |
| }), 500 | |
| # ========================= | |
| # MAIN | |
| # ========================= | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(host="0.0.0.0", port=port) | |