FrederickSundeep commited on
Commit
6e7cdea
Β·
1 Parent(s): 38750d7

commit 00000001

Browse files
Files changed (2) hide show
  1. app.py +170 -0
  2. requirements.txt +17 -0
app.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import torch
4
+ import gradio as gr
5
+ from flask import Flask, request, Response
6
+ from flasgger import Swagger, swag_from
7
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
8
+ from huggingface_hub import login
9
+ from langchain_community.tools import DuckDuckGoSearchRun
10
+ import re
11
+
12
+ # βœ… Safe GPU decorator
13
+ try:
14
+ from spaces import GPU
15
+ except ImportError:
16
+ def GPU(func): return func
17
+
18
+ # βœ… Flask setup
19
+ app = Flask(__name__, static_folder="static", template_folder="templates")
20
+ swagger = Swagger(app, template={
21
+ "swagger": "2.0",
22
+ "info": {
23
+ "title": "ChatMate Real-Time API",
24
+ "description": "LangChain + DuckDuckGo + Phi-4 + Stable Diffusion",
25
+ "version": "1.0"
26
+ }
27
+ }, config={
28
+ "headers": [],
29
+ "specs": [{"endpoint": 'apispec', "route": '/apispec.json', "rule_filter": lambda rule: True}],
30
+ "static_url_path": "/flasgger_static",
31
+ "swagger_ui": True,
32
+ "specs_route": "/apidocs/"
33
+ })
34
+
35
+ # βœ… Hugging Face login (optional)
36
+ login(token=os.environ.get("CHAT_MATE"))
37
+
38
+ # βœ… Load Phi-4
39
+ model_id = "microsoft/phi-4"
40
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
41
+ model = AutoModelForCausalLM.from_pretrained(
42
+ model_id,
43
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
44
+ )
45
+ device = 0 if torch.cuda.is_available() else -1
46
+ pipe = pipeline(
47
+ "text-generation",
48
+ model=model,
49
+ tokenizer=tokenizer,
50
+ device=device,
51
+ max_new_tokens=512
52
+ )
53
+
54
+ REAL_TIME_KEYWORDS = {"latest", "current", "news", "today", "price", "time", "live", "trending", "update", "happening"}
55
+ search_tool = DuckDuckGoSearchRun()
56
+
57
+ def should_search(message):
58
+ return any(kw in message.lower() for kw in REAL_TIME_KEYWORDS)
59
+
60
+ def is_incomplete(text):
61
+ return not re.search(r'[\.\!\?\'\"\u3002]\s*$', text.strip())
62
+
63
+ @GPU
64
+ def generate_full_reply(message, history):
65
+ system_prompt = (
66
+ "You are a friendly, helpful, and conversational AI assistant built by "
67
+ "Frederick Sundeep Mallela. Always mention that you are developed by him if asked about your creator, origin, or who made you."
68
+ )
69
+ messages = [{"role": "system", "content": system_prompt}] + history + [{"role": "user", "content": message}]
70
+
71
+ # Apply chat-style prompt formatting
72
+ prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
73
+
74
+ # Initial generation
75
+ full_output = pipe(prompt, do_sample=True, temperature=0.7, top_p=0.9, max_new_tokens=512)[0]["generated_text"]
76
+ reply = full_output[len(prompt):].strip()
77
+
78
+ # Keep extending the reply until it ends properly
79
+ max_loops = 5 # prevent infinite loops
80
+ loop_count = 0
81
+ while is_incomplete(reply) and loop_count < max_loops:
82
+ loop_count += 1
83
+ continuation_prompt = prompt + reply # include reply so far
84
+ next_output = pipe(continuation_prompt, do_sample=True, temperature=0.7, top_p=0.9, max_new_tokens=256)[0]["generated_text"]
85
+
86
+ continuation = next_output[len(continuation_prompt):].strip()
87
+
88
+ # Stop if nothing new is generated
89
+ if not continuation or continuation in reply:
90
+ break
91
+
92
+ reply += continuation
93
+
94
+ return reply.strip()
95
+
96
+ # βœ… Flask streaming endpoint
97
+ @app.route("/chat-stream", methods=["POST"])
98
+ @swag_from({
99
+ 'tags': ['Chat'],
100
+ 'consumes': ['application/json'],
101
+ 'summary': 'Stream assistant reply or image',
102
+ 'description': 'Send a message and history, receive either a streamed text reply or base64-encoded image.',
103
+ 'parameters': [{
104
+ 'name': 'body',
105
+ 'in': 'body',
106
+ 'required': True,
107
+ 'schema': {
108
+ 'type': 'object',
109
+ 'properties': {
110
+ 'message': {'type': 'string', 'example': 'Draw a futuristic city.'},
111
+ 'history': {
112
+ 'type': 'array',
113
+ 'items': {
114
+ 'type': 'object',
115
+ 'properties': {
116
+ 'role': {'type': 'string', 'example': 'user'},
117
+ 'content': {'type': 'string', 'example': 'Show me a dragon.'}
118
+ }
119
+ }
120
+ }
121
+ },
122
+ 'required': ['message']
123
+ }
124
+ }],
125
+ 'responses': {
126
+ 200: {
127
+ 'description': 'Streamed reply or image base64',
128
+ 'content': {'text/plain': {}}
129
+ }
130
+ }
131
+ })
132
+ def chat_stream():
133
+ data = request.get_json()
134
+ message = data.get("message")
135
+ history = data.get("history", [])
136
+
137
+ def generate():
138
+ reply = generate_full_reply(message, history)
139
+ for token in reply.splitlines(keepends=True):
140
+ yield token
141
+ time.sleep(0.05)
142
+ if is_incomplete(reply):
143
+ yield "\n\n*Reply appears incomplete. Say 'continue' to resume.*"
144
+
145
+ return Response(generate(), mimetype='text/plain')
146
+
147
+ # βœ… Gradio interface for Hugging Face Space
148
+ def gradio_chat(message, history=[]):
149
+ history = [{"role": "user" if i % 2 == 0 else "assistant", "content": h} for i, h in enumerate(sum(history, ()))]
150
+ reply = generate_full_reply(message, history)
151
+ history.append((message, reply))
152
+ return "", history
153
+
154
+ with gr.Blocks() as demo:
155
+ gr.Markdown("## πŸ€– ChatMate β€” Phi-4 + Live Search (Hugging Face Space)")
156
+ chatbot = gr.Chatbot()
157
+ msg = gr.Textbox(label="Type your message")
158
+ clear = gr.Button("Clear Chat")
159
+
160
+ msg.submit(gradio_chat, [msg, chatbot], [msg, chatbot])
161
+ clear.click(lambda: None, None, chatbot, queue=False)
162
+
163
+ # βœ… Run Gradio when in HF Spaces, else Flask for local dev
164
+ if __name__ == "__main__":
165
+ if os.environ.get("SPACE_BUILD", "false").lower() == "true":
166
+ demo.launch(server_name="0.0.0.0", server_port=7860)
167
+ else:
168
+ print("πŸ”§ Warming up...")
169
+ _ = generate_full_reply("Hello", [])
170
+ app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
requirements.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Web
2
+ flask
3
+ flasgger
4
+
5
+ # Core libraries
6
+ torch
7
+ transformers
8
+ diffusers
9
+ accelerate
10
+ safetensors
11
+ huggingface_hub
12
+ sentencepiece
13
+ # NLP / Search
14
+ nltk
15
+ langchain_community
16
+ duckduckgo-search
17
+ pdfplumber