dboa9 commited on
Commit
134c04b
·
1 Parent(s): 3e21203

updated doc corrections/edits & hugin face updates

Browse files
Files changed (2) hide show
  1. Dockerfile +0 -70
  2. shared/jira_adapter.py +0 -295
Dockerfile DELETED
@@ -1,70 +0,0 @@
1
- # Moltbot Hybrid Engine - Multi-service Dockerfile
2
- # Runs: FastAPI (port 7860) + Ollama (port 11434, background)
3
- # Build: 2026-02-06 v5.0
4
- # Dev Mode compatible per HF docs
5
- # FIX: Install Ollama as root BEFORE switching to user
6
-
7
- FROM python:3.11-slim
8
-
9
- # Install ALL packages required for HF Spaces Dev Mode + our needs
10
- RUN apt-get update && apt-get install -y --no-install-recommends \
11
- bash \
12
- curl \
13
- wget \
14
- procps \
15
- git \
16
- git-lfs \
17
- && apt-get clean \
18
- && rm -rf /var/lib/apt/lists/*
19
-
20
- # Install Ollama AS ROOT - detect architecture and download correct binary
21
- # The install.sh may fail in Docker, so we do direct download with arch detection
22
- RUN ARCH=$(uname -m) && \
23
- echo "Detected architecture: $ARCH" && \
24
- if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then \
25
- OLLAMA_URL="https://ollama.com/download/ollama-linux-amd64"; \
26
- elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
27
- OLLAMA_URL="https://ollama.com/download/ollama-linux-arm64"; \
28
- else \
29
- echo "Unknown architecture: $ARCH, trying amd64"; \
30
- OLLAMA_URL="https://ollama.com/download/ollama-linux-amd64"; \
31
- fi && \
32
- echo "Downloading Ollama from: $OLLAMA_URL" && \
33
- curl -fSL "$OLLAMA_URL" -o /usr/local/bin/ollama && \
34
- chmod +x /usr/local/bin/ollama && \
35
- echo "Ollama binary size: $(du -h /usr/local/bin/ollama | cut -f1)" && \
36
- ls -la /usr/local/bin/ollama
37
-
38
- # Create HF-required user (uid 1000)
39
- RUN useradd -m -u 1000 user
40
-
41
- # Create Ollama model storage directory owned by user
42
- RUN mkdir -p /home/user/ollama_models && chown -R user:user /home/user/ollama_models
43
-
44
- # Switch to user
45
- USER user
46
- ENV HOME=/home/user \
47
- PATH=/home/user/.local/bin:/usr/local/bin:$PATH \
48
- OLLAMA_MODELS=/home/user/ollama_models \
49
- OLLAMA_HOST=0.0.0.0
50
-
51
- # Set working directory to /app (required for dev mode)
52
- WORKDIR /app
53
-
54
- # Upgrade pip
55
- RUN pip install --no-cache-dir --upgrade pip
56
-
57
- # Copy all files with correct ownership
58
- COPY --chown=user . /app
59
-
60
- # Install Python dependencies
61
- RUN pip install --no-cache-dir -r requirements.txt
62
-
63
- # Make start script executable
64
- RUN chmod +x start.sh
65
-
66
- # Expose HF Spaces port
67
- EXPOSE 7860
68
-
69
- # CMD required (not ENTRYPOINT) for dev mode compatibility
70
- CMD ["./start.sh"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
shared/jira_adapter.py DELETED
@@ -1,295 +0,0 @@
1
- """
2
- JIRA & CONFLUENCE ADAPTER
3
- =========================
4
- Zero-risk adapter for Jira and Confluence integration.
5
- Loads credentials from environment variables or config files.
6
-
7
- Usage:
8
- from shared import JiraAdapter, ConfluenceAdapter
9
-
10
- jira = JiraAdapter()
11
- jira.add_comment("COURT-123", "Bundle generated successfully")
12
-
13
- confluence = ConfluenceAdapter()
14
- confluence.update_page("123456", "New content")
15
-
16
- Created: 2026-02-04
17
- """
18
-
19
- import os
20
- import re
21
- from pathlib import Path
22
- from typing import Optional, Dict, Any
23
-
24
- # Try to import jira library
25
- try:
26
- from jira import JIRA
27
- JIRA_AVAILABLE = True
28
- except ImportError:
29
- JIRA = None
30
- JIRA_AVAILABLE = False
31
-
32
- # Try to import atlassian library for Confluence
33
- try:
34
- from atlassian import Confluence
35
- CONFLUENCE_AVAILABLE = True
36
- except ImportError:
37
- Confluence = None
38
- CONFLUENCE_AVAILABLE = False
39
-
40
-
41
- def _load_config_from_files() -> Dict[str, str]:
42
- """
43
- Load configuration from ~/.bashrc or ~/.secure/api_keys.
44
- Returns dict with JIRA_URL, JIRA_EMAIL, JIRA_TOKEN, CONFLUENCE_URL.
45
- """
46
- config = {}
47
-
48
- # Files to search for credentials
49
- config_files = [
50
- Path.home() / ".bashrc",
51
- Path.home() / ".secure" / "api_keys",
52
- Path.home() / ".env",
53
- ]
54
-
55
- patterns = {
56
- 'JIRA_URL': r'export\s+JIRA_URL\s*=\s*["\']?([^"\';\n]+)',
57
- 'JIRA_EMAIL': r'export\s+JIRA_EMAIL\s*=\s*["\']?([^"\';\n]+)',
58
- 'JIRA_TOKEN': r'export\s+JIRA_TOKEN\s*=\s*["\']?([^"\';\n]+)',
59
- 'CONFLUENCE_URL': r'export\s+CONFLUENCE_URL\s*=\s*["\']?([^"\';\n]+)',
60
- }
61
-
62
- for config_file in config_files:
63
- if config_file.exists():
64
- try:
65
- content = config_file.read_text()
66
- for key, pattern in patterns.items():
67
- if key not in config or not config[key]:
68
- match = re.search(pattern, content)
69
- if match:
70
- config[key] = match.group(1).strip()
71
- except Exception:
72
- continue
73
-
74
- return config
75
-
76
-
77
- class JiraAdapter:
78
- """
79
- Robust Jira adapter with automatic credential loading.
80
- """
81
-
82
- def __init__(self, url: str = None, email: str = None, token: str = None):
83
- """
84
- Initialize Jira connection.
85
- Credentials loaded from: args > env vars > config files
86
- """
87
- # Load from config files first as fallback
88
- file_config = _load_config_from_files()
89
-
90
- # Priority: args > env vars > config files
91
- self.url = url or os.environ.get('JIRA_URL') or file_config.get('JIRA_URL')
92
- self.email = email or os.environ.get('JIRA_EMAIL') or file_config.get('JIRA_EMAIL')
93
- self.token = token or os.environ.get('JIRA_TOKEN') or file_config.get('JIRA_TOKEN')
94
-
95
- self.client = None
96
- self.connected = False
97
- self.error_message = None
98
-
99
- # Attempt connection
100
- if self.url and self.email and self.token and JIRA_AVAILABLE:
101
- try:
102
- self.client = JIRA(
103
- server=self.url,
104
- basic_auth=(self.email, self.token)
105
- )
106
- self.connected = True
107
- print(f"✅ [JiraAdapter] Connected to {self.url}")
108
- except Exception as e:
109
- self.error_message = str(e)
110
- print(f"⚠️ [JiraAdapter] Connection failed: {e}")
111
- else:
112
- missing = []
113
- if not self.url:
114
- missing.append('JIRA_URL')
115
- if not self.email:
116
- missing.append('JIRA_EMAIL')
117
- if not self.token:
118
- missing.append('JIRA_TOKEN')
119
- if not JIRA_AVAILABLE:
120
- missing.append('jira library')
121
- self.error_message = f"Missing: {', '.join(missing)}"
122
- print(f"⚠️ [JiraAdapter] Not configured: {self.error_message}")
123
-
124
- def add_comment(self, issue_key: str, comment: str) -> bool:
125
- """Add a comment to a Jira issue."""
126
- if not self.connected:
127
- print(f"⚠️ [JiraAdapter] Cannot add comment - not connected")
128
- return False
129
-
130
- try:
131
- self.client.add_comment(issue_key, comment)
132
- print(f"✅ [JiraAdapter] Comment added to {issue_key}")
133
- return True
134
- except Exception as e:
135
- print(f"❌ [JiraAdapter] Failed to add comment to {issue_key}: {e}")
136
- return False
137
-
138
- def update_status(self, issue_key: str, status: str) -> bool:
139
- """Update the status of a Jira issue."""
140
- if not self.connected:
141
- return False
142
-
143
- try:
144
- transitions = self.client.transitions(issue_key)
145
- for t in transitions:
146
- if t['name'].lower() == status.lower():
147
- self.client.transition_issue(issue_key, t['id'])
148
- print(f"✅ [JiraAdapter] Status updated to '{status}' for {issue_key}")
149
- return True
150
- print(f"⚠️ [JiraAdapter] Status '{status}' not found for {issue_key}")
151
- return False
152
- except Exception as e:
153
- print(f"❌ [JiraAdapter] Failed to update status: {e}")
154
- return False
155
-
156
- def create_issue(self, project: str, summary: str, description: str = "",
157
- issue_type: str = "Task") -> Optional[str]:
158
- """Create a new Jira issue. Returns issue key or None."""
159
- if not self.connected:
160
- return None
161
-
162
- try:
163
- issue = self.client.create_issue(
164
- project=project,
165
- summary=summary,
166
- description=description,
167
- issuetype={'name': issue_type}
168
- )
169
- print(f"✅ [JiraAdapter] Created issue {issue.key}")
170
- return issue.key
171
- except Exception as e:
172
- print(f"❌ [JiraAdapter] Failed to create issue: {e}")
173
- return None
174
-
175
-
176
- def is_connected(self) -> bool:
177
- """Check if JIRA connection is active (Added by Auto-Fix)."""
178
- return self.connected and self.client is not None
179
-
180
- def get_issue(self, issue_key: str) -> Optional[Dict[str, Any]]:
181
- """Get issue details."""
182
- if not self.connected:
183
- return None
184
-
185
- try:
186
- issue = self.client.issue(issue_key)
187
- return {
188
- 'key': issue.key,
189
- 'summary': issue.fields.summary,
190
- 'status': issue.fields.status.name,
191
- 'description': issue.fields.description
192
- }
193
- except Exception as e:
194
- print(f"❌ [JiraAdapter] Failed to get issue {issue_key}: {e}")
195
- return None
196
-
197
-
198
- class ConfluenceAdapter:
199
- """
200
- Robust Confluence adapter with automatic credential loading.
201
- """
202
-
203
- def __init__(self, url: str = None, email: str = None, token: str = None):
204
- """
205
- Initialize Confluence connection.
206
- """
207
- file_config = _load_config_from_files()
208
-
209
- self.url = url or os.environ.get('CONFLUENCE_URL') or file_config.get('CONFLUENCE_URL')
210
- self.email = email or os.environ.get('JIRA_EMAIL') or file_config.get('JIRA_EMAIL')
211
- self.token = token or os.environ.get('JIRA_TOKEN') or file_config.get('JIRA_TOKEN')
212
-
213
- self.client = None
214
- self.connected = False
215
-
216
- if self.url and self.email and self.token and CONFLUENCE_AVAILABLE:
217
- try:
218
- self.client = Confluence(
219
- url=self.url,
220
- username=self.email,
221
- password=self.token,
222
- cloud=True
223
- )
224
- self.connected = True
225
- print(f"✅ [ConfluenceAdapter] Connected to {self.url}")
226
- except Exception as e:
227
- print(f"⚠️ [ConfluenceAdapter] Connection failed: {e}")
228
- else:
229
- print(f"⚠️ [ConfluenceAdapter] Not configured")
230
-
231
- def is_connected(self) -> bool:
232
- """Check if Confluence connection is active."""
233
- return self.connected and self.client is not None
234
-
235
- def update_page(self, page_id: str, content: str, title: str = None) -> bool:
236
- """Update a Confluence page."""
237
- if not self.connected:
238
- return False
239
-
240
- try:
241
- page = self.client.get_page_by_id(page_id)
242
- current_title = title or page['title']
243
-
244
- self.client.update_page(
245
- page_id=page_id,
246
- title=current_title,
247
- body=content
248
- )
249
- print(f"✅ [ConfluenceAdapter] Updated page {page_id}")
250
- return True
251
- except Exception as e:
252
- print(f"❌ [ConfluenceAdapter] Failed to update page: {e}")
253
- return False
254
-
255
- def get_page_content(self, page_id: str) -> Optional[str]:
256
- """Get Confluence page content."""
257
- if not self.connected:
258
- return None
259
-
260
- try:
261
- page = self.client.get_page_by_id(page_id, expand='body.storage')
262
- return page['body']['storage']['value']
263
- except Exception as e:
264
- print(f"❌ [ConfluenceAdapter] Failed to get page: {e}")
265
- return None
266
-
267
-
268
- def diagnose():
269
- """Run diagnostic check on Jira/Confluence connectivity."""
270
- print("=" * 60)
271
- print("JIRA/CONFLUENCE ADAPTER DIAGNOSTIC")
272
- print("=" * 60)
273
-
274
- config = _load_config_from_files()
275
- print(f"\nConfig from files:")
276
- for k, v in config.items():
277
- masked = v[:10] + "..." if v and len(v) > 10 else v
278
- print(f" {k}: {masked}")
279
-
280
- print(f"\nJira library available: {JIRA_AVAILABLE}")
281
- print(f"Confluence library available: {CONFLUENCE_AVAILABLE}")
282
-
283
- print("\nTesting Jira connection...")
284
- jira = JiraAdapter()
285
- print(f" Connected: {jira.connected}")
286
-
287
- print("\nTesting Confluence connection...")
288
- confluence = ConfluenceAdapter()
289
- print(f" Connected: {confluence.connected}")
290
-
291
- print("=" * 60)
292
-
293
-
294
- if __name__ == "__main__":
295
- diagnose()