kcrobot20 commited on
Commit
3848b94
·
verified ·
1 Parent(s): 63de067
Files changed (1) hide show
  1. app.py +96 -156
app.py CHANGED
@@ -1,202 +1,142 @@
1
  # =============================================
2
- # app.py v8.0RobotAI Server (ESP32 + HF Cloud + Telegram)
3
- # Author: GPT-5 Assistant for Cường Phan
4
  # =============================================
5
 
6
  import os
7
  import json
8
- import uuid
9
- import time
10
- import queue
11
  import requests
12
- import threading
 
13
  from datetime import datetime
14
- from flask import Flask, request, jsonify, send_file
15
 
16
  app = Flask(__name__)
17
 
18
  # ======================
19
- # Configuration
20
  # ======================
21
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
22
- HF_MODEL = os.environ.get("HF_MODEL", "mistralai/Mistral-7B-Instruct-v0.3")
23
- HF_STT_MODEL = os.environ.get("HF_STT_MODEL", "openai/whisper-small")
24
  HF_TTS_MODEL = os.environ.get("HF_TTS_MODEL", "espnet/kan-bayashi_ljspeech_vits")
25
  TELEGRAM_TOKEN = os.environ.get("TELEGRAM_TOKEN", "")
26
  TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "")
27
 
28
- COMMAND_QUEUE = queue.Queue()
29
- CONFIG_FILE = "config.json"
30
  AUDIO_DIR = "audio_cache"
 
31
 
32
- if not os.path.exists(AUDIO_DIR):
33
- os.makedirs(AUDIO_DIR)
34
 
35
  # ======================
36
- # Utility Functions
37
  # ======================
38
  def log(msg):
39
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}")
40
-
41
- def save_config(data):
42
- with open(CONFIG_FILE, "w", encoding="utf-8") as f:
43
- json.dump(data, f, ensure_ascii=False, indent=2)
44
-
45
- def load_config():
46
- if os.path.exists(CONFIG_FILE):
47
- with open(CONFIG_FILE, "r", encoding="utf-8") as f:
48
- return json.load(f)
49
- return {}
50
-
51
- def send_telegram_message(text):
52
- if not TELEGRAM_TOKEN or not TELEGRAM_CHAT_ID:
53
- return
54
- url = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage"
55
- payload = {"chat_id": TELEGRAM_CHAT_ID, "text": text}
56
- try:
57
- requests.post(url, json=payload, timeout=5)
58
- except Exception as e:
59
- log(f"[Telegram Error] {e}")
60
 
61
- def hf_query(model_id, inputs, parameters=None, timeout=60):
62
- url = f"https://api-inference.huggingface.co/models/{model_id}"
 
 
 
 
63
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
64
- payload = {"inputs": inputs}
65
- if parameters:
66
- payload["parameters"] = parameters
67
  try:
68
- r = requests.post(url, headers=headers, json=payload, timeout=timeout)
 
 
 
 
 
 
 
 
 
 
69
  except Exception as e:
70
- log(f"[HF request exception] {e}")
71
- return {"error": str(e)}
72
-
73
- if r.status_code == 200:
74
- try:
75
- return r.json()
76
- except Exception:
77
- return {"raw_text": r.text}
78
- else:
79
- log(f"[HF Error] {r.status_code} - {r.text}")
80
- return {"error": r.text, "status_code": r.status_code}
81
-
82
- def detect_language(text):
83
- if not text:
84
- return "en"
85
- vi_chars = "àáảãạăằắẳẵặâầấẩẫậđêềếểễệôồốổỗộơờớởỡợưừứửữự"
86
- if any(ch in text for ch in vi_chars):
87
- return "vi"
88
- return "en"
89
-
90
- def generate_tts_audio(text, lang="en"):
91
- session_id = str(uuid.uuid4())[:8]
92
- filename = f"{AUDIO_DIR}/{session_id}.mp3"
93
-
94
- if HF_TTS_MODEL:
95
- try:
96
- url = f"https://api-inference.huggingface.co/models/{HF_TTS_MODEL}"
97
- headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
98
- rr = requests.post(url, headers=headers, json={"inputs": text}, timeout=120)
99
- if rr.status_code == 200 and rr.content:
100
- with open(filename, "wb") as f:
101
- f.write(rr.content)
102
- return filename
103
- except Exception as e:
104
- log(f"[TTS exception] {e}")
105
 
 
106
  try:
107
- from gtts import gTTS
108
- lang_code = "vi" if lang == "vi" else "en"
109
- tts = gTTS(text=text, lang=lang_code)
110
- tts.save(filename)
111
- return filename
112
  except Exception as e:
113
- log(f"gTTS fallback failed: {e}")
114
- return None
 
115
 
116
  # ======================
117
- # API ROUTES
118
  # ======================
119
  @app.route("/")
120
  def home():
