Spaces:
Running
Running
Stepan
commited on
Commit
·
4717959
1
Parent(s):
a8d3adb
Init
Browse files- .gitignore +3 -0
- .python-version +1 -0
- .vscode/launch.json +20 -0
- .vscode/settings.json +5 -0
- app.py +191 -0
- data_processor.py +157 -0
- example.html +1205 -0
- ltu_programme_data.json +0 -0
- progremme-spider.py +29 -0
- qdrant_data/meta.json +1 -0
- rag_pipeline.py +236 -0
- requirements.txt +6 -0
- test.py +12 -0
.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&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&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)
|