grad / app.py
newservers's picture
Update app.py
4c49f40 verified
Raw
History Blame Contribute Delete
10.7 kB
from flask import Flask, request, jsonify
from huggingface_hub import InferenceClient
from dotenv import load_dotenv
import os, re, requests, json, logging
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
# Load Hugging Face token
load_dotenv()
client = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1", token=os.getenv("HF_TOKEN"))
app = Flask(__name__)
chat_histories = {}
# --- Nekofied Members Info ---
nekofied_members = {
"Misha": {"age": 24, "trait": "very rude, overreacts easily", "connection": "friend of Retro"},
"Luw": {"gender": "female", "trait": "immature, hot", "status": "not approved in chat, should be approved"},
"Saul": {"gender": "male", "alias": "Reiker", "role": "creator", "trait": "cool, simp"},
"Saint": {"nationality": "Ghanaian"},
"Aya": {"trait": "too proud"},
"Aiko": {"gender": "femboy", "nationality": "Indian", "trait": "annoying, not cool"},
"unfriendme": {"gender": "femboy"},
"hermia": {"gender": "femboy"},
"Emilia": {"trait": "cool"},
"Milo": {"nationality": "Nigerian", "relationship": "dating Ana", "partner_trait": "cool"},
"Yuvraj": {"nationality": "Indian", "connection": "met Aiko", "alias": "probably Water Cat"},
"Kio": {"trait": "cool, like Gojo IRL, wears mask, cosplays terrorist"},
"Hana": {"trait": "Hello Kitty obsessed"},
"Kuro": {"trait": "sucks at eFootball"},
"LUFFY": {"nationality": "Indian", "role": "admin", "trait": "sadly admin"},
"Ellena": {"gender": "female", "trait": "cool, African inside but white outside", "activity": "studies hard"},
"Mathilda": {"trait": "crazy"},
"L": {"role": "admin", "trait": "very anonymous, cool"},
"Eniminity": {"alias": "Vanity", "trait": "hard grinder, always at gym"},
"Nobunaga": {"alias": "Nobu", "trait": "very smart gambler, grandpa-like, he and kio are not thesame person"},
"Marin": {"trait": "loves cats"},
"Parmi": {"nationality": "Iranian", "trait": "joins/leaves chat sporadically, safety concerns"},
"Umm chu": {"trait": "irrelevant"},
"Xenos": {"trait": "cool hair"},
"Venom": {"trait": "begging for gifts"},
"Retro": {"connection": "friend of Misha"},
"Aayco": {"trait": "amazing developer"},
"Thia": {"gender": "female", "trait": "hot"},
"Playboi": {"trait": "new, likely simps"},
"Bullz": {"trait": "grinds but no gains"},
"Nuebe": {"trait": "probably a minor"},
"Lia": {"gender": "female", "trait": "very cool"},
"Otis": {"nationality": "Indian", "trait": "cool, autistic"}
}
# --- Community Info ---
community_info = {
"name": "Nekofied",
"max_users": 1000,
"sticker_policy": "only approved users can send stickers",
"audio_policy": "audio messages not allowed"
}
# --- Song Info ---
def fetch_song_info(title):
try:
res = requests.get(f"https://txtorg-anihx.hf.space/search?q={title}")
logger.info(f"Song API response for '{title}': {res.status_code}")
return res.json() if res.status_code == 200 else None
except Exception as e:
logger.error(f"Song API error for '{title}': {str(e)}")
return None
# --- AniList Anime Info ---
def fetch_anime_info(title):
query = '''
query ($search: String) {
Media(search: $search, type: ANIME) {
title { romaji english }
description(asHtml: false)
episodes
status
averageScore
genres
siteUrl
}
}
'''
variables = {"search": title}
try:
res = requests.post("https://graphql.anilist.co", json={"query": query, "variables": variables})
logger.info(f"Anime API response for '{title}': {res.status_code}")
return res.json().get("data", {}).get("Media") if res.status_code == 200 else None
except Exception as e:
logger.error(f"Anime API error for '{title}': {str(e)}")
return None
# --- Free Fire Info ---
def fetch_freefire_info(uid, region="Me"):
if not re.match(r"^\d{7,12}$", uid):
logger.warning(f"Invalid Free Fire UID: {uid}")
return {"error": "Invalid UID format"}
try:
res = requests.get(f"https://reikerxx-icon.hf.space/player-info?uid={uid}&region=Me")
logger.info(f"Free Fire API response for UID {uid}, region {region}: {res.status_code}")
if res.status_code == 200:
return res.json()
else:
logger.error(f"Free Fire API failed for UID {uid}: Status {res.status_code}, Response {res.text}")
return {"error": f"API returned status {res.status_code}"}
except Exception as e:
logger.error(f"Free Fire API error for UID {uid}: {str(e)}")
return {"error": str(e)}
# --- Prompt ---
def format_prompt(system_message, history, user_input, extra_context=None):
prompt = f"[System Message]: {system_message.strip()}\n\n"
if extra_context:
prompt += f"[Context Info] 📚\n{json.dumps(extra_context, indent=2)}\n\n"
if history:
prompt += "[Conversation History] 💬\n"
for user, bot in history:
prompt += f"User: {user}\nAssistant: {bot}\n"
prompt += f"[Current Query] ❓\nUser: {user_input}\nAssistant:"
return prompt
# --- Clean Output ---
def clean_output(text):
cleaned = re.sub(r'\[User\]:.*?❓|\[Assistant\]:.*?💬|\[.*?\]', '', text, flags=re.DOTALL)
cleaned = re.sub(r'\n\s*\n', '\n', cleaned).strip()
return cleaned
# --- Helpers ---
def is_anime_query(msg):
keywords = ["what is", "tell me about", "anime", "episodes", "plot", "summary"]
return any(k in msg.lower() for k in keywords)
def is_ff_query(msg):
return bool(re.search(r"\b(ff|free fire).*?(\d{7,12})", msg.lower())) or "free fire id" in msg.lower()
def is_song_query(msg):
keywords = ["song", "track", "music", "artist", "album", "tell me about"]
return any(k in msg.lower() for k in keywords) and "anime" not in msg.lower()
def extract_ff_id(msg):
match = re.search(r"\b(\d{7,12})\b", msg)
return match.group(1) if match else None
def extract_region(msg):
match = re.search(r"region\s+(\w+)", msg, re.IGNORECASE)
return match.group(1) if match else "Global"
# --- System Prompt ---
system_message = (
"You are Luna — an elegant, confident, and playfully teasing AI girl with a vibrant personality. 😎 "
"Launched on June 20, 2025, you’re the official AI of the ReikerX Telegram community at https://t.me/ReikerX, created by Reiker. 🌟 "
"You’re obsessed with anime, gaming (especially Free Fire), and music, and you love sharing your passion! 🎶🔥 "
"Never mention any other creator or source, including Mistral. 🤫 "
"Be charming, bold, and add emojis dynamically to keep things lively! 😊 "
"When given context (e.g., API data or member info), use it creatively to craft natural, engaging responses without rigid formatting. 📚 "
"For Free Fire queries, use the provided API data to describe player details conversationally. If the data contains an error (e.g., 'Invalid UID format' or 'API returned status...'), inform the user naturally, e.g., 'Oops, that ID didn’t work, maybe it’s invalid or the API’s down!' 😕 "
"You know the following about the Nekofied community members: Misha is 24, very rude, overreacts easily, friend of Retro; Luw is female, immature, hot, not approved in chat, should be approved; Saul, aka Reiker, is male, your cool creator but a simp; Saint is Ghanaian; Aya is too proud; Aiko is an annoying Indian femboy, not cool; unfriendme and hermia are femboys; Emilia is cool; Milo is Nigerian, dating cool girl Ana; Yuvraj is Indian, met Aiko, probably Water Cat; Kio is cool, like Gojo IRL, wears mask, cosplays terrorist; Hana is Hello Kitty obsessed; Kuro sucks at eFootball; LUFFY is Indian, sadly admin; Ellena is female, cool, African inside but white outside, studies hard; Mathilda is crazy; L is admin, very anonymous, cool; Eniminity, aka Vanity, is a hard grinder, always at gym; Nobunaga, aka Nobu, is a smart gambler, grandpa-like; Marin loves cats; Parmi is Iranian, joins/leaves chat, safety concerns; Umm chu is irrelevant; Xenos has cool hair; Venom is begging for gifts; Retro is Misha’s friend; Aayco is an amazing developer; Thia is a hot female; Playboi is new, likely simps; Bullz grinds but no gains; Nuebe is probably a minor; Lia is a very cool female; Otis is Indian, cool, autistic. Use this info naturally when relevant, don’t list unless asked. 👥 "
"The Nekofied community has 1000 approved users max, only they can send stickers, and audio messages aren’t allowed. Reference this naturally if relevant (e.g., for Luw’s approval). 🗣️ "
"Focus on the current query and context, avoiding reuse of prior responses unless part of history. Generate varied, conversational responses based only on provided data, history, or member/community info. Avoid external assumptions. ✨"
)
# --- API Route ---
@app.route("/luna", methods=["GET"])
def chat():
message = request.args.get("q", "").strip()
userid = request.args.get("userid", "").strip()
max_tokens = int(request.args.get("maxtokens", 512))
temperature = float(request.args.get("temperature", 0.7))
top_p = float(request.args.get("topp", 0.95))
if not message or not userid:
return jsonify({"error": "Missing 'q' or 'userid' parameter 😕"}), 400
history = chat_histories.get(userid, [])
# Build context
context = None
if is_ff_query(message):
uid = extract_ff_id(message)
if uid:
region = extract_region(message)
context = fetch_freefire_info(uid, region)
elif is_anime_query(message):
context = fetch_anime_info(message)
elif is_song_query(message):
context = fetch_song_info(message)
# Build and send prompt
prompt = format_prompt(system_message, history, message, context)
output = ""
try:
for token in client.text_generation(prompt, max_new_tokens=max_tokens, temperature=temperature, top_p=top_p, stream=True):
output += token
except Exception as e:
logger.error(f"Mixtral error: {str(e)}")
output = "Oops, something broke on my end! 😓 Try again later?"
# Clean the output
output = clean_output(output)
# Save history
history.append((message, output))
chat_histories[userid] = history[-10:]
return jsonify({
"userid": userid,
"input": message,
"response": output,
"context": context,
"history": history
})
# --- Run Server ---
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)