121
- return "<h2>🤖 RobotAI v8.0 Server Running Successfully!</h2>"
122
-
123
- @app.route("/model_check")
124
- def model_check():
125
- info = {"HF_MODEL": HF_MODEL, "token_present": bool(HF_TOKEN)}
126
- try:
127
- r = hf_query(HF_MODEL, "Hello world", parameters={"max_new_tokens": 10}, timeout=10)
128
- info["probe"] = r
129
- except Exception as e:
130
- info["probe_error"] = str(e)
131
- return jsonify(info)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  @app.route("/api/chat", methods=["POST"])
134
  def api_chat():
135
  data = request.get_json(force=True)
136
- text = data.get("text", "").strip()
137
- if not text:
138
- return jsonify({"error": "missing text"}), 400
139
- lang = detect_language(text)
140
- prefix = "Hãy trả lời bằng tiếng Việt:" if lang == "vi" else "Answer in English:"
141
- prompt = f"{prefix}\n\n{text}"
142
- r = hf_query(HF_MODEL, prompt, parameters={"max_new_tokens": 200, "temperature": 0.7}, timeout=60)
143
- reply = ""
144
- if isinstance(r, list) and r and isinstance(r[0], dict):
145
- reply = r[0].get("generated_text") or r[0].get("text") or str(r[0])
146
- elif isinstance(r, dict) and "generated_text" in r:
147
- reply = r["generated_text"]
148
- else:
149
- reply = str(r)
150
-
151
- tts_file = generate_tts_audio(reply, lang)
152
- return jsonify({"reply": reply, "lang": lang, "tts_url": f"/api/tts/{os.path.basename(tts_file)}" if tts_file else None})
153
-
154
- @app.route("/api/tts/<filename>")
155
- def api_tts_file(filename):
156
- path = os.path.join(AUDIO_DIR, filename)
157
- if os.path.exists(path):
158
- return send_file(path, mimetype="audio/mpeg")
159
- return jsonify({"error": "file not found"}), 404
160
 
161
  @app.route("/api/presence", methods=["POST"])
162
  def api_presence():
163
  data = request.get_json(force=True)
164
- note = data.get("note", "Có người xuất hiện!")
165
- send_telegram_message(f"🚶 {note}")
166
- greeting = "Xin chào! Mình là RobotAI, thể giúp gì không?"
167
- audio = generate_tts_audio(greeting, lang="vi")
168
- return jsonify({"greeting": greeting, "tts_url": f"/api/tts/{os.path.basename(audio)}" if audio else None})
169
-
170
- @app.route("/api/control", methods=["POST"])
171
- def api_control():
172
- data = request.get_json(force=True)
173
- COMMAND_QUEUE.put(data)
174
- log(f"Command added: {data}")
175
- return jsonify({"status": "queued"})
176
-
177
- @app.route("/api/poll_commands")
178
- def api_poll_commands():
179
- cmds = []
180
- while not COMMAND_QUEUE.empty():
181
- cmds.append(COMMAND_QUEUE.get())
182
- return jsonify({"commands": cmds})
183
-
184
- @app.route("/api/config", methods=["GET", "POST"])
185
- def api_config():
186
- if request.method == "POST":
187
- data = request.get_json(force=True)
188
- save_config(data)
189
- return jsonify({"status": "saved"})
190
- return jsonify(load_config())
191
 
192
- # ======================
193
- # Background thread
194
- # ======================
195
- def heartbeat():
196
- while True:
197
- log("Heartbeat: RobotAI active")
198
- time.sleep(60)
199
 
200
  if __name__ == "__main__":
201
- threading.Thread(target=heartbeat, daemon=True).start()
202
- app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)), debug=True)
 
1
  # =============================================
2
+ # RobotAI v8.5All-in-One (UI + ESP32 + Telegram)
3
+ # Author: GPT-5 for Cường Phan
4
  # =============================================
5
 
6
  import os
7
  import json
 
 
 
8
  import requests
9
+ from flask import Flask, request, jsonify, render_template_string
10
+ from gtts import gTTS
11
  from datetime import datetime
 
12
 
13
  app = Flask(__name__)
14
 
15
  # ======================
16
+ # Config
17
  # ======================
18
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
19
+ HF_MODEL = os.environ.get("HF_MODEL", "mistralai/Mistral-7B-Instruct-v0.3") # model public
 
20
  HF_TTS_MODEL = os.environ.get("HF_TTS_MODEL", "espnet/kan-bayashi_ljspeech_vits")
21
  TELEGRAM_TOKEN = os.environ.get("TELEGRAM_TOKEN", "")
22
  TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "")
23
 
 
 
24
  AUDIO_DIR = "audio_cache"
25
+ os.makedirs(AUDIO_DIR, exist_ok=True)
26
 
 
 
27
 
28
  # ======================
29
+ # Utils
30
  # ======================
31
  def log(msg):
32
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
33
+
34
+ def send_telegram(text):
35
+ if TELEGRAM_TOKEN and TELEGRAM_CHAT_ID:
36
+ url = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage"
37
+ requests.post(url, json={"chat_id": TELEGRAM_CHAT_ID, "text": text})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ def detect_lang(text):
40
+ vi_chars = "ăâđêôơưáàảãạấầẩẫậắằẳẵặéèẻẽẹếềểễệóòỏõọốồổỗộớờởỡợúùủũụứừửữựýỳỷỹỵ"
41
+ return "vi" if any(c in text for c in vi_chars) else "en"
42
+
43
+ def query_huggingface(prompt, max_new_tokens=200):
44
+ url = f"https://api-inference.huggingface.co/models/{HF_MODEL}"
45
  headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
