Stepan commited on
Commit
4717959
·
1 Parent(s): a8d3adb
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .venv
2
+ __pycache__
3
+ .streamlit
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
.vscode/launch.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Python Debugger: Module",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "module": "streamlit",
12
+ "args": [
13
+ "run",
14
+ "app.py",
15
+ // "--server.port",
16
+ // "SPECIFY_YOUR_OWN_PORT_NUMBER_HERE"
17
+ ]
18
+ }
19
+ ]
20
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "cSpell.words": [
3
+ "qdrant"
4
+ ]
5
+ }
app.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import logging
4
+ from typing import List, Dict, Any
5
+ from data_processor import load_json_data, process_documents, split_documents
6
+ from rag_pipeline import RAGPipeline
7
+
8
+ # Configure logging
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Constants
13
+ DATA_PATH = "ltu_programme_data.json"
14
+ QDRANT_PATH = "./qdrant_data"
15
+ EMBEDDING_MODEL = "BAAI/bge-en-icl"
16
+ LLM_MODEL = "meta-llama/Llama-3.3-70B-Instruct"
17
+ qdrant = None
18
+
19
+ # Initialize session state
20
+ if "messages" not in st.session_state:
21
+ st.session_state.messages = []
22
+
23
+ if "rag_pipeline" not in st.session_state:
24
+ st.session_state.rag_pipeline = None
25
+
26
+ @st.cache_resource
27
+ def get_rag_pipeline():
28
+ return RAGPipeline(
29
+ embedding_model_name=EMBEDDING_MODEL,
30
+ llm_model_name=LLM_MODEL,
31
+ qdrant_path = QDRANT_PATH
32
+ )
33
+
34
+ def load_and_index_documents(rag_pipeline: RAGPipeline) -> bool:
35
+ """Load and index documents"""
36
+ if not os.path.exists(DATA_PATH):
37
+ st.error(f"Data file not found: {DATA_PATH}")
38
+ return False
39
+
40
+ with st.spinner("Loading and processing documents..."):
41
+ # Load data
42
+ data = load_json_data(DATA_PATH)
43
+
44
+ if not data:
45
+ st.error("Failed to load data")
46
+ return False
47
+
48
+ # Process documents
49
+ processed_docs = process_documents(data)
50
+
51
+ if not processed_docs:
52
+ st.error("Failed to process documents")
53
+ return False
54
+
55
+ # Split documents
56
+ chunked_docs = split_documents(processed_docs, chunk_size=1000, overlap=100)
57
+
58
+ if not chunked_docs:
59
+ st.error("Failed to split documents")
60
+ return False
61
+
62
+ # Index documents
63
+ with st.spinner(f"Indexing {len(chunked_docs)} document chunks..."):
64
+ rag_pipeline.index_documents(chunked_docs)
65
+
66
+ return True
67
+
68
+ def display_document_sources(documents: List[Dict[str, Any]]):
69
+ """Display the sources of the retrieved documents"""
70
+ if documents:
71
+ with st.expander("View Sources"):
72
+ for i, doc in enumerate(documents):
73
+ st.markdown(f"**Source {i+1}**: [{doc.meta.get('url', 'Unknown')}]({doc.meta.get('url', '#')})")
74
+ st.markdown(f"**Excerpt**: {doc.content[:200]}...")
75
+ st.markdown("---")
76
+
77
+ def check_documents_indexed(qdrant_path: str) -> int:
78
+ """Check if documents are already indexed by returning the number of documents in Qdrant"""
79
+ try:
80
+ from haystack_integrations.document_stores.qdrant import QdrantDocumentStore
81
+
82
+ # Initialize the document store with the existing path
83
+ document_store = QdrantDocumentStore(
84
+ path=qdrant_path,
85
+ embedding_dim=4096,
86
+ recreate_index=False,
87
+ index="ltu_documents"
88
+ )
89
+
90
+ # Get the document count
91
+ document_count = len(document_store.filter_documents({}))
92
+ return document_count
93
+ except Exception:
94
+ # If there's an error (e.g., Qdrant not initialized), return 0
95
+ return 0
96
+
97
+ def main():
98
+ # Set page config
99
+ st.set_page_config(
100
+ page_title="LTU Chat - QA App",
101
+ page_icon="🎓",
102
+ layout="wide"
103
+ )
104
+
105
+ # Header
106
+ st.title("🎓 LTU Chat - QA App")
107
+ st.markdown("""
108
+ Ask questions about LTU programmes and get answers powered by AI.
109
+ This app uses RAG (Retrieval Augmented Generation) to provide accurate information.
110
+ """)
111
+ rag_pipeline = get_rag_pipeline()
112
+ # Sidebar
113
+ with st.sidebar:
114
+ st.header("Settings")
115
+
116
+ # Initialize RAG pipeline if not already done
117
+ # if st.session_state.rag_pipeline is None:
118
+ # if st.button("Initialize RAG Pipeline"):
119
+ # st.session_state.rag_pipeline = get_rag_pipeline()
120
+ # st.success("RAG pipeline initialized successfully!")
121
+ # else:
122
+ # st.success("RAG pipeline is ready!")
123
+
124
+ # Check if documents are already indexed
125
+ documents_indexed = rag_pipeline.get_document_count()
126
+ if not documents_indexed:
127
+ if st.button("Index Documents"):
128
+ success = load_and_index_documents(st.session_state.rag_pipeline)
129
+ if success:
130
+ st.success("Documents indexed successfully!")
131
+ # Refresh the documents_indexed status
132
+ documents_indexed = True
133
+
134
+ # Get document counts
135
+ count = rag_pipeline.get_document_count()
136
+ st.info(f"Indexed {count} documents documents in vector store.")
137
+ else:
138
+ st.success(f"{documents_indexed} documents are indexed and ready!")
139
+
140
+ top_k = st.slider("Number of documents to retrieve", min_value=1, max_value=10, value=5)
141
+ # Advanced settings
142
+ # with st.expander("Advanced Settings"):
143
+
144
+
145
+ # Display chat messages
146
+ for message in st.session_state.messages:
147
+ with st.chat_message(message["role"]):
148
+ st.markdown(message["content"])
149
+ if message.get("documents"):
150
+ display_document_sources(message["documents"])
151
+
152
+ # Chat input
153
+ if prompt := st.chat_input("Ask a question about LTU programmes"):
154
+ # Add user message to chat history
155
+ st.session_state.messages.append({"role": "user", "content": prompt})
156
+
157
+ # Display user message
158
+ with st.chat_message("user"):
159
+ st.markdown(prompt)
160
+
161
+ # Generate response
162
+ if rag_pipeline and documents_indexed:
163
+ with st.chat_message("assistant"):
164
+ with st.spinner("Thinking..."):
165
+ # Query the RAG pipeline
166
+ result = rag_pipeline.query(prompt, top_k=top_k)
167
+
168
+ # Display the answer
169
+ st.markdown(result["answer"])
170
+
171
+ # Display sources
172
+ if result.get("documents"):
173
+ display_document_sources(result["documents"])
174
+
175
+ # Add assistant message to chat history
176
+ st.session_state.messages.append({
177
+ "role": "assistant",
178
+ "content": result["answer"],
179
+ "documents": result.get("documents", [])
180
+ })
181
+ else:
182
+ with st.chat_message("assistant"):
183
+ if not rag_pipeline:
184
+ error_message = "Please initialize the RAG pipeline first."
185
+ else:
186
+ error_message = "Please index documents first."
187
+ st.error(error_message)
188
+ st.session_state.messages.append({"role": "assistant", "content": error_message})
189
+
190
+ if __name__ == "__main__":
191
+ main()
data_processor.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from bs4 import BeautifulSoup
4
+ import logging
5
+ from typing import List, Dict, Any
6
+ from haystack.components.preprocessors.document_splitter import DocumentSplitter
7
+ from haystack import Document
8
+
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ def load_json_data(file_path: str) -> List[Dict[str, str]]:
13
+ """
14
+ Load data from a JSON file.
15
+
16
+ Args:
17
+ file_path: Path to the JSON file
18
+
19
+ Returns:
20
+ List of dictionaries containing the data
21
+ """
22
+ try:
23
+ with open(file_path, 'r', encoding='utf-8') as f:
24
+ data = json.load(f)
25
+ logger.info(f"Successfully loaded {len(data)} records from {file_path}")
26
+ return data
27
+ except Exception as e:
28
+ logger.error(f"Error loading JSON data: {e}")
29
+ return []
30
+
31
+ def extract_text_from_html(html_content: str) -> str:
32
+ """
33
+ Extract text content from HTML.
34
+
35
+ Args:
36
+ html_content: HTML content as string
37
+
38
+ Returns:
39
+ Extracted text content
40
+ """
41
+ try:
42
+ soup = BeautifulSoup(html_content, 'html.parser')
43
+
44
+ # Remove script and style elements
45
+ for script in soup(["script", "style"]):
46
+ script.extract()
47
+
48
+ # Get text
49
+ text = soup.get_text(separator=' ', strip=True)
50
+
51
+ # Remove extra whitespace
52
+ lines = (line.strip() for line in text.splitlines())
53
+ chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
54
+ text = ' '.join(chunk for chunk in chunks if chunk)
55
+
56
+ return text
57
+ except Exception as e:
58
+ logger.error(f"Error extracting text from HTML: {e}")
59
+ return ""
60
+
61
+ def process_documents(data: List[Dict[str, str]]) -> List[Dict[str, Any]]:
62
+ """
63
+ Process documents from the dataset.
64
+
65
+ Args:
66
+ data: List of dictionaries containing url and html fields
67
+
68
+ Returns:
69
+ List of processed documents with text content
70
+ """
71
+ processed_docs = []
72
+
73
+ for i, item in enumerate(data):
74
+ try:
75
+ url = item.get('url', '')
76
+ content = item.get('content', '')
77
+
78
+ if not url or not content:
79
+ continue
80
+
81
+ # text = extract_text_from_html(html)
82
+ # text = html
83
+
84
+ # if not text:
85
+ # continue
86
+
87
+ # Create document with metadata
88
+ doc = {
89
+ 'content': content,
90
+ 'meta': {
91
+ 'url': url,
92
+ 'doc_id': f"doc_{i}"
93
+ }
94
+ }
95
+
96
+ processed_docs.append(doc)
97
+
98
+ except Exception as e:
99
+ logger.error(f"Error processing document {i}: {e}")
100
+
101
+ logger.info(f"Successfully processed {len(processed_docs)} documents")
102
+ return processed_docs
103
+
104
+ def split_documents(docs: List[Dict[str, Any]], chunk_size: int = 500, overlap: int = 50) -> List[Dict[str, Any]]:
105
+ """
106
+ Split documents into smaller chunks for better retrieval using Haystack.
107
+
108
+ Args:
109
+ docs: List of processed documents
110
+ chunk_size: Size of each chunk in characters
111
+ overlap: Overlap between chunks in characters
112
+
113
+ Returns:
114
+ List of document chunks
115
+ """
116
+ # Initialize Haystack document splitter
117
+ document_splitter = DocumentSplitter(
118
+ # split_by="character",
119
+ split_length=chunk_size,
120
+ split_overlap=overlap
121
+ )
122
+
123
+ chunked_docs = []
124
+
125
+ for doc in docs:
126
+ # If content is shorter than chunk_size, keep as is
127
+ if len(doc['content']) <= chunk_size:
128
+ chunked_docs.append(doc)
129
+ continue
130
+
131
+ # Prepare document for Haystack splitter
132
+ haystack_doc = Document(
133
+ content=doc['content'],
134
+ meta=doc['meta']
135
+ )
136
+
137
+ # Split the document
138
+ result = document_splitter.run(documents=[haystack_doc])
139
+ split_docs = result["documents"]
140
+
141
+ # Update document IDs for the chunks
142
+ for i, split_doc in enumerate(split_docs):
143
+ split_doc.meta["doc_id"] = f"{doc['meta']['doc_id']}_chunk_{i}"
144
+ split_doc.meta["chunk_id"] = i
145
+ chunked_docs.append(split_doc)
146
+
147
+ logger.info(f"Split {len(docs)} documents into {len(chunked_docs)} chunks")
148
+ return chunked_docs
149
+
150
+ if __name__ == "__main__":
151
+ # Test the functions
152
+ data_path = "ltu_programme_data.json"
153
+ if os.path.exists(data_path):
154
+ data = load_json_data(data_path)
155
+ processed_docs = process_documents(data[:5]) # Process first 5 docs as a test
156
+ chunked_docs = split_documents(processed_docs)
157
+ print(f"Processed {len(processed_docs)} documents into {len(chunked_docs)} chunks")
example.html ADDED
@@ -0,0 +1,1205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html class="sv-no-js sv-template-program" lang="en">
3
+ <head>
4
+ <title> Bachelor Programme in Computer Graphics for Games and Film | Lule\u00e5 University of Technology </title>
5
+ </head>
6
+ <body class="sv-responsive env-m-around--0">
7
+ <div class="sv-layout" id="svid10_4ba0e70b186a198d5ae4ec2f">
8
+ <div class="sv-custom-module sv-404statusCodeTranslation sv-skip-spacer sv-template-portlet" id="svid12_4c63de6f18c8ad0610e3ece8">
9
+ </div>
10
+ <div id="svid94_4ba0e70b186a198d5ae4ec3a">
11
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_110defe1188bd8d55c0d2f1a">
12
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_110defe1188bd8d55c0d39f6">
13
+ <div class="sv-custom-module sv-marketplace-sitevision-cookie-consent sv-skip-spacer sv-template-portlet" id="svid12_110defe1188bd8d55c0d39f7">
14
+ <div data-cid="12.110defe1188bd8d55c0d39f7">
15
+ <div aria-hidden="false" aria-labelledby="sv_NZzPUSk6owvv2-Meo4hgR" aria-modal="true" class="env-modal-dialog oHJ5jYD6hE4G0dWjJEyW sv-cookie-consent-modal env-modal-dialog--show env-modal-dialog--inner-scroll LaJqpGNhg_GETNxRY5qw" data-nosnippet="true" role="dialog">
16
+ <div class="env-modal-dialog__dialog" data-testid="modal-dialog">
17
+ <section aria-live="polite" class="env-modal-dialog__content">
18
+ <header class="env-modal-dialog__header">
19
+ <h2 class="env-modal-dialog__header__title env-text-h4" id="sv_NZzPUSk6owvv2-Meo4hgR"> Cookies on ltu.se </h2>
20
+ </header>
21
+ <div class="env-modal-dialog__body">
22
+ <div class="env-d--flex env-flex--column">
23
+ <p class="env-m-top--x-small env-text">
24
+ <a class="env-link" href="/en/about-cookies" rel="" target="_self"> Read more in our cookie policy </a>
25
+ </p>
26
+ </div>
27
+ </div>
28
+ </section>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <header class="sv-vertical sv-layout sv-template-layout" id="svid10_4ba0e70b186a198d5ae4ec3b">
36
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_110defe1188bd8d55c041d91">
37
+ <div class="sv-predefinedsearch-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_110defe1188bd8d55c041d9d">
38
+ </div>
39
+ </div>
40
+ <div class="sv-html-portlet sv-portlet sv-template-portlet" id="svid12_4ba0e70b186a198d5ae4f148">
41
+ <a class="main-content env-assistive-text is-focusable" href="#main-content"> Hoppa till huvudinneh\u00e5llet </a>
42
+ </div>
43
+ <div class="sv-script-portlet sv-portlet sv-template-portlet" id="svid12_4ba0e70b186a198d5ae4f149">
44
+ </div>
45
+ <div class="sv-vertical sv-layout ltu-header sv-template-layout" id="svid10_110defe1188bd8d55c041d9e">
46
+ <div class="sv-vertical sv-layout ltu-header-main sv-skip-spacer sv-template-layout" id="svid10_b529e7118ab83c4fc61851a">
47
+ <div class="sv-fixed-fluid-grid sv-grid-12-kolumner-1224 sv-layout sv-skip-spacer sv-template-layout" id="svid10_4ba0e70b186a198d5ae4fc7a">
48
+ <div class="sv-vertical sv-layout ltu-header__wrapper sv-skip-spacer sv-template-layout" id="svid10_4ba0e70b186a198d5ae4fc7b">
49
+ <div class="sv-vertical sv-layout ltu-header__logotype sv-skip-spacer sv-template-layout" id="svid10_4ba0e70b186a198d5ae4ec9e">
50
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_54e1ff71188bd846477110d">
51
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_54e1ff71188bd846477110c">
52
+ </div>
53
+ </div>
54
+ </div>
55
+ <div class="sv-vertical sv-layout ltu-header__buttons--wrapper sv-template-layout" id="svid10_4ba0e70b186a198d5ae4ec9f">
56
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_110defe1188bd8d55c0c06d5">
57
+ </div>
58
+ </div>
59
+ <div class="sv-vertical sv-layout ltu-header__search-panel sv-template-layout" id="svid10_4ba0e70b186a198d5ae4f741">
60
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_77ae0016189943c42b132e92">
61
+ <div class="sv-searchform-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_77ae0016189943c42b132e93">
62
+ </div>
63
+ <div class="sv-layout sv-template-portlet" id="svid30_3ea3c9a518adb77cb5410a43">
64
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_4c63de6f18c8ad0610e3ee62">
65
+ <div class="sv-script-portlet sv-portlet ltu-main__search-quick-links sv-skip-spacer sv-template-portlet" id="svid12_4c63de6f18c8ad0610e3ee63">
66
+ <p> Quick links </p>
67
+ <ul>
68
+ <li>
69
+ <a href="/en/education"> Education </a>
70
+ </li>
71
+ <li>
72
+ <a href="/en/latest-news/calendar"> Calendar </a>
73
+ </li>
74
+ <li>
75
+ <a href="/en/latest-news/news"> News </a>
76
+ </li>
77
+ </ul>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ <div class="sv-script-portlet sv-portlet sv-template-portlet" id="svid12_4ba0e70b186a198d5ae4fc5f">
84
+ <nav aria-label="Main menu" class="ltu-menu" id="ltu-menu">
85
+ <ul aria-hidden="false" class="ltu-menu-ul" data-is-start-node="true" data-link="/en" data-node-id="4.6cee445918721b0da0b3232b" data-parent="Start" data-parent-node-id="2.c3cb020184e60e73e2103f_sitePage" data-start-node="Lule\u00e5 University of Technology">
86
+ <li class="ltu-menu-item">
87
+ <div class="ltu-menu-item-wrapper">
88
+ <a class="ltu-menu-item-link" href="/en/latest-news"> Latest news </a>
89
+ </div>
90
+ </li>
91
+ <li class="ltu-menu-item" data-hascontentloaded="true">
92
+ <div class="ltu-menu-item-wrapper">
93
+ <a class="ltu-menu-item-link" href="/en/education"> Education </a>
94
+ </div>
95
+ </li>
96
+ <li class="ltu-menu-item">
97
+ <div class="ltu-menu-item-wrapper">
98
+ <a class="ltu-menu-item-link" href="/en/research"> Research </a>
99
+ </div>
100
+ </li>
101
+ <li class="ltu-menu-item">
102
+ <div class="ltu-menu-item-wrapper">
103
+ <a class="ltu-menu-item-link" href="/en/collaboration"> Collaboration </a>
104
+ </div>
105
+ </li>
106
+ <li class="ltu-menu-item">
107
+ <div class="ltu-menu-item-wrapper">
108
+ <a class="ltu-menu-item-link" href="/en/university-library"> University Library </a>
109
+ </div>
110
+ </li>
111
+ <li class="ltu-menu-item">
112
+ <div class="ltu-menu-item-wrapper">
113
+ <a class="ltu-menu-item-link" href="/en/about-the-university"> About the University </a>
114
+ </div>
115
+ </li>
116
+ <li class="ltu-menu-item">
117
+ <div class="ltu-menu-item-wrapper">
118
+ <a class="ltu-menu-item-link" href="/en/contact-lulea-university-of-technology"> Contact Lule\u00e5 University of Technology </a>
119
+ </div>
120
+ </li>
121
+ <li class="ltu-menu-item">
122
+ <div class="ltu-menu-item-wrapper">
123
+ <a class="ltu-menu-item-link" href="/en/in-case-of-incident-or-emergency"> In case of incident or emergency </a>
124
+ </div>
125
+ </li>
126
+ </ul>
127
+ <ul aria-hidden="false" class="ltu-menu-ul" data-link="/en/education" data-node-id="4.54e1ff71188bd8464773caa0" data-parent="Lule\u00e5 University of Technology" data-parent-node-id="4.6cee445918721b0da0b3232b">
128
+ <li class="ltu-menu-item">
129
+ <div class="ltu-menu-item-wrapper">
130
+ <a class="ltu-menu-item-link" href="/en/education/find-programmes-and-courses"> Find programmes and courses </a>
131
+ </div>
132
+ </li>
133
+ <li class="ltu-menu-item">
134
+ <div class="ltu-menu-item-wrapper">
135
+ <a class="ltu-menu-item-link" href="/en/education/master-and-bachelor-programmes"> Master and Bachelor Programmes </a>
136
+ </div>
137
+ </li>
138
+ <li class="ltu-menu-item">
139
+ <div class="ltu-menu-item-wrapper">
140
+ <a class="ltu-menu-item-link" href="/en/education/our-courses"> Our Courses </a>
141
+ </div>
142
+ </li>
143
+ <li class="ltu-menu-item">
144
+ <div class="ltu-menu-item-wrapper">
145
+ <a class="ltu-menu-item-link" href="/en/education/erasmus-mundus-programmes"> Erasmus mundus programmes </a>
146
+ </div>
147
+ </li>
148
+ <li class="ltu-menu-item">
149
+ <div class="ltu-menu-item-wrapper">
150
+ <a class="ltu-menu-item-link" href="/en/education/exchange-studies"> Exchange studies </a>
151
+ </div>
152
+ </li>
153
+ <li class="ltu-menu-item">
154
+ <div class="ltu-menu-item-wrapper">
155
+ <a class="ltu-menu-item-link" href="/en/education/single-subject-courses"> Single subject courses </a>
156
+ </div>
157
+ </li>
158
+ <li class="ltu-menu-item">
159
+ <div class="ltu-menu-item-wrapper">
160
+ <a class="ltu-menu-item-link" href="/en/education/tuition-and-application-fees"> Tuition and application fees </a>
161
+ </div>
162
+ </li>
163
+ <li class="ltu-menu-item">
164
+ <div class="ltu-menu-item-wrapper">
165
+ <a class="ltu-menu-item-link" href="/en/education/scholarship-opportunities"> Scholarship opportunities </a>
166
+ </div>
167
+ </li>
168
+ <li class="ltu-menu-item">
169
+ <div class="ltu-menu-item-wrapper">
170
+ <a class="ltu-menu-item-link" href="/en/education/syllabuses"> Syllabuses </a>
171
+ </div>
172
+ </li>
173
+ <li class="ltu-menu-item">
174
+ <div class="ltu-menu-item-wrapper">
175
+ <a class="ltu-menu-item-link" href="/en/education/academic-calendar"> Academic Calendar </a>
176
+ </div>
177
+ </li>
178
+ <li class="ltu-menu-item">
179
+ <div class="ltu-menu-item-wrapper">
180
+ <a class="ltu-menu-item-link" href="/en/education/elite-sports-and-studies"> Elite sports and studies </a>
181
+ </div>
182
+ </li>
183
+ <li class="ltu-menu-item">
184
+ <div class="ltu-menu-item-wrapper">
185
+ <a class="ltu-menu-item-link" href="/en/education/faq"> FAQ </a>
186
+ </div>
187
+ </li>
188
+ <li class="ltu-menu-item">
189
+ <div class="ltu-menu-item-wrapper">
190
+ <a class="ltu-menu-item-link" href="/en/education/skills-development-for-professionals"> Skills development for professionals </a>
191
+ </div>
192
+ </li>
193
+ </ul>
194
+ <div class="heading-menu-section">
195
+ <a class="ltu-menu-parent subheading" href="/en/education"> Education </a>
196
+ </div>
197
+ <ul class="service-menu">
198
+ <li>
199
+ <a href="/utbildning/program/tkdsg-datorgrafik-for-spel-och-film-kandidat" lang="sv">
200
+ <span> P\u00e5 svenska </span>
201
+ </a>
202
+ </li>
203
+ <li>
204
+ <a href="/en/staff-web">
205
+ <span> Staff </span>
206
+ </a>
207
+ </li>
208
+ <li>
209
+ <a href="/en/student-web">
210
+ <span> Student website </span>
211
+ </a>
212
+ </li>
213
+ </ul>
214
+ </nav>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ </div>
219
+ <div class="sv-vertical sv-layout ltu-header-toc-mobile sv-template-layout" id="svid10_b529e7118ab83c4fc618723">
220
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_b529e7118ab83c4fc618422">
221
+ </div>
222
+ </div>
223
+ </div>
224
+ </header>
225
+ <main class="sv-vertical sv-layout ltu-main sv-template-layout" id="svid10_4ba0e70b186a198d5ae4ec3c">
226
+ <div class="sv-html-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_4ba0e70b186a198d5ae4ec3e">
227
+ </div>
228
+ <div id="svid94_2a813a51877918956fccd2">
229
+ <div class="sv-fixed-fluid-grid sv-grid-12-kolumner-1224 sv-layout sv-skip-spacer sv-template-layout" id="svid10_2a813a51877918956fccd3">
230
+ <div class="sv-row sv-layout sv-hide-sv-bp-telefon sv-visible-sv-bp-barbar sv-visible-sv-bp-storre-an-desktop sv-visible-sv-bp-tablet sv-skip-spacer sv-template-layout" id="svid10_2a813a51877918956fccd4">
231
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_2a813a51877918956fcce9">
232
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_6cee445918721b0da0be463">
233
+ <nav aria-label="Breadcrumb">
234
+ <ol class="ltu-main__breadcrumbs--list">
235
+ <li class="ltu-main__breadcrumbs--item">
236
+ <a href="/en"> Lule\u00e5 University of Technology </a>
237
+ </li>
238
+ <li class="ltu-main__breadcrumbs--item">
239
+ <a href="/en/education"> Education </a>
240
+ </li>
241
+ <li class="ltu-main__breadcrumbs--item">
242
+ <a href="/en/education/programme"> Programme </a>
243
+ </li>
244
+ <li class="ltu-main__breadcrumbs--item">
245
+ <a class="ltu-main__breadcrumbs--item-last" href="/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film"> Bachelor Programme in Computer Graphics for Games and Film </a>
246
+ </li>
247
+ </ol>
248
+ </nav>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_2a813a51877918956fccd5">
253
+ <div class="sv-html-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_2a813a51877918956fcd30">
254
+ </div>
255
+ </div>
256
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_2a813a51877918956fcd2b">
257
+ <div id="svid94_9d9795118afe541238182d5">
258
+ <div class="sv-custom-module sv-Title-Hook sv-skip-spacer sv-template-portlet" id="svid12_113c8d5d18b5cf299b62c70">
259
+ </div>
260
+ <div class="sv-vertical sv-layout ltu-main__programpage-wrapper sv-template-layout" id="svid10_19b2182518e5fcf57f3524ae">
261
+ <div class="sv-row sv-layout ltu-main__top-image sv-skip-spacer sv-template-layout" id="svid10_9d9795118afe5412381832c">
262
+ <div class="pagecontent sv-layout" id="svid94_5100ce5c18bc193fe5e285c">
263
+ <div class="sv-mfpimage-portlet sv-portlet sv-skip-spacer" id="svid12_5100ce5c18bc193fe5e285d">
264
+ </div>
265
+ </div>
266
+ </div>
267
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_9d9795118afe5412381857d">
268
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_9d9795118afe5412381857e">
269
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_54e1ff71188bd8464773d108">
270
+ <div class="sv-language-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_54e1ff71188bd84647711a3">
271
+ <p class="normal language">
272
+ <a href="/utbildning/program/tkdsg-datorgrafik-for-spel-och-film-kandidat" lang="sv"> P\u00e5 svenska </a>
273
+ </p>
274
+ </div>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_9d9795118afe541238206a5">
279
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_9d9795118afe54123818316">
280
+ <div class="sv-text-portlet-content">
281
+ <h1 class="heading" id="h-BachelorProgrammeinComputerGraphicsforGamesandFilm"> Bachelor Programme in Computer Graphics for Games and Film </h1>
282
+ </div>
283
+ </div>
284
+ </div>
285
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_9d9795118afe5412381830e">
286
+ <div class="sv-vertical sv-layout sv-hide-sv-bp-telefon sv-hide-sv-bp-tablet sv-skip-spacer sv-template-layout" id="svid10_76a8fd2c18bacfca06c1ab">
287
+ <div class="sv-layout sv-skip-spacer sv-column-8 sv-template-layout" id="svid10_9d9795118afe54123818312">
288
+ <div class="sv-custom-module sv-Utbildningsinfo sv-skip-spacer sv-template-portlet" id="svid12_767116d318b37dcb73886a3">
289
+ <div data-cid="12.767116d318b37dcb73886a3">
290
+ <div class="n643rbQmLp1JhPH6BNOP" data-reactroot="">
291
+ <div class="YCmRRC2mkPKvIvPGgVS1">
292
+ <div>
293
+ <div class="HMw9ixbm69bdZBQgzYIc">
294
+ <p class="PT2hF8CC4ZkIu8gQjcXZ P6maIg6cPpOpyvdkNWhU"> 180 credits, programme, bachelor's level, TKDSG </p>
295
+ </div>
296
+ </div>
297
+ <div class="Ow6v240LEi5yqxc5rGR5">
298
+ <div class="NCeqmR8pzeE44yTVEI57">
299
+ <div class="xSna321hZeZMiT3Krt5Q">
300
+ <div aria-hidden="true" class="QIGBu7OXJcb9eqnrSJh2" id="semester-list-12-767116d318b37dcb73886a3" style="display:none">
301
+ <a class="P6maIg6cPpOpyvdkNWhU" href="?termin=HT%202024"> Autumn 2024 </a>
302
+ </div>
303
+ </div>
304
+ </div>
305
+ <div class="k2P1IeAKKuFzeBtQpNAH Anuhi5WUjEADMmjifqzb">
306
+ <p class="P6maIg6cPpOpyvdkNWhU"> Open for late application! </p>
307
+ </div>
308
+ <div class="XSSl3yA6zZnlVfET_yP8">
309
+ <a class="P6maIg6cPpOpyvdkNWhU" href=""> To signup </a>
310
+ </div>
311
+ </div>
312
+ </div>
313
+ <div class="ihAUe3Ae4xOF4DoCK40U">
314
+ <p class="mbr3VVI67WGiBBWXN62d"> Do you want to be part of the teams that create the visual effects for the next Hollywood blockbuster or the stunning levels of award-winning AAA video games? In the Computer Graphics for Film and Games programme, you will learn to transform your creative ideas into spectacular digital worlds. </p>
315
+ <div class="ne945o61E5G3OHW9nAsv">
316
+ <div> Do you enjoy crafting beautiful images - and technical problem-solving? Perhaps you are already exploring digital technologies, such as image editing, animation, 3D modelling, or modding games. Whether you have a background in traditional arts or the natural sciences, computer graphics offers many different pathways to developing your creative possibilities. </div>
317
+ <div>
318
+ </div>
319
+ <div> This programme accepts both Swedish and international applicants, creating a dynamic and diverse study environment. You will learn professional tools and processes to take a project from concept to finished film or game production. More than that, you will hone your artistic eye, understand the scientific foundations of the field, and gain experience collaborating with others on creative briefs. With over thirty years of experience teaching in the field, we focus on the key skills required in an industry that is constantly changing and evolving. </div>
320
+ <div>
321
+ </div>
322
+ <div> After graduation, you will join our many alumni in fields such as game development, visual effects production for film, or feature animation. A university degree gives you the advantage needed when applying for jobs in the highly competitive and international market. </div>
323
+ </div>
324
+ <div class="h1RG7SwGDaAhnFCbNq5p">
325
+ <div class="sv-vertical sv-layout sv-skip-spacer" id="layout-accordion-12-767116d318b37dcb73886a3-0">
326
+ <div class="sv-vertical sv-layout ltu__accordion sv-skip-spacer">
327
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer">
328
+ <div class="ltu__accordion-container">
329
+ </div>
330
+ </div>
331
+ <div class="sv-vertical sv-layout sv-decoration-content">
332
+ <div class="bLA8XBv10huo26rMBkg2">
333
+ <div> The first semester lays the groundwork for the rest of your studies. Beginning with traditional art exercises, you will quickly move on to collaborative creative projects where a client sets the expectations. At the same time, you learn the basics of digital media and the key technical concepts that underpin future courses. </div>
334
+ <div> In the spring semester, you will develop core skills in 2D digital compositing\u2014the foundation of all film visual effects\u2014alongside 3D modelling, animation, and rendering. A programming course rounds out your introduction to computer graphics. During your second year, you dive deeper into 3D graphics. Advanced modelling and texturing techniques will allow you to create more realistic assets, while an introduction to real-time graphics opens up the world of interactive video games. Effects simulation will teach you how to replicate complex natural phenomena like smoke and water, and a mathematics course will give you the theoretical tools to understand these processes.The spring semester offers opportunities to further hone your artistic and technical skills through project-based courses. </div>
335
+ <div>
336
+ </div>
337
+ <div> Your final year focuses on applying everything you have learned. Collaboration, teamwork, independence, and problem-solving will all be key to your professional future. Some projects will have you working in large teams under close supervision, while others will involve solo research and skill development to help you build a strong portfolio. In your last semester, you collaborate with your peers to create a fully realised product - such as a game or short film. This hands-on experience will give you a comprehensive understanding of professional workflows and a finished product to showcase to potential employers. By graduation, you will have both specialised knowledge and practical experience, setting you up for a successful career in computer graphics. </div>
338
+ </div>
339
+ </div>
340
+ </div>
341
+ </div>
342
+ <div class="sv-vertical sv-layout sv-skip-spacer" id="layout-accordion-12-767116d318b37dcb73886a3-2">
343
+ <div class="sv-vertical sv-layout ltu__accordion sv-skip-spacer">
344
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer">
345
+ <div class="ltu__accordion-container">
346
+ </div>
347
+ </div>
348
+ <div class="sv-vertical sv-layout sv-decoration-content">
349
+ <div class="bLA8XBv10huo26rMBkg2">
350
+ <div> The programme prepares you for a range of roles working with digital media in the fields of game development, film post-production (VFX), and feature animation. Your skills will also translate into related industries, such as advertising and architectural visualisation. After graduation, you might find yourself in generalised roles such as 3D Artist, CG Generalist, or Technical Director. You may also specialise in careers such as Environment Artist, VFX Artist, Compositor, Animator, FX Artist, and more. </div>
351
+ <div> Our alumni have worked on film projects such as The Lord of the Rings films, Harry Potter series, and Shogun; and games such as Battlefront series, Assassin\u2019s Creed, and Helldivers II. </div>
352
+ </div>
353
+ </div>
354
+ </div>
355
+ </div>
356
+ </div>
357
+ </div>
358
+ </div>
359
+ </div>
360
+ </div>
361
+ <div class="sv-custom-module sv-Antagningsinfo sv-template-portlet" id="svid12_113c8d5d18b5cf299b6203c">
362
+ <div data-cid="12.113c8d5d18b5cf299b6203c">
363
+ <div class="ZNUvioejd0sf76mDllUw" data-reactroot="">
364
+ <div class="nO6gixhkydP0V1HvItFs">
365
+ <h2 class="Omzt6wK6ec3dPmWuUGys"> Sign up for the programme </h2>
366
+ <div>
367
+ <div class="zLzFOMPisNxzvt_htr0Q">
368
+ <div class="zlkqdrXR1uei8xmUnfyZ">
369
+ <div class="hBedBl2wkkgVgAAgDlWf">
370
+ <div class="kTKjJ7LBjjCvDKQ54obI">
371
+ <p class="yOIfCXndb3ZR16kbRgAt C6m2QJ0XjKwKscgJhFzK"> LTU-87020 </p>
372
+ <div class="gk0D3Ip7pLalmcnWorhD w7_ihQcJBol8nnSs9g73">
373
+ <p class="C6m2QJ0XjKwKscgJhFzK"> Open for late application! </p>
374
+ </div>
375
+ </div>
376
+ <h3 class="UU3Vc64tqr14z9OQCw5w"> Bachelor Programme in Computer graphics for game and film, International students </h3>
377
+ <p class="DK3aev8MNKGpfCwrSXq7 C6m2QJ0XjKwKscgJhFzK">
378
+ <span class="ybOpqUwzAposuRmd1kvi"> Start date 2025-09-01, v. 36 2025 , </span>
379
+ <span class="ubuecRhlCCNGE0h1a0BB"> Skellefte\u00e5 </span>
380
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Normal teaching </span>
381
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Day-time 100% </span>
382
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Autumn 2025 </span>
383
+ </p>
384
+ </div>
385
+ <div class="FANKPZoqsFhpSbBZw8Bp">
386
+ <a href="https://www.universityadmissions.se/intl/addtobasket?period=ht_2025&amp;id=LTU-87020" rel="external"> Apply here <span class="env-assistive-text"> to the programme Bachelor Programme in Computer graphics for game and film, International students - LTU-87020 Link to another website, opens in new window </span>
387
+ </a>
388
+ </div>
389
+ </div>
390
+ <div aria-hidden="true" aria-labelledby="btn-LTU-87020-12-113c8d5d18b5cf299b6203c-id787eb468517f98" class="ZRtoL3It3_sm8MY77J2q" id="acc-LTU-87020-12-113c8d5d18b5cf299b6203c-id787eb468517f98" role="region" style="display:none">
391
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
392
+ <span> Period : </span>
393
+ <span> Start date 2025-09-01, v. 36 2025 </span>
394
+ </div>
395
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
396
+ <span> Location : </span>
397
+ <span> Skellefte\u00e5 </span>
398
+ </div>
399
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
400
+ <span> Form of study : </span>
401
+ <span> Day-time 100% </span>
402
+ </div>
403
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
404
+ <span> Language : </span>
405
+ <span> English </span>
406
+ </div>
407
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
408
+ <span> Tuition fees : </span>
409
+ <a href="/en/education/tuition-and-application-fees"> Information for non-EU/EEA students </a>
410
+ </div>
411
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
412
+ <span> Application code : </span>
413
+ <span> LTU-87020 </span>
414
+ </div>
415
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
416
+ <span> Last day for application : </span>
417
+ <span> 2025-01-15 </span>
418
+ </div>
419
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
420
+ <span> Number of places : </span>
421
+ <span> 10 </span>
422
+ </div>
423
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK" style="white-space:pre-line">
424
+ <span> Entry requirements : </span>
425
+ <span> In order to meet the general entry requirements for first cycle studies you must have successfully completed upper secondary education and have documented skills in English language + Upper secondary school courses English 6, Mathematics 2a or 2b or 2c. </span>
426
+ </div>
427
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
428
+ <span> Selection : </span>
429
+ <span> The selection is based on final school grades or Swedish Scholastic Aptitude Test. </span>
430
+ </div>
431
+ </div>
432
+ </div>
433
+ </div>
434
+ </div>
435
+ </div>
436
+ </div>
437
+ </div>
438
+ </div>
439
+ <div class="sv-layout sv-column-4 sv-template-layout" id="svid10_9d9795118afe54123818313" style="padding-left:32px">
440
+ <div class="sv-custom-module sv-Programoversikt sv-skip-spacer sv-template-portlet" id="svid12_113c8d5d18b5cf299b62034">
441
+ <div data-cid="12.113c8d5d18b5cf299b62034">
442
+ <div class="b6DYXDzwiQ61krbimq_w" data-reactroot="">
443
+ <h2> Programme overview </h2>
444
+ <div>
445
+ <div class="Pdg9fxg_yuAW9NmUiXxO">
446
+ <dialog aria-labelledby="dialog-12-113c8d5d18b5cf299b62034-0-header" class="env-dialog env-dialog--large EfAJEnr0TqLs2hdF_boN" id="dialog-12-113c8d5d18b5cf299b62034-0">
447
+ <div class="env-dialog__controls env-dialog__controls--end">
448
+ <h2 class="env-dialog__title" id="dialog-12-113c8d5d18b5cf299b62034-0-header"> Media Technology 180 cr </h2>
449
+ </div>
450
+ <div class="env-dialog__main">
451
+ <div>
452
+ <h3 class="env-dialog__title"> Compulsory courses </h3>
453
+ <ul>
454
+ <li>
455
+ <p class="env-text"> Degree Project in Computer Graphics, Bachelor 15 cr </p>
456
+ </li>
457
+ </ul>
458
+ </div>
459
+ <div>
460
+ <h3 class="env-dialog__title"> Compulsory courses </h3>
461
+ <ul>
462
+ <li>
463
+ <p class="env-text"> Animation and Rigging 7.5 cr </p>
464
+ </li>
465
+ <li>
466
+ <p class="env-text"> Professional practices 15 cr </p>
467
+ </li>
468
+ <li>
469
+ <p class="env-text"> 3D Graphics 7.5 cr </p>
470
+ </li>
471
+ <li>
472
+ <p class="env-text"> Applied mathematics for computer graphics 7.5 cr </p>
473
+ </li>
474
+ <li>
475
+ <p class="env-text"> Scripting for computer graphics 7.5 cr </p>
476
+ </li>
477
+ <li>
478
+ <p class="env-text"> Visual effects and simulation 7.5 cr </p>
479
+ </li>
480
+ <li>
481
+ <p class="env-text"> Advanced 3D graphics 7.5 cr </p>
482
+ </li>
483
+ <li>
484
+ <p class="env-text"> Professional studio production 15 cr </p>
485
+ </li>
486
+ <li>
487
+ <p class="env-text"> Design processes and methods for Computer Graphics 15 cr </p>
488
+ </li>
489
+ <li>
490
+ <p class="env-text"> Compositing 7.5 cr </p>
491
+ </li>
492
+ <li>
493
+ <p class="env-text"> Specialisation project in computer graphics 15 cr </p>
494
+ </li>
495
+ <li>
496
+ <p class="env-text"> Introduction to Computer Graphics 15 cr </p>
497
+ </li>
498
+ <li>
499
+ <p class="env-text"> Studio production practices 15 cr </p>
500
+ </li>
501
+ <li>
502
+ <p class="env-text"> Profession specialism 15 cr </p>
503
+ </li>
504
+ <li>
505
+ <p class="env-text"> Realtime Graphics 7.5 cr </p>
506
+ </li>
507
+ </ul>
508
+ </div>
509
+ </div>
510
+ </dialog>
511
+ </div>
512
+ </div>
513
+ </div>
514
+ </div>
515
+ </div>
516
+ <div class="sv-custom-module sv-Utbildningslankar sv-template-portlet" id="svid12_4c63de6f18c8ad0610eee8a">
517
+ <div class="nv3w53uN_xYlnScEDbR_">
518
+ <div class="btn btn-primary">
519
+ <a href="/en/education/syllabuses/programme-syllabus?id=TKDSG"> Programme syllabus </a>
520
+ </div>
521
+ <div class="btn btn-primary">
522
+ <a href="/en/education/degree/exa4580-degree-of-bachelor---major-media-technology?inrKod=INR010"> Degree of Bachelor - Major; Media Technology specializing in Computer graphics for game and film </a>
523
+ </div>
524
+ </div>
525
+ </div>
526
+ </div>
527
+ </div>
528
+ <div class="sv-vertical sv-layout sv-hide-sv-bp-barbar sv-hide-sv-bp-storre-an-desktop sv-template-layout" id="svid10_76a8fd2c18bacfca06c1b3">
529
+ <div class="sv-custom-module sv-Utbildningsinfo sv-skip-spacer sv-template-portlet" id="svid12_76a8fd2c18bacfca06c1bb">
530
+ <div data-cid="12.76a8fd2c18bacfca06c1bb">
531
+ <div class="n643rbQmLp1JhPH6BNOP" data-reactroot="">
532
+ <div class="YCmRRC2mkPKvIvPGgVS1">
533
+ <div>
534
+ <div class="HMw9ixbm69bdZBQgzYIc">
535
+ <p class="PT2hF8CC4ZkIu8gQjcXZ P6maIg6cPpOpyvdkNWhU"> 180 credits, programme, bachelor's level, TKDSG </p>
536
+ </div>
537
+ </div>
538
+ <div class="Ow6v240LEi5yqxc5rGR5">
539
+ <div class="NCeqmR8pzeE44yTVEI57">
540
+ <div class="xSna321hZeZMiT3Krt5Q">
541
+ <div aria-hidden="true" class="QIGBu7OXJcb9eqnrSJh2" id="semester-list-12-76a8fd2c18bacfca06c1bb" style="display:none">
542
+ <a class="P6maIg6cPpOpyvdkNWhU" href="?termin=HT%202024"> Autumn 2024 </a>
543
+ </div>
544
+ </div>
545
+ </div>
546
+ <div class="k2P1IeAKKuFzeBtQpNAH Anuhi5WUjEADMmjifqzb">
547
+ <p class="P6maIg6cPpOpyvdkNWhU"> Open for late application! </p>
548
+ </div>
549
+ <div class="XSSl3yA6zZnlVfET_yP8">
550
+ <a class="P6maIg6cPpOpyvdkNWhU" href=""> To signup </a>
551
+ </div>
552
+ </div>
553
+ </div>
554
+ <div class="ihAUe3Ae4xOF4DoCK40U">
555
+ <p class="mbr3VVI67WGiBBWXN62d"> Do you want to be part of the teams that create the visual effects for the next Hollywood blockbuster or the stunning levels of award-winning AAA video games? In the Computer Graphics for Film and Games programme, you will learn to transform your creative ideas into spectacular digital worlds. </p>
556
+ <div class="ne945o61E5G3OHW9nAsv">
557
+ <div> Do you enjoy crafting beautiful images - and technical problem-solving? Perhaps you are already exploring digital technologies, such as image editing, animation, 3D modelling, or modding games. Whether you have a background in traditional arts or the natural sciences, computer graphics offers many different pathways to developing your creative possibilities. </div>
558
+ <div>
559
+ </div>
560
+ <div> This programme accepts both Swedish and international applicants, creating a dynamic and diverse study environment. You will learn professional tools and processes to take a project from concept to finished film or game production. More than that, you will hone your artistic eye, understand the scientific foundations of the field, and gain experience collaborating with others on creative briefs. With over thirty years of experience teaching in the field, we focus on the key skills required in an industry that is constantly changing and evolving. </div>
561
+ <div>
562
+ </div>
563
+ <div> After graduation, you will join our many alumni in fields such as game development, visual effects production for film, or feature animation. A university degree gives you the advantage needed when applying for jobs in the highly competitive and international market. </div>
564
+ </div>
565
+ <div class="h1RG7SwGDaAhnFCbNq5p">
566
+ <div class="sv-vertical sv-layout sv-skip-spacer" id="layout-accordion-12-76a8fd2c18bacfca06c1bb-0">
567
+ <div class="sv-vertical sv-layout ltu__accordion sv-skip-spacer">
568
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer">
569
+ <div class="ltu__accordion-container">
570
+ </div>
571
+ </div>
572
+ <div class="sv-vertical sv-layout sv-decoration-content">
573
+ <div class="bLA8XBv10huo26rMBkg2">
574
+ <div> The first semester lays the groundwork for the rest of your studies. Beginning with traditional art exercises, you will quickly move on to collaborative creative projects where a client sets the expectations. At the same time, you learn the basics of digital media and the key technical concepts that underpin future courses. </div>
575
+ <div> In the spring semester, you will develop core skills in 2D digital compositing\u2014the foundation of all film visual effects\u2014alongside 3D modelling, animation, and rendering. A programming course rounds out your introduction to computer graphics. During your second year, you dive deeper into 3D graphics. Advanced modelling and texturing techniques will allow you to create more realistic assets, while an introduction to real-time graphics opens up the world of interactive video games. Effects simulation will teach you how to replicate complex natural phenomena like smoke and water, and a mathematics course will give you the theoretical tools to understand these processes.The spring semester offers opportunities to further hone your artistic and technical skills through project-based courses. </div>
576
+ <div>
577
+ </div>
578
+ <div> Your final year focuses on applying everything you have learned. Collaboration, teamwork, independence, and problem-solving will all be key to your professional future. Some projects will have you working in large teams under close supervision, while others will involve solo research and skill development to help you build a strong portfolio. In your last semester, you collaborate with your peers to create a fully realised product - such as a game or short film. This hands-on experience will give you a comprehensive understanding of professional workflows and a finished product to showcase to potential employers. By graduation, you will have both specialised knowledge and practical experience, setting you up for a successful career in computer graphics. </div>
579
+ </div>
580
+ </div>
581
+ </div>
582
+ </div>
583
+ <div class="sv-vertical sv-layout sv-skip-spacer" id="layout-accordion-12-76a8fd2c18bacfca06c1bb-2">
584
+ <div class="sv-vertical sv-layout ltu__accordion sv-skip-spacer">
585
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer">
586
+ <div class="ltu__accordion-container">
587
+ </div>
588
+ </div>
589
+ <div class="sv-vertical sv-layout sv-decoration-content">
590
+ <div class="bLA8XBv10huo26rMBkg2">
591
+ <div> The programme prepares you for a range of roles working with digital media in the fields of game development, film post-production (VFX), and feature animation. Your skills will also translate into related industries, such as advertising and architectural visualisation. After graduation, you might find yourself in generalised roles such as 3D Artist, CG Generalist, or Technical Director. You may also specialise in careers such as Environment Artist, VFX Artist, Compositor, Animator, FX Artist, and more. </div>
592
+ <div> Our alumni have worked on film projects such as The Lord of the Rings films, Harry Potter series, and Shogun; and games such as Battlefront series, Assassin\u2019s Creed, and Helldivers II. </div>
593
+ </div>
594
+ </div>
595
+ </div>
596
+ </div>
597
+ </div>
598
+ </div>
599
+ </div>
600
+ </div>
601
+ </div>
602
+ <div class="sv-custom-module sv-Programoversikt sv-template-portlet" id="svid12_76a8fd2c18bacfca06c1bd">
603
+ <div data-cid="12.76a8fd2c18bacfca06c1bd">
604
+ <div class="b6DYXDzwiQ61krbimq_w" data-reactroot="">
605
+ <h2> Programme overview </h2>
606
+ <div>
607
+ <div class="Pdg9fxg_yuAW9NmUiXxO">
608
+ <dialog aria-labelledby="dialog-12-76a8fd2c18bacfca06c1bd-0-header" class="env-dialog env-dialog--large EfAJEnr0TqLs2hdF_boN" id="dialog-12-76a8fd2c18bacfca06c1bd-0">
609
+ <div class="env-dialog__controls env-dialog__controls--end">
610
+ <h2 class="env-dialog__title" id="dialog-12-76a8fd2c18bacfca06c1bd-0-header"> Media Technology 180 cr </h2>
611
+ </div>
612
+ <div class="env-dialog__main">
613
+ <div>
614
+ <h3 class="env-dialog__title"> Compulsory courses </h3>
615
+ <ul>
616
+ <li>
617
+ <p class="env-text"> Degree Project in Computer Graphics, Bachelor 15 cr </p>
618
+ </li>
619
+ </ul>
620
+ </div>
621
+ <div>
622
+ <h3 class="env-dialog__title"> Compulsory courses </h3>
623
+ <ul>
624
+ <li>
625
+ <p class="env-text"> Animation and Rigging 7.5 cr </p>
626
+ </li>
627
+ <li>
628
+ <p class="env-text"> Professional practices 15 cr </p>
629
+ </li>
630
+ <li>
631
+ <p class="env-text"> 3D Graphics 7.5 cr </p>
632
+ </li>
633
+ <li>
634
+ <p class="env-text"> Applied mathematics for computer graphics 7.5 cr </p>
635
+ </li>
636
+ <li>
637
+ <p class="env-text"> Scripting for computer graphics 7.5 cr </p>
638
+ </li>
639
+ <li>
640
+ <p class="env-text"> Visual effects and simulation 7.5 cr </p>
641
+ </li>
642
+ <li>
643
+ <p class="env-text"> Advanced 3D graphics 7.5 cr </p>
644
+ </li>
645
+ <li>
646
+ <p class="env-text"> Professional studio production 15 cr </p>
647
+ </li>
648
+ <li>
649
+ <p class="env-text"> Design processes and methods for Computer Graphics 15 cr </p>
650
+ </li>
651
+ <li>
652
+ <p class="env-text"> Compositing 7.5 cr </p>
653
+ </li>
654
+ <li>
655
+ <p class="env-text"> Specialisation project in computer graphics 15 cr </p>
656
+ </li>
657
+ <li>
658
+ <p class="env-text"> Introduction to Computer Graphics 15 cr </p>
659
+ </li>
660
+ <li>
661
+ <p class="env-text"> Studio production practices 15 cr </p>
662
+ </li>
663
+ <li>
664
+ <p class="env-text"> Profession specialism 15 cr </p>
665
+ </li>
666
+ <li>
667
+ <p class="env-text"> Realtime Graphics 7.5 cr </p>
668
+ </li>
669
+ </ul>
670
+ </div>
671
+ </div>
672
+ </dialog>
673
+ </div>
674
+ </div>
675
+ </div>
676
+ </div>
677
+ </div>
678
+ <div class="sv-custom-module sv-Utbildningslankar sv-template-portlet" id="svid12_4c63de6f18c8ad0610eee6d">
679
+ <div class="nv3w53uN_xYlnScEDbR_">
680
+ <div class="btn btn-primary">
681
+ <a href="/en/education/syllabuses/programme-syllabus?id=TKDSG"> Programme syllabus </a>
682
+ </div>
683
+ <div class="btn btn-primary">
684
+ <a href="/en/education/degree/exa4580-degree-of-bachelor---major-media-technology?inrKod=INR010"> Degree of Bachelor - Major; Media Technology specializing in Computer graphics for game and film </a>
685
+ </div>
686
+ </div>
687
+ </div>
688
+ <div class="sv-custom-module sv-Antagningsinfo sv-template-portlet" id="svid12_76a8fd2c18bacfca06c1bf">
689
+ <div data-cid="12.76a8fd2c18bacfca06c1bf">
690
+ <div class="ZNUvioejd0sf76mDllUw" data-reactroot="">
691
+ <div class="nO6gixhkydP0V1HvItFs">
692
+ <h2 class="Omzt6wK6ec3dPmWuUGys"> Sign up for the programme </h2>
693
+ <div>
694
+ <div class="zLzFOMPisNxzvt_htr0Q">
695
+ <div class="zlkqdrXR1uei8xmUnfyZ">
696
+ <div class="hBedBl2wkkgVgAAgDlWf">
697
+ <div class="kTKjJ7LBjjCvDKQ54obI">
698
+ <p class="yOIfCXndb3ZR16kbRgAt C6m2QJ0XjKwKscgJhFzK"> LTU-87020 </p>
699
+ <div class="gk0D3Ip7pLalmcnWorhD w7_ihQcJBol8nnSs9g73">
700
+ <p class="C6m2QJ0XjKwKscgJhFzK"> Open for late application! </p>
701
+ </div>
702
+ </div>
703
+ <h3 class="UU3Vc64tqr14z9OQCw5w"> Bachelor Programme in Computer graphics for game and film, International students </h3>
704
+ <p class="DK3aev8MNKGpfCwrSXq7 C6m2QJ0XjKwKscgJhFzK">
705
+ <span class="ybOpqUwzAposuRmd1kvi"> Start date 2025-09-01, v. 36 2025 , </span>
706
+ <span class="ubuecRhlCCNGE0h1a0BB"> Skellefte\u00e5 </span>
707
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Normal teaching </span>
708
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Day-time 100% </span>
709
+ <span class="ubuecRhlCCNGE0h1a0BB UQLL1eLNucalw06yh6U4"> Autumn 2025 </span>
710
+ </p>
711
+ </div>
712
+ <div class="FANKPZoqsFhpSbBZw8Bp">
713
+ <a href="https://www.universityadmissions.se/intl/addtobasket?period=ht_2025&amp;id=LTU-87020" rel="external"> Apply here <span class="env-assistive-text"> to the programme Bachelor Programme in Computer graphics for game and film, International students - LTU-87020 Link to another website, opens in new window </span>
714
+ </a>
715
+ </div>
716
+ </div>
717
+ <div aria-hidden="true" aria-labelledby="btn-LTU-87020-12-76a8fd2c18bacfca06c1bf-idc8f9a86707a968" class="ZRtoL3It3_sm8MY77J2q" id="acc-LTU-87020-12-76a8fd2c18bacfca06c1bf-idc8f9a86707a968" role="region" style="display:none">
718
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
719
+ <span> Period : </span>
720
+ <span> Start date 2025-09-01, v. 36 2025 </span>
721
+ </div>
722
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
723
+ <span> Location : </span>
724
+ <span> Skellefte\u00e5 </span>
725
+ </div>
726
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
727
+ <span> Form of study : </span>
728
+ <span> Day-time 100% </span>
729
+ </div>
730
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
731
+ <span> Language : </span>
732
+ <span> English </span>
733
+ </div>
734
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
735
+ <span> Tuition fees : </span>
736
+ <a href="/en/education/tuition-and-application-fees"> Information for non-EU/EEA students </a>
737
+ </div>
738
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
739
+ <span> Application code : </span>
740
+ <span> LTU-87020 </span>
741
+ </div>
742
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
743
+ <span> Last day for application : </span>
744
+ <span> 2025-01-15 </span>
745
+ </div>
746
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
747
+ <span> Number of places : </span>
748
+ <span> 10 </span>
749
+ </div>
750
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK" style="white-space:pre-line">
751
+ <span> Entry requirements : </span>
752
+ <span> In order to meet the general entry requirements for first cycle studies you must have successfully completed upper secondary education and have documented skills in English language + Upper secondary school courses English 6, Mathematics 2a or 2b or 2c. </span>
753
+ </div>
754
+ <div class="lhgan24SXOCFJ2gbcDaQ C6m2QJ0XjKwKscgJhFzK">
755
+ <span> Selection : </span>
756
+ <span> The selection is based on final school grades or Swedish Scholastic Aptitude Test. </span>
757
+ </div>
758
+ </div>
759
+ </div>
760
+ </div>
761
+ </div>
762
+ </div>
763
+ </div>
764
+ </div>
765
+ </div>
766
+ </div>
767
+ <div class="sv-row sv-layout ltu-imagepuff__wrapper sv-template-layout" id="svid10_9d9795118afe541238182f1">
768
+ <div class="pagecontent sv-layout" id="svid94_5100ce5c18bc193fe5e285e">
769
+ <div class="sv-row sv-layout sv-skip-spacer" id="svid10_5100ce5c18bc193fe5e285f">
770
+ <div class="sv-layout sv-skip-spacer sv-column-4" id="svid10_5100ce5c18bc193fe5e2860">
771
+ <div class="sv-custom-module sv-bildpuff sv-skip-spacer" id="svid12_5100ce5c18bc193fe5e2861">
772
+ <div class="ltu-imagepuff ltu-imagepuff__color-lightgrey">
773
+ <div class="ltu-imagepuff__topwrapper">
774
+ <div class="ltu-imagepuff__image">
775
+ </div>
776
+ </div>
777
+ <div class="ltu-imagepuff__text">
778
+ <h2 class="ltu-imagepuff__title" id="12.5100ce5c18bc193fe5e2861_heading">
779
+ <a class="ltu-imagepuff__link" href="/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film/about-the-programme"> Check out the film about Computer Graphics for Games and Film </a>
780
+ </h2>
781
+ <p class="ltu-imagepuff__preamble normal"> This programme is for you who want to create digital environments, characters, animations and visual effects for movies, TV-series and computer games. </p>
782
+ </div>
783
+ </div>
784
+ </div>
785
+ </div>
786
+ <div class="sv-layout sv-column-4" id="svid10_5100ce5c18bc193fe5e2863">
787
+ <div class="sv-custom-module sv-bildpuff sv-skip-spacer" id="svid12_5100ce5c18bc193fe5e2864">
788
+ <div class="ltu-imagepuff ltu-imagepuff__color-lightgrey">
789
+ <div class="ltu-imagepuff__topwrapper">
790
+ <div class="ltu-imagepuff__image">
791
+ </div>
792
+ </div>
793
+ <div class="ltu-imagepuff__text">
794
+ <h2 class="ltu-imagepuff__title" id="12.5100ce5c18bc193fe5e2864_heading">
795
+ <a class="ltu-imagepuff__link" href="/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film/student"> "Follow your dreams and create games and movies" </a>
796
+ </h2>
797
+ <p class="ltu-imagepuff__preamble normal"> Fabian Zackrisson tells about how it is to study Computer Graphics programme. </p>
798
+ </div>
799
+ </div>
800
+ </div>
801
+ </div>
802
+ <div class="sv-layout sv-column-4" id="svid10_5100ce5c18bc193fe5e2866">
803
+ <div class="sv-custom-module sv-bildpuff sv-skip-spacer" id="svid12_5100ce5c18bc193fe5e2867">
804
+ <div class="ltu-imagepuff ltu-imagepuff__color-lightgrey">
805
+ <div class="ltu-imagepuff__topwrapper">
806
+ <div class="ltu-imagepuff__image">
807
+ </div>
808
+ </div>
809
+ <div class="ltu-imagepuff__text">
810
+ <h2 class="ltu-imagepuff__title" id="12.5100ce5c18bc193fe5e2867_heading">
811
+ <a class="ltu-imagepuff__link" href="/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film/former-students"> Former students </a>
812
+ </h2>
813
+ <p class="ltu-imagepuff__preamble normal"> Read more about our former students and what they are doing after their studies. </p>
814
+ </div>
815
+ </div>
816
+ </div>
817
+ </div>
818
+ </div>
819
+ </div>
820
+ </div>
821
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_9d9795118afe541238182f2">
822
+ <div class="pagecontent sv-layout" id="svid94_5100ce5c18bc193fe5e2869">
823
+ <div class="sv-custom-module sv-bannerblock sv-skip-spacer" id="svid12_5100ce5c18bc193fe5e286a">
824
+ <div class="ltu-bannerblock variant1 ltu-bannerblock__color-lightgrey">
825
+ <div class="ltu-bannerblock__image">
826
+ </div>
827
+ <div class="ltu-bannerblock__text">
828
+ <h2 class="ltu-bannerblock__title" id="12.5100ce5c18bc193fe5e286a_heading"> How to apply </h2>
829
+ <p class="ltu-bannerblock__preamble"> How to apply for your bachelor programme. </p>
830
+ <div class="ltu-bannerblock__buttons">
831
+ <div class="btn btn--large btn-primary">
832
+ <a class="ltu-bannerblock__link" href="/en/education/how-to-apply"> Read more </a>
833
+ </div>
834
+ </div>
835
+ </div>
836
+ </div>
837
+ </div>
838
+ </div>
839
+ </div>
840
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_9d9795118afe54123818413">
841
+ <div class="sv-layout sv-skip-spacer sv-column-8 sv-template-layout" id="svid10_9d9795118afe54123818432">
842
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_7bdab48918c624d207d57a5">
843
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_7bdab48918c624d207d57a6">
844
+ <div class="sv-text-portlet-content">
845
+ <h2 class="subheading" id="h-Doyouhavequestionsabouttheprogram"> Do you have questions about the program? </h2>
846
+ </div>
847
+ </div>
848
+ <div class="sv-text-portlet sv-use-margins sv-template-portlet" id="svid12_7bdab48918c624d207d57a7">
849
+ <div class="sv-text-portlet-content">
850
+ <p class="normal"> Our staff will answer you as soon as possible. </p>
851
+ </div>
852
+ </div>
853
+ <div class="sv-form-portlet sv-portlet ltu-main__program-detail-page-form sv-template-portlet" id="svid12_7bdab48918c624d207d57a8">
854
+ </div>
855
+ </div>
856
+ </div>
857
+ </div>
858
+ <div class="sv-row sv-layout ltu-main__programpages-related-programs--wrapper sv-template-layout" id="svid10_9d9795118afe54123818414">
859
+ <div class="sv-related-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_9d9795118afe5412381846d">
860
+ </div>
861
+ </div>
862
+ <div class="sv-row sv-layout ltu-main__pageinfo sv-template-layout" id="svid10_9d9795118afe541238182df">
863
+ <div class="sv-layout sv-skip-spacer sv-column-8 sv-template-layout" id="svid10_9d9795118afe541238182e0">
864
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_9d9795118afe541238182e1">
865
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_7250aafe18a25f9f4f5f13">
866
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_7250aafe18a25f9f4f5f14">
867
+ <div class="sv-text-portlet-content">
868
+ <p class="normal"> Updated: <time datetime="2024-08-26T10:19:01+02:00"> 26 August 2024 </time>
869
+ </p>
870
+ </div>
871
+ </div>
872
+ </div>
873
+ </div>
874
+ <div class="sv-layout sv-template-portlet" id="svid30_9d9795118afe541238182e2">
875
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_6cee445918721b0da0b1827e">
876
+ </div>
877
+ </div>
878
+ </div>
879
+ </div>
880
+ </div>
881
+ </div>
882
+ </div>
883
+ <div class="sv-row sv-layout sv-hide-sv-bp-barbar sv-hide-sv-bp-storre-an-desktop sv-hide-sv-bp-tablet sv-visible-sv-bp-telefon sv-template-layout" id="svid10_2a813a51877918956fcd11">
884
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_2a813a51877918956fcd12">
885
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_4083afc618721a87d7e37eac">
886
+ <nav aria-label="Breadcrumb in mobile">
887
+ <ol class="ltu-main__breadcrumbs--list">
888
+ <li class="ltu-main__breadcrumbs--item">
889
+ <a href="/en">
890
+ <span class="env-assistive-text"> Start </span>
891
+ </a>
892
+ </li>
893
+ <li class="ltu-main__breadcrumbs--item">
894
+ <a href="/en/education"> Education </a>
895
+ </li>
896
+ <li class="ltu-main__breadcrumbs--item">
897
+ <a href="/en/education/programme"> Programme </a>
898
+ </li>
899
+ <li class="ltu-main__breadcrumbs--item">
900
+ <a class="ltu-main__breadcrumbs--item-last" href="/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film"> Bachelor Programme in Computer Graphics for Games and Film </a>
901
+ </li>
902
+ </ol>
903
+ </nav>
904
+ </div>
905
+ </div>
906
+ </div>
907
+ </div>
908
+ </div>
909
+ </main>
910
+ <footer class="sv-vertical sv-layout sv-template-layout" id="svid10_216994f318d5490e1ff39715">
911
+ <div class="sv-fixed-fluid-grid sv-grid-12-kolumner-1224 sv-layout ltu-footer sv-skip-spacer sv-template-layout" id="svid10_363208b0186a1918f7f5e83b">
912
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid93_588ff970189d1c739351fcb8">
913
+ <div class="sv-row sv-layout ltu-footer__logotext sv-skip-spacer sv-template-layout" id="svid10_588ff970189d1c739351fcb9">
914
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_588ff970189d1c739351fcba">
915
+ <div class="sv-script-portlet sv-portlet ltu-footer__logoscript sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351ecf3">
916
+ </div>
917
+ </div>
918
+ <div class="sv-vertical sv-layout sv-template-layout" id="svid10_588ff970189d1c739351fcbb">
919
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcbd">
920
+ <div class="sv-text-portlet-content">
921
+ <p class="normal"> Lule\u00e5 University of Technology is in strong growth with world-leading competence in several research areas. We have a total turnover of SEK 2 billion per year, 1,900 employees, and 17,900 students. </p>
922
+ </div>
923
+ </div>
924
+ </div>
925
+ </div>
926
+ <div class="sv-row sv-layout sv-hide-sv-bp-telefon ltu-footer__links sv-template-layout" id="svid10_588ff970189d1c739351fcbe">
927
+ <div class="sv-layout sv-skip-spacer sv-column-3 sv-template-layout" id="svid10_588ff970189d1c739351fcbf">
928
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcc0">
929
+ <div class="sv-text-portlet-content">
930
+ <h2 class="subheading" id="h-Contact"> Contact </h2>
931
+ </div>
932
+ </div>
933
+ <div class="sv-vertical sv-layout sv-template-layout" id="svid10_588ff970189d1c739351fcc1">
934
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcc2">
935
+ <div class="sv-text-portlet-content">
936
+ <p class="normal"> Lule\u00e5 University of Technology <br> 97187 Lule\u00e5, Sweden Phone: +46 (0)920-491000 Registration number: 202100-2841 </br>
937
+ </p>
938
+ <p class="normal">
939
+ <a href="/en/contact-lulea-university-of-technology"> Contact us </a>
940
+ </p>
941
+ <p class="normal">
942
+ <a href="/en/contact-lulea-university-of-technology/find-lulea-university-of-technology"> Directions </a>
943
+ </p>
944
+ <ul class="normal">
945
+ <li>
946
+ <a href="https://map.ltu.se/" rel="external"> LTU maps <span class="env-assistive-text"> External link, opens in new window. </span>
947
+ </a>
948
+ </li>
949
+ </ul>
950
+ </div>
951
+ </div>
952
+ </div>
953
+ </div>
954
+ <div class="sv-layout sv-column-3 sv-template-layout" id="svid10_588ff970189d1c739351fcc6">
955
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcc7">
956
+ <div class="sv-text-portlet-content">
957
+ <h2 class="subheading" id="h-Shortcuts"> Shortcuts </h2>
958
+ </div>
959
+ </div>
960
+ <div class="sv-vertical sv-layout sv-template-layout" id="svid10_588ff970189d1c739351fcc8">
961
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcc9">
962
+ <div class="sv-text-portlet-content">
963
+ <ul>
964
+ <li>
965
+ <a href="/en/in-case-of-incident-or-emergency"> In case of incident or emergency </a>
966
+ </li>
967
+ <li>
968
+ <a href="/en/in-case-of-incident-or-emergency/report-faulty-facilities-or-equipment"> Report faulty facilities or equipment </a>
969
+ </li>
970
+ <li>
971
+ <a href="/en/about-the-university/rules-guidelines-and-policies"> Governing documents </a>
972
+ </li>
973
+ <li>
974
+ <a href="/en/latest-news/press"> Press </a>
975
+ </li>
976
+ <li>
977
+ <a href="/en/about-the-university/organisation"> Organisation </a>
978
+ </li>
979
+ <li>
980
+ <a href="/en/university-library"> University Library </a>
981
+ </li>
982
+ <li>
983
+ <a href="/en/about-the-university/work-with-us/job-vacancies"> Job vacancies </a>
984
+ </li>
985
+ <li>
986
+ </li>
987
+ </ul>
988
+ </div>
989
+ </div>
990
+ </div>
991
+ </div>
992
+ <div class="sv-layout sv-column-3 sv-template-layout" id="svid10_588ff970189d1c739351fccf">
993
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcd0">
994
+ <div class="sv-text-portlet-content">
995
+ <h2 class="subheading" id="h-Aboutthiswebsite"> About this website </h2>
996
+ </div>
997
+ </div>
998
+ <div class="sv-vertical sv-layout sv-template-layout" id="svid10_588ff970189d1c739351fcd1">
999
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739351fcd2">
1000
+ <div class="sv-text-portlet-content">
1001
+ <ul class="normal">
1002
+ <li>
1003
+ <a href="/en/in-case-of-incident-or-emergency/whistleblowing"> Whistleblowing </a>
1004
+ </li>
1005
+ <li>
1006
+ <a href="/en/processing-of-personal-data-gdpr"> Processing of personal data, GDPR </a>
1007
+ </li>
1008
+ <li>
1009
+ <a href="/en/accessibility"> Accessibility </a>
1010
+ </li>
1011
+ <li>
1012
+ <a href="/en/about-cookies"> Cookies </a>
1013
+ </li>
1014
+ <li>
1015
+ <a href="/kontakt-for-webbplatsen"> Contact for website </a>
1016
+ </li>
1017
+ </ul>
1018
+ </div>
1019
+ </div>
1020
+ </div>
1021
+ </div>
1022
+ <div class="sv-layout sv-column-3 sv-template-layout" id="svid10_588ff970189d1c739351fcd7">
1023
+ <div class="sv-vertical sv-layout ltu-footer__links--last-column sv-skip-spacer sv-template-layout" id="svid10_588ff970189d1c739351fcd8">
1024
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79c10095">
1025
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_20d3a04618d2a60c79c10096">
1026
+ <ul>
1027
+ <li>
1028
+ <a href="/utbildning/program/tkdsg-datorgrafik-for-spel-och-film-kandidat" lang="sv"> P\u00e5 svenska </a>
1029
+ </li>
1030
+ <li>
1031
+ <a class="testar" href="/en/staff-web"> Staff </a>
1032
+ </li>
1033
+ <li>
1034
+ <a class="testar" href="/en/student-web"> Student website </a>
1035
+ </li>
1036
+ </ul>
1037
+ </div>
1038
+ </div>
1039
+ </div>
1040
+ </div>
1041
+ </div>
1042
+ <div class="sv-row sv-layout sv-visible-sv-bp-telefon ltu-footer__links ltu-footer__links-mobile sv-template-layout" id="svid10_588ff970189d1c739351ffc2">
1043
+ <div class="sv-collapsible-content sv-skip-spacer">
1044
+ <h2 class="env-m-around--0 subheading" id="h-Contactus">
1045
+ <a aria-controls="svid10_20d3a04618d2a60c79cfe13" aria-expanded="false" class="env-button env-button--link" data-env-collapse="" data-target="#svid10_20d3a04618d2a60c79cfe13" href="#svid10_20d3a04618d2a60c79cfe13" role="button">
1046
+ <span> Contact us </span>
1047
+ </a>
1048
+ </h2>
1049
+ <div class="sv-layout sv-column-3 env-collapse sv-clearfix sv-template-layout" id="svid10_20d3a04618d2a60c79cfe13">
1050
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79cfe2c">
1051
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_20d3a04618d2a60c79cfe2d">
1052
+ <div class="sv-text-portlet-content">
1053
+ <p class="normal"> Lule\u00e5 University of Technology 97187 Lule\u00e5, Sweden Phone: +46 (0)920-491000 Registration number: 202100-2841 </p>
1054
+ <p class="normal">
1055
+ <a href="/en/contact-lulea-university-of-technology"> Contact us </a>
1056
+ </p>
1057
+ <p class="normal">
1058
+ <a href="/en/contact-lulea-university-of-technology/find-lulea-university-of-technology"> Directions </a>
1059
+ </p>
1060
+ <ul class="normal">
1061
+ <li>
1062
+ <a href="https://map.ltu.se/" rel="external"> LTU maps <span class="env-assistive-text"> External link, opens in new window. </span>
1063
+ </a>
1064
+ </li>
1065
+ </ul>
1066
+ </div>
1067
+ </div>
1068
+ </div>
1069
+ </div>
1070
+ </div>
1071
+ <div class="sv-collapsible-content">
1072
+ <h2 class="env-m-around--0 subheading" id="h-Shortcuts-0">
1073
+ <a aria-controls="svid10_20d3a04618d2a60c79cfe15" aria-expanded="false" class="env-button env-button--link" data-env-collapse="" data-target="#svid10_20d3a04618d2a60c79cfe15" href="#svid10_20d3a04618d2a60c79cfe15" role="button">
1074
+ <span> Shortcuts </span>
1075
+ </a>
1076
+ </h2>
1077
+ <div class="sv-layout sv-column-3 env-collapse sv-clearfix sv-template-layout" id="svid10_20d3a04618d2a60c79cfe15">
1078
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79cfe31">
1079
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_20d3a04618d2a60c79cfe32">
1080
+ <div class="sv-text-portlet-content">
1081
+ <ul>
1082
+ <li>
1083
+ <a href="/en/in-case-of-incident-or-emergency"> In case of incident or emergency </a>
1084
+ </li>
1085
+ <li>
1086
+ <a href="/en/in-case-of-incident-or-emergency/report-faulty-facilities-or-equipment"> Report faulty facilities or equipment </a>
1087
+ </li>
1088
+ <li>
1089
+ <a href="/en/latest-news/press"> Press </a>
1090
+ </li>
1091
+ <li>
1092
+ <a href="/en/about-the-university/organisation"> Organisation </a>
1093
+ </li>
1094
+ <li>
1095
+ <a href="/en/university-library"> University Library </a>
1096
+ </li>
1097
+ <li>
1098
+ </li>
1099
+ <li>
1100
+ </li>
1101
+ </ul>
1102
+ </div>
1103
+ </div>
1104
+ </div>
1105
+ </div>
1106
+ </div>
1107
+ <div class="sv-collapsible-content">
1108
+ <h2 class="env-m-around--0 subheading" id="h-Aboutthiswebsite-0">
1109
+ <a aria-controls="svid10_20d3a04618d2a60c79cfe17" aria-expanded="false" class="env-button env-button--link" data-env-collapse="" data-target="#svid10_20d3a04618d2a60c79cfe17" href="#svid10_20d3a04618d2a60c79cfe17" role="button">
1110
+ <span> About this website </span>
1111
+ </a>
1112
+ </h2>
1113
+ <div class="sv-layout sv-column-3 env-collapse sv-clearfix sv-template-layout" id="svid10_20d3a04618d2a60c79cfe17">
1114
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79cfe38">
1115
+ <div class="sv-text-portlet sv-use-margins sv-skip-spacer sv-template-portlet" id="svid12_20d3a04618d2a60c79cfe39">
1116
+ <div class="sv-text-portlet-content">
1117
+ <ul class="normal">
1118
+ <li>
1119
+ <a href="/en/in-case-of-incident-or-emergency/whistleblowing"> Whistleblowing </a>
1120
+ </li>
1121
+ <li>
1122
+ <a href="/en/processing-of-personal-data-gdpr"> Processing of personal data, GDPR </a>
1123
+ </li>
1124
+ <li>
1125
+ <a href="/en/accessibility"> Accessibility </a>
1126
+ </li>
1127
+ <li>
1128
+ <a href="/en/about-cookies"> Cookies </a>
1129
+ </li>
1130
+ <li>
1131
+ <a href="/kontakt-for-webbplatsen"> Contact for website </a>
1132
+ </li>
1133
+ </ul>
1134
+ </div>
1135
+ </div>
1136
+ </div>
1137
+ </div>
1138
+ </div>
1139
+ <div class="sv-layout sv-column-3 sv-template-layout" id="svid10_20d3a04618d2a60c79cfe19">
1140
+ <div class="sv-vertical sv-layout ltu-footer__links--last-column sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79cfe1a">
1141
+ <div class="sv-vertical sv-layout ltu-footer__links--last-column sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79cfe3f">
1142
+ <div class="sv-vertical sv-layout sv-skip-spacer sv-template-layout" id="svid10_20d3a04618d2a60c79c10097">
1143
+ <div class="sv-script-portlet sv-portlet sv-skip-spacer sv-template-portlet" id="svid12_20d3a04618d2a60c79c10098">
1144
+ <ul>
1145
+ <li>
1146
+ <a href="/utbildning/program/tkdsg-datorgrafik-for-spel-och-film-kandidat" lang="sv"> P\u00e5 svenska </a>
1147
+ </li>
1148
+ <li>
1149
+ <a class="testar" href="/en/staff-web"> Staff </a>
1150
+ </li>
1151
+ <li>
1152
+ <a class="testar" href="/en/student-web"> Student website </a>
1153
+ </li>
1154
+ </ul>
1155
+ </div>
1156
+ </div>
1157
+ </div>
1158
+ </div>
1159
+ </div>
1160
+ </div>
1161
+ <div class="sv-row sv-layout sv-template-layout" id="svid10_588ff970189d1c739351fcdb">
1162
+ <div class="sv-layout sv-skip-spacer sv-template-portlet" id="svid30_588ff970189d1c739352003a">
1163
+ <div class="sv-script-portlet sv-portlet ltu-footer__iconscript sv-skip-spacer sv-template-portlet" id="svid12_588ff970189d1c739352001f">
1164
+ <div class="ltu-footer__social-media">
1165
+ <ul class="sv-defaultlist">
1166
+ <li class="facebook">
1167
+ <a href="https://www.facebook.com/LuleaUniversityofTechnology" rel="external">
1168
+ <span class="env-assistive-text"> Follow us on Facebook </span>
1169
+ <span class="env-assistive-text"> External link, opens in new window. </span>
1170
+ </a>
1171
+ </li>
1172
+ <li class="instagram">
1173
+ <a href="https://www.instagram.com/luleatekniskauniversitet" rel="external">
1174
+ <span class="env-assistive-text"> Follow us on Instagram </span>
1175
+ <span class="env-assistive-text"> External link, opens in new window. </span>
1176
+ </a>
1177
+ </li>
1178
+ <li class="youtube">
1179
+ <a href="https://www.youtube.com/c/ltuse" rel="external">
1180
+ <span class="env-assistive-text"> Follow us on Youtube </span>
1181
+ <span class="env-assistive-text"> External link, opens in new window. </span>
1182
+ </a>
1183
+ </li>
1184
+ <li class="linkedin">
1185
+ <a href="https://www.linkedin.com/school/lulea-university-of-technology" rel="external">
1186
+ <span class="env-assistive-text"> Follow us on Linkedin </span>
1187
+ <span class="env-assistive-text"> External link, opens in new window. </span>
1188
+ </a>
1189
+ </li>
1190
+ </ul>
1191
+ </div>
1192
+ </div>
1193
+ </div>
1194
+ </div>
1195
+ </div>
1196
+ </div>
1197
+ <div class="sv-script-portlet sv-portlet sv-template-portlet" id="svid12_5d674a3a1919745b8ec6045">
1198
+ </div>
1199
+ </footer>
1200
+ </div>
1201
+ <div class="sv-custom-module sv-marketplace-reakai-rekai-webapp sv-skip-spacer sv-template-portlet" id="svid12_110defe1188bd8d55c042459">
1202
+ </div>
1203
+ </div>
1204
+ </body>
1205
+ </html>
ltu_programme_data.json ADDED
The diff for this file is too large to render. See raw diff
 
