Alibrown commited on
Commit
f87cc9b
·
verified ·
1 Parent(s): 47ad52e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -0
app.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ import tempfile
4
+ import requests
5
+ import json
6
+
7
+ # ----------------------------------------------------
8
+ # 🚨 CRITICAL FIXES FOR PERMISSION ERRORS
9
+ # Forces Streamlit to write temporary/config files
10
+ # to the writable /tmp directory.
11
+ # ----------------------------------------------------
12
+
13
+ # 1. Create a temporary, writable path
14
+ TEMP_STREAMLIT_HOME = os.path.join(tempfile.gettempdir(), "st_config_workaround")
15
+ os.makedirs(TEMP_STREAMLIT_HOME, exist_ok=True)
16
+
17
+ # 2. Set environment variables
18
+ os.environ["STREAMLIT_HOME"] = TEMP_STREAMLIT_HOME
19
+ os.environ["STREAMLIT_GATHER_USAGE_STATS"] = "false"
20
+
21
+ # 3. Create minimal config.toml to prevent write attempts elsewhere
22
+ CONFIG_PATH = os.path.join(TEMP_STREAMLIT_HOME, "config.toml")
23
+ CONFIG_CONTENT = """
24
+ [browser]
25
+ gatherUsageStats = false
26
+ """
27
+
28
+ if not os.path.exists(CONFIG_PATH):
29
+ try:
30
+ with open(CONFIG_PATH, "w") as f:
31
+ f.write(CONFIG_CONTENT)
32
+ except Exception as e:
33
+ print(f"WARNING: Could not write config.toml: {e}")
34
+
35
+ # ----------------------------------------------------
36
+ # End of Workarounds
37
+ # ----------------------------------------------------
38
+
39
+ # --- Configuration ---
40
+ st.set_page_config(page_title="OpenRouter Minimal Chat UI", layout="wide")
41
+ OPENROUTER_API_BASE = "https://openrouter.ai/api/v1"
42
+
43
+ # --- Page Title ---
44
+ st.title("💸 OpenRouter Minimal Chat Interface")
45
+ st.markdown("""
46
+ **Welcome to the OpenRouter Minimal Chat Interface!**
47
+ Chat with **Free-Tier** models via the OpenRouter API. Text-only chat.
48
+ """)
49
+
50
+ # --- Session State Management ---
51
+ if "messages" not in st.session_state:
52
+ st.session_state.messages = []
53
+
54
+ # --- Context-Length Fetch ---
55
+ def fetch_model_contexts(api_key):
56
+ """Fetches all models and their respective context_length."""
57
+ if not api_key:
58
+ return {}
59
+ headers = {"Authorization": f"Bearer {api_key}"}
60
+ try:
61
+ res = requests.get(f"{OPENROUTER_API_BASE}/models", headers=headers, timeout=10)
62
+ contexts = {}
63
+ if res.status_code == 200:
64
+ for m in res.json().get("data", []):
65
+ mid = m.get("id")
66
+ ctx = m.get("context_length", 4096)
67
+ contexts[mid] = ctx
68
+ return contexts
69
+ except Exception as e:
70
+ return {}
71
+
72
+
73
+ # --- Sidebar ---
74
+ with st.sidebar:
75
+ st.header("⚙️ API Settings")
76
+ api_key = st.text_input("OpenRouter API Key", type="password")
77
+
78
+ # --- Manual Model Selection ---
79
+ FREE_MODEL_LIST = [
80
+ "cognitivecomputations/dolphin-mistral-24b-venice-edition:free",
81
+ "deepseek/deepseek-chat-v3.1:free",
82
+ "nvidia/nemotron-nano-9b-v2:free",
83
+ "google/gemma-3-27b-it:free",
84
+ "openai/gpt-oss-20b:free",
85
+ "qwen/qwen3-coder:free",
86
+ "qwen/qwen2.5-vl-72b-instruct:free",
87
+ "nousresearch/deephermes-3-llama-3-8b-preview:free",
88
+ ]
89
+ model = st.selectbox("Select a Model", FREE_MODEL_LIST, index=0)
90
+
91
+ # Get context length with fallback
92
+ model_contexts = fetch_model_contexts(api_key)
93
+ default_ctx = model_contexts.get(model, 4096)
94
+
95
+ temperature = st.slider("Temperature", 0.0, 1.0, 0.7)
96
+ max_tokens = st.slider(
97
+ f"Max Output Tokens (max {default_ctx})",
98
+ 1,
99
+ min(default_ctx, 128000),
100
+ min(512, default_ctx)
101
+ )
102
+ st.caption(f"🔢 Model Context Length (Fallback 4096): {default_ctx}")
103
+
104
+ if st.button("🔄 Reset Chat"):
105
+ st.session_state.messages = []
106
+ st.success("Chat history cleared.")
107
+ st.experimental_rerun()
108
+
109
+ st.markdown("""
110
+ ---
111
+ **Minimal UI:** Text chat only.
112
+ """)
113
+
114
+
115
+ # --- Display Chat History ---
116
+ for msg in st.session_state.messages:
117
+ with st.chat_message(msg["role"]):
118
+ st.markdown(msg["content"])
119
+
120
+
121
+ # --- API Request Function ---
122
+ def call_openrouter(model, messages, temp, max_tok, key):
123
+ headers = {
124
+ "Authorization": f"Bearer {key}",
125
+ "Content-Type": "application/json",
126
+ "Referer": "https://aicodecraft.io",
127
+ "X-Title": "OpenRouter-Minimal-Interface",
128
+ }
129
+ payload = {
130
+ "model": model,
131
+ "messages": messages,
132
+ "temperature": temp,
133
+ "max_tokens": max_tok,
134
+ }
135
+
136
+ res = requests.post(f"{OPENROUTER_API_BASE}/chat/completions", headers=headers, data=json.dumps(payload))
137
+
138
+ if res.status_code == 200:
139
+ try:
140
+ return res.json()["choices"][0]["message"]["content"]
141
+ except (KeyError, IndexError):
142
+ raise Exception("Invalid API response: Could not extract response text.")
143
+ else:
144
+ try:
145
+ err = res.json()
146
+ msg = err.get("error", {}).get("message", res.text)
147
+ except:
148
+ msg = res.text
149
+ raise Exception(f"API Error {res.status_code}: {msg}")
150
+
151
+
152
+ # --- Chat Input ---
153
+ if prompt := st.chat_input("Your message..."):
154
+ if not api_key:
155
+ st.warning("Please enter your OpenRouter API Key in the sidebar.")
156
+ st.stop()
157
+
158
+ # Add and display user message
159
+ st.session_state.messages.append({"role": "user", "content": prompt})
160
+ with st.chat_message("user"):
161
+ st.markdown(prompt)
162
+
163
+ # Prepare API message history
164
+ messages = [{"role": m["role"], "content": m["content"]} for m in st.session_state.messages]
165
+
166
+ # Generate response
167
+ with st.chat_message("assistant"):
168
+ with st.spinner(f"Querying {model}..."):
169
+ try:
170
+ reply = call_openrouter(model, messages, temperature, max_tokens, api_key)
171
+ st.markdown(reply)
172
+ st.session_state.messages.append({"role": "assistant", "content": reply})
173
+ except Exception as e:
174
+ st.error(str(e))
175
+ st.session_state.messages.append({"role": "assistant", "content": f"❌ {str(e)}"})