46
+ payload = {"inputs": prompt, "parameters": {"max_new_tokens": max_new_tokens, "temperature": 0.7}}
 
 
47
  try:
48
+ r = requests.post(url, headers=headers, json=payload, timeout=90)
49
+ if r.status_code == 200:
50
+ out = r.json()
51
+ if isinstance(out, list) and len(out) > 0:
52
+ return out[0].get("generated_text", out[0].get("text", ""))
53
+ elif isinstance(out, dict):
54
+ return out.get("generated_text", str(out))
55
+ elif r.status_code == 404:
56
+ return "⚠️ Model not found. Please check HF_MODEL name."
57
+ else:
58
+ return f"⚠️ Error: {r.status_code} - {r.text}"
59
  except Exception as e:
60
+ return f"⚠️ Exception: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ def gen_tts(text, lang="en"):
63
  try:
64
+ path = os.path.join(AUDIO_DIR, f"tts_{int(datetime.now().timestamp())}.mp3")
65
+ tts = gTTS(text=text, lang="vi" if lang == "vi" else "en")
66
+ tts.save(path)
67
+ return f"/tts/{os.path.basename(path)}"
 
68
  except Exception as e:
69
+ log(f"TTS error: {e}")
70
+ return None
71
+
72
 
73
  # ======================
74
+ # ROUTES
75
  # ======================
76
  @app.route("/")
77
  def home():
78
+ return render_template_string("""
79
+ <html><head><title>RobotAI v8.5</title></head>
80
+ <body style="font-family:sans-serif;text-align:center;">
81
+ <h2>🤖 RobotAI v8.5 — All-in-One Server</h2>
82
+ <p>Server is running successfully! Use /chat API or chat below.</p>
83
+ <form method="post" action="/chat_ui">
84
+ <textarea name="text" rows="3" cols="50" placeholder="Nhập tiếng Việt hoặc English..."></textarea><br>
85
+ <button type="submit">Gửi</button>
86
+ </form>
87
+ {% if reply %}
88
+ <p><b>Robot:</b> {{ reply }}</p>
89
+ {% if tts_url %}<audio controls autoplay><source src="{{ tts_url }}" type="audio/mpeg"></audio>{% endif %}
90
+ {% endif %}
91
+ </body></html>
92
+ """, reply=None)
93
+
94
+ @app.route("/chat_ui", methods=["POST"])
95
+ def chat_ui():
96
+ text = request.form.get("text", "")
97
+ lang = detect_lang(text)
98
+ prefix = "Trả lời bằng tiếng Việt:" if lang == "vi" else "Answer in English:"
99
+ reply = query_huggingface(f"{prefix}\n\n{text}")
100
+ tts_url = gen_tts(reply, lang)
101
+ return render_template_string("""
102
+ <html><head><title>RobotAI v8.5</title></head>
103
+ <body style="font-family:sans-serif;text-align:center;">
104
+ <h2>🤖 RobotAI v8.5 — Chat</h2>
105
+ <form method="post" action="/chat_ui">
106
+ <textarea name="text" rows="3" cols="50">{{text}}</textarea><br>
107
+ <button type="submit">Gửi</button>
108
+ </form>
109
+ <p><b>Robot:</b> {{ reply }}</p>
110
+ {% if tts_url %}<audio controls autoplay><source src="{{ tts_url }}" type="audio/mpeg"></audio>{% endif %}
111
+ </body></html>
112
+ """, text=text, reply=reply, tts_url=tts_url)
113
 
114
  @app.route("/api/chat", methods=["POST"])
115
  def api_chat():
116
  data = request.get_json(force=True)
117
+ text = data.get("text", "")
118
+ lang = detect_lang(text)
119
+ reply = query_huggingface(text)
120
+ tts_url = gen_tts(reply, lang)
121
+ return jsonify({"reply": reply, "tts": tts_url, "lang": lang})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  @app.route("/api/presence", methods=["POST"])
124
  def api_presence():
125
  data = request.get_json(force=True)
126
+ note = data.get("note", "🚶 Có người vừa đi qua!")
127
+ send_telegram(note)
128
+ reply = "Xin chào! Tôi là RobotAI. thể giúp gì cho bạn?"
129
+ tts_url = gen_tts(reply, "vi")
130
+ return jsonify({"reply": reply, "tts": tts_url})
131
+
132
+ @app.route("/tts/<fname>")
133
+ def serve_tts(fname):
134
+ return app.send_static_file(os.path.join(AUDIO_DIR, fname))
135
+
136
+ @app.route("/model_check")
137
+ def model_check():
138
+ return jsonify({"HF_MODEL": HF_MODEL, "Token": bool(HF_TOKEN)})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
 
 
 
 
 
 
 
140
 
141
  if __name__ == "__main__":
142
+ app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)), debug=False)