progremme-spider.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from bs4 import BeautifulSoup, Comment
2
+ import scrapy, re
3
+ from boilerpy3 import extractors
4
+
5
+
6
+ class FullHTMLSpider(scrapy.spiders.SitemapSpider):
7
+ name = "ltu_programme_crawler"
8
+ # allowed_domains = ["www.ltu.se"]
9
+ sitemap_urls = ["https://www.ltu.se/robots.txt"]
10
+ sitemap_rules = [(re.compile(r'\/en\/education\/programme\/[a-zA-Z0-9-]*$'), 'parse')]
11
+ exclude_patterns = [
12
+ "sdhog-continuing-part-of-study-programme-non-freshmen-120-300-credits",
13
+ "international-orchestra-academy"]
14
+
15
+ def parse(self, response):
16
+ # Skip the page if its URL contains any excluded pattern.
17
+ if any(pattern in response.url for pattern in self.exclude_patterns):
18
+ self.logger.info("Skipping page due to excluded URL pattern: %s", response.url)
19
+ return
20
+
21
+ html = response.text
22
+ if "Discontinued." in html:
23
+ self.logger.info("Skipping page (contains 'Discontinued.'): %s", response.url)
24
+ return
25
+ extractor = extractors.ArticleExtractor()
26
+ # Pass HTML to Extractor
27
+ content = extractor.get_content(html)
28
+
29
+ return {'url': response.url, 'content': content}
qdrant_data/meta.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"collections": {"ltu_documents": {"vectors": {"text-dense": {"size": 4096, "distance": "Cosine", "hnsw_config": null, "quantization_config": null, "on_disk": true, "datatype": null, "multivector_config": null}}, "shard_number": null, "sharding_method": null, "replication_factor": null, "write_consistency_factor": null, "on_disk_payload": null, "hnsw_config": null, "wal_config": null, "optimizers_config": null, "init_from": null, "quantization_config": null, "sparse_vectors": {"text-sparse": {"index": {"full_scan_threshold": null, "on_disk": true, "datatype": null}, "modifier": null}}, "strict_mode_config": null}}, "aliases": {}}
rag_pipeline.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from typing import List, Dict, Any, Optional
4
+ from pathlib import Path
5
+ # import torch
6
+ from dotenv import load_dotenv
7
+ from haystack_integrations.document_stores.qdrant import QdrantDocumentStore
8
+ from haystack_integrations.components.retrievers.qdrant import QdrantEmbeddingRetriever, QdrantSparseEmbeddingRetriever
9
+ from haystack.components.embedders import OpenAIDocumentEmbedder, OpenAITextEmbedder
10
+ from haystack.components.builders.prompt_builder import PromptBuilder
11
+ from haystack.components.joiners.document_joiner import DocumentJoiner
12
+ from haystack.components.preprocessors.document_cleaner import DocumentCleaner
13
+ # from haystack.components.rankers.transformers import TransformersRanker
14
+ from haystack.components.writers import DocumentWriter
15
+ from haystack.components.generators.openai import OpenAIGenerator
16
+ from haystack import Pipeline
17
+ from haystack.utils import Secret
18
+ from haystack import tracing
19
+ from haystack.tracing.logging_tracer import LoggingTracer
20
+
21
+ # Load environment variables
22
+ load_dotenv()
23
+
24
+ logging.basicConfig(level=logging.INFO)
25
+ logger = logging.getLogger(__name__)
26
+
27
+ logging.basicConfig(format="%(levelname)s - %(name)s - %(message)s", level=logging.WARNING)
28
+ logging.getLogger("haystack").setLevel(logging.DEBUG)
29
+
30
+ tracing.tracer.is_content_tracing_enabled = True # to enable tracing/logging content (inputs/outputs)
31
+ tracing.enable_tracing(LoggingTracer(tags_color_strings={"haystack.component.input": "\x1b[1;31m", "haystack.component.name": "\x1b[1;34m"}))
32
+
33
+ class RAGPipeline:
34
+ def __init__(
35
+ self,
36
+ embedding_model_name: str = "BAAI/bge-en-icl",
37
+ llm_model_name: str = "meta-llama/Llama-3.3-70B-Instruct",
38
+ qdrant_path: str = None
39
+ ):
40
+ self.embedding_model_name = embedding_model_name
41
+ self.llm_model_name = llm_model_name
42
+ self.qdrant_path = qdrant_path
43
+ self.nebius_api_key = Secret.from_token(os.getenv("NEBIUS_API_KEY"))
44
+
45
+ if not self.nebius_api_key:
46
+ logger.warning("NEBIUS_API_KEY not found in environment variables")
47
+
48
+ # Initialize document stores and components
49
+ self.init_document_store()
50
+ self.init_components()
51
+ self.build_indexing_pipeline()
52
+ self.build_query_pipeline()
53
+
54
+ def init_document_store(self):
55
+ """Initialize Qdrant document store for both vector and BM25 search"""
56
+ # Qdrant store for both vector and BM25 search
57
+ self.document_store = QdrantDocumentStore(
58
+ path=self.qdrant_path,
59
+ embedding_dim=4096, # Dimension for BGE model
60
+ recreate_index=False,
61
+ on_disk=True,
62
+ on_disk_payload=True,
63
+ index="ltu_documents",
64
+ force_disable_check_same_thread=True,
65
+ use_sparse_embeddings=True # Enable BM25 support
66
+ )
67
+
68
+ def init_components(self):
69
+ """Initialize all components needed for the pipelines"""
70
+ # Document processing
71
+ self.document_cleaner = DocumentCleaner()
72
+
73
+ # Embedding components
74
+ self.document_embedder = OpenAIDocumentEmbedder(
75
+ api_base_url="https://api.studio.nebius.com/v1/",
76
+ model=self.embedding_model_name,
77
+ api_key=self.nebius_api_key,
78
+ )
79
+
80
+ self.text_embedder = OpenAITextEmbedder(
81
+ api_base_url="https://api.studio.nebius.com/v1/",
82
+ model=self.embedding_model_name,
83
+ api_key=self.nebius_api_key,
84
+ )
85
+
86
+ # Retrievers
87
+ self.bm25_retriever = QdrantSparseEmbeddingRetriever(
88
+ document_store=self.document_store,
89
+ top_k=5
90
+ )
91
+
92
+ self.embedding_retriever = QdrantEmbeddingRetriever(
93
+ document_store=self.document_store,
94
+ top_k=5
95
+ )
96
+
97
+ # Document joiner for combining results
98
+ self.document_joiner = DocumentJoiner()
99
+
100
+ # Ranker for re-ranking combined results
101
+ # self.ranker = TransformersRanker(
102
+ # model="cross-encoder/ms-marco-MiniLM-L-6-v2",
103
+ # top_k=5,
104
+ # device="cuda" if self.use_gpu else "cpu"
105
+ # )
106
+
107
+ # LLM components
108
+ self.llm = OpenAIGenerator(
109
+ api_base_url="https://api.studio.nebius.com/v1/",
110
+ model=self.llm_model_name,
111
+ api_key=self.nebius_api_key,
112
+ generation_kwargs={
113
+ "max_tokens": 1024,
114
+ "temperature": 0.1,
115
+ "top_p": 0.95,
116
+ }
117
+ )
118
+
119
+ # Prompt builder
120
+ self.prompt_builder = PromptBuilder(
121
+ template="""
122
+ <s>[INST] You are a helpful assistant that answers questions based on the provided context.
123
+
124
+ Context:
125
+ {% for document in documents %}
126
+ {{ document.content }}
127
+ {% endfor %}
128
+
129
+ Question: {{ question }}
130
+
131
+ Answer the question based only on the provided context. If the context doesn't contain the answer, say "I don't have enough information to answer this question."
132
+
133
+ Answer: [/INST]
134
+ """
135
+ )
136
+
137
+ def build_indexing_pipeline(self):
138
+ """Build the pipeline for indexing documents"""
139
+ self.indexing_pipeline = Pipeline()
140
+ self.indexing_pipeline.add_component("document_cleaner", self.document_cleaner)
141
+ self.indexing_pipeline.add_component("document_embedder", self.document_embedder)
142
+ self.indexing_pipeline.add_component("document_writer", DocumentWriter(document_store=self.document_store))
143
+
144
+ # Connect components
145
+ self.indexing_pipeline.connect("document_cleaner", "document_embedder")
146
+ self.indexing_pipeline.connect("document_embedder", "document_writer")
147
+
148
+ def build_query_pipeline(self):
149
+ """Build the pipeline for querying"""
150
+ self.query_pipeline = Pipeline()
151
+
152
+ # Add components
153
+ self.query_pipeline.add_component("text_embedder", self.text_embedder)
154
+ # self.query_pipeline.add_component("bm25_retriever", self.bm25_retriever)
155
+ self.query_pipeline.add_component("embedding_retriever", self.embedding_retriever)
156
+ # self.query_pipeline.add_component("document_joiner", self.document_joiner)
157
+ # self.query_pipeline.add_component("ranker", self.ranker)
158
+ self.query_pipeline.add_component("prompt_builder", self.prompt_builder)
159
+ self.query_pipeline.add_component("llm", self.llm)
160
+
161
+ # Connect components
162
+ self.query_pipeline.connect("text_embedder.embedding", "embedding_retriever.query_embedding")
163
+ # self.query_pipeline.connect("bm25_retriever", "document_joiner.documents_1")
164
+ # self.query_pipeline.connect("embedding_retriever", "document_joiner.documents_2")
165
+ # self.query_pipeline.connect("document_joiner", "ranker")
166
+ # self.query_pipeline.connect("ranker", "prompt_builder.documents")
167
+ self.query_pipeline.connect("embedding_retriever.documents", "prompt_builder.documents")
168
+ self.query_pipeline.connect("prompt_builder.prompt", "llm")
169
+
170
+ def index_documents(self, documents: List[Dict[str, Any]]):
171
+ """
172
+ Index documents in the document store.
173
+
174
+ Args:
175
+ documents: List of documents to index
176
+ """
177
+ logger.info(f"Indexing {len(documents)} documents")
178
+
179
+ try:
180
+ self.indexing_pipeline.run(
181
+ {"document_cleaner": {"documents": documents}}
182
+ )
183
+ logger.info("Indexing completed successfully")
184
+ except Exception as e:
185
+ logger.error(f"Error during indexing: {e}")
186
+
187
+ def query(self, question: str, top_k: int = 5) -> Dict[str, Any]:
188
+ """
189
+ Query the RAG pipeline with a question.
190
+
191
+ Args:
192
+ question: The question to ask
193
+ top_k: Number of documents to retrieve
194
+
195
+ Returns:
196
+ Dictionary containing the answer and retrieved documents
197
+ """
198
+ logger.info(f"Querying with question: {question}")
199
+
200
+ try:
201
+ # Update top_k for retrievers
202
+ self.bm25_retriever.top_k = top_k
203
+ self.embedding_retriever.top_k = top_k
204
+
205
+ # Run the query pipeline
206
+ result = self.query_pipeline.run({
207
+ "text_embedder": {"text": question},
208
+ # "bm25_retriever": {"query": question},
209
+ "prompt_builder": {"question": question}
210
+ })
211
+
212
+ # Extract answer and documents
213
+ answer = result["llm"]["replies"][0]
214
+ # documents = result["embedding_retriever"]["documents"]
215
+
216
+ return {
217
+ "answer": answer,
218
+ "documents": [], #documents,
219
+ "question": question
220
+ }
221
+ except Exception as e:
222
+ logger.error(f"Error during query: {e}")
223
+ return {
224
+ "answer": f"An error occurred: {str(e)}",
225
+ "documents": [],
226
+ "question": question
227
+ }
228
+
229
+ def get_document_count(self) -> int:
230
+ """
231
+ Get the number of documents in the document store.
232
+
233
+ Returns:
234
+ Document count
235
+ """
236
+ return self.document_store.count_documents()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit==1.42.2
2
+ haystack-ai==2.10.3
3
+ qdrant-client==1.13.2
4
+ python-dotenv==1.0.1
5
+ beautifulsoup4==4.13.3
6
+ qdrant-haystack==8.0.0
test.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from boilerpy3 import extractors
3
+
4
+ extractor = extractors.ArticleExtractor()
5
+
6
+ # Make request to URL
7
+ resp = requests.get('https://www.ltu.se/en/education/programme/tkdsg-bachelor-programme-in-computer-graphics-for-games-and-film')
8
+
9
+ # Pass HTML to Extractor
10
+ content = extractor.get_content(resp.text)
11
+
12
+ print(content)