CooLLaMACEO commited on
Commit
ef91df3
·
verified ·
1 Parent(s): 2d115b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -128
app.py CHANGED
@@ -1,128 +1,184 @@
1
- import os
2
- import uuid
3
- from flask import Flask, request, jsonify, render_template_string, send_from_directory
4
- import ollama
5
- import requests
6
-
7
- app = Flask(__name__)
8
-
9
- # === GGUF MODEL DOWNLOAD ===
10
- MODEL_URL = "https://huggingface.co/CooLLaMACEO/CooLLaMA-Gemma2/resolve/main/gemma-2-2b-it.q3_k_m.gguf"
11
- MODEL_DIR = "models"
12
- MODEL_PATH = os.path.join(MODEL_DIR, "gemma-2-2b-it.q3_k_m.gguf")
13
-
14
- os.makedirs(MODEL_DIR, exist_ok=True)
15
-
16
- if not os.path.exists(MODEL_PATH):
17
- print("Downloading GGUF model...")
18
- with requests.get(MODEL_URL, stream=True) as r:
19
- r.raise_for_status()
20
- with open(MODEL_PATH, "wb") as f:
21
- for chunk in r.iter_content(chunk_size=1024*1024):
22
- if chunk:
23
- f.write(chunk)
24
- print("Download complete!")
25
-
26
- # === HTML TEMPLATE ===
27
- HTML_TEMPLATE = """
28
- <!DOCTYPE html>
29
- <html lang="en">
30
- <head>
31
- <meta charset="UTF-8">
32
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
33
- <title>CooLLaMA AI</title>
34
- <link rel="icon" type="image/x-icon" href="/favicon.ico">
35
- <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;800&display=swap" rel="stylesheet">
36
- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
37
- <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
38
- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
39
- <style>
40
- :root { --bg:#0b0f1a; --card:#161b2c; --user-blue:#2563eb; --ai-bubble:#1e293b; --accent:#8b5cf6; --text-light:#f1f5f9; --text-dim:#64748b; }
41
- body { font-family:'Plus Jakarta Sans',sans-serif; background:var(--bg); color:var(--text-light); display:flex; height:100vh; margin:0; overflow:hidden; }
42
- #sidebar { width:260px; background:#090c14; display:flex; flex-direction:column; border-right:1px solid #2d3748; padding:20px; }
43
- .new-chat-btn { background:linear-gradient(135deg,#2563eb,#7c3aed); border:none; color:white; padding:14px; border-radius:12px; cursor:pointer; font-weight:800; margin-bottom:25px; transition:all 0.2s ease; }
44
- .new-chat-btn:hover { transform:translateY(-2px); box-shadow:0 5px 15px rgba(37,99,235,0.4); }
45
- #chat-list { flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:8px; }
46
- .chat-item { padding:12px; border-radius:10px; cursor:pointer; font-size:13px; color:var(--text-dim); transition:0.3s; border:1px solid transparent; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
47
- .chat-item:hover { background:#1e293b; color:white; border-color:#334155; box-shadow:0 0 10px rgba(139,92,246,0.1); }
48
- .chat-item.active { background:#1e293b; color:white; border-color:#2563eb; }
49
- #main-container { flex:1; display:flex; flex-direction:column; }
50
- header { padding:20px 30px; border-bottom:1px solid #2d3748; display:flex; justify-content:space-between; align-items:center; }
51
- header h1 { font-size:1.5rem; margin:0; font-weight:800; background:linear-gradient(90deg,#60a5fa,#a78bfa); -webkit-background-clip:text; -webkit-text-fill-color:transparent; }
52
- #chat { flex:1; padding:25px; overflow-y:auto; display:flex; flex-direction:column; gap:20px; scroll-behavior:smooth; }
53
- .message-row { display:flex; flex-direction:column; width:100%; animation:slideUp 0.3s ease-out forwards; }
54
- @keyframes slideUp { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
55
- .message { max-width:85%; padding:14px 20px; border-radius:18px; font-size:15px; line-height:1.6; }
56
- .user-row { align-items:flex-end; }
57
- .user { background:var(--user-blue); color:white; border-bottom-right-radius:2px; }
58
- .ai-row { align-items:flex-start; }
59
- .ai { background:var(--ai-bubble); color:var(--text-light); border:1px solid #334155; border-bottom-left-radius:2px; }
60
- .ai-cursor { color:var(--accent); font-weight:bold; margin-right:8px; animation:blink 1s infinite; }
61
- @keyframes blink { 0%,100% {opacity:1;} 50% {opacity:0.3;} }
62
- .label { font-size:10px; font-weight:700; margin-bottom:6px; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.8px; }
63
- #input-container { padding:25px; background:var(--card); border-top:1px solid #2d3748; }
64
- .input-box { max-width:850px; margin:0 auto; display:flex; background:#0b0f1a; border:1px solid #334155; border-radius:15px; padding:10px; align-items:flex-end; }
65
- textarea { flex:1; border:none; background:transparent; padding:10px; font-size:16px; outline:none; color:white; resize:none; font-family:inherit; }
66
- button#send-btn { background:var(--user-blue); border:none; color:white; padding:0 25px; border-radius:10px; cursor:pointer; font-weight:800; height:45px; }
67
- .typing-container { display:flex; align-items:flex-start; gap:10px; margin-top:5px; }
68
- .dot { width:6px; height:6px; background:var(--accent); border-radius:50%; animation:bounce 1.4s infinite ease-in-out both; }
69
- .dot:nth-child(1){animation-delay:-0.32s;} .dot:nth-child(2){animation-delay:-0.16s;}
70
- @keyframes bounce {0%,80%,100%{transform:scale(0);}40%{transform:scale(1.0);}}
71
- </style>
72
- </head>
73
- <body>
74
- <div id="sidebar">
75
- <button class="new-chat-btn" onclick="startNewChat()">+ New Chat</button>
76
- <div id="chat-list"></div>
77
- <button onclick="clearAllCache()" style="background:transparent; border:none; color:#334155; font-size:10px; cursor:pointer; margin-top:20px; font-weight:700;">RESET CACHE</button>
78
- </div>
79
- <div id="main-container">
80
- <header><h1>🦙 CooLLaMA</h1><div style="font-size:10px; color:#64748b; font-weight:700;">v3.5 ANIMATED</div></header>
81
- <div id="chat"></div>
82
- <div id="input-container">
83
- <div class="input-box">
84
- <textarea id="message" placeholder="Send a message..." rows="1" oninput="this.style.height='';this.style.height=this.scrollHeight+'px'"></textarea>
85
- <button id="send-btn" onclick="sendMessage()">Send</button>
86
- </div>
87
- </div>
88
- </div>
89
- <script>
90
- let currentChatId = null;
91
- let localData = JSON.parse(localStorage.getItem('coolllama_v4_chats')) || {};
92
- marked.setOptions({ breaks:true, highlight:(code,lang)=>Prism.languages[lang]?Prism.highlight(code,Prism.languages[lang],lang):code });
93
- function loadSidebar(){const list=document.getElementById("chat-list");list.innerHTML="";Object.keys(localData).reverse().forEach(id=>{const item=document.createElement("div");item.className="chat-item"+(id===currentChatId?" active":"");item.id="item-"+id;item.innerHTML=`💬 Session ${id}`;item.onclick=()=>selectChat(id);list.appendChild(item);});}
94
- async function startNewChat(){const res=await fetch("/new_chat",{method:"POST"});const data=await res.json();currentChatId=data.chat_id;localData[currentChatId]=[];saveToCache();loadSidebar();selectChat(currentChatId);}
95
- function selectChat(id){currentChatId=id;document.querySelectorAll('.chat-item').forEach(el=>el.classList.remove('active'));if(document.getElementById("item-"+id))document.getElementById("item-"+id).classList.add("active");document.getElementById("chat").innerHTML="";if(localData[id])localData[id].forEach(msg=>appendMessage(msg.role,msg.content,false));}
96
- function appendMessage(role,text,isNew=true){const chatDiv=document.getElementById("chat");const row=document.createElement("div");row.className=`message-row ${role==='user'?'user-row':'ai-row'}`;if(!isNew)row.style.animation='none';const prefix=(role!=='user')?'<span class="ai-cursor">■</span>':'';const content=role==='user'?document.createTextNode(text).textContent:marked.parse(text);row.innerHTML=`<span class="label">${role==='user'?'You':'CooLLaMA'}</span><div class="message ${role==='user'?'user':'ai'}">${prefix}${content}</div>`;chatDiv.appendChild(row);chatDiv.scrollTop=chatDiv.scrollHeight;Prism.highlightAll();}
97
- async function sendMessage(){const input=document.getElementById("message");const text=input.value.trim();if(!text||!currentChatId)return;appendMessage('user',text);localData[currentChatId].push({role:'user',content:text});saveToCache();input.value="";input.style.height='auto';const chatDiv=document.getElementById("chat");const thinkRow=document.createElement("div");thinkRow.id="thinking-indicator";thinkRow.className="message-row ai-row";thinkRow.innerHTML=`<span class="label">CooLLaMA</span><div class="typing-container"><div class="dot"></div><div class="dot"></div><div class="dot"></div></div>`;chatDiv.appendChild(thinkRow);chatDiv.scrollTop=chatDiv.scrollHeight;try{const res=await fetch("/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({history:localData[currentChatId]})});const data=await res.json();document.getElementById("thinking-indicator").remove();appendMessage('assistant',data.response);localData[currentChatId].push({role:'assistant',content:data.response});saveToCache();}catch(e){document.getElementById("thinking-indicator").innerText="Error."}}
98
- function saveToCache(){localStorage.setItem('coolllama_v4_chats',JSON.stringify(localData));}
99
- function clearAllCache(){if(confirm("Reset all?")){localStorage.clear();location.reload();}}
100
- document.getElementById("message").addEventListener("keydown",e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();sendMessage();}});
101
- loadSidebar();if(Object.keys(localData).length>0)selectChat(Object.keys(localData).sort().reverse()[0]);else startNewChat();
102
- </script>
103
- </body>
104
- </html>
105
- """
106
-
107
- @app.route("/")
108
- def index():
109
- return render_template_string(HTML_TEMPLATE)
110
-
111
- @app.route('/favicon.ico')
112
- def favicon():
113
- return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico', mimetype='image/vnd.microsoft.icon')
114
-
115
- @app.route("/new_chat", methods=["POST"])
116
- def new_chat():
117
- return jsonify({"chat_id": str(uuid.uuid4())[:8].upper()})
118
-
119
- @app.route("/chat", methods=["POST"])
120
- def chat():
121
- data = request.json
122
- history = data.get("history", [])
123
- messages = [{"role": "system", "content": "You are CooLLaMA, an AI by the CooLLaMA Team."}] + history[-10:]
124
- result = ollama.chat(model=MODEL_PATH, messages=messages, options={"temperature":0.4})
125
- return jsonify({"response": result["message"]["content"]})
126
-
127
- if __name__ == "__main__":
128
- app.run(host="0.0.0.0", port=5000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import uuid
3
+ import requests
4
+ from flask import Flask, request, jsonify, render_template_string
5
+ from llama_cpp import Llama
6
+
7
+ app = Flask(__name__)
8
+
9
+ # === CONFIGURATION ===
10
+ MODEL_URL = "https://huggingface.co/CooLLaMACEO/CooLLaMA-Gemma2/resolve/main/gemma-2-2b-it.q3_k_m.gguf"
11
+ MODEL_PATH = "model.gguf"
12
+
13
+ # === DOWNLOAD MODEL (Run once) ===
14
+ if not os.path.exists(MODEL_PATH):
15
+ print("Downloading GGUF model... this may take a few minutes.")
16
+ with requests.get(MODEL_URL, stream=True) as r:
17
+ r.raise_for_status()
18
+ with open(MODEL_PATH, "wb") as f:
19
+ for chunk in r.iter_content(chunk_size=8192):
20
+ f.write(chunk)
21
+ print("Download complete!")
22
+
23
+ # === INITIALIZE LLM ===
24
+ # n_ctx is the context window (memory). 2048 is a good balance for free tier RAM.
25
+ llm = Llama(
26
+ model_path=MODEL_PATH,
27
+ n_ctx=2048,
28
+ n_threads=4 # Optimized for HF free tier CPU
29
+ )
30
+
31
+ # === HTML TEMPLATE ===
32
+ HTML_TEMPLATE = """
33
+ <!DOCTYPE html>
34
+ <html lang="en">
35
+ <head>
36
+ <meta charset="UTF-8">
37
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
38
+ <title>CooLLaMA AI</title>
39
+ <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;800&display=swap" rel="stylesheet">
40
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
41
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
42
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
43
+ <style>
44
+ :root { --bg:#0b0f1a; --card:#161b2c; --user-blue:#2563eb; --ai-bubble:#1e293b; --accent:#8b5cf6; --text-light:#f1f5f9; --text-dim:#64748b; }
45
+ body { font-family:'Plus Jakarta Sans',sans-serif; background:var(--bg); color:var(--text-light); display:flex; height:100vh; margin:0; overflow:hidden; }
46
+ #sidebar { width:260px; background:#090c14; display:flex; flex-direction:column; border-right:1px solid #2d3748; padding:20px; }
47
+ .new-chat-btn { background:linear-gradient(135deg,#2563eb,#7c3aed); border:none; color:white; padding:14px; border-radius:12px; cursor:pointer; font-weight:800; margin-bottom:25px; transition:all 0.2s ease; }
48
+ .new-chat-btn:hover { transform:translateY(-2px); box-shadow:0 5px 15px rgba(37,99,235,0.4); }
49
+ #chat-list { flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:8px; }
50
+ .chat-item { padding:12px; border-radius:10px; cursor:pointer; font-size:13px; color:var(--text-dim); transition:0.3s; border:1px solid transparent; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
51
+ .chat-item:hover { background:#1e293b; color:white; border-color:#334155; }
52
+ .chat-item.active { background:#1e293b; color:white; border-color:#2563eb; }
53
+ #main-container { flex:1; display:flex; flex-direction:column; }
54
+ header { padding:20px 30px; border-bottom:1px solid #2d3748; display:flex; justify-content:space-between; align-items:center; }
55
+ header h1 { font-size:1.5rem; margin:0; font-weight:800; background:linear-gradient(90deg,#60a5fa,#a78bfa); -webkit-background-clip:text; -webkit-text-fill-color:transparent; }
56
+ #chat { flex:1; padding:25px; overflow-y:auto; display:flex; flex-direction:column; gap:20px; }
57
+ .message-row { display:flex; flex-direction:column; width:100%; animation:slideUp 0.3s ease-out; }
58
+ .message { max-width:85%; padding:14px 20px; border-radius:18px; font-size:15px; line-height:1.6; }
59
+ .user-row { align-items:flex-end; }
60
+ .user { background:var(--user-blue); color:white; border-bottom-right-radius:2px; }
61
+ .ai-row { align-items:flex-start; }
62
+ .ai { background:var(--ai-bubble); color:var(--text-light); border:1px solid #334155; border-bottom-left-radius:2px; }
63
+ .label { font-size:10px; font-weight:700; margin-bottom:6px; color:var(--text-dim); text-transform:uppercase; }
64
+ #input-container { padding:25px; background:var(--card); border-top:1px solid #2d3748; }
65
+ .input-box { max-width:850px; margin:0 auto; display:flex; background:#0b0f1a; border:1px solid #334155; border-radius:15px; padding:10px; }
66
+ textarea { flex:1; border:none; background:transparent; padding:10px; font-size:16px; outline:none; color:white; resize:none; }
67
+ button#send-btn { background:var(--user-blue); border:none; color:white; padding:0 25px; border-radius:10px; cursor:pointer; font-weight:800; }
68
+ </style>
69
+ </head>
70
+ <body>
71
+ <div id="sidebar">
72
+ <button class="new-chat-btn" onclick="startNewChat()">+ New Chat</button>
73
+ <div id="chat-list"></div>
74
+ </div>
75
+ <div id="main-container">
76
+ <header><h1>🦙 CooLLaMA</h1><div style="font-size:10px; color:#64748b; font-weight:700;">v3.5 GGUF</div></header>
77
+ <div id="chat"></div>
78
+ <div id="input-container">
79
+ <div class="input-box">
80
+ <textarea id="message" placeholder="Send a message..." rows="1"></textarea>
81
+ <button id="send-btn" onclick="sendMessage()">Send</button>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ <script>
86
+ let currentChatId = null;
87
+ let localData = JSON.parse(localStorage.getItem('coolllama_chats')) || {};
88
+
89
+ function loadSidebar(){
90
+ const list=document.getElementById("chat-list"); list.innerHTML="";
91
+ Object.keys(localData).reverse().forEach(id=>{
92
+ const item=document.createElement("div");
93
+ item.className="chat-item"+(id===currentChatId?" active":"");
94
+ item.innerText=`Session ${id}`;
95
+ item.onclick=()=>selectChat(id);
96
+ list.appendChild(item);
97
+ });
98
+ }
99
+
100
+ async function startNewChat(){
101
+ const res=await fetch("/new_chat",{method:"POST"});
102
+ const data=await res.json();
103
+ currentChatId=data.chat_id;
104
+ localData[currentChatId]=[];
105
+ saveToCache(); loadSidebar(); selectChat(currentChatId);
106
+ }
107
+
108
+ function selectChat(id){
109
+ currentChatId=id;
110
+ document.getElementById("chat").innerHTML="";
111
+ (localData[id] || []).forEach(msg=>appendMessage(msg.role,msg.content));
112
+ loadSidebar();
113
+ }
114
+
115
+ function appendMessage(role,text){
116
+ const chatDiv=document.getElementById("chat");
117
+ const row=document.createElement("div");
118
+ row.className=`message-row ${role==='user'?'user-row':'ai-row'}`;
119
+ const content = role==='user' ? text : marked.parse(text);
120
+ row.innerHTML=`<span class="label">${role==='user'?'You':'CooLLaMA'}</span><div class="message ${role==='user'?'user':'ai'}">${content}</div>`;
121
+ chatDiv.appendChild(row);
122
+ chatDiv.scrollTop=chatDiv.scrollHeight;
123
+ }
124
+
125
+ async function sendMessage(){
126
+ const input=document.getElementById("message");
127
+ const text=input.value.trim();
128
+ if(!text || !currentChatId) return;
129
+
130
+ appendMessage('user', text);
131
+ localData[currentChatId].push({role:'user', content:text});
132
+ input.value="";
133
+
134
+ const res=await fetch("/chat",{
135
+ method:"POST",
136
+ headers:{"Content-Type":"application/json"},
137
+ body:JSON.stringify({history:localData[currentChatId]})
138
+ });
139
+ const data=await res.json();
140
+ appendMessage('assistant', data.response);
141
+ localData[currentChatId].push({role:'assistant', content:data.response});
142
+ saveToCache();
143
+ }
144
+
145
+ function saveToCache(){ localStorage.setItem('coolllama_chats', JSON.stringify(localData)); }
146
+ loadSidebar();
147
+ if(Object.keys(localData).length > 0) selectChat(Object.keys(localData).sort().reverse()[0]);
148
+ else startNewChat();
149
+ </script>
150
+ </body>
151
+ </html>
152
+ """
153
+
154
+ @app.route("/")
155
+ def index():
156
+ return render_template_string(HTML_TEMPLATE)
157
+
158
+ @app.route("/new_chat", methods=["POST"])
159
+ def new_chat():
160
+ return jsonify({"chat_id": str(uuid.uuid4())[:8].upper()})
161
+
162
+ @app.route("/chat", methods=["POST"])
163
+ def chat():
164
+ data = request.json
165
+ history = data.get("history", [])
166
+
167
+ # Simple Prompt Formatting for Gemma-2
168
+ user_input = history[-1]["content"] if history else ""
169
+ prompt = f"<start_of_turn>user\n{user_input}<end_of_turn>\n<start_of_turn>model\n"
170
+
171
+ # Generate
172
+ output = llm(
173
+ prompt,
174
+ max_tokens=512,
175
+ stop=["<end_of_turn>", "user"],
176
+ echo=False
177
+ )
178
+
179
+ response_text = output["choices"][0]["text"].strip()
180
+ return jsonify({"response": response_text})
181
+
182
+ if __name__ == "__main__":
183
+ # HF Spaces listen on port 7860 by default
184
+ app.run(host="0.0.0.0", port=7860)